Microsoft Compound File Binary (CFB), AKA OLE (Object Linking and Embedding) file format: Go parsing library

This page hosts a formal specification of Microsoft Compound File Binary (CFB), AKA OLE (Object Linking and Embedding) file 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 Microsoft Compound File Binary (CFB), AKA OLE (Object Linking and Embedding) file format

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

type MicrosoftCfb struct {
	Header *MicrosoftCfb_CfbHeader
	_io *kaitai.Stream
	_root *MicrosoftCfb
	_parent interface{}
	_raw_fat []byte
	_f_sectorSize bool
	sectorSize int
	_f_fat bool
	fat *MicrosoftCfb_FatEntries
	_f_dir bool
	dir *MicrosoftCfb_DirEntry
}
func NewMicrosoftCfb() *MicrosoftCfb {
	return &MicrosoftCfb{
	}
}

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

	tmp1 := NewMicrosoftCfb_CfbHeader()
	err = tmp1.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Header = tmp1
	return err
}
func (this *MicrosoftCfb) SectorSize() (v int, err error) {
	if (this._f_sectorSize) {
		return this.sectorSize, nil
	}
	this.sectorSize = int((1 << this.Header.SectorShift))
	this._f_sectorSize = true
	return this.sectorSize, nil
}
func (this *MicrosoftCfb) Fat() (v *MicrosoftCfb_FatEntries, err error) {
	if (this._f_fat) {
		return this.fat, nil
	}
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	tmp2, err := this.SectorSize()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(tmp2), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp3, err := this.SectorSize()
	if err != nil {
		return nil, err
	}
	tmp4, err := this._io.ReadBytes(int((this.Header.SizeFat * tmp3)))
	if err != nil {
		return nil, err
	}
	tmp4 = tmp4
	this._raw_fat = tmp4
	_io__raw_fat := kaitai.NewStream(bytes.NewReader(this._raw_fat))
	tmp5 := NewMicrosoftCfb_FatEntries()
	err = tmp5.Read(_io__raw_fat, this, this._root)
	if err != nil {
		return nil, err
	}
	this.fat = tmp5
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	this._f_fat = true
	this._f_fat = true
	return this.fat, nil
}
func (this *MicrosoftCfb) Dir() (v *MicrosoftCfb_DirEntry, err error) {
	if (this._f_dir) {
		return this.dir, nil
	}
	_pos, err := this._io.Pos()
	if err != nil {
		return nil, err
	}
	tmp6, err := this.SectorSize()
	if err != nil {
		return nil, err
	}
	_, err = this._io.Seek(int64(((this.Header.OfsDir + 1) * tmp6)), io.SeekStart)
	if err != nil {
		return nil, err
	}
	tmp7 := NewMicrosoftCfb_DirEntry()
	err = tmp7.Read(this._io, this, this._root)
	if err != nil {
		return nil, err
	}
	this.dir = tmp7
	_, err = this._io.Seek(_pos, io.SeekStart)
	if err != nil {
		return nil, err
	}
	this._f_dir = true
	this._f_dir = true
	return this.dir, nil
}
type MicrosoftCfb_CfbHeader struct {
	Signature []byte
	Clsid []byte
	VersionMinor uint16
	VersionMajor uint16
	ByteOrder []byte
	SectorShift uint16
	MiniSectorShift uint16
	Reserved1 []byte
	SizeDir int32
	SizeFat int32
	OfsDir int32
	TransactionSeq int32
	MiniStreamCutoffSize int32
	OfsMiniFat int32
	SizeMiniFat int32
	OfsDifat int32
	SizeDifat int32
	Difat []int32
	_io *kaitai.Stream
	_root *MicrosoftCfb
	_parent *MicrosoftCfb
}
func NewMicrosoftCfb_CfbHeader() *MicrosoftCfb_CfbHeader {
	return &MicrosoftCfb_CfbHeader{
	}
}

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

	tmp8, err := this._io.ReadBytes(int(8))
	if err != nil {
		return err
	}
	tmp8 = tmp8
	this.Signature = tmp8
	if !(bytes.Equal(this.Signature, []uint8{208, 207, 17, 224, 161, 177, 26, 225})) {
		return kaitai.NewValidationNotEqualError([]uint8{208, 207, 17, 224, 161, 177, 26, 225}, this.Signature, this._io, "/types/cfb_header/seq/0")
	}
	tmp9, err := this._io.ReadBytes(int(16))
	if err != nil {
		return err
	}
	tmp9 = tmp9
	this.Clsid = tmp9
	if !(bytes.Equal(this.Clsid, []uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})) {
		return kaitai.NewValidationNotEqualError([]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, this.Clsid, this._io, "/types/cfb_header/seq/1")
	}
	tmp10, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.VersionMinor = uint16(tmp10)
	tmp11, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.VersionMajor = uint16(tmp11)
	tmp12, err := this._io.ReadBytes(int(2))
	if err != nil {
		return err
	}
	tmp12 = tmp12
	this.ByteOrder = tmp12
	if !(bytes.Equal(this.ByteOrder, []uint8{254, 255})) {
		return kaitai.NewValidationNotEqualError([]uint8{254, 255}, this.ByteOrder, this._io, "/types/cfb_header/seq/4")
	}
	tmp13, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.SectorShift = uint16(tmp13)
	tmp14, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.MiniSectorShift = uint16(tmp14)
	tmp15, err := this._io.ReadBytes(int(6))
	if err != nil {
		return err
	}
	tmp15 = tmp15
	this.Reserved1 = tmp15
	tmp16, err := this._io.ReadS4le()
	if err != nil {
		return err
	}
	this.SizeDir = int32(tmp16)
	tmp17, err := this._io.ReadS4le()
	if err != nil {
		return err
	}
	this.SizeFat = int32(tmp17)
	tmp18, err := this._io.ReadS4le()
	if err != nil {
		return err
	}
	this.OfsDir = int32(tmp18)
	tmp19, err := this._io.ReadS4le()
	if err != nil {
		return err
	}
	this.TransactionSeq = int32(tmp19)
	tmp20, err := this._io.ReadS4le()
	if err != nil {
		return err
	}
	this.MiniStreamCutoffSize = int32(tmp20)
	tmp21, err := this._io.ReadS4le()
	if err != nil {
		return err
	}
	this.OfsMiniFat = int32(tmp21)
	tmp22, err := this._io.ReadS4le()
	if err != nil {
		return err
	}
	this.SizeMiniFat = int32(tmp22)
	tmp23, err := this._io.ReadS4le()
	if err != nil {
		return err
	}
	this.OfsDifat = int32(tmp23)
	tmp24, err := this._io.ReadS4le()
	if err != nil {
		return err
	}
	this.SizeDifat = int32(tmp24)
	for i := 0; i < int(109); i++ {
		_ = i
		tmp25, err := this._io.ReadS4le()
		if err != nil {
			return err
		}
		this.Difat = append(this.Difat, tmp25)
	}
	return err
}

