Skip to content

gerph/python-packdir-riscos

Repository files navigation

Python PackDir processing for RISC OS archives

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.

Installing

Install the module and the riscos-packdir command with pip:

python3 -m pip install packdir

packdir

The packdir module provides PackDirFile, which is used in a similar way to zipfile.ZipFile and tarfile.TarFile.

Reading archive contents

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.

Member properties

Each PackDirInfo object describes a file or directory in the archive. The following fields are available:

  • name and filename are the full archive member name.
  • load_address and riscos_loadaddr are the RISC OS load address.
  • execution_address and riscos_execaddr are the RISC OS execution address.
  • attributes and riscos_attr are the RISC OS attributes word.
  • file_size and size are the uncompressed byte length.
  • is_directory records whether the member is a directory; is_dir() returns the same value.
  • compress_size is the stored payload length, and is_compressed indicates whether the member uses PackDir LZW compression.

Reading and extracting files

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.

Creating archives

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.

Command line usage

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.

Tests

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

About

Python tool to creation and extraction of RISC OS !PackDir archives

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Contributors