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


/**
 * MiniFS is a file system found in certain firmware files from TP-Link
 * (including its Mercusys brand) and Mercury. Such firmware contains an RTOS
 * kernel, e.g. VxWorks in
 * [`RE450(V4)_210531.zip`](https://static.tp-link.com/firmware/2021/202107/20210709/RE450(V4)_210531.zip)
 * ([archived](https://web.archive.org/web/20261105175157/https://static.tp-link.com/firmware/2021/202107/20210709/RE450(V4)_210531.zip))
 * or TPOS, TP-Link's RTOS, in
 * [`TL-WA850RE(EU)_V7.0_250808.zip`](https://static.tp-link.com/upload/firmware/2025/202509/20250919/TL-WA850RE(EU)_V7.0_250808.zip)
 * ([archived](https://web.archive.org/web/20260903180047/https://static.tp-link.com/upload/firmware/2025/202509/20250919/TL-WA850RE(EU)_V7.0_250808.zip)).
 * 
 * According to a TP-Link manager quoted in a
 * [2021 article](https://shiftdelete.net/tp-link-mercusys-ile-ilgili-hedeflerini-paylasti)
 * ([archived](https://web.archive.org/web/20230513175833/https://shiftdelete.net/tp-link-mercusys-ile-ilgili-hedeflerini-paylasti)),
 * Mercusys has been sold in China as Mercury since 2001. All Mercury images
 * examined contain a certificate with `O=tplink` in its issuer and subject.
 * 
 * All versions share the same header, and its `version` field determines the
 * layout of the rest of the image.
 * 
 * In version 3, the header is followed by a table of directory paths and file
 * names, followed by meta information for each file, meta information about
 * the LZMA compressed blobs including length, offset and uncompressed length,
 * and then a number of LZMA compressed blobs.
 * 
 * The LZMA blobs can contain the concatenated contents of multiple files.
 * The meta information of a file contains the offsets of its directory path
 * and file name, the LZMA blob (numbering starts at 0), the offset of the file
 * in the uncompressed data and the size of the uncompressed file.
 * 
 * Some version 3 images have no uncompressed length in the meta information
 * about the blobs (see `has_8_byte_lzma_metas` in `body_v3`).
 * 
 * In version 2, the header is followed by the length of the files area and a
 * meta information record for each file, each followed directly by the file's
 * data. Unlike versions 1 and 3, version 2 stores no paths or file names at
 * all, only the MD5 hash of each file's path.
 * 
 * In version 1, the header is followed by a record with the path, the compressed
 * length and the offset of each file, and then one LZMA blob per file.
 * 
 * This Kaitai Struct implementation was written independently of the paper
 * [Reverse Engineered MiniFS File System](https://arxiv.org/abs/2407.05064v1).
 * It was started in the firmware analysis project
 * [BANG](https://github.com/armijnhemel/binaryanalysis-ng) (Binary Analysis
 * Next Generation) in
 * [2021](https://github.com/armijnhemel/binaryanalysis-ng/commit/531203a076e3761116320b77b2b9c64a9dca6186)
 * and submitted to the Kaitai Struct format gallery in
 * [September 2023](https://github.com/kaitai-io/kaitai_struct_formats/pull/682),
 * whereas the paper was published in July 2024.
 * @see <a href="https://arxiv.org/html/2407.05064v1#S4">The paper, section 4 (version 3)</a>
 * @see <a href="https://github.com/zh-explorer/tp_research/blob/a42f9d0427ad0c453a7060f3236c4174bb883441/Minifs.py">tp_research's `Minifs.py` (version 2)</a>
 * @see <a href="https://github.com/onekey-sec/unblob/blob/678dbce13dcabe3b4ff16b2b958d6f2cfce9ae3f/python/unblob/handlers/filesystem/minifs.py">unblob's MiniFS handler (version 3)</a>
 */

