tive { keyLen := len(keyBytes) keyString := string(keyBytes) for i := 0; i < len(structType.fields); i++ { fld := structType.fields[i] if len(fld.name) == keyLen && strings.EqualFold(fld.name, keyString) { if !foundFldIdx[i] { f = fld foundFldIdx[i] = true } else if d.dm.dupMapKey == DupMapKeyEnforcedAPF { err = &DupMapKeyError{keyString, 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 } else { // discard repeated match d.skip() continue MapEntryLoop } break } } } if d.dm.dupMapKey == DupMapKeyEnforcedAPF && f == nil { 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 fld.keyAsInt && fld.nameAsInt == nameAsInt { if !foundFldIdx[i] { f = fld foundFldIdx[i] = true } else if d.dm.dupMapKey == DupMapKeyEnforcedAPF { err = &DupMapKeyError{nameAsInt, 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 } else { // discard repeated match d.skip() continue MapEntryLoop } break } } if d.dm.dupMapKey == DupMapKeyEnforcedAPF && f == nil { 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 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 } // Two map keys that match the same struct field are immediately considered // duplicates. This check detects duplicates between two map keys that do // not match a struct field. If unknown field errors are enabled, then this // check is never reached. if d.dm.dupMapKey == DupMapKeyEnforcedAPF { if mapKeys == nil { mapKeys = make(map[any]struct{}, 1) } 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 } 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, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() if indefiniteLength { switch t { case cborTypeByteString, cborTypeTextString, cborTypeArray, cborTypeMap: for { if isBreakFlag(d.data[d.off]) { 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() } } func (d *decoder) getHeadWithIndefiniteLengthFlag() ( t cborType, ai byte, val uint64, indefiniteLength bool, ) { t, ai, val = d.getHead() indefiniteLength = additionalInformation(ai).isIndefiniteLength() return } // getHead assumes data is well-formed, and does not perform bounds checking. func (d *decoder) getHead() (t cborType, ai byte, val uint64) { t, ai = parseInitialByte(d.data[d.off]) val = uint64(ai) d.off++ if ai <= maxAdditionalInformationWithoutArgument { return } if ai == additionalInformationWith1ByteArgument { val = uint64(d.data[d.off]) d.off++ return } if ai == additionalInformationWith2ByteArgument { const argumentSize = 2 val = uint64(binary.BigEndian.Uint16(d.data[d.off : d.off+argumentSize])) d.off += argumentSize return } if ai == additionalInformationWith4ByteArgument { const argumentSize = 4 val = uint64(binary.BigEndian.Uint32(d.data[d.off : d.off+argumentSize])) d.off += argumentSize return } if ai == additionalInformationWith8ByteArgument { const argumentSize = 8 val = binary.BigEndian.Uint64(d.data[d.off : d.off+argumentSize]) d.off += argumentSize return } return } func (d *decoder) numOfItemsUntilBreak() int { savedOff := d.off i := 0 for !d.foundBreak() { d.skip() i++ } d.off = savedOff return i } // foundBreak returns true if next byte is CBOR break code and moves cursor by 1, // otherwise it returns false. // foundBreak assumes data is well-formed, and does not perform bounds checking. func (d *decoder) foundBreak() bool { if isBreakFlag(d.data[d.off]) { d.off++ return true } return false } func (d *decoder) reset(data []byte) { d.data = data d.off = 0 d.expectedLaterEncodingTags = d.expectedLaterEncodingTags[:0] } func (d *decoder) nextCBORType() cborType { return getType(d.data[d.off]) } func (d *decoder) nextCBORNil() bool { return d.data[d.off] == 0xf6 || d.data[d.off] == 0xf7 } type jsonUnmarshaler interface{ UnmarshalJSON([]byte) error } var ( typeIntf = reflect.TypeOf([]any(nil)).Elem() typeTime = reflect.TypeOf(time.Time{}) typeBigInt = reflect.TypeOf(big.Int{}) typeUnmarshaler = reflect.TypeOf((*Unmarshaler)(nil)).Elem() typeUnexportedUnmarshaler = reflect.TypeOf((*unmarshaler)(nil)).Elem() typeBinaryUnmarshaler = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem() typeTextUnmarshaler = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() typeJSONUnmarshaler = reflect.TypeOf((*jsonUnmarshaler)(nil)).Elem() typeString = reflect.TypeOf("") typeByteSlice = reflect.TypeOf([]byte(nil)) ) func fillNil(_ cborType, v reflect.Value) error { switch v.Kind() { case reflect.Slice, reflect.Map, reflect.Interface, reflect.Pointer: v.SetZero() 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, shared bool, v reflect.Value, bsts ByteStringToStringMode, bum BinaryUnmarshalerMode, tum TextUnmarshalerMode) error { if bum == BinaryUnmarshalerByteString && reflect.PointerTo(v.Type()).Implements(typeBinaryUnmarshaler) { if v.CanAddr() { v = v.Addr() if u, ok := v.Interface().(encoding.BinaryUnmarshaler); ok { // The contract of BinaryUnmarshaler forbids // retaining the input bytes, so no copying is // required even if val is shared. return u.UnmarshalBinary(val) } } return errors.New("cbor: cannot set new value for " + v.Type().String()) } if bsts != ByteStringToStringForbidden { if tum == TextUnmarshalerTextString && reflect.PointerTo(v.Type()).Implements(typeTextUnmarshaler) { if v.CanAddr() { v = v.Addr() if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { // The contract of TextUnmarshaler forbids retaining the input // bytes, so no copying is required even if val is shared. if err := u.UnmarshalText(val); err != nil { return fmt.Errorf("cbor: cannot unmarshal text for %s: %w", v.Type(), err) } return nil } } return errors.New("cbor: cannot set new value for " + v.Type().String()) } if v.Kind() == reflect.String { v.SetString(string(val)) return nil } } if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 { src := val if shared { // SetBytes shares the underlying bytes of the source slice. src = make([]byte, len(val)) copy(src, val) } v.SetBytes(src) 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 { for ; i < vLen; i++ { v.Index(i).SetZero() } } return nil } return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()} } func fillTextString(t cborType, val []byte, v reflect.Value, tum TextUnmarshalerMode) error { // Check if the value implements TextUnmarshaler and the mode allows it if tum == TextUnmarshalerTextString && reflect.PointerTo(v.Type()).Implements(typeTextUnmarshaler) { if v.CanAddr() { v = v.Addr() if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { // The contract of TextUnmarshaler forbids retaining the input // bytes, so no copying is required even if val is shared. if err := u.UnmarshalText(val); err != nil { return fmt.Errorf("cbor: cannot unmarshal text for %s: %w", v.Type(), err) } return nil } } return errors.New("cbor: cannot set new value for " + v.Type().String()) } 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 } // convertByteSliceToByteString converts []byte to ByteString if // - v is []byte type, or // - v is Tag type and tag content type is []byte // This function also handles nested tags. // CBOR data is already verified to be well-formed before this function is used, // so the recursion won't exceed max nested levels. func convertByteSliceToByteString(v any) (any, bool) { switch v := v.(type) { case []byte: return ByteString(v), true case Tag: content, converted := convertByteSliceToByteString(v.Content) if converted { return Tag{Number: v.Number, Content: content}, true } } return v, false }