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('resourceFile', help='file to be decompiled')
parser.add_argument('-ascii', action='store_true', help='guarantee ASCII output') 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('-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() args = parser.parse_args()
with open(args.resourceFile, 'rb') as f: 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: 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: except BrokenPipeError:
pass # like we get when we pipe into head 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('-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('-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('-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() args = parser.parse_args()
resources = [] resources = []
for in_path in args.rezFile: for in_path in args.rezFile:
with open(in_path, 'rb') as f: 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: 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 import enum
FAKE_HEADER_RSRC_NAME = 'Header as fake resource (not for Rez)'
MAP = bytearray(range(256)) MAP = bytearray(range(256))
for i in range(32): MAP[i] = ord('.') for i in range(32): MAP[i] = ord('.')
MAP[127] = 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) 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.""" """Get an iterator of Resource objects from a binary resource file."""
if not from_resfile: # empty resource forks are fine if not from_resfile: # empty resource forks are fine
return 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) 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) 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)) 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).""" """Get an iterator of Resource objects from code in a subset of the Rez language (bytes or str)."""
try: try:
@ -228,7 +234,7 @@ def parse_rez_code(from_rezcode):
pass 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.""" """Pack an iterator of Resource objects into a binary resource file."""
class wrap: class wrap:
@ -240,6 +246,12 @@ def make_file(from_iter, align=1):
data_offset = len(accum) data_offset = len(accum)
bigdict = collections.OrderedDict() # maintain order of types, but manually order IDs bigdict = collections.OrderedDict() # maintain order of types, but manually order IDs
for r in from_iter: 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) wrapped = wrap(r)
while len(accum) % align: while len(accum) % align:
@ -310,7 +322,7 @@ def make_file(from_iter, align=1):
return bytes(accum) 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). """Express an iterator of Resource objects as Rez code (bytes).
This will match the output of the deprecated Rez utility, unless the 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) 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)) lines.append(b'data %s (%s) {' % (fourcc, args))
step = 16 step = 16
@ -361,6 +375,8 @@ def make_rez_code(from_iter, ascii_clean=False):
lines.append(line) lines.append(line)
lines.append(b'};') lines.append(b'};')
if fake_header_rsrc and resource.name == FAKE_HEADER_RSRC_NAME:
lines.append(b'#endif')
lines.append(b'') lines.append(b'')
if lines: lines.append(b'') # hack, because all posix lines end with a newline if lines: lines.append(b'') # hack, because all posix lines end with a newline