type TplinkMinifs_CompressionType int
const (
	TplinkMinifs_CompressionType__Lzma TplinkMinifs_CompressionType = 0
	TplinkMinifs_CompressionType__Raw TplinkMinifs_CompressionType = 2
	TplinkMinifs_CompressionType__Lzma2014 TplinkMinifs_CompressionType = 4
)
var values_TplinkMinifs_CompressionType = map[TplinkMinifs_CompressionType]struct{}{0: {}, 2: {}, 4: {}}
func (v TplinkMinifs_CompressionType) isDefined() bool {
	_, ok := values_TplinkMinifs_CompressionType[v]
	return ok
}
type TplinkMinifs struct {
	Header *TplinkMinifs_MinifsHeader
	Body kaitai.Struct
	_io *kaitai.Stream
	_root *TplinkMinifs
	_parent kaitai.Struct
}
func NewTplinkMinifs() *TplinkMinifs {
	return &TplinkMinifs{
	}
}

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

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

	tmp1 := NewTplinkMinifs_MinifsHeader()
	err = tmp1.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Header = tmp1
	switch (this.Header.Version) {
	case 1:
		tmp2 := NewTplinkMinifs_BodyV1()
		err = tmp2.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp2
	case 2:
		tmp3 := NewTplinkMinifs_BodyV2()
		err = tmp3.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp3
	case 3:
		tmp4 := NewTplinkMinifs_BodyV3()
		err = tmp4.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp4
	}
	return err
}

/**
 * @see <a href="https://arxiv.org/html/2407.05064v1#S2.SS2">Source</a>
 */
type TplinkMinifs_BodyV1 struct {
	Inodes []*TplinkMinifs_InodeV1
	BlobsArea *TplinkMinifs_Dummy
	_io *kaitai.Stream
	_root *TplinkMinifs
	_parent *TplinkMinifs
	_raw_BlobsArea []byte
}
func NewTplinkMinifs_BodyV1() *TplinkMinifs_BodyV1 {
	return &TplinkMinifs_BodyV1{
	}
}

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

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

	for i := 0; i < int(this._root.Header.NumFiles); i++ {
		_ = i
		var tmp5 int;
		if (i != 0) {
			tmp6, err := this.Inodes[i - 1].OfsEnd()
			if err != nil {
				return err
			}
			tmp5 = tmp6
		} else {
			tmp5 = 0
		}
		tmp7 := NewTplinkMinifs_InodeV1(uint32(tmp5))
		err = tmp7.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Inodes = append(this.Inodes, tmp7)
	}
	tmp8 := this.Inodes
	tmp9, err := tmp8[len(tmp8) - 1].OfsEnd()
	if err != nil {
		return err
	}
	tmp10, err := this._io.ReadBytes(int(tmp9))
	if err != nil {
		return err
	}
	tmp10 = tmp10
	this._raw_BlobsArea = tmp10
	_io__raw_BlobsArea := kaitai.NewStream(bytes.NewReader(this._raw_BlobsArea))
	tmp11 := NewTplinkMinifs_Dummy()
	err = tmp11.Read(_io__raw_BlobsArea, this, this._root)
	if err != nil {
		return err
	}
	this.BlobsArea = tmp11
	return err
}
type TplinkMinifs_BodyV2 struct {
	LenFilesArea uint32
	FilesArea *TplinkMinifs_FilesAreaV2
	_io *kaitai.Stream
	_root *TplinkMinifs
	_parent *TplinkMinifs
	_raw_FilesArea []byte
}
func NewTplinkMinifs_BodyV2() *TplinkMinifs_BodyV2 {
	return &TplinkMinifs_BodyV2{
	}
}

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

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

	tmp12, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LenFilesArea = uint32(tmp12)
	tmp13, err := this._io.ReadBytes(int(this.LenFilesArea))
	if err != nil {
		return err
	}
	tmp13 = tmp13
	this._raw_FilesArea = tmp13
	_io__raw_FilesArea := kaitai.NewStream(bytes.NewReader(this._raw_FilesArea))
	tmp14 := NewTplinkMinifs_FilesAreaV2()
	err = tmp14.Read(_io__raw_FilesArea, this, this._root)
	if err != nil {
		return err
	}
	this.FilesArea = tmp14
	return err
}
type TplinkMinifs_BodyV3 struct {
	LenNameTable uint32
	NameTable *TplinkMinifs_NameTable
	Inodes []*TplinkMinifs_Inode
	_unnamed3 []byte
	LzmaMetas []*TplinkMinifs_LzmaMeta
	LzmaBlobsArea *TplinkMinifs_Dummy
	_io *kaitai.Stream
	_root *TplinkMinifs
	_parent *TplinkMinifs
	_raw_NameTable []byte
	_raw_LzmaBlobsArea []byte
	_f_has8ByteLzmaMetas bool
	has8ByteLzmaMetas bool
	_f_lenFirstBlobUncompressedIf8ByteMetas bool
	lenFirstBlobUncompressedIf8ByteMetas uint64
	_f_lenLzmaMeta bool
	lenLzmaMeta int8
	_f_numLzmaBlobs bool
	numLzmaBlobs int
	_f_ofsLzmaMetas bool
	ofsLzmaMetas int
}
func NewTplinkMinifs_BodyV3() *TplinkMinifs_BodyV3 {
	return &TplinkMinifs_BodyV3{
	}
}

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

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

	tmp15, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LenNameTable = uint32(tmp15)
	tmp16, err := this._io.ReadBytes(int(this.LenNameTable))
	if err != nil {
		return err
	}
	tmp16 = tmp16
	this._raw_NameTable = tmp16
	_io__raw_NameTable := kaitai.NewStream(bytes.NewReader(this._raw_NameTable))
	tmp17 := NewTplinkMinifs_NameTable()
	err = tmp17.Read(_io__raw_NameTable, this, this._root)
	if err != nil {
		return err
	}
	this.NameTable = tmp17
	for i := 0; i < int(this._root.Header.NumFiles); i++ {
		_ = i
		var tmp18 int;
		if (i != 0) {
			tmp19, err := this.Inodes[i - 1].CurMaxLzmaBlob()
			if err != nil {
				return err
			}
			tmp18 = tmp19
		} else {
			tmp18 = 0
		}
		tmp20 := NewTplinkMinifs_Inode(uint32(tmp18))
		err = tmp20.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Inodes = append(this.Inodes, tmp20)
	}
	tmp21, err := this.OfsLzmaMetas()
	if err != nil {
		return err
	}
	if (tmp21 < 0) {
		tmp22, err := this._io.ReadBytes(int(0))
		if err != nil {
			return err
		}
		tmp22 = tmp22
		this._unnamed3 = tmp22
	}
	tmp23, err := this.NumLzmaBlobs()
	if err != nil {
		return err
	}
	for i := 0; i < int(tmp23); i++ {
		_ = i
		var tmp24 int;
		if (i != 0) {
			tmp25, err := this.LzmaMetas[i - 1].OfsEnd()
			if err != nil {
				return err
			}
			tmp24 = tmp25
		} else {
			tmp24 = 0
		}
		tmp26 := NewTplinkMinifs_LzmaMeta(uint32(tmp24))
		err = tmp26.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.LzmaMetas = append(this.LzmaMetas, tmp26)
	}
	tmp27 := this.LzmaMetas
	tmp28, err := tmp27[len(tmp27) - 1].OfsEnd()
	if err != nil {
		return err
	}
	tmp29, err := this._io.ReadBytes(int(tmp28))
	if err != nil {
		return err
	}
	tmp29 = tmp29
	this._raw_LzmaBlobsArea = tmp29
	_io__raw_LzmaBlobsArea := kaitai.NewStream(bytes.NewReader(this._raw_LzmaBlobsArea))
	tmp30 := NewTplinkMinifs_Dummy()
	err = tmp30.Read(_io__raw_LzmaBlobsArea, this, this._root)
	if err != nil {
		return err
	}
	this.LzmaBlobsArea = tmp30
	return err
}

