.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.
// 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
}