Huawei Bootloader packed image format: Go parsing library

Format of bootloader-*.img files found in factory images of certain Android devices from Huawei:

All image versions can be found in factory images at https://developers.google.com/android/images for the specific device. To avoid having to download an entire ZIP archive when you only need one file from it, install remotezip and use its command line tool to list members in the archive and then to download only the file you want.

File extension

img

KS implementation details

License: CC0-1.0

This page hosts a formal specification of Huawei Bootloader packed image 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 Huawei Bootloader packed image format

android_bootldr_huawei.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"
)


/**
 * Format of `bootloader-*.img` files found in factory images of certain Android devices from Huawei:
 * 
 * * Nexus 6P "angler": [sample][sample-angler] ([other samples][others-angler]),
 *   [releasetools.py](https://android.googlesource.com/device/huawei/angler/+/cf92cd8/releasetools.py#29)
 * 
 * [sample-angler]: https://androidfilehost.com/?fid=11410963190603870158 "bootloader-angler-angler-03.84.img"
 * [others-angler]: https://androidfilehost.com/?w=search&s=bootloader-angler&type=files
 * 
 * All image versions can be found in factory images at
 * <https://developers.google.com/android/images> for the specific device. To
 * avoid having to download an entire ZIP archive when you only need one file
 * from it, install [remotezip](https://github.com/gtsystem/python-remotezip) and
 * use its [command line
 * tool](https://github.com/gtsystem/python-remotezip#command-line-tool) to list
 * members in the archive and then to download only the file you want.
 * @see <a href="https://android.googlesource.com/device/huawei/angler/+/673cfb9/releasetools.py">Source</a>
 * @see <a href="https://source.codeaurora.org/quic/la/device/qcom/common/tree/meta_image/meta_format.h?h=LA.UM.6.1.1&amp;id=a68d284aee85">Source</a>
 * @see <a href="https://source.codeaurora.org/quic/la/device/qcom/common/tree/meta_image/meta_image.c?h=LA.UM.6.1.1&amp;id=a68d284aee85">Source</a>
 */
type AndroidBootldrHuawei struct {
	MetaHeader *AndroidBootldrHuawei_MetaHdr
	HeaderExt []byte
	ImageHeader *AndroidBootldrHuawei_ImageHdr
	_io *kaitai.Stream
	_root *AndroidBootldrHuawei
	_parent kaitai.Struct
	_raw_ImageHeader []byte
}
func NewAndroidBootldrHuawei() *AndroidBootldrHuawei {
	return &AndroidBootldrHuawei{
	}
}

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

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

	tmp1 := NewAndroidBootldrHuawei_MetaHdr()
	err = tmp1.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.MetaHeader = tmp1
	tmp2, err := this._io.ReadBytes(int(this.MetaHeader.LenMetaHeader - 76))
	if err != nil {
		return err
	}
	tmp2 = tmp2
	this.HeaderExt = tmp2
	tmp3, err := this._io.ReadBytes(int(this.MetaHeader.LenImageHeader))
	if err != nil {
		return err
	}
	tmp3 = tmp3
	this._raw_ImageHeader = tmp3
	_io__raw_ImageHeader := kaitai.NewStream(bytes.NewReader(this._raw_ImageHeader))
	tmp4 := NewAndroidBootldrHuawei_ImageHdr()
	err = tmp4.Read(_io__raw_ImageHeader, this, this._root)
	if err != nil {
		return err
	}
	this.ImageHeader = tmp4
	return err
}
type AndroidBootldrHuawei_ImageHdr struct {
	Entries []*AndroidBootldrHuawei_ImageHdrEntry
	_io *kaitai.Stream
	_root *AndroidBootldrHuawei
	_parent *AndroidBootldrHuawei
}
func NewAndroidBootldrHuawei_ImageHdr() *AndroidBootldrHuawei_ImageHdr {
	return &AndroidBootldrHuawei_ImageHdr{
	}
}

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

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

	for i := 0;; i++ {
		tmp5, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp5 {
			break
		}
		tmp6 := NewAndroidBootldrHuawei_ImageHdrEntry()
		err = tmp6.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Entries = append(this.Entries, tmp6)
	}
	return err
}

