APM (Apple Partition Map) partition table: Go parsing library

This page hosts a formal specification of APM (Apple Partition Map) partition table 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 APM (Apple Partition Map) partition table

apm_partition_table.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"
	"io"
	"bytes"
)


/**
 * @see <a href="https://en.wikipedia.org/wiki/Apple_Partition_Map">Source</a>
 */
type ApmPartitionTable struct {
	_io *kaitai.Stream
	_root *ApmPartitionTable
	_parent interface{}
	_raw_partitionLookup []byte
	_raw_partitionEntries [][]byte
	_f_sectorSize bool
	sectorSize int
	_f_partitionLookup bool
	partitionLookup *ApmPartitionTable_PartitionEntry
	_f_partitionEntries bool
	partitionEntries []*ApmPartitionTable_PartitionEntry
}
func NewApmPartitionTable() *ApmPartitionTable {
	return &ApmPartitionTable{
	}
}

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

	return err
}

/**
 * 0x200 (512) bytes for disks, 0x1000 (4096) bytes is not supported by APM
 * 0x800 (2048) bytes for CDROM
 */
func (this *ApmPartitionTable) SectorSize() (v int, err error) {
	if (this._f_sectorSize) {
		return this.sectorSize, nil
	}
	this.sectorSize = int(512)
	this._f_sectorSize = true
	return this.sectorSize, nil
}

/**
 * Every partition entry contains the number of partition entries.
 * We parse the first entry, to know how many to parse, including the first one.
 * No logic is given what to do if other entries have a different number.
 */
