ZIP archive file: Go parsing library

ZIP is a popular archive file format, introduced in 1989 by Phil Katz and originally implemented in PKZIP utility by PKWARE.

Thanks to solid support of it in most desktop environments and operating systems, and algorithms / specs availability in public domain, it quickly became tool of choice for implementing file containers.

For example, Java .jar files, OpenDocument, Office Open XML, EPUB files are actually ZIP archives.

File extension

zip

KS implementation details

License: CC0-1.0
Minimal Kaitai Struct required: 0.9

References

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

Go source code to parse ZIP archive file

zip.go

// 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"
	"io"
)


/**
 * ZIP is a popular archive file format, introduced in 1989 by Phil Katz
 * and originally implemented in PKZIP utility by PKWARE.
 * 
 * Thanks to solid support of it in most desktop environments and
 * operating systems, and algorithms / specs availability in public
 * domain, it quickly became tool of choice for implementing file
 * containers.
 * 
 * For example, Java .jar files, OpenDocument, Office Open XML, EPUB files
 * are actually ZIP archives.
 * @see <a href="https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT">Source</a>
 * @see <a href="https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html">Source</a>
 */

type Zip_Compression int
const (
	Zip_Compression__None Zip_Compression = 0
	Zip_Compression__Shrunk Zip_Compression = 1
	Zip_Compression__Reduced1 Zip_Compression = 2
	Zip_Compression__Reduced2 Zip_Compression = 3
	Zip_Compression__Reduced3 Zip_Compression = 4
	Zip_Compression__Reduced4 Zip_Compression = 5
	Zip_Compression__Imploded Zip_Compression = 6
	Zip_Compression__Deflated Zip_Compression = 8
	Zip_Compression__EnhancedDeflated Zip_Compression = 9
	Zip_Compression__PkwareDclImploded Zip_Compression = 10
	Zip_Compression__Bzip2 Zip_Compression = 12
	Zip_Compression__Lzma Zip_Compression = 14
	Zip_Compression__IbmTerse Zip_Compression = 18
	Zip_Compression__IbmLz77Z Zip_Compression = 19
	Zip_Compression__Zstandard Zip_Compression = 93
	Zip_Compression__Mp3 Zip_Compression = 94
	Zip_Compression__Xz Zip_Compression = 95
	Zip_Compression__Jpeg Zip_Compression = 96
	Zip_Compression__Wavpack Zip_Compression = 97
	Zip_Compression__Ppmd Zip_Compression = 98
	Zip_Compression__AexEncryptionMarker Zip_Compression = 99
)
var values_Zip_Compression = map[Zip_Compression]struct{}{0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 8: {}, 9: {}, 10: {}, 12: {}, 14: {}, 18: {}, 19: {}, 93: {}, 94: {}, 95: {}, 96: {}, 97: {}, 98: {}, 99: {}}
func (v Zip_Compression) isDefined() bool {
	_, ok := values_Zip_Compression[v]
	return ok
}

