| package msgpack |
| |
| import ( |
| "errors" |
| "fmt" |
| "reflect" |
| |
| "github.com/vmihailenco/msgpack/codes" |
| ) |
| |
| const mapElemsAllocLimit = 1e4 |
| |
| var mapStringStringPtrType = reflect.TypeOf((*map[string]string)(nil)) |
| var mapStringStringType = mapStringStringPtrType.Elem() |
| |
| var mapStringInterfacePtrType = reflect.TypeOf((*map[string]interface{})(nil)) |
| var mapStringInterfaceType = mapStringInterfacePtrType.Elem() |
| |
| var errInvalidCode = errors.New("invalid code") |
| |
| func decodeMapValue(d *Decoder, v reflect.Value) error { |
| size, err := d.DecodeMapLen() |
| if err != nil { |
| return err |
| } |
| |
| typ := v.Type() |
| if size == -1 { |
| v.Set(reflect.Zero(typ)) |
| return nil |
| } |
| |
| if v.IsNil() { |
| v.Set(reflect.MakeMap(typ)) |
| } |
| if size == 0 { |
| return nil |
| } |
| |
| return decodeMapValueSize(d, v, size) |
| } |
| |
| func decodeMapValueSize(d *Decoder, v reflect.Value, size int) error { |
| typ := v.Type() |
| keyType := typ.Key() |
| valueType := typ.Elem() |
| |
| for i := 0; i < size; i++ { |
| mk := reflect.New(keyType).Elem() |
| if err := d.DecodeValue(mk); err != nil { |
| return err |
| } |
| |
| mv := reflect.New(valueType).Elem() |
| if err := d.DecodeValue(mv); err != nil { |
| return err |
| } |
| |
| v.SetMapIndex(mk, mv) |
| } |
| |
| return nil |
| } |
| |
| // DecodeMapLen decodes map length. Length is -1 when map is nil. |
| func (d *Decoder) DecodeMapLen() (int, error) { |
| c, err := d.readCode() |
| if err != nil { |
| return 0, err |
| } |
| |
| if codes.IsExt(c) { |
| if err = d.skipExtHeader(c); err != nil { |
| return 0, err |
| } |
| |
| c, err = d.readCode() |
| if err != nil { |
| return 0, err |
| } |
| } |
| return d.mapLen(c) |
| } |
| |
| func (d *Decoder) mapLen(c codes.Code) (int, error) { |
| size, err := d._mapLen(c) |
| err = expandInvalidCodeMapLenError(c, err) |
| return size, err |
| } |
| |
| func (d *Decoder) _mapLen(c codes.Code) (int, error) { |
| if c == codes.Nil { |
| return -1, nil |
| } |
| if c >= codes.FixedMapLow && c <= codes.FixedMapHigh { |
| return int(c & codes.FixedMapMask), nil |
| } |
| if c == codes.Map16 { |
| size, err := d.uint16() |
| return int(size), err |
| } |
| if c == codes.Map32 { |
| size, err := d.uint32() |
| return int(size), err |
| } |
| return 0, errInvalidCode |
| } |
| |
| func expandInvalidCodeMapLenError(c codes.Code, err error) error { |
| if err == errInvalidCode { |
| return fmt.Errorf("msgpack: invalid code=%x decoding map length", c) |
| } |
| return err |
| } |
| |
| func decodeMapStringStringValue(d *Decoder, v reflect.Value) error { |
| mptr := v.Addr().Convert(mapStringStringPtrType).Interface().(*map[string]string) |
| return d.decodeMapStringStringPtr(mptr) |
| } |
| |
| func (d *Decoder) decodeMapStringStringPtr(ptr *map[string]string) error { |
| size, err := d.DecodeMapLen() |
| if err != nil { |
| return err |
| } |
| if size == -1 { |
| *ptr = nil |
| return nil |
| } |
| |
| m := *ptr |
| if m == nil { |
| *ptr = make(map[string]string, min(size, mapElemsAllocLimit)) |
| m = *ptr |
| } |
| |
| for i := 0; i < size; i++ { |
| mk, err := d.DecodeString() |
| if err != nil { |
| return err |
| } |
| mv, err := d.DecodeString() |
| if err != nil { |
| return err |
| } |
| m[mk] = mv |
| } |
| |
| return nil |
| } |
| |
| func decodeMapStringInterfaceValue(d *Decoder, v reflect.Value) error { |
| ptr := v.Addr().Convert(mapStringInterfacePtrType).Interface().(*map[string]interface{}) |
| return d.decodeMapStringInterfacePtr(ptr) |
| } |
| |
| func (d *Decoder) decodeMapStringInterfacePtr(ptr *map[string]interface{}) error { |
| n, err := d.DecodeMapLen() |
| if err != nil { |
| return err |
| } |
| if n == -1 { |
| *ptr = nil |
| return nil |
| } |
| |
| m := *ptr |
| if m == nil { |
| *ptr = make(map[string]interface{}, min(n, mapElemsAllocLimit)) |
| m = *ptr |
| } |
| |
| for i := 0; i < n; i++ { |
| mk, err := d.DecodeString() |
| if err != nil { |
| return err |
| } |
| mv, err := d.decodeInterfaceCond() |
| if err != nil { |
| return err |
| } |
| m[mk] = mv |
| } |
| |
| return nil |
| } |
| |
| func (d *Decoder) DecodeMap() (interface{}, error) { |
| if d.decodeMapFunc != nil { |
| return d.decodeMapFunc(d) |
| } |
| |
| size, err := d.DecodeMapLen() |
| if err != nil { |
| return nil, err |
| } |
| if size == -1 { |
| return nil, nil |
| } |
| if size == 0 { |
| return make(map[string]interface{}), nil |
| } |
| |
| code, err := d.PeekCode() |
| if err != nil { |
| return nil, err |
| } |
| |
| if codes.IsString(code) { |
| return d.decodeMapStringInterfaceSize(size) |
| } |
| |
| key, err := d.decodeInterfaceCond() |
| if err != nil { |
| return nil, err |
| } |
| |
| value, err := d.decodeInterfaceCond() |
| if err != nil { |
| return nil, err |
| } |
| |
| keyType := reflect.TypeOf(key) |
| valueType := reflect.TypeOf(value) |
| mapType := reflect.MapOf(keyType, valueType) |
| mapValue := reflect.MakeMap(mapType) |
| |
| mapValue.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(value)) |
| size-- |
| |
| err = decodeMapValueSize(d, mapValue, size) |
| if err != nil { |
| return nil, err |
| } |
| |
| return mapValue.Interface(), nil |
| } |
| |
| func (d *Decoder) decodeMapStringInterfaceSize(size int) (map[string]interface{}, error) { |
| m := make(map[string]interface{}, min(size, mapElemsAllocLimit)) |
| for i := 0; i < size; i++ { |
| mk, err := d.DecodeString() |
| if err != nil { |
| return nil, err |
| } |
| mv, err := d.decodeInterfaceCond() |
| if err != nil { |
| return nil, err |
| } |
| m[mk] = mv |
| } |
| return m, nil |
| } |
| |
| func (d *Decoder) skipMap(c codes.Code) error { |
| n, err := d.mapLen(c) |
| if err != nil { |
| return err |
| } |
| for i := 0; i < n; i++ { |
| if err := d.Skip(); err != nil { |
| return err |
| } |
| if err := d.Skip(); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
| |
| func decodeStructValue(d *Decoder, v reflect.Value) error { |
| c, err := d.readCode() |
| if err != nil { |
| return err |
| } |
| |
| var isArray bool |
| |
| n, err := d._mapLen(c) |
| if err != nil { |
| var err2 error |
| n, err2 = d.arrayLen(c) |
| if err2 != nil { |
| return expandInvalidCodeMapLenError(c, err) |
| } |
| isArray = true |
| } |
| if n == -1 { |
| if err = mustSet(v); err != nil { |
| return err |
| } |
| v.Set(reflect.Zero(v.Type())) |
| return nil |
| } |
| |
| var fields *fields |
| if d.useJSONTag { |
| fields = jsonStructs.Fields(v.Type()) |
| } else { |
| fields = structs.Fields(v.Type()) |
| } |
| |
| if isArray { |
| for i, f := range fields.List { |
| if i >= n { |
| break |
| } |
| if err := f.DecodeValue(d, v); err != nil { |
| return err |
| } |
| } |
| // Skip extra values. |
| for i := len(fields.List); i < n; i++ { |
| if err := d.Skip(); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
| |
| for i := 0; i < n; i++ { |
| name, err := d.DecodeString() |
| if err != nil { |
| return err |
| } |
| if f := fields.Table[name]; f != nil { |
| if err := f.DecodeValue(d, v); err != nil { |
| return err |
| } |
| } else { |
| if err := d.Skip(); err != nil { |
| return err |
| } |
| } |
| } |
| |
| return nil |
| } |