/**
 * Whether each record in `lzma_metas` lacks `len_blob_uncompressed` and
 * is therefore 8 bytes in size instead of 12.
 * 
 * The MiniFS header doesn't say which size is used (both use version 3),
 * so this Kaitai Struct implementation infers it using a heuristic based
 * on the `.lzma` header of the first blob. Bytes 5 to 12 of that header
 * are the uncompressed size, which was unknown (all bits set) for all
 * blobs in all version 3 images examined. So with 8-byte records,
 * `len_first_blob_uncompressed_if_8_byte_metas` has all bits set. With
 * 12-byte records, the same 8 bytes aren't the uncompressed size. With 3
 * or more blobs, they include a whole offset or length in `lzma_metas`,
 * which would have to be 4 GiB. With 1 or 2 blobs, they include the
 * first blob's dictionary size, which is 8 MiB in all images examined.
 * 
 * An image with 8-byte records and a known uncompressed size would be
 * rejected, or misparsed if it has a single blob and other data follows it.
 * 
 * In the images examined, 8-byte records occur in firmware files with
 * modification times from 2018 to 2022 (as stored in their ZIPs), e.g. in
 * [`MW301R(EU)_V2_180821.zip`](https://static.mercusys.com/software/MW301R(EU)_V2_180821.zip)
 * ([archived](https://web.archive.org/web/20261105093950/https://static.mercusys.com/software/MW301R(EU)_V2_180821.zip)),
 * listed on <https://www.mercusys.com/en/download/mw301r/v2/>
 * ([archived](https://web.archive.org/web/20261105142659/https://www.mercusys.com/en/download/mw301r/v2/)).
 * 
 * As far as we know, this implementation is the first description of
 * 8-byte records. The other descriptions and tools found either assume
 * 12 bytes or don't read `lzma_metas` at all. So there is no reference
 * to compare it with, and the evidence comes from the images. In all 49
 * distinct images examined with 8-byte records, the bytes at each
 * record's offset and length are exactly one complete LZMA stream. Each
 * such stream decompresses to exactly the length that the files packed
 * into it need. The file that ends last in it ends exactly where the
 * decompressed data ends. In addition:
 * 
 * * 2614 of the 7230 files in these 49 images have the same path and
 *   contents as a file in an image with 12-byte records. For example,
 *   49 files are the same in the image with 8-byte records in
 *   [`TL-WA850RE(EU)_V7_201029.zip`](https://static.tp-link.com/2021/202102/20210209/TL-WA850RE(EU)_V7_201029.zip)
 *   ([archived](https://web.archive.org/web/20220326032207/https://static.tp-link.com/2021/202102/20210209/TL-WA850RE(EU)_V7_201029.zip))
 *   and the image with 12-byte records in
 *   [`TL-WA850RE(EU)_V7.0_250808.zip`](https://static.tp-link.com/upload/firmware/2025/202509/20250919/TL-WA850RE(EU)_V7.0_250808.zip)
 *   ([archived](https://web.archive.org/web/20260903180047/https://static.tp-link.com/upload/firmware/2025/202509/20250919/TL-WA850RE(EU)_V7.0_250808.zip)).
 * * The repository
 *   [NurMohammadDuari/mw325r-hack-lab](https://github.com/NurMohammadDuari/mw325r-hack-lab/tree/024da680dbf4f9ca287d562622f02d7d8875bd45)
 *   has the [files](https://github.com/NurMohammadDuari/mw325r-hack-lab/tree/024da680dbf4f9ca287d562622f02d7d8875bd45/extracted-minifs)
 *   of the image with 8-byte records in
 *   [`MW325R(EU)_V2_20111620201211065426.zip`](https://static.mercusys.com/software/MW325R(EU)_V2_20111620201211065426.zip)
 *   ([archived](https://web.archive.org/web/20261105093427/https://static.mercusys.com/software/MW325R(EU)_V2_20111620201211065426.zip)).
 *   They match the files parsed by this implementation in all 92 files
 *   that can be compared. Its
 *   [extractor](https://github.com/NurMohammadDuari/mw325r-hack-lab/blob/024da680dbf4f9ca287d562622f02d7d8875bd45/analysis/minifs_extract.py)
 *   finds the blobs by searching for LZMA headers instead of reading
 *   `lzma_metas`.
 */
