package gob
import (
+ "bufio"
"bytes"
"io"
"os"
wireType map[typeId]*wireType // map from remote ID to local description
decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
ignorerCache map[typeId]**decEngine // ditto for ignored objects
- countState *decodeState // reads counts from wire
+ freeList *decoderState // list of free decoderStates; avoids reallocation
countBuf []byte // used for decoding integers while parsing messages
tmp []byte // temporary storage for i/o; saves reallocating
err os.Error
}
// NewDecoder returns a new decoder that reads from the io.Reader.
+// If r does not also implement io.ByteReader, it will be wrapped in a
+// bufio.Reader.
func NewDecoder(r io.Reader) *Decoder {
dec := new(Decoder)
+ // We use the ability to read bytes as a plausible surrogate for buffering.
+ if _, ok := r.(io.ByteReader); !ok {
+ r = bufio.NewReader(r)
+ }
dec.r = r
dec.wireType = make(map[typeId]*wireType)
dec.decoderCache = make(map[reflect.Type]map[typeId]**decEngine)
func (dec *Decoder) recvType(id typeId) {
// Have we already seen this type? That's an error
if id < firstUserId || dec.wireType[id] != nil {
- dec.err = os.ErrorString("gob: duplicate type received")
+ dec.err = os.NewError("gob: duplicate type received")
return
}
// Type:
wire := new(wireType)
- dec.err = dec.decodeValue(tWireType, reflect.NewValue(wire))
+ dec.decodeValue(tWireType, reflect.ValueOf(wire))
if dec.err != nil {
return
}
dec.wireType[id] = wire
}
+var errBadCount = os.NewError("invalid message length")
+
// recvMessage reads the next count-delimited item from the input. It is the converse
// of Encoder.writeMessage. It returns false on EOF or other error reading the message.
func (dec *Decoder) recvMessage() bool {
dec.err = err
return false
}
+ if nbytes >= 1<<31 {
+ dec.err = errBadCount
+ return false
+ }
dec.readMessage(int(nbytes))
return dec.err == nil
}
// will be absorbed by recvMessage.)
if dec.buf.Len() > 0 {
if !isInterface {
- dec.err = os.ErrorString("extra data in buffer")
+ dec.err = os.NewError("extra data in buffer")
break
}
dec.nextUint()
// Decode reads the next value from the connection and stores
// it in the data represented by the empty interface value.
// If e is nil, the value will be discarded. Otherwise,
-// the value underlying e must either be the correct type for the next
-// data item received, and must be a pointer.
+// the value underlying e must be a pointer to the
+// correct type for the next data item received.
func (dec *Decoder) Decode(e interface{}) os.Error {
if e == nil {
- return dec.DecodeValue(nil)
+ return dec.DecodeValue(reflect.Value{})
}
- value := reflect.NewValue(e)
+ value := reflect.ValueOf(e)
// If e represents a value as opposed to a pointer, the answer won't
// get back to the caller. Make sure it's a pointer.
if value.Type().Kind() != reflect.Ptr {
- dec.err = os.ErrorString("gob: attempt to decode into a non-pointer")
+ dec.err = os.NewError("gob: attempt to decode into a non-pointer")
return dec.err
}
return dec.DecodeValue(value)
}
-// DecodeValue reads the next value from the connection and stores
-// it in the data represented by the reflection value.
-// The value must be the correct type for the next
-// data item received, or it may be nil, which means the
-// value will be discarded.
-func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
+// DecodeValue reads the next value from the connection.
+// If v is the zero reflect.Value (v.Kind() == Invalid), DecodeValue discards the value.
+// Otherwise, it stores the value into v. In that case, v must represent
+// a non-nil pointer to data or be an assignable reflect.Value (v.CanSet())
+func (dec *Decoder) DecodeValue(v reflect.Value) os.Error {
+ if v.IsValid() {
+ if v.Kind() == reflect.Ptr && !v.IsNil() {
+ // That's okay, we'll store through the pointer.
+ } else if !v.CanSet() {
+ return os.NewError("gob: DecodeValue of unassignable value")
+ }
+ }
// Make sure we're single-threaded through here.
dec.mutex.Lock()
defer dec.mutex.Unlock()
dec.err = nil
id := dec.decodeTypeSequence(false)
if dec.err == nil {
- dec.err = dec.decodeValue(id, value)
+ dec.decodeValue(id, v)
}
return dec.err
}