| package msgp |
| |
| import ( |
| "github.com/philhofer/fwd" |
| "io" |
| "math" |
| "sync" |
| "time" |
| ) |
| |
| // 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 |
| |
| _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 "<invalid>" |
| } |
| } |
| |
| 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) |
| } |
| 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 *fwd.Reader |
| scratch []byte |
| } |
| |
| // Read implements `io.Reader` |
| func (m *Reader) Read(p []byte) (int, error) { |
| return m.r.Read(p) |
| } |
| |
| // ReadFull implements `io.ReadFull` |
| func (m *Reader) ReadFull(p []byte) (int, error) { |
| 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() } |
| |
| // NextType returns the next object type to be decoded. |
| func (m *Reader) NextType() (Type, error) { |
| 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 |
| } |
| } |
| return t, nil |
| } |
| |
| // IsNil returns whether or not |
| // the next byte is a null messagepack byte |
| func (m *Reader) IsNil() 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) { |
| 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) { |
| 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) { |
| 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) { |
| 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 { |
| 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 |
| } |
| |
| // 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) { |
| 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) { |
| 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) { |
| 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) { |
| 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) { |
| 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) { |
| 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) { |
| 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 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) { |
| 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) { |
| 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) { |
| 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) { |
| 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 smallint { |
| var un uint32 |
| un, err = m.ReadUint32() |
| u = uint(un) |
| return |
| } |
| var un uint64 |
| un, err = m.ReadUint64() |
| u = uint(un) |
| return |
| } |
| |
| func (m *Reader) ReadByte() (b byte, err error) { |
| 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) { |
| 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 |
| } |
| |
| // 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 { |
| 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) { |
| 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 |
| } |
| |
| // ReadString reads a utf-8 string from the reader |
| func (m *Reader) ReadString() (s string, err error) { |
| 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) { |
| 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) { |
| 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) { |
| 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) { |
| 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 |
| } |
| |
| // 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) { |
| 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 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 |
| } |
| } |