zisofs: format specification

zisofs is a compression format for files on ISO9660 file system. It has limited support across operating systems, mainly Linux kernel. Typically a directory tree is first preprocessed by mkzftree (from the zisofs-tools package before being turned into an ISO9660 image by mkisofs, genisoimage or similar tool. The data is zlib compressed.

The specification here describes the structure of a file that has been preprocessed by mkzftree, not of a full ISO9660 ziso. Data is not decompressed, as blocks with length 0 have a special meaning. Decompression and deconstruction of this data should be done outside of Kaitai Struct.

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of zisofs using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Block diagram

Format specification in Kaitai Struct YAML

meta:
  id: zisofs
  title: zisofs
  xref:
    justsolve: Zisofs
    wikidata: Q105854284
  tags:
    - archive
    - filesystem
  license: CC0-1.0
  endian: le
doc: |
  zisofs is a compression format for files on ISO9660 file system. It has
  limited support across operating systems, mainly Linux kernel. Typically a
  directory tree is first preprocessed by mkzftree (from the zisofs-tools
  package before being turned into an ISO9660 image by mkisofs, genisoimage
  or similar tool. The data is zlib compressed.

  The specification here describes the structure of a file that has been
  preprocessed by mkzftree, not of a full ISO9660 ziso. Data is not
  decompressed, as blocks with length 0 have a special meaning. Decompression
  and deconstruction of this data should be done outside of Kaitai Struct.
doc-ref: https://web.archive.org/web/20200612093441/https://dev.lovelyhq.com/libburnia/web/-/wikis/zisofs
seq:
  - id: header
    size: 16
    type: header
  - id: block_pointers
    type: u4
    repeat: expr
    repeat-expr: header.num_blocks + 1
    doc: |
      The final pointer (`block_pointers[header.num_blocks]`) indicates the end
      of the last block. Typically this is also the end of the file data.
instances:
  blocks:
    type: 'block(block_pointers[_index], block_pointers[_index + 1])'
    repeat: expr
    repeat-expr: header.num_blocks
types:
  header:
    seq:
      - id: magic
        contents: [0x37, 0xe4, 0x53, 0x96, 0xc9, 0xdb, 0xd6, 0x07]
      - id: uncompressed_size
        type: u4
        doc: Size of the original uncompressed file
      - id: len_header
        type: u1
        valid: 4
        doc: header_size >> 2 (currently 4)
      - id: block_size_log2
        type: u1
        valid:
          any-of: [15, 16, 17]
      - id: reserved
        contents: [0, 0]
    instances:
      block_size:
        value: 1 << block_size_log2
      num_blocks:
        value: '(uncompressed_size / block_size) + (uncompressed_size % block_size != 0 ? 1 : 0)'
        doc: ceil(uncompressed_size / block_size)
  block:
    -webide-representation: '[{ofs_start}, {ofs_end}): {len_data:dec} bytes'
    params:
      - id: ofs_start
        type: u4
      - id: ofs_end
        type: u4
    instances:
      len_data:
        value: ofs_end - ofs_start
      data:
        io: _root._io
        pos: ofs_start
        size: len_data