Update dependencies

This commit is contained in:
bluepython508
2025-04-09 01:00:12 +01:00
parent f0641ffd6e
commit 5a9cfc022c
882 changed files with 68930 additions and 24201 deletions

View File

@@ -1,12 +1,26 @@
# Do not delete linter settings. Linters like gocritic can be enabled on the command line.
linters-settings:
depguard:
rules:
prevent_unmaintained_packages:
list-mode: strict
files:
- $all
- "!$test"
allow:
- $gostd
- github.com/x448/float16
deny:
- pkg: io/ioutil
desc: "replaced by io and os packages since Go 1.16: https://tip.golang.org/doc/go1.16#ioutil"
dupl:
threshold: 100
funlen:
lines: 100
statements: 50
goconst:
ignore-tests: true
min-len: 2
min-occurrences: 3
gocritic:
@@ -17,12 +31,12 @@ linters-settings:
- performance
- style
disabled-checks:
- commentedOutCode
- dupImport # https://github.com/go-critic/go-critic/issues/845
- ifElseChain
- octalLiteral
- paramTypeCombine
- whyNoLint
- wrapperFunc
gofmt:
simplify: false
goimports:
@@ -37,22 +51,32 @@ linters-settings:
suggest-new: true
misspell:
locale: US
staticcheck:
checks: ["all"]
linters:
disable-all: true
enable:
- asciicheck
- bidichk
- depguard
- errcheck
- exportloopref
- goconst
- gocritic
- gocyclo
- gofmt
- goimports
- goprintffuncname
- gosec
- gosimple
- govet
- ineffassign
- misspell
- nilerr
- revive
- staticcheck
- stylecheck
- typecheck
- unconvert
- unused
@@ -62,16 +86,19 @@ issues:
max-issues-per-linter: 0
# max-same-issues default is 3. Set to 0 to disable limit.
max-same-issues: 0
# Excluding configuration per-path, per-linter, per-text and per-source
exclude-rules:
- path: _test\.go
linters:
- goconst
- dupl
- gomnd
- lll
- path: doc\.go
linters:
- goimports
- gomnd
- lll
- path: decode.go
text: "string ` overflows ` has (\\d+) occurrences, make it a constant"
- path: decode.go
text: "string ` \\(range is \\[` has (\\d+) occurrences, make it a constant"
- path: decode.go
text: "string `, ` has (\\d+) occurrences, make it a constant"
- path: decode.go
text: "string ` overflows Go's int64` has (\\d+) occurrences, make it a constant"
- path: decode.go
text: "string `\\]\\)` has (\\d+) occurrences, make it a constant"
- path: valid.go
text: "string ` for type ` has (\\d+) occurrences, make it a constant"
- path: valid.go
text: "string `cbor: ` has (\\d+) occurrences, make it a constant"

View File