/**
 * The C generator program defines `img_header` as a [fixed size
 * array](https://source.codeaurora.org/quic/la/device/qcom/common/tree/meta_image/meta_image.c?h=LA.UM.6.1.1&id=a68d284aee85#n42)
 * of `img_header_entry_t` structs with length `MAX_IMAGES` (which is
 * defined as `16`).
 * 
 * This means that technically there will always be 16 `image_hdr`
 * entries, the first *n* entries being used (filled with real values)
 * and the rest left unused with all bytes zero.
 * 
 * To check if an entry is used, use the `is_used` attribute.
 */
type AndroidBootldrHuawei_ImageHdrEntry struct {
	Name string
	OfsBody uint32
	LenBody uint32
	_io *kaitai.Stream
	_root *AndroidBootldrHuawei
	_parent *AndroidBootldrHuawei_ImageHdr
	_f_body bool
	body []byte
	_f_isUsed bool
	isUsed bool
}
func NewAndroidBootldrHuawei_ImageHdrEntry() *AndroidBootldrHuawei_ImageHdrEntry {
	return &AndroidBootldrHuawei_ImageHdrEntry{
	}
}

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

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

	tmp7, err := this._io.ReadBytes(int(72))
	if err != nil {
		return err
	}
	tmp7 = kaitai.BytesTerminate(tmp7, 0, false)
	this.Name = string(tmp7)
	tmp8, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.OfsBody = uint32(tmp8)
	tmp9, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.LenBody = uint32(tmp9)
	return err
}
func (this *AndroidBootldrHuawei_ImageHdrEntry) Body() (v []byte, err error) {
	if (this._f_body) {
		return this.body, nil
	}
	this._f_body = true
	tmp10, err := this.IsUsed()
	if err != nil {
		return nil, err
	}
	if (tmp10) {
		thisIo := this._root._io
		_pos, err := thisIo.Pos()
		if err != nil {
			return nil, err
		}
		_, err = thisIo.Seek(int64(this.OfsBody), io.SeekStart)
		if err != nil {
			return nil, err
		}
		tmp11, err := thisIo.ReadBytes(int(this.LenBody))
		if err != nil {
			return nil, err
		}
		tmp11 = tmp11
		this.body = tmp11
		_, err = thisIo.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
	}
	return this.body, nil
}

/**
 * @see <a href="https://source.codeaurora.org/quic/la/device/qcom/common/tree/meta_image/meta_image.c?h=LA.UM.6.1.1&amp;id=a68d284aee85#n119">Source</a>
 */
func (this *AndroidBootldrHuawei_ImageHdrEntry) IsUsed() (v bool, err error) {
	if (this._f_isUsed) {
		return this.isUsed, nil
	}
	this._f_isUsed = true
	this.isUsed = bool( ((this.OfsBody != 0) && (this.LenBody != 0)) )
	return this.isUsed, nil
}

/**
 * partition name
 */
type AndroidBootldrHuawei_MetaHdr struct {
	Magic []byte
	Version *AndroidBootldrHuawei_Version
	ImageVersion string
	LenMetaHeader uint16
	LenImageHeader uint16
	_io *kaitai.Stream
	_root *AndroidBootldrHuawei
	_parent *AndroidBootldrHuawei
}
func NewAndroidBootldrHuawei_MetaHdr() *AndroidBootldrHuawei_MetaHdr {
	return &AndroidBootldrHuawei_MetaHdr{
	}
}

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

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

	tmp12, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp12 = tmp12
	this.Magic = tmp12
	if !(bytes.Equal(this.Magic, []uint8{60, 214, 26, 206})) {
		return kaitai.NewValidationNotEqualError([]uint8{60, 214, 26, 206}, this.Magic, this._io, "/types/meta_hdr/seq/0")
	}
	tmp13 := NewAndroidBootldrHuawei_Version()
	err = tmp13.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Version = tmp13
	tmp14, err := this._io.ReadBytes(int(64))
	if err != nil {
		return err
	}
	tmp14 = kaitai.BytesTerminate(tmp14, 0, false)
	this.ImageVersion = string(tmp14)
	tmp15, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.LenMetaHeader = uint16(tmp15)
	tmp16, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.LenImageHeader = uint16(tmp16)
	return err
}
type AndroidBootldrHuawei_Version struct {
	Major uint16
	Minor uint16
	_io *kaitai.Stream
	_root *AndroidBootldrHuawei
	_parent *AndroidBootldrHuawei_MetaHdr
}
func NewAndroidBootldrHuawei_Version() *AndroidBootldrHuawei_Version {
	return &AndroidBootldrHuawei_Version{
	}
}

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

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

	tmp17, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.Major = uint16(tmp17)
	tmp18, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.Minor = uint16(tmp18)
	return err
}