macOS '.DS_Store' format: Go parsing library

Apple macOS '.DS_Store' file format.

File extension

DS_Store

KS implementation details

License: MIT
Minimal Kaitai Struct required: 0.9

References

This page hosts a formal specification of macOS '.DS_Store' format 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 macOS '.DS_Store' format

ds_store.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"
	"golang.org/x/text/encoding/unicode"
)


/**
 * Apple macOS '.DS_Store' file format.
 * @see <a href="https://en.wikipedia.org/wiki/.DS_Store">Source</a>
 * @see <a href="https://metacpan.org/dist/Mac-Finder-DSStore/view/DSStoreFormat.pod">Source</a>
 * @see <a href="https://0day.work/parsing-the-ds_store-file-format/">Source</a>
 */
type DsStore struct {
	AlignmentHeader []byte
	BuddyAllocatorHeader *DsStore_BuddyAllocatorHeader
	_io *kaitai.Stream
	_root *DsStore
	_parent kaitai.Struct
	_raw_buddyAllocatorBody []byte
	_f_blockAddressMask bool
	blockAddressMask int8
	_f_buddyAllocatorBody bool
	buddyAllocatorBody *DsStore_BuddyAllocatorBody
}
func NewDsStore() *DsStore {
	return &DsStore{
	}
}

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

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

	tmp1, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp1 = tmp1
	this.AlignmentHeader = tmp1
	if !(bytes.Equal(this.AlignmentHeader, []uint8{0, 0, 0, 1})) {
		return kaitai.NewValidationNotEqualError([]uint8{0, 0, 0, 1}, this.AlignmentHeader, this._io, "/seq/0")
	}
	tmp2 := NewDsStore_BuddyAllocatorHeader()
	err = tmp2.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.BuddyAllocatorHeader = tmp2
	return err
}

/**
 * Bitmask used to calculate the position and the size of each block
 * of the B-tree from the block addresses.
 */
func (this *DsStore) BlockAddressMask() (v int8, err error) {
	if (this._f_blockAddressMask) {
		return this.blockAddressMask, nil
	}
	this._f_blockAddressMask = true
	this.blockAddressMask = int8(31)
	return this.blockAddressMask, nil
}
func (this *DsStore) BuddyAllocatorBody() (v *DsStore_BuddyAllocatorBody, err error) {
	if (this._f_buddyAllocatorBody) {
		return this.buddyAllocatorBody, nil
	}
	this._f_buddyAllocatorBody = true
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(this.BuddyAllocatorHeader.OfsBookkeepingInfoBlock + 4), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp3, err := this._io.ReadBytes(int(this.BuddyAllocatorHeader.LenBookkeepingInfoBlock))
	if err != nil {
		return nil, err
	}
	tmp3 = tmp3
	this._raw_buddyAllocatorBody = tmp3
	_io__raw_buddyAllocatorBody := kaitai.NewStream(bytes.NewReader(this._raw_buddyAllocatorBody))
	tmp4 := NewDsStore_BuddyAllocatorBody()
	err = tmp4.Read(_io__raw_buddyAllocatorBody, this, this._root)
	if err != nil {
		return nil, err
	}
	this.buddyAllocatorBody = tmp4
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.buddyAllocatorBody, nil
}
type DsStore_Block struct {
	Mode uint32
	Counter uint32
	Data []*DsStore_Block_BlockData
	_io *kaitai.Stream
	_root *DsStore
	_parent kaitai.Struct
	_f_rightmostBlock bool
	rightmostBlock *DsStore_Block
}
func NewDsStore_Block() *DsStore_Block {
	return &DsStore_Block{
	}
}

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

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

	tmp5, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Mode = uint32(tmp5)
	tmp6, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Counter = uint32(tmp6)
	for i := 0; i < int(this.Counter); i++ {
		_ = i
		tmp7 := NewDsStore_Block_BlockData(this.Mode)
		err = tmp7.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Data = append(this.Data, tmp7)
	}
	return err
}

/**
 * Rightmost child block pointer.
 */