/**
 * Magic bytes that confirm that this is a CFB file
 */

/**
 * Reserved class ID field, must be all 0
 */

/**
 * In theory, specifies a byte order. In practice, no other values besides FE FF (which imply little endian order) are used.
 */

/**
 * For major version 3, must be 0x9 (sector size = 512 bytes). For major version 4, must be 0xc (sector size = 4096 bytes).
 */

/**
 * Number of directory sectors in this file. For major version 3, must be 0.
 */

/**
 * Number of FAT sectors in this file.
 */

/**
 * Starting sector number for directory stream.
 */

/**
 * A transaction sequence number, which is incremented each time the file is saved if transactions are implemented, 0 otherwise.
 */

/**
 * Starting sector number for mini FAT.
 */

/**
 * Number of mini FAT sectors in this file.
 */

/**
 * Starting sector number for DIFAT.
 */

/**
 * Number of DIFAT sectors in this file.
 */
type MicrosoftCfb_FatEntries struct {
	Entries []int32
	_io *kaitai.Stream
	_root *MicrosoftCfb
	_parent *MicrosoftCfb
}
func NewMicrosoftCfb_FatEntries() *MicrosoftCfb_FatEntries {
	return &MicrosoftCfb_FatEntries{
	}
}

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

	for i := 1;; i++ {
		tmp26, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp26 {
			break
		}
		tmp27, err := this._io.ReadS4le()
		if err != nil {
			return err
		}
		this.Entries = append(this.Entries, tmp27)
	}
	return err
}