type Zip_ExtraCodes int
const (
	Zip_ExtraCodes__Zip64 Zip_ExtraCodes = 1
	Zip_ExtraCodes__AvInfo Zip_ExtraCodes = 7
	Zip_ExtraCodes__Os2 Zip_ExtraCodes = 9
	Zip_ExtraCodes__Ntfs Zip_ExtraCodes = 10
	Zip_ExtraCodes__Openvms Zip_ExtraCodes = 12
	Zip_ExtraCodes__PkwareUnix Zip_ExtraCodes = 13
	Zip_ExtraCodes__FileStreamAndForkDescriptors Zip_ExtraCodes = 14
	Zip_ExtraCodes__PatchDescriptor Zip_ExtraCodes = 15
	Zip_ExtraCodes__Pkcs7 Zip_ExtraCodes = 20
	Zip_ExtraCodes__X509CertIdAndSignatureForFile Zip_ExtraCodes = 21
	Zip_ExtraCodes__X509CertIdForCentralDir Zip_ExtraCodes = 22
	Zip_ExtraCodes__StrongEncryptionHeader Zip_ExtraCodes = 23
	Zip_ExtraCodes__RecordManagementControls Zip_ExtraCodes = 24
	Zip_ExtraCodes__Pkcs7EncRecipCertList Zip_ExtraCodes = 25
	Zip_ExtraCodes__IbmS390Uncomp Zip_ExtraCodes = 101
	Zip_ExtraCodes__IbmS390Comp Zip_ExtraCodes = 102
	Zip_ExtraCodes__Poszip4690 Zip_ExtraCodes = 18064
	Zip_ExtraCodes__ExtendedTimestamp Zip_ExtraCodes = 21589
	Zip_ExtraCodes__Beos Zip_ExtraCodes = 25922
	Zip_ExtraCodes__AsiUnix Zip_ExtraCodes = 30062
	Zip_ExtraCodes__InfozipUnix Zip_ExtraCodes = 30805
	Zip_ExtraCodes__InfozipUnixVarSize Zip_ExtraCodes = 30837
	Zip_ExtraCodes__AexEncryption Zip_ExtraCodes = 39169
	Zip_ExtraCodes__ApacheCommonsCompress Zip_ExtraCodes = 41246
	Zip_ExtraCodes__MicrosoftOpenPackagingGrowthHint Zip_ExtraCodes = 41504
	Zip_ExtraCodes__SmsQdos Zip_ExtraCodes = 64842
)
var values_Zip_ExtraCodes = map[Zip_ExtraCodes]struct{}{1: {}, 7: {}, 9: {}, 10: {}, 12: {}, 13: {}, 14: {}, 15: {}, 20: {}, 21: {}, 22: {}, 23: {}, 24: {}, 25: {}, 101: {}, 102: {}, 18064: {}, 21589: {}, 25922: {}, 30062: {}, 30805: {}, 30837: {}, 39169: {}, 41246: {}, 41504: {}, 64842: {}}
func (v Zip_ExtraCodes) isDefined() bool {
	_, ok := values_Zip_ExtraCodes[v]
	return ok
}
type Zip struct {
	Sections []*Zip_PkSection
	_io *kaitai.Stream
	_root *Zip
	_parent kaitai.Struct
}
func NewZip() *Zip {
	return &Zip{
	}
}

func (this Zip) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip) Read(io *kaitai.Stream, parent kaitai.Struct, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	for i := 0;; i++ {
		tmp1, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp1 {
			break
		}
		tmp2 := NewZip_PkSection()
		err = tmp2.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Sections = append(this.Sections, tmp2)
	}
	return err
}

/**
 * @see <a href="https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT">- 4.3.12</a>
 */
type Zip_CentralDirEntry struct {
	VersionMadeBy uint16
	VersionNeededToExtract uint16
	Flags uint16
	CompressionMethod Zip_Compression
	FileModTime *DosDatetime
	Crc32 uint32
	LenBodyCompressed uint32
	LenBodyUncompressed uint32
	LenFileName uint16
	LenExtra uint16
	LenComment uint16
	DiskNumberStart uint16
	IntFileAttr uint16
	ExtFileAttr uint32
	OfsLocalHeader int32
	FileName string
	Extra *Zip_Extras
	Comment string
	_io *kaitai.Stream
	_root *Zip
	_parent *Zip_PkSection
	_raw_FileModTime []byte
	_raw_Extra []byte
	_f_localHeader bool
	localHeader *Zip_PkSection
}
func NewZip_CentralDirEntry() *Zip_CentralDirEntry {
	return &Zip_CentralDirEntry{
	}
}

