From 0e003c179c422af0f09ef12134291f899f98e96c Mon Sep 17 00:00:00 2001 From: Takahiro YAMASHITA Date: Wed, 19 Aug 2020 12:17:17 +0900 Subject: [PATCH 1/2] support mixed endian Signed-off-by: Takahiro YAMASHITA --- pkg/bit/v2/decode.go | 36 ++++++++++++++++++++++++-- pkg/bit/v2/decode_test.go | 54 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 85 insertions(+), 5 deletions(-) diff --git a/pkg/bit/v2/decode.go b/pkg/bit/v2/decode.go index 87d6d52..618863e 100644 --- a/pkg/bit/v2/decode.go +++ b/pkg/bit/v2/decode.go @@ -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 { @@ -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 } @@ -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) @@ -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) diff --git a/pkg/bit/v2/decode_test.go b/pkg/bit/v2/decode_test.go index 2ce9abc..227a16a 100644 --- a/pkg/bit/v2/decode_test.go +++ b/pkg/bit/v2/decode_test.go @@ -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 @@ -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 From 96d81004b689c3d1a58b5e24cc58637c2c3c024a Mon Sep 17 00:00:00 2001 From: Takahiro YAMASHITA Date: Wed, 19 Aug 2020 12:19:38 +0900 Subject: [PATCH 2/2] support mixed endian Signed-off-by: Takahiro YAMASHITA --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ed35143..e321b32 100644 --- a/README.md +++ b/README.md @@ -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)