Commit a54684f8 authored by Môshe van der Sterre's avatar Môshe van der Sterre Committed by Russ Cox

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
parent a09997c3
...@@ -117,8 +117,8 @@ func (bigEndian) GoString() string { return "binary.BigEndian" } ...@@ -117,8 +117,8 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
// A fixed-size value is either a fixed-size integer // A fixed-size value is either a fixed-size integer
// (int8, uint8, int16, uint16, ...) or an array or struct // (int8, uint8, int16, uint16, ...) or an array or struct
// containing only fixed-size values. Bytes read from // containing only fixed-size values. Bytes read from
// r are decoded using order and written to successive // r are decoded using the specified byte order and written
// fields of the data. // to successive fields of the data.
func Read(r io.Reader, order ByteOrder, data interface{}) os.Error { func Read(r io.Reader, order ByteOrder, data interface{}) os.Error {
v := reflect.NewValue(data).(*reflect.PtrValue).Elem(); v := reflect.NewValue(data).(*reflect.PtrValue).Elem();
size := sizeof(v.Type()); size := sizeof(v.Type());
...@@ -133,6 +133,27 @@ func Read(r io.Reader, order ByteOrder, data interface{}) os.Error { ...@@ -133,6 +133,27 @@ func Read(r io.Reader, order ByteOrder, data interface{}) os.Error {
return nil; 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 { func sizeof(t reflect.Type) int {
switch t := t.(type) { switch t := t.(type) {
case *reflect.ArrayType: case *reflect.ArrayType:
...@@ -182,38 +203,71 @@ type decoder struct { ...@@ -182,38 +203,71 @@ type decoder struct {
buf []byte; buf []byte;
} }
type encoder struct {
order ByteOrder;
buf []byte;
}
func (d *decoder) uint8() uint8 { func (d *decoder) uint8() uint8 {
x := d.buf[0]; x := d.buf[0];
d.buf = d.buf[1:len(d.buf)]; d.buf = d.buf[1:len(d.buf)];
return x; 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 { func (d *decoder) uint16() uint16 {
x := d.order.Uint16(d.buf[0:2]); x := d.order.Uint16(d.buf[0:2]);
d.buf = d.buf[2:len(d.buf)]; d.buf = d.buf[2:len(d.buf)];
return x; 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 { func (d *decoder) uint32() uint32 {
x := d.order.Uint32(d.buf[0:4]); x := d.order.Uint32(d.buf[0:4]);
d.buf = d.buf[4:len(d.buf)]; d.buf = d.buf[4:len(d.buf)];
return x; 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 { func (d *decoder) uint64() uint64 {
x := d.order.Uint64(d.buf[0:8]); x := d.order.Uint64(d.buf[0:8]);
d.buf = d.buf[8:len(d.buf)]; d.buf = d.buf[8:len(d.buf)];
return x; 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 (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 (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 (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 (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) { func (d *decoder) value(v reflect.Value) {
switch v := v.(type) { switch v := v.(type) {
case *reflect.ArrayValue: case *reflect.ArrayValue:
...@@ -249,3 +303,39 @@ func (d *decoder) value(v reflect.Value) { ...@@ -249,3 +303,39 @@ func (d *decoder) value(v reflect.Value) {
v.Set(math.Float64frombits(d.uint64())) 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()))
}
}
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package binary package binary
import ( import (
"os";
"bytes"; "bytes";
"math"; "math";
"reflect"; "reflect";
...@@ -63,24 +64,36 @@ var little = []byte{ ...@@ -63,24 +64,36 @@ var little = []byte{
39, 40, 41, 42, 39, 40, 41, 42,
} }
func TestRead(t *testing.T) { func checkResult(t *testing.T, dir string, order, err os.Error, have, want interface{}) {
var sl, sb Struct;
err := Read(bytes.NewBuffer(big), BigEndian, &sb);
if err != nil { if err != nil {
t.Errorf("Read big-endian: %v", err); t.Errorf("%v %v: %v", dir, order, err);
goto little; return;
} }
if !reflect.DeepEqual(sb, s) { if !reflect.DeepEqual(have, want) {
t.Errorf("Read big-endian:\n\thave %+v\n\twant %+v", sb, s) t.Errorf("%v %v:\n\thave %+v\n\twant %+v", dir, order, have, want)
} }
}
little: func testRead(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
err = Read(bytes.NewBuffer(little), LittleEndian, &sl); var s2 Struct;
if err != nil { err := Read(bytes.NewBuffer(b), order, &s2);
t.Errorf("Read little-endian: %v", err) checkResult(t, "Read", order, err, s2, s1);
} }
if !reflect.DeepEqual(sl, s) {
t.Errorf("Read little-endian:\n\thave %+v\n\twant %+v", sl, s) 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) }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment