mirror of
https://github.com/elliotnunn/enablifier.git
synced 2025-02-17 05:31:09 +00:00
Initial commit
This commit is contained in:
commit
88b93fe9ff
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
.DS_Store
|
20
README.md
Normal file
20
README.md
Normal file
@ -0,0 +1,20 @@
|
||||
*Enablifier*: add a System Enabler to a Mac OS ROM file
|
||||
=======================================================
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
The destination file must first contain an Open Firmware bootinfo image (<https://github.com/elliotnunn/newworld-rom>). System Enabler data will be copied from the source file to the destination file's data and resource forks. This tool is *idempotent*: existing enabler data will be removed from the destination.
|
||||
|
||||
enablify SOURCE-ENABLER DEST-FILE
|
||||
|
||||
Example:
|
||||
|
||||
cp tbxi tbxi-enabler
|
||||
enablify templates/mac-os-rom-9.6.1 tbxi-enabler
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
- Python 3
|
||||
- Rez and DeRez (part of Apple's Command Line Developer Tools)
|
153
enablify
Executable file
153
enablify
Executable file
@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from zlib import adler32
|
||||
from subprocess import run, DEVNULL, PIPE
|
||||
from sys import argv
|
||||
from os.path import exists
|
||||
from shutil import copyfile
|
||||
import tempfile
|
||||
|
||||
MAGIC = b'Joy!peffpwpc'
|
||||
RFORK = '/..namedfork/rsrc'
|
||||
|
||||
|
||||
# def copyfile(a, b):
|
||||
# run(['cp', a, b], check=True, stderr=DEVNULL)
|
||||
|
||||
|
||||
def _get_info_size(b):
|
||||
a, b, c = b.partition(b'constant info-size')
|
||||
a, b, c = a.rpartition(b'h#')
|
||||
return int(c, 16)
|
||||
|
||||
|
||||
def _get_cfrg_resources(path, *args):
|
||||
cfrg_derez = run(['DeRez', '-only', 'cfrg', *args, path], check=True, stdout=PIPE).stdout
|
||||
|
||||
line_groups = []
|
||||
for l in cfrg_derez.split(b'\n'):
|
||||
if not l: continue
|
||||
|
||||
if l.startswith(b'data'):
|
||||
line_groups.append([l])
|
||||
else:
|
||||
line_groups[-1].append(l)
|
||||
|
||||
cfrg_tuples = [] # list of (firstline, lastline, binary)
|
||||
for l in line_groups:
|
||||
if not l[-1].startswith(b'}'): raise ValueError
|
||||
|
||||
accum = bytearray()
|
||||
for dl in l:
|
||||
if not dl.lstrip().startswith(b'$'): continue
|
||||
_, _, h = dl.partition(b'$"')
|
||||
h, _, _ = h.rpartition(b'"')
|
||||
h = h.decode('ascii')
|
||||
h = bytes.fromhex(h)
|
||||
accum.extend(h)
|
||||
|
||||
cfrg_tuples.append((l[0], l[-1], accum))
|
||||
|
||||
return cfrg_tuples
|
||||
|
||||
|
||||
def _save_cfrg_resources(path, the_resources):
|
||||
savestr = bytearray()
|
||||
|
||||
for firstline, lastline, data in the_resources:
|
||||
savestr.extend(firstline)
|
||||
savestr.extend(b'\n')
|
||||
savestr.extend(b'$"' + data.hex().encode('ascii') + b'"\n')
|
||||
# for b in data:
|
||||
# savestr.extend((' $"%02x"\n' % b).encode('ascii'))
|
||||
savestr.extend(lastline)
|
||||
savestr.extend(b'\n')
|
||||
|
||||
# run(['cat'], check=True, input=savestr)
|
||||
with tempfile.NamedTemporaryFile(mode='wb') as f:
|
||||
f.write(savestr)
|
||||
f.flush()
|
||||
run(['Rez', '-a', '-o', path, f.name], check=True)
|
||||
|
||||
|
||||
# return (start, stop)
|
||||
def _get_code_fragment_range(b):
|
||||
NASTY = b'\r\\ h#'
|
||||
info_size = _get_info_size(b)
|
||||
the_start = b.find(MAGIC, info_size)
|
||||
|
||||
the_end = len(b)
|
||||
if NASTY in b[-100:]:
|
||||
the_end = b.rfind(NASTY)
|
||||
|
||||
return the_start, the_end
|
||||
|
||||
|
||||
def _find_all(a_str, sub):
|
||||
start = 0
|
||||
while True:
|
||||
start = a_str.find(sub, start)
|
||||
if start == -1: return
|
||||
yield start
|
||||
start += len(sub) # use start += 1 to find overlapping matches
|
||||
|
||||
|
||||
def _replace_int32_in_bytearray(b, x, y):
|
||||
x = x.to_bytes(length=4, byteorder='big', signed=False)
|
||||
y = y.to_bytes(length=4, byteorder='big', signed=False)
|
||||
b[:] = b.replace(x, y)
|
||||
|
||||
|
||||
def enablify(orig, dest):
|
||||
with open(orig, 'rb') as f:
|
||||
orig_df = f.read()
|
||||
with open(dest, 'rb') as f:
|
||||
dest_df = bytearray(f.read())
|
||||
|
||||
# trim dest data fork if it already has enabler-related junk at the end
|
||||
dest_info_size = _get_info_size(dest_df)
|
||||
if len(dest_df) > dest_info_size + 20:
|
||||
cut_at = dest_df.find(MAGIC, dest_info_size)
|
||||
del dest_df[cut_at:]
|
||||
|
||||
dest_needs_checksum = b'\r\\ h#' in dest_df[-20:]
|
||||
|
||||
old_offset, old_stop = _get_code_fragment_range(orig_df)
|
||||
|
||||
while len(dest_df) % 16:
|
||||
dest_df.append(0)
|
||||
new_offset = len(dest_df)
|
||||
|
||||
every_sub_offset = list(_find_all(orig_df[old_offset:old_stop], MAGIC))
|
||||
|
||||
the_resources = list(_get_cfrg_resources(orig))
|
||||
|
||||
for _, _, rsrc_data in the_resources:
|
||||
for this_sub_offset in every_sub_offset:
|
||||
# print('Replacing', hex(old_offset + this_sub_offset), 'with', hex(new_offset + this_sub_offset))
|
||||
_replace_int32_in_bytearray(rsrc_data, old_offset + this_sub_offset, new_offset + this_sub_offset)
|
||||
|
||||
dest_df.extend(orig_df[old_offset:old_stop])
|
||||
|
||||
# re-checksum?
|
||||
if dest_needs_checksum:
|
||||
cksum = adler32(dest_df)
|
||||
cksum_str = ('\r\\ h# %08X' % cksum).encode('ascii')
|
||||
dest_df.extend(cksum_str)
|
||||
|
||||
|
||||
with open(dest, 'wb') as f:
|
||||
f.write(dest_df)
|
||||
|
||||
if exists(orig + '.r'):
|
||||
# print('doing the rez thing')
|
||||
run(['Rez', '-o', dest, orig + '.r'], check=True)
|
||||
else:
|
||||
copyfile(orig + RFORK, dest + RFORK)
|
||||
|
||||
_save_cfrg_resources(dest, the_resources)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
orig, dest = argv[1:]
|
||||
enablify(orig, dest)
|
9855
templates/mac-os-rom-9.6.1
Normal file
9855
templates/mac-os-rom-9.6.1
Normal file
File diff suppressed because one or more lines are too long
39098
templates/mac-os-rom-9.6.1.r
Normal file
39098
templates/mac-os-rom-9.6.1.r
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user