mirror of
https://github.com/dgelessus/python-rsrcfork.git
synced 2025-07-03 00:23:56 +00:00
Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
bc4bad678a | |||
ee796d0eb1 | |||
3d802c570f | |||
f6e424674d | |||
5dbec5d905 | |||
c207703c9f |
15
README.rst
15
README.rst
@ -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
|
||||
`````````````
|
||||
|
||||
|
62
rsrcfork.py
62
rsrcfork.py
@ -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)
|
||||
|
||||
|
3
setup.py
3
setup.py
@ -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"],
|
||||
)
|
||||
|
Reference in New Issue
Block a user