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