func (this Zip_CentralDirEntry) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip_CentralDirEntry) Read(io *kaitai.Stream, parent *Zip_PkSection, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp3, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.VersionMadeBy = uint16(tmp3)
	tmp4, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.VersionNeededToExtract = uint16(tmp4)
	tmp5, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.Flags = uint16(tmp5)
	tmp6, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.CompressionMethod = Zip_Compression(tmp6)
	tmp7, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp7 = tmp7
	this._raw_FileModTime = tmp7
	_io__raw_FileModTime := kaitai.NewStream(bytes.NewReader(this._raw_FileModTime))
	tmp8 := NewDosDatetime()
	err = tmp8.Read(_io__raw_FileModTime, nil, nil)
	if err != nil {
		return err
	}
	this.FileModTime = tmp8
	tmp9, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Crc32 = uint32(tmp9)
	tmp10, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LenBodyCompressed = uint32(tmp10)
	tmp11, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LenBodyUncompressed = uint32(tmp11)
	tmp12, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.LenFileName = uint16(tmp12)
	tmp13, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.LenExtra = uint16(tmp13)
	tmp14, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.LenComment = uint16(tmp14)
	tmp15, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.DiskNumberStart = uint16(tmp15)
	tmp16, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.IntFileAttr = uint16(tmp16)
	tmp17, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.ExtFileAttr = uint32(tmp17)
	tmp18, err := this._io.ReadS4le()
	if err != nil {
		return err
	}
	this.OfsLocalHeader = int32(tmp18)
	tmp19, err := this._io.ReadBytes(int(this.LenFileName))
	if err != nil {
		return err
	}
	tmp19 = tmp19
	this.FileName = string(tmp19)
	tmp20, err := this._io.ReadBytes(int(this.LenExtra))
	if err != nil {
		return err
	}
	tmp20 = tmp20
	this._raw_Extra = tmp20
	_io__raw_Extra := kaitai.NewStream(bytes.NewReader(this._raw_Extra))
	tmp21 := NewZip_Extras()
	err = tmp21.Read(_io__raw_Extra, this, this._root)
	if err != nil {
		return err
	}
	this.Extra = tmp21
	tmp22, err := this._io.ReadBytes(int(this.LenComment))
	if err != nil {
		return err
	}
	tmp22 = tmp22
	this.Comment = string(tmp22)
	return err
}
func (this *Zip_CentralDirEntry) LocalHeader() (v *Zip_PkSection, err error) {
	if (this._f_localHeader) {
		return this.localHeader, nil
	}
	this._f_localHeader = true
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(this.OfsLocalHeader), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp23 := NewZip_PkSection()
	err = tmp23.Read(this._io, this, this._root)
	if err != nil {
		return nil, err
	}
	this.localHeader = tmp23
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.localHeader, nil
}
type Zip_DataDescriptor struct {
	Crc32 uint32
	LenBodyCompressed uint32
	LenBodyUncompressed uint32
	_io *kaitai.Stream
	_root *Zip
	_parent *Zip_PkSection
}
func NewZip_DataDescriptor() *Zip_DataDescriptor {
	return &Zip_DataDescriptor{
	}
}

func (this Zip_DataDescriptor) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip_DataDescriptor) Read(io *kaitai.Stream, parent *Zip_PkSection, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp24, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Crc32 = uint32(tmp24)
	tmp25, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LenBodyCompressed = uint32(tmp25)
	tmp26, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LenBodyUncompressed = uint32(tmp26)
	return err
}
type Zip_EndOfCentralDir struct {
	DiskOfEndOfCentralDir uint16
	DiskOfCentralDir uint16
	NumCentralDirEntriesOnDisk uint16
	NumCentralDirEntriesTotal uint16
	LenCentralDir uint32
	OfsCentralDir uint32
	LenComment uint16
	Comment string
	_io *kaitai.Stream
	_root *Zip
	_parent *Zip_PkSection
}
func NewZip_EndOfCentralDir() *Zip_EndOfCentralDir {
	return &Zip_EndOfCentralDir{
	}
}

func (this Zip_EndOfCentralDir) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip_EndOfCentralDir) Read(io *kaitai.Stream, parent *Zip_PkSection, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp27, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.DiskOfEndOfCentralDir = uint16(tmp27)
	tmp28, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.DiskOfCentralDir = uint16(tmp28)
	tmp29, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.NumCentralDirEntriesOnDisk = uint16(tmp29)
	tmp30, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.NumCentralDirEntriesTotal = uint16(tmp30)
	tmp31, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LenCentralDir = uint32(tmp31)
	tmp32, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.OfsCentralDir = uint32(tmp32)
	tmp33, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.LenComment = uint16(tmp33)
	tmp34, err := this._io.ReadBytes(int(this.LenComment))
	if err != nil {
		return err
	}
	tmp34 = tmp34
	this.Comment = string(tmp34)
	return err
}
type Zip_ExtraField struct {
	Code Zip_ExtraCodes
	LenBody uint16
	Body interface{}
	_io *kaitai.Stream
	_root *Zip
	_parent *Zip_Extras
	_raw_Body []byte
}
func NewZip_ExtraField() *Zip_ExtraField {
	return &Zip_ExtraField{
	}
}

