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
|
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
|
// 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
|
// 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
|
// 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
|
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
|
// PutUint marshals an uint in native endianess and alignment for the C
|
||||||
// "unsigned int" type. Please note that on 64bit platforms, the size and
|
// "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
|
// 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 uint64AlignMask = int(unsafe.Alignof(uint64(0)) - 1)
|
||||||
var padding = bytes.Repeat([]byte{0}, uint64AlignMask)
|
var padding = bytes.Repeat([]byte{0}, uint64AlignMask)
|
||||||
|
|
||||||
|
var int32AlignMask = int(unsafe.Alignof(int32(0)) - 1)
|
||||||
|
|
||||||
// And this even worse.
|
// And this even worse.
|
||||||
var uintSize = unsafe.Sizeof(uint32(0))
|
var uintSize = unsafe.Sizeof(uint32(0))
|
||||||
|
|
|
@ -20,6 +20,9 @@ func TestAlignmentData(t *testing.T) {
|
||||||
if uintSize == 0 {
|
if uintSize == 0 {
|
||||||
t.Fatal("zero uint size")
|
t.Fatal("zero uint size")
|
||||||
}
|
}
|
||||||
|
if int32AlignMask == 0 {
|
||||||
|
t.Fatal("zero uint32 alignment mask")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAlignedBuff8(t *testing.T) {
|
func TestAlignedBuff8(t *testing.T) {
|
||||||
|
@ -202,3 +205,114 @@ func TestAlignedUint(t *testing.T) {
|
||||||
t.Fatalf("sentinel read failed")
|
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
|
package binaryutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
@ -102,3 +103,23 @@ func (bigEndian) Uint32(b []byte) uint32 {
|
||||||
func (bigEndian) Uint64(b []byte) uint64 {
|
func (bigEndian) Uint64(b []byte) uint64 {
|
||||||
return binary.BigEndian.Uint64(b)
|
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