This page hosts a formal specification of Zchunk using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.
import (
"github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
"bytes"
)
/**
* @see <a href="https://github.com/zchunk/zchunk/blob/99e51afa38c723e7c25834c2c3b305d20ef55d04/zchunk_format.txt">Source</a>
*/
type Zchunk_ChecksumTypes int
const (
Zchunk_ChecksumTypes__Sha1 Zchunk_ChecksumTypes = 0
Zchunk_ChecksumTypes__Sha256 Zchunk_ChecksumTypes = 1
Zchunk_ChecksumTypes__Sha512 Zchunk_ChecksumTypes = 2
Zchunk_ChecksumTypes__Sha512128 Zchunk_ChecksumTypes = 3
)
var values_Zchunk_ChecksumTypes = map[Zchunk_ChecksumTypes]struct{}{0: {}, 1: {}, 2: {}, 3: {}}
func (v Zchunk_ChecksumTypes) isDefined() bool {
_, ok := values_Zchunk_ChecksumTypes[v]
return ok
}
type Zchunk_CompressionTypes int
const (
Zchunk_CompressionTypes__None Zchunk_CompressionTypes = 0
Zchunk_CompressionTypes__Zstd Zchunk_CompressionTypes = 2
)
var values_Zchunk_CompressionTypes = map[Zchunk_CompressionTypes]struct{}{0: {}, 2: {}}
func (v Zchunk_CompressionTypes) isDefined() bool {
_, ok := values_Zchunk_CompressionTypes[v]
return ok
}
type Zchunk struct {
Lead *Zchunk_HeaderLead
HeaderRest *Zchunk_HeaderWithoutLead
Dict []byte
Chunks [][]byte
_io *kaitai.Stream
_root *Zchunk
_parent kaitai.Struct
_raw_HeaderRest []byte
}
func NewZchunk() *Zchunk {
return &Zchunk{
}
}
func (this Zchunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Zchunk) Read(io *kaitai.Stream, parent kaitai.Struct, root *Zchunk) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp1 := NewZchunk_HeaderLead()
err = tmp1.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Lead = tmp1
tmp2, err := this.Lead.LenHeaderRest.Value()
if err != nil {
return err
}
tmp3, err := this._io.ReadBytes(int(tmp2))
if err != nil {
return err
}
tmp3 = tmp3
this._raw_HeaderRest = tmp3
_io__raw_HeaderRest := kaitai.NewStream(bytes.NewReader(this._raw_HeaderRest))
tmp4 := NewZchunk_HeaderWithoutLead()
err = tmp4.Read(_io__raw_HeaderRest, this, this._root)
if err != nil {
return err
}
this.HeaderRest = tmp4
tmp5, err := this.HeaderRest.Index.LenDict.Value()
if err != nil {
return err
}
tmp6, err := this._io.ReadBytes(int(tmp5))
if err != nil {
return err
}
tmp6 = tmp6
this.Dict = tmp6
tmp7, err := this.Lead.IsDetachedHeader()
if err != nil {
return err
}
if (!(tmp7)) {
for i := 0; i < int(len(this.HeaderRest.Index.ChunksMetadata)); i++ {
_ = i
tmp8, err := this.HeaderRest.Index.ChunksMetadata[i].LenChunk.Value()
if err != nil {
return err
}
tmp9, err := this._io.ReadBytes(int(tmp8))
if err != nil {
return err
}
tmp9 = tmp9
this.Chunks = append(this.Chunks, tmp9)
}
}
return err
}
/**
* Custom dictionary used when compressing each chunk. It's compressed itself
* without a dictionary.
*
* The official zchunk specification calls this section "Compressed Dict".
* It's also called a "dictionary chunk". `zck_read_header -c` presents it as
* "chunk 0" (which is always shown in the chunk table, but can have size 0
* if the dictionary is not in use).
*/
/**
* Chunks of data, each compressed with the custom dictionary `dict` (if
* applicable).
*
* They are not included in a detached header (`.zhr`) file. Detached headers
* contain the dictionary, but none of the data chunks.
*/
type Zchunk_ChecksumType struct {
Raw *Zchunk_CompressedInteger
_io *kaitai.Stream
_root *Zchunk
_parent kaitai.Struct
_f_lenChecksum bool
lenChecksum int8
_f_value bool
value Zchunk_ChecksumTypes
}
func NewZchunk_ChecksumType() *Zchunk_ChecksumType {
return &Zchunk_ChecksumType{
}
}
func (this Zchunk_ChecksumType) IO_() *kaitai.Stream {
return this._io
}
func (this *Zchunk_ChecksumType) Read(io *kaitai.Stream, parent kaitai.Struct, root *Zchunk) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp10 := NewZchunk_CompressedInteger()
err = tmp10.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Raw = tmp10
{
_it := this.Raw
tmp11, err := this.LenChecksum()
if err != nil {
return err
}
if !(tmp11 != 0) {
return kaitai.NewValidationExprError(this.Raw, this._io, "/types/checksum_type/seq/0")
}
}
return err
}
func (this *Zchunk_ChecksumType) LenChecksum() (v int8, err error) {
if (this._f_lenChecksum) {
return this.lenChecksum, nil
}
this._f_lenChecksum = true
var tmp12 int8;
tmp13, err := this.Value()
if err != nil {
return 0, err
}
if (tmp13 == Zchunk_ChecksumTypes__Sha1) {
tmp12 = 20
} else {
var tmp14 int8;
tmp15, err := this.Value()
if err != nil {
return 0, err
}
if (tmp15 == Zchunk_ChecksumTypes__Sha256) {
tmp14 = 32
} else {
var tmp16 int8;
tmp17, err := this.Value()
if err != nil {
return 0, err
}
if (tmp17 == Zchunk_ChecksumTypes__Sha512) {
tmp16 = 64
} else {
var tmp18 int8;
tmp19, err := this.Value()
if err != nil {
return 0, err
}
if (tmp19 == Zchunk_ChecksumTypes__Sha512128) {
tmp18 = 16
} else {
tmp18 = 0
}
tmp16 = tmp18
}
tmp14 = tmp16
}
tmp12 = tmp14
}
this.lenChecksum = int8(tmp12)
return this.lenChecksum, nil
}
func (this *Zchunk_ChecksumType) Value() (v Zchunk_ChecksumTypes, err error) {
if (this._f_value) {
return this.value, nil
}
this._f_value = true
tmp20, err := this.Raw.Value()
if err != nil {
return nil, err
}
this.value = Zchunk_ChecksumTypes(Zchunk_ChecksumTypes(tmp20))
return this.value, nil
}
/**
* Raw integer, don't read this field - access `value` instead.
*/
type Zchunk_Chunk struct {
ChunkStream *Zchunk_CompressedInteger
ChunkChecksum []byte
UncompressedChunkChecksum []byte
LenChunk *Zchunk_CompressedInteger
LenUncompressedChunk *Zchunk_CompressedInteger
LenChecksum uint32
HasDataStreams bool
HasUncompressedSource bool
_io *kaitai.Stream
_root *Zchunk
_parent *Zchunk_Index
}
func NewZchunk_Chunk(lenChecksum uint32, hasDataStreams bool, hasUncompressedSource bool) *Zchunk_Chunk {
return &Zchunk_Chunk{
LenChecksum: lenChecksum,
HasDataStreams: hasDataStreams,
HasUncompressedSource: hasUncompressedSource,
}
}
func (this Zchunk_Chunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Zchunk_Chunk) Read(io *kaitai.Stream, parent *Zchunk_Index, root *Zchunk) (err error) {
this._io = io
this._parent = parent
this._root = root
if (this.HasDataStreams) {
tmp21 := NewZchunk_CompressedInteger()
err = tmp21.Read(this._io, this, this._root)
if err != nil {
return err
}
this.ChunkStream = tmp21
}
tmp22, err := this._io.ReadBytes(int(this.LenChecksum))
if err != nil {
return err
}
tmp22 = tmp22
this.ChunkChecksum = tmp22
if (this.HasUncompressedSource) {
tmp23, err := this._io.ReadBytes(int(this.LenChecksum))
if err != nil {
return err
}
tmp23 = tmp23
this.UncompressedChunkChecksum = tmp23
}
tmp24 := NewZchunk_CompressedInteger()
err = tmp24.Read(this._io, this, this._root)
if err != nil {
return err
}
this.LenChunk = tmp24
tmp25 := NewZchunk_CompressedInteger()
err = tmp25.Read(this._io, this, this._root)
if err != nil {
return err
}
this.LenUncompressedChunk = tmp25
return err
}
/**
* Checksum of the uncompressed chunk. Used to detect whether a chunk
* from an uncompressed source is identical to the compressed chunk.
*/
/**
* Like `/common/vlq_base128_le` (LEB128), but the logic of the
* "continuation" flag in the most significant bit is inverted, so instead of
* `has_next`, it is called `is_last` (if the highest bit is set to zero, it
* means "continue", whereas in standard LEB128, the highest bit set to
* **one** means "continue"). Therefore, we cannot simply import
* `/common/vlq_base128_le` and use it, because it is incompatible.
*/
type Zchunk_CompressedInteger struct {
Groups []*Zchunk_CompressedInteger_Group
_io *kaitai.Stream
_root *Zchunk
_parent kaitai.Struct
_f_len bool
len int
_f_value bool
value uint64
}
func NewZchunk_CompressedInteger() *Zchunk_CompressedInteger {
return &Zchunk_CompressedInteger{
}
}
func (this Zchunk_CompressedInteger) IO_() *kaitai.Stream {
return this._io
}
func (this *Zchunk_CompressedInteger) Read(io *kaitai.Stream, parent kaitai.Struct, root *Zchunk) (err error) {
this._io = io
this._parent = parent
this._root = root
for i := 1;; i++ {
tmp26 := NewZchunk_CompressedInteger_Group(i)
err = tmp26.Read(this._io, this, this._root)
if err != nil {
return err
}
_it := tmp26
this.Groups = append(this.Groups, _it)
if _it.IsLast {
break
}
}
return err
}
func (this *Zchunk_CompressedInteger) Len() (v int, err error) {
if (this._f_len) {
return this.len, nil
}
this._f_len = true
this.len = int(len(this.Groups))
return this.len, nil
}
/**
* Resulting unsigned value as normal integer
*/
func (this *Zchunk_CompressedInteger) Value() (v uint64, err error) {
if (this._f_value) {
return this.value, nil
}
this._f_value = true
var tmp27 int;
tmp28, err := this.Len()
if err != nil {
return 0, err
}
if (tmp28 >= 2) {
tmp27 = this.Groups[1].Value << 7
} else {
tmp27 = 0
}
var tmp29 int;
tmp30, err := this.Len()
if err != nil {
return 0, err
}
if (tmp30 >= 3) {
tmp29 = this.Groups[2].Value << 14
} else {
tmp29 = 0
}
var tmp31 int;
tmp32, err := this.Len()
if err != nil {
return 0, err
}
if (tmp32 >= 4) {
tmp31 = this.Groups[3].Value << 21
} else {
tmp31 = 0
}
var tmp33 int;
tmp34, err := this.Len()
if err != nil {
return 0, err
}
if (tmp34 >= 5) {
tmp33 = this.Groups[4].Value << 28
} else {
tmp33 = 0
}
var tmp35 int;
tmp36, err := this.Len()
if err != nil {
return 0, err
}
if (tmp36 >= 6) {
tmp35 = this.Groups[5].Value << 35
} else {
tmp35 = 0
}
var tmp37 int;
tmp38, err := this.Len()
if err != nil {
return 0, err
}
if (tmp38 >= 7) {
tmp37 = this.Groups[6].Value << 42
} else {
tmp37 = 0
}
var tmp39 int;
tmp40, err := this.Len()
if err != nil {
return 0, err
}
if (tmp40 >= 8) {
tmp39 = this.Groups[7].Value << 49
} else {
tmp39 = 0
}
var tmp41 int;
tmp42, err := this.Len()
if err != nil {
return 0, err
}
if (tmp42 >= 9) {
tmp41 = this.Groups[8].Value << 56
} else {
tmp41 = 0
}
var tmp43 int;
tmp44, err := this.Len()
if err != nil {
return 0, err
}
if (tmp44 >= 10) {
tmp43 = this.Groups[9].Value << 63
} else {
tmp43 = 0
}
this.value = uint64(uint64(((((((((this.Groups[0].Value | tmp27) | tmp29) | tmp31) | tmp33) | tmp35) | tmp37) | tmp39) | tmp41) | tmp43))
return this.value, nil
}
/**
* One byte group, clearly divided into 7-bit "value" chunk and 1-bit "continuation" flag.
*/
type Zchunk_CompressedInteger_Group struct {
IsLast bool
Value uint64
Idx int32
_io *kaitai.Stream
_root *Zchunk
_parent *Zchunk_CompressedInteger
}
func NewZchunk_CompressedInteger_Group(idx int32) *Zchunk_CompressedInteger_Group {
return &Zchunk_CompressedInteger_Group{
Idx: idx,
}
}
func (this Zchunk_CompressedInteger_Group) IO_() *kaitai.Stream {
return this._io
}
func (this *Zchunk_CompressedInteger_Group) Read(io *kaitai.Stream, parent *Zchunk_CompressedInteger, root *Zchunk) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp45, err := this._io.ReadBitsIntBe(1)
if err != nil {
return err
}
this.IsLast = tmp45 != 0
var tmp46 bool;
if (this.Idx == 9) {
tmp46 = true
} else {
tmp46 = this.IsLast
}
var tmp47 bool;
if (this.Idx == 9) {
tmp47 = true
} else {
tmp47 = this.IsLast
}
if !(this.IsLast == tmp46) {
return kaitai.NewValidationNotEqualError(tmp47, this.IsLast, this._io, "/types/compressed_integer/types/group/seq/0")
}
tmp48, err := this._io.ReadBitsIntBe(7)
if err != nil {
return err
}
this.Value = tmp48
var tmp49 int8;
if (this.Idx == 9) {
tmp49 = 1
} else {
tmp49 = 127
}
var tmp50 int8;
if (this.Idx == 9) {
tmp50 = 1
} else {
tmp50 = 127
}
if !(this.Value <= uint64(tmp49)) {
return kaitai.NewValidationGreaterThanError(uint64(tmp50), this.Value, this._io, "/types/compressed_integer/types/group/seq/1")
}
return err
}
/**
* If `true`, then this is the last byte of the compressed integer.
*
* Since this implementation only supports serialized values up to 10
* bytes, this must be `true` in the 10th group (`groups[9]`).
*/
/**
* The 7-bit (base128) numeric value chunk of this group
*
* Since this implementation only supports integer values up to 64 bits,
* the `value` in the 10th group (`groups[9]`) can only be `0` or `1`
* (otherwise the width of the represented value would be 65 bits or
* more, which is not supported).
*/
type Zchunk_HeaderLead struct {
Magic []byte
OverallChecksumType *Zchunk_ChecksumType
LenHeaderRest *Zchunk_CompressedInteger
HeaderChecksum []byte
_io *kaitai.Stream
_root *Zchunk
_parent *Zchunk
_f_isDetachedHeader bool
isDetachedHeader bool
}
func NewZchunk_HeaderLead() *Zchunk_HeaderLead {
return &Zchunk_HeaderLead{
}
}
func (this Zchunk_HeaderLead) IO_() *kaitai.Stream {
return this._io
}
func (this *Zchunk_HeaderLead) Read(io *kaitai.Stream, parent *Zchunk, root *Zchunk) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp51, err := this._io.ReadBytes(int(5))
if err != nil {
return err
}
tmp51 = tmp51
this.Magic = tmp51
if !( ((bytes.Equal(this.Magic, []uint8{0, 90, 67, 75, 49})) || (bytes.Equal(this.Magic, []uint8{0, 90, 72, 82, 49}))) ) {
return kaitai.NewValidationNotAnyOfError(this.Magic, this._io, "/types/header_lead/seq/0")
}
tmp52 := NewZchunk_ChecksumType()
err = tmp52.Read(this._io, this, this._root)
if err != nil {
return err
}
this.OverallChecksumType = tmp52
tmp53 := NewZchunk_CompressedInteger()
err = tmp53.Read(this._io, this, this._root)
if err != nil {
return err
}
this.LenHeaderRest = tmp53
tmp54, err := this.OverallChecksumType.LenChecksum()
if err != nil {
return err
}
tmp55, err := this._io.ReadBytes(int(tmp54))
if err != nil {
return err
}
tmp55 = tmp55
this.HeaderChecksum = tmp55
return err
}
/**
* Determines whether this file is a zchunk detached header (`.zhr`). If
* not, it is a complete zchunk file (`.zck`).
*/
func (this *Zchunk_HeaderLead) IsDetachedHeader() (v bool, err error) {
if (this._f_isDetachedHeader) {
return this.isDetachedHeader, nil
}
this._f_isDetachedHeader = true
this.isDetachedHeader = bool(this.Magic[2] == 72)
return this.isDetachedHeader, nil
}
/**
* There are two valid magic numbers for zchunk files:
*
* * `'\0ZCK1'` identifies a zchunk version 1 file (`.zck`)
* * `'\0ZHR1'` identifies a zchunk version 1 detached header file (`.zhr`)
*/
/**
* Type of the checksum used for `header_checksum` and
* `_root.header_rest.preface.data_checksum`.
*/
/**
* Size of the header, not including the lead
*/
/**
* Checksum of the entire header, which consists of `_root.lead` and
* `_root.header_rest` (i.e. everything from the beginning of the file to
* the end of `_root.header_rest`), not including the `header_checksum`
* field itself (i.e. the input for the checksum algorithm is a
* concatenation of the bytes preceding the `header_checksum` field with
* the bytes following it).
*
* For detached headers, the checksum is calculated as if the `magic`
* field were set to `'\0ZCK1'`, so that it matches the checksum in the
* full zchunk file.
*/
type Zchunk_HeaderWithoutLead struct {
Preface *Zchunk_Preface
LenIndex *Zchunk_CompressedInteger
Index *Zchunk_Index
NumSignatures *Zchunk_CompressedInteger
_io *kaitai.Stream
_root *Zchunk
_parent *Zchunk
_raw_Index []byte
}
func NewZchunk_HeaderWithoutLead() *Zchunk_HeaderWithoutLead {
return &Zchunk_HeaderWithoutLead{
}
}
func (this Zchunk_HeaderWithoutLead) IO_() *kaitai.Stream {
return this._io
}
func (this *Zchunk_HeaderWithoutLead) Read(io *kaitai.Stream, parent *Zchunk, root *Zchunk) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp56 := NewZchunk_Preface()
err = tmp56.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Preface = tmp56
tmp57 := NewZchunk_CompressedInteger()
err = tmp57.Read(this._io, this, this._root)
if err != nil {
return err
}
this.LenIndex = tmp57
tmp58, err := this.LenIndex.Value()
if err != nil {
return err
}
tmp59, err := this._io.ReadBytes(int(tmp58))
if err != nil {
return err
}
tmp59 = tmp59
this._raw_Index = tmp59
_io__raw_Index := kaitai.NewStream(bytes.NewReader(this._raw_Index))
tmp60 := NewZchunk_Index()
err = tmp60.Read(_io__raw_Index, this, this._root)
if err != nil {
return err
}
this.Index = tmp60
tmp61 := NewZchunk_CompressedInteger()
err = tmp61.Read(this._io, this, this._root)
if err != nil {
return err
}
this.NumSignatures = tmp61
{
_it := this.NumSignatures
tmp62, err := _it.Value()
if err != nil {
return err
}
if !(tmp62 == 0) {
return kaitai.NewValidationExprError(this.NumSignatures, this._io, "/types/header_without_lead/seq/3")
}
}
return err
}
/**
* Must be 0. The reference implementation also rejects any file with a
* non-zero "Signature count", throwing a fatal error stating "Signatures
* aren't supported yet" - see
* [`src/lib/header.c:259-264`](https://github.com/zchunk/zchunk/blob/99e51afa38c723e7c25834c2c3b305d20ef55d04/src/lib/header.c#L259-L264).
*
* Although the structure of signatures is defined [in the official
* textual
* specification](https://github.com/zchunk/zchunk/blob/99e51afa38c723e7c25834c2c3b305d20ef55d04/zchunk_format.txt#L219-L252),
* no signature types are defined, and as of this writing no publicly
* known implementation generates or interprets these signatures.
* Therefore, we've decided not to implement them here either.
*
* For more details, see
* <https://github.com/kaitai-io/kaitai_struct_formats/pull/539#discussion_r3713109887>.
*/
type Zchunk_Index struct {
ChunkChecksumType *Zchunk_ChecksumType
NumChunks *Zchunk_CompressedInteger
DictStream *Zchunk_CompressedInteger
DictChecksum []byte
UncompressedDictChecksum []byte
LenDict *Zchunk_CompressedInteger
LenUncompressedDict *Zchunk_CompressedInteger
ChunksMetadata []*Zchunk_Chunk
_io *kaitai.Stream
_root *Zchunk
_parent *Zchunk_HeaderWithoutLead
_f_numDataChunks bool
numDataChunks int
}
func NewZchunk_Index() *Zchunk_Index {
return &Zchunk_Index{
}
}
func (this Zchunk_Index) IO_() *kaitai.Stream {
return this._io
}
func (this *Zchunk_Index) Read(io *kaitai.Stream, parent *Zchunk_HeaderWithoutLead, root *Zchunk) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp63 := NewZchunk_ChecksumType()
err = tmp63.Read(this._io, this, this._root)
if err != nil {
return err
}
this.ChunkChecksumType = tmp63
tmp64 := NewZchunk_CompressedInteger()
err = tmp64.Read(this._io, this, this._root)
if err != nil {
return err
}
this.NumChunks = tmp64
{
_it := this.NumChunks
tmp65, err := _it.Value()
if err != nil {
return err
}
if !(tmp65 >= 1) {
return kaitai.NewValidationExprError(this.NumChunks, this._io, "/types/index/seq/1")
}
}
tmp66, err := this._parent.Preface.HasDataStreams()
if err != nil {
return err
}
if (tmp66) {
tmp67 := NewZchunk_CompressedInteger()
err = tmp67.Read(this._io, this, this._root)
if err != nil {
return err
}
this.DictStream = tmp67
{
_it := this.DictStream
tmp68, err := _it.Value()
if err != nil {
return err
}
if !(tmp68 == 0) {
return kaitai.NewValidationExprError(this.DictStream, this._io, "/types/index/seq/2")
}
}
}
tmp69, err := this.ChunkChecksumType.LenChecksum()
if err != nil {
return err
}
tmp70, err := this._io.ReadBytes(int(tmp69))
if err != nil {
return err
}
tmp70 = tmp70
this.DictChecksum = tmp70
tmp71, err := this._parent.Preface.HasUncompressedSource()
if err != nil {
return err
}
if (tmp71) {
tmp72, err := this.ChunkChecksumType.LenChecksum()
if err != nil {
return err
}
tmp73, err := this._io.ReadBytes(int(tmp72))
if err != nil {
return err
}
tmp73 = tmp73
this.UncompressedDictChecksum = tmp73
}
tmp74 := NewZchunk_CompressedInteger()
err = tmp74.Read(this._io, this, this._root)
if err != nil {
return err
}
this.LenDict = tmp74
tmp75 := NewZchunk_CompressedInteger()
err = tmp75.Read(this._io, this, this._root)
if err != nil {
return err
}
this.LenUncompressedDict = tmp75
tmp76, err := this.NumDataChunks()
if err != nil {
return err
}
for i := 0; i < int(tmp76); i++ {
_ = i
tmp77, err := this.ChunkChecksumType.LenChecksum()
if err != nil {
return err
}
tmp78, err := this._parent.Preface.HasDataStreams()
if err != nil {
return err
}
tmp79, err := this._parent.Preface.HasUncompressedSource()
if err != nil {
return err
}
tmp80 := NewZchunk_Chunk(tmp77, tmp78, tmp79)
err = tmp80.Read(this._io, this, this._root)
if err != nil {
return err
}
this.ChunksMetadata = append(this.ChunksMetadata, tmp80)
}
return err
}
/**
* Number of data chunks. `num_chunks` counts the dictionary as chunk 0,
* so it is one greater than this number.
*/
func (this *Zchunk_Index) NumDataChunks() (v int, err error) {
if (this._f_numDataChunks) {
return this.numDataChunks, nil
}
this._f_numDataChunks = true
tmp81, err := this.NumChunks.Value()
if err != nil {
return 0, err
}
this.numDataChunks = int(tmp81 - 1)
return this.numDataChunks, nil
}
/**
* Type of the checksum used for `dict_checksum` and for all
* `chunks_metadata[...].chunk_checksum` and
* `chunks_metadata[...].uncompressed_chunk_checksum`.
*/
/**
* Number of chunks, **including** the dictionary chunk.
*
* Must be at least 1, because the dictionary chunk is always present,
* even if it is empty. The reference implementation also fails when the
* number of chunks is 0, see
* [`src/lib/index/index_read.c:181-184`](https://github.com/zchunk/zchunk/blob/99e51afa38c723e7c25834c2c3b305d20ef55d04/src/lib/index/index_read.c#L181-L184).
*/
/**
* If present, it must always be 0.
* @see <a href="https://github.com/zchunk/zchunk/blob/99e51afa38c723e7c25834c2c3b305d20ef55d04/zchunk_format.txt#L159-L162">Source</a>
*/
/**
* Checksum of the uncompressed dictionary. It has no real use, as the
* uncompressed source won't have a dictionary.
*/
/**
* Metadata of the data chunks. The dictionary is chunk 0 and its
* metadata is stored in the `*dict*` fields above, so there is one fewer
* entry here than indicated by `num_chunks`.
*/
type Zchunk_OptionalElement struct {
ElementId *Zchunk_CompressedInteger
LenData *Zchunk_CompressedInteger
Data []byte
_io *kaitai.Stream
_root *Zchunk
_parent *Zchunk_Preface
}
func NewZchunk_OptionalElement() *Zchunk_OptionalElement {
return &Zchunk_OptionalElement{
}
}
func (this Zchunk_OptionalElement) IO_() *kaitai.Stream {
return this._io
}
func (this *Zchunk_OptionalElement) Read(io *kaitai.Stream, parent *Zchunk_Preface, root *Zchunk) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp82 := NewZchunk_CompressedInteger()
err = tmp82.Read(this._io, this, this._root)
if err != nil {
return err
}
this.ElementId = tmp82
tmp83 := NewZchunk_CompressedInteger()
err = tmp83.Read(this._io, this, this._root)
if err != nil {
return err
}
this.LenData = tmp83
tmp84, err := this.LenData.Value()
if err != nil {
return err
}
tmp85, err := this._io.ReadBytes(int(tmp84))
if err != nil {
return err
}
tmp85 = tmp85
this.Data = tmp85
return err
}
type Zchunk_Preface struct {
DataChecksum []byte
Flags *Zchunk_CompressedInteger
CompressionTypeInt *Zchunk_CompressedInteger
NumOptionalElements *Zchunk_CompressedInteger
OptionalElements []*Zchunk_OptionalElement
_io *kaitai.Stream
_root *Zchunk
_parent *Zchunk_HeaderWithoutLead
_f_compressionType bool
compressionType Zchunk_CompressionTypes
_f_hasDataStreams bool
hasDataStreams bool
_f_hasOptionalElements bool
hasOptionalElements bool
_f_hasUncompressedSource bool
hasUncompressedSource bool
}
func NewZchunk_Preface() *Zchunk_Preface {
return &Zchunk_Preface{
}
}
func (this Zchunk_Preface) IO_() *kaitai.Stream {
return this._io
}
func (this *Zchunk_Preface) Read(io *kaitai.Stream, parent *Zchunk_HeaderWithoutLead, root *Zchunk) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp86, err := this._root.Lead.OverallChecksumType.LenChecksum()
if err != nil {
return err
}
tmp87, err := this._io.ReadBytes(int(tmp86))
if err != nil {
return err
}
tmp87 = tmp87
this.DataChecksum = tmp87
tmp88 := NewZchunk_CompressedInteger()
err = tmp88.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Flags = tmp88
{
_it := this.Flags
tmp89, err := _it.Value()
if err != nil {
return err
}
if !(tmp89 <= 7) {
return kaitai.NewValidationExprError(this.Flags, this._io, "/types/preface/seq/1")
}
}
tmp90 := NewZchunk_CompressedInteger()
err = tmp90.Read(this._io, this, this._root)
if err != nil {
return err
}
this.CompressionTypeInt = tmp90
{
_it := this.CompressionTypeInt
tmp91, err := _it.Value()
if err != nil {
return err
}
tmp92, err := _it.Value()
if err != nil {
return err
}
if !( ((tmp91 == Zchunk_CompressionTypes__None) || (tmp92 == Zchunk_CompressionTypes__Zstd)) ) {
return kaitai.NewValidationExprError(this.CompressionTypeInt, this._io, "/types/preface/seq/2")
}
}
tmp93, err := this.HasOptionalElements()
if err != nil {
return err
}
if (tmp93) {
tmp94 := NewZchunk_CompressedInteger()
err = tmp94.Read(this._io, this, this._root)
if err != nil {
return err
}
this.NumOptionalElements = tmp94
{
_it := this.NumOptionalElements
tmp95, err := _it.Value()
if err != nil {
return err
}
if !(tmp95 >= 1) {
return kaitai.NewValidationExprError(this.NumOptionalElements, this._io, "/types/preface/seq/3")
}
}
}
tmp96, err := this.HasOptionalElements()
if err != nil {
return err
}
if (tmp96) {
tmp97, err := this.NumOptionalElements.Value()
if err != nil {
return err
}
for i := 0; i < int(tmp97); i++ {
_ = i
tmp98 := NewZchunk_OptionalElement()
err = tmp98.Read(this._io, this, this._root)
if err != nil {
return err
}
this.OptionalElements = append(this.OptionalElements, tmp98)
}
}
return err
}
func (this *Zchunk_Preface) CompressionType() (v Zchunk_CompressionTypes, err error) {
if (this._f_compressionType) {
return this.compressionType, nil
}
this._f_compressionType = true
tmp99, err := this.CompressionTypeInt.Value()
if err != nil {
return nil, err
}
this.compressionType = Zchunk_CompressionTypes(Zchunk_CompressionTypes(tmp99))
return this.compressionType, nil
}
func (this *Zchunk_Preface) HasDataStreams() (v bool, err error) {
if (this._f_hasDataStreams) {
return this.hasDataStreams, nil
}
this._f_hasDataStreams = true
tmp100, err := this.Flags.Value()
if err != nil {
return false, err
}
this.hasDataStreams = bool(tmp100 & 1 != 0)
return this.hasDataStreams, nil
}
func (this *Zchunk_Preface) HasOptionalElements() (v bool, err error) {
if (this._f_hasOptionalElements) {
return this.hasOptionalElements, nil
}
this._f_hasOptionalElements = true
tmp101, err := this.Flags.Value()
if err != nil {
return false, err
}
this.hasOptionalElements = bool(tmp101 & 2 != 0)
return this.hasOptionalElements, nil
}
/**
* The file may be applied against an uncompressed source. This adds an
* uncompressed checksum to every index entry, including the dictionary.
*/
func (this *Zchunk_Preface) HasUncompressedSource() (v bool, err error) {
if (this._f_hasUncompressedSource) {
return this.hasUncompressedSource, nil
}
this._f_hasUncompressedSource = true
tmp102, err := this.Flags.Value()
if err != nil {
return false, err
}
this.hasUncompressedSource = bool(tmp102 & 4 != 0)
return this.hasUncompressedSource, nil
}
/**
* Total data checksum. Checksum of everything after the header,
* including the compressed dictionary (`_root.dict`) and all compressed
* chunks (`_root.chunks`). The type of this checksum is
* `_root.lead.overall_checksum_type.value`.
*
* If `has_uncompressed_source` is true, this checksum must not be
* checked and should not be generated. In that case, the reference
* implementation writes it as all zeros - see the sample file
* [`mini-uncomp-cksums.zck`](https://github.com/kaitai-io/kaitai_struct_samples/blob/1d2fe11c971fb7e86f343b77a1ed341a0217e86a/archive/zchunk/README.md#mini-uncomp-cksumszck).
*/
/**
* Compressed integer containing a bitmask of the flags. All unused flags
* MUST be set to 0. If a decoder sees a flag set that it doesn't
* recognize, it MUST exit with an error.
* @see <a href="https://github.com/zchunk/zchunk/blob/99e51afa38c723e7c25834c2c3b305d20ef55d04/zchunk_format.txt#L78-L81">Source</a>
*/
/**
* Raw integer, don't read this field - access `compression_type`
* instead.
*/
/**
* If present, it must be at least 1. This is because if there are no
* optional elements, `has_optional_elements` must be false, and then
* neither this field nor `optional_elements` is present.
* @see <a href="https://github.com/zchunk/zchunk/blob/99e51afa38c723e7c25834c2c3b305d20ef55d04/zchunk_format.txt#L99-L102">Source</a>
*/