func (this *TplinkMinifs_BodyV3) Has8ByteLzmaMetas() (v bool, err error) {
	if (this._f_has8ByteLzmaMetas) {
		return this.has8ByteLzmaMetas, nil
	}
	this._f_has8ByteLzmaMetas = true
	tmp31, err := this.LenFirstBlobUncompressedIf8ByteMetas()
	if err != nil {
		return false, err
	}
	this.has8ByteLzmaMetas = bool(tmp31 == uint64(18446744073709551615))
	return this.has8ByteLzmaMetas, nil
}

/**
 * The uncompressed size in the `.lzma` header of the first blob, if
 * `lzma_metas` have 8-byte records. It follows the properties byte and the
 * 4-byte dictionary size.
 */
func (this *TplinkMinifs_BodyV3) LenFirstBlobUncompressedIf8ByteMetas() (v uint64, err error) {
	if (this._f_lenFirstBlobUncompressedIf8ByteMetas) {
		return this.lenFirstBlobUncompressedIf8ByteMetas, nil
	}
	this._f_lenFirstBlobUncompressedIf8ByteMetas = true
	_pos, err := this._io.Pos()
	if err != nil {
		return 0, err
	}
	tmp32, err := this.OfsLzmaMetas()
	if err != nil {
		return 0, err
	}
	tmp33, err := this.NumLzmaBlobs()
	if err != nil {
		return 0, err
	}
	_, err = this._io.Seek(int64((tmp32 + 8 * tmp33) + 5), io.SeekStart)
	if err != nil {
		return 0, err
	}
	tmp34, err := this._io.ReadU8le()
	if err != nil {
		return 0, err
	}
	this.lenFirstBlobUncompressedIf8ByteMetas = tmp34
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return 0, err
	}
	return this.lenFirstBlobUncompressedIf8ByteMetas, nil
}

/**
 * The size of each record in `lzma_metas` (8 or 12 bytes).
 */