func (this Zip_ExtraField) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip_ExtraField) Read(io *kaitai.Stream, parent *Zip_Extras, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp35, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.Code = Zip_ExtraCodes(tmp35)
	tmp36, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.LenBody = uint16(tmp36)
	switch (this.Code) {
	case Zip_ExtraCodes__ExtendedTimestamp:
		tmp37, err := this._io.ReadBytes(int(this.LenBody))
		if err != nil {
			return err
		}
		tmp37 = tmp37
		this._raw_Body = tmp37
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp38 := NewZip_ExtraField_ExtendedTimestamp()
		err = tmp38.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp38
	case Zip_ExtraCodes__InfozipUnixVarSize:
		tmp39, err := this._io.ReadBytes(int(this.LenBody))
		if err != nil {
			return err
		}
		tmp39 = tmp39
		this._raw_Body = tmp39
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp40 := NewZip_ExtraField_InfozipUnixVarSize()
		err = tmp40.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp40
	case Zip_ExtraCodes__Ntfs:
		tmp41, err := this._io.ReadBytes(int(this.LenBody))
		if err != nil {
			return err
		}
		tmp41 = tmp41
		this._raw_Body = tmp41
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp42 := NewZip_ExtraField_Ntfs()
		err = tmp42.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp42
	default:
		tmp43, err := this._io.ReadBytes(int(this.LenBody))
		if err != nil {
			return err
		}
		tmp43 = tmp43
		this._raw_Body = tmp43
	}
	return err
}

/**
 * @see <a href="https://github.com/LuaDist/zip/blob/b710806/proginfo/extrafld.txt#L817">Source</a>
 */
type Zip_ExtraField_ExtendedTimestamp struct {
	Flags *Zip_ExtraField_ExtendedTimestamp_InfoFlags
	ModTime uint32
	AccessTime uint32
	CreateTime uint32
	_io *kaitai.Stream
	_root *Zip
	_parent *Zip_ExtraField
	_raw_Flags []byte
}
func NewZip_ExtraField_ExtendedTimestamp() *Zip_ExtraField_ExtendedTimestamp {
	return &Zip_ExtraField_ExtendedTimestamp{
	}
}

func (this Zip_ExtraField_ExtendedTimestamp) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip_ExtraField_ExtendedTimestamp) Read(io *kaitai.Stream, parent *Zip_ExtraField, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp44, err := this._io.ReadBytes(int(1))
	if err != nil {
		return err
	}
	tmp44 = tmp44
	this._raw_Flags = tmp44
	_io__raw_Flags := kaitai.NewStream(bytes.NewReader(this._raw_Flags))
	tmp45 := NewZip_ExtraField_ExtendedTimestamp_InfoFlags()
	err = tmp45.Read(_io__raw_Flags, this, this._root)
	if err != nil {
		return err
	}
	this.Flags = tmp45
	if (this.Flags.HasModTime) {
		tmp46, err := this._io.ReadU4le()
		if err != nil {
			return err
		}
		this.ModTime = uint32(tmp46)
	}
	if (this.Flags.HasAccessTime) {
		tmp47, err := this._io.ReadU4le()
		if err != nil {
			return err
		}
		this.AccessTime = uint32(tmp47)
	}
	if (this.Flags.HasCreateTime) {
		tmp48, err := this._io.ReadU4le()
		if err != nil {
			return err
		}
		this.CreateTime = uint32(tmp48)
	}
	return err
}

/**
 * Unix timestamp
 */

/**
 * Unix timestamp
 */

/**
 * Unix timestamp
 */
type Zip_ExtraField_ExtendedTimestamp_InfoFlags struct {
	HasModTime bool
	HasAccessTime bool
	HasCreateTime bool
	Reserved uint64
	_io *kaitai.Stream
	_root *Zip
	_parent *Zip_ExtraField_ExtendedTimestamp
}
func NewZip_ExtraField_ExtendedTimestamp_InfoFlags() *Zip_ExtraField_ExtendedTimestamp_InfoFlags {
	return &Zip_ExtraField_ExtendedTimestamp_InfoFlags{
	}
}