@@ -6,9 +6,9 @@
CBOR is a [trusted alternative](https://www.rfc-editor.org/rfc/rfc8949.html#name-comparison-of-other-binary-) to JSON, MessagePack, Protocol Buffers, etc.  CBOR is an Internet Standard defined by [IETF STD 94 (RFC 8949)](https://www.rfc-editor.org/info/std94) and is designed to be relevant for decades.
`fxamacker/cbor` is used in projects by Arm Ltd., Cisco, Dapper Labs, EdgeX Foundry, Fraunhofer‑AISEC, Let's Encrypt (ISRG), Linux Foundation, Microsoft, Mozilla, Oasis Protocol, Tailscale, Teleport, [and others](https://github.com/fxamacker/cbor#who-uses-fxamackercbor).
`fxamacker/cbor` is used in projects by Arm Ltd., Cisco, EdgeX Foundry, Flow Foundation, Fraunhofer‑AISEC, Kubernetes, Let's Encrypt (ISRG), Linux Foundation, Microsoft, Mozilla, Oasis Protocol, Tailscale, Teleport, [etc](https://github.com/fxamacker/cbor#who-uses-fxamackercbor).
See [Quick Start](#quick-start) and [Releases](https://github.com/fxamacker/cbor/releases/). 🆕 `UnmarshalFirst` and `DiagnoseFirst` can decode CBOR Sequences.
See [Quick Start](#quick-start) and [Releases](https://github.com/fxamacker/cbor/releases/). 🆕 `UnmarshalFirst` and `DiagnoseFirst` can decode CBOR Sequences. `cbor.MarshalToBuffer()` and `UserBufferEncMode` accepts user-specified buffer.
## fxamacker/cbor
@@ -17,7 +17,6 @@ See [Quick Start](#quick-start) and [Releases](https://github.com/fxamacker
[![CodeQL](https://github.com/fxamacker/cbor/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/fxamacker/cbor/actions/workflows/codeql-analysis.yml)
[![](https://img.shields.io/badge/fuzzing-passing-44c010)](#fuzzing-and-code-coverage)
[![Go Report Card](https://goreportcard.com/badge/github.com/fxamacker/cbor)](https://goreportcard.com/report/github.com/fxamacker/cbor)
[![](https://img.shields.io/ossf-scorecard/github.com/fxamacker/cbor?label=openssf%20scorecard)](https://github.com/fxamacker/cbor#fuzzing-and-code-coverage)
`fxamacker/cbor` is a CBOR codec in full conformance with [IETF STD 94 (RFC 8949)](https://www.rfc-editor.org/info/std94). It also supports CBOR Sequences ([RFC 8742](https://www.rfc-editor.org/rfc/rfc8742.html)) and Extended Diagnostic Notation ([Appendix G of RFC 8610](https://www.rfc-editor.org/rfc/rfc8610.html#appendix-G)).
@@ -221,7 +220,7 @@ __Install__: `go get github.com/fxamacker/cbor/v2` and `import "github.com/fxama
This library can encode and decode CBOR (RFC 8949) and CBOR Sequences (RFC 8742).
- __CBOR data item__ is a single piece of CBOR data and its structure may contain zero, one, or more nested data items.
- __CBOR data item__ is a single piece of CBOR data and its structure may contain 0 or more nested data items.
- __CBOR sequence__ is a concatenation of 0 or more encoded CBOR data items.
Configurable limits and options can be used to balance trade-offs.
@@ -242,6 +241,9 @@ err = cbor.Unmarshal(b, &v) // decode []byte b to v
decoder = cbor.NewDecoder(r) // create decoder with io.Reader r
err = decoder.Decode(&v) // decode a CBOR data item to v
// v2.7.0 added MarshalToBuffer() and UserBufferEncMode interface.
err = cbor.MarshalToBuffer(v, b) // encode v to b instead of using built-in buf pool.
// v2.5.0 added new functions that return remaining bytes.
// UnmarshalFirst decodes first CBOR data item and returns remaining bytes.
@@ -297,6 +299,17 @@ err := encoder.Encode(v) // encode v to io.Writer w
Default mode and custom modes automatically apply struct tags.
### User Specified Buffer for Encoding (v2.7.0)
`UserBufferEncMode` interface extends `EncMode` interface to add `MarshalToBuffer()`. It accepts a user-specified buffer instead of using built-in buffer pool.
```Go
em, err := myEncOptions.UserBufferEncMode() // create UserBufferEncMode mode
var buf bytes.Buffer
err = em.MarshalToBuffer(v, &buf) // encode v to provided buf
```
### Struct Tags
Struct tags (`toarray`, `keyasint`, `omitempty`) reduce encoded size of structs.
@@ -459,12 +472,14 @@ Default limits may need to be increased for systems handling very large data (e.
## Status
v2.6.0 (February 2024) adds important new features, optimizations, and bug fixes. It is especially useful to systems that need to convert data between CBOR and JSON. New options and optimizations improve handling of bignum, integers, maps, and strings.
v2.7.0 (June 23, 2024) adds features and improvements that help large projects (e.g. Kubernetes) use CBOR as an alternative to JSON and Protocol Buffers. Other improvements include speedups, improved memory use, bug fixes, new serialization options, etc. It passed fuzz tests (5+ billion executions) and is production quality.
For more details, see [release notes](https://github.com/fxamacker/cbor/releases).
### Prior Release
[v2.6.0](https://github.com/fxamacker/cbor/releases/tag/v2.6.0) (February 2024) adds important new features, optimizations, and bug fixes. It is especially useful to systems that need to convert data between CBOR and JSON. New options and optimizations improve handling of bignum, integers, maps, and strings.
v2.5.0 was released on Sunday, August 13, 2023 with new features and important bug fixes. It is fuzz tested and production quality after extended beta [v2.5.0-beta](https://github.com/fxamacker/cbor/releases/tag/v2.5.0-beta) (Dec 2022) -> [v2.5.0](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) (Aug 2023).
__IMPORTANT__: 👉 Before upgrading from v2.4 or older release, please read the notable changes highlighted in the release notes. v2.5.0 is a large release with bug fixes to error handling for extraneous data in `Unmarshal`, etc. that should be reviewed before upgrading.
@@ -534,7 +549,7 @@ geomean 2.782
## Who uses fxamacker/cbor
`fxamacker/cbor` is used in projects by Arm Ltd., Berlin Institute of Health at Charité, Chainlink, Cisco, Confidential Computing Consortium, ConsenSys, Dapper Labs, EdgeX Foundry, F5, FIDO Alliance, Fraunhofer‑AISEC, Let's Encrypt (ISRG), Linux Foundation, Matrix.org, Microsoft, Mozilla, National Cybersecurity Agency of France (govt), Netherlands (govt), Oasis Protocol, Smallstep, Tailscale, Taurus SA, Teleport, TIBCO, and others.
`fxamacker/cbor` is used in projects by Arm Ltd., Berlin Institute of Health at Charité, Chainlink, Cisco, Confidential Computing Consortium, ConsenSys, Dapper Labs, EdgeX Foundry, F5, FIDO Alliance, Fraunhofer‑AISEC, Kubernetes, Let's Encrypt (ISRG), Linux Foundation, Matrix.org, Microsoft, Mozilla, National Cybersecurity Agency of France (govt), Netherlands (govt), Oasis Protocol, Smallstep, Tailscale, Taurus SA, Teleport, TIBCO, and others.
`fxamacker/cbor` passed multiple confidential security assessments. A [nonconfidential security assessment](https://github.com/veraison/go-cose/blob/v1.0.0-rc.1/reports/NCC_Microsoft-go-cose-Report_2022-05-26_v1.0.pdf) (prepared by NCC Group for Microsoft Corporation) includes a subset of fxamacker/cbor v2.4.0 in its scope.
@@ -657,6 +672,8 @@ I'm especially grateful to Bastian Müller and Dieter Shirley for suggesting and
I'm very grateful to Stefan Tatschner, Yawning Angel, Jernej Kos, x448, ZenGround0, and Jakob Borg for their contributions or support in the very early days.
Big thanks to Ben Luddy for his contributions in v2.6.0 and v2.7.0.
This library clearly wouldn't be possible without Carsten Bormann authoring CBOR RFCs.
Special thanks to Laurence Lundblade and Jeffrey Yasskin for their help on IETF mailing list or at [7049bis](https://github.com/cbor-wg/CBORbis).

View File

@@ -22,8 +22,8 @@ func (bs ByteString) Bytes() []byte {
// MarshalCBOR encodes ByteString as CBOR byte string (major type 2).
func (bs ByteString) MarshalCBOR() ([]byte, error) {
e := getEncoderBuffer()
defer putEncoderBuffer(e)
e := getEncodeBuffer()
defer putEncodeBuffer(e)
// Encode length
encodeHead(e, byte(cborTypeByteString), uint64(len(bs)))

View File

@@ -6,6 +6,7 @@ package cbor
import (
"bytes"
"errors"
"fmt"
"reflect"
"sort"
"strconv"
@@ -84,9 +85,25 @@ func newTypeInfo(t reflect.Type) *typeInfo {
}
type decodingStructType struct {
fields fields
err error
toArray bool
fields fields
fieldIndicesByName map[string]int
err error
toArray bool
}
// The stdlib errors.Join was introduced in Go 1.20, and we still support Go 1.17, so instead,
// here's a very basic implementation of an aggregated error.
type multierror []error
func (m multierror) Error() string {
var sb strings.Builder
for i, err := range m {
sb.WriteString(err.Error())
if i < len(m)-1 {
sb.WriteString(", ")
}
}
return sb.String()
}
func getDecodingStructType(t reflect.Type) *decodingStructType {
@@ -98,12 +115,12 @@ func getDecodingStructType(t reflect.Type) *decodingStructType {
toArray := hasToArrayOption(structOptions)
var err error
var errs []error
for i := 0; i < len(flds); i++ {
if flds[i].keyAsInt {
nameAsInt, numErr := strconv.Atoi(flds[i].name)
if numErr != nil {
err = errors.New("cbor: failed to parse field name \"" + flds[i].name + "\" to int (" + numErr.Error() + ")")
errs = append(errs, errors.New("cbor: failed to parse field name \""+flds[i].name+"\" to int ("+numErr.Error()+")"))
break
}
flds[i].nameAsInt = int64(nameAsInt)
@@ -112,7 +129,36 @@ func getDecodingStructType(t reflect.Type) *decodingStructType {
flds[i].typInfo = getTypeInfo(flds[i].typ)
}
structType := &decodingStructType{fields: flds, err: err, toArray: toArray}
fieldIndicesByName := make(map[string]int, len(flds))
for i, fld := range flds {
if _, ok := fieldIndicesByName[fld.name]; ok {
errs = append(errs, fmt.Errorf("cbor: two or more fields of %v have the same name %q", t, fld.name))
continue
}
fieldIndicesByName[fld.name] = i
}
var err error
{
var multi multierror
for _, each := range errs {
if each != nil {
multi = append(multi, each)
}
}
if len(multi) == 1 {
err = multi[0]
} else if len(multi) > 1 {
err = multi
}
}
structType := &decodingStructType{
fields: flds,
fieldIndicesByName: fieldIndicesByName,
err: err,
toArray: toArray,
}
decodingStructTypeCache.Store(t, structType)
return structType
}
@@ -124,17 +170,17 @@ type encodingStructType struct {
omitEmptyFieldsIdx []int
err error
toArray bool
fixedLength bool // Struct type doesn't have any omitempty or anonymous fields.
}
func (st *encodingStructType) getFields(em *encMode) fields {
if em.sort == SortNone {
switch em.sort {
case SortNone, SortFastShuffle:
return st.fields
}
if em.sort == SortLengthFirst {
case SortLengthFirst:
return st.lengthFirstFields
default:
return st.bytewiseFields
}
return st.bytewiseFields
}
type bytewiseFieldSorter struct {
@@ -188,8 +234,7 @@ func getEncodingStructType(t reflect.Type) (*encodingStructType, error) {
var hasKeyAsInt bool
var hasKeyAsStr bool
var omitEmptyIdx []int
fixedLength := true
e := getEncoderBuffer()
e := getEncodeBuffer()
for i := 0; i < len(flds); i++ {
// Get field's encodeFunc
flds[i].ef, flds[i].ief = getEncodeFunc(flds[i].typ)
@@ -231,23 +276,18 @@ func getEncodingStructType(t reflect.Type) (*encodingStructType, error) {
copy(flds[i].cborNameByteString, flds[i].cborName)
// Reset encoded CBOR type to byte string, preserving the "additional
// information" bits:
flds[i].cborNameByteString[0] = byte(cborTypeByteString) | (flds[i].cborNameByteString[0] & 0x1f)
flds[i].cborNameByteString[0] = byte(cborTypeByteString) |
getAdditionalInformation(flds[i].cborNameByteString[0])
hasKeyAsStr = true
}
// Check if field is from embedded struct
if len(flds[i].idx) > 1 {
fixedLength = false
}
// Check if field can be omitted when empty
if flds[i].omitEmpty {
fixedLength = false
omitEmptyIdx = append(omitEmptyIdx, i)
}
}
putEncoderBuffer(e)
putEncodeBuffer(e)
if err != nil {
structType := &encodingStructType{err: err}
@@ -272,8 +312,8 @@ func getEncodingStructType(t reflect.Type) (*encodingStructType, error) {
bytewiseFields: bytewiseFields,
lengthFirstFields: lengthFirstFields,
omitEmptyFieldsIdx: omitEmptyIdx,
fixedLength: fixedLength,
}
encodingStructTypeCache.Store(t, structType)
return structType, structType.err
}
@@ -290,9 +330,8 @@ func getEncodingStructToArrayType(t reflect.Type, flds fields) (*encodingStructT
}
structType := &encodingStructType{
fields: flds,
toArray: true,
fixedLength: true,
fields: flds,
toArray: true,
}
encodingStructTypeCache.Store(t, structType)
return structType, structType.err

182
vendor/github.com/fxamacker/cbor/v2/common.go generated vendored Normal file
View File

@@ -0,0 +1,182 @@
// Copyright (c) Faye Amacker. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
package cbor
import (
"fmt"
"strconv"
)
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))
}
}
type additionalInformation uint8
const (
maxAdditionalInformationWithoutArgument = 23
additionalInformationWith1ByteArgument = 24
additionalInformationWith2ByteArgument = 25
additionalInformationWith4ByteArgument = 26
additionalInformationWith8ByteArgument = 27
// For major type 7.
additionalInformationAsFalse = 20
additionalInformationAsTrue = 21
additionalInformationAsNull = 22
additionalInformationAsUndefined = 23
additionalInformationAsFloat16 = 25
additionalInformationAsFloat32 = 26
additionalInformationAsFloat64 = 27
// For major type 2, 3, 4, 5.
additionalInformationAsIndefiniteLengthFlag = 31
)
const (
maxSimpleValueInAdditionalInformation = 23
minSimpleValueIn1ByteArgument = 32
)
func (ai additionalInformation) isIndefiniteLength() bool {
return ai == additionalInformationAsIndefiniteLengthFlag
}
const (
// From RFC 8949 Section 3:
// "The initial byte of each encoded data item contains both information about the major type
// (the high-order 3 bits, described in Section 3.1) and additional information
// (the low-order 5 bits)."
// typeMask is used to extract major type in initial byte of encoded data item.
typeMask = 0xe0
// additionalInformationMask is used to extract additional information in initial byte of encoded data item.
additionalInformationMask = 0x1f
)
func getType(raw byte) cborType {
return cborType(raw & typeMask)
}
func getAdditionalInformation(raw byte) byte {
return raw & additionalInformationMask
}
func isBreakFlag(raw byte) bool {
return raw == cborBreakFlag
}
func parseInitialByte(b byte) (t cborType, ai byte) {
return getType(b), getAdditionalInformation(b)
}
const (
tagNumRFC3339Time = 0
tagNumEpochTime = 1
tagNumUnsignedBignum = 2
tagNumNegativeBignum = 3
tagNumExpectedLaterEncodingBase64URL = 21
tagNumExpectedLaterEncodingBase64 = 22
tagNumExpectedLaterEncodingBase16 = 23
tagNumSelfDescribedCBOR = 55799
)
const (
cborBreakFlag = byte(0xff)
cborByteStringWithIndefiniteLengthHead = byte(0x5f)
cborTextStringWithIndefiniteLengthHead = byte(0x7f)
cborArrayWithIndefiniteLengthHead = byte(0x9f)
cborMapWithIndefiniteLengthHead = byte(0xbf)
)
var (
cborFalse = []byte{0xf4}
cborTrue = []byte{0xf5}
cborNil = []byte{0xf6}
cborNaN = []byte{0xf9, 0x7e, 0x00}
cborPositiveInfinity = []byte{0xf9, 0x7c, 0x00}
cborNegativeInfinity = []byte{0xf9, 0xfc, 0x00}
)
// validBuiltinTag checks that supported built-in tag numbers are followed by expected content types.
func validBuiltinTag(tagNum uint64, contentHead byte) error {
t := getType(contentHead)
switch tagNum {
case tagNumRFC3339Time:
// Tag content (date/time text string in RFC 3339 format) must be string type.
if t != cborTypeTextString {
return newInadmissibleTagContentTypeError(
tagNumRFC3339Time,
"text string",
t.String())
}
return nil
case tagNumEpochTime:
// Tag content (epoch date/time) must be uint, int, or float type.
if t != cborTypePositiveInt && t != cborTypeNegativeInt && (contentHead < 0xf9 || contentHead > 0xfb) {
return newInadmissibleTagContentTypeError(
tagNumEpochTime,
"integer or floating-point number",
t.String())
}
return nil
case tagNumUnsignedBignum, tagNumNegativeBignum:
// Tag content (bignum) must be byte type.
if t != cborTypeByteString {
return newInadmissibleTagContentTypeErrorf(
fmt.Sprintf(
"tag number %d or %d must be followed by byte string, got %s",
tagNumUnsignedBignum,
tagNumNegativeBignum,
t.String(),
))
}
return nil
case tagNumExpectedLaterEncodingBase64URL, tagNumExpectedLaterEncodingBase64, tagNumExpectedLaterEncodingBase16:
// From RFC 8949 3.4.5.2:
// The data item tagged can be a byte string or any other data item. In the latter
// case, the tag applies to all of the byte string data items contained in the data
// item, except for those contained in a nested data item tagged with an expected
// conversion.
return nil
}
return nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,7 @@ import (
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"io"
"math"
"math/big"
@@ -158,7 +159,7 @@ func (dm *diagMode) Diagnose(data []byte) (string, error) {
}
// DiagnoseFirst returns extended diagnostic notation (EDN) of the first CBOR data item using the DiagMode. Any remaining bytes are returned in rest.
func (dm *diagMode) DiagnoseFirst(data []byte) (string, []byte, error) {
func (dm *diagMode) DiagnoseFirst(data []byte) (diagNotation string, rest []byte, err error) {
return newDiagnose(data, dm.decMode, dm).diagFirst()
}
@@ -173,7 +174,7 @@ func Diagnose(data []byte) (string, error) {
}
// Diagnose returns extended diagnostic notation (EDN) of the first CBOR data item using the DiagMode. Any remaining bytes are returned in rest.
func DiagnoseFirst(data []byte) (string, []byte, error) {
func DiagnoseFirst(data []byte) (diagNotation string, rest []byte, err error) {
return defaultDiagMode.DiagnoseFirst(data)
}
@@ -198,13 +199,11 @@ func (di *diagnose) diag(cborSequence bool) (string, error) {
switch err := di.wellformed(cborSequence); err {
case nil:
if !firstItem {
if err = di.writeString(", "); err != nil {
return di.w.String(), err
}
di.w.WriteString(", ")
}
firstItem = false
if err = di.item(); err != nil {
return di.w.String(), err
if itemErr := di.item(); itemErr != nil {
return di.w.String(), itemErr
}
case io.EOF:
@@ -219,8 +218,8 @@ func (di *diagnose) diag(cborSequence bool) (string, error) {
}
}
func (di *diagnose) diagFirst() (string, []byte, error) {
err := di.wellformed(true)
func (di *diagnose) diagFirst() (diagNotation string, rest []byte, err error) {
err = di.wellformed(true)
if err == nil {
err = di.item()
}
@@ -235,7 +234,7 @@ func (di *diagnose) diagFirst() (string, []byte, error) {
func (di *diagnose) wellformed(allowExtraData bool) error {
off := di.d.off
err := di.d.wellformed(allowExtraData)
err := di.d.wellformed(allowExtraData, false)
di.d.off = off
return err
}
@@ -243,30 +242,29 @@ func (di *diagnose) wellformed(allowExtraData bool) error {
func (di *diagnose) item() error { //nolint:gocyclo
initialByte := di.d.data[di.d.off]
switch initialByte {
case 0x5f, 0x7f: // indefinite-length byte/text string
case cborByteStringWithIndefiniteLengthHead,
cborTextStringWithIndefiniteLengthHead: // indefinite-length byte/text string
di.d.off++
if di.d.data[di.d.off] == 0xff {
if isBreakFlag(di.d.data[di.d.off]) {
di.d.off++
switch initialByte {
case 0x5f:
case cborByteStringWithIndefiniteLengthHead:
// indefinite-length bytes with no chunks.
return di.writeString(`''_`)
case 0x7f:
di.w.WriteString(`''_`)
return nil
case cborTextStringWithIndefiniteLengthHead:
// indefinite-length text with no chunks.
return di.writeString(`""_`)
di.w.WriteString(`""_`)
return nil
}
}
if err := di.writeString("(_ "); err != nil {
return err
}
di.w.WriteString("(_ ")
i := 0
for !di.d.foundBreak() {
if i > 0 {
if err := di.writeString(", "); err != nil {
return err
}
di.w.WriteString(", ")
}
i++
@@ -276,20 +274,17 @@ func (di *diagnose) item() error { //nolint:gocyclo
}
}
return di.writeByte(')')
di.w.WriteByte(')')
return nil
case 0x9f: // indefinite-length array
case cborArrayWithIndefiniteLengthHead: // indefinite-length array
di.d.off++
if err := di.writeString("[_ "); err != nil {
return err
}
di.w.WriteString("[_ ")
i := 0
for !di.d.foundBreak() {
if i > 0 {
if err := di.writeString(", "); err != nil {
return err
}
di.w.WriteString(", ")
}
i++
@@ -298,20 +293,17 @@ func (di *diagnose) item() error { //nolint:gocyclo
}
}
return di.writeByte(']')
di.w.WriteByte(']')
return nil
case 0xbf: // indefinite-length map
case cborMapWithIndefiniteLengthHead: // indefinite-length map
di.d.off++
if err := di.writeString("{_ "); err != nil {
return err
}
di.w.WriteString("{_ ")
i := 0
for !di.d.foundBreak() {
if i > 0 {
if err := di.writeString(", "); err != nil {
return err
}
di.w.WriteString(", ")
}
i++
@@ -320,9 +312,7 @@ func (di *diagnose) item() error { //nolint:gocyclo
return err
}
if err := di.writeString(": "); err != nil {
return err
}
di.w.WriteString(": ")
// value
if err := di.item(); err != nil {
@@ -330,14 +320,16 @@ func (di *diagnose) item() error { //nolint:gocyclo
}
}
return di.writeByte('}')
di.w.WriteByte('}')
return nil
}
t := di.d.nextCBORType()
switch t {
case cborTypePositiveInt:
_, _, val := di.d.getHead()
return di.writeString(strconv.FormatUint(val, 10))
di.w.WriteString(strconv.FormatUint(val, 10))
return nil
case cborTypeNegativeInt:
_, _, val := di.d.getHead()
@@ -347,11 +339,13 @@ func (di *diagnose) item() error { //nolint:gocyclo
bi.SetUint64(val)
bi.Add(bi, big.NewInt(1))
bi.Neg(bi)
return di.writeString(bi.String())
di.w.WriteString(bi.String())
return nil
}
nValue := int64(-1) ^ int64(val)
return di.writeString(strconv.FormatInt(nValue, 10))
di.w.WriteString(strconv.FormatInt(nValue, 10))
return nil
case cborTypeByteString:
b, _ := di.d.parseByteString()
@@ -367,135 +361,129 @@ func (di *diagnose) item() error { //nolint:gocyclo
case cborTypeArray:
_, _, val := di.d.getHead()
count := int(val)
if err := di.writeByte('['); err != nil {
return err
}
di.w.WriteByte('[')
for i := 0; i < count; i++ {
if i > 0 {
if err := di.writeString(", "); err != nil {
return err
}
di.w.WriteString(", ")
}
if err := di.item(); err != nil {
return err
}
}
return di.writeByte(']')
di.w.WriteByte(']')
return nil
case cborTypeMap:
_, _, val := di.d.getHead()
count := int(val)
if err := di.writeByte('{'); err != nil {
return err
}
di.w.WriteByte('{')
for i := 0; i < count; i++ {
if i > 0 {
if err := di.writeString(", "); err != nil {
return err
}
di.w.WriteString(", ")
}
// key
if err := di.item(); err != nil {
return err
}
if err := di.writeString(": "); err != nil {
return err
}
di.w.WriteString(": ")
// value
if err := di.item(); err != nil {
return err
}
}
return di.writeByte('}')
di.w.WriteByte('}')
return nil
case cborTypeTag:
_, _, tagNum := di.d.getHead()
switch tagNum {
case 2:
case tagNumUnsignedBignum:
if nt := di.d.nextCBORType(); nt != cborTypeByteString {
return errors.New("cbor: tag number 2 must be followed by byte string, got " + nt.String())
return newInadmissibleTagContentTypeError(
tagNumUnsignedBignum,
"byte string",
nt.String())
}
b, _ := di.d.parseByteString()
bi := new(big.Int).SetBytes(b)
return di.writeString(bi.String())
di.w.WriteString(bi.String())
return nil
case 3:
case tagNumNegativeBignum:
if nt := di.d.nextCBORType(); nt != cborTypeByteString {
return errors.New("cbor: tag number 3 must be followed by byte string, got " + nt.String())
return newInadmissibleTagContentTypeError(
tagNumNegativeBignum,
"byte string",
nt.String(),
)
}
b, _ := di.d.parseByteString()
bi := new(big.Int).SetBytes(b)
bi.Add(bi, big.NewInt(1))
bi.Neg(bi)
return di.writeString(bi.String())
di.w.WriteString(bi.String())
return nil
default:
if err := di.writeString(strconv.FormatUint(tagNum, 10)); err != nil {
return err
}
if err := di.writeByte('('); err != nil {
return err
}
di.w.WriteString(strconv.FormatUint(tagNum, 10))
di.w.WriteByte('(')
if err := di.item(); err != nil {
return err
}
return di.writeByte(')')
di.w.WriteByte(')')
return nil
}
case cborTypePrimitives:
_, ai, val := di.d.getHead()
switch ai {
case 20:
return di.writeString("false")
case additionalInformationAsFalse:
di.w.WriteString("false")
return nil
case 21:
return di.writeString("true")
case additionalInformationAsTrue:
di.w.WriteString("true")
return nil
case 22:
return di.writeString("null")
case additionalInformationAsNull:
di.w.WriteString("null")
return nil
case 23:
return di.writeString("undefined")
case additionalInformationAsUndefined:
di.w.WriteString("undefined")
return nil
case 25, 26, 27:
case additionalInformationAsFloat16,
additionalInformationAsFloat32,
additionalInformationAsFloat64:
return di.encodeFloat(ai, val)
default:
if err := di.writeString("simple("); err != nil {
return err
}
if err := di.writeString(strconv.FormatUint(val, 10)); err != nil {
return err
}
return di.writeByte(')')
di.w.WriteString("simple(")
di.w.WriteString(strconv.FormatUint(val, 10))
di.w.WriteByte(')')
return nil
}
}
return nil
}
func (di *diagnose) writeByte(val byte) error {
return di.w.WriteByte(val)
}
func (di *diagnose) writeString(val string) error {
_, err := di.w.WriteString(val)
return err
}
// writeU16 format a rune as "\uxxxx"
func (di *diagnose) writeU16(val rune) error {
if err := di.writeString("\\u"); err != nil {
return err
}
b := make([]byte, 2)
b[0] = byte(val >> 8)
b[1] = byte(val)
return di.writeString(hex.EncodeToString(b))
func (di *diagnose) writeU16(val rune) {
di.w.WriteString("\\u")
var in [2]byte
in[0] = byte(val >> 8)
in[1] = byte(val)
sz := hex.EncodedLen(len(in))
di.w.Grow(sz)
dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz]
hex.Encode(dst, in[:])
di.w.Write(dst)
}
var rawBase32Encoding = base32.StdEncoding.WithPadding(base32.NoPadding)
@@ -511,95 +499,91 @@ func (di *diagnose) encodeByteString(val []byte) error {
di2 := newDiagnose(val, di.dm.decMode, di.dm)
// should always notating embedded CBOR sequence.
if str, err := di2.diag(true); err == nil {
if err := di.writeString("<<"); err != nil {
return err
}
if err := di.writeString(str); err != nil {
return err
}
return di.writeString(">>")
di.w.WriteString("<<")
di.w.WriteString(str)
di.w.WriteString(">>")
return nil
}
}
}
switch di.dm.byteStringEncoding {
case ByteStringBase16Encoding:
if err := di.writeString("h'"); err != nil {
return err
}
encoder := hex.NewEncoder(di.w)
di.w.WriteString("h'")
if di.dm.byteStringHexWhitespace {
for i, b := range val {
sz := hex.EncodedLen(len(val))
if len(val) > 0 {
sz += len(val) - 1
}
di.w.Grow(sz)
dst := di.w.Bytes()[di.w.Len():]
for i := range val {
if i > 0 {
if err := di.writeByte(' '); err != nil {
return err
}
}
if _, err := encoder.Write([]byte{b}); err != nil {
return err
dst = append(dst, ' ')
}
hex.Encode(dst[len(dst):len(dst)+2], val[i:i+1])
dst = dst[:len(dst)+2]
}
di.w.Write(dst)
} else {
if _, err := encoder.Write(val); err != nil {
return err
}
sz := hex.EncodedLen(len(val))
di.w.Grow(sz)
dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz]
hex.Encode(dst, val)
di.w.Write(dst)
}
return di.writeByte('\'')
di.w.WriteByte('\'')
return nil
case ByteStringBase32Encoding:
if err := di.writeString("b32'"); err != nil {
return err
}
encoder := base32.NewEncoder(rawBase32Encoding, di.w)
if _, err := encoder.Write(val); err != nil {
return err
}
encoder.Close()
return di.writeByte('\'')
di.w.WriteString("b32'")
sz := rawBase32Encoding.EncodedLen(len(val))
di.w.Grow(sz)
dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz]
rawBase32Encoding.Encode(dst, val)
di.w.Write(dst)
di.w.WriteByte('\'')
return nil
case ByteStringBase32HexEncoding:
if err := di.writeString("h32'"); err != nil {
return err
}
encoder := base32.NewEncoder(rawBase32HexEncoding, di.w)
if _, err := encoder.Write(val); err != nil {
return err
}
encoder.Close()
return di.writeByte('\'')
di.w.WriteString("h32'")
sz := rawBase32HexEncoding.EncodedLen(len(val))
di.w.Grow(sz)
dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz]
rawBase32HexEncoding.Encode(dst, val)
di.w.Write(dst)
di.w.WriteByte('\'')
return nil
case ByteStringBase64Encoding:
if err := di.writeString("b64'"); err != nil {
return err
}
encoder := base64.NewEncoder(base64.RawURLEncoding, di.w)
if _, err := encoder.Write(val); err != nil {
return err
}
encoder.Close()
return di.writeByte('\'')
di.w.WriteString("b64'")
sz := base64.RawURLEncoding.EncodedLen(len(val))
di.w.Grow(sz)
dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz]
base64.RawURLEncoding.Encode(dst, val)
di.w.Write(dst)
di.w.WriteByte('\'')
return nil
default:
return di.dm.byteStringEncoding.valid()
// It should not be possible for users to construct a *diagMode with an invalid byte
// string encoding.
panic(fmt.Sprintf("diagmode has invalid ByteStringEncoding %v", di.dm.byteStringEncoding))
}
}
var utf16SurrSelf = rune(0x10000)
const utf16SurrSelf = rune(0x10000)
// quote should be either `'` or `"`
func (di *diagnose) encodeTextString(val string, quote byte) error {
if err := di.writeByte(quote); err != nil {
return err
}
di.w.WriteByte(quote)
for i := 0; i < len(val); {
if b := val[i]; b < utf8.RuneSelf {
switch {
case b == '\t', b == '\n', b == '\r', b == '\\', b == quote:
if err := di.writeByte('\\'); err != nil {
return err
}
di.w.WriteByte('\\')
switch b {
case '\t':
@@ -609,19 +593,13 @@ func (di *diagnose) encodeTextString(val string, quote byte) error {
case '\r':
b = 'r'
}
if err := di.writeByte(b); err != nil {
return err
}
di.w.WriteByte(b)
case b >= ' ' && b <= '~':
if err := di.writeByte(b); err != nil {
return err
}
di.w.WriteByte(b)
default:
if err := di.writeU16(rune(b)); err != nil {
return err
}
di.writeU16(rune(b))
}
i++
@@ -631,84 +609,86 @@ func (di *diagnose) encodeTextString(val string, quote byte) error {
c, size := utf8.DecodeRuneInString(val[i:])
switch {
case c == utf8.RuneError:
// if err := di.writeU16(rune(val[i])); err != nil {
// return err
// }
return &SemanticError{"cbor: invalid UTF-8 string"}
case c < utf16SurrSelf:
if err := di.writeU16(c); err != nil {
return err
}
di.writeU16(c)
default:
c1, c2 := utf16.EncodeRune(c)
if err := di.writeU16(c1); err != nil {
return err
}
if err := di.writeU16(c2); err != nil {
return err
}
di.writeU16(c1)
di.writeU16(c2)
}
i += size
}
return di.writeByte(quote)
di.w.WriteByte(quote)
return nil
}
func (di *diagnose) encodeFloat(ai byte, val uint64) error {
f64 := float64(0)
switch ai {
case 25:
case additionalInformationAsFloat16:
f16 := float16.Frombits(uint16(val))
switch {
case f16.IsNaN():
return di.writeString("NaN")
di.w.WriteString("NaN")
return nil
case f16.IsInf(1):
return di.writeString("Infinity")
di.w.WriteString("Infinity")
return nil
case f16.IsInf(-1):
return di.writeString("-Infinity")
di.w.WriteString("-Infinity")
return nil
default:
f64 = float64(f16.Float32())
}
case 26:
case additionalInformationAsFloat32:
f32 := math.Float32frombits(uint32(val))
switch {
case f32 != f32:
return di.writeString("NaN")
di.w.WriteString("NaN")
return nil
case f32 > math.MaxFloat32:
return di.writeString("Infinity")
di.w.WriteString("Infinity")
return nil
case f32 < -math.MaxFloat32:
return di.writeString("-Infinity")
di.w.WriteString("-Infinity")
return nil
default:
f64 = float64(f32)
}
case 27:
case additionalInformationAsFloat64:
f64 = math.Float64frombits(val)
switch {
case f64 != f64:
return di.writeString("NaN")
di.w.WriteString("NaN")
return nil
case f64 > math.MaxFloat64:
return di.writeString("Infinity")
di.w.WriteString("Infinity")
return nil
case f64 < -math.MaxFloat64:
return di.writeString("-Infinity")
di.w.WriteString("-Infinity")
return nil
}
}
// Use ES6 number to string conversion which should match most JSON generators.
// Inspired by https://github.com/golang/go/blob/4df10fba1687a6d4f51d7238a403f8f2298f6a16/src/encoding/json/encode.go#L585
const bitSize = 64
b := make([]byte, 0, 32)
if abs := math.Abs(f64); abs != 0 && (abs < 1e-6 || abs >= 1e21) {
b = strconv.AppendFloat(b, f64, 'e', -1, 64)
b = strconv.AppendFloat(b, f64, 'e', -1, bitSize)
// clean up e-09 to e-9
n := len(b)
if n >= 4 && string(b[n-4:n-1]) == "e-0" {
b = append(b[:n-2], b[n-1])
}
} else {
b = strconv.AppendFloat(b, f64, 'f', -1, 64)
b = strconv.AppendFloat(b, f64, 'f', -1, bitSize)
}
// add decimal point and trailing zero if needed
@@ -722,18 +702,21 @@ func (di *diagnose) encodeFloat(ai byte, val uint64) error {
}
}
if err := di.writeString(string(b)); err != nil {
return err
}
di.w.WriteString(string(b))
if di.dm.floatPrecisionIndicator {
switch ai {
case 25:
return di.writeString("_1")
case 26:
return di.writeString("_2")
case 27:
return di.writeString("_3")
case additionalInformationAsFloat16:
di.w.WriteString("_1")
return nil
case additionalInformationAsFloat32:
di.w.WriteString("_2")
return nil
case additionalInformationAsFloat64:
di.w.WriteString("_3")
return nil
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@
package cbor
import (
"bytes"
"reflect"
"sync"
)
@@ -15,8 +16,7 @@ type mapKeyValueEncodeFunc struct {
kpool, vpool sync.Pool
}
func (me *mapKeyValueEncodeFunc) encodeKeyValues(e *encoderBuffer, em *encMode, v reflect.Value, kvs []keyValue) error {
trackKeyValueLength := len(kvs) == v.Len()
func (me *mapKeyValueEncodeFunc) encodeKeyValues(e *bytes.Buffer, em *encMode, v reflect.Value, kvs []keyValue) error {
iterk := me.kpool.Get().(*reflect.Value)
defer func() {
iterk.SetZero()
@@ -27,24 +27,39 @@ func (me *mapKeyValueEncodeFunc) encodeKeyValues(e *encoderBuffer, em *encMode,
iterv.SetZero()
me.vpool.Put(iterv)
}()
iter := v.MapRange()
for i := 0; iter.Next(); i++ {
off := e.Len()
if kvs == nil {
for i, iter := 0, v.MapRange(); iter.Next(); i++ {
iterk.SetIterKey(iter)
iterv.SetIterValue(iter)
if err := me.kf(e, em, *iterk); err != nil {
return err
}
if err := me.ef(e, em, *iterv); err != nil {
return err
}
}
return nil
}
initial := e.Len()
for i, iter := 0, v.MapRange(); iter.Next(); i++ {
iterk.SetIterKey(iter)
iterv.SetIterValue(iter)
offset := e.Len()
if err := me.kf(e, em, *iterk); err != nil {
return err
}
if trackKeyValueLength {
kvs[i].keyLen = e.Len() - off
}
valueOffset := e.Len()
if err := me.ef(e, em, *iterv); err != nil {
return err
}
if trackKeyValueLength {
kvs[i].keyValueLen = e.Len() - off
kvs[i] = keyValue{
offset: offset - initial,
valueOffset: valueOffset - initial,
nextOffset: e.Len() - initial,
}
}

View File

@@ -6,6 +6,7 @@
package cbor
import (
"bytes"
"reflect"
)
@@ -13,25 +14,33 @@ type mapKeyValueEncodeFunc struct {
kf, ef encodeFunc
}
func (me *mapKeyValueEncodeFunc) encodeKeyValues(e *encoderBuffer, em *encMode, v reflect.Value, kvs []keyValue) error {
trackKeyValueLength := len(kvs) == v.Len()
iter := v.MapRange()
for i := 0; iter.Next(); i++ {
off := e.Len()
func (me *mapKeyValueEncodeFunc) encodeKeyValues(e *bytes.Buffer, em *encMode, v reflect.Value, kvs []keyValue) error {
if kvs == nil {
for i, iter := 0, v.MapRange(); iter.Next(); i++ {
if err := me.kf(e, em, iter.Key()); err != nil {
return err
}
if err := me.ef(e, em, iter.Value()); err != nil {
return err
}
}
return nil
}
initial := e.Len()
for i, iter := 0, v.MapRange(); iter.Next(); i++ {
offset := e.Len()
if err := me.kf(e, em, iter.Key()); err != nil {
return err
}
if trackKeyValueLength {
kvs[i].keyLen = e.Len() - off
}
valueOffset := e.Len()
if err := me.ef(e, em, iter.Value()); err != nil {
return err
}
if trackKeyValueLength {
kvs[i].keyValueLen = e.Len() - off
kvs[i] = keyValue{
offset: offset - initial,
valueOffset: valueOffset - initial,
nextOffset: e.Len() - initial,
}
}

View File

@@ -33,11 +33,11 @@ func (sv SimpleValue) MarshalCBOR() ([]byte, error) {
// only has a single representation variant)."
switch {
case sv <= 23:
case sv <= maxSimpleValueInAdditionalInformation:
return []byte{byte(cborTypePrimitives) | byte(sv)}, nil
case sv >= 32:
return []byte{byte(cborTypePrimitives) | byte(24), byte(sv)}, nil
case sv >= minSimpleValueIn1ByteArgument:
return []byte{byte(cborTypePrimitives) | additionalInformationWith1ByteArgument, byte(sv)}, nil
default:
return nil, &UnsupportedValueError{msg: fmt.Sprintf("SimpleValue(%d)", sv)}
@@ -57,7 +57,7 @@ func (sv *SimpleValue) UnmarshalCBOR(data []byte) error {
if typ != cborTypePrimitives {
return &UnmarshalTypeError{CBORType: typ.String(), GoType: "SimpleValue"}
}
if ai > 24 {
if ai > additionalInformationWith1ByteArgument {
return &UnmarshalTypeError{CBORType: typ.String(), GoType: "SimpleValue", errorMsg: "not simple values"}
}

View File

@@ -84,7 +84,7 @@ func (dec *Decoder) readNext() (int, error) {
if dec.off < len(dec.buf) {
dec.d.reset(dec.buf[dec.off:])
off := dec.off // Save offset before data validation
validErr = dec.d.wellformed(true)
validErr = dec.d.wellformed(true, false)
dec.off = off // Restore offset
if validErr == nil {
@@ -187,14 +187,14 @@ func (enc *Encoder) Encode(v interface{}) error {
}
}
buf := getEncoderBuffer()
buf := getEncodeBuffer()
err := encode(buf, enc.em, reflect.ValueOf(v))
if err == nil {
_, err = enc.w.Write(buf.Bytes())
}
putEncoderBuffer(buf)
putEncodeBuffer(buf)
return err
}
@@ -231,7 +231,7 @@ func (enc *Encoder) EndIndefinite() error {
if len(enc.indefTypes) == 0 {
return errors.New("cbor: cannot encode \"break\" code outside indefinite length values")
}
_, err := enc.w.Write([]byte{0xff})
_, err := enc.w.Write([]byte{cborBreakFlag})
if err == nil {
enc.indefTypes = enc.indefTypes[:len(enc.indefTypes)-1]
}
@@ -239,10 +239,10 @@ func (enc *Encoder) EndIndefinite() error {
}
var cborIndefHeader = map[cborType][]byte{
cborTypeByteString: {0x5f},
cborTypeTextString: {0x7f},
cborTypeArray: {0x9f},
cborTypeMap: {0xbf},
cborTypeByteString: {cborByteStringWithIndefiniteLengthHead},
cborTypeTextString: {cborTextStringWithIndefiniteLengthHead},
cborTypeArray: {cborArrayWithIndefiniteLengthHead},
cborTypeMap: {cborMapWithIndefiniteLengthHead},
}
func (enc *Encoder) startIndefinite(typ cborType) error {

View File

@@ -144,7 +144,15 @@ func getFields(t reflect.Type) (flds fields, structOptions string) {
}
// appendFields appends type t's exportable fields to flds and anonymous struct fields to nTypes .
func appendFields(t reflect.Type, idx []int, flds fields, nTypes map[reflect.Type][][]int) (fields, map[reflect.Type][][]int) {
func appendFields(
t reflect.Type,
idx []int,
flds fields,
nTypes map[reflect.Type][][]int,
) (
_flds fields,
_nTypes map[reflect.Type][][]int,
) {
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
@@ -165,12 +173,12 @@ func appendFields(t reflect.Type, idx []int, flds fields, nTypes map[reflect.Typ
continue
}
tagged := len(tag) > 0
tagged := tag != ""
// Parse field tag options
var tagFieldName string
var omitempty, keyasint bool
for j := 0; len(tag) > 0; j++ {
for j := 0; tag != ""; j++ {
var token string
idx := strings.IndexByte(tag, ',')
if idx == -1 {
@@ -199,7 +207,7 @@ func appendFields(t reflect.Type, idx []int, flds fields, nTypes map[reflect.Typ
copy(fIdx, idx)
fIdx[len(fIdx)-1] = i
if !f.Anonymous || ft.Kind() != reflect.Struct || len(tagFieldName) > 0 {
if !f.Anonymous || ft.Kind() != reflect.Struct || tagFieldName != "" {
flds = append(flds, &field{
name: fieldName,
idx: fIdx,
@@ -221,7 +229,7 @@ func appendFields(t reflect.Type, idx []int, flds fields, nTypes map[reflect.Typ
// isFieldExportable returns true if f is an exportable (regular or anonymous) field or
// a nonexportable anonymous field of struct type.
// Nonexportable anonymous field of struct type can contain exportable fields.
func isFieldExportable(f reflect.StructField, fk reflect.Kind) bool {
func isFieldExportable(f reflect.StructField, fk reflect.Kind) bool { //nolint:gocritic // ignore hugeParam
exportable := f.PkgPath == ""
return exportable || (f.Anonymous && fk == reflect.Struct)
}

View File

@@ -7,7 +7,9 @@ import (
"sync"
)
// Tag represents CBOR tag data, including tag number and unmarshaled tag content.
// Tag represents CBOR tag data, including tag number and unmarshaled tag content. Marshaling and
// unmarshaling of tag content is subject to any encode and decode options that would apply to
// enclosed data item if it were to appear outside of a tag.
type Tag struct {
Number uint64
Content interface{}
@@ -56,7 +58,7 @@ func (t RawTag) MarshalCBOR() ([]byte, error) {
return b, nil
}
e := getEncoderBuffer()
e := getEncodeBuffer()
encodeHead(e, byte(cborTypeTag), t.Number)
@@ -69,7 +71,7 @@ func (t RawTag) MarshalCBOR() ([]byte, error) {
n := copy(buf, e.Bytes())
copy(buf[n:], content)
putEncoderBuffer(e)
putEncodeBuffer(e)
return buf, nil
}
@@ -261,7 +263,7 @@ func newTagItem(opts TagOptions, contentType reflect.Type, num uint64, nestedNum
if num == 2 || num == 3 {
return nil, errors.New("cbor: cannot add tag number 2 or 3 to TagSet, it's built-in and supported automatically")
}
if num == selfDescribedCBORTagNum {
if num == tagNumSelfDescribedCBOR {
return nil, errors.New("cbor: cannot add tag number 55799 to TagSet, it's built-in and ignored automatically")
}
@@ -269,13 +271,13 @@ func newTagItem(opts TagOptions, contentType reflect.Type, num uint64, nestedNum
te.num = append(te.num, nestedNum...)
// Cache encoded tag numbers
e := getEncoderBuffer()
e := getEncodeBuffer()
for _, n := range te.num {
encodeHead(e, byte(cborTypeTag), n)
}
te.cborTagNum = make([]byte, e.Len())
copy(te.cborTagNum, e.Bytes())
putEncoderBuffer(e)
putEncodeBuffer(e)
return &te, nil
}

View File

@@ -7,7 +7,10 @@ import (
"encoding/binary"
"errors"
"io"
"math"
"strconv"
"github.com/x448/float16"
)
// SyntaxError is a description of a CBOR syntax error.
@@ -82,11 +85,11 @@ func (e *ExtraneousDataError) Error() string {
// allowExtraData indicates if extraneous data is allowed after the CBOR data item.
// - use allowExtraData = true when using Decoder.Decode()
// - use allowExtraData = false when using Unmarshal()
func (d *decoder) wellformed(allowExtraData bool) error {
func (d *decoder) wellformed(allowExtraData bool, checkBuiltinTags bool) error {
if len(d.data) == d.off {
return io.EOF
}
_, err := d.wellformedInternal(0)
_, err := d.wellformedInternal(0, checkBuiltinTags)
if err == nil {
if !allowExtraData && d.off != len(d.data) {
err = &ExtraneousDataError{len(d.data) - d.off, d.off}
@@ -96,19 +99,19 @@ func (d *decoder) wellformed(allowExtraData bool) error {
}
// wellformedInternal checks data's well-formedness and returns max depth and error.
func (d *decoder) wellformedInternal(depth int) (int, error) {
t, ai, val, err := d.wellformedHead()
func (d *decoder) wellformedInternal(depth int, checkBuiltinTags bool) (int, error) { //nolint:gocyclo
t, _, val, indefiniteLength, err := d.wellformedHeadWithIndefiniteLengthFlag()
if err != nil {
return 0, err
}
switch t {
case cborTypeByteString, cborTypeTextString:
if ai == 31 {
if indefiniteLength {
if d.dm.indefLength == IndefLengthForbidden {
return 0, &IndefiniteLengthError{t}
}
return d.wellformedIndefiniteString(t, depth)
return d.wellformedIndefiniteString(t, depth, checkBuiltinTags)
}
valInt := int(val)
if valInt < 0 {
@@ -119,17 +122,18 @@ func (d *decoder) wellformedInternal(depth int) (int, error) {
return 0, io.ErrUnexpectedEOF
}
d.off += valInt
case cborTypeArray, cborTypeMap:
depth++
if depth > d.dm.maxNestedLevels {
return 0, &MaxNestedLevelError{d.dm.maxNestedLevels}
}
if ai == 31 {
if indefiniteLength {
if d.dm.indefLength == IndefLengthForbidden {
return 0, &IndefiniteLengthError{t}
}
return d.wellformedIndefiniteArrayOrMap(t, depth)
return d.wellformedIndefiniteArrayOrMap(t, depth, checkBuiltinTags)
}
valInt := int(val)
@@ -156,7 +160,7 @@ func (d *decoder) wellformedInternal(depth int) (int, error) {
for j := 0; j < count; j++ {
for i := 0; i < valInt; i++ {
var dpt int
if dpt, err = d.wellformedInternal(depth); err != nil {
if dpt, err = d.wellformedInternal(depth, checkBuiltinTags); err != nil {
return 0, err
}
if dpt > maxDepth {
@@ -165,20 +169,35 @@ func (d *decoder) wellformedInternal(depth int) (int, error) {
}
}
depth = maxDepth
case cborTypeTag:
if d.dm.tagsMd == TagsForbidden {
return 0, &TagsMdError{}
}
tagNum := val
// Scan nested tag numbers to avoid recursion.
for {
if len(d.data) == d.off { // Tag number must be followed by tag content.
return 0, io.ErrUnexpectedEOF
}
if cborType(d.data[d.off]&0xe0) != cborTypeTag {
if checkBuiltinTags {
err = validBuiltinTag(tagNum, d.data[d.off])
if err != nil {
return 0, err
}
}
if d.dm.bignumTag == BignumTagForbidden && (tagNum == 2 || tagNum == 3) {
return 0, &UnacceptableDataItemError{
CBORType: cborTypeTag.String(),
Message: "bignum",
}
}
if getType(d.data[d.off]) != cborTypeTag {
break
}
if _, _, _, err = d.wellformedHead(); err != nil {
if _, _, tagNum, err = d.wellformedHead(); err != nil {
return 0, err
}
depth++
@@ -187,31 +206,32 @@ func (d *decoder) wellformedInternal(depth int) (int, error) {
}
}
// Check tag content.
return d.wellformedInternal(depth)
return d.wellformedInternal(depth, checkBuiltinTags)
}
return depth, nil
}
// wellformedIndefiniteString checks indefinite length byte/text string's well-formedness and returns max depth and error.
func (d *decoder) wellformedIndefiniteString(t cborType, depth int) (int, error) {
func (d *decoder) wellformedIndefiniteString(t cborType, depth int, checkBuiltinTags bool) (int, error) {
var err error
for {
if len(d.data) == d.off {
return 0, io.ErrUnexpectedEOF
}
if d.data[d.off] == 0xff {
if isBreakFlag(d.data[d.off]) {
d.off++
break
}
// Peek ahead to get next type and indefinite length status.
nt := cborType(d.data[d.off] & 0xe0)
nt, ai := parseInitialByte(d.data[d.off])
if t != nt {
return 0, &SyntaxError{"cbor: wrong element type " + nt.String() + " for indefinite-length " + t.String()}
}
if (d.data[d.off] & 0x1f) == 31 {
if additionalInformation(ai).isIndefiniteLength() {
return 0, &SyntaxError{"cbor: indefinite-length " + t.String() + " chunk is not definite-length"}
}
if depth, err = d.wellformedInternal(depth); err != nil {
if depth, err = d.wellformedInternal(depth, checkBuiltinTags); err != nil {
return 0, err
}
}
@@ -219,7 +239,7 @@ func (d *decoder) wellformedIndefiniteString(t cborType, depth int) (int, error)
}
// wellformedIndefiniteArrayOrMap checks indefinite length array/map's well-formedness and returns max depth and error.
func (d *decoder) wellformedIndefiniteArrayOrMap(t cborType, depth int) (int, error) {
func (d *decoder) wellformedIndefiniteArrayOrMap(t cborType, depth int, checkBuiltinTags bool) (int, error) {
var err error
maxDepth := depth
i := 0
@@ -227,12 +247,12 @@ func (d *decoder) wellformedIndefiniteArrayOrMap(t cborType, depth int) (int, er
if len(d.data) == d.off {
return 0, io.ErrUnexpectedEOF
}
if d.data[d.off] == 0xff {
if isBreakFlag(d.data[d.off]) {
d.off++
break
}
var dpt int
if dpt, err = d.wellformedInternal(depth); err != nil {
if dpt, err = d.wellformedInternal(depth, checkBuiltinTags); err != nil {
return 0, err
}
if dpt > maxDepth {
@@ -255,22 +275,39 @@ func (d *decoder) wellformedIndefiniteArrayOrMap(t cborType, depth int) (int, er
return maxDepth, nil
}
func (d *decoder) wellformedHeadWithIndefiniteLengthFlag() (
t cborType,
ai byte,
val uint64,
indefiniteLength bool,
err error,
) {
t, ai, val, err = d.wellformedHead()
if err != nil {
return
}
indefiniteLength = additionalInformation(ai).isIndefiniteLength()
return
}
func (d *decoder) wellformedHead() (t cborType, ai byte, val uint64, err error) {
dataLen := len(d.data) - d.off
if dataLen == 0 {
return 0, 0, 0, io.ErrUnexpectedEOF
}
t = cborType(d.data[d.off] & 0xe0)
ai = d.data[d.off] & 0x1f
t, ai = parseInitialByte(d.data[d.off])
val = uint64(ai)
d.off++
dataLen--
if ai < 24 {
if ai <= maxAdditionalInformationWithoutArgument {
return t, ai, val, nil
}
if ai == 24 {
if dataLen < 2 {
if ai == additionalInformationWith1ByteArgument {
const argumentSize = 1
if dataLen < argumentSize {
return 0, 0, 0, io.ErrUnexpectedEOF
}
val = uint64(d.data[d.off])
@@ -280,31 +317,53 @@ func (d *decoder) wellformedHead() (t cborType, ai byte, val uint64, err error)
}
return t, ai, val, nil
}
if ai == 25 {
if dataLen < 3 {
if ai == additionalInformationWith2ByteArgument {
const argumentSize = 2
if dataLen < argumentSize {
return 0, 0, 0, io.ErrUnexpectedEOF
}
val = uint64(binary.BigEndian.Uint16(d.data[d.off : d.off+2]))
d.off += 2
val = uint64(binary.BigEndian.Uint16(d.data[d.off : d.off+argumentSize]))
d.off += argumentSize
if t == cborTypePrimitives {
if err := d.acceptableFloat(float64(float16.Frombits(uint16(val)).Float32())); err != nil {
return 0, 0, 0, err
}
}
return t, ai, val, nil
}
if ai == 26 {
if dataLen < 5 {
if ai == additionalInformationWith4ByteArgument {
const argumentSize = 4
if dataLen < argumentSize {
return 0, 0, 0, io.ErrUnexpectedEOF
}
val = uint64(binary.BigEndian.Uint32(d.data[d.off : d.off+4]))
d.off += 4
val = uint64(binary.BigEndian.Uint32(d.data[d.off : d.off+argumentSize]))
d.off += argumentSize
if t == cborTypePrimitives {
if err := d.acceptableFloat(float64(math.Float32frombits(uint32(val)))); err != nil {
return 0, 0, 0, err
}
}
return t, ai, val, nil
}
if ai == 27 {
if dataLen < 9 {
if ai == additionalInformationWith8ByteArgument {
const argumentSize = 8
if dataLen < argumentSize {
return 0, 0, 0, io.ErrUnexpectedEOF
}
val = binary.BigEndian.Uint64(d.data[d.off : d.off+8])
d.off += 8
val = binary.BigEndian.Uint64(d.data[d.off : d.off+argumentSize])
d.off += argumentSize
if t == cborTypePrimitives {
if err := d.acceptableFloat(math.Float64frombits(val)); err != nil {
return 0, 0, 0, err
}
}
return t, ai, val, nil
}
if ai == 31 {
if additionalInformation(ai).isIndefiniteLength() {
switch t {
case cborTypePositiveInt, cborTypeNegativeInt, cborTypeTag:
return 0, 0, 0, &SyntaxError{"cbor: invalid additional information " + strconv.Itoa(int(ai)) + " for type " + t.String()}
@@ -313,6 +372,23 @@ func (d *decoder) wellformedHead() (t cborType, ai byte, val uint64, err error)
}
return t, ai, val, nil
}
// ai == 28, 29, 30
return 0, 0, 0, &SyntaxError{"cbor: invalid additional information " + strconv.Itoa(int(ai)) + " for type " + t.String()}
}
func (d *decoder) acceptableFloat(f float64) error {
switch {
case d.dm.nanDec == NaNDecodeForbidden && math.IsNaN(f):
return &UnacceptableDataItemError{
CBORType: cborTypePrimitives.String(),
Message: "floating-point NaN",
}
case d.dm.infDec == InfDecodeForbidden && math.IsInf(f, 0):
return &UnacceptableDataItemError{
CBORType: cborTypePrimitives.String(),
Message: "floating-point infinity",
}
}
return nil
}