| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318 |
- // Copyright (c) Faye Amacker. All rights reserved.
- // Licensed under the MIT License. See LICENSE in the project root for license information.
- package cbor
- import (
- "bytes"
- "encoding"
- "encoding/base64"
- "encoding/binary"
- "encoding/hex"
- "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.
- // CBOR tags with an unrecognized number decode to cbor.Tag
- //
- // 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. As a special case, Infinite
- // and NaN float values decode to time.Time's zero value.
- //
- // 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", unmarshaling 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).
- //
- // Unmarshal returns ExtraneousDataError error (without decoding into v)
- // if there are any remaining bytes following the first valid CBOR data item.
- // See UnmarshalFirst, if you want to unmarshal only the first
- // CBOR data item without ExtraneousDataError caused by remaining bytes.
- func Unmarshal(data []byte, v any) error {
- return defaultDecMode.Unmarshal(data, v)
- }
- // UnmarshalFirst parses the first CBOR data item into the value pointed to by v
- // using default decoding options. Any remaining bytes are returned in rest.
- //
- // If v is nil, not a pointer, or a nil pointer, UnmarshalFirst returns an error.
- //
- // See the documentation for Unmarshal for details.
- func UnmarshalFirst(data []byte, v any) (rest []byte, err error) {
- return defaultDecMode.UnmarshalFirst(data, v)
- }
- // Valid checks whether data is a well-formed encoded CBOR data item and
- // that it complies with default restrictions such as MaxNestedLevels,
- // MaxArrayElements, MaxMapPairs, etc.
- //
- // If there are any remaining bytes after the CBOR data item,
- // an ExtraneousDataError is returned.
- //
- // WARNING: Valid doesn't check if encoded CBOR data item is valid (i.e. validity)
- // and RFC 8949 distinctly defines what is "Valid" and what is "Well-formed".
- //
- // Deprecated: Valid is kept for compatibility and should not be used.
- // Use Wellformed instead because it has a more appropriate name.
- func Valid(data []byte) error {
- return defaultDecMode.Valid(data)
- }
- // Wellformed checks whether data is a well-formed encoded CBOR data item and
- // that it complies with default restrictions such as MaxNestedLevels,
- // MaxArrayElements, MaxMapPairs, etc.
- //
- // If there are any remaining bytes after the CBOR data item,
- // an ExtraneousDataError is returned.
- func Wellformed(data []byte) error {
- return defaultDecMode.Wellformed(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
- }
- 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
- }
- // InvalidMapKeyTypeError describes invalid Go map key type when decoding CBOR map.
- // For example, Go doesn't allow slice as map key.
- type InvalidMapKeyTypeError struct {
- GoType string
- }
- func (e *InvalidMapKeyTypeError) Error() string {
- return "cbor: invalid map key type: " + e.GoType
- }
- // DupMapKeyError describes detected duplicate map key in CBOR map.
- type DupMapKeyError struct {
- Key any
- 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)
- }
- // UnacceptableDataItemError is returned when unmarshaling a CBOR input that contains a data item
- // that is not acceptable to a specific CBOR-based application protocol ("invalid or unexpected" as
- // described in RFC 8949 Section 5 Paragraph 3).
- type UnacceptableDataItemError struct {
- CBORType string
- Message string
- }
- func (e UnacceptableDataItemError) Error() string {
- return fmt.Sprintf("cbor: data item of cbor type %s is not accepted by protocol: %s", e.CBORType, e.Message)
- }
- // ByteStringExpectedFormatError is returned when unmarshaling CBOR byte string fails when
- // using non-default ByteStringExpectedFormat decoding option that makes decoder expect
- // a specified format such as base64, hex, etc.
- type ByteStringExpectedFormatError struct {
- expectedFormatOption ByteStringExpectedFormatMode
- err error
- }
- func newByteStringExpectedFormatError(expectedFormatOption ByteStringExpectedFormatMode, err error) *ByteStringExpectedFormatError {
- return &ByteStringExpectedFormatError{expectedFormatOption, err}
- }
- func (e *ByteStringExpectedFormatError) Error() string {
- switch e.expectedFormatOption {
- case ByteStringExpectedBase64URL:
- return fmt.Sprintf("cbor: failed to decode base64url from byte string: %s", e.err)
- case ByteStringExpectedBase64:
- return fmt.Sprintf("cbor: failed to decode base64 from byte string: %s", e.err)
- case ByteStringExpectedBase16:
- return fmt.Sprintf("cbor: failed to decode hex from byte string: %s", e.err)
- default:
- return fmt.Sprintf("cbor: failed to decode byte string in expected format %d: %s", e.expectedFormatOption, e.err)
- }
- }
- func (e *ByteStringExpectedFormatError) Unwrap() error {
- return e.err
- }
- // InadmissibleTagContentTypeError is returned when unmarshaling built-in CBOR tags
- // fails because of inadmissible type for tag content. Currently, the built-in
- // CBOR tags in this codec are tags 0-3 and 21-23.
- // See "Tag validity" in RFC 8949 Section 5.3.2.
- type InadmissibleTagContentTypeError struct {
- s string
- tagNum int
- expectedTagContentType string
- gotTagContentType string
- }
- func newInadmissibleTagContentTypeError(
- tagNum int,
- expectedTagContentType string,
- gotTagContentType string,
- ) *InadmissibleTagContentTypeError {
- return &InadmissibleTagContentTypeError{
- tagNum: tagNum,
- expectedTagContentType: expectedTagContentType,
- gotTagContentType: gotTagContentType,
- }
- }
- func newInadmissibleTagContentTypeErrorf(s string) *InadmissibleTagContentTypeError {
- return &InadmissibleTagContentTypeError{s: "cbor: " + s} //nolint:goconst // ignore "cbor"
- }
- func (e *InadmissibleTagContentTypeError) Error() string {
- if e.s == "" {
- return fmt.Sprintf(
- "cbor: tag number %d must be followed by %s, got %s",
- e.tagNum,
- e.expectedTagContentType,
- e.gotTagContentType,
- )
- }
- return e.s
- }
- // DupMapKeyMode specifies how to enforce duplicate map key. Two map keys are considered duplicates if:
- // 1. When decoding into a struct, both keys match the same struct field. The keys are also
- // considered duplicates if neither matches any field and decoding to interface{} would produce
- // equal (==) values for both keys.
- // 2. When decoding into a map, both keys are equal (==) when decoded into values of the
- // destination map's key type.
- 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 >= 0 && 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 >= 0 && 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 >= 0 && tm < maxTagsMode
- }
- // IntDecMode specifies which Go type (int64, uint64, or big.Int) should
- // be used when decoding CBOR integers (major type 0 and 1) to Go interface{}.
- type IntDecMode int
- const (
- // IntDecConvertNone affects how CBOR integers (major type 0 and 1) decode to Go interface{}.
- // It decodes CBOR unsigned integer (major type 0) to:
- // - uint64
- // It decodes CBOR negative integer (major type 1) to:
- // - int64 if value fits
- // - big.Int or *big.Int (see BigIntDecMode) if value doesn't fit into int64
- IntDecConvertNone IntDecMode = iota
- // IntDecConvertSigned affects how CBOR integers (major type 0 and 1) decode to Go interface{}.
- // It decodes CBOR integers (major type 0 and 1) to:
- // - int64 if value fits
- // - big.Int or *big.Int (see BigIntDecMode) if value < math.MinInt64
- // - return UnmarshalTypeError if value > math.MaxInt64
- // Deprecated: IntDecConvertSigned should not be used.
- // Please use other options, such as IntDecConvertSignedOrError, IntDecConvertSignedOrBigInt, IntDecConvertNone.
- IntDecConvertSigned
- // IntDecConvertSignedOrFail affects how CBOR integers (major type 0 and 1) decode to Go interface{}.
- // It decodes CBOR integers (major type 0 and 1) to:
- // - int64 if value fits
- // - return UnmarshalTypeError if value doesn't fit into int64
- IntDecConvertSignedOrFail
- // IntDecConvertSignedOrBigInt affects how CBOR integers (major type 0 and 1) decode to Go interface{}.
- // It makes CBOR integers (major type 0 and 1) decode to:
- // - int64 if value fits
- // - big.Int or *big.Int (see BigIntDecMode) if value doesn't fit into int64
- IntDecConvertSignedOrBigInt
- maxIntDec
- )
- func (idm IntDecMode) valid() bool {
- return idm >= 0 && idm < maxIntDec
- }
- // MapKeyByteStringMode specifies how to decode CBOR byte string (major type 2)
- // as Go map key when decoding CBOR map key into an empty Go interface value.
- // Specifically, this option applies when decoding CBOR map into
- // - Go empty interface, or
- // - Go map with empty interface as key type.
- // The CBOR map key types handled by this option are
- // - byte string
- // - tagged byte string
- // - nested tagged byte string
- type MapKeyByteStringMode int
- const (
- // MapKeyByteStringAllowed allows CBOR byte string to be decoded as Go map key.
- // Since Go doesn't allow []byte as map key, CBOR byte string is decoded to
- // ByteString which has underlying string type.
- // This is the default setting.
- MapKeyByteStringAllowed MapKeyByteStringMode = iota
- // MapKeyByteStringForbidden forbids CBOR byte string being decoded as Go map key.
- // Attempting to decode CBOR byte string as map key into empty interface value
- // returns a decoding error.
- MapKeyByteStringForbidden
- maxMapKeyByteStringMode
- )
- func (mkbsm MapKeyByteStringMode) valid() bool {
- return mkbsm >= 0 && mkbsm < maxMapKeyByteStringMode
- }
- // 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
- }
- // UTF8Mode option specifies if decoder should
- // decode CBOR Text containing invalid UTF-8 string.
- type UTF8Mode int
- const (
- // UTF8RejectInvalid rejects CBOR Text containing
- // invalid UTF-8 string.
- UTF8RejectInvalid UTF8Mode = iota
- // UTF8DecodeInvalid allows decoding CBOR Text containing
- // invalid UTF-8 string.
- UTF8DecodeInvalid
- maxUTF8Mode
- )
- func (um UTF8Mode) valid() bool {
- return um >= 0 && um < maxUTF8Mode
- }
- // FieldNameMatchingMode specifies how string keys in CBOR maps are matched to Go struct field names.
- type FieldNameMatchingMode int
- const (
- // FieldNameMatchingPreferCaseSensitive prefers to decode map items into struct fields whose names (or tag
- // names) exactly match the item's key. If there is no such field, a map item will be decoded into a field whose
- // name is a case-insensitive match for the item's key.
- FieldNameMatchingPreferCaseSensitive FieldNameMatchingMode = iota
- // FieldNameMatchingCaseSensitive decodes map items only into a struct field whose name (or tag name) is an
- // exact match for the item's key.
- FieldNameMatchingCaseSensitive
- maxFieldNameMatchingMode
- )
- func (fnmm FieldNameMatchingMode) valid() bool {
- return fnmm >= 0 && fnmm < maxFieldNameMatchingMode
- }
- // BigIntDecMode specifies how to decode CBOR bignum to Go interface{}.
- type BigIntDecMode int
- const (
- // BigIntDecodeValue makes CBOR bignum decode to big.Int (instead of *big.Int)
- // when unmarshaling into a Go interface{}.
- BigIntDecodeValue BigIntDecMode = iota
- // BigIntDecodePointer makes CBOR bignum decode to *big.Int when
- // unmarshaling into a Go interface{}.
- BigIntDecodePointer
- maxBigIntDecMode
- )
- func (bidm BigIntDecMode) valid() bool {
- return bidm >= 0 && bidm < maxBigIntDecMode
- }
- // ByteStringToStringMode specifies the behavior when decoding a CBOR byte string into a Go string.
- type ByteStringToStringMode int
- const (
- // ByteStringToStringForbidden generates an error on an attempt to decode a CBOR byte string into a Go string.
- ByteStringToStringForbidden ByteStringToStringMode = iota
- // ByteStringToStringAllowed permits decoding a CBOR byte string into a Go string.
- ByteStringToStringAllowed
- // ByteStringToStringAllowedWithExpectedLaterEncoding permits decoding a CBOR byte string
- // into a Go string. Also, if the byte string is enclosed (directly or indirectly) by one of
- // the "expected later encoding" tags (numbers 21 through 23), the destination string will
- // be populated by applying the designated text encoding to the contents of the input byte
- // string.
- ByteStringToStringAllowedWithExpectedLaterEncoding
- maxByteStringToStringMode
- )
- func (bstsm ByteStringToStringMode) valid() bool {
- return bstsm >= 0 && bstsm < maxByteStringToStringMode
- }
- // FieldNameByteStringMode specifies the behavior when decoding a CBOR byte string map key as a Go struct field name.
- type FieldNameByteStringMode int
- const (
- // FieldNameByteStringForbidden generates an error on an attempt to decode a CBOR byte string map key as a Go struct field name.
- FieldNameByteStringForbidden FieldNameByteStringMode = iota
- // FieldNameByteStringAllowed permits CBOR byte string map keys to be recognized as Go struct field names.
- FieldNameByteStringAllowed
- maxFieldNameByteStringMode
- )
- func (fnbsm FieldNameByteStringMode) valid() bool {
- return fnbsm >= 0 && fnbsm < maxFieldNameByteStringMode
- }
- // UnrecognizedTagToAnyMode specifies how to decode unrecognized CBOR tag into an empty interface (any).
- // Currently, recognized CBOR tag numbers are 0, 1, 2, 3, or registered by TagSet.
- type UnrecognizedTagToAnyMode int
- const (
- // UnrecognizedTagNumAndContentToAny decodes CBOR tag number and tag content to cbor.Tag
- // when decoding unrecognized CBOR tag into an empty interface.
- UnrecognizedTagNumAndContentToAny UnrecognizedTagToAnyMode = iota
- // UnrecognizedTagContentToAny decodes only CBOR tag content (into its default type)
- // when decoding unrecognized CBOR tag into an empty interface.
- UnrecognizedTagContentToAny
- maxUnrecognizedTagToAny
- )
- func (uttam UnrecognizedTagToAnyMode) valid() bool {
- return uttam >= 0 && uttam < maxUnrecognizedTagToAny
- }
- // TimeTagToAnyMode specifies how to decode CBOR tag 0 and 1 into an empty interface (any).
- // Based on the specified mode, Unmarshal can return a time.Time value or a time string in a specific format.
- type TimeTagToAnyMode int
- const (
- // TimeTagToTime decodes CBOR tag 0 and 1 into a time.Time value
- // when decoding tag 0 or 1 into an empty interface.
- TimeTagToTime TimeTagToAnyMode = iota
- // TimeTagToRFC3339 decodes CBOR tag 0 and 1 into a time string in RFC3339 format
- // when decoding tag 0 or 1 into an empty interface.
- TimeTagToRFC3339
- // TimeTagToRFC3339Nano decodes CBOR tag 0 and 1 into a time string in RFC3339Nano format
- // when decoding tag 0 or 1 into an empty interface.
- TimeTagToRFC3339Nano
- maxTimeTagToAnyMode
- )
- func (tttam TimeTagToAnyMode) valid() bool {
- return tttam >= 0 && tttam < maxTimeTagToAnyMode
- }
- // SimpleValueRegistry is a registry of unmarshaling behaviors for each possible CBOR simple value
- // number (0...23 and 32...255).
- type SimpleValueRegistry struct {
- rejected [256]bool
- }
- // WithRejectedSimpleValue registers the given simple value as rejected. If the simple value is
- // encountered in a CBOR input during unmarshaling, an UnacceptableDataItemError is returned.
- func WithRejectedSimpleValue(sv SimpleValue) func(*SimpleValueRegistry) error {
- return func(r *SimpleValueRegistry) error {
- if sv >= 24 && sv <= 31 {
- return fmt.Errorf("cbor: cannot set analog for reserved simple value %d", sv)
- }
- r.rejected[sv] = true
- return nil
- }
- }
- // Creates a new SimpleValueRegistry. The registry state is initialized by executing the provided
- // functions in order against a registry that is pre-populated with the defaults for all well-formed
- // simple value numbers.
- func NewSimpleValueRegistryFromDefaults(fns ...func(*SimpleValueRegistry) error) (*SimpleValueRegistry, error) {
- var r SimpleValueRegistry
- for _, fn := range fns {
- if err := fn(&r); err != nil {
- return nil, err
- }
- }
- return &r, nil
- }
- // NaNMode specifies how to decode floating-point values (major type 7, additional information 25
- // through 27) representing NaN (not-a-number).
- type NaNMode int
- const (
- // NaNDecodeAllowed will decode NaN values to Go float32 or float64.
- NaNDecodeAllowed NaNMode = iota
- // NaNDecodeForbidden will return an UnacceptableDataItemError on an attempt to decode a NaN value.
- NaNDecodeForbidden
- maxNaNDecode
- )
- func (ndm NaNMode) valid() bool {
- return ndm >= 0 && ndm < maxNaNDecode
- }
- // InfMode specifies how to decode floating-point values (major type 7, additional information 25
- // through 27) representing positive or negative infinity.
- type InfMode int
- const (
- // InfDecodeAllowed will decode infinite values to Go float32 or float64.
- InfDecodeAllowed InfMode = iota
- // InfDecodeForbidden will return an UnacceptableDataItemError on an attempt to decode an
- // infinite value.
- InfDecodeForbidden
- maxInfDecode
- )
- func (idm InfMode) valid() bool {
- return idm >= 0 && idm < maxInfDecode
- }
- // ByteStringToTimeMode specifies the behavior when decoding a CBOR byte string into a Go time.Time.
- type ByteStringToTimeMode int
- const (
- // ByteStringToTimeForbidden generates an error on an attempt to decode a CBOR byte string into a Go time.Time.
- ByteStringToTimeForbidden ByteStringToTimeMode = iota
- // ByteStringToTimeAllowed permits decoding a CBOR byte string into a Go time.Time.
- ByteStringToTimeAllowed
- maxByteStringToTimeMode
- )
- func (bttm ByteStringToTimeMode) valid() bool {
- return bttm >= 0 && bttm < maxByteStringToTimeMode
- }
- // ByteStringExpectedFormatMode specifies how to decode CBOR byte string into Go byte slice
- // when the byte string is NOT enclosed in CBOR tag 21, 22, or 23. An error is returned if
- // the CBOR byte string does not contain the expected format (e.g. base64) specified.
- // For tags 21-23, see "Expected Later Encoding for CBOR-to-JSON Converters"
- // in RFC 8949 Section 3.4.5.2.
- type ByteStringExpectedFormatMode int
- const (
- // ByteStringExpectedFormatNone copies the unmodified CBOR byte string into Go byte slice
- // if the byte string is not tagged by CBOR tag 21-23.
- ByteStringExpectedFormatNone ByteStringExpectedFormatMode = iota
- // ByteStringExpectedBase64URL expects CBOR byte strings to contain base64url-encoded bytes
- // if the byte string is not tagged by CBOR tag 21-23. The decoder will attempt to decode
- // the base64url-encoded bytes into Go slice.
- ByteStringExpectedBase64URL
- // ByteStringExpectedBase64 expects CBOR byte strings to contain base64-encoded bytes
- // if the byte string is not tagged by CBOR tag 21-23. The decoder will attempt to decode
- // the base64-encoded bytes into Go slice.
- ByteStringExpectedBase64
- // ByteStringExpectedBase16 expects CBOR byte strings to contain base16-encoded bytes
- // if the byte string is not tagged by CBOR tag 21-23. The decoder will attempt to decode
- // the base16-encoded bytes into Go slice.
- ByteStringExpectedBase16
- maxByteStringExpectedFormatMode
- )
- func (bsefm ByteStringExpectedFormatMode) valid() bool {
- return bsefm >= 0 && bsefm < maxByteStringExpectedFormatMode
- }
- // BignumTagMode specifies whether or not the "bignum" tags 2 and 3 (RFC 8949 Section 3.4.3) can be
- // decoded.
- type BignumTagMode int
- const (
- // BignumTagAllowed allows bignum tags to be decoded.
- BignumTagAllowed BignumTagMode = iota
- // BignumTagForbidden produces an UnacceptableDataItemError during Unmarshal if a bignum tag
- // is encountered in the input.
- BignumTagForbidden
- maxBignumTag
- )
- func (btm BignumTagMode) valid() bool {
- return btm >= 0 && btm < maxBignumTag
- }
- // BinaryUnmarshalerMode specifies how to decode into types that implement
- // encoding.BinaryUnmarshaler.
- type BinaryUnmarshalerMode int
- const (
- // BinaryUnmarshalerByteString will invoke UnmarshalBinary on the contents of a CBOR byte
- // string when decoding into a value that implements BinaryUnmarshaler.
- BinaryUnmarshalerByteString BinaryUnmarshalerMode = iota
- // BinaryUnmarshalerNone does not recognize BinaryUnmarshaler implementations during decode.
- BinaryUnmarshalerNone
- maxBinaryUnmarshalerMode
- )
- func (bum BinaryUnmarshalerMode) valid() bool {
- return bum >= 0 && bum < maxBinaryUnmarshalerMode
- }
- // TextUnmarshalerMode specifies how to decode into types that implement
- // encoding.TextUnmarshaler.
- type TextUnmarshalerMode int
- const (
- // TextUnmarshalerNone does not recognize TextUnmarshaler implementations during decode.
- TextUnmarshalerNone TextUnmarshalerMode = iota
- // TextUnmarshalerTextString will invoke UnmarshalText on the contents of a CBOR text
- // string when decoding into a value that implements TextUnmarshaler.
- TextUnmarshalerTextString
- maxTextUnmarshalerMode
- )
- func (tum TextUnmarshalerMode) valid() bool {
- return tum >= 0 && tum < maxTextUnmarshalerMode
- }
- // DecOptions specifies decoding options.
- type DecOptions struct {
- // DupMapKey specifies whether to enforce duplicate map key.
- DupMapKey DupMapKeyMode
- // TimeTag specifies whether or not untagged data items, or tags other
- // than tag 0 and tag 1, can be decoded to time.Time. If tag 0 or tag 1
- // appears in an input, the type of its content is always validated as
- // specified in RFC 8949. That behavior is not controlled by this
- // option. The behavior of the supported modes are:
- //
- // DecTagIgnored (default): Untagged text strings and text strings
- // enclosed in tags other than 0 and 1 are decoded as though enclosed
- // in tag 0. Untagged unsigned integers, negative integers, and
- // floating-point numbers (or those enclosed in tags other than 0 and
- // 1) are decoded as though enclosed in tag 1. Decoding a tag other
- // than 0 or 1 enclosing simple values null or undefined into a
- // time.Time does not modify the destination value.
- //
- // DecTagOptional: Untagged text strings are decoded as though
- // enclosed in tag 0. Untagged unsigned integers, negative integers,
- // and floating-point numbers are decoded as though enclosed in tag
- // 1. Tags other than 0 and 1 will produce an error on attempts to
- // decode them into a time.Time.
- //
- // DecTagRequired: Only tags 0 and 1 can be decoded to time.Time. Any
- // other input will produce an error.
- 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, 65535]. Note that higher maximum levels of nesting can
- // require larger amounts of stack to deserialize. Don't increase this higher than you require.
- 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, uint64, or [big.Int]) to use
- // when decoding CBOR int (major type 0 and 1) to Go interface{}.
- IntDec IntDecMode
- // MapKeyByteString specifies how to decode CBOR byte string as map key
- // when decoding CBOR map with byte string key into an empty interface value.
- // By default, an error is returned when attempting to decode CBOR byte string
- // as map key because Go doesn't allow []byte as map key.
- MapKeyByteString MapKeyByteStringMode
- // ExtraReturnErrors specifies extra conditions that should be treated as errors.
- ExtraReturnErrors ExtraDecErrorCond
- // DefaultMapType specifies Go map type to create and decode to
- // when unmarshaling CBOR into an empty interface value.
- // By default, unmarshal uses map[interface{}]interface{}.
- DefaultMapType reflect.Type
- // UTF8 specifies if decoder should decode CBOR Text containing invalid UTF-8.
- // By default, unmarshal rejects CBOR text containing invalid UTF-8.
- UTF8 UTF8Mode
- // FieldNameMatching specifies how string keys in CBOR maps are matched to Go struct field names.
- FieldNameMatching FieldNameMatchingMode
- // BigIntDec specifies how to decode CBOR bignum to Go interface{}.
- BigIntDec BigIntDecMode
- // DefaultByteStringType is the Go type that should be produced when decoding a CBOR byte
- // string into an empty interface value. Types to which a []byte is convertible are valid
- // for this option, except for array and pointer-to-array types. If nil, the default is
- // []byte.
- DefaultByteStringType reflect.Type
- // ByteStringToString specifies the behavior when decoding a CBOR byte string into a Go string.
- ByteStringToString ByteStringToStringMode
- // FieldNameByteString specifies the behavior when decoding a CBOR byte string map key as a
- // Go struct field name.
- FieldNameByteString FieldNameByteStringMode
- // UnrecognizedTagToAny specifies how to decode unrecognized CBOR tag into an empty interface.
- // Currently, recognized CBOR tag numbers are 0, 1, 2, 3, or registered by TagSet.
- UnrecognizedTagToAny UnrecognizedTagToAnyMode
- // TimeTagToAny specifies how to decode CBOR tag 0 and 1 into an empty interface (any).
- // Based on the specified mode, Unmarshal can return a time.Time value or a time string in a specific format.
- TimeTagToAny TimeTagToAnyMode
- // SimpleValues is an immutable mapping from each CBOR simple value to a corresponding
- // unmarshal behavior. If nil, the simple values false, true, null, and undefined are mapped
- // to the Go analog values false, true, nil, and nil, respectively, and all other simple
- // values N (except the reserved simple values 24 through 31) are mapped to
- // cbor.SimpleValue(N). In other words, all well-formed simple values can be decoded.
- //
- // Users may provide a custom SimpleValueRegistry constructed via
- // NewSimpleValueRegistryFromDefaults.
- SimpleValues *SimpleValueRegistry
- // NaN specifies how to decode floating-point values (major type 7, additional information
- // 25 through 27) representing NaN (not-a-number).
- NaN NaNMode
- // Inf specifies how to decode floating-point values (major type 7, additional information
- // 25 through 27) representing positive or negative infinity.
- Inf InfMode
- // ByteStringToTime specifies how to decode CBOR byte string into Go time.Time.
- ByteStringToTime ByteStringToTimeMode
- // ByteStringExpectedFormat specifies how to decode CBOR byte string into Go byte slice
- // when the byte string is NOT enclosed in CBOR tag 21, 22, or 23. An error is returned if
- // the CBOR byte string does not contain the expected format (e.g. base64) specified.
- // For tags 21-23, see "Expected Later Encoding for CBOR-to-JSON Converters"
- // in RFC 8949 Section 3.4.5.2.
- ByteStringExpectedFormat ByteStringExpectedFormatMode
- // BignumTag specifies whether or not the "bignum" tags 2 and 3 (RFC 8949 Section 3.4.3) can
- // be decoded. Unlike BigIntDec, this option applies to all bignum tags encountered in a
- // CBOR input, independent of the type of the destination value of a particular Unmarshal
- // operation.
- BignumTag BignumTagMode
- // BinaryUnmarshaler specifies how to decode into types that implement
- // encoding.BinaryUnmarshaler.
- BinaryUnmarshaler BinaryUnmarshalerMode
- // TextUnmarshaler specifies how to decode into types that implement
- // encoding.TextUnmarshaler.
- TextUnmarshaler TextUnmarshalerMode
- // JSONUnmarshalerTranscoder sets the transcoding scheme used to unmarshal types that
- // implement json.Unmarshaler but do not also implement cbor.Unmarshaler. If nil, decoding
- // behavior is not influenced by whether or not a type implements json.Unmarshaler.
- JSONUnmarshalerTranscoder Transcoder
- }
- // DecMode returns DecMode with immutable options and no tags (safe for concurrency).
- func (opts DecOptions) DecMode() (DecMode, error) { //nolint:gocritic // ignore hugeParam
- return opts.decMode()
- }
- // validForTags checks that the provided tag set is compatible with these options and returns a
- // non-nil error if and only if the provided tag set is incompatible.
- func (opts DecOptions) validForTags(tags TagSet) error { //nolint:gocritic // ignore hugeParam
- if opts.TagsMd == TagsForbidden {
- return errors.New("cbor: cannot create DecMode with TagSet when TagsMd is TagsForbidden")
- }
- if tags == nil {
- return errors.New("cbor: cannot create DecMode with nil value as TagSet")
- }
- if opts.ByteStringToString == ByteStringToStringAllowedWithExpectedLaterEncoding ||
- opts.ByteStringExpectedFormat != ByteStringExpectedFormatNone {
- for _, tagNum := range []uint64{
- tagNumExpectedLaterEncodingBase64URL,
- tagNumExpectedLaterEncodingBase64,
- tagNumExpectedLaterEncodingBase16,
- } {
- if rt := tags.getTypeFromTagNum([]uint64{tagNum}); rt != nil {
- return fmt.Errorf("cbor: DecMode with non-default StringExpectedEncoding or ByteSliceExpectedEncoding treats tag %d as built-in and conflicts with the provided TagSet's registration of %v", tagNum, rt)
- }
- }
- }
- return nil
- }
- // DecModeWithTags returns DecMode with options and tags that are both immutable (safe for concurrency).
- func (opts DecOptions) DecModeWithTags(tags TagSet) (DecMode, error) { //nolint:gocritic // ignore hugeParam
- if err := opts.validForTags(tags); err != nil {
- return nil, err
- }
- 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) { //nolint:gocritic // ignore hugeParam
- if err := opts.validForTags(tags); err != nil {
- return nil, err
- }
- 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
- defaultMaxNestedLevels = 32
- minMaxNestedLevels = 4
- maxMaxNestedLevels = 65535
- )
- var defaultSimpleValues = func() *SimpleValueRegistry {
- registry, err := NewSimpleValueRegistryFromDefaults()
- if err != nil {
- panic(err)
- }
- return registry
- }()
- //nolint:gocyclo // Each option comes with some manageable boilerplate
- func (opts DecOptions) decMode() (*decMode, error) { //nolint:gocritic // ignore hugeParam
- 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.MapKeyByteString.valid() {
- return nil, errors.New("cbor: invalid MapKeyByteString " + strconv.Itoa(int(opts.MapKeyByteString)))
- }
- if opts.MaxNestedLevels == 0 {
- opts.MaxNestedLevels = defaultMaxNestedLevels
- } else if opts.MaxNestedLevels < minMaxNestedLevels || opts.MaxNestedLevels > maxMaxNestedLevels {
- return nil, errors.New("cbor: invalid MaxNestedLevels " + strconv.Itoa(opts.MaxNestedLevels) +
- " (range is [" + strconv.Itoa(minMaxNestedLevels) + ", " + strconv.Itoa(maxMaxNestedLevels) + "])")
- }
- 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)))
- }
- if opts.DefaultMapType != nil && opts.DefaultMapType.Kind() != reflect.Map {
- return nil, fmt.Errorf("cbor: invalid DefaultMapType %s", opts.DefaultMapType)
- }
- if !opts.UTF8.valid() {
- return nil, errors.New("cbor: invalid UTF8 " + strconv.Itoa(int(opts.UTF8)))
- }
- if !opts.FieldNameMatching.valid() {
- return nil, errors.New("cbor: invalid FieldNameMatching " + strconv.Itoa(int(opts.FieldNameMatching)))
- }
- if !opts.BigIntDec.valid() {
- return nil, errors.New("cbor: invalid BigIntDec " + strconv.Itoa(int(opts.BigIntDec)))
- }
- if opts.DefaultByteStringType != nil &&
- opts.DefaultByteStringType.Kind() != reflect.String &&
- (opts.DefaultByteStringType.Kind() != reflect.Slice || opts.DefaultByteStringType.Elem().Kind() != reflect.Uint8) {
- return nil, fmt.Errorf("cbor: invalid DefaultByteStringType: %s is not of kind string or []uint8", opts.DefaultByteStringType)
- }
- if !opts.ByteStringToString.valid() {
- return nil, errors.New("cbor: invalid ByteStringToString " + strconv.Itoa(int(opts.ByteStringToString)))
- }
- if !opts.FieldNameByteString.valid() {
- return nil, errors.New("cbor: invalid FieldNameByteString " + strconv.Itoa(int(opts.FieldNameByteString)))
- }
- if !opts.UnrecognizedTagToAny.valid() {
- return nil, errors.New("cbor: invalid UnrecognizedTagToAnyMode " + strconv.Itoa(int(opts.UnrecognizedTagToAny)))
- }
- simpleValues := opts.SimpleValues
- if simpleValues == nil {
- simpleValues = defaultSimpleValues
- }
- if !opts.TimeTagToAny.valid() {
- return nil, errors.New("cbor: invalid TimeTagToAny " + strconv.Itoa(int(opts.TimeTagToAny)))
- }
- if !opts.NaN.valid() {
- return nil, errors.New("cbor: invalid NaNDec " + strconv.Itoa(int(opts.NaN)))
- }
- if !opts.Inf.valid() {
- return nil, errors.New("cbor: invalid InfDec " + strconv.Itoa(int(opts.Inf)))
- }
- if !opts.ByteStringToTime.valid() {
- return nil, errors.New("cbor: invalid ByteStringToTime " + strconv.Itoa(int(opts.ByteStringToTime)))
- }
- if !opts.ByteStringExpectedFormat.valid() {
- return nil, errors.New("cbor: invalid ByteStringExpectedFormat " + strconv.Itoa(int(opts.ByteStringExpectedFormat)))
- }
- if !opts.BignumTag.valid() {
- return nil, errors.New("cbor: invalid BignumTag " + strconv.Itoa(int(opts.BignumTag)))
- }
- if !opts.BinaryUnmarshaler.valid() {
- return nil, errors.New("cbor: invalid BinaryUnmarshaler " + strconv.Itoa(int(opts.BinaryUnmarshaler)))
- }
- if !opts.TextUnmarshaler.valid() {
- return nil, errors.New("cbor: invalid TextUnmarshaler " + strconv.Itoa(int(opts.TextUnmarshaler)))
- }
- 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,
- mapKeyByteString: opts.MapKeyByteString,
- extraReturnErrors: opts.ExtraReturnErrors,
- defaultMapType: opts.DefaultMapType,
- utf8: opts.UTF8,
- fieldNameMatching: opts.FieldNameMatching,
- bigIntDec: opts.BigIntDec,
- defaultByteStringType: opts.DefaultByteStringType,
- byteStringToString: opts.ByteStringToString,
- fieldNameByteString: opts.FieldNameByteString,
- unrecognizedTagToAny: opts.UnrecognizedTagToAny,
- timeTagToAny: opts.TimeTagToAny,
- simpleValues: simpleValues,
- nanDec: opts.NaN,
- infDec: opts.Inf,
- byteStringToTime: opts.ByteStringToTime,
- byteStringExpectedFormat: opts.ByteStringExpectedFormat,
- bignumTag: opts.BignumTag,
- binaryUnmarshaler: opts.BinaryUnmarshaler,
- textUnmarshaler: opts.TextUnmarshaler,
- jsonUnmarshalerTranscoder: opts.JSONUnmarshalerTranscoder,
- }
- 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 any) error
- // UnmarshalFirst parses the first CBOR data item into the value pointed to by v
- // using the decoding mode. Any remaining bytes are returned in rest.
- //
- // If v is nil, not a pointer, or a nil pointer, UnmarshalFirst returns an error.
- //
- // See the documentation for Unmarshal for details.
- UnmarshalFirst(data []byte, v any) (rest []byte, err error)
- // Valid checks whether data is a well-formed encoded CBOR data item and
- // that it complies with configurable restrictions such as MaxNestedLevels,
- // MaxArrayElements, MaxMapPairs, etc.
- //
- // If there are any remaining bytes after the CBOR data item,
- // an ExtraneousDataError is returned.
- //
- // WARNING: Valid doesn't check if encoded CBOR data item is valid (i.e. validity)
- // and RFC 8949 distinctly defines what is "Valid" and what is "Well-formed".
- //
- // Deprecated: Valid is kept for compatibility and should not be used.
- // Use Wellformed instead because it has a more appropriate name.
- Valid(data []byte) error
- // Wellformed checks whether data is a well-formed encoded CBOR data item and
- // that it complies with configurable restrictions such as MaxNestedLevels,
- // MaxArrayElements, MaxMapPairs, etc.
- //
- // If there are any remaining bytes after the CBOR data item,
- // an ExtraneousDataError is returned.
- Wellformed(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
- mapKeyByteString MapKeyByteStringMode
- extraReturnErrors ExtraDecErrorCond
- defaultMapType reflect.Type
- utf8 UTF8Mode
- fieldNameMatching FieldNameMatchingMode
- bigIntDec BigIntDecMode
- defaultByteStringType reflect.Type
- byteStringToString ByteStringToStringMode
- fieldNameByteString FieldNameByteStringMode
- unrecognizedTagToAny UnrecognizedTagToAnyMode
- timeTagToAny TimeTagToAnyMode
- simpleValues *SimpleValueRegistry
- nanDec NaNMode
- infDec InfMode
- byteStringToTime ByteStringToTimeMode
- byteStringExpectedFormat ByteStringExpectedFormatMode
- bignumTag BignumTagMode
- binaryUnmarshaler BinaryUnmarshalerMode
- textUnmarshaler TextUnmarshalerMode
- jsonUnmarshalerTranscoder Transcoder
- }
- var defaultDecMode, _ = DecOptions{}.decMode()
- // DecOptions returns user specified options used to create this DecMode.
- func (dm *decMode) DecOptions() DecOptions {
- simpleValues := dm.simpleValues
- if simpleValues == defaultSimpleValues {
- // Users can't explicitly set this to defaultSimpleValues. It must have been nil in
- // the original DecOptions.
- simpleValues = nil
- }
- 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,
- MapKeyByteString: dm.mapKeyByteString,
- ExtraReturnErrors: dm.extraReturnErrors,
- DefaultMapType: dm.defaultMapType,
- UTF8: dm.utf8,
- FieldNameMatching: dm.fieldNameMatching,
- BigIntDec: dm.bigIntDec,
- DefaultByteStringType: dm.defaultByteStringType,
- ByteStringToString: dm.byteStringToString,
- FieldNameByteString: dm.fieldNameByteString,
- UnrecognizedTagToAny: dm.unrecognizedTagToAny,
- TimeTagToAny: dm.timeTagToAny,
- SimpleValues: simpleValues,
- NaN: dm.nanDec,
- Inf: dm.infDec,
- ByteStringToTime: dm.byteStringToTime,
- ByteStringExpectedFormat: dm.byteStringExpectedFormat,
- BignumTag: dm.bignumTag,
- BinaryUnmarshaler: dm.binaryUnmarshaler,
- TextUnmarshaler: dm.textUnmarshaler,
- JSONUnmarshalerTranscoder: dm.jsonUnmarshalerTranscoder,
- }
- }
- // 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 any) error {
- d := decoder{data: data, dm: dm}
- // Check well-formedness.
- off := d.off // Save offset before data validation
- err := d.wellformed(false, false) // don't allow any extra data after valid data item.
- d.off = off // Restore offset
- if err != nil {
- return err
- }
- return d.value(v)
- }
- // UnmarshalFirst parses the first CBOR data item into the value pointed to by v
- // using dm decoding mode. Any remaining bytes are returned in rest.
- //
- // If v is nil, not a pointer, or a nil pointer, UnmarshalFirst returns an error.
- //
- // See the documentation for Unmarshal for details.
- func (dm *decMode) UnmarshalFirst(data []byte, v any) (rest []byte, err error) {
- d := decoder{data: data, dm: dm}
- // check well-formedness.
- off := d.off // Save offset before data validation
- err = d.wellformed(true, false) // allow extra data after well-formed data item
- d.off = off // Restore offset
- // If it is well-formed, parse the value. This is structured like this to allow
- // better test coverage
- if err == nil {
- err = d.value(v)
- }
- // If either wellformed or value returned an error, do not return rest bytes
- if err != nil {
- return nil, err
- }
- // Return the rest of the data slice (which might be len 0)
- return d.data[d.off:], nil
- }
- // Valid checks whether data is a well-formed encoded CBOR data item and
- // that it complies with configurable restrictions such as MaxNestedLevels,
- // MaxArrayElements, MaxMapPairs, etc.
- //
- // If there are any remaining bytes after the CBOR data item,
- // an ExtraneousDataError is returned.
- //
- // WARNING: Valid doesn't check if encoded CBOR data item is valid (i.e. validity)
- // and RFC 8949 distinctly defines what is "Valid" and what is "Well-formed".
- //
- // Deprecated: Valid is kept for compatibility and should not be used.
- // Use Wellformed instead because it has a more appropriate name.
- func (dm *decMode) Valid(data []byte) error {
- return dm.Wellformed(data)
- }
- // Wellformed checks whether data is a well-formed encoded CBOR data item and
- // that it complies with configurable restrictions such as MaxNestedLevels,
- // MaxArrayElements, MaxMapPairs, etc.
- //
- // If there are any remaining bytes after the CBOR data item,
- // an ExtraneousDataError is returned.
- func (dm *decMode) Wellformed(data []byte) error {
- d := decoder{data: data, dm: dm}
- return d.wellformed(false, false)
- }
- // 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
- // expectedLaterEncodingTags stores a stack of encountered "Expected Later Encoding" tags,
- // if any.
- //
- // The "Expected Later Encoding" tags (21 to 23) are valid for any data item. When decoding
- // byte strings, the effective encoding comes from the tag nearest to the byte string being
- // decoded. For example, the effective encoding of the byte string 21(22(h'41')) would be
- // controlled by tag 22,and in the data item 23(h'42', 22([21(h'43')])]) the effective
- // encoding of the byte strings h'42' and h'43' would be controlled by tag 23 and 21,
- // respectively.
- expectedLaterEncodingTags []uint64
- }
- // value decodes CBOR data item into the value pointed to by v.
- // If CBOR data item fails to be decoded into v,
- // error is returned and offset is moved to the next CBOR data item.
- // Precondition: d.data contains at least one well-formed CBOR data item.
- func (d *decoder) value(v any) 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.Pointer {
- return &InvalidUnmarshalError{"cbor: Unmarshal(non-pointer " + rv.Type().String() + ")"}
- } else if rv.IsNil() {
- return &InvalidUnmarshalError{"cbor: Unmarshal(nil " + rv.Type().String() + ")"}
- }
- rv = rv.Elem()
- return d.parseToValue(rv, getTypeInfo(rv.Type()))
- }
- // 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
- // Decode CBOR nil or CBOR undefined to pointer value by setting pointer value to nil.
- if d.nextCBORNil() && v.Kind() == reflect.Pointer {
- d.skip()
- v.SetZero()
- return nil
- }
- if tInfo.spclType == specialTypeIface {
- if !v.IsNil() {
- // Use value type
- v = v.Elem()
- tInfo = getTypeInfo(v.Type())
- } else { //nolint:gocritic
- // Create and use registered type if CBOR data is registered tag
- if d.dm.tags != nil && d.nextCBORType() == cborTypeTag {
- off := d.off
- var tagNums []uint64
- for d.nextCBORType() == cborTypeTag {
- _, _, tagNum := d.getHead()
- tagNums = append(tagNums, tagNum)
- }
- d.off = off
- registeredType := d.dm.tags.getTypeFromTagNum(tagNums)
- if registeredType != nil {
- if registeredType.Implements(tInfo.nonPtrType) ||
- reflect.PointerTo(registeredType).Implements(tInfo.nonPtrType) {
- v.Set(reflect.New(registeredType))
- v = v.Elem()
- tInfo = getTypeInfo(registeredType)
- }
- }
- }
- }
- }
- // Create new value for the pointer v to point to.
- // At this point, CBOR value is not nil/undefined if v is a pointer.
- for v.Kind() == reflect.Pointer {
- 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 != tagNumSelfDescribedCBOR {
- d.off = off
- break
- }
- }
- // Check validity of supported built-in tags.
- off := d.off
- for d.nextCBORType() == cborTypeTag {
- _, _, 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, ok, err := d.parseToTime()
- if err != nil {
- return err
- }
- if ok {
- v.Set(reflect.ValueOf(tm))
- }
- return nil
- case specialTypeUnmarshalerIface:
- return d.parseToUnmarshaler(v)
- case specialTypeUnexportedUnmarshalerIface:
- return d.parseToUnexportedUnmarshaler(v)
- case specialTypeJSONUnmarshalerIface:
- // This special type implies that the type does not also implement
- // cbor.Umarshaler.
- if d.dm.jsonUnmarshalerTranscoder == nil {
- break
- }
- return d.parseToJSONUnmarshaler(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, copied := d.parseByteString()
- b, converted, err := d.applyByteStringTextConversion(b, v.Type())
- if err != nil {
- return err
- }
- copied = copied || converted
- return fillByteString(t, b, !copied, v, d.dm.byteStringToString, d.dm.binaryUnmarshaler, d.dm.textUnmarshaler)
- case cborTypeTextString:
- b, err := d.parseTextString()
- if err != nil {
- return err
- }
- return fillTextString(t, b, v, d.dm.textUnmarshaler)
- case cborTypePrimitives:
- _, ai, val := d.getHead()
- switch ai {
- case additionalInformationAsFloat16:
- f := float64(float16.Frombits(uint16(val)).Float32())
- return fillFloat(t, f, v)
- case additionalInformationAsFloat32:
- f := float64(math.Float32frombits(uint32(val)))
- return fillFloat(t, f, v)
- case additionalInformationAsFloat64:
- f := math.Float64frombits(val)
- return fillFloat(t, f, v)
- default: // ai <= 24
- if d.dm.simpleValues.rejected[SimpleValue(val)] {
- return &UnacceptableDataItemError{
- CBORType: t.String(),
- Message: "simple value " + strconv.FormatInt(int64(val), 10) + " is not recognized",
- }
- }
- switch ai {
- case additionalInformationAsFalse,
- additionalInformationAsTrue:
- return fillBool(t, ai == additionalInformationAsTrue, v)
- case additionalInformationAsNull,
- additionalInformationAsUndefined:
- return fillNil(t, v)
- default:
- return fillPositiveInt(t, val, v)
- }
- }
- case cborTypeTag:
- _, _, tagNum := d.getHead()
- switch tagNum {
- case tagNumUnsignedBignum:
- // Bignum (tag 2) can be decoded to uint, int, float, slice, array, or big.Int.
- b, copied := 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, !copied, v, ByteStringToStringForbidden, d.dm.binaryUnmarshaler, d.dm.textUnmarshaler)
- }
- 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 tagNumNegativeBignum:
- // Bignum (tag 3) can be decoded to int, float, slice, array, or big.Int.
- b, copied := 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, !copied, v, ByteStringToStringForbidden, d.dm.binaryUnmarshaler, d.dm.textUnmarshaler)
- }
- 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(),
- }
- case tagNumExpectedLaterEncodingBase64URL, tagNumExpectedLaterEncodingBase64, tagNumExpectedLaterEncodingBase16:
- // If conversion for interoperability with text encodings is not configured,
- // treat tags 21-23 as unregistered tags.
- if d.dm.byteStringToString == ByteStringToStringAllowedWithExpectedLaterEncoding || d.dm.byteStringExpectedFormat != ByteStringExpectedFormatNone {
- d.expectedLaterEncodingTags = append(d.expectedLaterEncodingTags, tagNum)
- defer func() {
- d.expectedLaterEncodingTags = d.expectedLaterEncodingTags[:len(d.expectedLaterEncodingTags)-1]
- }()
- }
- }
- 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
- }
- // parseToTime decodes the current data item as a time.Time. The bool return value is false if and
- // only if the destination value should remain unmodified.
- func (d *decoder) parseToTime() (time.Time, bool, error) {
- // Verify that tag number or absence of tag number is acceptable to specified timeTag.
- if t := d.nextCBORType(); t == cborTypeTag {
- if d.dm.timeTag == DecTagIgnored {
- // Skip all enclosing tags
- for t == cborTypeTag {
- d.getHead()
- t = d.nextCBORType()
- }
- if d.nextCBORNil() {
- d.skip()
- return time.Time{}, false, nil
- }
- } else {
- // Read tag number
- _, _, tagNum := d.getHead()
- if tagNum != 0 && tagNum != 1 {
- d.skip() // skip tag content
- return time.Time{}, false, errors.New("cbor: wrong tag number for time.Time, got " + strconv.Itoa(int(tagNum)) + ", expect 0 or 1")
- }
- }
- } else {
- if d.dm.timeTag == DecTagRequired {
- d.skip()
- return time.Time{}, false, &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String(), errorMsg: "expect CBOR tag value"}
- }
- }
- switch t := d.nextCBORType(); t {
- case cborTypeByteString:
- if d.dm.byteStringToTime == ByteStringToTimeAllowed {
- b, _ := d.parseByteString()
- t, err := time.Parse(time.RFC3339, string(b))
- if err != nil {
- return time.Time{}, false, fmt.Errorf("cbor: cannot set %q for time.Time: %w", string(b), err)
- }
- return t, true, nil
- }
- return time.Time{}, false, &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String()}
- case cborTypeTextString:
- s, err := d.parseTextString()
- if err != nil {
- return time.Time{}, false, err
- }
- t, err := time.Parse(time.RFC3339, string(s))
- if err != nil {
- return time.Time{}, false, errors.New("cbor: cannot set " + string(s) + " for time.Time: " + err.Error())
- }
- return t, true, nil
- case cborTypePositiveInt:
- _, _, val := d.getHead()
- if val > math.MaxInt64 {
- return time.Time{}, false, &UnmarshalTypeError{
- CBORType: t.String(),
- GoType: typeTime.String(),
- errorMsg: fmt.Sprintf("%d overflows Go's int64", val),
- }
- }
- return time.Unix(int64(val), 0), true, nil
- case cborTypeNegativeInt:
- _, _, val := d.getHead()
- if val > math.MaxInt64 {
- if val == math.MaxUint64 {
- // Maximum absolute value representable by negative integer is 2^64,
- // not 2^64-1, so it overflows uint64.
- return time.Time{}, false, &UnmarshalTypeError{
- CBORType: t.String(),
- GoType: typeTime.String(),
- errorMsg: "-18446744073709551616 overflows Go's int64",
- }
- }
- return time.Time{}, false, &UnmarshalTypeError{
- CBORType: t.String(),
- GoType: typeTime.String(),
- errorMsg: fmt.Sprintf("-%d overflows Go's int64", val+1),
- }
- }
- return time.Unix(int64(-1)^int64(val), 0), true, nil
- case cborTypePrimitives:
- _, ai, val := d.getHead()
- var f float64
- switch ai {
- case additionalInformationAsFloat16:
- f = float64(float16.Frombits(uint16(val)).Float32())
- case additionalInformationAsFloat32:
- f = float64(math.Float32frombits(uint32(val)))
- case additionalInformationAsFloat64:
- f = math.Float64frombits(val)
- default:
- return time.Time{}, false, &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String()}
- }
- if math.IsNaN(f) || math.IsInf(f, 0) {
- // https://www.rfc-editor.org/rfc/rfc8949.html#section-3.4.2-6
- return time.Time{}, true, nil
- }
- seconds, fractional := math.Modf(f)
- return time.Unix(int64(seconds), int64(fractional*1e9)), true, nil
- default:
- return time.Time{}, false, &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String()}
- }
- }
- // 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.Pointer && v.IsNil() {
- d.skip()
- return nil
- }
- if v.Kind() != reflect.Pointer && 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")
- }
- // parseToUnexportedUnmarshaler parses CBOR data to value implementing unmarshaler interface.
- // It assumes data is well-formed, and does not perform bounds checking.
- func (d *decoder) parseToUnexportedUnmarshaler(v reflect.Value) error {
- if d.nextCBORNil() && v.Kind() == reflect.Pointer && v.IsNil() {
- d.skip()
- return nil
- }
- if v.Kind() != reflect.Pointer && 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")
- }
- // parseToJSONUnmarshaler parses CBOR data to be transcoded to JSON and passed to the value's
- // implementation of the json.Unmarshaler interface. It assumes data is well-formed, and does not
- // perform bounds checking.
- func (d *decoder) parseToJSONUnmarshaler(v reflect.Value) error {
- if d.nextCBORNil() && v.Kind() == reflect.Pointer && v.IsNil() {
- d.skip()
- return nil
- }
- if v.Kind() != reflect.Pointer && v.CanAddr() {
- v = v.Addr()
- }
- if u, ok := v.Interface().(jsonUnmarshaler); ok {
- start := d.off
- d.skip()
- e := getEncodeBuffer()
- defer putEncodeBuffer(e)
- if err := d.dm.jsonUnmarshalerTranscoder.Transcode(e, bytes.NewReader(d.data[start:d.off])); err != nil {
- return &TranscodeError{err: err, rtype: v.Type(), sourceFormat: "cbor", targetFormat: "json"}
- }
- return u.UnmarshalJSON(e.Bytes())
- }
- d.skip()
- return errors.New("cbor: failed to assert " + v.Type().String() + " as json.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) (any, error) { //nolint:gocyclo
- // Strip self-described CBOR tag number.
- if skipSelfDescribedTag {
- for d.nextCBORType() == cborTypeTag {
- off := d.off
- _, _, tagNum := d.getHead()
- if tagNum != tagNumSelfDescribedCBOR {
- d.off = off
- break
- }
- }
- }
- // Check validity of supported built-in tags.
- off := d.off
- for d.nextCBORType() == cborTypeTag {
- _, _, 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()
- switch d.dm.intDec {
- case IntDecConvertNone:
- return val, nil
- case IntDecConvertSigned, IntDecConvertSignedOrFail:
- 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 IntDecConvertSignedOrBigInt:
- if val > math.MaxInt64 {
- bi := new(big.Int).SetUint64(val)
- if d.dm.bigIntDec == BigIntDecodePointer {
- return bi, nil
- }
- return *bi, nil
- }
- return int64(val), nil
- default:
- // not reachable
- }
- 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)
- if d.dm.intDec == IntDecConvertSignedOrFail {
- return nil, &UnmarshalTypeError{
- CBORType: t.String(),
- GoType: reflect.TypeOf(int64(0)).String(),
- errorMsg: bi.String() + " overflows Go's int64",
- }
- }
- if d.dm.bigIntDec == BigIntDecodePointer {
- return bi, nil
- }
- return *bi, nil
- }
- nValue := int64(-1) ^ int64(val)
- return nValue, nil
- case cborTypeByteString:
- b, copied := d.parseByteString()
- var effectiveByteStringType = d.dm.defaultByteStringType
- if effectiveByteStringType == nil {
- effectiveByteStringType = typeByteSlice
- }
- b, converted, err := d.applyByteStringTextConversion(b, effectiveByteStringType)
- if err != nil {
- return nil, err
- }
- copied = copied || converted
- switch effectiveByteStringType {
- case typeByteSlice:
- if copied {
- return b, nil
- }
- clone := make([]byte, len(b))
- copy(clone, b)
- return clone, nil
- case typeString:
- return string(b), nil
- default:
- if copied || d.dm.defaultByteStringType.Kind() == reflect.String {
- // Avoid an unnecessary copy since the conversion to string must
- // copy the underlying bytes.
- return reflect.ValueOf(b).Convert(d.dm.defaultByteStringType).Interface(), nil
- }
- clone := make([]byte, len(b))
- copy(clone, b)
- return reflect.ValueOf(clone).Convert(d.dm.defaultByteStringType).Interface(), 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 tagNumRFC3339Time, tagNumEpochTime:
- d.off = tagOff
- tm, _, err := d.parseToTime()
- if err != nil {
- return nil, err
- }
- switch d.dm.timeTagToAny {
- case TimeTagToTime:
- return tm, nil
- case TimeTagToRFC3339:
- if tagNum == 1 {
- tm = tm.UTC()
- }
- // Call time.MarshalText() to format decoded time to RFC3339 format,
- // and return error on time value that cannot be represented in
- // RFC3339 format. E.g. year cannot exceed 9999, etc.
- text, err := tm.Truncate(time.Second).MarshalText()
- if err != nil {
- return nil, fmt.Errorf("cbor: decoded time cannot be represented in RFC3339 format: %v", err)
- }
- return string(text), nil
- case TimeTagToRFC3339Nano:
- if tagNum == 1 {
- tm = tm.UTC()
- }
- // Call time.MarshalText() to format decoded time to RFC3339 format,
- // and return error on time value that cannot be represented in
- // RFC3339 format with sub-second precision.
- text, err := tm.MarshalText()
- if err != nil {
- return nil, fmt.Errorf("cbor: decoded time cannot be represented in RFC3339 format with sub-second precision: %v", err)
- }
- return string(text), nil
- default:
- // not reachable
- }
- case tagNumUnsignedBignum:
- b, _ := d.parseByteString()
- bi := new(big.Int).SetBytes(b)
- if d.dm.bigIntDec == BigIntDecodePointer {
- return bi, nil
- }
- return *bi, nil
- case tagNumNegativeBignum:
- b, _ := d.parseByteString()
- bi := new(big.Int).SetBytes(b)
- bi.Add(bi, big.NewInt(1))
- bi.Neg(bi)
- if d.dm.bigIntDec == BigIntDecodePointer {
- return bi, nil
- }
- return *bi, nil
- case tagNumExpectedLaterEncodingBase64URL, tagNumExpectedLaterEncodingBase64, tagNumExpectedLaterEncodingBase16:
- // If conversion for interoperability with text encodings is not configured,
- // treat tags 21-23 as unregistered tags.
- if d.dm.byteStringToString == ByteStringToStringAllowedWithExpectedLaterEncoding ||
- d.dm.byteStringExpectedFormat != ByteStringExpectedFormatNone {
- d.expectedLaterEncodingTags = append(d.expectedLaterEncodingTags, tagNum)
- defer func() {
- d.expectedLaterEncodingTags = d.expectedLaterEncodingTags[:len(d.expectedLaterEncodingTags)-1]
- }()
- return d.parse(false)
- }
- }
- 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
- }
- if d.dm.unrecognizedTagToAny == UnrecognizedTagContentToAny {
- return content, nil
- }
- return Tag{tagNum, content}, nil
- case cborTypePrimitives:
- _, ai, val := d.getHead()
- if ai <= 24 && d.dm.simpleValues.rejected[SimpleValue(val)] {
- return nil, &UnacceptableDataItemError{
- CBORType: t.String(),
- Message: "simple value " + strconv.FormatInt(int64(val), 10) + " is not recognized",
- }
- }
- if ai < 20 || ai == 24 {
- return SimpleValue(val), nil
- }
- switch ai {
- case additionalInformationAsFalse,
- additionalInformationAsTrue:
- return (ai == additionalInformationAsTrue), nil
- case additionalInformationAsNull,
- additionalInformationAsUndefined:
- return nil, nil
- case additionalInformationAsFloat16:
- f := float64(float16.Frombits(uint16(val)).Float32())
- return f, nil
- case additionalInformationAsFloat32:
- f := float64(math.Float32frombits(uint32(val)))
- return f, nil
- case additionalInformationAsFloat64:
- f := math.Float64frombits(val)
- return f, nil
- }
- case cborTypeArray:
- return d.parseArray()
- case cborTypeMap:
- if d.dm.defaultMapType != nil {
- m := reflect.New(d.dm.defaultMapType)
- err := d.parseToValue(m, getTypeInfo(m.Elem().Type()))
- if err != nil {
- return nil, err
- }
- return m.Elem().Interface(), nil
- }
- return d.parseMap()
- }
- return nil, nil
- }
- // parseByteString parses a CBOR encoded byte string. The returned byte slice
- // may be backed directly by the input. The second return value will be true if
- // and only if the slice is backed by a copy of the input. Callers are
- // responsible for making a copy if necessary.
- func (d *decoder) parseByteString() ([]byte, bool) {
- _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
- if !indefiniteLength {
- b := d.data[d.off : d.off+int(val)]
- d.off += int(val)
- return b, false
- }
- // 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, true
- }
- // applyByteStringTextConversion converts bytes read from a byte string to or from a configured text
- // encoding. If no transformation was performed (because it was not required), the original byte
- // slice is returned and the bool return value is false. Otherwise, a new slice containing the
- // converted bytes is returned along with the bool value true.
- func (d *decoder) applyByteStringTextConversion(
- src []byte,
- dstType reflect.Type,
- ) (
- dst []byte,
- transformed bool,
- err error,
- ) {
- switch dstType.Kind() {
- case reflect.String:
- if d.dm.byteStringToString != ByteStringToStringAllowedWithExpectedLaterEncoding || len(d.expectedLaterEncodingTags) == 0 {
- return src, false, nil
- }
- switch d.expectedLaterEncodingTags[len(d.expectedLaterEncodingTags)-1] {
- case tagNumExpectedLaterEncodingBase64URL:
- encoded := make([]byte, base64.RawURLEncoding.EncodedLen(len(src)))
- base64.RawURLEncoding.Encode(encoded, src)
- return encoded, true, nil
- case tagNumExpectedLaterEncodingBase64:
- encoded := make([]byte, base64.StdEncoding.EncodedLen(len(src)))
- base64.StdEncoding.Encode(encoded, src)
- return encoded, true, nil
- case tagNumExpectedLaterEncodingBase16:
- encoded := make([]byte, hex.EncodedLen(len(src)))
- hex.Encode(encoded, src)
- return encoded, true, nil
- default:
- // If this happens, there is a bug: the decoder has pushed an invalid
- // "expected later encoding" tag to the stack.
- panic(fmt.Sprintf("unrecognized expected later encoding tag: %d", d.expectedLaterEncodingTags))
- }
- case reflect.Slice:
- if dstType.Elem().Kind() != reflect.Uint8 || len(d.expectedLaterEncodingTags) > 0 {
- // Either the destination is not a slice of bytes, or the encoder that
- // produced the input indicated an expected text encoding tag and therefore
- // the content of the byte string has NOT been text encoded.
- return src, false, nil
- }
- switch d.dm.byteStringExpectedFormat {
- case ByteStringExpectedBase64URL:
- decoded := make([]byte, base64.RawURLEncoding.DecodedLen(len(src)))
- n, err := base64.RawURLEncoding.Decode(decoded, src)
- if err != nil {
- return nil, false, newByteStringExpectedFormatError(ByteStringExpectedBase64URL, err)
- }
- return decoded[:n], true, nil
- case ByteStringExpectedBase64:
- decoded := make([]byte, base64.StdEncoding.DecodedLen(len(src)))
- n, err := base64.StdEncoding.Decode(decoded, src)
- if err != nil {
- return nil, false, newByteStringExpectedFormatError(ByteStringExpectedBase64, err)
- }
- return decoded[:n], true, nil
- case ByteStringExpectedBase16:
- decoded := make([]byte, hex.DecodedLen(len(src)))
- n, err := hex.Decode(decoded, src)
- if err != nil {
- return nil, false, newByteStringExpectedFormatError(ByteStringExpectedBase16, err)
- }
- return decoded[:n], true, nil
- }
- }
- return src, false, nil
- }
- // 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) {
- _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
- if !indefiniteLength {
- b := d.data[d.off : d.off+int(val)]
- d.off += int(val)
- if d.dm.utf8 == UTF8RejectInvalid && !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 d.dm.utf8 == UTF8RejectInvalid && !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() ([]any, error) {
- _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
- hasSize := !indefiniteLength
- count := int(val)
- if !hasSize {
- count = d.numOfItemsUntilBreak() // peek ahead to get array size to preallocate slice for better performance
- }
- v := make([]any, count)
- var e any
- 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 {
- _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
- hasSize := !indefiniteLength
- 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 {
- _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
- hasSize := !indefiniteLength
- 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 {
- for ; gi < vLen; gi++ {
- v.Index(gi).SetZero()
- }
- }
- return err
- }
- func (d *decoder) parseMap() (any, error) {
- _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
- hasSize := !indefiniteLength
- count := int(val)
- m := make(map[any]any)
- var k, e any
- 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) {
- var converted bool
- if d.dm.mapKeyByteString == MapKeyByteStringAllowed {
- k, converted = convertByteSliceToByteString(k)
- }
- if !converted {
- if err == nil {
- err = &InvalidMapKeyTypeError{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
- _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
- hasSize := !indefiniteLength
- 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 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[any]bool // Store existing map keys, used for detecting duplicate map key.
- if d.dm.dupMapKey == DupMapKeyEnforcedAPF {
- existingKeys = make(map[any]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 {
- keyValue.SetZero()
- }
- 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()) {
- var converted bool
- if d.dm.mapKeyByteString == MapKeyByteStringAllowed {
- var k any
- k, converted = convertByteSliceToByteString(keyValue.Elem().Interface())
- if converted {
- keyValue.Set(reflect.ValueOf(k))
- }
- }
- if !converted {
- if err == nil {
- err = &InvalidMapKeyTypeError{keyValue.Elem().Type().String()}
- }
- d.skip()
- continue
- }
- }
- }
- // Parse CBOR map value.
- if !eleValue.IsValid() {
- eleValue = reflect.New(eleType).Elem()
- } else if !reuseEle {
- eleValue.SetZero()
- }
- 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
- _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
- hasSize := !indefiniteLength
- 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: cborTypeArray.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
- _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
- hasSize := !indefiniteLength
- count := int(val)
- // Keeps track of matched struct fields
- var foundFldIdx []bool
- {
- const maxStackFields = 128
- if nfields := len(structType.fields); nfields <= maxStackFields {
- // For structs with typical field counts, expect that this can be
- // stack-allocated.
- var a [maxStackFields]bool
- foundFldIdx = a[:nfields]
- } else {
- foundFldIdx = make([]bool, len(structType.fields))
- }
- }
- // Keeps track of CBOR map keys to detect duplicate map key
- keyCount := 0
- var mapKeys map[any]struct{}
- errOnUnknownField := (d.dm.extraReturnErrors & ExtraDecErrorUnknownField) > 0
- MapEntryLoop:
- for j := 0; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ {
- var f *field
- // If duplicate field detection is enabled and the key at index j did not match any
- // field, k will hold the map key.
- var k any
- t := d.nextCBORType()
- if t == cborTypeTextString || (t == cborTypeByteString && d.dm.fieldNameByteString == FieldNameByteStringAllowed) {
- var keyBytes []byte
- if t == cborTypeTextString {
- keyBytes, lastErr = d.parseTextString()
- if lastErr != nil {
- if err == nil {
- err = lastErr
- }
- d.skip() // skip value
- continue
- }
- } else { // cborTypeByteString
- keyBytes, _ = d.parseByteString()
- }
- // Check for exact match on field name.
- if i, ok := structType.fieldIndicesByName[string(keyBytes)]; ok {
- fld := structType.fields[i]
- if !foundFldIdx[i] {
- f = fld
- foundFldIdx[i] = true
- } else if d.dm.dupMapKey == DupMapKeyEnforcedAPF {
- err = &DupMapKeyError{fld.name, 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
- }
- }
- // Find field with case-insensitive match
- if f == nil && d.dm.fieldNameMatching == FieldNameMatchingPreferCaseSensitive {
- 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
- }
|