func (this Zip_ExtraField_ExtendedTimestamp_InfoFlags) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip_ExtraField_ExtendedTimestamp_InfoFlags) Read(io *kaitai.Stream, parent *Zip_ExtraField_ExtendedTimestamp, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp49, err := this._io.ReadBitsIntLe(1)
	if err != nil {
		return err
	}
	this.HasModTime = tmp49 != 0
	tmp50, err := this._io.ReadBitsIntLe(1)
	if err != nil {
		return err
	}
	this.HasAccessTime = tmp50 != 0
	tmp51, err := this._io.ReadBitsIntLe(1)
	if err != nil {
		return err
	}
	this.HasCreateTime = tmp51 != 0
	tmp52, err := this._io.ReadBitsIntLe(5)
	if err != nil {
		return err
	}
	this.Reserved = tmp52
	return err
}

/**
 * @see <a href="https://github.com/LuaDist/zip/blob/b710806/proginfo/extrafld.txt#L1339">Source</a>
 */
type Zip_ExtraField_InfozipUnixVarSize struct {
	Version uint8
	LenUid uint8
	Uid []byte
	LenGid uint8
	Gid []byte
	_io *kaitai.Stream
	_root *Zip
	_parent *Zip_ExtraField
}
func NewZip_ExtraField_InfozipUnixVarSize() *Zip_ExtraField_InfozipUnixVarSize {
	return &Zip_ExtraField_InfozipUnixVarSize{
	}
}

func (this Zip_ExtraField_InfozipUnixVarSize) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip_ExtraField_InfozipUnixVarSize) Read(io *kaitai.Stream, parent *Zip_ExtraField, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp53, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Version = tmp53
	tmp54, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.LenUid = tmp54
	tmp55, err := this._io.ReadBytes(int(this.LenUid))
	if err != nil {
		return err
	}
	tmp55 = tmp55
	this.Uid = tmp55
	tmp56, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.LenGid = tmp56
	tmp57, err := this._io.ReadBytes(int(this.LenGid))
	if err != nil {
		return err
	}
	tmp57 = tmp57
	this.Gid = tmp57
	return err
}

/**
 * Version of this extra field, currently 1
 */

/**
 * Size of UID field
 */

/**
 * UID (User ID) for a file
 */

/**
 * Size of GID field
 */

/**
 * GID (Group ID) for a file
 */

/**
 * @see <a href="https://github.com/LuaDist/zip/blob/b710806/proginfo/extrafld.txt#L191">Source</a>
 */
type Zip_ExtraField_Ntfs struct {
	Reserved uint32
	Attributes []*Zip_ExtraField_Ntfs_Attribute
	_io *kaitai.Stream
	_root *Zip
	_parent *Zip_ExtraField
}
func NewZip_ExtraField_Ntfs() *Zip_ExtraField_Ntfs {
	return &Zip_ExtraField_Ntfs{
	}
}

func (this Zip_ExtraField_Ntfs) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip_ExtraField_Ntfs) Read(io *kaitai.Stream, parent *Zip_ExtraField, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp58, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Reserved = uint32(tmp58)
	for i := 0;; i++ {
		tmp59, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp59 {
			break
		}
		tmp60 := NewZip_ExtraField_Ntfs_Attribute()
		err = tmp60.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Attributes = append(this.Attributes, tmp60)
	}
	return err
}
type Zip_ExtraField_Ntfs_Attribute struct {
	Tag uint16
	LenBody uint16
	Body interface{}
	_io *kaitai.Stream
	_root *Zip
	_parent *Zip_ExtraField_Ntfs
	_raw_Body []byte
}
func NewZip_ExtraField_Ntfs_Attribute() *Zip_ExtraField_Ntfs_Attribute {
	return &Zip_ExtraField_Ntfs_Attribute{
	}
}

func (this Zip_ExtraField_Ntfs_Attribute) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip_ExtraField_Ntfs_Attribute) Read(io *kaitai.Stream, parent *Zip_ExtraField_Ntfs, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp61, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.Tag = uint16(tmp61)
	tmp62, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.LenBody = uint16(tmp62)
	switch (this.Tag) {
	case 1:
		tmp63, err := this._io.ReadBytes(int(this.LenBody))
		if err != nil {
			return err
		}
		tmp63 = tmp63
		this._raw_Body = tmp63
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp64 := NewZip_ExtraField_Ntfs_Attribute1()
		err = tmp64.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp64
	default:
		tmp65, err := this._io.ReadBytes(int(this.LenBody))
		if err != nil {
			return err
		}
		tmp65 = tmp65
		this._raw_Body = tmp65
	}
	return err
}
type Zip_ExtraField_Ntfs_Attribute1 struct {
	LastModTime uint64
	LastAccessTime uint64
	CreationTime uint64
	_io *kaitai.Stream
	_root *Zip
	_parent *Zip_ExtraField_Ntfs_Attribute
}
func NewZip_ExtraField_Ntfs_Attribute1() *Zip_ExtraField_Ntfs_Attribute1 {
	return &Zip_ExtraField_Ntfs_Attribute1{
	}
}

func (this Zip_ExtraField_Ntfs_Attribute1) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip_ExtraField_Ntfs_Attribute1) Read(io *kaitai.Stream, parent *Zip_ExtraField_Ntfs_Attribute, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp66, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.LastModTime = uint64(tmp66)
	tmp67, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.LastAccessTime = uint64(tmp67)
	tmp68, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.CreationTime = uint64(tmp68)
	return err
}
type Zip_Extras struct {
	Entries []*Zip_ExtraField
	_io *kaitai.Stream
	_root *Zip
	_parent kaitai.Struct
}
func NewZip_Extras() *Zip_Extras {
	return &Zip_Extras{
	}
}

func (this Zip_Extras) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip_Extras) Read(io *kaitai.Stream, parent kaitai.Struct, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	for i := 0;; i++ {
		tmp69, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp69 {
			break
		}
		tmp70 := NewZip_ExtraField()
		err = tmp70.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Entries = append(this.Entries, tmp70)
	}
	return err
}
type Zip_LocalFile struct {
	Header *Zip_LocalFileHeader
	Body []byte
	_io *kaitai.Stream
	_root *Zip
	_parent *Zip_PkSection
}
func NewZip_LocalFile() *Zip_LocalFile {
	return &Zip_LocalFile{
	}
}

func (this Zip_LocalFile) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip_LocalFile) Read(io *kaitai.Stream, parent *Zip_PkSection, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp71 := NewZip_LocalFileHeader()
	err = tmp71.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Header = tmp71
	tmp72, err := this._io.ReadBytes(int(this.Header.LenBodyCompressed))
	if err != nil {
		return err
	}
	tmp72 = tmp72
	this.Body = tmp72
	return err
}
type Zip_LocalFileHeader struct {
	Version uint16
	Flags *Zip_LocalFileHeader_GpFlags
	CompressionMethod Zip_Compression
	FileModTime *DosDatetime
	Crc32 uint32
	LenBodyCompressed uint32
	LenBodyUncompressed uint32
	LenFileName uint16
	LenExtra uint16
	FileName string
	Extra *Zip_Extras
	_io *kaitai.Stream
	_root *Zip
	_parent *Zip_LocalFile
	_raw_Flags []byte
	_raw_FileModTime []byte
	_raw_Extra []byte
}
func NewZip_LocalFileHeader() *Zip_LocalFileHeader {
	return &Zip_LocalFileHeader{
	}
}

func (this Zip_LocalFileHeader) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip_LocalFileHeader) Read(io *kaitai.Stream, parent *Zip_LocalFile, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp73, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.Version = uint16(tmp73)
	tmp74, err := this._io.ReadBytes(int(2))
	if err != nil {
		return err
	}
	tmp74 = tmp74
	this._raw_Flags = tmp74
	_io__raw_Flags := kaitai.NewStream(bytes.NewReader(this._raw_Flags))
	tmp75 := NewZip_LocalFileHeader_GpFlags()
	err = tmp75.Read(_io__raw_Flags, this, this._root)
	if err != nil {
		return err
	}
	this.Flags = tmp75
	tmp76, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.CompressionMethod = Zip_Compression(tmp76)
	tmp77, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp77 = tmp77
	this._raw_FileModTime = tmp77
	_io__raw_FileModTime := kaitai.NewStream(bytes.NewReader(this._raw_FileModTime))
	tmp78 := NewDosDatetime()
	err = tmp78.Read(_io__raw_FileModTime, nil, nil)
	if err != nil {
		return err
	}
	this.FileModTime = tmp78
	tmp79, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Crc32 = uint32(tmp79)
	tmp80, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LenBodyCompressed = uint32(tmp80)
	tmp81, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LenBodyUncompressed = uint32(tmp81)
	tmp82, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.LenFileName = uint16(tmp82)
	tmp83, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.LenExtra = uint16(tmp83)
	tmp84, err := this._io.ReadBytes(int(this.LenFileName))
	if err != nil {
		return err
	}
	tmp84 = tmp84
	this.FileName = string(tmp84)
	tmp85, err := this._io.ReadBytes(int(this.LenExtra))
	if err != nil {
		return err
	}
	tmp85 = tmp85
	this._raw_Extra = tmp85
	_io__raw_Extra := kaitai.NewStream(bytes.NewReader(this._raw_Extra))
	tmp86 := NewZip_Extras()
	err = tmp86.Read(_io__raw_Extra, this, this._root)
	if err != nil {
		return err
	}
	this.Extra = tmp86
	return err
}

