1
0
mirror of https://github.com/zeldaret/oot.git synced 2024-09-21 04:24:43 +00:00

Syms DMA Entries Extraction Support (#1708)

* Archive compression support + small cleanups

* UNSET spec and PR comment

* UNSET -> SYMS

* Syms comment

* PR review

* remove stderr

* Format

* format2

* Remove trailing ,s
This commit is contained in:
Derek Hensley 2024-02-12 17:10:20 -08:00 committed by GitHub
parent 6c405b6ea3
commit 0ac4448d99
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 35 additions and 14 deletions

View File

@ -8,7 +8,6 @@ from __future__ import annotations
import argparse import argparse
from pathlib import Path from pathlib import Path
import dataclasses import dataclasses
import struct
import time import time
import multiprocessing import multiprocessing
import multiprocessing.pool import multiprocessing.pool
@ -28,6 +27,7 @@ class RomSegment:
vrom_start: int vrom_start: int
vrom_end: int vrom_end: int
is_compressed: bool is_compressed: bool
is_syms: bool
data: memoryview | None data: memoryview | None
data_async: multiprocessing.pool.AsyncResult | None data_async: multiprocessing.pool.AsyncResult | None
@ -92,6 +92,7 @@ def compress_rom(
dma_entry.vrom_start, dma_entry.vrom_start,
dma_entry.vrom_end, dma_entry.vrom_end,
is_compressed, is_compressed,
dma_entry.is_syms(),
segment_data, segment_data,
segment_data_async, segment_data_async,
) )
@ -167,17 +168,23 @@ def compress_rom(
assert i <= len(compressed_rom_data) assert i <= len(compressed_rom_data)
compressed_rom_data[segment_rom_start:i] = segment.data compressed_rom_data[segment_rom_start:i] = segment.data
rom_offset = segment_rom_end
if segment.is_syms:
segment_rom_start = 0xFFFFFFFF
segment_rom_end = 0xFFFFFFFF
elif not segment.is_compressed:
segment_rom_end = 0
compressed_rom_dma_entries.append( compressed_rom_dma_entries.append(
dmadata.DmaEntry( dmadata.DmaEntry(
segment.vrom_start, segment.vrom_start,
segment.vrom_end, segment.vrom_end,
segment_rom_start, segment_rom_start,
segment_rom_end if segment.is_compressed else 0, segment_rom_end,
) )
) )
rom_offset = segment_rom_end
assert rom_offset == compressed_rom_size assert rom_offset == compressed_rom_size
# Pad the compressed rom with the pattern matching the baseroms # Pad the compressed rom with the pattern matching the baseroms
for i in range(compressed_rom_size, compressed_rom_size_padded): for i in range(compressed_rom_size, compressed_rom_size_padded):

View File

@ -5,11 +5,11 @@
from __future__ import annotations from __future__ import annotations
import argparse
import hashlib import hashlib
import io import io
import struct
from pathlib import Path from pathlib import Path
import argparse import struct
import crunch64 import crunch64
import ipl3checksum import ipl3checksum
@ -67,7 +67,7 @@ def decompress_rom(
v_end = dma_entry.vrom_end v_end = dma_entry.vrom_end
p_start = dma_entry.rom_start p_start = dma_entry.rom_start
p_end = dma_entry.rom_end p_end = dma_entry.rom_end
if p_start == 0xFFFFFFFF and p_end == 0xFFFFFFFF: if dma_entry.is_syms():
new_dmadata.append(dma_entry) new_dmadata.append(dma_entry)
continue continue
if dma_entry.is_compressed(): if dma_entry.is_compressed():
@ -160,9 +160,9 @@ def find_baserom(version: str) -> Path | None:
def main(): def main():
description = "Convert a rom that uses dmadata to an uncompressed one." parser = argparse.ArgumentParser(
description="Convert a rom that uses dmadata to an uncompressed one."
parser = argparse.ArgumentParser(description=description) )
parser.add_argument( parser.add_argument(
"version", "version",
help="Version of the game to decompress.", help="Version of the game to decompress.",
@ -245,7 +245,7 @@ def main():
exit(1) exit(1)
# Write out our new ROM # Write out our new ROM
print(f"Writing new ROM {uncompressed_path}.") print(f"Writing new ROM {uncompressed_path}...")
uncompressed_path.write_bytes(file_content) uncompressed_path.write_bytes(file_content)
print("Done!") print("Done!")

View File

@ -58,6 +58,14 @@ class DmaEntry:
def is_compressed(self) -> bool: def is_compressed(self) -> bool:
return self.rom_end != 0 return self.rom_end != 0
def is_syms(self) -> bool:
"""
"SYMS" DMA entries describe segments that are always filled with 0's in the ROM.
The DMA entry has both rom_start and rom_end set to 0xFFFFFFFF, where the actual rom start and end is given by vrom_start and vrom_end instead.
These zeroed segments are used to record the offsets/sizes of subfiles in compressed yaz0 archive files but are not used by the game directly.
"""
return self.rom_start == 0xFFFFFFFF and self.rom_end == 0xFFFFFFFF
DMA_ENTRY_END = DmaEntry(0, 0, 0, 0) DMA_ENTRY_END = DmaEntry(0, 0, 0, 0)

View File

@ -56,12 +56,15 @@ def main():
args.output_dir.mkdir(parents=True, exist_ok=True) args.output_dir.mkdir(parents=True, exist_ok=True)
for dma_name, dma_entry in zip(dma_names, dma_entries): for dma_name, dma_entry in zip(dma_names, dma_entries):
if dma_entry.is_compressed(): if dma_entry.is_syms():
segment_rom_start = dma_entry.vrom_start
elif not dma_entry.is_compressed():
segment_rom_start = dma_entry.rom_start
else: # Segment compressed
print(f"Error: segment {dma_name} is compressed", file=sys.stderr) print(f"Error: segment {dma_name} is compressed", file=sys.stderr)
exit(1) exit(1)
segment_rom_start = dma_entry.rom_start segment_rom_end = segment_rom_start + (
segment_rom_end = dma_entry.rom_start + (
dma_entry.vrom_end - dma_entry.vrom_start dma_entry.vrom_end - dma_entry.vrom_start
) )

View File

@ -85,6 +85,8 @@ static bool parse_flags(char *str, unsigned int *flags)
f |= FLAG_RAW; f |= FLAG_RAW;
else if (strcmp(str, "NOLOAD") == 0) else if (strcmp(str, "NOLOAD") == 0)
f |= FLAG_NOLOAD; f |= FLAG_NOLOAD;
else if (strcmp(str, "SYMS") == 0)
f |= FLAG_SYMS;
else else
return false; return false;

View File

@ -28,6 +28,7 @@ enum {
FLAG_OBJECT = (1 << 1), FLAG_OBJECT = (1 << 1),
FLAG_RAW = (1 << 2), FLAG_RAW = (1 << 2),
FLAG_NOLOAD = (1 << 3), FLAG_NOLOAD = (1 << 3),
FLAG_SYMS = (1 << 4)
}; };
struct Include { struct Include {