func (this *DsStore_Block) RightmostBlock() (v *DsStore_Block, err error) {
	if (this._f_rightmostBlock) {
		return this.rightmostBlock, nil
	}
	this._f_rightmostBlock = true
	if (this.Mode > 0) {
		thisIo := this._root._io
		_pos, err := thisIo.Pos()
		if err != nil {
			return nil, err
		}
		tmp8, err := this._root.BuddyAllocatorBody()
		if err != nil {
			return nil, err
		}
		tmp9, err := tmp8.BlockAddresses[this.Mode].Offset()
		if err != nil {
			return nil, err
		}
		_, err = thisIo.Seek(int64(tmp9), io.SeekStart)
		if err != nil {
			return nil, err
		}
		tmp10 := NewDsStore_Block()
		err = tmp10.Read(thisIo, this, this._root)
		if err != nil {
			return nil, err
		}
		this.rightmostBlock = tmp10
		_, err = thisIo.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
	}
	return this.rightmostBlock, nil
}

/**
 * If mode is 0, this is a leaf node, otherwise it is an internal node.
 */

/**
 * Number of records or number of block id + record pairs.
 */
type DsStore_Block_BlockData struct {
	BlockId uint32
	Record *DsStore_Block_BlockData_Record
	Mode uint32
	_io *kaitai.Stream
	_root *DsStore
	_parent *DsStore_Block
	_f_block bool
	block *DsStore_Block
}
func NewDsStore_Block_BlockData(mode uint32) *DsStore_Block_BlockData {
	return &DsStore_Block_BlockData{
		Mode: mode,
	}
}

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

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

	if (this.Mode > 0) {
		tmp11, err := this._io.ReadU4be()
		if err != nil {
			return err
		}
		this.BlockId = uint32(tmp11)
	}
	tmp12 := NewDsStore_Block_BlockData_Record()
	err = tmp12.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Record = tmp12
	return err
}
func (this *DsStore_Block_BlockData) Block() (v *DsStore_Block, err error) {
	if (this._f_block) {
		return this.block, nil
	}
	this._f_block = true
	if (this.Mode > 0) {
		thisIo := this._root._io
		_pos, err := thisIo.Pos()
		if err != nil {
			return nil, err
		}
		tmp13, err := this._root.BuddyAllocatorBody()
		if err != nil {
			return nil, err
		}
		tmp14, err := tmp13.BlockAddresses[uint32(this.BlockId)].Offset()
		if err != nil {
			return nil, err
		}
		_, err = thisIo.Seek(int64(tmp14), io.SeekStart)
		if err != nil {
			return nil, err
		}
		tmp15 := NewDsStore_Block()
		err = tmp15.Read(thisIo, this, this._root)
		if err != nil {
			return nil, err
		}
		this.block = tmp15
		_, err = thisIo.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
	}
	return this.block, nil
}
type DsStore_Block_BlockData_Record struct {
	Filename *DsStore_Block_BlockData_Record_Ustr
	StructureType *DsStore_Block_BlockData_Record_FourCharCode
	DataType string
	Value interface{}
	_io *kaitai.Stream
	_root *DsStore
	_parent *DsStore_Block_BlockData
}
func NewDsStore_Block_BlockData_Record() *DsStore_Block_BlockData_Record {
	return &DsStore_Block_BlockData_Record{
	}
}

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

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

	tmp16 := NewDsStore_Block_BlockData_Record_Ustr()
	err = tmp16.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Filename = tmp16
	tmp17 := NewDsStore_Block_BlockData_Record_FourCharCode()
	err = tmp17.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.StructureType = tmp17
	tmp18, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp18 = tmp18
	this.DataType = string(tmp18)
	switch (this.DataType) {
	case "blob":
		tmp19 := NewDsStore_Block_BlockData_Record_RecordBlob()
		err = tmp19.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Value = tmp19
	case "bool":
		tmp20, err := this._io.ReadU1()
		if err != nil {
			return err
		}
		this.Value = tmp20
	case "comp":
		tmp21, err := this._io.ReadU8be()
		if err != nil {
			return err
		}
		this.Value = tmp21
	case "dutc":
		tmp22, err := this._io.ReadU8be()
		if err != nil {
			return err
		}
		this.Value = tmp22
	case "long":
		tmp23, err := this._io.ReadU4be()
		if err != nil {
			return err
		}
		this.Value = tmp23
	case "shor":
		tmp24, err := this._io.ReadU4be()
		if err != nil {
			return err
		}
		this.Value = tmp24
	case "type":
		tmp25 := NewDsStore_Block_BlockData_Record_FourCharCode()
		err = tmp25.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Value = tmp25
	case "ustr":
		tmp26 := NewDsStore_Block_BlockData_Record_Ustr()
		err = tmp26.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Value = tmp26
	}
	return err
}

/**
 * Description of the entry's property.
 */

/**
 * Data type of the value.
 */
