common.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Copyright (c) Faye Amacker. All rights reserved.
  2. // Licensed under the MIT License. See LICENSE in the project root for license information.
  3. package cbor
  4. import (
  5. "fmt"
  6. "io"
  7. "strconv"
  8. )
  9. type cborType uint8
  10. const (
  11. cborTypePositiveInt cborType = 0x00
  12. cborTypeNegativeInt cborType = 0x20
  13. cborTypeByteString cborType = 0x40
  14. cborTypeTextString cborType = 0x60
  15. cborTypeArray cborType = 0x80
  16. cborTypeMap cborType = 0xa0
  17. cborTypeTag cborType = 0xc0
  18. cborTypePrimitives cborType = 0xe0
  19. )
  20. func (t cborType) String() string {
  21. switch t {
  22. case cborTypePositiveInt:
  23. return "positive integer"
  24. case cborTypeNegativeInt:
  25. return "negative integer"
  26. case cborTypeByteString:
  27. return "byte string"
  28. case cborTypeTextString:
  29. return "UTF-8 text string"
  30. case cborTypeArray:
  31. return "array"
  32. case cborTypeMap:
  33. return "map"
  34. case cborTypeTag:
  35. return "tag"
  36. case cborTypePrimitives:
  37. return "primitives"
  38. default:
  39. return "Invalid type " + strconv.Itoa(int(t))
  40. }
  41. }
  42. type additionalInformation uint8
  43. const (
  44. maxAdditionalInformationWithoutArgument = 23
  45. additionalInformationWith1ByteArgument = 24
  46. additionalInformationWith2ByteArgument = 25
  47. additionalInformationWith4ByteArgument = 26
  48. additionalInformationWith8ByteArgument = 27
  49. // For major type 7.
  50. additionalInformationAsFalse = 20
  51. additionalInformationAsTrue = 21
  52. additionalInformationAsNull = 22
  53. additionalInformationAsUndefined = 23
  54. additionalInformationAsFloat16 = 25
  55. additionalInformationAsFloat32 = 26
  56. additionalInformationAsFloat64 = 27
  57. // For major type 2, 3, 4, 5.
  58. additionalInformationAsIndefiniteLengthFlag = 31
  59. )
  60. const (
  61. maxSimpleValueInAdditionalInformation = 23
  62. minSimpleValueIn1ByteArgument = 32
  63. )
  64. func (ai additionalInformation) isIndefiniteLength() bool {
  65. return ai == additionalInformationAsIndefiniteLengthFlag
  66. }
  67. const (
  68. // From RFC 8949 Section 3:
  69. // "The initial byte of each encoded data item contains both information about the major type
  70. // (the high-order 3 bits, described in Section 3.1) and additional information
  71. // (the low-order 5 bits)."
  72. // typeMask is used to extract major type in initial byte of encoded data item.
  73. typeMask = 0xe0
  74. // additionalInformationMask is used to extract additional information in initial byte of encoded data item.
  75. additionalInformationMask = 0x1f
  76. )
  77. func getType(raw byte) cborType {
  78. return cborType(raw & typeMask)
  79. }
  80. func getAdditionalInformation(raw byte) byte {
  81. return raw & additionalInformationMask
  82. }
  83. func isBreakFlag(raw byte) bool {
  84. return raw == cborBreakFlag
  85. }
  86. func parseInitialByte(b byte) (t cborType, ai byte) {
  87. return getType(b), getAdditionalInformation(b)
  88. }
  89. const (
  90. tagNumRFC3339Time = 0
  91. tagNumEpochTime = 1
  92. tagNumUnsignedBignum = 2
  93. tagNumNegativeBignum = 3
  94. tagNumExpectedLaterEncodingBase64URL = 21
  95. tagNumExpectedLaterEncodingBase64 = 22
  96. tagNumExpectedLaterEncodingBase16 = 23
  97. tagNumSelfDescribedCBOR = 55799
  98. )
  99. const (
  100. cborBreakFlag = byte(0xff)
  101. cborByteStringWithIndefiniteLengthHead = byte(0x5f)
  102. cborTextStringWithIndefiniteLengthHead = byte(0x7f)
  103. cborArrayWithIndefiniteLengthHead = byte(0x9f)
  104. cborMapWithIndefiniteLengthHead = byte(0xbf)
  105. )
  106. var (
  107. cborFalse = []byte{0xf4}
  108. cborTrue = []byte{0xf5}
  109. cborNil = []byte{0xf6}
  110. cborNaN = []byte{0xf9, 0x7e, 0x00}
  111. cborPositiveInfinity = []byte{0xf9, 0x7c, 0x00}
  112. cborNegativeInfinity = []byte{0xf9, 0xfc, 0x00}
  113. )
  114. // validBuiltinTag checks that supported built-in tag numbers are followed by expected content types.
  115. func validBuiltinTag(tagNum uint64, contentHead byte) error {
  116. t := getType(contentHead)
  117. switch tagNum {
  118. case tagNumRFC3339Time:
  119. // Tag content (date/time text string in RFC 3339 format) must be string type.
  120. if t != cborTypeTextString {
  121. return newInadmissibleTagContentTypeError(
  122. tagNumRFC3339Time,
  123. "text string",
  124. t.String())
  125. }
  126. return nil
  127. case tagNumEpochTime:
  128. // Tag content (epoch date/time) must be uint, int, or float type.
  129. if t != cborTypePositiveInt && t != cborTypeNegativeInt && (contentHead < 0xf9 || contentHead > 0xfb) {
  130. return newInadmissibleTagContentTypeError(
  131. tagNumEpochTime,
  132. "integer or floating-point number",
  133. t.String())
  134. }
  135. return nil
  136. case tagNumUnsignedBignum, tagNumNegativeBignum:
  137. // Tag content (bignum) must be byte type.
  138. if t != cborTypeByteString {
  139. return newInadmissibleTagContentTypeErrorf(
  140. fmt.Sprintf(
  141. "tag number %d or %d must be followed by byte string, got %s",
  142. tagNumUnsignedBignum,
  143. tagNumNegativeBignum,
  144. t.String(),
  145. ))
  146. }
  147. return nil
  148. case tagNumExpectedLaterEncodingBase64URL, tagNumExpectedLaterEncodingBase64, tagNumExpectedLaterEncodingBase16:
  149. // From RFC 8949 3.4.5.2:
  150. // The data item tagged can be a byte string or any other data item. In the latter
  151. // case, the tag applies to all of the byte string data items contained in the data
  152. // item, except for those contained in a nested data item tagged with an expected
  153. // conversion.
  154. return nil
  155. }
  156. return nil
  157. }
  158. // Transcoder is a scheme for transcoding a single CBOR encoded data item to or from a different
  159. // data format.
  160. type Transcoder interface {
  161. // Transcode reads the data item in its source format from a Reader and writes a
  162. // corresponding representation in its destination format to a Writer.
  163. Transcode(dst io.Writer, src io.Reader) error
  164. }