add int32 and string types to alignedbuff (#195)
This commit is contained in:
parent
d007ae63f1
commit
4f5cd5826f
|
@ -118,6 +118,39 @@ func (a *AlignedBuff) Uint64() (uint64, error) {
|
|||
return v, nil
|
||||
}
|
||||
|
||||
// Int32 unmarshals an int32 in native endianess and alignment. It returns
|
||||
// ErrEOF when trying to read beyond the payload.
|
||||
func (a *AlignedBuff) Int32() (int32, error) {
|
||||
if err := a.alignCheckedRead(int32AlignMask); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
v := binaryutil.Int32(a.data[a.pos : a.pos+4])
|
||||
a.pos += 4
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// String unmarshals a null terminated string
|
||||
func (a *AlignedBuff) String() (string, error) {
|
||||
len := 0
|
||||
for {
|
||||
if a.data[a.pos+len] == 0x00 {
|
||||
break
|
||||
}
|
||||
len++
|
||||
}
|
||||
|
||||
v := binaryutil.String(a.data[a.pos : a.pos+len])
|
||||
a.pos += len
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Unmarshals a string of a given length (for non-null terminated strings)
|
||||
func (a *AlignedBuff) StringWithLength(len int) (string, error) {
|
||||
v := binaryutil.String(a.data[a.pos : a.pos+len])
|
||||
a.pos += len
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Uint unmarshals an uint in native endianess and alignment for the C "unsigned
|
||||
// int" type. It returns ErrEOF when trying to read beyond the payload. Please
|
||||
// note that on 64bit platforms, the size and alignment of C's and Go's unsigned
|
||||
|
@ -190,6 +223,19 @@ func (a *AlignedBuff) PutUint64(v uint64) {
|
|||
a.pos += 8
|
||||
}
|
||||
|
||||
// PutInt32 marshals an int32 in native endianess and alignment.
|
||||
func (a *AlignedBuff) PutInt32(v int32) {
|
||||
a.alignWrite(int32AlignMask)
|
||||
a.data = append(a.data, binaryutil.PutInt32(v)...)
|
||||
a.pos += 4
|
||||
}
|
||||
|
||||
// PutString marshals a string.
|
||||
func (a *AlignedBuff) PutString(v string) {
|
||||
a.data = append(a.data, binaryutil.PutString(v)...)
|
||||
a.pos += len(v)
|
||||
}
|
||||
|
||||
// PutUint marshals an uint in native endianess and alignment for the C
|
||||
// "unsigned int" type. Please note that on 64bit platforms, the size and
|
||||
// alignment of C's and Go's unsigned integer data types differ, so we
|
||||
|
@ -236,5 +282,7 @@ var uint32AlignMask = int(unsafe.Alignof(uint32(0)) - 1)
|
|||
var uint64AlignMask = int(unsafe.Alignof(uint64(0)) - 1)
|
||||
var padding = bytes.Repeat([]byte{0}, uint64AlignMask)
|
||||
|
||||
var int32AlignMask = int(unsafe.Alignof(int32(0)) - 1)
|
||||
|
||||
// And this even worse.
|
||||
var uintSize = unsafe.Sizeof(uint32(0))
|
||||
|
|
|
@ -20,6 +20,9 @@ func TestAlignmentData(t *testing.T) {
|
|||
if uintSize == 0 {
|
||||
t.Fatal("zero uint size")
|
||||
}
|
||||
if int32AlignMask == 0 {
|
||||
t.Fatal("zero uint32 alignment mask")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlignedBuff8(t *testing.T) {
|
||||
|
@ -202,3 +205,114 @@ func TestAlignedUint(t *testing.T) {
|
|||
t.Fatalf("sentinel read failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlignedBuffInt32(t *testing.T) {
|
||||
b0 := New()
|
||||
b0.PutUint8(0x42)
|
||||
b0.PutInt32(0x12345678)
|
||||
b0.PutInt32(0x01cecafe)
|
||||
|
||||
b := NewWithData(b0.data)
|
||||
|
||||
if len(b0.Data()) != 4*4 {
|
||||
t.Fatalf("alignment padding failed")
|
||||
}
|
||||
|
||||
v, err := b.Uint8()
|
||||
if v != 0x42 || err != nil {
|
||||
t.Fatalf("unaligment read failed")
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
v int32
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "first read",
|
||||
v: 0x12345678,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "second read",
|
||||
v: 0x01cecafe,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "end of buffer",
|
||||
v: 0,
|
||||
err: ErrEOF,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
v, err := b.Int32()
|
||||
if v != tt.v || err != tt.err {
|
||||
t.Errorf("expected: %#v %#v, got: %#v, %#v",
|
||||
tt.v, tt.err, v, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlignedBuffPutNullTerminatedString(t *testing.T) {
|
||||
b0 := New()
|
||||
b0.PutUint8(0x42)
|
||||
b0.PutString("test" + "\x00")
|
||||
|
||||
b := NewWithData(b0.data)
|
||||
|
||||
v, err := b.Uint8()
|
||||
if v != 0x42 || err != nil {
|
||||
t.Fatalf("unaligment read failed")
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
v string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "first read",
|
||||
v: "test",
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
v, err := b.String()
|
||||
if v != tt.v || err != tt.err {
|
||||
t.Errorf("expected: %#v %#v, got: %#v, %#v",
|
||||
tt.v, tt.err, v, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlignedBuffPutString(t *testing.T) {
|
||||
b0 := New()
|
||||
b0.PutUint8(0x42)
|
||||
b0.PutString("test")
|
||||
|
||||
b := NewWithData(b0.data)
|
||||
|
||||
v, err := b.Uint8()
|
||||
if v != 0x42 || err != nil {
|
||||
t.Fatalf("unaligment read failed")
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
v string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "first read",
|
||||
v: "test",
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
v, err := b.StringWithLength(len("test"))
|
||||
if v != tt.v || err != tt.err {
|
||||
t.Errorf("expected: %#v %#v, got: %#v, %#v",
|
||||
tt.v, tt.err, v, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package binaryutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"unsafe"
|
||||
)
|
||||
|
@ -102,3 +103,23 @@ func (bigEndian) Uint32(b []byte) uint32 {
|
|||
func (bigEndian) Uint64(b []byte) uint64 {
|
||||
return binary.BigEndian.Uint64(b)
|
||||
}
|
||||
|
||||
// For dealing with types not supported by the encoding/binary interface
|
||||
|
||||
func PutInt32(v int32) []byte {
|
||||
buf := make([]byte, 4)
|
||||
*(*int32)(unsafe.Pointer(&buf[0])) = v
|
||||
return buf
|
||||
}
|
||||
|
||||
func Int32(b []byte) int32 {
|
||||
return *(*int32)(unsafe.Pointer(&b[0]))
|
||||
}
|
||||
|
||||
func PutString(s string) []byte {
|
||||
return []byte(s)
|
||||
}
|
||||
|
||||
func String(b []byte) string {
|
||||
return string(bytes.TrimRight(b, "\x00"))
|
||||
}
|
||||
|
|
|
@ -107,3 +107,36 @@ func TestBigEndian(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOtherTypes(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
expected []byte
|
||||
expectedv interface{}
|
||||
actual []byte
|
||||
unmarshal func(b []byte) interface{}
|
||||
}{
|
||||
{
|
||||
name: "Int32",
|
||||
expected: []byte{0x78, 0x56, 0x34, 0x12},
|
||||
expectedv: int32(0x12345678),
|
||||
actual: PutInt32(0x12345678),
|
||||
unmarshal: func(b []byte) interface{} { return Int32(b) },
|
||||
},
|
||||
{
|
||||
name: "String",
|
||||
expected: []byte{0x74, 0x65, 0x73, 0x74},
|
||||
expectedv: "test",
|
||||
actual: PutString("test"),
|
||||
unmarshal: func(b []byte) interface{} { return String(b) },
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if bytes.Compare(tt.actual, tt.expected) != 0 {
|
||||
t.Errorf("Put%s failure, expected: %#v, got: %#v", tt.name, tt.expected, tt.actual)
|
||||
}
|
||||
if actual := tt.unmarshal(tt.actual); !reflect.DeepEqual(actual, tt.expectedv) {
|
||||
t.Errorf("%s failure, expected: %#v, got: %#v", tt.name, tt.expectedv, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue