Add hack to save the header into a resource

This commit is contained in:
Elliot Nunn 2018-11-09 20:55:06 +08:00
parent 6187243466
commit f0ba2cba57
3 changed files with 26 additions and 8 deletions

View File

@ -15,13 +15,14 @@ parser = argparse.ArgumentParser(description='''
parser.add_argument('resourceFile', help='file to be decompiled')
parser.add_argument('-ascii', action='store_true', help='guarantee ASCII output')
parser.add_argument('-useDF', action='store_true', help='ignored: data fork is always used')
parser.add_argument('-fakehdr', action='store_true', help='output header as fake resource')
args = parser.parse_args()
with open(args.resourceFile, 'rb') as f:
resources = macresources.parse_file(f.read())
resources = macresources.parse_file(f.read(), fake_header_rsrc=args.fakehdr)
try:
sys.stdout.buffer.write(macresources.make_rez_code(resources, ascii_clean=args.ascii))
sys.stdout.buffer.write(macresources.make_rez_code(resources, ascii_clean=args.ascii, fake_header_rsrc=args.fakehdr))
except BrokenPipeError:
pass # like we get when we pipe into head

View File

@ -33,13 +33,14 @@ parser.add_argument('rezFile', nargs='+', help='resource description files')
parser.add_argument('-o', metavar='outputFile', default='Rez.out', help='default: Rez.out')
parser.add_argument('-align', metavar='word | longword | n', action='store', type=parse_align, default=1)
parser.add_argument('-useDF', action='store_true', help='ignored: data fork is always used')
parser.add_argument('-fakehdr', action='store_true', help='accept fake-header resource')
args = parser.parse_args()
resources = []
for in_path in args.rezFile:
with open(in_path, 'rb') as f:
resources.extend(macresources.parse_rez_code(f.read()))
resources.extend(macresources.parse_rez_code(f.read(), fake_header_rsrc=args.fakehdr))
with open(args.o, 'wb') as f:
f.write(macresources.make_file(resources, align=args.align))
f.write(macresources.make_file(resources, align=args.align, fake_header_rsrc=args.fakehdr))

View File

@ -3,6 +3,9 @@ import struct
import enum
FAKE_HEADER_RSRC_NAME = 'Header as fake resource (not for Rez)'
MAP = bytearray(range(256))
for i in range(32): MAP[i] = ord('.')
MAP[127] = ord('.')
@ -123,12 +126,15 @@ class Resource:
return '%s(type=%r, id=%r, name=%r, attribs=%r, data=%s)' % (self.__class__.__name__, self.type, self.id, self.name, self.attribs, datarep)
def parse_file(from_resfile):
def parse_file(from_resfile, fake_header_rsrc=False):
"""Get an iterator of Resource objects from a binary resource file."""
if not from_resfile: # empty resource forks are fine
return
if fake_header_rsrc and any(from_resfile[16:256]):
yield Resource(type=b'????', id=0, name=FAKE_HEADER_RSRC_NAME, data=from_resfile[16:256])
data_offset, map_offset, data_len, map_len = struct.unpack_from('>4L', from_resfile)
typelist_offset, namelist_offset, numtypes = struct.unpack_from('>24xHHH', from_resfile, map_offset)
@ -166,7 +172,7 @@ def parse_file(from_resfile):
yield Resource(type=rtype, id=rid, name=name, attribs=rattribs, data=bytearray(rdata))
def parse_rez_code(from_rezcode):
def parse_rez_code(from_rezcode, fake_header_rsrc=False):
"""Get an iterator of Resource objects from code in a subset of the Rez language (bytes or str)."""
try:
@ -228,7 +234,7 @@ def parse_rez_code(from_rezcode):
pass
def make_file(from_iter, align=1):
def make_file(from_iter, align=1, fake_header_rsrc=False):
"""Pack an iterator of Resource objects into a binary resource file."""
class wrap:
@ -240,6 +246,12 @@ def make_file(from_iter, align=1):
data_offset = len(accum)
bigdict = collections.OrderedDict() # maintain order of types, but manually order IDs
for r in from_iter:
if fake_header_rsrc and r.name == FAKE_HEADER_RSRC_NAME:
if len(r.data) > 256-16:
raise ValueError('Special resource length (%r) too long' % len(r.data))
accum[16:16+len(r.data)] = r.data
continue
wrapped = wrap(r)
while len(accum) % align:
@ -310,7 +322,7 @@ def make_file(from_iter, align=1):
return bytes(accum)
def make_rez_code(from_iter, ascii_clean=False):
def make_rez_code(from_iter, ascii_clean=False, fake_header_rsrc=False):
"""Express an iterator of Resource objects as Rez code (bytes).
This will match the output of the deprecated Rez utility, unless the
@ -333,6 +345,8 @@ def make_rez_code(from_iter, ascii_clean=False):
fourcc = _rez_escape(resource.type, singlequote=True, ascii_clean=ascii_clean)
if fake_header_rsrc and resource.name == FAKE_HEADER_RSRC_NAME:
lines.append(b'#if 0')
lines.append(b'data %s (%s) {' % (fourcc, args))
step = 16
@ -361,6 +375,8 @@ def make_rez_code(from_iter, ascii_clean=False):
lines.append(line)
lines.append(b'};')
if fake_header_rsrc and resource.name == FAKE_HEADER_RSRC_NAME:
lines.append(b'#endif')
lines.append(b'')
if lines: lines.append(b'') # hack, because all posix lines end with a newline