This repository contains a module and command for handling RISC OS PackDir archives. PackDir is the archive format used by a number of RISC OS tools. It stores a hierarchy of files and directories, along with RISC OS load and execution addresses, attributes, and optional LZW-compressed file data.
The packdir module follows the useful read-only parts of the standard
zipfile and tarfile interfaces. It can inspect, read, create, and extract
archives on RISC OS and non-RISC OS hosts.
Install the module and the riscos-packdir command with pip:
python3 -m pip install packdir
The packdir module provides PackDirFile, which is used in a similar way to
zipfile.ZipFile and tarfile.TarFile.
Open an archive with packdir.open() and enumerate its members:
import packdir
with packdir.open("application.pack") as archive:
for member in archive.infolist():
print(member.filename)namelist() and getnames() return the member names, while infolist() and
getmembers() return PackDirInfo objects. getinfo(name) and
getmember(name) look up one member by name.
The is_packdir() function can be used to check whether a path or binary file
object begins with a valid PackDir header.
Each PackDirInfo object describes a file or directory in the archive. The
following fields are available:
nameandfilenameare the full archive member name.load_addressandriscos_loadaddrare the RISC OS load address.execution_addressandriscos_execaddrare the RISC OS execution address.attributesandriscos_attrare the RISC OS attributes word.file_sizeandsizeare the uncompressed byte length.is_directoryrecords whether the member is a directory;is_dir()returns the same value.compress_sizeis the stored payload length, andis_compressedindicates whether the member uses PackDir LZW compression.
Use read() to obtain uncompressed file data, or open() to receive a binary
in-memory stream for a file:
with packdir.open("application.pack") as archive:
data = archive.read("application/!Run")
archive.extractall("extracted-application")extract() extracts one member and returns its destination path.
extractall() extracts all members, or a supplied list of members. Extracted
filenames use the NFS convention so that RISC OS metadata is retained on host
filesystems: name,abc represents filetype &ABC, while
name,llllllll,eeeeeeee represents explicit load and execution addresses.
Create an archive from files below a base directory with create():
import packdir
packdir.create("application.pack", ["!MyApp"], base_dir=".")Filenames using the NFS convention are decoded when the archive is created, so
that their RISC OS metadata is stored in the PackDir records. Files are
compressed with LZW by default. Pass compress=False to store file data
unchanged, and use max_width to choose an LZW code width from 12 to 16 bits.
The installed riscos-packdir tool offers the same operations as the Python
interface. It can also be invoked as python3 -m packdir.
Listing an archive:
riscos-packdir --list application.pack
Creating an archive from a directory or file:
riscos-packdir --create application.pack !MyApp
riscos-packdir --chdir source --create application.pack !MyApp
Extracting an archive:
riscos-packdir --extract --chdir output application.pack
Use --store (or -0) to create an archive without compression. --maxbits
selects the maximum LZW code width, and --verbose reports the members being
created or extracted.
The unit tests exercise the reader and writer API. The separate integration test runs the installed command through a create, list, and extract round trip:
make tests
make inttests