type DsStore_Block_BlockData_Record_FourCharCode struct {
	Value string
	_io *kaitai.Stream
	_root *DsStore
	_parent *DsStore_Block_BlockData_Record
}
func NewDsStore_Block_BlockData_Record_FourCharCode() *DsStore_Block_BlockData_Record_FourCharCode {
	return &DsStore_Block_BlockData_Record_FourCharCode{
	}
}

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

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

	tmp27, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp27 = tmp27
	this.Value = string(tmp27)
	return err
}
type DsStore_Block_BlockData_Record_RecordBlob struct {
	Length uint32
	Value []byte
	_io *kaitai.Stream
	_root *DsStore
	_parent *DsStore_Block_BlockData_Record
}
func NewDsStore_Block_BlockData_Record_RecordBlob() *DsStore_Block_BlockData_Record_RecordBlob {
	return &DsStore_Block_BlockData_Record_RecordBlob{
	}
}

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

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

	tmp28, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Length = uint32(tmp28)
	tmp29, err := this._io.ReadBytes(int(this.Length))
	if err != nil {
		return err
	}
	tmp29 = tmp29
	this.Value = tmp29
	return err
}
type DsStore_Block_BlockData_Record_Ustr struct {
	Length uint32
	Value string
	_io *kaitai.Stream
	_root *DsStore
	_parent *DsStore_Block_BlockData_Record
}
func NewDsStore_Block_BlockData_Record_Ustr() *DsStore_Block_BlockData_Record_Ustr {
	return &DsStore_Block_BlockData_Record_Ustr{
	}
}

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

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

	tmp30, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Length = uint32(tmp30)
	tmp31, err := this._io.ReadBytes(int(2 * this.Length))
	if err != nil {
		return err
	}
	tmp31 = tmp31
	tmp32, err := kaitai.BytesToStr(tmp31, unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM).NewDecoder())
	if err != nil {
		return err
	}
	this.Value = tmp32
	return err
}
type DsStore_BuddyAllocatorBody struct {
	NumBlocks uint32
	_unnamed1 []byte
	BlockAddresses []*DsStore_BuddyAllocatorBody_BlockDescriptor
	NumDirectories uint32
	DirectoryEntries []*DsStore_BuddyAllocatorBody_DirectoryEntry
	FreeLists []*DsStore_BuddyAllocatorBody_FreeList
	_io *kaitai.Stream
	_root *DsStore
	_parent *DsStore
	_f_directories bool
	directories []*DsStore_MasterBlockRef
	_f_numBlockAddresses bool
	numBlockAddresses int
	_f_numFreeLists bool
	numFreeLists int8
}
func NewDsStore_BuddyAllocatorBody() *DsStore_BuddyAllocatorBody {
	return &DsStore_BuddyAllocatorBody{
	}
}

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

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

	tmp33, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.NumBlocks = uint32(tmp33)
	tmp34, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp34 = tmp34
	this._unnamed1 = tmp34
	tmp35, err := this.NumBlockAddresses()
	if err != nil {
		return err
	}
	for i := 0; i < int(tmp35); i++ {
		_ = i
		tmp36 := NewDsStore_BuddyAllocatorBody_BlockDescriptor()
		err = tmp36.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.BlockAddresses = append(this.BlockAddresses, tmp36)
	}
	tmp37, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.NumDirectories = uint32(tmp37)
	for i := 0; i < int(this.NumDirectories); i++ {
		_ = i
		tmp38 := NewDsStore_BuddyAllocatorBody_DirectoryEntry()
		err = tmp38.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.DirectoryEntries = append(this.DirectoryEntries, tmp38)
	}
	tmp39, err := this.NumFreeLists()
	if err != nil {
		return err
	}
	for i := 0; i < int(tmp39); i++ {
		_ = i
		tmp40 := NewDsStore_BuddyAllocatorBody_FreeList()
		err = tmp40.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.FreeLists = append(this.FreeLists, tmp40)
	}
	return err
}

/**
 * Master blocks of the different B-trees.
 */
