Golang binary decoder to structure
go get -u github.com/ghostiam/binstruct
package main
import (
"encoding/binary""fmt""log""os""github.com/ghostiam/binstruct"
)
funcmain() {
file, err:=os.Open("testdata/file.bin")
iferr!=nil {
log.Fatal(err)
}
typedataStructstruct {
Arr []int16`bin:"len:4"`
}
varactualdataStructdecoder:=binstruct.NewDecoder(file, binary.BigEndian)
// decoder.SetDebug(true) // you can enable the output of bytes read for debuggingerr=decoder.Decode(&actual)
iferr!=nil {
log.Fatal(err)
}
fmt.Printf("%+v", actual)
// Output:// {Arr:[1 2 3 4]}
}package main
import (
"fmt""log""github.com/ghostiam/binstruct"
)
funcmain() {
data:= []byte{
0x00, 0x01,
0x00, 0x02,
0x00, 0x03,
0x00, 0x04,
}
typedataStructstruct {
Arr []int16`bin:"len:4"`
}
varactualdataStructerr:=binstruct.UnmarshalBE(data, &actual) // UnmarshalLE() or Unmarshal()iferr!=nil {
log.Fatal(err)
}
fmt.Printf("%+v", actual)
// Output: {Arr:[1 2 3 4]}
}You can not use the functionality for mapping data into the structure, you can use the interface to get data from the stream (io.ReadSeeker)
typeReaderinterface {
io.ReadSeeker// Peek returns the next n bytes without advancing the reader.Peek(nint) ([]byte, error)
// ReadBytes reads up to n bytes. It returns the number of bytes// read, bytes and any error encountered.ReadBytes(nint) (anint, b []byte, errerror)
// ReadAll reads until an error or EOF and returns the data it read.ReadAll() ([]byte, error)
// ReadByte read and return one byteReadByte() (byte, error)
// ReadBool read one byte and return boolean valueReadBool() (bool, error)
// ReadUint8 read one byte and return uint8 valueReadUint8() (uint8, error)
// ReadUint16 read two bytes and return uint16 valueReadUint16() (uint16, error)
// ReadUint32 read four bytes and return uint32 valueReadUint32() (uint32, error)
// ReadUint64 read eight bytes and return uint64 valueReadUint64() (uint64, error)
// ReadUintX read X bytes and return uint64 valueReadUintX(xint) (uint64, error)
// ReadInt8 read one byte and return int8 valueReadInt8() (int8, error)
// ReadInt16 read two bytes and return int16 valueReadInt16() (int16, error)
// ReadInt32 read four bytes and return int32 valueReadInt32() (int32, error)
// ReadInt64 read eight bytes and return int64 valueReadInt64() (int64, error)
// ReadIntX read X bytes and return int64 valueReadIntX(xint) (int64, error)
// ReadFloat32 read four bytes and return float32 valueReadFloat32() (float32, error)
// ReadFloat64 read eight bytes and return float64 valueReadFloat64() (float64, error)
// Unmarshal parses the binary data and stores the result// in the value pointed to by v.Unmarshal(vinterface{}) error// WithOrder changes the byte order for the new ReaderWithOrder(order binary.ByteOrder) Reader
}Example:
package main
import (
"encoding/binary""fmt""log""github.com/ghostiam/binstruct"
)
funcmain() {
data:= []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}
reader:=binstruct.NewReaderFromBytes(data, binary.BigEndian, false)
i16, err:=reader.ReadInt16()
iferr!=nil {
log.Fatal(err)
}
fmt.Println(i16)
i32, err:=reader.ReadInt32()
iferr!=nil {
log.Fatal(err)
}
fmt.Println(i32)
b, err:=reader.Peek(4)
iferr!=nil {
log.Fatal(err)
}
fmt.Printf("Peek bytes: %#v\n", b)
an, b, err:=reader.ReadBytes(4)
iferr!=nil {
log.Fatal(err)
}
fmt.Printf("Read %d bytes: %#v\n", an, b)
other, err:=reader.ReadAll()
iferr!=nil {
log.Fatal(err)
}
fmt.Printf("Read all: %#v\n", other)
// Output:// 258// 50595078// Peek bytes: []byte{0x7, 0x8, 0x9, 0xa}// Read 4 bytes: []byte{0x7, 0x8, 0x9, 0xa}// Read all: []byte{0xb, 0xc, 0xd, 0xe, 0xf}
}typeteststruct {
// Read 1 byteFieldboolFieldbyteField [1]byteFieldint8Fielduint8// Read 2 bytesFieldint16Fielduint16Field [2]byte// Read 4 bytesFieldint32Fielduint32Field [4]byte// Read 8 bytesFieldint64Fielduint64Field [8]byte// You can override lengthFieldint64`bin:"len:2"`// Or even use very weird byte lengths for intFieldint64`bin:"len:3"`Fieldint64`bin:"len:5"`Fieldint64`bin:"len:7"`// Fields of type int, uint and string are not read automatically // because the size is not known, you need to set it manuallyFieldint`bin:"len:2"`Fielduint`bin:"len:4"`Fieldstring`bin:"len:42"`// Can read arrays and slicesArray [2]int32// read 8 bytes (4+4byte for 2 int32)Slice []int32`bin:"len:2"`// read 8 bytes (4+4byte for 2 int32)// Also two-dimensional slices work (binstruct_test.go:307 Test_SliceOfSlice)Slice2D [][]int32`bin:"len:2,[len:2]"`// and even three-dimensional slices (binstruct_test.go:329 Test_SliceOfSliceOfSlice)Slice3D [][][]int32`bin:"len:2,[len:2,[len:2]]"`// Structures and embedding are also supported.Structstruct {
...
}
OtherStructOtherOther// embedding
}
typeOtherstruct {
...
}typeteststruct {
IgnoredField []byte`bin:"-"`// ignore fieldCallMethod []byte`bin:"MethodName"`// Call method "MethodName"ReadLength []byte`bin:"len:42"`// read 42 bytes// Offsets test binstruct_test.go:9Offsetbyte`bin:"offset:42"`// move to 42 bytes from current position and read byteOffsetStartbyte`bin:"offsetStart:42"`// move to 42 bytes from start position and read byteOffsetEndbyte`bin:"offsetEnd:-42"`// move to -42 bytes from end position and read byteOffsetStartbyte`bin:"offsetStart:42, offset:10"`// also worked and equally `offsetStart:52`OffsetWithRestorebyte`bin:"offset:42, offsetRestore"`// move to 42 bytes from current position and read byte, then restore position to the previous one (before offset)// Calculations supported +,-,/,* and are performed from left to right that is 2+2*2=8 not 6!!!CalcTagValue []byte`bin:"len:10+5+2+3"`// equally len:20// You can refer to another field to get the value.DataLengthint// actual lengthValueFromOtherFieldstring`bin:"len:DataLength"`CalcValueFromOtherFieldstring`bin:"len:DataLength+10"`// also work calculations// Also supported nested structures.Innerstruct {
DataLengthint// actual length for ValueFromInnerField and CalcValueFromInnerField
}
ValueFromInnerFieldstring`bin:"len:Inner.DataLength"`CalcValueFromInnerFieldstring`bin:"len:Inner.DataLength+10"`// You can change the byte order directly from the tagUInt16LEuint16`bin:"le"`UInt16BEuint16`bin:"be"`// Or when you call the method, it will contain the Reader with the byte order you needCallMethodWithLEReaderuint16`bin:"MethodNameWithLEReader,le"`CallMethodWithBEReaderuint16`bin:"be,MethodNameWithBEReader"`
} // Method can be:func (*test) MethodName(r binstruct.Reader) (error) {}
// orfunc (*test) MethodName(r binstruct.Reader) (FieldType, error) {}See the tests and examples for more information.
MIT License