mirror of
https://github.com/notwa/mm
synced 2024-11-05 04:29:03 -08:00
clean, refactor
This commit is contained in:
parent
6e8d3f9bc2
commit
7758bed4ac
4 changed files with 90 additions and 99 deletions
21
chksum.py
21
chksum.py
|
@ -3,13 +3,10 @@
|
||||||
# note: copies are ignored and overwritten, so don't bother editing them.
|
# note: copies are ignored and overwritten, so don't bother editing them.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import struct, array
|
from util import R2, W2, swap_order
|
||||||
|
|
||||||
lament = lambda *args, **kwargs: print(*args, file=sys.stderr, **kwargs)
|
lament = lambda *args, **kwargs: print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
R2 = lambda data: struct.unpack('>H', data)[0]
|
|
||||||
W2 = lambda data: struct.pack('>H', data)
|
|
||||||
|
|
||||||
save_1 = 0x20800
|
save_1 = 0x20800
|
||||||
save_2 = 0x24800
|
save_2 = 0x24800
|
||||||
owl_1 = 0x28800
|
owl_1 = 0x28800
|
||||||
|
@ -59,18 +56,7 @@ def delete_save(f, addr):
|
||||||
# TODO: handle owl size properly
|
# TODO: handle owl size properly
|
||||||
f.write(b'\x00'*save_size)
|
f.write(b'\x00'*save_size)
|
||||||
|
|
||||||
def swap_order(f, size='H'):
|
|
||||||
f.seek(0)
|
|
||||||
a = array.array(size, f.read())
|
|
||||||
a.byteswap()
|
|
||||||
f.seek(0)
|
|
||||||
f.write(a.tobytes())
|
|
||||||
|
|
||||||
def run(args):
|
def run(args):
|
||||||
args = args[1:]
|
|
||||||
if len(args) == 0:
|
|
||||||
lament("TODO: convert stdin to stdout")
|
|
||||||
return 0
|
|
||||||
for fn in args:
|
for fn in args:
|
||||||
with open(fn, 'r+b') as f:
|
with open(fn, 'r+b') as f:
|
||||||
# dumb way to determine byte order
|
# dumb way to determine byte order
|
||||||
|
@ -96,9 +82,8 @@ def run(args):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
ret = 0
|
|
||||||
try:
|
try:
|
||||||
ret = run(sys.argv)
|
ret = run(sys.argv[1:])
|
||||||
|
sys.exit(ret)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
sys.exit(ret)
|
|
||||||
|
|
1
n64.py
1
n64.py
|
@ -81,4 +81,3 @@ def crc(f, bootcode=6105):
|
||||||
def bootcode_version(f):
|
def bootcode_version(f):
|
||||||
f.seek(0x40)
|
f.seek(0x40)
|
||||||
return bootcode_crcs[crc32(f.read(0x1000 - 0x40)) & MAX32]
|
return bootcode_crcs[crc32(f.read(0x1000 - 0x40)) & MAX32]
|
||||||
|
|
||||||
|
|
33
util.py
Normal file
33
util.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import os
|
||||||
|
import struct, array
|
||||||
|
|
||||||
|
R1 = lambda data: struct.unpack('>B', data)[0]
|
||||||
|
R2 = lambda data: struct.unpack('>H', data)[0]
|
||||||
|
R4 = lambda data: struct.unpack('>I', data)[0]
|
||||||
|
W1 = lambda data: struct.pack('>B', data)
|
||||||
|
W2 = lambda data: struct.pack('>H', data)
|
||||||
|
W4 = lambda data: struct.pack('>I', data)
|
||||||
|
|
||||||
|
def dump_as(b, fn):
|
||||||
|
with open(fn, 'w+b') as f:
|
||||||
|
f.write(b)
|
||||||
|
|
||||||
|
def swap_order(f, size='H'):
|
||||||
|
f.seek(0)
|
||||||
|
a = array.array(size, f.read())
|
||||||
|
a.byteswap()
|
||||||
|
f.seek(0)
|
||||||
|
f.write(a.tobytes())
|
||||||
|
|
||||||
|
class SubDir:
|
||||||
|
def __init__(self, d):
|
||||||
|
self.d = d
|
||||||
|
def __enter__(self):
|
||||||
|
self.cwd = os.getcwd()
|
||||||
|
try:
|
||||||
|
os.mkdir(self.d)
|
||||||
|
except FileExistsError:
|
||||||
|
pass
|
||||||
|
os.chdir(self.d)
|
||||||
|
def __exit__(self, type_, value, traceback):
|
||||||
|
os.chdir(self.cwd)
|
134
z64dump.py
134
z64dump.py
|
@ -1,43 +1,19 @@
|
||||||
#!/bin/python
|
#!/bin/python
|
||||||
# shoutouts to spinout182
|
# shoutouts to spinout182
|
||||||
|
|
||||||
import os, os.path
|
|
||||||
import sys
|
import sys
|
||||||
import io
|
import os, os.path
|
||||||
import struct, array
|
from io import BytesIO
|
||||||
import hashlib
|
from hashlib import sha1
|
||||||
|
|
||||||
|
from util import *
|
||||||
import n64
|
import n64
|
||||||
import Yaz0
|
import Yaz0
|
||||||
|
|
||||||
lament = lambda *args, **kwargs: print(*args, file=sys.stderr, **kwargs)
|
lament = lambda *args, **kwargs: print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
R1 = lambda data: struct.unpack('>B', data)[0]
|
|
||||||
R2 = lambda data: struct.unpack('>H', data)[0]
|
|
||||||
R4 = lambda data: struct.unpack('>I', data)[0]
|
|
||||||
W1 = lambda data: struct.pack('>B', data)
|
|
||||||
W2 = lambda data: struct.pack('>H', data)
|
|
||||||
W4 = lambda data: struct.pack('>I', data)
|
|
||||||
|
|
||||||
# assume first entry is makerom (0x1060), and second entry begins from makerom
|
# assume first entry is makerom (0x1060), and second entry begins from makerom
|
||||||
fs_sig = b"\x00\x00\x00\x00\x00\x00\x10\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x60"
|
dma_sig = b"\x00\x00\x00\x00\x00\x00\x10\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x60"
|
||||||
|
|
||||||
class SubDir:
|
|
||||||
def __init__(self, d):
|
|
||||||
self.d = d
|
|
||||||
def __enter__(self):
|
|
||||||
self.cwd = os.getcwd()
|
|
||||||
try:
|
|
||||||
os.mkdir(self.d)
|
|
||||||
except FileExistsError:
|
|
||||||
pass
|
|
||||||
os.chdir(self.d)
|
|
||||||
def __exit__(self, type_, value, traceback):
|
|
||||||
os.chdir(self.cwd)
|
|
||||||
|
|
||||||
def dump_as(b, fn):
|
|
||||||
with open(fn, 'w+b') as f:
|
|
||||||
f.write(b)
|
|
||||||
|
|
||||||
def z_dump_file(f, prefix=None):
|
def z_dump_file(f, prefix=None):
|
||||||
vs = R4(f.read(4)) # virtual start
|
vs = R4(f.read(4)) # virtual start
|
||||||
|
@ -78,24 +54,25 @@ def z_dump_file(f, prefix=None):
|
||||||
f.seek(here)
|
f.seek(here)
|
||||||
return True, fn, vs, ve, ps, pe
|
return True, fn, vs, ve, ps, pe
|
||||||
|
|
||||||
def z_find_fs(f):
|
def z_find_dma(f):
|
||||||
while True:
|
while True:
|
||||||
# assume row alignment
|
# assume row alignment
|
||||||
data = f.read(16)
|
data = f.read(16)
|
||||||
if len(data) == 0: # EOF
|
if len(data) == 0: # EOF
|
||||||
break
|
break
|
||||||
if data == fs_sig[:16]:
|
if data == dma_sig[:16]:
|
||||||
rest = fs_sig[16:]
|
rest = dma_sig[16:]
|
||||||
if f.read(len(rest)) == rest:
|
if f.read(len(rest)) == rest:
|
||||||
return f.tell() - len(rest) - 16
|
return f.tell() - len(rest) - 16
|
||||||
else:
|
else:
|
||||||
f.seek(len(rest), 1)
|
f.seek(len(rest), 1)
|
||||||
|
|
||||||
def z_dump(f):
|
def z_dump(f):
|
||||||
f.seek(0x1060) # skip header when finding fs
|
f.seek(0x1060) # skip header when finding dma
|
||||||
addr = z_find_fs(f)
|
addr = z_find_dma(f)
|
||||||
if addr == None:
|
if addr == None:
|
||||||
raise Exception("couldn't find file offset table")
|
lament("couldn't find file offset table")
|
||||||
|
return
|
||||||
|
|
||||||
f.seek(addr - 0x30)
|
f.seek(addr - 0x30)
|
||||||
build = f.read(0x30).strip(b'\x00').replace(b'\x00', b'\n')
|
build = f.read(0x30).strip(b'\x00').replace(b'\x00', b'\n')
|
||||||
|
@ -106,18 +83,11 @@ def z_dump(f):
|
||||||
while z_dump_file(f, '{:05} '.format(i)):
|
while z_dump_file(f, '{:05} '.format(i)):
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
def swap_order(f, size='H'):
|
|
||||||
f.seek(0)
|
|
||||||
a = array.array(size, f.read())
|
|
||||||
a.byteswap()
|
|
||||||
f.seek(0)
|
|
||||||
f.write(a.tobytes())
|
|
||||||
|
|
||||||
def dump_rom(fn):
|
def dump_rom(fn):
|
||||||
with open(fn, 'rb') as f:
|
with open(fn, 'rb') as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
|
|
||||||
with io.BytesIO(data) as f:
|
with BytesIO(data) as f:
|
||||||
start = f.read(4)
|
start = f.read(4)
|
||||||
if start == b'\x37\x80\x40\x12':
|
if start == b'\x37\x80\x40\x12':
|
||||||
swap_order(f)
|
swap_order(f)
|
||||||
|
@ -126,10 +96,7 @@ def dump_rom(fn):
|
||||||
return
|
return
|
||||||
|
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
data = f.read()
|
outdir = sha1(f.read()).hexdigest()
|
||||||
|
|
||||||
outdir = hashlib.sha1(data).hexdigest()
|
|
||||||
del data
|
|
||||||
|
|
||||||
with SubDir(outdir):
|
with SubDir(outdir):
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
|
@ -138,6 +105,7 @@ def dump_rom(fn):
|
||||||
def z_read_file(path, fn=None):
|
def z_read_file(path, fn=None):
|
||||||
if fn == None:
|
if fn == None:
|
||||||
fn = os.path.basename(path)
|
fn = os.path.basename(path)
|
||||||
|
|
||||||
if len(fn) < 37:
|
if len(fn) < 37:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -159,14 +127,44 @@ def z_read_file(path, fn=None):
|
||||||
|
|
||||||
return True, data, vs, ve, ps, pe
|
return True, data, vs, ve, ps, pe
|
||||||
|
|
||||||
|
def z_write_dma(f, dma):
|
||||||
|
dma.sort(key=lambda vf: vf[0]) # sort by vs
|
||||||
|
assert(len(dma) > 2)
|
||||||
|
dma_entry = dma[2] # assumption
|
||||||
|
vs, ve, ps, pe = dma_entry
|
||||||
|
|
||||||
|
# initialize with zeros
|
||||||
|
dma_size = ve - vs
|
||||||
|
f.seek(ps)
|
||||||
|
f.write(bytearray(dma_size))
|
||||||
|
|
||||||
|
f.seek(ps)
|
||||||
|
for vf in dma:
|
||||||
|
vs, ve, ps, pe = vf
|
||||||
|
#lament('{:08X} {:08X} {:08X} {:08X}'.format(vs, ve, ps, pe))
|
||||||
|
f.write(W4(vs))
|
||||||
|
f.write(W4(ve))
|
||||||
|
f.write(W4(ps))
|
||||||
|
f.write(W4(pe))
|
||||||
|
assert(f.tell() <= (pe or ve))
|
||||||
|
|
||||||
|
def fix_rom(f):
|
||||||
|
bootcode = n64.bootcode_version(f)
|
||||||
|
lament('bootcode:', bootcode)
|
||||||
|
crc1, crc2 = n64.crc(f, bootcode)
|
||||||
|
lament('crcs: {:08X} {:08X}'.format(crc1, crc2))
|
||||||
|
f.seek(0x10)
|
||||||
|
f.write(W4(crc1))
|
||||||
|
f.write(W4(crc2))
|
||||||
|
|
||||||
def create_rom(d):
|
def create_rom(d):
|
||||||
walker = os.walk(d)
|
root, _, files = next(os.walk(d))
|
||||||
root, _, files = next(walker)
|
|
||||||
del walker
|
|
||||||
|
|
||||||
rom_size = 64*1024*1024
|
rom_size = 64*1024*1024
|
||||||
with open(d+'.z64', 'w+b') as f:
|
with open(d+'.z64', 'w+b') as f:
|
||||||
fs = []
|
dma = []
|
||||||
|
|
||||||
|
# initialize with zeros
|
||||||
f.write(bytearray(rom_size))
|
f.write(bytearray(rom_size))
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
|
|
||||||
|
@ -188,37 +186,14 @@ def create_rom(d):
|
||||||
f.seek(vs)
|
f.seek(vs)
|
||||||
f.write(data)
|
f.write(data)
|
||||||
|
|
||||||
fs.append([vs, ve, ps, pe])
|
dma.append([vs, ve, ps, pe])
|
||||||
|
|
||||||
# fix filesystem
|
z_write_dma(f, dma)
|
||||||
fs.sort(key=lambda vf: vf[0]) # sort by vs
|
fix_rom(f)
|
||||||
assert(len(fs) > 2)
|
|
||||||
fs_entry = fs[2] # assumption
|
|
||||||
vs, ve, ps, pe = fs_entry
|
|
||||||
fs_size = ve - vs
|
|
||||||
f.seek(ps)
|
|
||||||
f.write(bytearray(fs_size))
|
|
||||||
f.seek(ps)
|
|
||||||
for vf in fs:
|
|
||||||
vs, ve, ps, pe = vf
|
|
||||||
#lament('{:08X} {:08X} {:08X} {:08X}'.format(vs, ve, ps, pe))
|
|
||||||
f.write(W4(vs))
|
|
||||||
f.write(W4(ve))
|
|
||||||
f.write(W4(ps))
|
|
||||||
f.write(W4(pe))
|
|
||||||
assert(f.tell() <= (pe or ve))
|
|
||||||
|
|
||||||
# fix makerom (n64 header)
|
|
||||||
bootcode = n64.bootcode_version(f)
|
|
||||||
lament('bootcode:', bootcode)
|
|
||||||
crc1, crc2 = n64.crc(f, bootcode)
|
|
||||||
lament('crcs: {:08X} {:08X}'.format(crc1, crc2))
|
|
||||||
f.seek(0x10)
|
|
||||||
f.write(W4(crc1))
|
|
||||||
f.write(W4(crc2))
|
|
||||||
|
|
||||||
def run(args):
|
def run(args):
|
||||||
for path in args:
|
for path in args:
|
||||||
|
# directories are technically files, so check this first
|
||||||
if os.path.isdir(path):
|
if os.path.isdir(path):
|
||||||
create_rom(path)
|
create_rom(path)
|
||||||
elif os.path.isfile(path):
|
elif os.path.isfile(path):
|
||||||
|
@ -227,9 +202,8 @@ def run(args):
|
||||||
lament('no-op:', path)
|
lament('no-op:', path)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
ret = 0
|
|
||||||
try:
|
try:
|
||||||
ret = run(sys.argv[1:])
|
ret = run(sys.argv[1:])
|
||||||
|
sys.exit(ret)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
sys.exit(ret)
|
|
||||||
|
|
Loading…
Reference in a new issue