1package cbor 2 3import ( 4 "errors" 5 "fmt" 6 "reflect" 7 "sync" 8) 9 10// Tag represents CBOR tag data, including tag number and unmarshaled tag content. 11type Tag struct { 12 Number uint64 13 Content interface{} 14} 15 16// RawTag represents CBOR tag data, including tag number and raw tag content. 17// RawTag implements Unmarshaler and Marshaler interfaces. 18type RawTag struct { 19 Number uint64 20 Content RawMessage 21} 22 23// UnmarshalCBOR sets *t with tag number and raw tag content copied from data. 24func (t *RawTag) UnmarshalCBOR(data []byte) error { 25 if t == nil { 26 return errors.New("cbor.RawTag: UnmarshalCBOR on nil pointer") 27 } 28 29 // Decoding CBOR null and undefined to cbor.RawTag is no-op. 30 if len(data) == 1 && (data[0] == 0xf6 || data[0] == 0xf7) { 31 return nil 32 } 33 34 d := decoder{data: data, dm: defaultDecMode} 35 36 // Unmarshal tag number. 37 typ, _, num := d.getHead() 38 if typ != cborTypeTag { 39 return &UnmarshalTypeError{CBORType: typ.String(), GoType: typeRawTag.String()} 40 } 41 t.Number = num 42 43 // Unmarshal tag content. 44 c := d.data[d.off:] 45 t.Content = make([]byte, len(c)) 46 copy(t.Content, c) 47 return nil 48} 49 50// MarshalCBOR returns CBOR encoding of t. 51func (t RawTag) MarshalCBOR() ([]byte, error) { 52 if t.Number == 0 && len(t.Content) == 0 { 53 // Marshal uninitialized cbor.RawTag 54 b := make([]byte, len(cborNil)) 55 copy(b, cborNil) 56 return b, nil 57 } 58 59 e := getEncoderBuffer() 60 61 encodeHead(e, byte(cborTypeTag), t.Number) 62 63 content := t.Content 64 if len(content) == 0 { 65 content = cborNil 66 } 67 68 buf := make([]byte, len(e.Bytes())+len(content)) 69 n := copy(buf, e.Bytes()) 70 copy(buf[n:], content) 71 72 putEncoderBuffer(e) 73 return buf, nil 74} 75 76// DecTagMode specifies how decoder handles tag number. 77type DecTagMode int 78 79const ( 80 // DecTagIgnored makes decoder ignore tag number (skips if present). 81 DecTagIgnored DecTagMode = iota 82 83 // DecTagOptional makes decoder verify tag number if it's present. 84 DecTagOptional 85 86 // DecTagRequired makes decoder verify tag number and tag number must be present. 87 DecTagRequired 88 89 maxDecTagMode 90) 91 92func (dtm DecTagMode) valid() bool { 93 return dtm < maxDecTagMode 94} 95 96// EncTagMode specifies how encoder handles tag number. 97type EncTagMode int 98 99const ( 100 // EncTagNone makes encoder not encode tag number. 101 EncTagNone EncTagMode = iota 102 103 // EncTagRequired makes encoder encode tag number. 104 EncTagRequired 105 106 maxEncTagMode 107) 108 109func (etm EncTagMode) valid() bool { 110 return etm < maxEncTagMode 111} 112 113// TagOptions specifies how encoder and decoder handle tag number. 114type TagOptions struct { 115 DecTag DecTagMode 116 EncTag EncTagMode 117} 118 119// TagSet is an interface to add and remove tag info. It is used by EncMode and DecMode 120// to provide CBOR tag support. 121type TagSet interface { 122 // Add adds given tag number(s), content type, and tag options to TagSet. 123 Add(opts TagOptions, contentType reflect.Type, num uint64, nestedNum ...uint64) error 124 125 // Remove removes given tag content type from TagSet. 126 Remove(contentType reflect.Type) 127 128 tagProvider 129} 130 131type tagProvider interface { 132 getTagItemFromType(t reflect.Type) *tagItem 133 getTypeFromTagNum(num []uint64) reflect.Type 134} 135 136type tagItem struct { 137 num []uint64 138 cborTagNum []byte 139 contentType reflect.Type 140 opts TagOptions 141} 142 143func (t *tagItem) equalTagNum(num []uint64) bool { 144 // Fast path to compare 1 tag number 145 if len(t.num) == 1 && len(num) == 1 && t.num[0] == num[0] { 146 return true 147 } 148 149 if len(t.num) != len(num) { 150 return false 151 } 152 153 for i := 0; i < len(t.num); i++ { 154 if t.num[i] != num[i] { 155 return false 156 } 157 } 158 159 return true 160} 161 162type ( 163 tagSet map[reflect.Type]*tagItem 164 165 syncTagSet struct { 166 sync.RWMutex 167 t tagSet 168 } 169) 170 171func (t tagSet) getTagItemFromType(typ reflect.Type) *tagItem { 172 return t[typ] 173} 174 175func (t tagSet) getTypeFromTagNum(num []uint64) reflect.Type { 176 for typ, tag := range t { 177 if tag.equalTagNum(num) { 178 return typ 179 } 180 } 181 return nil 182} 183 184// NewTagSet returns TagSet (safe for concurrency). 185func NewTagSet() TagSet { 186 return &syncTagSet{t: make(map[reflect.Type]*tagItem)} 187} 188 189// Add adds given tag number(s), content type, and tag options to TagSet. 190func (t *syncTagSet) Add(opts TagOptions, contentType reflect.Type, num uint64, nestedNum ...uint64) error { 191 if contentType == nil { 192 return errors.New("cbor: cannot add nil content type to TagSet") 193 } 194 for contentType.Kind() == reflect.Ptr { 195 contentType = contentType.Elem() 196 } 197 tag, err := newTagItem(opts, contentType, num, nestedNum...) 198 if err != nil { 199 return err 200 } 201 t.Lock() 202 defer t.Unlock() 203 for typ, ti := range t.t { 204 if typ == contentType { 205 return errors.New("cbor: content type " + contentType.String() + " already exists in TagSet") 206 } 207 if ti.equalTagNum(tag.num) { 208 return fmt.Errorf("cbor: tag number %v already exists in TagSet", tag.num) 209 } 210 } 211 t.t[contentType] = tag 212 return nil 213} 214 215// Remove removes given tag content type from TagSet. 216func (t *syncTagSet) Remove(contentType reflect.Type) { 217 for contentType.Kind() == reflect.Ptr { 218 contentType = contentType.Elem() 219 } 220 t.Lock() 221 delete(t.t, contentType) 222 t.Unlock() 223} 224 225func (t *syncTagSet) getTagItemFromType(typ reflect.Type) *tagItem { 226 t.RLock() 227 ti := t.t[typ] 228 t.RUnlock() 229 return ti 230} 231 232func (t *syncTagSet) getTypeFromTagNum(num []uint64) reflect.Type { 233 t.RLock() 234 rt := t.t.getTypeFromTagNum(num) 235 t.RUnlock() 236 return rt 237} 238 239func newTagItem(opts TagOptions, contentType reflect.Type, num uint64, nestedNum ...uint64) (*tagItem, error) { 240 if opts.DecTag == DecTagIgnored && opts.EncTag == EncTagNone { 241 return nil, errors.New("cbor: cannot add tag with DecTagIgnored and EncTagNone options to TagSet") 242 } 243 if contentType.PkgPath() == "" || contentType.Kind() == reflect.Interface { 244 return nil, errors.New("cbor: can only add named types to TagSet, got " + contentType.String()) 245 } 246 if contentType == typeTime { 247 return nil, errors.New("cbor: cannot add time.Time to TagSet, use EncOptions.TimeTag and DecOptions.TimeTag instead") 248 } 249 if contentType == typeBigInt { 250 return nil, errors.New("cbor: cannot add big.Int to TagSet, it's built-in and supported automatically") 251 } 252 if contentType == typeTag { 253 return nil, errors.New("cbor: cannot add cbor.Tag to TagSet") 254 } 255 if contentType == typeRawTag { 256 return nil, errors.New("cbor: cannot add cbor.RawTag to TagSet") 257 } 258 if num == 0 || num == 1 { 259 return nil, errors.New("cbor: cannot add tag number 0 or 1 to TagSet, use EncOptions.TimeTag and DecOptions.TimeTag instead") 260 } 261 if num == 2 || num == 3 { 262 return nil, errors.New("cbor: cannot add tag number 2 or 3 to TagSet, it's built-in and supported automatically") 263 } 264 if num == selfDescribedCBORTagNum { 265 return nil, errors.New("cbor: cannot add tag number 55799 to TagSet, it's built-in and ignored automatically") 266 } 267 268 te := tagItem{num: []uint64{num}, opts: opts, contentType: contentType} 269 te.num = append(te.num, nestedNum...) 270 271 // Cache encoded tag numbers 272 e := getEncoderBuffer() 273 for _, n := range te.num { 274 encodeHead(e, byte(cborTypeTag), n) 275 } 276 te.cborTagNum = make([]byte, e.Len()) 277 copy(te.cborTagNum, e.Bytes()) 278 putEncoderBuffer(e) 279 280 return &te, nil 281} 282 283var ( 284 typeTag = reflect.TypeOf(Tag{}) 285 typeRawTag = reflect.TypeOf(RawTag{}) 286) 287 288// WrongTagError describes mismatch between CBOR tag and registered tag. 289type WrongTagError struct { 290 RegisteredType reflect.Type 291 RegisteredTagNum []uint64 292 TagNum []uint64 293} 294 295func (e *WrongTagError) Error() string { 296 return fmt.Sprintf("cbor: wrong tag number for %s, got %v, expected %v", e.RegisteredType.String(), e.TagNum, e.RegisteredTagNum) 297} 298