Source File
decoder.go
Belonging Package
encoding/gob
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gob
import (
)
// tooBig provides a sanity check for sizes; used in several places. Upper limit
// of is 1GB on 32-bit systems, 8GB on 64-bit, allowing room to grow a little
// without overflow.
const tooBig = (1 << 30) << (^uint(0) >> 62)
// A Decoder manages the receipt of type and data information read from the
// remote side of a connection. It is safe for concurrent use by multiple
// goroutines.
//
// The Decoder does only basic sanity checking on decoded input sizes,
// and its limits are not configurable. Take caution when decoding gob data
// from untrusted sources.
type Decoder struct {
mutex sync.Mutex // each item must be received atomically
r io.Reader // source of the data
buf decBuffer // buffer for more efficient i/o from r
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
freeList *decoderState // list of free decoderStates; avoids reallocation
countBuf []byte // used for decoding integers while parsing messages
err 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 ( io.Reader) *Decoder {
:= new(Decoder)
// We use the ability to read bytes as a plausible surrogate for buffering.
if , := .(io.ByteReader); ! {
= bufio.NewReader()
}
.r =
.wireType = make(map[typeId]*wireType)
.decoderCache = make(map[reflect.Type]map[typeId]**decEngine)
.ignorerCache = make(map[typeId]**decEngine)
.countBuf = make([]byte, 9) // counts may be uint64s (unlikely!), require 9 bytes
return
}
// recvType loads the definition of a type.
func ( *Decoder) ( typeId) {
// Have we already seen this type? That's an error
if < firstUserId || .wireType[] != nil {
.err = errors.New("gob: duplicate type received")
return
}
// Type:
:= new(wireType)
.decodeValue(tWireType, reflect.ValueOf())
if .err != nil {
return
}
// Remember we've seen this type.
.wireType[] =
}
var errBadCount = errors.New("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 ( *Decoder) () bool {
// Read a count.
, , := decodeUintReader(.r, .countBuf)
if != nil {
.err =
return false
}
if >= tooBig {
.err = errBadCount
return false
}
.readMessage(int())
return .err == nil
}
// readMessage reads the next nbytes bytes from the input.
func ( *Decoder) ( int) {
if .buf.Len() != 0 {
// The buffer should always be empty now.
panic("non-empty decoder buffer")
}
// Read the data
var []byte
, .err = saferio.ReadData(.r, uint64())
.buf.SetBytes()
if .err == io.EOF {
.err = io.ErrUnexpectedEOF
}
}
// toInt turns an encoded uint64 into an int, according to the marshaling rules.
func toInt( uint64) int64 {
:= int64( >> 1)
if &1 != 0 {
= ^
}
return
}
func ( *Decoder) () int64 {
, , := decodeUintReader(&.buf, .countBuf)
if != nil {
.err =
}
return toInt()
}
func ( *Decoder) () uint64 {
, , := decodeUintReader(&.buf, .countBuf)
if != nil {
.err =
}
return
}
// decodeTypeSequence parses:
// TypeSequence
//
// (TypeDefinition DelimitedTypeDefinition*)?
//
// and returns the type id of the next value. It returns -1 at
// EOF. Upon return, the remainder of dec.buf is the value to be
// decoded. If this is an interface value, it can be ignored by
// resetting that buffer.
func ( *Decoder) ( bool) typeId {
:= true
for .err == nil {
if .buf.Len() == 0 {
if !.recvMessage() {
// We can only return io.EOF if the input was empty.
// If we read one or more type spec messages,
// require a data item message to follow.
// If we hit an EOF before that, then give ErrUnexpectedEOF.
if ! && .err == io.EOF {
.err = io.ErrUnexpectedEOF
}
break
}
}
// Receive a type id.
:= typeId(.nextInt())
if >= 0 {
// Value follows.
return
}
// Type definition for (-id) follows.
.recvType(-)
if .err != nil {
break
}
// When decoding an interface, after a type there may be a
// DelimitedValue still in the buffer. Skip its count.
// (Alternatively, the buffer is empty and the byte count
// will be absorbed by recvMessage.)
if .buf.Len() > 0 {
if ! {
.err = errors.New("extra data in buffer")
break
}
.nextUint()
}
= false
}
return -1
}
// Decode reads the next value from the input stream 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 be a pointer to the
// correct type for the next data item received.
// If the input is at EOF, Decode returns [io.EOF] and
// does not modify e.
func ( *Decoder) ( any) error {
if == nil {
return .DecodeValue(reflect.Value{})
}
:= reflect.ValueOf()
// 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 .Type().Kind() != reflect.Pointer {
.err = errors.New("gob: attempt to decode into a non-pointer")
return .err
}
return .DecodeValue()
}
// DecodeValue reads the next value from the input stream.
// 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())
// If the input is at EOF, DecodeValue returns [io.EOF] and
// does not modify v.
func ( *Decoder) ( reflect.Value) error {
if .IsValid() {
if .Kind() == reflect.Pointer && !.IsNil() {
// That's okay, we'll store through the pointer.
} else if !.CanSet() {
return errors.New("gob: DecodeValue of unassignable value")
}
}
// Make sure we're single-threaded through here.
.mutex.Lock()
defer .mutex.Unlock()
.buf.Reset() // In case data lingers from previous invocation.
.err = nil
:= .decodeTypeSequence(false)
if .err == nil {
.decodeValue(, )
}
return .err
}
// If debug.go is compiled into the program, debugFunc prints a human-readable
// representation of the gob data read from r by calling that file's Debug function.
// Otherwise it is nil.
var debugFunc func(io.Reader)
The pages are generated with Golds v0.7.0-preview. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |