package msgp import ( "fmt" "github.com/philhofer/fwd" "io" "math" "sync" "time" ) var _ = fmt.Printf // everything generallly needed to be Serializable/Unserializable type Serz interface { Unmarshaler Decodable Marshaler Encodable Sizer } // PreSave will be called before EncodeMsg/MarshalMsg // if your struct implements it. type PreSave interface { // PreSaveHook is called before msgp.MarshalMsg // and msgp.EncodeMsg. It allows you to prep // the struct for serialization. See // PostLoadHook for the complimentary hook // called after deserialization. PreSaveHook() } // PostLoad will be called after DecodeMsg/UnmarshalMsg, // if your struct implements it. type PostLoad interface { // PostLoadHook is called after // msgp.UnmarshalMsg and msgp.DecodeMsg. // The opposite of PreSaveHook, it allows // one to add a custom finishing step // after basic deserialization has // completed. PostLoadHook() } type ConcreteFactory interface { NewValueAsInterface(zid int64, typename string) interface{} } // where we keep old *Readers var readerPool = sync.Pool{New: func() interface{} { return &Reader{} }} // Type is a MessagePack wire type, // including this package's built-in // extension types. type Type byte // MessagePack Types // // The zero value of Type // is InvalidType. const ( InvalidType Type = iota // MessagePack built-in types StrType BinType MapType ArrayType Float64Type Float32Type BoolType IntType UintType NilType ExtensionType // pseudo-types provided // by extensions Complex64Type Complex128Type TimeType DurationType _maxtype ) // String implements fmt.Stringer func (t Type) String() string { switch t { case StrType: return "str" case BinType: return "bin" case MapType: return "map" case ArrayType: return "array" case Float64Type: return "float64" case Float32Type: return "float32" case BoolType: return "bool" case UintType: return "uint" case IntType: return "int" case ExtensionType: return "ext" case NilType: return "nil" default: return "" } } func freeR(m *Reader) { readerPool.Put(m) } // Unmarshaler is the interface fulfilled // by objects that know how to unmarshal // themselves from MessagePack. // UnmarshalMsg unmarshals the object // from binary, returing any leftover // bytes and any errors encountered. type Unmarshaler interface { UnmarshalMsg([]byte) ([]byte, error) } // Decodable is the interface fulfilled // by objects that know how to read // themselves from a *Reader. type Decodable interface { DecodeMsg(*Reader) error } // Decode decodes 'd' from 'r'. func Decode(r io.Reader, d Decodable) error { rd := NewReader(r) err := d.DecodeMsg(rd) freeR(rd) return err } // NewReader returns a *Reader that // reads from the provided reader. The // reader will be buffered. func NewReader(r io.Reader) *Reader { p := readerPool.Get().(*Reader) if p.R == nil { p.R = fwd.NewReader(r) } else { p.R.Reset(r) p.DedupReset() } return p } // NewReaderSize returns a *Reader with a buffer of the given size. // (This is vastly preferable to passing the decoder a reader that is already buffered.) func NewReaderSize(r io.Reader, sz int) *Reader { return &Reader{R: fwd.NewReaderSize(r, sz)} } // Reader wraps an io.Reader and provides // methods to read MessagePack-encoded values // from it. Readers are buffered. type Reader struct { // R is the buffered reader // that the Reader uses // to decode MessagePack. // The Reader itself // is stateless; all the // buffering is done // within R. R *fwd.Reader scratch []byte NilTracker dedupPointers []interface{} } // NilTracker maintains a stack to assit // DecodeMsg methods when deserializing // from nil fields. type NilTracker struct { // simulate getting nils on the wire AlwaysNil bool LifoAlwaysNil []bool } // AlwaysNilString returns a string representation // of the internal state of the stack for // debugging purposes. func (r *NilTracker) AlwaysNilString() string { s := "bottom: " for _, v := range r.LifoAlwaysNil { if v { s += "T" } else { s += "f" } } return s } // PushAlwaysNil will set r.AlwaysNil to true // and store the previous value of r.AlwaysNil // on the internal stack. func (r *NilTracker) PushAlwaysNil() { // save current state r.LifoAlwaysNil = append(r.LifoAlwaysNil, r.AlwaysNil) // set reader r to always return nils r.AlwaysNil = true } // PopAlwaysNil pops the last entry off the // internal stack and uses it to set // r.AlwaysNil. func (r *NilTracker) PopAlwaysNil() { n := len(r.LifoAlwaysNil) //fmt.Printf("\n Reader.PopAlwaysNil() called! qlen = %d, '%s'\n", // n, r.AlwaysNilString()) if n == 0 { panic("PopAlwaysNil called on empty lifo") return } a := r.LifoAlwaysNil[n-1] r.LifoAlwaysNil = r.LifoAlwaysNil[:n-1] r.AlwaysNil = a } // Read implements `io.Reader` func (m *Reader) Read(p []byte) (int, error) { if m.AlwaysNil { return 0, nil } return m.R.Read(p) } // ReadFull implements `io.ReadFull` func (m *Reader) ReadFull(p []byte) (int, error) { if m.AlwaysNil { return 0, nil } return m.R.ReadFull(p) } // Reset resets the underlying reader. func (m *Reader) Reset(r io.Reader) { m.R.Reset(r) } // Buffered returns the number of bytes currently in the read buffer. func (m *Reader) Buffered() int { return m.R.Buffered() } // BufferSize returns the capacity of the read buffer. func (m *Reader) BufferSize() int { return m.R.BufferSize() } // NextStructName inspects the next time, assuming it is a // struct (map) for its (-1: name) key-value pair, and returns the name // or empty string if not found. Also empty string if not // a map type. func (m *Reader) NextStructName() string { ty, err := m.NextType() if err != nil { return "" } if ty != MapType { return "" } // map header can be of varying size hdsz := 1 var p []byte var lead byte p, err = m.R.Peek(2) if err != nil { return "" } lead = p[0] if isfixmap(lead) { hdsz = 1 } else { switch lead { case mmap16: hdsz = 3 case mmap32: hdsz = 5 default: //err = badPrefix(MapType, lead) return "" } } // now we've got the map header out of the // way in hdsz bytes p, err = m.R.Peek(hdsz + 3) if err != nil { return "" } keystart := p[hdsz:] if keystart[0] != 0xa1 || keystart[1] != 0x40 { return "" // not the "@" key with value the struct name } valstart := hdsz + 2 valTypeBytes := 1 skip := valstart + valTypeBytes lead = p[valstart] var read int if isfixstr(lead) { // lead is a fixstr, good read = int(rfixstr(lead)) } else { switch lead { case mstr8, mbin8: valTypeBytes = 2 skip = valstart + valTypeBytes p, err = m.R.Peek(skip) if err != nil { return "" } read = int(p[valstart+1]) case mstr16, mbin16: valTypeBytes = 3 skip = valstart + valTypeBytes p, err = m.R.Peek(skip) if err != nil { return "" } read = int(big.Uint16(p[valstart+1:])) case mstr32, mbin32: valTypeBytes = 5 skip = valstart + valTypeBytes p, err = m.R.Peek(skip) if err != nil { return "" } read = int(big.Uint32(p[valstart+1:])) default: return "" // not a string } } // read string strictly through peaking! if read == 0 { return "" } p, err = m.R.Peek(skip + read) if err != nil { return "" } //_, _ = m.R.Skip(skip + read) return string(p[skip:]) } // NextType returns the next object type to be decoded. func (m *Reader) NextType() (Type, error) { if m.AlwaysNil { return NilType, nil } p, err := m.R.Peek(1) if err != nil { return InvalidType, err } t := getType(p[0]) if t == InvalidType { return t, InvalidPrefixError(p[0]) } if t == ExtensionType { v, err := m.peekExtensionType() if err != nil { return InvalidType, err } switch v { case Complex64Extension: return Complex64Type, nil case Complex128Extension: return Complex128Type, nil case TimeExtension: return TimeType, nil case DurationExtension: return DurationType, nil } } return t, nil } // IsNil returns whether or not // the next byte is a null messagepack byte func (m *Reader) IsNil() bool { if m.AlwaysNil { return true } p, err := m.R.Peek(1) return err == nil && p[0] == mnil } func (m *Reader) peekNil() bool { p, err := m.R.Peek(1) return err == nil && p[0] == mnil } // returns (obj size, obj elements, error) // only maps and arrays have non-zero obj elements // // use uintptr b/c it's guaranteed to be large enough // to hold whatever we can fit in memory. func getNextSize(r *fwd.Reader) (uintptr, uintptr, error) { b, err := r.Peek(1) if err != nil { return 0, 0, err } lead := b[0] spec := &sizes[lead] size, mode := spec.size, spec.extra if size == 0 { return 0, 0, InvalidPrefixError(lead) } if mode >= 0 { return uintptr(size), uintptr(mode), nil } b, err = r.Peek(int(size)) if err != nil { return 0, 0, err } switch mode { case extra8: return uintptr(size) + uintptr(b[1]), 0, nil case extra16: return uintptr(size) + uintptr(big.Uint16(b[1:])), 0, nil case extra32: return uintptr(size) + uintptr(big.Uint32(b[1:])), 0, nil case map16v: return uintptr(size), 2 * uintptr(big.Uint16(b[1:])), nil case map32v: return uintptr(size), 2 * uintptr(big.Uint32(b[1:])), nil case array16v: return uintptr(size), uintptr(big.Uint16(b[1:])), nil case array32v: return uintptr(size), uintptr(big.Uint32(b[1:])), nil default: return 0, 0, fatal } } // Skip skips over the next object, regardless of // its type. If it is an array or map, the whole array // or map will be skipped. func (m *Reader) Skip() error { var ( v uintptr // bytes o uintptr // objects err error p []byte ) // we can use the faster // method if we have enough // buffered data if m.R.Buffered() >= 5 { p, err = m.R.Peek(5) if err != nil { return err } v, o, err = getSize(p) if err != nil { return err } } else { v, o, err = getNextSize(m.R) if err != nil { return err } } // 'v' is always non-zero // if err == nil _, err = m.R.Skip(int(v)) if err != nil { return err } // for maps and slices, skip elements for x := uintptr(0); x < o; x++ { err = m.Skip() if err != nil { return err } } return nil } // ReadMapHeader reads the next object // as a map header and returns the size // of the map and the number of bytes written. // It will return a TypeError{} if the next // object is not a map. func (m *Reader) ReadMapHeader() (sz uint32, err error) { if m.checkAndConsumeNil() { return 0, nil } var p []byte var lead byte p, err = m.R.Peek(1) if err != nil { return } lead = p[0] if isfixmap(lead) { sz = uint32(rfixmap(lead)) _, err = m.R.Skip(1) return } switch lead { case mmap16: p, err = m.R.Next(3) if err != nil { return } sz = uint32(big.Uint16(p[1:])) return case mmap32: p, err = m.R.Next(5) if err != nil { return } sz = big.Uint32(p[1:]) return default: err = badPrefix(MapType, lead) return } } // ReadMapKey reads either a 'str' or 'bin' field from // the reader and returns the value as a []byte. It uses // scratch for storage if it is large enough. func (m *Reader) ReadMapKey(scratch []byte) ([]byte, error) { if m.checkAndConsumeNil() { return nil, nil } out, err := m.ReadStringAsBytes(scratch) if err != nil { if tperr, ok := err.(TypeError); ok && tperr.Encoded == BinType { return m.ReadBytes(scratch) } return nil, err } return out, nil } // MapKeyPtr returns a []byte pointing to the contents // of a valid map key. The key cannot be empty, and it // must be shorter than the total buffer size of the // *Reader. Additionally, the returned slice is only // valid until the next *Reader method call. Users // should exercise extreme care when using this // method; writing into the returned slice may // corrupt future reads. func (m *Reader) ReadMapKeyPtr() ([]byte, error) { if m.checkAndConsumeNil() { return nil, nil } p, err := m.R.Peek(1) if err != nil { return nil, err } lead := p[0] var read int if isfixstr(lead) { read = int(rfixstr(lead)) m.R.Skip(1) goto fill } switch lead { case mstr8, mbin8: p, err = m.R.Next(2) if err != nil { return nil, err } read = int(p[1]) case mstr16, mbin16: p, err = m.R.Next(3) if err != nil { return nil, err } read = int(big.Uint16(p[1:])) case mstr32, mbin32: p, err = m.R.Next(5) if err != nil { return nil, err } read = int(big.Uint32(p[1:])) default: return nil, badPrefix(StrType, lead) } fill: if read == 0 { return nil, ErrShortBytes } return m.R.Next(read) } // ReadArrayHeader reads the next object as an // array header and returns the size of the array // and the number of bytes read. func (m *Reader) ReadArrayHeader() (sz uint32, err error) { if m.checkAndConsumeNil() { return 0, nil } var lead byte var p []byte p, err = m.R.Peek(1) if err != nil { return } lead = p[0] if isfixarray(lead) { sz = uint32(rfixarray(lead)) _, err = m.R.Skip(1) return } switch lead { case marray16: p, err = m.R.Next(3) if err != nil { return } sz = uint32(big.Uint16(p[1:])) return case marray32: p, err = m.R.Next(5) if err != nil { return } sz = big.Uint32(p[1:]) return default: err = badPrefix(ArrayType, lead) return } } // ReadNil reads a 'nil' MessagePack byte from the reader func (m *Reader) ReadNil() error { if m.AlwaysNil { return nil } p, err := m.R.Peek(1) if err != nil { return err } if p[0] != mnil { return badPrefix(NilType, p[0]) } _, err = m.R.Skip(1) return err } // checkAndConsumeNil returns true, nil if the // m.AlwaysNil flag is true. // // Otherwise, checkAndConsumeNil returns true if the next byte // was nil and we consumed it. We only consume // the next byte if it was a nil. We return // false if the next byte was not a nil. The // error return value provides diagnostics. func (m *Reader) checkAndConsumeNil() bool { if m.AlwaysNil { return true } p, err := m.R.Peek(1) if err != nil { return false } if p[0] != mnil { return false //, badPrefix(NilType, p[0]) } _, _ = m.R.Skip(1) return true } // ReadFloat64 reads a float64 from the reader. // (If the value on the wire is encoded as a float32, // it will be up-cast to a float64.) func (m *Reader) ReadFloat64() (f float64, err error) { if m.checkAndConsumeNil() { return 0, nil } var p []byte p, err = m.R.Peek(9) if err != nil { // we'll allow a coversion from float32 to float64, // since we don't lose any precision if err == io.EOF && len(p) > 0 && p[0] == mfloat32 { ef, err := m.ReadFloat32() return float64(ef), err } return } if p[0] != mfloat64 { // see above if p[0] == mfloat32 { ef, err := m.ReadFloat32() return float64(ef), err } err = badPrefix(Float64Type, p[0]) return } f = math.Float64frombits(getMuint64(p)) _, err = m.R.Skip(9) return } // ReadFloat32 reads a float32 from the reader func (m *Reader) ReadFloat32() (f float32, err error) { if m.checkAndConsumeNil() { return 0, nil } var p []byte p, err = m.R.Peek(5) if err != nil { return } if p[0] != mfloat32 { err = badPrefix(Float32Type, p[0]) return } f = math.Float32frombits(getMuint32(p)) _, err = m.R.Skip(5) return } // ReadBool reads a bool from the reader func (m *Reader) ReadBool() (b bool, err error) { if m.checkAndConsumeNil() { return false, nil } var p []byte p, err = m.R.Peek(1) if err != nil { return } switch p[0] { case mtrue: b = true case mfalse: default: err = badPrefix(BoolType, p[0]) return } _, err = m.R.Skip(1) return } // ReadInt64 reads an int64 from the reader func (m *Reader) ReadInt64() (i int64, err error) { if m.checkAndConsumeNil() { return 0, nil } var p []byte var lead byte p, err = m.R.Peek(1) if err != nil { return } lead = p[0] if isfixint(lead) { i = int64(rfixint(lead)) _, err = m.R.Skip(1) return } else if isnfixint(lead) { i = int64(rnfixint(lead)) _, err = m.R.Skip(1) return } switch lead { case mint8: p, err = m.R.Next(2) if err != nil { return } i = int64(getMint8(p)) return case mint16: p, err = m.R.Next(3) if err != nil { return } i = int64(getMint16(p)) return case mint32: p, err = m.R.Next(5) if err != nil { return } i = int64(getMint32(p)) return case mint64: p, err = m.R.Next(9) if err != nil { return } i = getMint64(p) return default: err = badPrefix(IntType, lead) return } } // ReadInt32 reads an int32 from the reader func (m *Reader) ReadInt32() (i int32, err error) { if m.checkAndConsumeNil() { return 0, nil } var in int64 in, err = m.ReadInt64() if in > math.MaxInt32 || in < math.MinInt32 { err = IntOverflow{Value: in, FailedBitsize: 32} return } i = int32(in) return } // ReadInt16 reads an int16 from the reader func (m *Reader) ReadInt16() (i int16, err error) { if m.checkAndConsumeNil() { return 0, nil } var in int64 in, err = m.ReadInt64() if in > math.MaxInt16 || in < math.MinInt16 { err = IntOverflow{Value: in, FailedBitsize: 16} return } i = int16(in) return } // ReadInt8 reads an int8 from the reader func (m *Reader) ReadInt8() (i int8, err error) { if m.checkAndConsumeNil() { return 0, nil } var in int64 in, err = m.ReadInt64() if in > math.MaxInt8 || in < math.MinInt8 { err = IntOverflow{Value: in, FailedBitsize: 8} return } i = int8(in) return } // ReadInt reads an int from the reader func (m *Reader) ReadInt() (i int, err error) { if m.checkAndConsumeNil() { return 0, nil } if smallint { var in int32 in, err = m.ReadInt32() i = int(in) return } var in int64 in, err = m.ReadInt64() i = int(in) return } // ReadUint64 reads a uint64 from the reader func (m *Reader) ReadUint64() (u uint64, err error) { if m.checkAndConsumeNil() { return 0, nil } var p []byte var lead byte p, err = m.R.Peek(1) if err != nil { return } lead = p[0] if isfixint(lead) { u = uint64(rfixint(lead)) _, err = m.R.Skip(1) return } switch lead { case muint8: p, err = m.R.Next(2) if err != nil { return } u = uint64(getMuint8(p)) return case muint16: p, err = m.R.Next(3) if err != nil { return } u = uint64(getMuint16(p)) return case muint32: p, err = m.R.Next(5) if err != nil { return } u = uint64(getMuint32(p)) return case muint64: p, err = m.R.Next(9) if err != nil { return } u = getMuint64(p) return default: err = badPrefix(UintType, lead) return } } // ReadUint32 reads a uint32 from the reader func (m *Reader) ReadUint32() (u uint32, err error) { if m.checkAndConsumeNil() { return 0, nil } var in uint64 in, err = m.ReadUint64() if in > math.MaxUint32 { err = UintOverflow{Value: in, FailedBitsize: 32} return } u = uint32(in) return } // ReadUint16 reads a uint16 from the reader func (m *Reader) ReadUint16() (u uint16, err error) { if m.checkAndConsumeNil() { return 0, nil } var in uint64 in, err = m.ReadUint64() if in > math.MaxUint16 { err = UintOverflow{Value: in, FailedBitsize: 16} return } u = uint16(in) return } // ReadUint8 reads a uint8 from the reader func (m *Reader) ReadUint8() (u uint8, err error) { if m.checkAndConsumeNil() { return 0, nil } var in uint64 in, err = m.ReadUint64() if in > math.MaxUint8 { err = UintOverflow{Value: in, FailedBitsize: 8} return } u = uint8(in) return } // ReadUint reads a uint from the reader func (m *Reader) ReadUint() (u uint, err error) { if m.checkAndConsumeNil() { return 0, nil } if smallint { var un uint32 un, err = m.ReadUint32() u = uint(un) return } var un uint64 un, err = m.ReadUint64() u = uint(un) return } // ReadByte is analogous to ReadUint8. // // NOTE: this is *not* an implementation // of io.ByteReader. func (m *Reader) ReadByte() (b byte, err error) { if m.checkAndConsumeNil() { return 0, nil } var in uint64 in, err = m.ReadUint64() if in > math.MaxUint8 { err = UintOverflow{Value: in, FailedBitsize: 8} return } b = byte(in) return } // ReadBytes reads a MessagePack 'bin' object // from the reader and returns its value. It may // use 'scratch' for storage if it is non-nil. func (m *Reader) ReadBytes(scratch []byte) (b []byte, err error) { if m.checkAndConsumeNil() { return nil, nil } var p []byte var lead byte p, err = m.R.Peek(2) if err != nil { return } lead = p[0] var read int64 switch lead { case mbin8: read = int64(p[1]) m.R.Skip(2) case mbin16: p, err = m.R.Next(3) if err != nil { return } read = int64(big.Uint16(p[1:])) case mbin32: p, err = m.R.Next(5) if err != nil { return } read = int64(big.Uint32(p[1:])) default: err = badPrefix(BinType, lead) return } if int64(cap(scratch)) < read { b = make([]byte, read) } else { b = scratch[0:read] } _, err = m.R.ReadFull(b) return } // ReadBytesHeader reads the size header // of a MessagePack 'bin' object. The user // is responsible for dealing with the next // 'sz' bytes from the reader in an application-specific // way. func (m *Reader) ReadBytesHeader() (sz uint32, err error) { if m.checkAndConsumeNil() { return 0, nil } var p []byte p, err = m.R.Peek(1) if err != nil { return } switch p[0] { case mbin8: p, err = m.R.Next(2) if err != nil { return } sz = uint32(p[1]) return case mbin16: p, err = m.R.Next(3) if err != nil { return } sz = uint32(big.Uint16(p[1:])) return case mbin32: p, err = m.R.Next(5) if err != nil { return } sz = uint32(big.Uint32(p[1:])) return default: err = badPrefix(BinType, p[0]) return } } // ReadExactBytes reads a MessagePack 'bin'-encoded // object off of the wire into the provided slice. An // ArrayError will be returned if the object is not // exactly the length of the input slice. func (m *Reader) ReadExactBytes(into []byte) error { if m.checkAndConsumeNil() { for i := range into { into[i] = 0 } return nil } p, err := m.R.Peek(2) if err != nil { return err } lead := p[0] var read int64 // bytes to read var skip int // prefix size to skip switch lead { case mbin8: read = int64(p[1]) skip = 2 case mbin16: p, err = m.R.Peek(3) if err != nil { return err } read = int64(big.Uint16(p[1:])) skip = 3 case mbin32: p, err = m.R.Peek(5) if err != nil { return err } read = int64(big.Uint32(p[1:])) skip = 5 default: return badPrefix(BinType, lead) } if read != int64(len(into)) { return ArrayError{Wanted: uint32(len(into)), Got: uint32(read)} } m.R.Skip(skip) _, err = m.R.ReadFull(into) return err } // ReadStringAsBytes reads a MessagePack 'str' (utf-8) string // and returns its value as bytes. It may use 'scratch' for storage // if it is non-nil. func (m *Reader) ReadStringAsBytes(scratch []byte) (b []byte, err error) { if m.checkAndConsumeNil() { return nil, nil } var p []byte var lead byte p, err = m.R.Peek(1) if err != nil { return } lead = p[0] var read int64 if isfixstr(lead) { read = int64(rfixstr(lead)) m.R.Skip(1) goto fill } switch lead { case mstr8: p, err = m.R.Next(2) if err != nil { return } read = int64(uint8(p[1])) case mstr16: p, err = m.R.Next(3) if err != nil { return } read = int64(big.Uint16(p[1:])) case mstr32: p, err = m.R.Next(5) if err != nil { return } read = int64(big.Uint32(p[1:])) default: err = badPrefix(StrType, lead) return } fill: if int64(cap(scratch)) < read { b = make([]byte, read) } else { b = scratch[0:read] } _, err = m.R.ReadFull(b) return } // ReadStringHeader reads a string header // off of the wire. The user is then responsible // for dealing with the next 'sz' bytes from // the reader in an application-specific manner. func (m *Reader) ReadStringHeader() (sz uint32, err error) { if m.checkAndConsumeNil() { return 0, nil } var p []byte p, err = m.R.Peek(1) if err != nil { return } lead := p[0] if isfixstr(lead) { sz = uint32(rfixstr(lead)) m.R.Skip(1) return } switch lead { case mstr8: p, err = m.R.Next(2) if err != nil { return } sz = uint32(p[1]) return case mstr16: p, err = m.R.Next(3) if err != nil { return } sz = uint32(big.Uint16(p[1:])) return case mstr32: p, err = m.R.Next(5) if err != nil { return } sz = big.Uint32(p[1:]) return default: err = badPrefix(StrType, lead) return } } // ReadString reads a utf-8 string from the reader func (m *Reader) ReadString() (s string, err error) { if m.checkAndConsumeNil() { return "", nil } var p []byte var lead byte var read int64 p, err = m.R.Peek(1) if err != nil { return } lead = p[0] if isfixstr(lead) { read = int64(rfixstr(lead)) m.R.Skip(1) goto fill } switch lead { case mstr8: p, err = m.R.Next(2) if err != nil { return } read = int64(uint8(p[1])) case mstr16: p, err = m.R.Next(3) if err != nil { return } read = int64(big.Uint16(p[1:])) case mstr32: p, err = m.R.Next(5) if err != nil { return } read = int64(big.Uint32(p[1:])) default: err = badPrefix(StrType, lead) return } fill: if read == 0 { s, err = "", nil return } // reading into the memory // that will become the string // itself has vastly superior // worst-case performance, because // the reader buffer doesn't have // to be large enough to hold the string. // the idea here is to make it more // difficult for someone malicious // to cause the system to run out of // memory by sending very large strings. // // NOTE: this works because the argument // passed to (*fwd.Reader).ReadFull escapes // to the heap; its argument may, in turn, // be passed to the underlying reader, and // thus escape analysis *must* conclude that // 'out' escapes. out := make([]byte, read) _, err = m.R.ReadFull(out) if err != nil { return } s = UnsafeString(out) return } // ReadComplex64 reads a complex64 from the reader func (m *Reader) ReadComplex64() (f complex64, err error) { if m.checkAndConsumeNil() { return 0, nil } var p []byte p, err = m.R.Peek(10) if err != nil { return } if p[0] != mfixext8 { err = badPrefix(Complex64Type, p[0]) return } if int8(p[1]) != Complex64Extension { err = errExt(int8(p[1]), Complex64Extension) return } f = complex(math.Float32frombits(big.Uint32(p[2:])), math.Float32frombits(big.Uint32(p[6:]))) _, err = m.R.Skip(10) return } // ReadComplex128 reads a complex128 from the reader func (m *Reader) ReadComplex128() (f complex128, err error) { if m.checkAndConsumeNil() { return 0, nil } var p []byte p, err = m.R.Peek(18) if err != nil { return } if p[0] != mfixext16 { err = badPrefix(Complex128Type, p[0]) return } if int8(p[1]) != Complex128Extension { err = errExt(int8(p[1]), Complex128Extension) return } f = complex(math.Float64frombits(big.Uint64(p[2:])), math.Float64frombits(big.Uint64(p[10:]))) _, err = m.R.Skip(18) return } // ReadMapStrIntf reads a MessagePack map into a map[string]interface{}. // (You must pass a non-nil map into the function.) func (m *Reader) ReadMapStrIntf(mp map[string]interface{}) (err error) { if m.checkAndConsumeNil() { return nil } var sz uint32 sz, err = m.ReadMapHeader() if err != nil { return } for key := range mp { delete(mp, key) } for i := uint32(0); i < sz; i++ { var key string var val interface{} key, err = m.ReadString() if err != nil { return } val, err = m.ReadIntf() if err != nil { return } mp[key] = val } return } // ReadTime reads a time.Time object from the reader. // The returned time's location will be set to time.Local. func (m *Reader) ReadTime() (t time.Time, err error) { if m.checkAndConsumeNil() { return time.Time{}, nil } var p []byte p, err = m.R.Peek(15) if err != nil { return } if p[0] != mext8 || p[1] != 12 { err = badPrefix(TimeType, p[0]) return } if int8(p[2]) != TimeExtension { err = errExt(int8(p[2]), TimeExtension) return } sec, nsec := getUnix(p[3:]) t = time.Unix(sec, int64(nsec)).Local() _, err = m.R.Skip(15) return } // ReadDuration reads a time.Duration object from the reader. func (m *Reader) ReadDuration() (t time.Duration, err error) { if m.checkAndConsumeNil() { return 0, nil } var p []byte p, err = m.R.Peek(4) if err != nil { return } if p[0] != mext8 { err = badPrefix(DurationType, p[0]) return } if int8(p[2]) != DurationExtension { err = errExt(int8(p[2]), DurationExtension) return } n := int(p[1]) if n > 9 { // type error of expected Duration and got Duration will // have to mean this byte count was way out of line. err = badPrefix(DurationType, p[0]) return } _, err = m.R.Skip(3) if err != nil { return } var n64 int64 n64, err = m.ReadInt64() if err != nil { return } t = time.Duration(n64) return } // ReadIntf reads out the next object as a raw interface{}. // Arrays are decoded as []interface{}, and maps are decoded // as map[string]interface{}. Integers are decoded as int64 // and unsigned integers are decoded as uint64. func (m *Reader) ReadIntf() (i interface{}, err error) { if m.checkAndConsumeNil() { return } var t Type t, err = m.NextType() if err != nil { return } switch t { case BoolType: i, err = m.ReadBool() return case IntType: i, err = m.ReadInt64() return case UintType: i, err = m.ReadUint64() return case BinType: i, err = m.ReadBytes(nil) return case StrType: i, err = m.ReadString() return case Complex64Type: i, err = m.ReadComplex64() return case Complex128Type: i, err = m.ReadComplex128() return case TimeType: i, err = m.ReadTime() return case DurationType: i, err = m.ReadDuration() return case ExtensionType: var t int8 t, err = m.peekExtensionType() if err != nil { return } f, ok := extensionReg[t] if ok { e := f() err = m.ReadExtension(e) i = e return } var e RawExtension e.Type = t err = m.ReadExtension(&e) i = &e return case MapType: mp := make(map[string]interface{}) err = m.ReadMapStrIntf(mp) i = mp return case NilType: err = m.ReadNil() i = nil return case Float32Type: i, err = m.ReadFloat32() return case Float64Type: i, err = m.ReadFloat64() return case ArrayType: var sz uint32 sz, err = m.ReadArrayHeader() if err != nil { return } out := make([]interface{}, int(sz)) for j := range out { out[j], err = m.ReadIntf() if err != nil { return } } i = out return default: return nil, fatal // unreachable } }