.dbf file format of dBASE: Go parsing library

.dbf is a relational database format introduced in DOS database management system dBASE in 1982.

One .dbf file corresponds to one table and contains a series of headers, specification of fields, and a number of fixed-size records.

This page hosts a formal specification of .dbf file format of dBASE 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 .dbf file format of dBASE

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


/**
 * .dbf is a relational database format introduced in DOS database
 * management system dBASE in 1982.
 * 
 * One .dbf file corresponds to one table and contains a series of headers,
 * specification of fields, and a number of fixed-size records.
 * @see <a href="http://www.dbase.com/Knowledgebase/INT/db7_file_fmt.htm">Source</a>
 */

type Dbf_DeleteState int
const (
	Dbf_DeleteState__False Dbf_DeleteState = 32
	Dbf_DeleteState__True Dbf_DeleteState = 42
)
type Dbf struct {
	Header1 *Dbf_Header1
	Header2 *Dbf_Header2
	HeaderTerminator []byte
	Records []*Dbf_Record
	_io *kaitai.Stream
	_root *Dbf
	_parent interface{}
	_raw_Header2 []byte
	_raw_Records [][]byte
}
func NewDbf() *Dbf {
	return &Dbf{
	}
}

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

	tmp1 := NewDbf_Header1()
	err = tmp1.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Header1 = tmp1
	tmp2, err := this._io.ReadBytes(int(((this.Header1.LenHeader - 12) - 1)))
	if err != nil {
		return err
	}
	tmp2 = tmp2
	this._raw_Header2 = tmp2
	_io__raw_Header2 := kaitai.NewStream(bytes.NewReader(this._raw_Header2))
	tmp3 := NewDbf_Header2()
	err = tmp3.Read(_io__raw_Header2, this, this._root)
	if err != nil {
		return err
	}
	this.Header2 = tmp3
	tmp4, err := this._io.ReadBytes(int(1))
	if err != nil {
		return err
	}
	tmp4 = tmp4
	this.HeaderTerminator = tmp4
	if !(bytes.Equal(this.HeaderTerminator, []uint8{13})) {
		return kaitai.NewValidationNotEqualError([]uint8{13}, this.HeaderTerminator, this._io, "/seq/2")
	}
	for i := 0; i < int(this.Header1.NumRecords); i++ {
		_ = i
		tmp5, err := this._io.ReadBytes(int(this.Header1.LenRecord))
		if err != nil {
			return err
		}
		tmp5 = tmp5
		this._raw_Records = append(this._raw_Records, tmp5)
		_io__raw_Records := kaitai.NewStream(bytes.NewReader(this._raw_Records[i]))
		tmp6 := NewDbf_Record()
		err = tmp6.Read(_io__raw_Records, this, this._root)
		if err != nil {
			return err
		}
		this.Records = append(this.Records, tmp6)
	}
	return err
}
type Dbf_Header2 struct {
	HeaderDbase3 *Dbf_HeaderDbase3
	HeaderDbase7 *Dbf_HeaderDbase7
	Fields []*Dbf_Field
	_io *kaitai.Stream
	_root *Dbf
	_parent *Dbf
}
func NewDbf_Header2() *Dbf_Header2 {
	return &Dbf_Header2{
	}
}

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

	tmp7, err := this._root.Header1.DbaseLevel()
	if err != nil {
		return err
	}
	if (tmp7 == 3) {
		tmp8 := NewDbf_HeaderDbase3()
		err = tmp8.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.HeaderDbase3 = tmp8
	}
	tmp9, err := this._root.Header1.DbaseLevel()
	if err != nil {
		return err
	}
	if (tmp9 == 7) {
		tmp10 := NewDbf_HeaderDbase7()
		err = tmp10.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.HeaderDbase7 = tmp10
	}
	for i := 1;; i++ {
		tmp11, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp11 {
			break
		}
		tmp12 := NewDbf_Field()
		err = tmp12.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Fields = append(this.Fields, tmp12)
	}
	return err
}
type Dbf_Field struct {
	Name string
	Datatype uint8
	DataAddress uint32
	Length uint8
	DecimalCount uint8
	Reserved1 []byte
	WorkAreaId uint8
	Reserved2 []byte
	SetFieldsFlag uint8
	Reserved3 []byte
	_io *kaitai.Stream
	_root *Dbf
	_parent *Dbf_Header2
}
func NewDbf_Field() *Dbf_Field {
	return &Dbf_Field{
	}
}

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

	tmp13, err := this._io.ReadBytes(int(11))
	if err != nil {
		return err
	}
	tmp13 = kaitai.BytesTerminate(tmp13, 0, false)
	this.Name = string(tmp13)
	tmp14, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Datatype = tmp14
	tmp15, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.DataAddress = uint32(tmp15)
	tmp16, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Length = tmp16
	tmp17, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.DecimalCount = tmp17
	tmp18, err := this._io.ReadBytes(int(2))
	if err != nil {
		return err
	}
	tmp18 = tmp18
	this.Reserved1 = tmp18
	tmp19, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.WorkAreaId = tmp19
	tmp20, err := this._io.ReadBytes(int(2))
	if err != nil {
		return err
	}
	tmp20 = tmp20
	this.Reserved2 = tmp20
	tmp21, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.SetFieldsFlag = tmp21
	tmp22, err := this._io.ReadBytes(int(8))
	if err != nil {
		return err
	}
	tmp22 = tmp22
	this.Reserved3 = tmp22
	return err
}

