mirror of
https://github.com/zeldaret/oot.git
synced 2024-11-25 01:34:18 +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:
parent
6c405b6ea3
commit
0ac4448d99
6 changed files with 35 additions and 14 deletions
|
@ -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):
|
||||||
|
|
|
@ -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!")
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue