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 gobimport ()// 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 atomicallyr io.Reader // source of the databuf decBuffer // buffer for more efficient i/o from rwireType map[typeId]*wireType // map from remote ID to local descriptiondecoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled enginesignorerCache map[typeId]**decEngine // ditto for ignored objectsfreeList *decoderState // list of free decoderStates; avoids reallocationcountBuf []byte // used for decoding integers while parsing messageserr error// ignoreDepth tracks the depth of recursively parsed ignored fieldsignoreDepth int}// 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 bytesreturn}// recvType loads the definition of a type.func ( *Decoder) ( typeId) {// Have we already seen this type? That's an errorif < 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 = errBadCountreturn 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 datavar []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 {:= truefor .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 .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.9-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. |