/**
 * @see <a href="https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT">- 4.4.4</a>
 * @see <a href="https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html">Local file headers</a>
 */

type Zip_LocalFileHeader_GpFlags_DeflateMode int
const (
	Zip_LocalFileHeader_GpFlags_DeflateMode__Normal Zip_LocalFileHeader_GpFlags_DeflateMode = 0
	Zip_LocalFileHeader_GpFlags_DeflateMode__Maximum Zip_LocalFileHeader_GpFlags_DeflateMode = 1
	Zip_LocalFileHeader_GpFlags_DeflateMode__Fast Zip_LocalFileHeader_GpFlags_DeflateMode = 2
	Zip_LocalFileHeader_GpFlags_DeflateMode__SuperFast Zip_LocalFileHeader_GpFlags_DeflateMode = 3
)
var values_Zip_LocalFileHeader_GpFlags_DeflateMode = map[Zip_LocalFileHeader_GpFlags_DeflateMode]struct{}{0: {}, 1: {}, 2: {}, 3: {}}
func (v Zip_LocalFileHeader_GpFlags_DeflateMode) isDefined() bool {
	_, ok := values_Zip_LocalFileHeader_GpFlags_DeflateMode[v]
	return ok
}
type Zip_LocalFileHeader_GpFlags struct {
	FileEncrypted bool
	CompOptionsRaw uint64
	HasDataDescriptor bool
	Reserved1 bool
	CompPatchedData bool
	StrongEncrypt bool
	Reserved2 uint64
	LangEncoding bool
	Reserved3 bool
	MaskHeaderValues bool
	Reserved4 uint64
	_io *kaitai.Stream
	_root *Zip
	_parent *Zip_LocalFileHeader
	_f_deflatedMode bool
	deflatedMode Zip_LocalFileHeader_GpFlags_DeflateMode
	_f_implodedDictByteSize bool
	implodedDictByteSize int
	_f_implodedNumSfTrees bool
	implodedNumSfTrees int8
	_f_lzmaHasEosMarker bool
	lzmaHasEosMarker bool
}
func NewZip_LocalFileHeader_GpFlags() *Zip_LocalFileHeader_GpFlags {
	return &Zip_LocalFileHeader_GpFlags{
	}
}

func (this Zip_LocalFileHeader_GpFlags) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip_LocalFileHeader_GpFlags) Read(io *kaitai.Stream, parent *Zip_LocalFileHeader, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp87, err := this._io.ReadBitsIntLe(1)
	if err != nil {
		return err
	}
	this.FileEncrypted = tmp87 != 0
	tmp88, err := this._io.ReadBitsIntLe(2)
	if err != nil {
		return err
	}
	this.CompOptionsRaw = tmp88
	tmp89, err := this._io.ReadBitsIntLe(1)
	if err != nil {
		return err
	}
	this.HasDataDescriptor = tmp89 != 0
	tmp90, err := this._io.ReadBitsIntLe(1)
	if err != nil {
		return err
	}
	this.Reserved1 = tmp90 != 0
	tmp91, err := this._io.ReadBitsIntLe(1)
	if err != nil {
		return err
	}
	this.CompPatchedData = tmp91 != 0
	tmp92, err := this._io.ReadBitsIntLe(1)
	if err != nil {
		return err
	}
	this.StrongEncrypt = tmp92 != 0
	tmp93, err := this._io.ReadBitsIntLe(4)
	if err != nil {
		return err
	}
	this.Reserved2 = tmp93
	tmp94, err := this._io.ReadBitsIntLe(1)
	if err != nil {
		return err
	}
	this.LangEncoding = tmp94 != 0
	tmp95, err := this._io.ReadBitsIntLe(1)
	if err != nil {
		return err
	}
	this.Reserved3 = tmp95 != 0
	tmp96, err := this._io.ReadBitsIntLe(1)
	if err != nil {
		return err
	}
	this.MaskHeaderValues = tmp96 != 0
	tmp97, err := this._io.ReadBitsIntLe(2)
	if err != nil {
		return err
	}
	this.Reserved4 = tmp97
	return err
}
func (this *Zip_LocalFileHeader_GpFlags) DeflatedMode() (v Zip_LocalFileHeader_GpFlags_DeflateMode, err error) {
	if (this._f_deflatedMode) {
		return this.deflatedMode, nil
	}
	this._f_deflatedMode = true
	if ( ((this._parent.CompressionMethod == Zip_Compression__Deflated) || (this._parent.CompressionMethod == Zip_Compression__EnhancedDeflated)) ) {
		this.deflatedMode = Zip_LocalFileHeader_GpFlags_DeflateMode(Zip_LocalFileHeader_GpFlags_DeflateMode(this.CompOptionsRaw))
	}
	return this.deflatedMode, nil
}

