Support compressed resources

This commit is contained in:
Elliot Nunn 2018-11-10 18:05:43 +08:00
parent f0ba2cba57
commit bda55a52b2
2 changed files with 25 additions and 8 deletions

View File

@ -16,6 +16,7 @@ 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') parser.add_argument('-fakehdr', action='store_true', help='output header as fake resource')
parser.add_argument('-compcmt', action='store_true', help='helpfully comment compressed resources')
args = parser.parse_args() args = parser.parse_args()
@ -23,6 +24,7 @@ with open(args.resourceFile, 'rb') as f:
resources = macresources.parse_file(f.read(), fake_header_rsrc=args.fakehdr) 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, fake_header_rsrc=args.fakehdr)) rez = macresources.make_rez_code(resources, ascii_clean=args.ascii, fake_header_rsrc=args.fakehdr, cmt_unsupported_attrib=args.compcmt)
sys.stdout.buffer.write(rez)
except BrokenPipeError: except BrokenPipeError:
pass # like we get when we pipe into head pass # like we get when we pipe into head

View File

@ -91,10 +91,13 @@ class ResourceAttrs(enum.IntFlag):
_changed = 0x02 # marks a resource that has been changes since loading from file (should not be seen on disk) _changed = 0x02 # marks a resource that has been changes since loading from file (should not be seen on disk)
_compressed = 0x01 # "indicates that the resource data is compressed" (only documented in https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format) _compressed = 0x01 # "indicates that the resource data is compressed" (only documented in https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format)
def _for_derez(self): def _for_derez(self, cmt_unsupported=True):
for possible in self.__class__: mylist = [p.name for p in self.__class__ if self & p]
if not possible.name.startswith('_') and self & possible: if any(p.startswith('_') for p in mylist):
yield possible.name arg = '$%02X' % self
if cmt_unsupported: arg += ' /*%s*/' % ', '.join(mylist)
mylist = [arg]
return mylist
class Resource: class Resource:
@ -184,6 +187,12 @@ def parse_rez_code(from_rezcode, fake_header_rsrc=False):
for line in from_rezcode.split(b'\n'): for line in from_rezcode.split(b'\n'):
line = line.lstrip() line = line.lstrip()
while b'/*' in line:
a, b, c = line.partition(b'/*')
d, e, f = c.partition(b'*/')
line = a + f
if line.startswith(b'data '): if line.startswith(b'data '):
try: try:
yield cur_resource yield cur_resource
@ -219,7 +228,13 @@ def parse_rez_code(from_rezcode, fake_header_rsrc=False):
if argtype == 'string': if argtype == 'string':
rsrcname = arg.decode('mac_roman') rsrcname = arg.decode('mac_roman')
else: else:
rsrcattrs |= getattr(ResourceAttrs, arg.decode('ascii')) if arg.startswith(b'$'):
newattr = int(arg[1:], 16)
elif arg and arg[0] in b'0123456789':
newattr = int(arg)
else:
newattr = getattr(ResourceAttrs, arg.decode('ascii'))
rsrcattrs |= newattr
cur_resource = Resource(type=rsrctype, id=rsrcid, name=rsrcname, attribs=rsrcattrs) cur_resource = Resource(type=rsrctype, id=rsrcid, name=rsrcname, attribs=rsrcattrs)
@ -322,7 +337,7 @@ def make_file(from_iter, align=1, fake_header_rsrc=False):
return bytes(accum) return bytes(accum)
def make_rez_code(from_iter, ascii_clean=False, fake_header_rsrc=False): def make_rez_code(from_iter, ascii_clean=False, fake_header_rsrc=False, cmt_unsupported_attrib=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
@ -340,7 +355,7 @@ def make_rez_code(from_iter, ascii_clean=False, fake_header_rsrc=False):
args.append(str(resource.id).encode('ascii')) args.append(str(resource.id).encode('ascii'))
if resource.name is not None: if resource.name is not None:
args.append(_rez_escape(resource.name.encode('mac_roman'), singlequote=False, ascii_clean=ascii_clean)) args.append(_rez_escape(resource.name.encode('mac_roman'), singlequote=False, ascii_clean=ascii_clean))
args.extend(x.encode('ascii') for x in resource.attribs._for_derez()) args.extend(x.encode('ascii') for x in resource.attribs._for_derez(cmt_unsupported=cmt_unsupported_attrib))
args = b', '.join(args) args = b', '.join(args)
fourcc = _rez_escape(resource.type, singlequote=True, ascii_clean=ascii_clean) fourcc = _rez_escape(resource.type, singlequote=True, ascii_clean=ascii_clean)