4 Commits

3 changed files with 41 additions and 25 deletions

View File

@ -85,7 +85,8 @@ Command-line interface
$ python3 -m rsrcfork /Users/Shared/Test.textClipping "'TEXT' (256)" $ python3 -m rsrcfork /Users/Shared/Test.textClipping "'TEXT' (256)"
Resource 'TEXT' (256), unnamed, no attributes, 17 bytes: Resource 'TEXT' (256), unnamed, no attributes, 17 bytes:
00000000 48 65 72 65 20 69 73 20 73 6f 6d 65 20 74 65 78 |Here is some tex| 00000000 48 65 72 65 20 69 73 20 73 6f 6d 65 20 74 65 78 |Here is some tex|
00000010 74 |t | 00000010 74 |t|
00000011
Limitations Limitations
@ -138,6 +139,12 @@ __ https://archive.fo/
Changelog Changelog
--------- ---------
Version 1.1.1
`````````````
* Fixed overflow issue with empty resource files or empty resource type entries
* Changed ``_hexdump`` to behave more like ``hexdump -C``
Version 1.1.0 Version 1.1.0
````````````` `````````````

View File

@ -22,7 +22,7 @@ __all__ = [
"open", "open",
] ]
__version__ = "1.1.0" __version__ = "1.1.1"
# Translation table to replace ASCII non-printable characters with periods. # Translation table to replace ASCII non-printable characters with periods.
_TRANSLATE_NONPRINTABLES = {k: "." for k in [*range(0x20), 0x7f]} _TRANSLATE_NONPRINTABLES = {k: "." for k in [*range(0x20), 0x7f]}
@ -345,14 +345,16 @@ class ResourceFile(collections.abc.Mapping):
self._reference_counts: typing.MutableMapping[bytes, int] = collections.OrderedDict() self._reference_counts: typing.MutableMapping[bytes, int] = collections.OrderedDict()
(type_list_length_m1,) = self._stream_unpack(STRUCT_RESOURCE_TYPE_LIST_HEADER) (type_list_length_m1,) = self._stream_unpack(STRUCT_RESOURCE_TYPE_LIST_HEADER)
type_list_length = (type_list_length_m1 + 1) % 0x10000
for _ in range(type_list_length_m1 + 1): for _ in range(type_list_length):
( (
resource_type, resource_type,
count_m1, count_m1,
reflist_offset, reflist_offset,
) = self._stream_unpack(STRUCT_RESOURCE_TYPE) ) = self._stream_unpack(STRUCT_RESOURCE_TYPE)
self._reference_counts[resource_type] = count_m1 + 1 count = (count_m1 + 1) % 0x10000
self._reference_counts[resource_type] = count
def _read_all_references(self): def _read_all_references(self):
"""Read all resource references, starting at the current stream position.""" """Read all resource references, starting at the current stream position."""
@ -575,7 +577,10 @@ def _hexdump(data: bytes):
line = data[i:i + 16] line = data[i:i + 16]
line_hex = " ".join(f"{byte:02x}" for byte in line) line_hex = " ".join(f"{byte:02x}" for byte in line)
line_char = line.decode("MacRoman").translate(_TRANSLATE_NONPRINTABLES) line_char = line.decode("MacRoman").translate(_TRANSLATE_NONPRINTABLES)
print(f"{i:08x} {line_hex:<{16*2+15}} |{line_char:<16}|") print(f"{i:08x} {line_hex:<{16*2+15}} |{line_char}|")
if data:
print(f"{len(data):08x}")
def _raw_hexdump(data: bytes): def _raw_hexdump(data: bytes):
for i in range(0, len(data), 16): for i in range(0, len(data), 16):
@ -745,25 +750,28 @@ def main(args: typing.Sequence[str]):
else: else:
print("No file attributes") print("No file attributes")
print(f"{len(rf)} resource types:") if len(rf) > 0:
for typecode, resources in rf.items(): print(f"{len(rf)} resource types:")
restype = _bytes_escape(typecode, quote="'") for typecode, resources in rf.items():
print(f"'{restype}': {len(resources)} resources:") restype = _bytes_escape(typecode, quote="'")
for resid, res in rf[typecode].items(): print(f"'{restype}': {len(resources)} resources:")
if res.name is None: for resid, res in rf[typecode].items():
name = "unnamed" if res.name is None:
else: name = "unnamed"
name = _bytes_escape(res.name, quote='"') else:
name = f'name "{name}"' name = _bytes_escape(res.name, quote='"')
name = f'name "{name}"'
attrs = _decompose_flags(res.attributes)
if attrs: attrs = _decompose_flags(res.attributes)
attrdesc = " | ".join(attr.name for attr in attrs) if attrs:
else: attrdesc = " | ".join(attr.name for attr in attrs)
attrdesc = "no attributes" else:
attrdesc = "no attributes"
print(f"({resid}), {name}, {attrdesc}, {len(res.data)} bytes")
print() print(f"({resid}), {name}, {attrdesc}, {len(res.data)} bytes")
print()
else:
print("No resource types (empty resource file)")
sys.exit(0) sys.exit(0)

View File

@ -7,7 +7,7 @@ with open("README.rst", "r", encoding="utf-8") as f:
setuptools.setup( setuptools.setup(
name="rsrcfork", name="rsrcfork",
version="1.1.0", version="1.1.1",
description="A pure Python library for reading old Macintosh resource manager data", description="A pure Python library for reading old Macintosh resource manager data",
long_description=long_description, long_description=long_description,
url="https://github.com/dgelessus/python-rsrcfork", url="https://github.com/dgelessus/python-rsrcfork",
@ -26,5 +26,6 @@ setuptools.setup(
"Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.6",
], ],
keywords="rsrc fork resource manager macintosh mac macos", keywords="rsrc fork resource manager macintosh mac macos",
python_requires=">=3.6",
py_modules=["rsrcfork"], py_modules=["rsrcfork"],
) )