func (this *TplinkMinifs_BodyV3) LenLzmaMeta() (v int8, err error) {
	if (this._f_lenLzmaMeta) {
		return this.lenLzmaMeta, nil
	}
	this._f_lenLzmaMeta = true
	var tmp35 int8;
	tmp36, err := this.Has8ByteLzmaMetas()
	if err != nil {
		return 0, err
	}
	if (tmp36) {
		tmp35 = 8
	} else {
		tmp35 = 12
	}
	this.lenLzmaMeta = int8(tmp35)
	return this.lenLzmaMeta, nil
}

/**
 * Count starts at 0, so there is one more blob than the highest blob number
 * @see <a href="https://github.com/onekey-sec/unblob/blob/678dbce13dcabe3b4ff16b2b958d6f2cfce9ae3f/python/unblob/handlers/filesystem/minifs.py#L129-L130">Source</a>
 */
func (this *TplinkMinifs_BodyV3) NumLzmaBlobs() (v int, err error) {
	if (this._f_numLzmaBlobs) {
		return this.numLzmaBlobs, nil
	}
	this._f_numLzmaBlobs = true
	tmp37 := this.Inodes
	tmp38, err := tmp37[len(tmp37) - 1].CurMaxLzmaBlob()
	if err != nil {
		return 0, err
	}
	this.numLzmaBlobs = int(tmp38 + 1)
	return this.numLzmaBlobs, nil
}
func (this *TplinkMinifs_BodyV3) OfsLzmaMetas() (v int, err error) {
	if (this._f_ofsLzmaMetas) {
		return this.ofsLzmaMetas, nil
	}
	this._f_ofsLzmaMetas = true
	tmp39, err := this._io.Pos()
	if err != nil {
		return 0, err
	}
	this.ofsLzmaMetas = int(tmp39)
	return this.ofsLzmaMetas, nil
}
type TplinkMinifs_Dummy struct {
	_io *kaitai.Stream
	_root *TplinkMinifs
	_parent kaitai.Struct
}
func NewTplinkMinifs_Dummy() *TplinkMinifs_Dummy {
	return &TplinkMinifs_Dummy{
	}
}

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

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

	return err
}

/**
 * @see <a href="https://github.com/zh-explorer/tp_research/blob/a42f9d0427ad0c453a7060f3236c4174bb883441/Minifs.py#L41-L52">Source</a>
 */
type TplinkMinifs_FileV2 struct {
	PathMd5 []byte
	LenData uint32
	OfsData uint32
	LenDataUncompressed uint32
	Compression TplinkMinifs_CompressionType
	Data []byte
	_io *kaitai.Stream
	_root *TplinkMinifs
	_parent *TplinkMinifs_FilesAreaV2
}
func NewTplinkMinifs_FileV2() *TplinkMinifs_FileV2 {
	return &TplinkMinifs_FileV2{
	}
}

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

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

	tmp40, err := this._io.ReadBytes(int(16))
	if err != nil {
		return err
	}
	tmp40 = tmp40
	this.PathMd5 = tmp40
	tmp41, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LenData = uint32(tmp41)
	tmp42, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.OfsData = uint32(tmp42)
	tmp43, err := this._io.Pos()
	if err != nil {
		return err
	}
	tmp44, err := this._io.Pos()
	if err != nil {
		return err
	}
	if !(this.OfsData == tmp43 + 8) {
		return kaitai.NewValidationNotEqualError(tmp44 + 8, this.OfsData, this._io, "/types/file_v2/seq/2")
	}
	tmp45, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LenDataUncompressed = uint32(tmp45)
	tmp46, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Compression = TplinkMinifs_CompressionType(tmp46)
	tmp47, err := this._io.ReadBytes(int(this.LenData))
	if err != nil {
		return err
	}
	tmp47 = tmp47
	this.Data = tmp47
	return err
}

/**
 * The MD5 hash of the absolute path of the file, e.g. of
 * `/conf/priv-key.pem`.
 * 
 * Version 2 images store only these hashes, not the paths, so a path can
 * only be found by hashing candidate paths and comparing.
 * [`Minifs.py`](https://github.com/zh-explorer/tp_research/blob/a42f9d0427ad0c453a7060f3236c4174bb883441/Minifs.py#L181-L209)
 * takes the candidates from path-like strings in the files' contents.
 */

/**
 * Offset of `data` relative to the start of `<body_v2>.files_area`.
 */

