// Copyright (c) Faye Amacker. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. package cbor import ( "encoding" "encoding/binary" "errors" "fmt" "io" "math" "math/big" "reflect" "strconv" "strings" "time" "unicode/utf8" "github.com/x448/float16" ) // Unmarshal parses the CBOR-encoded data into the value pointed to by v // using default decoding options. If v is nil, not a pointer, or // a nil pointer, Unmarshal returns an error. // // To unmarshal CBOR into a value implementing the Unmarshaler interface, // Unmarshal calls that value's UnmarshalCBOR method with a valid // CBOR value. // // To unmarshal CBOR byte string into a value implementing the // encoding.BinaryUnmarshaler interface, Unmarshal calls that value's // UnmarshalBinary method with decoded CBOR byte string. // // To unmarshal CBOR into a pointer, Unmarshal sets the pointer to nil // if CBOR data is null (0xf6) or undefined (0xf7). Otherwise, Unmarshal // unmarshals CBOR into the value pointed to by the pointer. If the // pointer is nil, Unmarshal creates a new value for it to point to. // // To unmarshal CBOR into an empty interface value, Unmarshal uses the // following rules: // // CBOR booleans decode to bool. // CBOR positive integers decode to uint64. // CBOR negative integers decode to int64 (big.Int if value overflows). // CBOR floating points decode to float64. // CBOR byte strings decode to []byte. // CBOR text strings decode to string. // CBOR arrays decode to []interface{}. // CBOR maps decode to map[interface{}]interface{}. // CBOR null and undefined values decode to nil. // CBOR times (tag 0 and 1) decode to time.Time. // CBOR bignums (tag 2 and 3) decode to big.Int. // // To unmarshal a CBOR array into a slice, Unmarshal allocates a new slice // if the CBOR array is empty or slice capacity is less than CBOR array length. // Otherwise Unmarshal overwrites existing elements, and sets slice length // to CBOR array length. // // To unmarshal a CBOR array into a Go array, Unmarshal decodes CBOR array // elements into Go array elements. If the Go array is smaller than the // CBOR array, the extra CBOR array elements are discarded. If the CBOR // array is smaller than the Go array, the extra Go array elements are // set to zero values. // // To unmarshal a CBOR array into a struct, struct must have a special field "_" // with struct tag `cbor:",toarray"`. Go array elements are decoded into struct // fields. Any "omitempty" struct field tag option is ignored in this case. // // To unmarshal a CBOR map into a map, Unmarshal allocates a new map only if the // map is nil. Otherwise Unmarshal reuses the existing map and keeps existing // entries. Unmarshal stores key-value pairs from the CBOR map into Go map. // See DecOptions.DupMapKey to enable duplicate map key detection. // // To unmarshal a CBOR map into a struct, Unmarshal matches CBOR map keys to the // keys in the following priority: // // 1. "cbor" key in struct field tag, // 2. "json" key in struct field tag, // 3. struct field name. // // Unmarshal tries an exact match for field name, then a case-insensitive match. // Map key-value pairs without corresponding struct fields are ignored. See // DecOptions.ExtraReturnErrors to return error at unknown field. // // To unmarshal a CBOR text string into a time.Time value, Unmarshal parses text // string formatted in RFC3339. To unmarshal a CBOR integer/float into a // time.Time value, Unmarshal creates an unix time with integer/float as seconds // and fractional seconds since January 1, 1970 UTC. // // To unmarshal CBOR null (0xf6) and undefined (0xf7) values into a // slice/map/pointer, Unmarshal sets Go value to nil. Because null is often // used to mean "not present", unmarshalling CBOR null and undefined value // into any other Go type has no effect and returns no error. // // Unmarshal supports CBOR tag 55799 (self-describe CBOR), tag 0 and 1 (time), // and tag 2 and 3 (bignum). func Unmarshal(data []byte, v interface{}) error { return defaultDecMode.Unmarshal(data, v) } // Valid checks whether the CBOR data is complete and well-formed. func Valid(data []byte) error { return defaultDecMode.Valid(data) } // Unmarshaler is the interface implemented by types that wish to unmarshal // CBOR data themselves. The input is a valid CBOR value. UnmarshalCBOR // must copy the CBOR data if it needs to use it after returning. type Unmarshaler interface { UnmarshalCBOR([]byte) error } // InvalidUnmarshalError describes an invalid argument passed to Unmarshal. type InvalidUnmarshalError struct { s string } func (e *InvalidUnmarshalError) Error() string { return e.s } // UnmarshalTypeError describes a CBOR value that can't be decoded to a Go type. type UnmarshalTypeError struct { CBORType string // type of CBOR value GoType string // type of Go value it could not be decoded into StructFieldName string // name of the struct field holding the Go value (optional) errorMsg string // additional error message (optional) } func (e *UnmarshalTypeError) Error() string { var s string if e.StructFieldName != "" { s = "cbor: cannot unmarshal " + e.CBORType + " into Go struct field " + e.StructFieldName + " of type " + e.GoType } else { s = "cbor: cannot unmarshal " + e.CBORType + " into Go value of type " + e.GoType } if e.errorMsg != "" { s += " (" + e.errorMsg + ")" } return s } // DupMapKeyError describes detected duplicate map key in CBOR map. type DupMapKeyError struct { Key interface{} Index int } func (e *DupMapKeyError) Error() string { return fmt.Sprintf("cbor: found duplicate map key \"%v\" at map element index %d", e.Key, e.Index) } // UnknownFieldError describes detected unknown field in CBOR map when decoding to Go struct. type UnknownFieldError struct { Index int } func (e *UnknownFieldError) Error() string { return fmt.Sprintf("cbor: found unknown field at map element index %d", e.Index) } // DupMapKeyMode specifies how to enforce duplicate map key. type DupMapKeyMode int const ( // DupMapKeyQuiet doesn't enforce duplicate map key. Decoder quietly (no error) // uses faster of "keep first" or "keep last" depending on Go data type and other factors. DupMapKeyQuiet DupMapKeyMode = iota // DupMapKeyEnforcedAPF enforces detection and rejection of duplicate map keys. // APF means "Allow Partial Fill" and the destination map or struct can be partially filled. // If a duplicate map key is detected, DupMapKeyError is returned without further decoding // of the map. It's the caller's responsibility to respond to DupMapKeyError by // discarding the partially filled result if their protocol requires it. // WARNING: using DupMapKeyEnforcedAPF will decrease performance and increase memory use. DupMapKeyEnforcedAPF maxDupMapKeyMode ) func (dmkm DupMapKeyMode) valid() bool { return dmkm < maxDupMapKeyMode } // IndefLengthMode specifies whether to allow indefinite length items. type IndefLengthMode int const ( // IndefLengthAllowed allows indefinite length items. IndefLengthAllowed IndefLengthMode = iota // IndefLengthForbidden disallows indefinite length items. IndefLengthForbidden maxIndefLengthMode ) func (m IndefLengthMode) valid() bool { return m < maxIndefLengthMode } // TagsMode specifies whether to allow CBOR tags. type TagsMode int const ( // TagsAllowed allows CBOR tags. TagsAllowed TagsMode = iota // TagsForbidden disallows CBOR tags. TagsForbidden maxTagsMode ) func (tm TagsMode) valid() bool { return tm < maxTagsMode } // IntDecMode specifies which Go int type (int64 or uint64) should // be used when decoding CBOR int (major type 0 and 1) to Go interface{}. type IntDecMode int const ( // IntDecConvertNone affects how CBOR int (major type 0 and 1) decodes to Go interface{}. // It makes CBOR positive int (major type 0) decode to uint64 value, and // CBOR negative int (major type 1) decode to int64 value. IntDecConvertNone IntDecMode = iota // IntDecConvertSigned affects how CBOR int (major type 0 and 1) decodes to Go interface{}. // It makes CBOR positive/negative int (major type 0 and 1) decode to int64 value. // If value overflows int64, UnmarshalTypeError is returned. IntDecConvertSigned maxIntDec ) func (idm IntDecMode) valid() bool { return idm < maxIntDec } // ExtraDecErrorCond specifies extra conditions that should be treated as errors. type ExtraDecErrorCond uint // ExtraDecErrorNone indicates no extra error condition. const ExtraDecErrorNone ExtraDecErrorCond = 0 const ( // ExtraDecErrorUnknownField indicates error condition when destination // Go struct doesn't have a field matching a CBOR map key. ExtraDecErrorUnknownField ExtraDecErrorCond = 1 << iota maxExtraDecError ) func (ec ExtraDecErrorCond) valid() bool { return ec < maxExtraDecError } // DecOptions specifies decoding options. type DecOptions struct { // DupMapKey specifies whether to enforce duplicate map key. DupMapKey DupMapKeyMode // TimeTag specifies whether to check validity of time.Time (e.g. valid tag number and tag content type). // For now, valid tag number means 0 or 1 as specified in RFC 7049 if the Go type is time.Time. TimeTag DecTagMode // MaxNestedLevels specifies the max nested levels allowed for any combination of CBOR array, maps, and tags. // Default is 32 levels and it can be set to [4, 256]. MaxNestedLevels int // MaxArrayElements specifies the max number of elements for CBOR arrays. // Default is 128*1024=131072 and it can be set to [16, 2147483647] MaxArrayElements int // MaxMapPairs specifies the max number of key-value pairs for CBOR maps. // Default is 128*1024=131072 and it can be set to [16, 2147483647] MaxMapPairs int // IndefLength specifies whether to allow indefinite length CBOR items. IndefLength IndefLengthMode // TagsMd specifies whether to allow CBOR tags (major type 6). TagsMd TagsMode // IntDec specifies which Go integer type (int64 or uint64) to use // when decoding CBOR int (major type 0 and 1) to Go interface{}. IntDec IntDecMode // ExtraReturnErrors specifies extra conditions that should be treated as errors. ExtraReturnErrors ExtraDecErrorCond } // DecMode returns DecMode with immutable options and no tags (safe for concurrency). func (opts DecOptions) DecMode() (DecMode, error) { return opts.decMode() } // DecModeWithTags returns DecMode with options and tags that are both immutable (safe for concurrency). func (opts DecOptions) DecModeWithTags(tags TagSet) (DecMode, error) { if opts.TagsMd == TagsForbidden { return nil, errors.New("cbor: cannot create DecMode with TagSet when TagsMd is TagsForbidden") } if tags == nil { return nil, errors.New("cbor: cannot create DecMode with nil value as TagSet") } dm, err := opts.decMode() if err != nil { return nil, err } // Copy tags ts := tagSet(make(map[reflect.Type]*tagItem)) syncTags := tags.(*syncTagSet) syncTags.RLock() for contentType, tag := range syncTags.t { if tag.opts.DecTag != DecTagIgnored { ts[contentType] = tag } } syncTags.RUnlock() if len(ts) > 0 { dm.tags = ts } return dm, nil } // DecModeWithSharedTags returns DecMode with immutable options and mutable shared tags (safe for concurrency). func (opts DecOptions) DecModeWithSharedTags(tags TagSet) (DecMode, error) { if opts.TagsMd == TagsForbidden { return nil, errors.New("cbor: cannot create DecMode with TagSet when TagsMd is TagsForbidden") } if tags == nil { return nil, errors.New("cbor: cannot create DecMode with nil value as TagSet") } dm, err := opts.decMode() if err != nil { return nil, err } dm.tags = tags return dm, nil } const ( defaultMaxArrayElements = 131072 minMaxArrayElements = 16 maxMaxArrayElements = 2147483647 defaultMaxMapPairs = 131072 minMaxMapPairs = 16 maxMaxMapPairs = 2147483647 ) func (opts DecOptions) decMode() (*decMode, error) { if !opts.DupMapKey.valid() { return nil, errors.New("cbor: invalid DupMapKey " + strconv.Itoa(int(opts.DupMapKey))) } if !opts.TimeTag.valid() { return nil, errors.New("cbor: invalid TimeTag " + strconv.Itoa(int(opts.TimeTag))) } if !opts.IndefLength.valid() { return nil, errors.New("cbor: invalid IndefLength " + strconv.Itoa(int(opts.IndefLength))) } if !opts.TagsMd.valid() { return nil, errors.New("cbor: invalid TagsMd " + strconv.Itoa(int(opts.TagsMd))) } if !opts.IntDec.valid() { return nil, errors.New("cbor: invalid IntDec " + strconv.Itoa(int(opts.IntDec))) } if opts.MaxNestedLevels == 0 { opts.MaxNestedLevels = 32 } else if opts.MaxNestedLevels < 4 || opts.MaxNestedLevels > 256 { return nil, errors.New("cbor: invalid MaxNestedLevels " + strconv.Itoa(opts.MaxNestedLevels) + " (range is [4, 256])") } if opts.MaxArrayElements == 0 { opts.MaxArrayElements = defaultMaxArrayElements } else if opts.MaxArrayElements < minMaxArrayElements || opts.MaxArrayElements > maxMaxArrayElements { return nil, errors.New("cbor: invalid MaxArrayElements " + strconv.Itoa(opts.MaxArrayElements) + " (range is [" + strconv.Itoa(minMaxArrayElements) + ", " + strconv.Itoa(maxMaxArrayElements) + "])") } if opts.MaxMapPairs == 0 { opts.MaxMapPairs = defaultMaxMapPairs } else if opts.MaxMapPairs < minMaxMapPairs || opts.MaxMapPairs > maxMaxMapPairs { return nil, errors.New("cbor: invalid MaxMapPairs " + strconv.Itoa(opts.MaxMapPairs) + " (range is [" + strconv.Itoa(minMaxMapPairs) + ", " + strconv.Itoa(maxMaxMapPairs) + "])") } if !opts.ExtraReturnErrors.valid() { return nil, errors.New("cbor: invalid ExtraReturnErrors " + strconv.Itoa(int(opts.ExtraReturnErrors))) } dm := decMode{ dupMapKey: opts.DupMapKey, timeTag: opts.TimeTag, maxNestedLevels: opts.MaxNestedLevels, maxArrayElements: opts.MaxArrayElements, maxMapPairs: opts.MaxMapPairs, indefLength: opts.IndefLength, tagsMd: opts.TagsMd, intDec: opts.IntDec, extraReturnErrors: opts.ExtraReturnErrors, } return &dm, nil } // DecMode is the main interface for CBOR decoding. type DecMode interface { // Unmarshal parses the CBOR-encoded data into the value pointed to by v // using the decoding mode. If v is nil, not a pointer, or a nil pointer, // Unmarshal returns an error. // // See the documentation for Unmarshal for details. Unmarshal(data []byte, v interface{}) error // Valid checks whether the CBOR data is complete and well-formed. Valid(data []byte) error // NewDecoder returns a new decoder that reads from r using dm DecMode. NewDecoder(r io.Reader) *Decoder // DecOptions returns user specified options used to create this DecMode. DecOptions() DecOptions } type decMode struct { tags tagProvider dupMapKey DupMapKeyMode timeTag DecTagMode maxNestedLevels int maxArrayElements int maxMapPairs int indefLength IndefLengthMode tagsMd TagsMode intDec IntDecMode extraReturnErrors ExtraDecErrorCond } var defaultDecMode, _ = DecOptions{}.decMode() // DecOptions returns user specified options used to create this DecMode. func (dm *decMode) DecOptions() DecOptions { return DecOptions{ DupMapKey: dm.dupMapKey, TimeTag: dm.timeTag, MaxNestedLevels: dm.maxNestedLevels, MaxArrayElements: dm.maxArrayElements, MaxMapPairs: dm.maxMapPairs, IndefLength: dm.indefLength, TagsMd: dm.tagsMd, IntDec: dm.intDec, ExtraReturnErrors: dm.extraReturnErrors, } } // Unmarshal parses the CBOR-encoded data into the value pointed to by v // using dm decoding mode. If v is nil, not a pointer, or a nil pointer, // Unmarshal returns an error. // // See the documentation for Unmarshal for details. func (dm *decMode) Unmarshal(data []byte, v interface{}) error { d := decoder{data: data, dm: dm} return d.value(v) } // Valid checks whether the CBOR data is complete and well-formed. func (dm *decMode) Valid(data []byte) error { d := decoder{data: data, dm: dm} return d.valid() } // NewDecoder returns a new decoder that reads from r using dm DecMode. func (dm *decMode) NewDecoder(r io.Reader) *Decoder { return &Decoder{r: r, d: decoder{dm: dm}} } type decoder struct { data []byte off int // next read offset in data dm *decMode } func (d *decoder) value(v interface{}) error { // v can't be nil, non-pointer, or nil pointer value. if v == nil { return &InvalidUnmarshalError{"cbor: Unmarshal(nil)"} } rv := reflect.ValueOf(v) if rv.Kind() != reflect.Ptr { return &InvalidUnmarshalError{"cbor: Unmarshal(non-pointer " + rv.Type().String() + ")"} } else if rv.IsNil() { return &InvalidUnmarshalError{"cbor: Unmarshal(nil " + rv.Type().String() + ")"} } off := d.off // Save offset before data validation err := d.valid() d.off = off // Restore offset if err != nil { return err } rv = rv.Elem() return d.parseToValue(rv, getTypeInfo(rv.Type())) } type cborType uint8 const ( cborTypePositiveInt cborType = 0x00 cborTypeNegativeInt cborType = 0x20 cborTypeByteString cborType = 0x40 cborTypeTextString cborType = 0x60 cborTypeArray cborType = 0x80 cborTypeMap cborType = 0xa0 cborTypeTag cborType = 0xc0 cborTypePrimitives cborType = 0xe0 ) func (t cborType) String() string { switch t { case cborTypePositiveInt: return "positive integer" case cborTypeNegativeInt: return "negative integer" case cborTypeByteString: return "byte string" case cborTypeTextString: return "UTF-8 text string" case cborTypeArray: return "array" case cborTypeMap: return "map" case cborTypeTag: return "tag" case cborTypePrimitives: return "primitives" default: return "Invalid type " + strconv.Itoa(int(t)) } } const ( selfDescribedCBORTagNum = 55799 ) // parseToValue decodes CBOR data to value. It assumes data is well-formed, // and does not perform bounds checking. func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolint:gocyclo // Create new value for the pointer v to point to if CBOR value is not nil/undefined. if !d.nextCBORNil() { for v.Kind() == reflect.Ptr { if v.IsNil() { if !v.CanSet() { d.skip() return errors.New("cbor: cannot set new value for " + v.Type().String()) } v.Set(reflect.New(v.Type().Elem())) } v = v.Elem() } } // Strip self-described CBOR tag number. for d.nextCBORType() == cborTypeTag { off := d.off _, _, tagNum := d.getHead() if tagNum != selfDescribedCBORTagNum { d.off = off break } } // Check validity of supported built-in tags. if d.nextCBORType() == cborTypeTag { off := d.off _, _, tagNum := d.getHead() if err := validBuiltinTag(tagNum, d.data[d.off]); err != nil { d.skip() return err } d.off = off } if tInfo.spclType != specialTypeNone { switch tInfo.spclType { case specialTypeEmptyIface: iv, err := d.parse(false) // Skipped self-described CBOR tag number already. if iv != nil { v.Set(reflect.ValueOf(iv)) } return err case specialTypeTag: return d.parseToTag(v) case specialTypeTime: if d.nextCBORNil() { // Decoding CBOR null and undefined to time.Time is no-op. d.skip() return nil } tm, err := d.parseToTime() if err != nil { return err } v.Set(reflect.ValueOf(tm)) return nil case specialTypeUnmarshalerIface: return d.parseToUnmarshaler(v) } } // Check registered tag number if tagItem := d.getRegisteredTagItem(tInfo.nonPtrType); tagItem != nil { t := d.nextCBORType() if t != cborTypeTag { if tagItem.opts.DecTag == DecTagRequired { d.skip() // Required tag number is absent, skip entire tag return &UnmarshalTypeError{ CBORType: t.String(), GoType: tInfo.typ.String(), errorMsg: "expect CBOR tag value"} } } else if err := d.validRegisteredTagNums(tagItem); err != nil { d.skip() // Skip tag content return err } } t := d.nextCBORType() switch t { case cborTypePositiveInt: _, _, val := d.getHead() return fillPositiveInt(t, val, v) case cborTypeNegativeInt: _, _, val := d.getHead() if val > math.MaxInt64 { // CBOR negative integer overflows int64, use big.Int to store value. bi := new(big.Int) bi.SetUint64(val) bi.Add(bi, big.NewInt(1)) bi.Neg(bi) if tInfo.nonPtrType == typeBigInt { v.Set(reflect.ValueOf(*bi)) return nil } return &UnmarshalTypeError{ CBORType: t.String(), GoType: tInfo.nonPtrType.String(), errorMsg: bi.String() + " overflows Go's int64", } } nValue := int64(-1) ^ int64(val) return fillNegativeInt(t, nValue, v) case cborTypeByteString: b := d.parseByteString() return fillByteString(t, b, v) case cborTypeTextString: b, err := d.parseTextString() if err != nil { return err } return fillTextString(t, b, v) case cborTypePrimitives: _, ai, val := d.getHead() if ai < 20 || ai == 24 { return fillPositiveInt(t, val, v) } switch ai { case 20, 21: return fillBool(t, ai == 21, v) case 22, 23: return fillNil(t, v) case 25: f := float64(float16.Frombits(uint16(val)).Float32()) return fillFloat(t, f, v) case 26: f := float64(math.Float32frombits(uint32(val))) return fillFloat(t, f, v) case 27: f := math.Float64frombits(val) return fillFloat(t, f, v) } case cborTypeTag: _, _, tagNum := d.getHead() switch tagNum { case 2: // Bignum (tag 2) can be decoded to uint, int, float, slice, array, or big.Int. b := d.parseByteString() bi := new(big.Int).SetBytes(b) if tInfo.nonPtrType == typeBigInt { v.Set(reflect.ValueOf(*bi)) return nil } if tInfo.nonPtrKind == reflect.Slice || tInfo.nonPtrKind == reflect.Array { return fillByteString(t, b, v) } if bi.IsUint64() { return fillPositiveInt(t, bi.Uint64(), v) } return &UnmarshalTypeError{ CBORType: t.String(), GoType: tInfo.nonPtrType.String(), errorMsg: bi.String() + " overflows " + v.Type().String(), } case 3: // Bignum (tag 3) can be decoded to int, float, slice, array, or big.Int. b := d.parseByteString() bi := new(big.Int).SetBytes(b) bi.Add(bi, big.NewInt(1)) bi.Neg(bi) if tInfo.nonPtrType == typeBigInt { v.Set(reflect.ValueOf(*bi)) return nil } if tInfo.nonPtrKind == reflect.Slice || tInfo.nonPtrKind == reflect.Array { return fillByteString(t, b, v) } if bi.IsInt64() { return fillNegativeInt(t, bi.Int64(), v) } return &UnmarshalTypeError{ CBORType: t.String(), GoType: tInfo.nonPtrType.String(), errorMsg: bi.String() + " overflows " + v.Type().String(), } } return d.parseToValue(v, tInfo) case cborTypeArray: if tInfo.nonPtrKind == reflect.Slice { return d.parseArrayToSlice(v, tInfo) } else if tInfo.nonPtrKind == reflect.Array { return d.parseArrayToArray(v, tInfo) } else if tInfo.nonPtrKind == reflect.Struct { return d.parseArrayToStruct(v, tInfo) } d.skip() return &UnmarshalTypeError{CBORType: t.String(), GoType: tInfo.nonPtrType.String()} case cborTypeMap: if tInfo.nonPtrKind == reflect.Struct { return d.parseMapToStruct(v, tInfo) } else if tInfo.nonPtrKind == reflect.Map { return d.parseMapToMap(v, tInfo) } d.skip() return &UnmarshalTypeError{CBORType: t.String(), GoType: tInfo.nonPtrType.String()} } return nil } func (d *decoder) parseToTag(v reflect.Value) error { if d.nextCBORNil() { // Decoding CBOR null and undefined to cbor.Tag is no-op. d.skip() return nil } t := d.nextCBORType() if t != cborTypeTag { d.skip() return &UnmarshalTypeError{CBORType: t.String(), GoType: typeTag.String()} } // Unmarshal tag number _, _, num := d.getHead() // Unmarshal tag content content, err := d.parse(false) if err != nil { return err } v.Set(reflect.ValueOf(Tag{num, content})) return nil } func (d *decoder) parseToTime() (tm time.Time, err error) { t := d.nextCBORType() // Verify that tag number or absence of tag number is acceptable to specified timeTag. if t == cborTypeTag { if d.dm.timeTag == DecTagIgnored { // Skip tag number for t == cborTypeTag { d.getHead() t = d.nextCBORType() } } else { // Read tag number _, _, tagNum := d.getHead() if tagNum != 0 && tagNum != 1 { d.skip() err = errors.New("cbor: wrong tag number for time.Time, got " + strconv.Itoa(int(tagNum)) + ", expect 0 or 1") return } } } else { if d.dm.timeTag == DecTagRequired { d.skip() err = &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String(), errorMsg: "expect CBOR tag value"} return } } var content interface{} content, err = d.parse(false) if err != nil { return } switch c := content.(type) { case nil: return case uint64: return time.Unix(int64(c), 0), nil case int64: return time.Unix(c, 0), nil case float64: if math.IsNaN(c) || math.IsInf(c, 0) { return } f1, f2 := math.Modf(c) return time.Unix(int64(f1), int64(f2*1e9)), nil case string: tm, err = time.Parse(time.RFC3339, c) if err != nil { tm = time.Time{} err = errors.New("cbor: cannot set " + c + " for time.Time: " + err.Error()) return } return default: err = &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String()} return } } // parseToUnmarshaler parses CBOR data to value implementing Unmarshaler interface. // It assumes data is well-formed, and does not perform bounds checking. func (d *decoder) parseToUnmarshaler(v reflect.Value) error { if d.nextCBORNil() && v.Kind() == reflect.Ptr && v.IsNil() { d.skip() return nil } if v.Kind() != reflect.Ptr && v.CanAddr() { v = v.Addr() } if u, ok := v.Interface().(Unmarshaler); ok { start := d.off d.skip() return u.UnmarshalCBOR(d.data[start:d.off]) } d.skip() return errors.New("cbor: failed to assert " + v.Type().String() + " as cbor.Unmarshaler") } // parse parses CBOR data and returns value in default Go type. // It assumes data is well-formed, and does not perform bounds checking. func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //nolint:gocyclo // Strip self-described CBOR tag number. if skipSelfDescribedTag { for d.nextCBORType() == cborTypeTag { off := d.off _, _, tagNum := d.getHead() if tagNum != selfDescribedCBORTagNum { d.off = off break } } } // Check validity of supported built-in tags. if d.nextCBORType() == cborTypeTag { off := d.off _, _, tagNum := d.getHead() if err := validBuiltinTag(tagNum, d.data[d.off]); err != nil { d.skip() return nil, err } d.off = off } t := d.nextCBORType() switch t { case cborTypePositiveInt: _, _, val := d.getHead() if d.dm.intDec == IntDecConvertNone { return val, nil } if val > math.MaxInt64 { return nil, &UnmarshalTypeError{ CBORType: t.String(), GoType: reflect.TypeOf(int64(0)).String(), errorMsg: strconv.FormatUint(val, 10) + " overflows Go's int64", } } return int64(val), nil case cborTypeNegativeInt: _, _, val := d.getHead() if val > math.MaxInt64 { // CBOR negative integer value overflows Go int64, use big.Int instead. bi := new(big.Int).SetUint64(val) bi.Add(bi, big.NewInt(1)) bi.Neg(bi) return *bi, nil } nValue := int64(-1) ^ int64(val) return nValue, nil case cborTypeByteString: return d.parseByteString(), nil case cborTypeTextString: b, err := d.parseTextString() if err != nil { return nil, err } return string(b), nil case cborTypeTag: tagOff := d.off _, _, tagNum := d.getHead() contentOff := d.off switch tagNum { case 0, 1: d.off = tagOff return d.parseToTime() case 2: b := d.parseByteString() bi := new(big.Int).SetBytes(b) return *bi, nil case 3: b := d.parseByteString() bi := new(big.Int).SetBytes(b) bi.Add(bi, big.NewInt(1)) bi.Neg(bi) return *bi, nil } if d.dm.tags != nil { // Parse to specified type if tag number is registered. tagNums := []uint64{tagNum} for d.nextCBORType() == cborTypeTag { _, _, num := d.getHead() tagNums = append(tagNums, num) } registeredType := d.dm.tags.getTypeFromTagNum(tagNums) if registeredType != nil { d.off = tagOff rv := reflect.New(registeredType) if err := d.parseToValue(rv.Elem(), getTypeInfo(registeredType)); err != nil { return nil, err } return rv.Elem().Interface(), nil } } // Parse tag content d.off = contentOff content, err := d.parse(false) if err != nil { return nil, err } return Tag{tagNum, content}, nil case cborTypePrimitives: _, ai, val := d.getHead() if ai < 20 || ai == 24 { return val, nil } switch ai { case 20, 21: return (ai == 21), nil case 22, 23: return nil, nil case 25: f := float64(float16.Frombits(uint16(val)).Float32()) return f, nil case 26: f := float64(math.Float32frombits(uint32(val))) return f, nil case 27: f := math.Float64frombits(val) return f, nil } case cborTypeArray: return d.parseArray() case cborTypeMap: return d.parseMap() } return nil, nil } // parseByteString parses CBOR encoded byte string. It returns a byte slice // pointing to a copy of parsed data. func (d *decoder) parseByteString() []byte { _, ai, val := d.getHead() if ai != 31 { b := make([]byte, int(val)) copy(b, d.data[d.off:d.off+int(val)]) d.off += int(val) return b } // Process indefinite length string chunks. b := []byte{} for !d.foundBreak() { _, _, val = d.getHead() b = append(b, d.data[d.off:d.off+int(val)]...) d.off += int(val) } return b } // parseTextString parses CBOR encoded text string. It returns a byte slice // to prevent creating an extra copy of string. Caller should wrap returned // byte slice as string when needed. func (d *decoder) parseTextString() ([]byte, error) { _, ai, val := d.getHead() if ai != 31 { b := d.data[d.off : d.off+int(val)] d.off += int(val) if !utf8.Valid(b) { return nil, &SemanticError{"cbor: invalid UTF-8 string"} } return b, nil } // Process indefinite length string chunks. b := []byte{} for !d.foundBreak() { _, _, val = d.getHead() x := d.data[d.off : d.off+int(val)] d.off += int(val) if !utf8.Valid(x) { for !d.foundBreak() { d.skip() // Skip remaining chunk on error } return nil, &SemanticError{"cbor: invalid UTF-8 string"} } b = append(b, x...) } return b, nil } func (d *decoder) parseArray() ([]interface{}, error) { _, ai, val := d.getHead() hasSize := (ai != 31) count := int(val) if !hasSize { count = d.numOfItemsUntilBreak() // peek ahead to get array size to preallocate slice for better performance } v := make([]interface{}, count) var e interface{} var err, lastErr error for i := 0; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ { if e, lastErr = d.parse(true); lastErr != nil { if err == nil { err = lastErr } continue } v[i] = e } return v, err } func (d *decoder) parseArrayToSlice(v reflect.Value, tInfo *typeInfo) error { _, ai, val := d.getHead() hasSize := (ai != 31) count := int(val) if !hasSize { count = d.numOfItemsUntilBreak() // peek ahead to get array size to preallocate slice for better performance } if v.IsNil() || v.Cap() < count || count == 0 { v.Set(reflect.MakeSlice(tInfo.nonPtrType, count, count)) } v.SetLen(count) var err error for i := 0; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ { if lastErr := d.parseToValue(v.Index(i), tInfo.elemTypeInfo); lastErr != nil { if err == nil { err = lastErr } } } return err } func (d *decoder) parseArrayToArray(v reflect.Value, tInfo *typeInfo) error { _, ai, val := d.getHead() hasSize := (ai != 31) count := int(val) gi := 0 vLen := v.Len() var err error for ci := 0; (hasSize && ci < count) || (!hasSize && !d.foundBreak()); ci++ { if gi < vLen { // Read CBOR array element and set array element if lastErr := d.parseToValue(v.Index(gi), tInfo.elemTypeInfo); lastErr != nil { if err == nil { err = lastErr } } gi++ } else { d.skip() // Skip remaining CBOR array element } } // Set remaining Go array elements to zero values. if gi < vLen { zeroV := reflect.Zero(tInfo.elemTypeInfo.typ) for ; gi < vLen; gi++ { v.Index(gi).Set(zeroV) } } return err } func (d *decoder) parseMap() (map[interface{}]interface{}, error) { _, ai, val := d.getHead() hasSize := (ai != 31) count := int(val) m := make(map[interface{}]interface{}) var k, e interface{} var err, lastErr error keyCount := 0 for i := 0; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ { // Parse CBOR map key. if k, lastErr = d.parse(true); lastErr != nil { if err == nil { err = lastErr } d.skip() continue } // Detect if CBOR map key can be used as Go map key. rv := reflect.ValueOf(k) if !isHashableValue(rv) { if err == nil { err = errors.New("cbor: invalid map key type: " + rv.Type().String()) } d.skip() continue } // Parse CBOR map value. if e, lastErr = d.parse(true); lastErr != nil { if err == nil { err = lastErr } continue } // Add key-value pair to Go map. m[k] = e // Detect duplicate map key. if d.dm.dupMapKey == DupMapKeyEnforcedAPF { newKeyCount := len(m) if newKeyCount == keyCount { m[k] = nil err = &DupMapKeyError{k, i} i++ // skip the rest of the map for ; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ { d.skip() // Skip map key d.skip() // Skip map value } return m, err } keyCount = newKeyCount } } return m, err } func (d *decoder) parseMapToMap(v reflect.Value, tInfo *typeInfo) error { //nolint:gocyclo _, ai, val := d.getHead() hasSize := (ai != 31) count := int(val) if v.IsNil() { mapsize := count if !hasSize { mapsize = 0 } v.Set(reflect.MakeMapWithSize(tInfo.nonPtrType, mapsize)) } keyType, eleType := tInfo.keyTypeInfo.typ, tInfo.elemTypeInfo.typ reuseKey, reuseEle := isImmutableKind(tInfo.keyTypeInfo.kind), isImmutableKind(tInfo.elemTypeInfo.kind) var keyValue, eleValue, zeroKeyValue, zeroEleValue reflect.Value keyIsInterfaceType := keyType == typeIntf // If key type is interface{}, need to check if key value is hashable. var err, lastErr error keyCount := v.Len() var existingKeys map[interface{}]bool // Store existing map keys, used for detecting duplicate map key. if d.dm.dupMapKey == DupMapKeyEnforcedAPF { existingKeys = make(map[interface{}]bool, keyCount) if keyCount > 0 { vKeys := v.MapKeys() for i := 0; i < len(vKeys); i++ { existingKeys[vKeys[i].Interface()] = true } } } for i := 0; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ { // Parse CBOR map key. if !keyValue.IsValid() { keyValue = reflect.New(keyType).Elem() } else if !reuseKey { if !zeroKeyValue.IsValid() { zeroKeyValue = reflect.Zero(keyType) } keyValue.Set(zeroKeyValue) } if lastErr = d.parseToValue(keyValue, tInfo.keyTypeInfo); lastErr != nil { if err == nil { err = lastErr } d.skip() continue } // Detect if CBOR map key can be used as Go map key. if keyIsInterfaceType && keyValue.Elem().IsValid() { if !isHashableValue(keyValue.Elem()) { if err == nil { err = errors.New("cbor: invalid map key type: " + keyValue.Elem().Type().String()) } d.skip() continue } } // Parse CBOR map value. if !eleValue.IsValid() { eleValue = reflect.New(eleType).Elem() } else if !reuseEle { if !zeroEleValue.IsValid() { zeroEleValue = reflect.Zero(eleType) } eleValue.Set(zeroEleValue) } if lastErr := d.parseToValue(eleValue, tInfo.elemTypeInfo); lastErr != nil { if err == nil { err = lastErr } continue } // Add key-value pair to Go map. v.SetMapIndex(keyValue, eleValue) // Detect duplicate map key. if d.dm.dupMapKey == DupMapKeyEnforcedAPF { newKeyCount := v.Len() if newKeyCount == keyCount { kvi := keyValue.Interface() if !existingKeys[kvi] { v.SetMapIndex(keyValue, reflect.New(eleType).Elem()) err = &DupMapKeyError{kvi, i} i++ // skip the rest of the map for ; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ { d.skip() // skip map key d.skip() // skip map value } return err } delete(existingKeys, kvi) } keyCount = newKeyCount } } return err } func (d *decoder) parseArrayToStruct(v reflect.Value, tInfo *typeInfo) error { structType := getDecodingStructType(tInfo.nonPtrType) if structType.err != nil { return structType.err } if !structType.toArray { t := d.nextCBORType() d.skip() return &UnmarshalTypeError{ CBORType: t.String(), GoType: tInfo.nonPtrType.String(), errorMsg: "cannot decode CBOR array to struct without toarray option", } } start := d.off t, ai, val := d.getHead() hasSize := (ai != 31) count := int(val) if !hasSize { count = d.numOfItemsUntilBreak() // peek ahead to get array size } if count != len(structType.fields) { d.off = start d.skip() return &UnmarshalTypeError{ CBORType: t.String(), GoType: tInfo.typ.String(), errorMsg: "cannot decode CBOR array to struct with different number of elements", } } var err, lastErr error for i := 0; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ { f := structType.fields[i] // Get field value by index var fv reflect.Value if len(f.idx) == 1 { fv = v.Field(f.idx[0]) } else { fv, lastErr = getFieldValue(v, f.idx, func(v reflect.Value) (reflect.Value, error) { // Return a new value for embedded field null pointer to point to, or return error. if !v.CanSet() { return reflect.Value{}, errors.New("cbor: cannot set embedded pointer to unexported struct: " + v.Type().String()) } v.Set(reflect.New(v.Type().Elem())) return v, nil }) if lastErr != nil && err == nil { err = lastErr } if !fv.IsValid() { d.skip() continue } } if lastErr = d.parseToValue(fv, f.typInfo); lastErr != nil { if err == nil { if typeError, ok := lastErr.(*UnmarshalTypeError); ok { typeError.StructFieldName = tInfo.typ.String() + "." + f.name err = typeError } else { err = lastErr } } } } return err } // parseMapToStruct needs to be fast so gocyclo can be ignored for now. func (d *decoder) parseMapToStruct(v reflect.Value, tInfo *typeInfo) error { //nolint:gocyclo structType := getDecodingStructType(tInfo.nonPtrType) if structType.err != nil { return structType.err } if structType.toArray { t := d.nextCBORType() d.skip() return &UnmarshalTypeError{ CBORType: t.String(), GoType: tInfo.nonPtrType.String(), errorMsg: "cannot decode CBOR map to struct with toarray option", } } var err, lastErr error // Get CBOR map size _, ai, val := d.getHead() hasSize := (ai != 31) count := int(val) // Keeps track of matched struct fields foundFldIdx := make([]bool, len(structType.fields)) // Keeps track of CBOR map keys to detect duplicate map key keyCount := 0 var mapKeys map[interface{}]struct{} if d.dm.dupMapKey == DupMapKeyEnforcedAPF { mapKeys = make(map[interface{}]struct{}, len(structType.fields)) } errOnUnknownField := (d.dm.extraReturnErrors & ExtraDecErrorUnknownField) > 0 for j := 0; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ { var f *field var k interface{} // Used by duplicate map key detection t := d.nextCBORType() if t == cborTypeTextString { var keyBytes []byte keyBytes, lastErr = d.parseTextString() if lastErr != nil { if err == nil { err = lastErr } d.skip() // skip value continue } keyLen := len(keyBytes) // Find field with exact match for i := 0; i < len(structType.fields); i++ { fld := structType.fields[i] if !foundFldIdx[i] && len(fld.name) == keyLen && fld.name == string(keyBytes) { f = fld foundFldIdx[i] = true break } } // Find field with case-insensitive match if f == nil { keyString := string(keyBytes) for i := 0; i < len(structType.fields); i++ { fld := structType.fields[i] if !foundFldIdx[i] && len(fld.name) == keyLen && strings.EqualFold(fld.name, keyString) { f = fld foundFldIdx[i] = true break } } } if d.dm.dupMapKey == DupMapKeyEnforcedAPF { k = string(keyBytes) } } else if t <= cborTypeNegativeInt { // uint/int var nameAsInt int64 if t == cborTypePositiveInt { _, _, val := d.getHead() nameAsInt = int64(val) } else { _, _, val := d.getHead() if val > math.MaxInt64 { if err == nil { err = &UnmarshalTypeError{ CBORType: t.String(), GoType: reflect.TypeOf(int64(0)).String(), errorMsg: "-1-" + strconv.FormatUint(val, 10) + " overflows Go's int64", } } d.skip() // skip value continue } nameAsInt = int64(-1) ^ int64(val) } // Find field for i := 0; i < len(structType.fields); i++ { fld := structType.fields[i] if !foundFldIdx[i] && fld.keyAsInt && fld.nameAsInt == nameAsInt { f = fld foundFldIdx[i] = true break } } if d.dm.dupMapKey == DupMapKeyEnforcedAPF { k = nameAsInt } } else { if err == nil { err = &UnmarshalTypeError{ CBORType: t.String(), GoType: reflect.TypeOf("").String(), errorMsg: "map key is of type " + t.String() + " and cannot be used to match struct field name", } } if d.dm.dupMapKey == DupMapKeyEnforcedAPF { // parse key k, lastErr = d.parse(true) if lastErr != nil { d.skip() // skip value continue } // Detect if CBOR map key can be used as Go map key. if !isHashableValue(reflect.ValueOf(k)) { d.skip() // skip value continue } } else { d.skip() // skip key } } if d.dm.dupMapKey == DupMapKeyEnforcedAPF { mapKeys[k] = struct{}{} newKeyCount := len(mapKeys) if newKeyCount == keyCount { err = &DupMapKeyError{k, j} d.skip() // skip value j++ // skip the rest of the map for ; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ { d.skip() d.skip() } return err } keyCount = newKeyCount } if f == nil { if errOnUnknownField { err = &UnknownFieldError{j} d.skip() // Skip value j++ // skip the rest of the map for ; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ { d.skip() d.skip() } return err } d.skip() // Skip value continue } // Get field value by index var fv reflect.Value if len(f.idx) == 1 { fv = v.Field(f.idx[0]) } else { fv, lastErr = getFieldValue(v, f.idx, func(v reflect.Value) (reflect.Value, error) { // Return a new value for embedded field null pointer to point to, or return error. if !v.CanSet() { return reflect.Value{}, errors.New("cbor: cannot set embedded pointer to unexported struct: " + v.Type().String()) } v.Set(reflect.New(v.Type().Elem())) return v, nil }) if lastErr != nil && err == nil { err = lastErr } if !fv.IsValid() { d.skip() continue } } if lastErr = d.parseToValue(fv, f.typInfo); lastErr != nil { if err == nil { if typeError, ok := lastErr.(*UnmarshalTypeError); ok { typeError.StructFieldName = tInfo.nonPtrType.String() + "." + f.name err = typeError } else { err = lastErr } } } } return err } // validRegisteredTagNums verifies that tag numbers match registered tag numbers of type t. // validRegisteredTagNums assumes next CBOR data type is tag. It scans all tag numbers, and stops at tag content. func (d *decoder) validRegisteredTagNums(registeredTag *tagItem) error { // Scan until next cbor data is tag content. tagNums := make([]uint64, 0, 1) for d.nextCBORType() == cborTypeTag { _, _, val := d.getHead() tagNums = append(tagNums, val) } if !registeredTag.equalTagNum(tagNums) { return &WrongTagError{registeredTag.contentType, registeredTag.num, tagNums} } return nil } func (d *decoder) getRegisteredTagItem(vt reflect.Type) *tagItem { if d.dm.tags != nil { return d.dm.tags.getTagItemFromType(vt) } return nil } // skip moves data offset to the next item. skip assumes data is well-formed, // and does not perform bounds checking. func (d *decoder) skip() { t, ai, val := d.getHead() if ai == 31 { switch t { case cborTypeByteString, cborTypeTextString, cborTypeArray, cborTypeMap: for { if d.data[d.off] == 0xff { d.off++ return } d.skip() } } } switch t { case cborTypeByteString, cborTypeTextString: d.off += int(val) case cborTypeArray: for i := 0; i < int(val); i++ { d.skip() } case cborTypeMap: for i := 0; i < int(val)*2; i++ { d.skip() } case cborTypeTag: d.skip() } } // getHead assumes data is well-formed, and does not perform bounds checking. func (d *decoder) getHead() (t cborType, ai byte, val uint64) { t = cborType(d.data[d.off] & 0xe0) ai = d.data[d.off] & 0x1f val = uint64(ai) d.off++ if ai < 24 { return } if ai == 24 { val = uint64(d.data[d.off]) d.off++ return } if ai == 25 { val = uint64(binary.BigEndian.Uint16(d.data[d.off : d.off+2])) d.off += 2 return } if ai == 26 { val = uint64(binary.BigEndian.Uint32(d.data[d.off : d.off+4])) d.off += 4 return } if ai == 27 { val = binary.BigEndian.Uint64(d.data[d.off : d.off+8]) d.off += 8 return } return } func (d *decoder) numOfItemsUntilBreak() int { savedOff := d.off i := 0 for !d.foundBreak() { d.skip() i++ } d.off = savedOff return i } // foundBreak assumes data is well-formed, and does not perform bounds checking. func (d *decoder) foundBreak() bool { if d.data[d.off] == 0xff { d.off++ return true } return false } func (d *decoder) reset(data []byte) { d.data = data d.off = 0 } func (d *decoder) nextCBORType() cborType { return cborType(d.data[d.off] & 0xe0) } func (d *decoder) nextCBORNil() bool { return d.data[d.off] == 0xf6 || d.data[d.off] == 0xf7 } var ( typeIntf = reflect.TypeOf([]interface{}(nil)).Elem() typeTime = reflect.TypeOf(time.Time{}) typeBigInt = reflect.TypeOf(big.Int{}) typeUnmarshaler = reflect.TypeOf((*Unmarshaler)(nil)).Elem() typeBinaryUnmarshaler = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem() ) func fillNil(t cborType, v reflect.Value) error { switch v.Kind() { case reflect.Slice, reflect.Map, reflect.Interface, reflect.Ptr: v.Set(reflect.Zero(v.Type())) return nil } return nil } func fillPositiveInt(t cborType, val uint64, v reflect.Value) error { switch v.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if val > math.MaxInt64 { return &UnmarshalTypeError{ CBORType: t.String(), GoType: v.Type().String(), errorMsg: strconv.FormatUint(val, 10) + " overflows " + v.Type().String(), } } if v.OverflowInt(int64(val)) { return &UnmarshalTypeError{ CBORType: t.String(), GoType: v.Type().String(), errorMsg: strconv.FormatUint(val, 10) + " overflows " + v.Type().String(), } } v.SetInt(int64(val)) return nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: if v.OverflowUint(val) { return &UnmarshalTypeError{ CBORType: t.String(), GoType: v.Type().String(), errorMsg: strconv.FormatUint(val, 10) + " overflows " + v.Type().String(), } } v.SetUint(val) return nil case reflect.Float32, reflect.Float64: f := float64(val) v.SetFloat(f) return nil } if v.Type() == typeBigInt { i := new(big.Int).SetUint64(val) v.Set(reflect.ValueOf(*i)) return nil } return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()} } func fillNegativeInt(t cborType, val int64, v reflect.Value) error { switch v.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if v.OverflowInt(val) { return &UnmarshalTypeError{ CBORType: t.String(), GoType: v.Type().String(), errorMsg: strconv.FormatInt(val, 10) + " overflows " + v.Type().String(), } } v.SetInt(val) return nil case reflect.Float32, reflect.Float64: f := float64(val) v.SetFloat(f) return nil } if v.Type() == typeBigInt { i := new(big.Int).SetInt64(val) v.Set(reflect.ValueOf(*i)) return nil } return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()} } func fillBool(t cborType, val bool, v reflect.Value) error { if v.Kind() == reflect.Bool { v.SetBool(val) return nil } return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()} } func fillFloat(t cborType, val float64, v reflect.Value) error { switch v.Kind() { case reflect.Float32, reflect.Float64: if v.OverflowFloat(val) { return &UnmarshalTypeError{ CBORType: t.String(), GoType: v.Type().String(), errorMsg: strconv.FormatFloat(val, 'E', -1, 64) + " overflows " + v.Type().String(), } } v.SetFloat(val) return nil } return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()} } func fillByteString(t cborType, val []byte, v reflect.Value) error { if reflect.PtrTo(v.Type()).Implements(typeBinaryUnmarshaler) { if v.CanAddr() { v = v.Addr() if u, ok := v.Interface().(encoding.BinaryUnmarshaler); ok { return u.UnmarshalBinary(val) } } return errors.New("cbor: cannot set new value for " + v.Type().String()) } if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 { v.SetBytes(val) return nil } if v.Kind() == reflect.Array && v.Type().Elem().Kind() == reflect.Uint8 { vLen := v.Len() i := 0 for ; i < vLen && i < len(val); i++ { v.Index(i).SetUint(uint64(val[i])) } // Set remaining Go array elements to zero values. if i < vLen { zeroV := reflect.Zero(reflect.TypeOf(byte(0))) for ; i < vLen; i++ { v.Index(i).Set(zeroV) } } return nil } return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()} } func fillTextString(t cborType, val []byte, v reflect.Value) error { if v.Kind() == reflect.String { v.SetString(string(val)) return nil } return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()} } func isImmutableKind(k reflect.Kind) bool { switch k { case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String: return true default: return false } } func isHashableValue(rv reflect.Value) bool { switch rv.Kind() { case reflect.Slice, reflect.Map, reflect.Func: return false case reflect.Struct: switch rv.Type() { case typeTag: tag := rv.Interface().(Tag) return isHashableValue(reflect.ValueOf(tag.Content)) case typeBigInt: return false } } return true } // validBuiltinTag checks that supported built-in tag numbers are followed by expected content types. func validBuiltinTag(tagNum uint64, contentHead byte) error { t := cborType(contentHead & 0xe0) switch tagNum { case 0: // Tag content (date/time text string in RFC 3339 format) must be string type. if t != cborTypeTextString { return errors.New("cbor: tag number 0 must be followed by text string, got " + t.String()) } return nil case 1: // Tag content (epoch date/time) must be uint, int, or float type. if t != cborTypePositiveInt && t != cborTypeNegativeInt && (contentHead < 0xf9 || contentHead > 0xfb) { return errors.New("cbor: tag number 1 must be followed by integer or floating-point number, got " + t.String()) } return nil case 2, 3: // Tag content (bignum) must be byte type. if t != cborTypeByteString { return errors.New("cbor: tag number 2 or 3 must be followed by byte string, got " + t.String()) } return nil } return nil }