"""A library for reading old Macintosh resource manager data, as found in resource forks or .rsrc files even on current Mac OS X/macOS systems.
Thislibraryonlyunderstandstheresourcefile's general structure, i. e. the type codes, IDs, attributes, and data of the resources stored in the file. The data of individual resources is provided in raw bytes form and is not processed further - the format of this data is specific to each resource type.
# The formats of all following structures is as described in the Inside Macintosh book (see module docstring).
# Signedness and byte order of the integers is never stated explicitly in IM.
# All integers are big-endian, as this is the native byte order of the 68k and PowerPC processors used in old Macs.
# Almost all integers are non-negative byte counts or offsets, so it only makes sense for them to be unsigned. Sometimes the number -1 is used as a placeholder value, it should be considered equivalent to its two's complement value interpreted as unsigned (i. e. all bits set). The only exception is the resource ID field, which is signed.
# Resource file header, found at the start of the resource file.
# 4 bytes: Offset from beginning of resource file to resource data. Basically guaranteed to be 0x100.
# 4 bytes: Offset from beginning of resource file to resource map.
# 4 bytes: Length of resource data.
# 4 bytes: Length of resource map.
# 112 bytes: System-reserved data. In practice, this is usually all null bytes.
# 128 bytes: Application-specific data. In practice, this is usually all null bytes.
# 4 bytes: Resource type. This is usually a 4-character ASCII mnemonic, but may be any 4 bytes.
# 2 bytes: Number of resources of this type in the map minus 1.
# 2 bytes: Offset from beginning of type list to reference list for resources of this type.
STRUCT_RESOURCE_TYPE=struct.Struct(">4sHH")
# A single resource reference in a reference list. (A reference list has no header, and neither does the list of reference lists.)
# 2 bytes: Resource ID.
# 2 bytes: Offset from beginning of resource name list to length of resource name, or -1 (0xffff) if none.
# 1 byte: Resource attributes. Combination of ResourceAttrs flags, see below. (Note: packed into 4 bytes together with the next 3 bytes.)
# 3 bytes: Offset from beginning of resource data to length of data for this resource. (Note: packed into 4 bytes together with the previous 1 byte.)
# 4 bytes: Reserved for handle to resource (in memory). Should be 0 in file.
STRUCT_RESOURCE_REFERENCE=struct.Struct(">hHI4x")
# Header for a resource name, found immediately before the name itself. (The name list has no header.)
# 1 byte: Length of following resource name.
STRUCT_RESOURCE_NAME_HEADER=struct.Struct(">B")
classResourceFileAttrs(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>."""
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"
_UNKNOWN_16=16
_UNKNOWN_8=8
_UNKNOWN_4=4
_UNKNOWN_2=2
_UNKNWON_1=1
classResourceAttrs(enum.Flag):
"""Resource attribute flags. The descriptions for these flags are taken from comments on the res*Bit and res* enum constants in <CarbonCore/Resources.h>."""
resSysRef=128# "reference to system/local reference" (only documented as resSysRefBit = 7 in <CarbonCore/Resources.h>
resSysHeap=64# "In system/in application heap", "System or application heap?"
resCompressed=1# "indicates that the resource data is compressed" (only documented in https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format)
_REZ_ATTR_NAMES={
ResourceAttrs.resSysRef:None,# "Illegal or reserved attribute"
ResourceAttrs.resSysHeap:"sysheap",
ResourceAttrs.resPurgeable:"purgeable",
ResourceAttrs.resLocked:"locked",
ResourceAttrs.resProtected:"protected",
ResourceAttrs.resPreload:"preload",
ResourceAttrs.resChanged:None,# "Illegal or reserved attribute"
"""Unpack data from the stream according to the struct st. The number of bytes to read is determined using st.size, so variable-sized structs cannot be used with this method."""
returnst.unpack(self._read(st.size))
def_read_header(self):
"""Read the resource file header, starting at the current stream position."""
assertself._tell()==0
self.data_offset:int
self.map_offset:int
self.data_length:int
self.map_length:int
self.header_system_data:bytes
self.header_application_data:bytes
(
self.data_offset,
self.map_offset,
self.data_length,
self.map_length,
self.header_system_data,
self.header_application_data,
)=self._stream_unpack(STRUCT_RESOURCE_HEADER)
assertself._tell()==self.data_offset
def_read_all_resource_data(self):
"""Read all resource data blocks, starting at the current stream position, until self.map_offset is reached."""
"""Close the underlying stream, unless this behavior was suppressed by passing close=False to the constructor. If seeking is enabled for this ResourceFile, resources can no longer be read after closing the stream. On the other hand, if seeking is disabled, closing the stream does not affect the ResourceFile."""
ifself._close_stream:
self._stream.close()
def__enter__(self):
pass
def__exit__(self,exc_type,exc_val,exc_tb):
self.close()
def__len__(self):
"""Get the number of resource types in this ResourceFile."""
returnlen(self._references)
def__iter__(self):
"""Iterate over all resource types in this ResourceFile."""
returniter(self._references)
def__contains__(self,key:bytes):
"""Check whether this ResourceFile contains any resources of the given type."""
ap.add_argument("--help",action="help",help="Display this help message and exit")
ap.add_argument("--version",action="version",version=__version__,help="Display version information and exit")
ap.add_argument("-a","--all",action="store_true",help="When no filters are given, show all resources in full, instead of an overview")
ap.add_argument("-f","--fork",choices=["auto","data","rsrc"],default="auto",help="The fork from which to read the resource data, or auto to guess (default: %(default)s)")
ap.add_argument("--format",choices=["dump","hex","raw","derez"],default="dump",help="How to output the resources - human-readable info with hex dump (dump), data only as hex (hex), data only as raw bytes (raw), or like DeRez with no resource definitions (derez)")
ap.add_argument("--header-system",action="store_true",help="Output system-reserved header data and nothing else")
ap.add_argument("--header-application",action="store_true",help="Output application-specific header data and nothing else")
ap.add_argument("--read-mode",choices=["auto","stream","seek"],default="auto",help="Whether to read the data sequentially (stream) or on-demand (seek), or auto to use seeking when possible (default: %(default)s)")
ap.add_argument("file",help="The file to read, or - for stdin")
ap.add_argument("filter",nargs="*",help="One or more filters to select which resources to display, or omit to show an overview of all resources")