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.
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.
import kaitai_struct_nim_runtime
import options
type
Zisofs* = ref object of KaitaiStruct
`header`*: Zisofs_Header
`blockPointers`*: seq[uint32]
`parent`*: KaitaiStruct
`rawHeader`*: seq[byte]
`blocksInst`: seq[Zisofs_Block]
`blocksInstFlag`: bool
Zisofs_Header* = ref object of KaitaiStruct
`magic`*: seq[byte]
`uncompressedSize`*: uint32
`lenHeader`*: uint8
`blockSizeLog2`*: uint8
`reserved`*: seq[byte]
`parent`*: Zisofs
`blockSizeInst`: int
`blockSizeInstFlag`: bool
`numBlocksInst`: int
`numBlocksInstFlag`: bool
Zisofs_Block* = ref object of KaitaiStruct
`ofsStart`*: uint32
`ofsEnd`*: uint32
`parent`*: Zisofs
`lenDataInst`: int
`lenDataInstFlag`: bool
`dataInst`: seq[byte]
`dataInstFlag`: bool
proc read*(_: typedesc[Zisofs], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): Zisofs
proc read*(_: typedesc[Zisofs_Header], io: KaitaiStream, root: KaitaiStruct, parent: Zisofs): Zisofs_Header
proc read*(_: typedesc[Zisofs_Block], io: KaitaiStream, root: KaitaiStruct, parent: Zisofs, ofsStart: any, ofsEnd: any): Zisofs_Block
proc blocks*(this: Zisofs): seq[Zisofs_Block]
proc blockSize*(this: Zisofs_Header): int
proc numBlocks*(this: Zisofs_Header): int
proc lenData*(this: Zisofs_Block): int
proc data*(this: Zisofs_Block): seq[byte]
##[
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.
@see <a href="https://web.archive.org/web/20200612093441/https://dev.lovelyhq.com/libburnia/web/-/wikis/zisofs">Source</a>
]##
proc read*(_: typedesc[Zisofs], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): Zisofs =
template this: untyped = result
this = new(Zisofs)
let root = if root == nil: cast[Zisofs](this) else: cast[Zisofs](root)
this.io = io
this.root = root
this.parent = parent
let rawHeaderExpr = this.io.readBytes(int(16))
this.rawHeader = rawHeaderExpr
let rawHeaderIo = newKaitaiStream(rawHeaderExpr)
let headerExpr = Zisofs_Header.read(rawHeaderIo, this.root, this)
this.header = headerExpr
##[
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.
]##
for i in 0 ..< int((this.header.numBlocks + 1)):
let it = this.io.readU4le()
this.blockPointers.add(it)
proc blocks(this: Zisofs): seq[Zisofs_Block] =
if this.blocksInstFlag:
return this.blocksInst
for i in 0 ..< int(this.header.numBlocks):
let it = Zisofs_Block.read(this.io, this.root, this, this.blockPointers[i], this.blockPointers[(i + 1)])
this.blocksInst.add(it)
this.blocksInstFlag = true
return this.blocksInst
proc fromFile*(_: typedesc[Zisofs], filename: string): Zisofs =
Zisofs.read(newKaitaiFileStream(filename), nil, nil)
proc read*(_: typedesc[Zisofs_Header], io: KaitaiStream, root: KaitaiStruct, parent: Zisofs): Zisofs_Header =
template this: untyped = result
this = new(Zisofs_Header)
let root = if root == nil: cast[Zisofs](this) else: cast[Zisofs](root)
this.io = io
this.root = root
this.parent = parent
let magicExpr = this.io.readBytes(int(8))
this.magic = magicExpr
##[
Size of the original uncompressed file
]##
let uncompressedSizeExpr = this.io.readU4le()
this.uncompressedSize = uncompressedSizeExpr
##[
header_size >> 2 (currently 4)
]##
let lenHeaderExpr = this.io.readU1()
this.lenHeader = lenHeaderExpr
let blockSizeLog2Expr = this.io.readU1()
this.blockSizeLog2 = blockSizeLog2Expr
let reservedExpr = this.io.readBytes(int(2))
this.reserved = reservedExpr
proc blockSize(this: Zisofs_Header): int =
if this.blockSizeInstFlag:
return this.blockSizeInst
let blockSizeInstExpr = int((1 shl this.blockSizeLog2))
this.blockSizeInst = blockSizeInstExpr
this.blockSizeInstFlag = true
return this.blockSizeInst
proc numBlocks(this: Zisofs_Header): int =
##[
ceil(uncompressed_size / block_size)
]##
if this.numBlocksInstFlag:
return this.numBlocksInst
let numBlocksInstExpr = int(((this.uncompressedSize div this.blockSize) + (if (this.uncompressedSize %%% this.blockSize) != 0: 1 else: 0)))
this.numBlocksInst = numBlocksInstExpr
this.numBlocksInstFlag = true
return this.numBlocksInst
proc fromFile*(_: typedesc[Zisofs_Header], filename: string): Zisofs_Header =
Zisofs_Header.read(newKaitaiFileStream(filename), nil, nil)
proc read*(_: typedesc[Zisofs_Block], io: KaitaiStream, root: KaitaiStruct, parent: Zisofs, ofsStart: any, ofsEnd: any): Zisofs_Block =
template this: untyped = result
this = new(Zisofs_Block)
let root = if root == nil: cast[Zisofs](this) else: cast[Zisofs](root)
this.io = io
this.root = root
this.parent = parent
let ofsStartExpr = uint32(ofsStart)
this.ofsStart = ofsStartExpr
let ofsEndExpr = uint32(ofsEnd)
this.ofsEnd = ofsEndExpr
proc lenData(this: Zisofs_Block): int =
if this.lenDataInstFlag:
return this.lenDataInst
let lenDataInstExpr = int((this.ofsEnd - this.ofsStart))
this.lenDataInst = lenDataInstExpr
this.lenDataInstFlag = true
return this.lenDataInst
proc data(this: Zisofs_Block): seq[byte] =
if this.dataInstFlag:
return this.dataInst
let io = Zisofs(this.root).io
let pos = io.pos()
io.seek(int(this.ofsStart))
let dataInstExpr = io.readBytes(int(this.lenData))
this.dataInst = dataInstExpr
io.seek(pos)
this.dataInstFlag = true
return this.dataInst
proc fromFile*(_: typedesc[Zisofs_Block], filename: string): Zisofs_Block =
Zisofs_Block.read(newKaitaiFileStream(filename), nil, nil)