/**
 * With `compression_type::lzma`, an LZMA stream in the `.lzma` format
 * (also known as LZMA_Alone). Decompress it in the same way as
 * `<lzma_meta>.blob`.
 * 
 * In all images examined, the `.lzma` header specifies the properties
 * lc = 0, lp = 0, pb = 2 and an 8 MiB dictionary, so it starts with the
 * bytes `5A 00 00 80 00`. It also specifies the uncompressed size of the
 * stream, and there is no end-of-payload marker.
 */
type TplinkMinifs_FilesAreaV2 struct {
	Files []*TplinkMinifs_FileV2
	_io *kaitai.Stream
	_root *TplinkMinifs
	_parent *TplinkMinifs_BodyV2
}
func NewTplinkMinifs_FilesAreaV2() *TplinkMinifs_FilesAreaV2 {
	return &TplinkMinifs_FilesAreaV2{
	}
}

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

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

	for i := 0; i < int(this._root.Header.NumFiles); i++ {
		_ = i
		tmp48 := NewTplinkMinifs_FileV2()
		err = tmp48.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Files = append(this.Files, tmp48)
	}
	return err
}

/**
 * @see <a href="https://arxiv.org/html/2407.05064v1#S4.SS3">Source</a>
 * @see <a href="https://github.com/onekey-sec/unblob/blob/678dbce13dcabe3b4ff16b2b958d6f2cfce9ae3f/python/unblob/handlers/filesystem/minifs.py#L36-L42">Source</a>
 */
type TplinkMinifs_Inode struct {
	OfsDirectoryPath uint32
	OfsFileName uint32
	LzmaBlob uint32
	OfsFile uint32
	LenFile uint32
	PrevMaxLzmaBlob uint32
	_io *kaitai.Stream
	_root *TplinkMinifs
	_parent *TplinkMinifs_BodyV3
	_f_curMaxLzmaBlob bool
	curMaxLzmaBlob int
	_f_directoryPath bool
	directoryPath string
	_f_fileName bool
	fileName string
}
func NewTplinkMinifs_Inode(prevMaxLzmaBlob uint32) *TplinkMinifs_Inode {
	return &TplinkMinifs_Inode{
		PrevMaxLzmaBlob: prevMaxLzmaBlob,
	}
}

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

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

	tmp49, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.OfsDirectoryPath = uint32(tmp49)
	tmp50, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.OfsFileName = uint32(tmp50)
	tmp51, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LzmaBlob = uint32(tmp51)
	tmp52, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.OfsFile = uint32(tmp52)
	tmp53, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LenFile = uint32(tmp53)
	return err
}
func (this *TplinkMinifs_Inode) CurMaxLzmaBlob() (v int, err error) {
	if (this._f_curMaxLzmaBlob) {
		return this.curMaxLzmaBlob, nil
	}
	this._f_curMaxLzmaBlob = true
	var tmp54 uint32;
	if (this.LzmaBlob > this.PrevMaxLzmaBlob) {
		tmp54 = this.LzmaBlob
	} else {
		tmp54 = this.PrevMaxLzmaBlob
	}
	this.curMaxLzmaBlob = int(tmp54)
	return this.curMaxLzmaBlob, nil
}
func (this *TplinkMinifs_Inode) DirectoryPath() (v string, err error) {
	if (this._f_directoryPath) {
		return this.directoryPath, nil
	}
	this._f_directoryPath = true
	thisIo := this._parent.NameTable._io
	_pos, err := thisIo.Pos()
	if err != nil {
		return "", err
	}
	_, err = thisIo.Seek(int64(this.OfsDirectoryPath), io.SeekStart)
	if err != nil {
		return "", err
	}
	tmp55, err := thisIo.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return "", err
	}
	this.directoryPath = string(tmp55)
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return "", err
	}
	return this.directoryPath, nil
}
func (this *TplinkMinifs_Inode) FileName() (v string, err error) {
	if (this._f_fileName) {
		return this.fileName, nil
	}
	this._f_fileName = true
	thisIo := this._parent.NameTable._io
	_pos, err := thisIo.Pos()
	if err != nil {
		return "", err
	}
	_, err = thisIo.Seek(int64(this.OfsFileName), io.SeekStart)
	if err != nil {
		return "", err
	}
	tmp56, err := thisIo.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return "", err
	}
	this.fileName = string(tmp56)
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return "", err
	}
	return this.fileName, nil
}
type TplinkMinifs_InodeV1 struct {
	Path string
	LenBlob uint32
	OfsBlob uint32
	PrevOfsEnd uint32
	_io *kaitai.Stream
	_root *TplinkMinifs
	_parent *TplinkMinifs_BodyV1
	_f_blob bool
	blob []byte
	_f_ofsEnd bool
	ofsEnd int
}
func NewTplinkMinifs_InodeV1(prevOfsEnd uint32) *TplinkMinifs_InodeV1 {
	return &TplinkMinifs_InodeV1{
		PrevOfsEnd: prevOfsEnd,
	}
}

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

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

	tmp57, err := this._io.ReadBytes(int(80))
	if err != nil {
		return err
	}
	tmp57 = kaitai.BytesTerminate(tmp57, 0, false)
	this.Path = string(tmp57)
	tmp58, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LenBlob = uint32(tmp58)
	tmp59, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.OfsBlob = uint32(tmp59)
	if !(this.OfsBlob == this.PrevOfsEnd) {
		return kaitai.NewValidationNotEqualError(this.PrevOfsEnd, this.OfsBlob, this._io, "/types/inode_v1/seq/2")
	}
	return err
}

