6 Commits

Author SHA1 Message Date
bc4bad678a Bump version to 1.1.2 2018-02-01 11:06:22 +01:00
ee796d0eb1 Support additional resource file attributes
Added the attributes "Resources Locked" and "Printer Driver MultiFinder
Compatible" from ResEdit, as well as more dummy constants (512-16384)
for attributes with no known meaning.
2018-02-01 11:05:25 +01:00
3d802c570f Add python_requires to setup.py 2017-07-14 18:01:38 +02:00
f6e424674d Bump version to 1.1.1 2017-07-14 17:56:07 +02:00
5dbec5d905 Make _hexdump behave more like "hexdump -C" 2017-07-14 14:53:55 +02:00
c207703c9f Fix overflow with empty resource files or empty resource type entries 2017-07-14 13:50:21 +02:00
3 changed files with 55 additions and 25 deletions

View File

@ -85,7 +85,8 @@ Command-line interface
$ python3 -m rsrcfork /Users/Shared/Test.textClipping "'TEXT' (256)"
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|
00000010 74 |t |
00000010 74 |t|
00000011
Limitations
@ -138,6 +139,18 @@ __ https://archive.fo/
Changelog
---------
Version 1.1.2
`````````````
* Added support for the resource file attributes "Resources Locked" and "Printer Driver MultiFinder Compatible" from ResEdit.
* Added more dummy constants for resource attributes with unknown meaning, so that resource files containing such attributes can be loaded without errors.
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
`````````````

View File

@ -22,7 +22,7 @@ __all__ = [
"open",
]
__version__ = "1.1.0"
__version__ = "1.1.2"
# Translation table to replace ASCII non-printable characters with periods.
_TRANSLATE_NONPRINTABLES = {k: "." for k in [*range(0x20), 0x7f]}
@ -79,6 +79,14 @@ STRUCT_RESOURCE_NAME_HEADER = struct.Struct(">B")
class ResourceFileAttrs(enum.Flag):
"""Resource file attribute flags. The descriptions for these flags are taken from comments on the map*Bit and map* enum constants in <CarbonCore/Resources.h>."""
mapResourcesLocked = 32768 # "Resources Locked" (undocumented, but available as a checkbox in ResEdit)
_UNKNOWN_16384 = 16384
_UNKNOWN_8192 = 8192
_UNKNOWN_4096 = 4096
_UNKNOWN_2048 = 2048
_UNKNOWN_1024 = 1024
_UNKNOWN_512 = 512
mapPrinterDriverMultiFinderCompatible = 256 # "Printer Driver MultiFinder Compatible" (undocumented, but available as a checkbox in ResEdit)
mapReadOnly = 128 # "is this file read-only?", "Resource file read-only"
mapCompact = 64 # "Is a compact necessary?", "Compact resource file"
mapChanged = 32 # "Is it necessary to write map?", "Write map out at update"
@ -345,14 +353,16 @@ class ResourceFile(collections.abc.Mapping):
self._reference_counts: typing.MutableMapping[bytes, int] = collections.OrderedDict()
(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,
count_m1,
reflist_offset,
) = 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):
"""Read all resource references, starting at the current stream position."""
@ -575,7 +585,10 @@ def _hexdump(data: bytes):
line = data[i:i + 16]
line_hex = " ".join(f"{byte:02x}" for byte in line)
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):
for i in range(0, len(data), 16):
@ -745,25 +758,28 @@ def main(args: typing.Sequence[str]):
else:
print("No file attributes")
print(f"{len(rf)} resource types:")
for typecode, resources in rf.items():
restype = _bytes_escape(typecode, quote="'")
print(f"'{restype}': {len(resources)} resources:")
for resid, res in rf[typecode].items():
if res.name is None:
name = "unnamed"
else:
name = _bytes_escape(res.name, quote='"')
name = f'name "{name}"'
attrs = _decompose_flags(res.attributes)
if attrs:
attrdesc = " | ".join(attr.name for attr in attrs)
else:
attrdesc = "no attributes"
print(f"({resid}), {name}, {attrdesc}, {len(res.data)} bytes")
print()
if len(rf) > 0:
print(f"{len(rf)} resource types:")
for typecode, resources in rf.items():
restype = _bytes_escape(typecode, quote="'")
print(f"'{restype}': {len(resources)} resources:")
for resid, res in rf[typecode].items():
if res.name is None:
name = "unnamed"
else:
name = _bytes_escape(res.name, quote='"')
name = f'name "{name}"'
attrs = _decompose_flags(res.attributes)
if attrs:
attrdesc = " | ".join(attr.name for attr in attrs)
else:
attrdesc = "no attributes"
print(f"({resid}), {name}, {attrdesc}, {len(res.data)} bytes")
print()
else:
print("No resource types (empty resource file)")
sys.exit(0)

View File

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