func (this *DsStore_BuddyAllocatorBody) Directories() (v []*DsStore_MasterBlockRef, err error) {
	if (this._f_directories) {
		return this.directories, nil
	}
	this._f_directories = true
	thisIo := this._root._io
	for i := 0; i < int(this.NumDirectories); i++ {
		_ = i
		tmp41 := NewDsStore_MasterBlockRef(i)
		err = tmp41.Read(thisIo, this, this._root)
		if err != nil {
			return nil, err
		}
		this.directories = append(this.directories, tmp41)
	}
	return this.directories, nil
}
func (this *DsStore_BuddyAllocatorBody) NumBlockAddresses() (v int, err error) {
	if (this._f_numBlockAddresses) {
		return this.numBlockAddresses, nil
	}
	this._f_numBlockAddresses = true
	this.numBlockAddresses = int(256)
	return this.numBlockAddresses, nil
}
func (this *DsStore_BuddyAllocatorBody) NumFreeLists() (v int8, err error) {
	if (this._f_numFreeLists) {
		return this.numFreeLists, nil
	}
	this._f_numFreeLists = true
	this.numFreeLists = int8(32)
	return this.numFreeLists, nil
}

/**
 * Number of blocks in the allocated-blocks list.
 */

/**
 * Unknown field which appears to always be 0.
 */

/**
 * Addresses of the different blocks.
 */

/**
 * Indicates the number of directory entries.
 */

/**
 * Each directory is an independent B-tree.
 */
type DsStore_BuddyAllocatorBody_BlockDescriptor struct {
	AddressRaw uint32
	_io *kaitai.Stream
	_root *DsStore
	_parent *DsStore_BuddyAllocatorBody
	_f_offset bool
	offset int
	_f_size bool
	size int
}
func NewDsStore_BuddyAllocatorBody_BlockDescriptor() *DsStore_BuddyAllocatorBody_BlockDescriptor {
	return &DsStore_BuddyAllocatorBody_BlockDescriptor{
	}
}

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

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

	tmp42, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.AddressRaw = uint32(tmp42)
	return err
}
func (this *DsStore_BuddyAllocatorBody_BlockDescriptor) Offset() (v int, err error) {
	if (this._f_offset) {
		return this.offset, nil
	}
	this._f_offset = true
	tmp43, err := this._root.BlockAddressMask()
	if err != nil {
		return 0, err
	}
	this.offset = int(this.AddressRaw & ^(tmp43) + 4)
	return this.offset, nil
}
func (this *DsStore_BuddyAllocatorBody_BlockDescriptor) Size() (v int, err error) {
	if (this._f_size) {
		return this.size, nil
	}
	this._f_size = true
	tmp44, err := this._root.BlockAddressMask()
	if err != nil {
		return 0, err
	}
	this.size = int(1 << (this.AddressRaw & tmp44))
	return this.size, nil
}
type DsStore_BuddyAllocatorBody_DirectoryEntry struct {
	LenName uint8
	Name string
	BlockId uint32
	_io *kaitai.Stream
	_root *DsStore
	_parent *DsStore_BuddyAllocatorBody
}
func NewDsStore_BuddyAllocatorBody_DirectoryEntry() *DsStore_BuddyAllocatorBody_DirectoryEntry {
	return &DsStore_BuddyAllocatorBody_DirectoryEntry{
	}
}

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

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

	tmp45, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.LenName = tmp45
	tmp46, err := this._io.ReadBytes(int(this.LenName))
	if err != nil {
		return err
	}
	tmp46 = tmp46
	this.Name = string(tmp46)
	tmp47, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.BlockId = uint32(tmp47)
	return err
}
type DsStore_BuddyAllocatorBody_FreeList struct {
	Counter uint32
	Offsets []uint32
	_io *kaitai.Stream
	_root *DsStore
	_parent *DsStore_BuddyAllocatorBody
}
func NewDsStore_BuddyAllocatorBody_FreeList() *DsStore_BuddyAllocatorBody_FreeList {
	return &DsStore_BuddyAllocatorBody_FreeList{
	}
}

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

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

	tmp48, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Counter = uint32(tmp48)
	for i := 0; i < int(this.Counter); i++ {
		_ = i
		tmp49, err := this._io.ReadU4be()
		if err != nil {
			return err
		}
		this.Offsets = append(this.Offsets, tmp49)
	}
	return err
}
type DsStore_BuddyAllocatorHeader struct {
	Magic []byte
	OfsBookkeepingInfoBlock uint32
	LenBookkeepingInfoBlock uint32
	CopyOfsBookkeepingInfoBlock uint32
	_unnamed4 []byte
	_io *kaitai.Stream
	_root *DsStore
	_parent *DsStore
}
func NewDsStore_BuddyAllocatorHeader() *DsStore_BuddyAllocatorHeader {
	return &DsStore_BuddyAllocatorHeader{
	}
}

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

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

	tmp50, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp50 = tmp50
	this.Magic = tmp50
	if !(bytes.Equal(this.Magic, []uint8{66, 117, 100, 49})) {
		return kaitai.NewValidationNotEqualError([]uint8{66, 117, 100, 49}, this.Magic, this._io, "/types/buddy_allocator_header/seq/0")
	}
	tmp51, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.OfsBookkeepingInfoBlock = uint32(tmp51)
	tmp52, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.LenBookkeepingInfoBlock = uint32(tmp52)
	tmp53, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.CopyOfsBookkeepingInfoBlock = uint32(tmp53)
	tmp54, err := this._io.ReadBytes(int(16))
	if err != nil {
		return err
	}
	tmp54 = tmp54
	this._unnamed4 = tmp54
	return err
}

