Include ROM utilities from Grid SRAM dumper project.
This commit is contained in:
parent
9715e3b747
commit
2b5ddaee7b
|
@ -52,3 +52,9 @@ A patch with multiple offsets, and helpful author descriptions for each section:
|
|||
# This part of the patch fixes sound playback issues.
|
||||
256: 33 -> 44
|
||||
```
|
||||
|
||||
## splitrom
|
||||
|
||||
Utility for combining/splitting/byteswapping ROM files. Run it like `./splitrom --help`
|
||||
to see generic help and what commands are available, and like `./splitrom <command> --help`
|
||||
for a specific command's help.
|
||||
|
|
|
@ -261,3 +261,38 @@ class BinaryDiff:
|
|||
|
||||
# Now, get the maximum byte we need to apply this patch.
|
||||
return max([offset for offset, _, _ in differences]) + 1 if differences else 0
|
||||
|
||||
|
||||
class ByteUtil:
|
||||
|
||||
@staticmethod
|
||||
def byteswap(data: bytes) -> bytes:
|
||||
even = [d for d in data[::2]]
|
||||
odd = [d for d in data[1::2]]
|
||||
chunks = [bytes([odd[i], even[i]]) for i in range(len(even))]
|
||||
return b''.join(chunks)
|
||||
|
||||
@staticmethod
|
||||
def wordswap(data: bytes) -> bytes:
|
||||
one = [d for d in data[::4]]
|
||||
two = [d for d in data[1::4]]
|
||||
three = [d for d in data[2::4]]
|
||||
four = [d for d in data[3::4]]
|
||||
chunks = [
|
||||
bytes([four[i], three[i], two[i], one[i]])
|
||||
for i in range(len(one))
|
||||
]
|
||||
return b''.join(chunks)
|
||||
|
||||
@staticmethod
|
||||
def combine16bithalves(upper: bytes, lower: bytes) -> bytes:
|
||||
chunks = [
|
||||
b''.join([upper[i:(i+2)], lower[i:(i+2)]])
|
||||
for i in range(0, len(upper), 2)
|
||||
]
|
||||
return b''.join(chunks)
|
||||
|
||||
@staticmethod
|
||||
def combine8bithalves(upper: bytes, lower: bytes) -> bytes:
|
||||
chunks = [bytes([upper[i], lower[i]]) for i in range(len(upper))]
|
||||
return b''.join(chunks)
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
#! /usr/bin/env python3
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
from arcadeutils.binary import ByteUtil
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser("ROM manipulation utilities.")
|
||||
subparsers = parser.add_subparsers(
|
||||
dest="action",
|
||||
help="Action to perform.",
|
||||
)
|
||||
|
||||
byteswap = subparsers.add_parser(
|
||||
"byteswap",
|
||||
help="Swap every byte pair of a 16bit rom.",
|
||||
)
|
||||
byteswap.add_argument(
|
||||
"old",
|
||||
metavar="OLD",
|
||||
type=str,
|
||||
help="Old rom file to byteswap.",
|
||||
)
|
||||
byteswap.add_argument(
|
||||
"new",
|
||||
metavar="NEW",
|
||||
type=str,
|
||||
help="New rom file to write after byteswapping.",
|
||||
)
|
||||
|
||||
wordswap = subparsers.add_parser(
|
||||
"wordswap",
|
||||
help="Swap every 32bit value in a 32bit rom.",
|
||||
)
|
||||
wordswap.add_argument(
|
||||
"old",
|
||||
metavar="OLD",
|
||||
type=str,
|
||||
help="Old rom file to wordswap.",
|
||||
)
|
||||
wordswap.add_argument(
|
||||
"new",
|
||||
metavar="NEW",
|
||||
type=str,
|
||||
help="New rom file to write after wordswapping.",
|
||||
)
|
||||
|
||||
combine8 = subparsers.add_parser(
|
||||
"combine8",
|
||||
help="Combine two 8bit roms to one 16bit rom.",
|
||||
)
|
||||
combine8.add_argument(
|
||||
"upper",
|
||||
metavar="UPPER",
|
||||
type=str,
|
||||
help="Upper half of rom file.",
|
||||
)
|
||||
combine8.add_argument(
|
||||
"lower",
|
||||
metavar="LOWER",
|
||||
type=str,
|
||||
help="Lower half of rom file.",
|
||||
)
|
||||
combine8.add_argument(
|
||||
"combined",
|
||||
metavar="COMBINED",
|
||||
type=str,
|
||||
help="Combined output file.",
|
||||
)
|
||||
|
||||
combine16 = subparsers.add_parser(
|
||||
"combine16",
|
||||
help="Combine two 16bit roms to one 32bit rom.",
|
||||
)
|
||||
combine16.add_argument(
|
||||
"upper",
|
||||
metavar="UPPER",
|
||||
type=str,
|
||||
help="Upper half of rom file.",
|
||||
)
|
||||
combine16.add_argument(
|
||||
"lower",
|
||||
metavar="LOWER",
|
||||
type=str,
|
||||
help="Lower half of rom file.",
|
||||
)
|
||||
combine16.add_argument(
|
||||
"combined",
|
||||
metavar="COMBINED",
|
||||
type=str,
|
||||
help="Combined output file.",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
if args.action == "combine8":
|
||||
with open(args.upper, "rb") as fp:
|
||||
upper = fp.read()
|
||||
with open(args.lower, "rb") as fp:
|
||||
lower = fp.read()
|
||||
with open(args.combined, "wb") as fp:
|
||||
fp.write(ByteUtil.combine8bithalves(upper, lower))
|
||||
elif args.action == "combine16":
|
||||
with open(args.upper, "rb") as fp:
|
||||
upper = fp.read()
|
||||
with open(args.lower, "rb") as fp:
|
||||
lower = fp.read()
|
||||
with open(args.combined, "wb") as fp:
|
||||
fp.write(ByteUtil.combine16bithalves(upper, lower))
|
||||
elif args.action == "byteswap":
|
||||
with open(args.old, "rb") as fp:
|
||||
old = fp.read()
|
||||
with open(args.new, "wb") as fp:
|
||||
fp.write(ByteUtil.byteswap(old))
|
||||
elif args.action == "wordswap":
|
||||
with open(args.old, "rb") as fp:
|
||||
old = fp.read()
|
||||
with open(args.new, "wb") as fp:
|
||||
fp.write(ByteUtil.wordswap(old))
|
||||
else:
|
||||
print(f"Please specify a valid command!{os.linesep}", file=sys.stderr)
|
||||
parser.print_help()
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
Loading…
Reference in New Issue