func (this *ApmPartitionTable) PartitionLookup() (v *ApmPartitionTable_PartitionEntry, err error) {
	if (this._f_partitionLookup) {
		return this.partitionLookup, nil
	}
	thisIo := this._root._io
	_pos, err := thisIo.Pos()
	if err != nil {
		return nil, err
	}
	tmp1, err := this._root.SectorSize()
	if err != nil {
		return nil, err
	}
	_, err = thisIo.Seek(int64(tmp1), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp2, err := this.SectorSize()
	if err != nil {
		return nil, err
	}
	tmp3, err := thisIo.ReadBytes(int(tmp2))
	if err != nil {
		return nil, err
	}
	tmp3 = tmp3
	this._raw_partitionLookup = tmp3
	_io__raw_partitionLookup := kaitai.NewStream(bytes.NewReader(this._raw_partitionLookup))
	tmp4 := NewApmPartitionTable_PartitionEntry()
	err = tmp4.Read(_io__raw_partitionLookup, this, this._root)
	if err != nil {
		return nil, err
	}
	this.partitionLookup = tmp4
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	this._f_partitionLookup = true
	this._f_partitionLookup = true
	return this.partitionLookup, nil
}
func (this *ApmPartitionTable) PartitionEntries() (v []*ApmPartitionTable_PartitionEntry, err error) {
	if (this._f_partitionEntries) {
		return this.partitionEntries, nil
	}
	thisIo := this._root._io
	_pos, err := thisIo.Pos()
	if err != nil {
		return nil, err
	}
	tmp5, err := this._root.SectorSize()
	if err != nil {
		return nil, err
	}
	_, err = thisIo.Seek(int64(tmp5), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp6, err := this._root.PartitionLookup()
	if err != nil {
		return nil, err
	}
	for i := 0; i < int(tmp6.NumberOfPartitions); i++ {
		_ = i
		tmp7, err := this.SectorSize()
		if err != nil {
			return nil, err
		}
		tmp8, err := thisIo.ReadBytes(int(tmp7))
		if err != nil {
			return nil, err
		}
		tmp8 = tmp8
		this._raw_partitionEntries = append(this._raw_partitionEntries, tmp8)
		_io__raw_partitionEntries := kaitai.NewStream(bytes.NewReader(this._raw_partitionEntries[i]))
		tmp9 := NewApmPartitionTable_PartitionEntry()
		err = tmp9.Read(_io__raw_partitionEntries, this, this._root)
		if err != nil {
			return nil, err
		}
		this.partitionEntries = append(this.partitionEntries, tmp9)
	}
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	this._f_partitionEntries = true
	this._f_partitionEntries = true
	return this.partitionEntries, nil
}
type ApmPartitionTable_PartitionEntry struct {
	Magic []byte
	Reserved1 []byte
	NumberOfPartitions uint32
	PartitionStart uint32
	PartitionSize uint32
	PartitionName string
	PartitionType string
	DataStart uint32
	DataSize uint32
	PartitionStatus uint32
	BootCodeStart uint32
	BootCodeSize uint32
	BootLoaderAddress uint32
	Reserved2 []byte
	BootCodeEntry uint32
	Reserved3 []byte
	BootCodeCksum uint32
	ProcessorType string
	_io *kaitai.Stream
	_root *ApmPartitionTable
	_parent *ApmPartitionTable
	_f_partition bool
	partition []byte
	_f_data bool
	data []byte
	_f_bootCode bool
	bootCode []byte
}
func NewApmPartitionTable_PartitionEntry() *ApmPartitionTable_PartitionEntry {
	return &ApmPartitionTable_PartitionEntry{
	}
}

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

	tmp10, err := this._io.ReadBytes(int(2))
	if err != nil {
		return err
	}
	tmp10 = tmp10
	this.Magic = tmp10
	if !(bytes.Equal(this.Magic, []uint8{80, 77})) {
		return kaitai.NewValidationNotEqualError([]uint8{80, 77}, this.Magic, this._io, "/types/partition_entry/seq/0")
	}
	tmp11, err := this._io.ReadBytes(int(2))
	if err != nil {
		return err
	}
	tmp11 = tmp11
	this.Reserved1 = tmp11
	tmp12, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.NumberOfPartitions = uint32(tmp12)
	tmp13, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.PartitionStart = uint32(tmp13)
	tmp14, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.PartitionSize = uint32(tmp14)
	tmp15, err := this._io.ReadBytes(int(32))
	if err != nil {
		return err
	}
	tmp15 = kaitai.BytesTerminate(tmp15, 0, false)
	this.PartitionName = string(tmp15)
	tmp16, err := this._io.ReadBytes(int(32))
	if err != nil {
		return err
	}
	tmp16 = kaitai.BytesTerminate(tmp16, 0, false)
	this.PartitionType = string(tmp16)
	tmp17, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.DataStart = uint32(tmp17)
	tmp18, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.DataSize = uint32(tmp18)
	tmp19, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.PartitionStatus = uint32(tmp19)
	tmp20, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.BootCodeStart = uint32(tmp20)
	tmp21, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.BootCodeSize = uint32(tmp21)
	tmp22, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.BootLoaderAddress = uint32(tmp22)
	tmp23, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp23 = tmp23
	this.Reserved2 = tmp23
	tmp24, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.BootCodeEntry = uint32(tmp24)
	tmp25, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp25 = tmp25
	this.Reserved3 = tmp25
	tmp26, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.BootCodeCksum = uint32(tmp26)
	tmp27, err := this._io.ReadBytes(int(16))
	if err != nil {
		return err
	}
	tmp27 = kaitai.BytesTerminate(tmp27, 0, false)
	this.ProcessorType = string(tmp27)
	return err
}
func (this *ApmPartitionTable_PartitionEntry) Partition() (v []byte, err error) {
	if (this._f_partition) {
		return this.partition, nil
	}
	if ((this.PartitionStatus & 1) != 0) {
		thisIo := this._root._io
		_pos, err := thisIo.Pos()
		if err != nil {
			return nil, err
		}
		tmp28, err := this._root.SectorSize()
		if err != nil {
			return nil, err
		}
		_, err = thisIo.Seek(int64((this.PartitionStart * tmp28)), io.SeekStart)
		if err != nil {
			return nil, err
		}
		tmp29, err := this._root.SectorSize()
		if err != nil {
			return nil, err
		}
		tmp30, err := thisIo.ReadBytes(int((this.PartitionSize * tmp29)))
		if err != nil {
			return nil, err
		}
		tmp30 = tmp30
		this.partition = tmp30
		_, err = thisIo.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
		this._f_partition = true
	}
	this._f_partition = true
	return this.partition, nil
}
func (this *ApmPartitionTable_PartitionEntry) Data() (v []byte, err error) {
	if (this._f_data) {
		return this.data, nil
	}
	thisIo := this._root._io
	_pos, err := thisIo.Pos()
	if err != nil {
		return nil, err
	}
	tmp31, err := this._root.SectorSize()
	if err != nil {
		return nil, err
	}
	_, err = thisIo.Seek(int64((this.DataStart * tmp31)), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp32, err := this._root.SectorSize()
	if err != nil {
		return nil, err
	}
	tmp33, err := thisIo.ReadBytes(int((this.DataSize * tmp32)))
	if err != nil {
		return nil, err
	}
	tmp33 = tmp33
	this.data = tmp33
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	this._f_data = true
	this._f_data = true
	return this.data, nil
}
func (this *ApmPartitionTable_PartitionEntry) BootCode() (v []byte, err error) {
	if (this._f_bootCode) {
		return this.bootCode, nil
	}
	thisIo := this._root._io
	_pos, err := thisIo.Pos()
	if err != nil {
		return nil, err
	}
	tmp34, err := this._root.SectorSize()
	if err != nil {
		return nil, err
	}
	_, err = thisIo.Seek(int64((this.BootCodeStart * tmp34)), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp35, err := thisIo.ReadBytes(int(this.BootCodeSize))
	if err != nil {
		return nil, err
	}
	tmp35 = tmp35
	this.bootCode = tmp35
	_, err = thisIo.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	this._f_bootCode = true
	this._f_bootCode = true
	return this.bootCode, nil
}

/**
 * First sector
 */

/**
 * Number of sectors
 */

/**
 * First sector
 */

/**
 * Number of sectors
 */

/**
 * First sector
 */

/**
 * Number of bytes
 */

/**
 * Address of bootloader code
 */

/**
 * Boot code entry point
 */

/**
 * Boot code checksum
 */