/**
 * 8KiB or 4KiB in bytes
 */
func (this *Zip_LocalFileHeader_GpFlags) ImplodedDictByteSize() (v int, err error) {
	if (this._f_implodedDictByteSize) {
		return this.implodedDictByteSize, nil
	}
	this._f_implodedDictByteSize = true
	if (this._parent.CompressionMethod == Zip_Compression__Imploded) {
		var tmp98 int8;
		if (this.CompOptionsRaw & 1 != 0) {
			tmp98 = 8
		} else {
			tmp98 = 4
		}
		this.implodedDictByteSize = int(tmp98 * 1024)
	}
	return this.implodedDictByteSize, nil
}
func (this *Zip_LocalFileHeader_GpFlags) ImplodedNumSfTrees() (v int8, err error) {
	if (this._f_implodedNumSfTrees) {
		return this.implodedNumSfTrees, nil
	}
	this._f_implodedNumSfTrees = true
	if (this._parent.CompressionMethod == Zip_Compression__Imploded) {
		var tmp99 int8;
		if (this.CompOptionsRaw & 2 != 0) {
			tmp99 = 3
		} else {
			tmp99 = 2
		}
		this.implodedNumSfTrees = int8(tmp99)
	}
	return this.implodedNumSfTrees, nil
}
func (this *Zip_LocalFileHeader_GpFlags) LzmaHasEosMarker() (v bool, err error) {
	if (this._f_lzmaHasEosMarker) {
		return this.lzmaHasEosMarker, nil
	}
	this._f_lzmaHasEosMarker = true
	if (this._parent.CompressionMethod == Zip_Compression__Lzma) {
		this.lzmaHasEosMarker = bool(this.CompOptionsRaw & 1 != 0)
	}
	return this.lzmaHasEosMarker, nil
}

/**
 * internal; access derived value instances instead
 */
type Zip_PkSection struct {
	Magic []byte
	SectionType uint16
	Body kaitai.Struct
	_io *kaitai.Stream
	_root *Zip
	_parent kaitai.Struct
}
func NewZip_PkSection() *Zip_PkSection {
	return &Zip_PkSection{
	}
}

func (this Zip_PkSection) IO_() *kaitai.Stream {
	return this._io
}

func (this *Zip_PkSection) Read(io *kaitai.Stream, parent kaitai.Struct, root *Zip) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp100, err := this._io.ReadBytes(int(2))
	if err != nil {
		return err
	}
	tmp100 = tmp100
	this.Magic = tmp100
	if !(bytes.Equal(this.Magic, []uint8{80, 75})) {
		return kaitai.NewValidationNotEqualError([]uint8{80, 75}, this.Magic, this._io, "/types/pk_section/seq/0")
	}
	tmp101, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.SectionType = uint16(tmp101)
	switch (this.SectionType) {
	case 1027:
		tmp102 := NewZip_LocalFile()
		err = tmp102.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp102
	case 1541:
		tmp103 := NewZip_EndOfCentralDir()
		err = tmp103.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp103
	case 2055:
		tmp104 := NewZip_DataDescriptor()
		err = tmp104.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp104
	case 513:
		tmp105 := NewZip_CentralDirEntry()
		err = tmp105.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp105
	}
	return err
}