type MicrosoftCfb_DirEntry_ObjType int
const (
	MicrosoftCfb_DirEntry_ObjType__Unknown MicrosoftCfb_DirEntry_ObjType = 0
	MicrosoftCfb_DirEntry_ObjType__Storage MicrosoftCfb_DirEntry_ObjType = 1
	MicrosoftCfb_DirEntry_ObjType__Stream MicrosoftCfb_DirEntry_ObjType = 2
	MicrosoftCfb_DirEntry_ObjType__RootStorage MicrosoftCfb_DirEntry_ObjType = 5
)

type MicrosoftCfb_DirEntry_RbColor int
const (
	MicrosoftCfb_DirEntry_RbColor__Red MicrosoftCfb_DirEntry_RbColor = 0
	MicrosoftCfb_DirEntry_RbColor__Black MicrosoftCfb_DirEntry_RbColor = 1
)
type MicrosoftCfb_DirEntry struct {
	Name string
	NameLen uint16
	ObjectType MicrosoftCfb_DirEntry_ObjType
	ColorFlag MicrosoftCfb_DirEntry_RbColor
	LeftSiblingId int32
	RightSiblingId int32
	ChildId int32
	Clsid []byte
	State uint32
	TimeCreate uint64
	TimeMod uint64
	Ofs int32
	Size uint64
	_io *kaitai.Stream
	_root *MicrosoftCfb
	_parent interface{}
	_f_miniStream bool
	miniStream []byte
	_f_child bool
	child *MicrosoftCfb_DirEntry
	_f_leftSibling bool
	leftSibling *MicrosoftCfb_DirEntry
	_f_rightSibling bool
	rightSibling *MicrosoftCfb_DirEntry
}
func NewMicrosoftCfb_DirEntry() *MicrosoftCfb_DirEntry {
	return &MicrosoftCfb_DirEntry{
	}
}

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

	tmp28, err := this._io.ReadBytes(int(64))
	if err != nil {
		return err
	}
	tmp28 = tmp28
	tmp29, err := kaitai.BytesToStr(tmp28, unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewDecoder())
	if err != nil {
		return err
	}
	this.Name = tmp29
	tmp30, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.NameLen = uint16(tmp30)
	tmp31, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.ObjectType = MicrosoftCfb_DirEntry_ObjType(tmp31)
	tmp32, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.ColorFlag = MicrosoftCfb_DirEntry_RbColor(tmp32)
	tmp33, err := this._io.ReadS4le()
	if err != nil {
		return err
	}
	this.LeftSiblingId = int32(tmp33)
	tmp34, err := this._io.ReadS4le()
	if err != nil {
		return err
	}
	this.RightSiblingId = int32(tmp34)
	tmp35, err := this._io.ReadS4le()
	if err != nil {
		return err
	}
	this.ChildId = int32(tmp35)
	tmp36, err := this._io.ReadBytes(int(16))
	if err != nil {
		return err
	}
	tmp36 = tmp36
	this.Clsid = tmp36
	tmp37, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.State = uint32(tmp37)
	tmp38, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.TimeCreate = uint64(tmp38)
	tmp39, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.TimeMod = uint64(tmp39)
	tmp40, err := this._io.ReadS4le()
	if err != nil {
		return err
	}
	this.Ofs = int32(tmp40)
	tmp41, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.Size = uint64(tmp41)
	return err
}
func (this *MicrosoftCfb_DirEntry) MiniStream() (v []byte, err error) {
	if (this._f_miniStream) {
		return this.miniStream, nil
	}
	if (this.ObjectType == MicrosoftCfb_DirEntry_ObjType__RootStorage) {
		thisIo := this._root._io
		_pos, err := thisIo.Pos()
		if err != nil {
			return nil, err
		}
		tmp42, err := this._root.SectorSize()
		if err != nil {
			return nil, err
		}
		_, err = thisIo.Seek(int64(((this.Ofs + 1) * tmp42)), io.SeekStart)
		if err != nil {
			return nil, err
		}
		tmp43, err := thisIo.ReadBytes(int(this.Size))
		if err != nil {
			return nil, err
		}
		tmp43 = tmp43
		this.miniStream = tmp43
		_, err = thisIo.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
		this._f_miniStream = true
	}
	this._f_miniStream = true
	return this.miniStream, nil
}
func (this *MicrosoftCfb_DirEntry) Child() (v *MicrosoftCfb_DirEntry, err error) {
	if (this._f_child) {
		return this.child, nil
	}
	if (this.ChildId != -1) {
		thisIo := this._root._io
		_pos, err := thisIo.Pos()
		if err != nil {
			return nil, err
		}
		tmp44, err := this._root.SectorSize()
		if err != nil {
			return nil, err
		}
		_, err = thisIo.Seek(int64((((this._root.Header.OfsDir + 1) * tmp44) + (this.ChildId * 128))), io.SeekStart)
		if err != nil {
			return nil, err
		}
		tmp45 := NewMicrosoftCfb_DirEntry()
		err = tmp45.Read(thisIo, this, this._root)
		if err != nil {
			return nil, err
		}
		this.child = tmp45
		_, err = thisIo.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
		this._f_child = true
	}
	this._f_child = true
	return this.child, nil
}
func (this *MicrosoftCfb_DirEntry) LeftSibling() (v *MicrosoftCfb_DirEntry, err error) {
	if (this._f_leftSibling) {
		return this.leftSibling, nil
	}
	if (this.LeftSiblingId != -1) {
		thisIo := this._root._io
		_pos, err := thisIo.Pos()
		if err != nil {
			return nil, err
		}
		tmp46, err := this._root.SectorSize()
		if err != nil {
			return nil, err
		}
		_, err = thisIo.Seek(int64((((this._root.Header.OfsDir + 1) * tmp46) + (this.LeftSiblingId * 128))), io.SeekStart)
		if err != nil {
			return nil, err
		}
		tmp47 := NewMicrosoftCfb_DirEntry()
		err = tmp47.Read(thisIo, this, this._root)
		if err != nil {
			return nil, err
		}
		this.leftSibling = tmp47
		_, err = thisIo.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
		this._f_leftSibling = true
	}
	this._f_leftSibling = true
	return this.leftSibling, nil
}
func (this *MicrosoftCfb_DirEntry) RightSibling() (v *MicrosoftCfb_DirEntry, err error) {
	if (this._f_rightSibling) {
		return this.rightSibling, nil
	}
	if (this.RightSiblingId != -1) {
		thisIo := this._root._io
		_pos, err := thisIo.Pos()
		if err != nil {
			return nil, err
		}
		tmp48, err := this._root.SectorSize()
		if err != nil {
			return nil, err
		}
		_, err = thisIo.Seek(int64((((this._root.Header.OfsDir + 1) * tmp48) + (this.RightSiblingId * 128))), io.SeekStart)
		if err != nil {
			return nil, err
		}
		tmp49 := NewMicrosoftCfb_DirEntry()
		err = tmp49.Read(thisIo, this, this._root)
		if err != nil {
			return nil, err
		}
		this.rightSibling = tmp49
		_, err = thisIo.Seek(_pos, io.SeekStart)
		if err != nil {
			return nil, err
		}
		this._f_rightSibling = true
	}
	this._f_rightSibling = true
	return this.rightSibling, nil
}

/**
 * User-defined flags for storage or root storage objects
 */

/**
 * Creation time, in Windows FILETIME format (number of 100-nanosecond intervals since January 1, 1601, UTC)
 */

/**
 * Modification time, in Windows FILETIME format (number of 100-nanosecond intervals since January 1, 1601, UTC).
 */

/**
 * For stream object, number of starting sector. For a root storage object, first sector of the mini stream, if the mini stream exists.
 */

/**
 * For stream object, size of user-defined data in bytes. For a root storage object, size of the mini stream.
 */