/**
 * Magic number 'Bud1'.
 */

/**
 * Needs to match 'offset_bookkeeping_info_block'.
 */

/**
 * Unused field which might simply be the unused space at the end of the block,
 * since the minimum allocation size is 32 bytes.
 */
type DsStore_MasterBlockRef struct {
	Idx uint64
	_io *kaitai.Stream
	_root *DsStore
	_parent *DsStore_BuddyAllocatorBody
	_raw_masterBlock []byte
	_f_masterBlock bool
	masterBlock *DsStore_MasterBlockRef_MasterBlock
}
func NewDsStore_MasterBlockRef(idx uint64) *DsStore_MasterBlockRef {
	return &DsStore_MasterBlockRef{
		Idx: idx,
	}
}

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

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

	return err
}
func (this *DsStore_MasterBlockRef) MasterBlock() (v *DsStore_MasterBlockRef_MasterBlock, err error) {
	if (this._f_masterBlock) {
		return this.masterBlock, nil
	}
	this._f_masterBlock = true
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	tmp55, err := this._parent.BlockAddresses[this._parent.DirectoryEntries[this.Idx].BlockId].Offset()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(tmp55), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp56, err := this._parent.BlockAddresses[this._parent.DirectoryEntries[this.Idx].BlockId].Size()
	if err != nil {
		return nil, err
	}
	tmp57, err := this._io.ReadBytes(int(tmp56))
	if err != nil {
		return nil, err
	}
	tmp57 = tmp57
	this._raw_masterBlock = tmp57
	_io__raw_masterBlock := kaitai.NewStream(bytes.NewReader(this._raw_masterBlock))
	tmp58 := NewDsStore_MasterBlockRef_MasterBlock()
	err = tmp58.Read(_io__raw_masterBlock, this, this._root)
	if err != nil {
		return nil, err
	}
	this.masterBlock = tmp58
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.masterBlock, nil
}
type DsStore_MasterBlockRef_MasterBlock struct {
	BlockId uint32
	NumInternalNodes uint32
	NumRecords uint32
	NumNodes uint32
	_unnamed4 uint32
	_io *kaitai.Stream
	_root *DsStore
	_parent *DsStore_MasterBlockRef
	_f_rootBlock bool
	rootBlock *DsStore_Block
}
func NewDsStore_MasterBlockRef_MasterBlock() *DsStore_MasterBlockRef_MasterBlock {
	return &DsStore_MasterBlockRef_MasterBlock{
	}
}

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

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

	tmp59, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.BlockId = uint32(tmp59)
	tmp60, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.NumInternalNodes = uint32(tmp60)
	tmp61, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.NumRecords = uint32(tmp61)
	tmp62, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.NumNodes = uint32(tmp62)
	tmp63, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this._unnamed4 = tmp63
	return err
}
func (this *DsStore_MasterBlockRef_MasterBlock) RootBlock() (v *DsStore_Block, err error) {
	if (this._f_rootBlock) {
		return this.rootBlock, nil
	}
	this._f_rootBlock = true
	thisIo := this._root._io
	_pos, err := thisIo.Pos()
	if err != nil {
		return nil, err
	}
	tmp64, err := this._root.BuddyAllocatorBody()
	if err != nil {
		return nil, err
	}
	tmp65, err := tmp64.BlockAddresses[this.BlockId].Offset()
	if err != nil {
		return nil, err
	}
	_, err = thisIo.Seek(int64(tmp65), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp66 := NewDsStore_Block()
	err = tmp66.Read(thisIo, this, this._root)
	if err != nil {
		return nil, err
	}
	this.rootBlock = tmp66
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	return this.rootBlock, nil
}

/**
 * Block number of the B-tree's root node.
 */

/**
 * Number of internal node levels.
 */

/**
 * Number of records in the tree.
 */

/**
 * Number of nodes in the tree.
 */

/**
 * Always 0x1000, probably the B-tree node page size.
 */