mirror of
https://github.com/dgelessus/python-rsrcfork.git
synced 2024-12-01 15:49:44 +00:00
Change naming of compression types
The old names ("system" and "application" compression) were not really accurate in all cases, so the compression types are now referred to by their number.
This commit is contained in:
parent
a71274d554
commit
f3b3de496e
@ -9,30 +9,30 @@ class DecompressError(Exception):
|
|||||||
|
|
||||||
# The signature of all compressed resource data, 0xa89f6572 in hex, or "®üer" in MacRoman.
|
# The signature of all compressed resource data, 0xa89f6572 in hex, or "®üer" in MacRoman.
|
||||||
COMPRESSED_SIGNATURE = b"\xa8\x9fer"
|
COMPRESSED_SIGNATURE = b"\xa8\x9fer"
|
||||||
# The compression type commonly used for application resources.
|
# The number of the "type 8" compression type. This type is used in the Finder, ResEdit, and some other system files.
|
||||||
COMPRESSED_TYPE_APPLICATION = 0x0801
|
COMPRESSED_TYPE_8 = 0x0801
|
||||||
# The compression type commonly used for System file resources.
|
# The number of the "type 9" compression type. This type is used in the System file and System 7.5's Installer.
|
||||||
COMPRESSED_TYPE_SYSTEM = 0x0901
|
COMPRESSED_TYPE_9 = 0x0901
|
||||||
|
|
||||||
# Common header for compressed resources of all types.
|
# Common header for compressed resources of all types.
|
||||||
# 4 bytes: Signature (see above).
|
# 4 bytes: Signature (see above).
|
||||||
# 2 bytes: Length of the complete header (this common part and the type-specific part that follows it). (This meaning is just a guess - the field's value is always 0x0012, so there's no way to know for certain what it means.)
|
# 2 bytes: Length of the complete header (this common part and the type-specific part that follows it). (This meaning is just a guess - the field's value is always 0x0012, so there's no way to know for certain what it means.)
|
||||||
# 2 bytes: Compression type. Known so far: 0x0901 is used in the System file's resources. 0x0801 is used in other files' resources.
|
# 2 bytes: Compression type. Known so far: 0x0801 ("type 8") and 0x0901 ("type 9").
|
||||||
# 4 bytes: Length of the data after decompression.
|
# 4 bytes: Length of the data after decompression.
|
||||||
# 6 bytes: Remainder of the header. The exact format varies depending on the compression type.
|
# 6 bytes: Remainder of the header. The exact format varies depending on the compression type.
|
||||||
STRUCT_COMPRESSED_HEADER = struct.Struct(">4sHHI6s")
|
STRUCT_COMPRESSED_HEADER = struct.Struct(">4sHHI6s")
|
||||||
|
|
||||||
# Remainder of header for an "application" compressed resource.
|
# Remainder of header for a "type 8" compressed resource.
|
||||||
# 1 byte: "Working buffer fractional size" - the ratio of the compressed data size to the uncompressed data size, times 256.
|
# 1 byte: "Working buffer fractional size" - the ratio of the compressed data size to the uncompressed data size, times 256.
|
||||||
# 1 byte: "Expansion buffer size" - the maximum number of bytes that the data might grow during decompression.
|
# 1 byte: "Expansion buffer size" - the maximum number of bytes that the data might grow during decompression.
|
||||||
# 2 bytes: The ID of the 'dcmp' resource that can decompress this resource. Currently only ID 0 is supported.
|
# 2 bytes: The ID of the 'dcmp' resource that can decompress this resource. Currently only ID 0 is supported.
|
||||||
# 2 bytes: Reserved (always zero).
|
# 2 bytes: Reserved (always zero).
|
||||||
STRUCT_COMPRESSED_APPLICATION_HEADER = struct.Struct(">BBhH")
|
STRUCT_COMPRESSED_TYPE_8_HEADER = struct.Struct(">BBhH")
|
||||||
|
|
||||||
# Remainder of header for a "system" compressed resource.
|
# Remainder of header for a "type 9" compressed resource.
|
||||||
# 2 bytes: The ID of the 'dcmp' resource that can decompress this resource. Currently only ID 2 is supported.
|
# 2 bytes: The ID of the 'dcmp' resource that can decompress this resource. Currently only ID 2 is supported.
|
||||||
# 4 bytes: Decompressor-specific parameters.
|
# 4 bytes: Decompressor-specific parameters.
|
||||||
STRUCT_COMPRESSED_SYSTEM_HEADER = struct.Struct(">h4s")
|
STRUCT_COMPRESSED_TYPE_9_HEADER = struct.Struct(">h4s")
|
||||||
|
|
||||||
|
|
||||||
class CompressedHeaderInfo(object):
|
class CompressedHeaderInfo(object):
|
||||||
@ -47,17 +47,17 @@ class CompressedHeaderInfo(object):
|
|||||||
if header_length != 0x12:
|
if header_length != 0x12:
|
||||||
raise DecompressError(f"Unsupported header length: 0x{header_length:>04x}, expected 0x12")
|
raise DecompressError(f"Unsupported header length: 0x{header_length:>04x}, expected 0x12")
|
||||||
|
|
||||||
if compression_type == COMPRESSED_TYPE_APPLICATION:
|
if compression_type == COMPRESSED_TYPE_8:
|
||||||
working_buffer_fractional_size, expansion_buffer_size, dcmp_id, reserved = STRUCT_COMPRESSED_APPLICATION_HEADER.unpack(remainder)
|
working_buffer_fractional_size, expansion_buffer_size, dcmp_id, reserved = STRUCT_COMPRESSED_TYPE_8_HEADER.unpack(remainder)
|
||||||
|
|
||||||
if reserved != 0:
|
if reserved != 0:
|
||||||
raise DecompressError(f"Reserved field should be 0, not 0x{reserved:>04x}")
|
raise DecompressError(f"Reserved field should be 0, not 0x{reserved:>04x}")
|
||||||
|
|
||||||
return CompressedApplicationHeaderInfo(header_length, compression_type, decompressed_length, dcmp_id, working_buffer_fractional_size, expansion_buffer_size)
|
return CompressedType8HeaderInfo(header_length, compression_type, decompressed_length, dcmp_id, working_buffer_fractional_size, expansion_buffer_size)
|
||||||
elif compression_type == COMPRESSED_TYPE_SYSTEM:
|
elif compression_type == COMPRESSED_TYPE_9:
|
||||||
dcmp_id, parameters = STRUCT_COMPRESSED_SYSTEM_HEADER.unpack(remainder)
|
dcmp_id, parameters = STRUCT_COMPRESSED_TYPE_9_HEADER.unpack(remainder)
|
||||||
|
|
||||||
return CompressedSystemHeaderInfo(header_length, compression_type, decompressed_length, dcmp_id, parameters)
|
return CompressedType9HeaderInfo(header_length, compression_type, decompressed_length, dcmp_id, parameters)
|
||||||
else:
|
else:
|
||||||
raise DecompressError(f"Unsupported compression type: 0x{compression_type:>04x}")
|
raise DecompressError(f"Unsupported compression type: 0x{compression_type:>04x}")
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ class CompressedHeaderInfo(object):
|
|||||||
self.dcmp_id = dcmp_id
|
self.dcmp_id = dcmp_id
|
||||||
|
|
||||||
|
|
||||||
class CompressedApplicationHeaderInfo(CompressedHeaderInfo):
|
class CompressedType8HeaderInfo(CompressedHeaderInfo):
|
||||||
working_buffer_fractional_size: int
|
working_buffer_fractional_size: int
|
||||||
expansion_buffer_size: int
|
expansion_buffer_size: int
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ class CompressedApplicationHeaderInfo(CompressedHeaderInfo):
|
|||||||
return f"{type(self).__qualname__}(header_length={self.header_length}, compression_type=0x{self.compression_type:>04x}, decompressed_length={self.decompressed_length}, dcmp_id={self.dcmp_id}, working_buffer_fractional_size={self.working_buffer_fractional_size}, expansion_buffer_size={self.expansion_buffer_size})"
|
return f"{type(self).__qualname__}(header_length={self.header_length}, compression_type=0x{self.compression_type:>04x}, decompressed_length={self.decompressed_length}, dcmp_id={self.dcmp_id}, working_buffer_fractional_size={self.working_buffer_fractional_size}, expansion_buffer_size={self.expansion_buffer_size})"
|
||||||
|
|
||||||
|
|
||||||
class CompressedSystemHeaderInfo(CompressedHeaderInfo):
|
class CompressedType9HeaderInfo(CompressedHeaderInfo):
|
||||||
parameters: bytes
|
parameters: bytes
|
||||||
|
|
||||||
def __init__(self, header_length: int, compression_type: int, decompressed_length: int, dcmp_id: int, parameters: bytes) -> None:
|
def __init__(self, header_length: int, compression_type: int, decompressed_length: int, dcmp_id: int, parameters: bytes) -> None:
|
||||||
|
@ -42,7 +42,7 @@ assert len(TABLE) == len(range(0x4b, 0xfe))
|
|||||||
def decompress_stream_inner(header_info: common.CompressedHeaderInfo, stream: typing.BinaryIO, *, debug: bool=False) -> typing.Iterator[bytes]:
|
def decompress_stream_inner(header_info: common.CompressedHeaderInfo, stream: typing.BinaryIO, *, debug: bool=False) -> typing.Iterator[bytes]:
|
||||||
"""Internal helper function, implements the main decompression algorithm. Only called from decompress_stream, which performs some extra checks and debug logging."""
|
"""Internal helper function, implements the main decompression algorithm. Only called from decompress_stream, which performs some extra checks and debug logging."""
|
||||||
|
|
||||||
if not isinstance(header_info, common.CompressedApplicationHeaderInfo):
|
if not isinstance(header_info, common.CompressedType8HeaderInfo):
|
||||||
raise common.DecompressError(f"Incorrect header type: {type(header_info).__qualname__}")
|
raise common.DecompressError(f"Incorrect header type: {type(header_info).__qualname__}")
|
||||||
|
|
||||||
prev_literals: typing.List[bytes] = []
|
prev_literals: typing.List[bytes] = []
|
||||||
|
@ -25,7 +25,7 @@ assert len(TABLE) == len(range(0xd5, 0xfe))
|
|||||||
def decompress_stream_inner(header_info: common.CompressedHeaderInfo, stream: typing.BinaryIO, *, debug: bool=False) -> typing.Iterator[bytes]:
|
def decompress_stream_inner(header_info: common.CompressedHeaderInfo, stream: typing.BinaryIO, *, debug: bool=False) -> typing.Iterator[bytes]:
|
||||||
"""Internal helper function, implements the main decompression algorithm. Only called from decompress_stream, which performs some extra checks and debug logging."""
|
"""Internal helper function, implements the main decompression algorithm. Only called from decompress_stream, which performs some extra checks and debug logging."""
|
||||||
|
|
||||||
if not isinstance(header_info, common.CompressedApplicationHeaderInfo):
|
if not isinstance(header_info, common.CompressedType8HeaderInfo):
|
||||||
raise common.DecompressError(f"Incorrect header type: {type(header_info).__qualname__}")
|
raise common.DecompressError(f"Incorrect header type: {type(header_info).__qualname__}")
|
||||||
|
|
||||||
prev_literals: typing.List[bytes] = []
|
prev_literals: typing.List[bytes] = []
|
||||||
|
@ -74,7 +74,7 @@ def _split_bits(i: int) -> typing.Tuple[bool, bool, bool, bool, bool, bool, bool
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _decompress_system_untagged(stream: "common.PeekableIO", decompressed_length: int, table: typing.Sequence[bytes], *, debug: bool=False) -> typing.Iterator[bytes]:
|
def _decompress_untagged(stream: "common.PeekableIO", decompressed_length: int, table: typing.Sequence[bytes], *, debug: bool=False) -> typing.Iterator[bytes]:
|
||||||
while True: # Loop is terminated when EOF is reached.
|
while True: # Loop is terminated when EOF is reached.
|
||||||
table_index_data = stream.read(1)
|
table_index_data = stream.read(1)
|
||||||
if not table_index_data:
|
if not table_index_data:
|
||||||
@ -93,7 +93,7 @@ def _decompress_system_untagged(stream: "common.PeekableIO", decompressed_length
|
|||||||
print(f"Reference: {table_index} -> {table[table_index]}")
|
print(f"Reference: {table_index} -> {table[table_index]}")
|
||||||
yield table[table_index]
|
yield table[table_index]
|
||||||
|
|
||||||
def _decompress_system_tagged(stream: "common.PeekableIO", decompressed_length: int, table: typing.Sequence[bytes], *, debug: bool=False) -> typing.Iterator[bytes]:
|
def _decompress_tagged(stream: "common.PeekableIO", decompressed_length: int, table: typing.Sequence[bytes], *, debug: bool=False) -> typing.Iterator[bytes]:
|
||||||
while True: # Loop is terminated when EOF is reached.
|
while True: # Loop is terminated when EOF is reached.
|
||||||
tag_data = stream.read(1)
|
tag_data = stream.read(1)
|
||||||
if not tag_data:
|
if not tag_data:
|
||||||
@ -136,7 +136,7 @@ def _decompress_system_tagged(stream: "common.PeekableIO", decompressed_length:
|
|||||||
def decompress_stream(header_info: common.CompressedHeaderInfo, stream: typing.BinaryIO, *, debug: bool=False) -> typing.Iterator[bytes]:
|
def decompress_stream(header_info: common.CompressedHeaderInfo, stream: typing.BinaryIO, *, debug: bool=False) -> typing.Iterator[bytes]:
|
||||||
"""Decompress compressed data in the format used by 'dcmp' (2)."""
|
"""Decompress compressed data in the format used by 'dcmp' (2)."""
|
||||||
|
|
||||||
if not isinstance(header_info, common.CompressedSystemHeaderInfo):
|
if not isinstance(header_info, common.CompressedType9HeaderInfo):
|
||||||
raise common.DecompressError(f"Incorrect header type: {type(header_info).__qualname__}")
|
raise common.DecompressError(f"Incorrect header type: {type(header_info).__qualname__}")
|
||||||
|
|
||||||
unknown, table_count_m1, flags_raw = STRUCT_PARAMETERS.unpack(header_info.parameters)
|
unknown, table_count_m1, flags_raw = STRUCT_PARAMETERS.unpack(header_info.parameters)
|
||||||
@ -170,8 +170,8 @@ def decompress_stream(header_info: common.CompressedHeaderInfo, stream: typing.B
|
|||||||
print("Using default table")
|
print("Using default table")
|
||||||
|
|
||||||
if ParameterFlags.TAGGED in flags:
|
if ParameterFlags.TAGGED in flags:
|
||||||
decompress_func = _decompress_system_tagged
|
decompress_func = _decompress_tagged
|
||||||
else:
|
else:
|
||||||
decompress_func = _decompress_system_untagged
|
decompress_func = _decompress_untagged
|
||||||
|
|
||||||
yield from decompress_func(common.make_peekable(stream), header_info.decompressed_length, table, debug=debug)
|
yield from decompress_func(common.make_peekable(stream), header_info.decompressed_length, table, debug=debug)
|
||||||
|
Loading…
Reference in New Issue
Block a user