Skip to content

Commit

Permalink
Merge pull request #8 from nokute78/mixedendian
Browse files Browse the repository at this point in the history
support mixed endian
  • Loading branch information
nokute78 authored Aug 19, 2020
2 parents a093d9a + 96d8100 commit a7b69ea
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 6 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ The package supports struct tags.
|Tag|Description|
|---|-----------|
|`` `bit:"skip"` ``|Ignore the field. Offset is updated by the size of the field. It is useful for reserved field.|
|`` `bit:"-"` ``|Ignore the field. Offset is not updated.|
|`` `bit:"-"` `` |Ignore the field. Offset is not updated.|
|`` `bit:"BE"` ``|Decode the field as big endian. It is useful for mixed endian data.|
|`` `bit:"LE"` ``|Decode the field as little endian. It is useful for mixed endian data.|

## Tool
* [readbit](cmd/readbit/README.md)
Expand Down
36 changes: 34 additions & 2 deletions pkg/bit/v2/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ const (
// tagConfig represents StructTag.
// "-" : ignore the field
// "skip": ignore but offset will be updated
// "BE" : the field is treated as big endian
// "LE" : the field is treated as little endian
type tagConfig struct {
ignore bool
skip bool
endian binary.ByteOrder
}

func parseStructTag(t reflect.StructTag) *tagConfig {
Expand All @@ -52,7 +55,12 @@ func parseStructTag(t reflect.StructTag) *tagConfig {
case "skip":
ret.skip = true
return ret
case "BE":
ret.endian = binary.BigEndian
case "LE":
ret.endian = binary.LittleEndian
}

}
return ret
}
Expand Down Expand Up @@ -171,9 +179,27 @@ func fillData(b []byte, order binary.ByteOrder, v reflect.Value, o *Offset) erro
if err != nil {
return err
}

return nil

} else if v.Index(0).Kind() == reflect.Uint8 {
ret, err := GetBitsAsByte(b, *o, uint64(v.Len()*8), binary.LittleEndian)
if err != nil {
return err
}
for i := 0; i < v.Len(); i++ {
if v.Index(i).CanSet() {
if order == binary.BigEndian {
// workaround! binary.Read doesn't support []byte in BigEndian
v.Index(i).Set(reflect.ValueOf(ret[v.Len()-1-i]))
} else {
v.Index(i).Set(reflect.ValueOf(ret[i]))
}
}
}
*o, err = o.AddOffset(Offset{Byte: uint64(v.Len())})
if err != nil {
return err
}
return nil
} else {
for i := 0; i < v.Len(); i++ {
err := fillData(b, order, v.Index(i), o)
Expand Down Expand Up @@ -201,6 +227,12 @@ func fillData(b []byte, order binary.ByteOrder, v reflect.Value, o *Offset) erro
return err
}
continue
} else if cnf.endian != nil {
err := fillData(b, cnf.endian, v.Field(i), o)
if err != nil {
return err
}
continue
}
}
err := fillData(b, order, v.Field(i), o)
Expand Down
54 changes: 51 additions & 3 deletions pkg/bit/v2/decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,20 @@ func TestStructTag(t *testing.T) {
}
}

func TestReadArray(t *testing.T) {
input := bytes.NewBuffer([]byte{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff})
var b [6]byte

if err := bit.Read(input, binary.BigEndian, &b); err != nil {
t.Fatalf("bit.Read:%s", err)
}

expect := []byte{0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa}
if bytes.Compare(b[:], expect) != 0 {
t.Fatalf("mismatch: given=%x expect=%x", b, expect)
}
}

func TestReadBigEndian(t *testing.T) {
type TcpHeader struct {
SrcPort uint16
Expand Down Expand Up @@ -255,20 +269,54 @@ func TestReadBigEndian(t *testing.T) {
if s.DstPort != 0x1bb {
t.Errorf("DstPort:given=0x%x expect=0x%x", s.DstPort, 0x1bb)
}
/* TODO:

if !s.ACK {
t.Errorf("ACK is false")
}

if s.HeaderLen[0] || !s.HeaderLen[1] || s.HeaderLen[2] || !s.HeaderLen[3] {
if !s.HeaderLen[0] || s.HeaderLen[1] || !s.HeaderLen[2] || s.HeaderLen[3] {
t.Errorf("HeaderLength is not 5. %v\n", s.HeaderLen)
}
*/
if s.CheckSum != 0x0ec1 {
t.Errorf("CheckSum:given=0x%x expect=0x%x", s.CheckSum, 0x1018)
}
}

func TestMixedEndian(t *testing.T) {
type Data struct {
F1 uint32
F2 uint16
F3 uint16
F4 uint16 `bit:"BE"`
F5 [6]byte `bit:"BE"`
}

d := Data{}
b := bytes.NewBuffer([]byte{0x57, 0xab, 0xdf, 0x5d, 0xa1, 0xdf, 0xaa, 0x4e, 0x96, 0xb5, 0x3a, 0x5f, 0xe7, 0x66, 0x92, 0x65})
if err := bit.Read(b, binary.LittleEndian, &d); err != nil {
t.Fatalf("bit.Read:%s", err)
}

if d.F1 != 0x5ddfab57 {
t.Errorf("F1 mismatch:given=0x%x expect=0x%x", d.F1, 0x5ddfab57)
}
if d.F2 != 0xdfa1 {
t.Errorf("F2 mismatch:given=0x%x expect=0x%x", d.F2, 0xdfa1)
}
if d.F3 != 0x4eaa {
t.Errorf("F3 mismatch:given=0x%x expect=0x%x", d.F3, 0x4eaa)
}

if d.F4 != 0x96b5 {
t.Errorf("F4 mismatch:given=0x%x expect=0x%x", d.F4, 0x96b5)
}

expect := []byte{0x65, 0x92, 0x66, 0xe7, 0x5f, 0x3a}
if bytes.Compare(d.F5[:], expect) != 0 {
t.Errorf("F5 mismatch:given=%x expect=%x", d.F5, expect)
}
}

func BenchmarkReadStruct(b *testing.B) {
type Sample struct {
Header byte
Expand Down

0 comments on commit a7b69ea

Please sign in to comment.