Writing Packers
To write an OFRAK Packer, an OFRAK contributor needs to:
- Create a class that inherits from
ofrak.component.component_packer.Packer
with a defined component config (ofrak.model.component_model.CC
-- this will typically beNone
); - Implement the
targets
to indicate what resource tags the packer targets; - Implement the
pack
method such that it correctly packs the resource's children or descendants.
The following is an example of a fully implemented OFRAK packer:
from dataclasses import dataclass
from ofrak.component.packer import Packer
from ofrak.service.resource_service_i import ResourceFilter
from ofrak.core.binary import GenericBinary
from ofrak.resource import Resource
from ofrak_type.range import Range
[ ... ]
@dataclass
class UImage(GenericBinary):
async def get_header(self) -> UImageHeader:
return await self.resource.get_only_child_as_view(
UImageHeader, ResourceFilter.with_tags(UImageHeader)
)
async def get_body(self) -> UImageBody:
return await self.resource.get_only_child_as_view(
UImageBody, ResourceFilter.with_tags(UImageBody),
)
[ ... ]
class UImagePacker(Packer[None]):
"""
UImage packer.
It patches the resource's header and body into a single binary, updating the CRC
checksums and image data size in the header.
"""
id = b"UImagePacker"
targets = (UImage,)
async def pack(self, resource: Resource, config=None):
uimage_view = await resource.view_as(UImage)
header = await uimage_view.get_header()
uimage_body = await uimage_view.get_body()
# Modify the header with the data size and CRC32
uimage_body_bytes = await uimage_body.resource.get_data()
ih_size = len(uimage_body_bytes)
ih_dcrc = zlib.crc32(uimage_body_bytes)
header_modifier_config = UImageHeaderModifierConfig(ih_size=ih_size, ih_dcrc=ih_dcrc)
await header.resource.run(UImageHeaderModifier, header_modifier_config)
resource.queue_patch(Range.from_size(UIMAGE_HEADER_LEN, ih_size), uimage_body_bytes)
This packer targets a UImage
and repacks a UImageBody
with updated UImageHeader
values.
Handling External Dependencies
If the Packer makes use of tools that are not packaged in modules installable via pip
from
PyPI (commonly command-line tools), these dependencies must be explicitly declared as part of the
packer's class declaration. See the Components Using External Tools doc for
information on how to do that.