1
0
mirror of https://github.com/golang/go synced 2024-11-12 08:10:21 -07:00

encoding/binary: implemented the Write function

The ByteOrder.Put* methods are already available, this change uses
them to implement the Write function.

R=golang-dev, agl1, rsc, r
https://golang.org/cl/152141
This commit is contained in:
Môshe van der Sterre 2009-11-14 14:42:22 -08:00 committed by Russ Cox
parent a09997c3aa
commit a54684f8da
2 changed files with 122 additions and 19 deletions

View File

@ -117,8 +117,8 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
// A fixed-size value is either a fixed-size integer
// (int8, uint8, int16, uint16, ...) or an array or struct
// containing only fixed-size values. Bytes read from
// r are decoded using order and written to successive
// fields of the data.
// r are decoded using the specified byte order and written
// to successive fields of the data.
func Read(r io.Reader, order ByteOrder, data interface{}) os.Error {
v := reflect.NewValue(data).(*reflect.PtrValue).Elem();
size := sizeof(v.Type());
@ -133,6 +133,27 @@ func Read(r io.Reader, order ByteOrder, data interface{}) os.Error {
return nil;
}
// Write writes the binary representation of data into w.
// Data must be a fixed-size value or a pointer to
// a fixed-size value.
// A fixed-size value is either a fixed-size integer
// (int8, uint8, int16, uint16, ...) or an array or struct
// containing only fixed-size values. Bytes written to
// w are encoded using the specified byte order and read
// from successive fields of the data.
func Write(w io.Writer, order ByteOrder, data interface{}) os.Error {
v := reflect.Indirect(reflect.NewValue(data));
size := sizeof(v.Type());
if size < 0 {
return os.NewError("binary.Write: invalid type " + v.Type().String())
}
buf := make([]byte, size);
e := &encoder{order: order, buf: buf};
e.value(v);
_, err := w.Write(buf);
return err;
}
func sizeof(t reflect.Type) int {
switch t := t.(type) {
case *reflect.ArrayType:
@ -182,38 +203,71 @@ type decoder struct {
buf []byte;
}
type encoder struct {
order ByteOrder;
buf []byte;
}
func (d *decoder) uint8() uint8 {
x := d.buf[0];
d.buf = d.buf[1:len(d.buf)];
return x;
}
func (e *encoder) uint8(x uint8) {
e.buf[0] = x;
e.buf = e.buf[1:len(e.buf)];
}
func (d *decoder) uint16() uint16 {
x := d.order.Uint16(d.buf[0:2]);
d.buf = d.buf[2:len(d.buf)];
return x;
}
func (e *encoder) uint16(x uint16) {
e.order.PutUint16(e.buf[0:2], x);
e.buf = e.buf[2:len(e.buf)];
}
func (d *decoder) uint32() uint32 {
x := d.order.Uint32(d.buf[0:4]);
d.buf = d.buf[4:len(d.buf)];
return x;
}
func (e *encoder) uint32(x uint32) {
e.order.PutUint32(e.buf[0:4], x);
e.buf = e.buf[4:len(e.buf)];
}
func (d *decoder) uint64() uint64 {
x := d.order.Uint64(d.buf[0:8]);
d.buf = d.buf[8:len(d.buf)];
return x;
}
func (e *encoder) uint64(x uint64) {
e.order.PutUint64(e.buf[0:8], x);
e.buf = e.buf[8:len(e.buf)];
}
func (d *decoder) int8() int8 { return int8(d.uint8()) }
func (e *encoder) int8(x int8) { e.uint8(uint8(x)) }
func (d *decoder) int16() int16 { return int16(d.uint16()) }
func (e *encoder) int16(x int16) { e.uint16(uint16(x)) }
func (d *decoder) int32() int32 { return int32(d.uint32()) }
func (e *encoder) int32(x int32) { e.uint32(uint32(x)) }
func (d *decoder) int64() int64 { return int64(d.uint64()) }
func (e *encoder) int64(x int64) { e.uint64(uint64(x)) }
func (d *decoder) value(v reflect.Value) {
switch v := v.(type) {
case *reflect.ArrayValue:
@ -249,3 +303,39 @@ func (d *decoder) value(v reflect.Value) {
v.Set(math.Float64frombits(d.uint64()))
}
}
func (e *encoder) value(v reflect.Value) {
switch v := v.(type) {
case *reflect.ArrayValue:
l := v.Len();
for i := 0; i < l; i++ {
e.value(v.Elem(i))
}
case *reflect.StructValue:
l := v.NumField();
for i := 0; i < l; i++ {
e.value(v.Field(i))
}
case *reflect.Uint8Value:
e.uint8(v.Get())
case *reflect.Uint16Value:
e.uint16(v.Get())
case *reflect.Uint32Value:
e.uint32(v.Get())
case *reflect.Uint64Value:
e.uint64(v.Get())
case *reflect.Int8Value:
e.int8(v.Get())
case *reflect.Int16Value:
e.int16(v.Get())
case *reflect.Int32Value:
e.int32(v.Get())
case *reflect.Int64Value:
e.int64(v.Get())
case *reflect.Float32Value:
e.uint32(math.Float32bits(v.Get()))
case *reflect.Float64Value:
e.uint64(math.Float64bits(v.Get()))
}
}

View File

@ -5,6 +5,7 @@
package binary
import (
"os";
"bytes";
"math";
"reflect";
@ -63,24 +64,36 @@ var little = []byte{
39, 40, 41, 42,
}
func TestRead(t *testing.T) {
var sl, sb Struct;
err := Read(bytes.NewBuffer(big), BigEndian, &sb);
func checkResult(t *testing.T, dir string, order, err os.Error, have, want interface{}) {
if err != nil {
t.Errorf("Read big-endian: %v", err);
goto little;
t.Errorf("%v %v: %v", dir, order, err);
return;
}
if !reflect.DeepEqual(sb, s) {
t.Errorf("Read big-endian:\n\thave %+v\n\twant %+v", sb, s)
}
little:
err = Read(bytes.NewBuffer(little), LittleEndian, &sl);
if err != nil {
t.Errorf("Read little-endian: %v", err)
}
if !reflect.DeepEqual(sl, s) {
t.Errorf("Read little-endian:\n\thave %+v\n\twant %+v", sl, s)
if !reflect.DeepEqual(have, want) {
t.Errorf("%v %v:\n\thave %+v\n\twant %+v", dir, order, have, want)
}
}
func testRead(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
var s2 Struct;
err := Read(bytes.NewBuffer(b), order, &s2);
checkResult(t, "Read", order, err, s2, s1);
}
func testWrite(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
buf := new(bytes.Buffer);
err := Write(buf, order, s1);
checkResult(t, "Write", order, err, buf.Bytes(), b);
}
func TestBigEndianRead(t *testing.T) { testRead(t, BigEndian, big, s) }
func TestLittleEndianRead(t *testing.T) { testRead(t, LittleEndian, little, s) }
func TestBigEndianWrite(t *testing.T) { testWrite(t, BigEndian, big, s) }
func TestLittleEndianWrite(t *testing.T) { testWrite(t, LittleEndian, little, s) }
func TestBigEndianPtrWrite(t *testing.T) { testWrite(t, BigEndian, big, &s) }
func TestLittleEndianPtrWrite(t *testing.T) { testWrite(t, LittleEndian, little, &s) }