/**
 * An LZMA stream in the `.lzma` format (also known as LZMA_Alone) with
 * the contents of the file. Decompress it in the same way as
 * `<lzma_meta>.blob`.
 * 
 * In all images examined, the `.lzma` header specifies the properties
 * lc = 0, lp = 0, pb = 2 and an 8 MiB dictionary, so it starts with the
 * bytes `5A 00 00 80 00`. It also specifies the uncompressed size of the
 * stream, and there is no end-of-payload marker.
 */
func (this *TplinkMinifs_InodeV1) Blob() (v []byte, err error) {
	if (this._f_blob) {
		return this.blob, nil
	}
	this._f_blob = true
	thisIo := this._parent.BlobsArea._io
	_pos, err := thisIo.Pos()
	if err != nil {
		return nil, err
	}
	_, err = thisIo.Seek(int64(this.OfsBlob), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp60, err := thisIo.ReadBytes(int(this.LenBlob))
	if err != nil {
		return nil, err
	}
	tmp60 = tmp60
	this.blob = tmp60
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.blob, nil
}
func (this *TplinkMinifs_InodeV1) OfsEnd() (v int, err error) {
	if (this._f_ofsEnd) {
		return this.ofsEnd, nil
	}
	this._f_ofsEnd = true
	this.ofsEnd = int(this.OfsBlob + this.LenBlob)
	return this.ofsEnd, nil
}

/**
 * Relative to the start of `<body_v1>.blobs_area`.
 */

/**
 * @see <a href="https://arxiv.org/html/2407.05064v1#S4.SS4">Source</a>
 * @see <a href="https://github.com/onekey-sec/unblob/blob/678dbce13dcabe3b4ff16b2b958d6f2cfce9ae3f/python/unblob/handlers/filesystem/minifs.py#L44-L48">Source</a>
 */
type TplinkMinifs_LzmaMeta struct {
	OfsBlob uint32
	LenBlob uint32
	LenBlobUncompressed uint32
	PrevOfsEnd uint32
	_io *kaitai.Stream
	_root *TplinkMinifs
	_parent *TplinkMinifs_BodyV3
	_f_blob bool
	blob []byte
	_f_ofsEnd bool
	ofsEnd int
}
func NewTplinkMinifs_LzmaMeta(prevOfsEnd uint32) *TplinkMinifs_LzmaMeta {
	return &TplinkMinifs_LzmaMeta{
		PrevOfsEnd: prevOfsEnd,
	}
}

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

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

	tmp61, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.OfsBlob = uint32(tmp61)
	if !(this.OfsBlob == this.PrevOfsEnd) {
		return kaitai.NewValidationNotEqualError(this.PrevOfsEnd, this.OfsBlob, this._io, "/types/lzma_meta/seq/0")
	}
	tmp62, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LenBlob = uint32(tmp62)
	tmp63, err := this._parent.Has8ByteLzmaMetas()
	if err != nil {
		return err
	}
	if (!(tmp63)) {
		tmp64, err := this._io.ReadU4be()
		if err != nil {
			return err
		}
		this.LenBlobUncompressed = uint32(tmp64)
	}
	return err
}

/**
 * An LZMA stream in the `.lzma` format (also known as LZMA_Alone):
 * a 13-byte header followed by the compressed data. Decompress it
 * with a ready-made LZMA decoder that reads this header, e.g. in
 * Python with `lzma.decompress(blob, format=lzma.FORMAT_ALONE)`. The
 * size of the decompressed data is `len_blob_uncompressed`, if present.
 * 
 * In all images examined with `header.version` = 3, the `.lzma` header
 * specifies the properties lc = 3, lp = 0, pb = 2 and an 8 MiB
 * dictionary, so it starts with the bytes `5D 00 00 80 00`. The
 * uncompressed size in the header is unknown (`0xFFFF_FFFF_FFFF_FFFF`),
 * so the stream ends with an end-of-payload marker.
 * @see <a href="https://arxiv.org/html/2407.05064v1#S4.SS5">Source</a>
 * @see <a href="https://github.com/onekey-sec/unblob/blob/678dbce13dcabe3b4ff16b2b958d6f2cfce9ae3f/python/unblob/handlers/filesystem/minifs.py#L175-L187">Source</a>
 */
func (this *TplinkMinifs_LzmaMeta) Blob() (v []byte, err error) {
	if (this._f_blob) {
		return this.blob, nil
	}
	this._f_blob = true
	thisIo := this._parent.LzmaBlobsArea._io
	_pos, err := thisIo.Pos()
	if err != nil {
		return nil, err
	}
	_, err = thisIo.Seek(int64(this.OfsBlob), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp65, err := thisIo.ReadBytes(int(this.LenBlob))
	if err != nil {
		return nil, err
	}
	tmp65 = tmp65
	this.blob = tmp65
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.blob, nil
}
func (this *TplinkMinifs_LzmaMeta) OfsEnd() (v int, err error) {
	if (this._f_ofsEnd) {
		return this.ofsEnd, nil
	}
	this._f_ofsEnd = true
	this.ofsEnd = int(this.OfsBlob + this.LenBlob)
	return this.ofsEnd, nil
}

/**
 * @see <a href="https://arxiv.org/html/2407.05064v1#S4.SS1">Source</a>
 * @see <a href="https://github.com/onekey-sec/unblob/blob/678dbce13dcabe3b4ff16b2b958d6f2cfce9ae3f/python/unblob/handlers/filesystem/minifs.py#L27-L34">Source</a>
 */
type TplinkMinifs_MinifsHeader struct {
	Magic []byte
	Version uint32
	NumFiles uint32
	LenLargestFile uint32
	_io *kaitai.Stream
	_root *TplinkMinifs
	_parent *TplinkMinifs
}
func NewTplinkMinifs_MinifsHeader() *TplinkMinifs_MinifsHeader {
	return &TplinkMinifs_MinifsHeader{
	}
}

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

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

	tmp66, err := this._io.ReadBytes(int(16))
	if err != nil {
		return err
	}
	tmp66 = tmp66
	this.Magic = tmp66
	if !(bytes.Equal(this.Magic, []uint8{77, 73, 78, 73, 70, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})) {
		return kaitai.NewValidationNotEqualError([]uint8{77, 73, 78, 73, 70, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, this.Magic, this._io, "/types/minifs_header/seq/0")
	}
	tmp67, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Version = uint32(tmp67)
	if !( ((this.Version == 1) || (this.Version == 2) || (this.Version == 3)) ) {
		return kaitai.NewValidationNotAnyOfError(this.Version, this._io, "/types/minifs_header/seq/1")
	}
	tmp68, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.NumFiles = uint32(tmp68)
	tmp69, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LenLargestFile = uint32(tmp69)
	return err
}

/**
 * The uncompressed size of the largest file. In all images examined with
 * version 3, the inodes are sorted by size in descending order, so it is
 * also the size of the first file. In all images examined with versions
 * 1 and 2, the value is rounded up to a multiple of 4.
 */

/**
 * Table of null-terminated directory paths and file names, referenced by
 * `<inode>.ofs_directory_path` and `<inode>.ofs_file_name`. In all images
 * examined, each non-empty string occurs only once, which saves space in
 * flash memory, as many files share a directory or a name.
 * 
 * In all images examined, the table is padded with null bytes to a multiple
 * of 4 bytes, so `names` can end with up to 3 empty strings (one for each
 * padding byte).
 * @see <a href="https://arxiv.org/html/2407.05064v1#S4.SS2">Source</a>
 */
type TplinkMinifs_NameTable struct {
	Names []string
	_io *kaitai.Stream
	_root *TplinkMinifs
	_parent *TplinkMinifs_BodyV3
}
func NewTplinkMinifs_NameTable() *TplinkMinifs_NameTable {
	return &TplinkMinifs_NameTable{
	}
}

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

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

	for i := 0;; i++ {
		tmp70, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp70 {
			break
		}
		tmp71, err := this._io.ReadBytesTerm(0, false, true, true)
		if err != nil {
			return err
		}
		this.Names = append(this.Names, string(tmp71))
	}
	return err
}
