-
Notifications
You must be signed in to change notification settings - Fork 14
/
rom_info.py
100 lines (80 loc) · 3.29 KB
/
rom_info.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
from enum import Enum
from tabnanny import check
import struct
class Checksums(Enum):
OOT_NTSC_10 = "EC7011B7"
OOT_NTSC_11 = "D43DA81F"
OOT_NTSC_12 = "693BA2AE"
OOT_PAL_10 = "B044B569"
OOT_PAL_11 = "B2055FBD"
OOT_NTSC_JP_GC_CE = "F7F52DB8"
OOT_NTSC_JP_GC = "F611F4BA"
OOT_NTSC_US_GC = "F3DD35BA"
OOT_PAL_GC = "09465AC3"
OOT_NTSC_JP_MQ = "F43B45BA"
OOT_NTSC_US_MQ = "F034001A"
OOT_PAL_MQ = "1D4136F3"
OOT_PAL_GC_DBG1 = "871E1C92"
OOT_PAL_GC_DBG2 = "87121EFE"
OOT_PAL_GC_MQ_DBG = "917D18F6"
OOT_IQUE_TW = "3D81FB3E"
OOT_IQUE_CN = "B1E1E07B"
OOT_UNKNOWN = "FFFFFFFF"
@classmethod
def has_value(self, value):
return value in self._value2member_map_
class RomVersion:
def __init__(self, file_table_path, file_table_off, xml_ver):
self.file_table_off = file_table_off
self.xml_ver = xml_ver
with open(file_table_path, 'r') as f:
self.file_table = [line.strip('\n') for line in f]
ROM_INFO_TABLE = dict()
ROM_INFO_TABLE[Checksums.OOT_PAL_GC] = RomVersion("CFG/filelists/gamecube_pal.txt", 0x7170, "GC_NMQ_PAL_F")
ROM_INFO_TABLE[Checksums.OOT_PAL_MQ] = RomVersion("CFG/filelists/gamecube_pal.txt", 0x7170, "GC_MQ_PAL_F")
ROM_INFO_TABLE[Checksums.OOT_PAL_GC_DBG1] = RomVersion("CFG/filelists/dbg.txt", 0x12F70, "GC_NMQ_D")
ROM_INFO_TABLE[Checksums.OOT_PAL_GC_MQ_DBG] = RomVersion("CFG/filelists/dbg.txt", 0x12F70, "GC_MQ_D")
ROM_INFO_TABLE[Checksums.OOT_PAL_10] = RomVersion("CFG/filelists/pal_oot.txt", 0x7950, "N64_PAL_10")
ROM_INFO_TABLE[Checksums.OOT_PAL_11] = RomVersion("CFG/filelists/pal_oot.txt", 0x7950, "N64_PAL_11")
class RomDmaEntry:
def __init__(self, rom, i):
off = rom.version.file_table_off + 16 * i
(self.virtStart, \
self.virtEnd, \
self.physStart, \
self.physEnd) = struct.unpack('>IIII', rom.rom_data[off:off+4*4])
self.compressed = self.physEnd != 0
self.size = self.physEnd - self.physStart \
if self.compressed \
else self.virtEnd - self.virtStart
self.name = rom.version.file_table[i]
class Z64Rom:
def __init__(self, file_path):
self.file_path = file_path
with open(file_path, 'rb') as f:
self.rom_data = f.read()
self.is_valid = len(self.rom_data) > 20 * 1024 * 1024
if not self.is_valid:
return
# get checkum
checksum_str = self.rom_data[16:16+4].hex().upper()
self.checksum = Checksums(checksum_str) if Checksums.has_value(checksum_str) else Checksums.OOT_UNKNOWN
if self.checksum == Checksums.OOT_UNKNOWN:
self.is_valid = False
return
if self.checksum in [Checksums.OOT_NTSC_JP_MQ, Checksums.OOT_NTSC_US_MQ, Checksums.OOT_PAL_GC_MQ_DBG, Checksums.OOT_PAL_MQ]:
self.isMq = True
else:
self.isMq = False
# get rom version
self.version = ROM_INFO_TABLE[self.checksum]
def getDmaEntryByIndex(self, i):
return RomDmaEntry(self, i)
def readDmaEntry(self, entry):
return self.rom_data[entry.physStart:entry.physStart + entry.size]
@staticmethod
def isValidRom(rom_path):
return Z64Rom(rom_path).is_valid
@staticmethod
def isMqRom(rom_path):
return Z64Rom(rom_path).isMq