diff --git a/CHANGELOG.md b/CHANGELOG.md index 015c307e..668f86db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # splat Release Notes +### 0.36.4 + +* Add more checks for texture and palette segments to have a correct size in their yaml entries, ensuring their `width`/`height` or `size` attributes match the sizes relative to other segments. + ### 0.36.3 * Fix not generating nonmatching `.s` files for quoted symbols. diff --git a/README.md b/README.md index af1c45b7..4c999927 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ The brackets corresponds to the optional dependencies to install while installin If you use a `requirements.txt` file in your repository, then you can add this library with the following line: ```txt -splat64[mips]>=0.36.3,<1.0.0 +splat64[mips]>=0.36.4,<1.0.0 ``` ### Optional dependencies diff --git a/pyproject.toml b/pyproject.toml index 688f7064..7a696924 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "splat64" # Should be synced with src/splat/__init__.py -version = "0.36.3" +version = "0.36.4" description = "A binary splitting tool to assist with decompilation and modding projects" readme = "README.md" license = {file = "LICENSE"} diff --git a/src/splat/__init__.py b/src/splat/__init__.py index c504024b..1ceb8bbb 100644 --- a/src/splat/__init__.py +++ b/src/splat/__init__.py @@ -1,7 +1,7 @@ __package_name__ = __name__ # Should be synced with pyproject.toml -__version__ = "0.36.3" +__version__ = "0.36.4" __author__ = "ethteck" from . import util as util diff --git a/src/splat/segtypes/n64/ci.py b/src/splat/segtypes/n64/ci.py index 74cdb717..68e6e4da 100644 --- a/src/splat/segtypes/n64/ci.py +++ b/src/splat/segtypes/n64/ci.py @@ -48,6 +48,8 @@ def out_path_pal(self, pal_name) -> Path: return options.opts.asset_path / self.dir / f"{out_name}{type_extension}.png" def split(self, rom_bytes): + self.check_len() + assert self.palettes is not None if len(self.palettes) == 0: # TODO: output with blank palette diff --git a/src/splat/segtypes/n64/img.py b/src/splat/segtypes/n64/img.py index edfb35aa..6bb09a68 100644 --- a/src/splat/segtypes/n64/img.py +++ b/src/splat/segtypes/n64/img.py @@ -64,6 +64,10 @@ def check_len(self) -> None: log.error( f"Error: {self.name} should end at 0x{self.rom_start + expected_len:X}, but it ends at 0x{self.rom_end:X}\n(hint: add a 'bin' segment after it)" ) + elif actual_len < expected_len: + log.error( + f"Error: {self.name} should end at 0x{self.rom_start + expected_len:X}, but it ends at 0x{self.rom_end:X}" + ) def out_path(self) -> Path: type_extension = f".{self.type}" if self.image_type_in_extension else "" diff --git a/src/splat/segtypes/n64/palette.py b/src/splat/segtypes/n64/palette.py index 046a7cd6..de0d830b 100644 --- a/src/splat/segtypes/n64/palette.py +++ b/src/splat/segtypes/n64/palette.py @@ -23,7 +23,21 @@ def __init__(self, *args, **kwargs): f"segment {self.name} needs to know where it ends; add a position marker [0xDEADBEEF] after it" ) - if not isinstance(self.yaml, dict) or "size" not in self.yaml: + if isinstance(self.yaml, dict) and "size" in self.yaml: + yaml_size: int = self.yaml["size"] + if isinstance(self.rom_start, int) and isinstance(self.rom_end, int): + rom_len = self.rom_end - self.rom_start + if rom_len < yaml_size: + log.error( + f"Error: {self.name} has a `size` value of 0x{yaml_size:X}, but this is smaller than the actual rom size of the palette (0x{rom_len:X}, start: 0x{self.rom_start:X}, end: 0x{self.rom_end:X})" + ) + elif rom_len > yaml_size: + log.error( + f"Warning: {self.name} has a `size` value of 0x{yaml_size:X}, but this is larger than the end of the palette (0x{rom_len:X}, start: 0x{self.rom_start:X}, end: 0x{self.rom_end:X})\n(hint add a 'bin' segment after this palette with address 0x{self.rom_end:X})", + ) + + size = yaml_size + else: assert self.rom_end is not None assert self.rom_start is not None actual_len = self.rom_end - self.rom_start @@ -39,7 +53,11 @@ def __init__(self, *args, **kwargs): log.error( f"Error: {self.name} (0x{actual_len:X} bytes) is not a valid palette size ({', '.join(hex(s) for s in VALID_SIZES)})\n{hint_msg}" ) + size = actual_len + else: + size = 0 + self.palette_size: int = size self.global_id: Optional[str] = ( self.yaml.get("global_id") if isinstance(self.yaml, dict) else None ) @@ -61,7 +79,8 @@ def iter_in_groups(iterable, n, fillvalue=None): return palette def parse_palette(self, rom_bytes) -> List[Tuple[int, int, int, int]]: - data = rom_bytes[self.rom_start : self.rom_end] + assert self.rom_start is not None + data = rom_bytes[self.rom_start : self.rom_start + self.palette_size] return N64SegPalette.parse_palette_bytes(data)