/**
 * @see <a href="http://www.dbase.com/Knowledgebase/INT/db7_file_fmt.htm">- section 1.1</a>
 */
type Dbf_Header1 struct {
	Version uint8
	LastUpdateY uint8
	LastUpdateM uint8
	LastUpdateD uint8
	NumRecords uint32
	LenHeader uint16
	LenRecord uint16
	_io *kaitai.Stream
	_root *Dbf
	_parent *Dbf
	_f_dbaseLevel bool
	dbaseLevel int
}
func NewDbf_Header1() *Dbf_Header1 {
	return &Dbf_Header1{
	}
}

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

	tmp23, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Version = tmp23
	tmp24, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.LastUpdateY = tmp24
	tmp25, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.LastUpdateM = tmp25
	tmp26, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.LastUpdateD = tmp26
	tmp27, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.NumRecords = uint32(tmp27)
	tmp28, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.LenHeader = uint16(tmp28)
	tmp29, err := this._io.ReadU2le()
	if err != nil {
		return err
	}
	this.LenRecord = uint16(tmp29)
	return err
}
func (this *Dbf_Header1) DbaseLevel() (v int, err error) {
	if (this._f_dbaseLevel) {
		return this.dbaseLevel, nil
	}
	this.dbaseLevel = int((this.Version & 7))
	this._f_dbaseLevel = true
	return this.dbaseLevel, nil
}
type Dbf_HeaderDbase3 struct {
	Reserved1 []byte
	Reserved2 []byte
	Reserved3 []byte
	_io *kaitai.Stream
	_root *Dbf
	_parent *Dbf_Header2
}
func NewDbf_HeaderDbase3() *Dbf_HeaderDbase3 {
	return &Dbf_HeaderDbase3{
	}
}

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

	tmp30, err := this._io.ReadBytes(int(3))
	if err != nil {
		return err
	}
	tmp30 = tmp30
	this.Reserved1 = tmp30
	tmp31, err := this._io.ReadBytes(int(13))
	if err != nil {
		return err
	}
	tmp31 = tmp31
	this.Reserved2 = tmp31
	tmp32, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp32 = tmp32
	this.Reserved3 = tmp32
	return err
}
type Dbf_HeaderDbase7 struct {
	Reserved1 []byte
	HasIncompleteTransaction uint8
	DbaseIvEncryption uint8
	Reserved2 []byte
	ProductionMdx uint8
	LanguageDriverId uint8
	Reserved3 []byte
	LanguageDriverName []byte
	Reserved4 []byte
	_io *kaitai.Stream
	_root *Dbf
	_parent *Dbf_Header2
}
func NewDbf_HeaderDbase7() *Dbf_HeaderDbase7 {
	return &Dbf_HeaderDbase7{
	}
}

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

	tmp33, err := this._io.ReadBytes(int(2))
	if err != nil {
		return err
	}
	tmp33 = tmp33
	this.Reserved1 = tmp33
	if !(bytes.Equal(this.Reserved1, []uint8{0, 0})) {
		return kaitai.NewValidationNotEqualError([]uint8{0, 0}, this.Reserved1, this._io, "/types/header_dbase_7/seq/0")
	}
	tmp34, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.HasIncompleteTransaction = tmp34
	tmp35, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.DbaseIvEncryption = tmp35
	tmp36, err := this._io.ReadBytes(int(12))
	if err != nil {
		return err
	}
	tmp36 = tmp36
	this.Reserved2 = tmp36
	tmp37, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.ProductionMdx = tmp37
	tmp38, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.LanguageDriverId = tmp38
	tmp39, err := this._io.ReadBytes(int(2))
	if err != nil {
		return err
	}
	tmp39 = tmp39
	this.Reserved3 = tmp39
	if !(bytes.Equal(this.Reserved3, []uint8{0, 0})) {
		return kaitai.NewValidationNotEqualError([]uint8{0, 0}, this.Reserved3, this._io, "/types/header_dbase_7/seq/6")
	}
	tmp40, err := this._io.ReadBytes(int(32))
	if err != nil {
		return err
	}
	tmp40 = tmp40
	this.LanguageDriverName = tmp40
	tmp41, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp41 = tmp41
	this.Reserved4 = tmp41
	return err
}
type Dbf_Record struct {
	Deleted Dbf_DeleteState
	RecordFields [][]byte
	_io *kaitai.Stream
	_root *Dbf
	_parent *Dbf
}
func NewDbf_Record() *Dbf_Record {
	return &Dbf_Record{
	}
}

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

	tmp42, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Deleted = Dbf_DeleteState(tmp42)
	for i := 0; i < int(len(this._root.Header2.Fields)); i++ {
		_ = i
		tmp43, err := this._io.ReadBytes(int(this._root.Header2.Fields[i].Length))
		if err != nil {
			return err
		}
		tmp43 = tmp43
		this.RecordFields = append(this.RecordFields, tmp43)
	}
	return err
}