# 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)
"""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."""