952 lines
21 KiB
Go
952 lines
21 KiB
Go
|
// Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
|
||
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
||
|
|
||
|
package codec
|
||
|
|
||
|
import (
|
||
|
"math"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// major
|
||
|
const (
|
||
|
cborMajorUint byte = iota
|
||
|
cborMajorNegInt
|
||
|
cborMajorBytes
|
||
|
cborMajorString
|
||
|
cborMajorArray
|
||
|
cborMajorMap
|
||
|
cborMajorTag
|
||
|
cborMajorSimpleOrFloat
|
||
|
)
|
||
|
|
||
|
// simple
|
||
|
const (
|
||
|
cborBdFalse byte = 0xf4 + iota
|
||
|
cborBdTrue
|
||
|
cborBdNil
|
||
|
cborBdUndefined
|
||
|
cborBdExt
|
||
|
cborBdFloat16
|
||
|
cborBdFloat32
|
||
|
cborBdFloat64
|
||
|
)
|
||
|
|
||
|
// indefinite
|
||
|
const (
|
||
|
cborBdIndefiniteBytes byte = 0x5f
|
||
|
cborBdIndefiniteString byte = 0x7f
|
||
|
cborBdIndefiniteArray byte = 0x9f
|
||
|
cborBdIndefiniteMap byte = 0xbf
|
||
|
cborBdBreak byte = 0xff
|
||
|
)
|
||
|
|
||
|
// These define some in-stream descriptors for
|
||
|
// manual encoding e.g. when doing explicit indefinite-length
|
||
|
const (
|
||
|
CborStreamBytes byte = 0x5f
|
||
|
CborStreamString byte = 0x7f
|
||
|
CborStreamArray byte = 0x9f
|
||
|
CborStreamMap byte = 0xbf
|
||
|
CborStreamBreak byte = 0xff
|
||
|
)
|
||
|
|
||
|
// base values
|
||
|
const (
|
||
|
cborBaseUint byte = 0x00
|
||
|
cborBaseNegInt byte = 0x20
|
||
|
cborBaseBytes byte = 0x40
|
||
|
cborBaseString byte = 0x60
|
||
|
cborBaseArray byte = 0x80
|
||
|
cborBaseMap byte = 0xa0
|
||
|
cborBaseTag byte = 0xc0
|
||
|
cborBaseSimple byte = 0xe0
|
||
|
)
|
||
|
|
||
|
// const (
|
||
|
// cborSelfDesrTag byte = 0xd9
|
||
|
// cborSelfDesrTag2 byte = 0xd9
|
||
|
// cborSelfDesrTag3 byte = 0xf7
|
||
|
// )
|
||
|
|
||
|
var (
|
||
|
cbordescSimpleNames = map[byte]string{
|
||
|
cborBdNil: "nil",
|
||
|
cborBdFalse: "false",
|
||
|
cborBdTrue: "true",
|
||
|
cborBdFloat16: "float",
|
||
|
cborBdFloat32: "float",
|
||
|
cborBdFloat64: "float",
|
||
|
cborBdBreak: "break",
|
||
|
}
|
||
|
cbordescIndefNames = map[byte]string{
|
||
|
cborBdIndefiniteBytes: "bytes*",
|
||
|
cborBdIndefiniteString: "string*",
|
||
|
cborBdIndefiniteArray: "array*",
|
||
|
cborBdIndefiniteMap: "map*",
|
||
|
}
|
||
|
cbordescMajorNames = map[byte]string{
|
||
|
cborMajorUint: "(u)int",
|
||
|
cborMajorNegInt: "int",
|
||
|
cborMajorBytes: "bytes",
|
||
|
cborMajorString: "string",
|
||
|
cborMajorArray: "array",
|
||
|
cborMajorMap: "map",
|
||
|
cborMajorTag: "tag",
|
||
|
cborMajorSimpleOrFloat: "simple",
|
||
|
}
|
||
|
)
|
||
|
|
||
|
func cbordesc(bd byte) (s string) {
|
||
|
bm := bd >> 5
|
||
|
if bm == cborMajorSimpleOrFloat {
|
||
|
s = cbordescSimpleNames[bd]
|
||
|
} else {
|
||
|
s = cbordescMajorNames[bm]
|
||
|
if s == "" {
|
||
|
s = cbordescIndefNames[bd]
|
||
|
}
|
||
|
}
|
||
|
if s == "" {
|
||
|
s = "unknown"
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// -------------------
|
||
|
|
||
|
type cborEncDriver struct {
|
||
|
noBuiltInTypes
|
||
|
encDriverNoopContainerWriter
|
||
|
h *CborHandle
|
||
|
// x [8]byte
|
||
|
|
||
|
e Encoder
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) encoder() *Encoder {
|
||
|
return &e.e
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) EncodeNil() {
|
||
|
e.e.encWr.writen1(cborBdNil)
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) EncodeBool(b bool) {
|
||
|
if b {
|
||
|
e.e.encWr.writen1(cborBdTrue)
|
||
|
} else {
|
||
|
e.e.encWr.writen1(cborBdFalse)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) EncodeFloat32(f float32) {
|
||
|
b := math.Float32bits(f)
|
||
|
if e.h.OptimumSize {
|
||
|
if h := floatToHalfFloatBits(b); halfFloatToFloatBits(h) == b {
|
||
|
e.e.encWr.writen1(cborBdFloat16)
|
||
|
bigen.writeUint16(e.e.w(), h)
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
e.e.encWr.writen1(cborBdFloat32)
|
||
|
bigen.writeUint32(e.e.w(), b)
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) EncodeFloat64(f float64) {
|
||
|
if e.h.OptimumSize {
|
||
|
if f32 := float32(f); float64(f32) == f {
|
||
|
e.EncodeFloat32(f32)
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
e.e.encWr.writen1(cborBdFloat64)
|
||
|
bigen.writeUint64(e.e.w(), math.Float64bits(f))
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) encUint(v uint64, bd byte) {
|
||
|
if v <= 0x17 {
|
||
|
e.e.encWr.writen1(byte(v) + bd)
|
||
|
} else if v <= math.MaxUint8 {
|
||
|
e.e.encWr.writen2(bd+0x18, uint8(v))
|
||
|
} else if v <= math.MaxUint16 {
|
||
|
e.e.encWr.writen1(bd + 0x19)
|
||
|
bigen.writeUint16(e.e.w(), uint16(v))
|
||
|
} else if v <= math.MaxUint32 {
|
||
|
e.e.encWr.writen1(bd + 0x1a)
|
||
|
bigen.writeUint32(e.e.w(), uint32(v))
|
||
|
} else { // if v <= math.MaxUint64 {
|
||
|
e.e.encWr.writen1(bd + 0x1b)
|
||
|
bigen.writeUint64(e.e.w(), v)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) EncodeInt(v int64) {
|
||
|
if v < 0 {
|
||
|
e.encUint(uint64(-1-v), cborBaseNegInt)
|
||
|
} else {
|
||
|
e.encUint(uint64(v), cborBaseUint)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) EncodeUint(v uint64) {
|
||
|
e.encUint(v, cborBaseUint)
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) encLen(bd byte, length int) {
|
||
|
e.encUint(uint64(length), bd)
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) EncodeTime(t time.Time) {
|
||
|
if t.IsZero() {
|
||
|
e.EncodeNil()
|
||
|
} else if e.h.TimeRFC3339 {
|
||
|
e.encUint(0, cborBaseTag)
|
||
|
e.encStringBytesS(cborBaseString, t.Format(time.RFC3339Nano))
|
||
|
} else {
|
||
|
e.encUint(1, cborBaseTag)
|
||
|
t = t.UTC().Round(time.Microsecond)
|
||
|
sec, nsec := t.Unix(), uint64(t.Nanosecond())
|
||
|
if nsec == 0 {
|
||
|
e.EncodeInt(sec)
|
||
|
} else {
|
||
|
e.EncodeFloat64(float64(sec) + float64(nsec)/1e9)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext) {
|
||
|
e.encUint(uint64(xtag), cborBaseTag)
|
||
|
if ext == SelfExt {
|
||
|
rv2 := baseRV(rv)
|
||
|
e.e.encodeValue(rv2, e.h.fnNoExt(rvType(rv2)))
|
||
|
} else if v := ext.ConvertExt(rv); v == nil {
|
||
|
e.EncodeNil()
|
||
|
} else {
|
||
|
e.e.encode(v)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) EncodeRawExt(re *RawExt) {
|
||
|
e.encUint(uint64(re.Tag), cborBaseTag)
|
||
|
// only encodes re.Value (never re.Data)
|
||
|
if re.Value != nil {
|
||
|
e.e.encode(re.Value)
|
||
|
} else {
|
||
|
e.EncodeNil()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) WriteArrayStart(length int) {
|
||
|
if e.h.IndefiniteLength {
|
||
|
e.e.encWr.writen1(cborBdIndefiniteArray)
|
||
|
} else {
|
||
|
e.encLen(cborBaseArray, length)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) WriteMapStart(length int) {
|
||
|
if e.h.IndefiniteLength {
|
||
|
e.e.encWr.writen1(cborBdIndefiniteMap)
|
||
|
} else {
|
||
|
e.encLen(cborBaseMap, length)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) WriteMapEnd() {
|
||
|
if e.h.IndefiniteLength {
|
||
|
e.e.encWr.writen1(cborBdBreak)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) WriteArrayEnd() {
|
||
|
if e.h.IndefiniteLength {
|
||
|
e.e.encWr.writen1(cborBdBreak)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) EncodeString(v string) {
|
||
|
if e.h.StringToRaw {
|
||
|
e.EncodeStringBytesRaw(bytesView(v))
|
||
|
return
|
||
|
}
|
||
|
e.encStringBytesS(cborBaseString, v)
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) EncodeStringBytesRaw(v []byte) {
|
||
|
if v == nil {
|
||
|
e.EncodeNil()
|
||
|
} else {
|
||
|
e.encStringBytesS(cborBaseBytes, stringView(v))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) encStringBytesS(bb byte, v string) {
|
||
|
if e.h.IndefiniteLength {
|
||
|
if bb == cborBaseBytes {
|
||
|
e.e.encWr.writen1(cborBdIndefiniteBytes)
|
||
|
} else {
|
||
|
e.e.encWr.writen1(cborBdIndefiniteString)
|
||
|
}
|
||
|
var vlen uint = uint(len(v))
|
||
|
blen := vlen / 4
|
||
|
if blen == 0 {
|
||
|
blen = 64
|
||
|
} else if blen > 1024 {
|
||
|
blen = 1024
|
||
|
}
|
||
|
for i := uint(0); i < vlen; {
|
||
|
var v2 string
|
||
|
i2 := i + blen
|
||
|
if i2 >= i && i2 < vlen {
|
||
|
v2 = v[i:i2]
|
||
|
} else {
|
||
|
v2 = v[i:]
|
||
|
}
|
||
|
e.encLen(bb, len(v2))
|
||
|
e.e.encWr.writestr(v2)
|
||
|
i = i2
|
||
|
}
|
||
|
e.e.encWr.writen1(cborBdBreak)
|
||
|
} else {
|
||
|
e.encLen(bb, len(v))
|
||
|
e.e.encWr.writestr(v)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ----------------------
|
||
|
|
||
|
type cborDecDriver struct {
|
||
|
decDriverNoopContainerReader
|
||
|
h *CborHandle
|
||
|
bdRead bool
|
||
|
bd byte
|
||
|
st bool // skip tags
|
||
|
_ bool // found nil
|
||
|
noBuiltInTypes
|
||
|
d Decoder
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) decoder() *Decoder {
|
||
|
return &d.d
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) readNextBd() {
|
||
|
d.bd = d.d.decRd.readn1()
|
||
|
d.bdRead = true
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) advanceNil() (null bool) {
|
||
|
if !d.bdRead {
|
||
|
d.readNextBd()
|
||
|
}
|
||
|
if d.bd == cborBdNil || d.bd == cborBdUndefined {
|
||
|
d.bdRead = false
|
||
|
return true // null = true
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) TryNil() bool {
|
||
|
return d.advanceNil()
|
||
|
}
|
||
|
|
||
|
// skipTags is called to skip any tags in the stream.
|
||
|
//
|
||
|
// Since any value can be tagged, then we should call skipTags
|
||
|
// before any value is decoded.
|
||
|
//
|
||
|
// By definition, skipTags should not be called before
|
||
|
// checking for break, or nil or undefined.
|
||
|
func (d *cborDecDriver) skipTags() {
|
||
|
for d.bd>>5 == cborMajorTag {
|
||
|
d.decUint()
|
||
|
d.bd = d.d.decRd.readn1()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) ContainerType() (vt valueType) {
|
||
|
if !d.bdRead {
|
||
|
d.readNextBd()
|
||
|
}
|
||
|
if d.st {
|
||
|
d.skipTags()
|
||
|
}
|
||
|
if d.bd == cborBdNil {
|
||
|
d.bdRead = false // always consume nil after seeing it in container type
|
||
|
return valueTypeNil
|
||
|
}
|
||
|
major := d.bd >> 5
|
||
|
if major == cborMajorBytes {
|
||
|
return valueTypeBytes
|
||
|
} else if major == cborMajorString {
|
||
|
return valueTypeString
|
||
|
} else if major == cborMajorArray {
|
||
|
return valueTypeArray
|
||
|
} else if major == cborMajorMap {
|
||
|
return valueTypeMap
|
||
|
}
|
||
|
return valueTypeUnset
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) CheckBreak() (v bool) {
|
||
|
if !d.bdRead {
|
||
|
d.readNextBd()
|
||
|
}
|
||
|
if d.bd == cborBdBreak {
|
||
|
d.bdRead = false
|
||
|
v = true
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) decUint() (ui uint64) {
|
||
|
v := d.bd & 0x1f
|
||
|
if v <= 0x17 {
|
||
|
ui = uint64(v)
|
||
|
} else if v == 0x18 {
|
||
|
ui = uint64(d.d.decRd.readn1())
|
||
|
} else if v == 0x19 {
|
||
|
ui = uint64(bigen.Uint16(d.d.decRd.readn2()))
|
||
|
} else if v == 0x1a {
|
||
|
ui = uint64(bigen.Uint32(d.d.decRd.readn4()))
|
||
|
} else if v == 0x1b {
|
||
|
ui = uint64(bigen.Uint64(d.d.decRd.readn8()))
|
||
|
} else {
|
||
|
d.d.errorf("invalid descriptor decoding uint: %x/%s", d.bd, cbordesc(d.bd))
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) decCheckInteger() (neg bool) {
|
||
|
if d.st {
|
||
|
d.skipTags()
|
||
|
}
|
||
|
major := d.bd >> 5
|
||
|
if major == cborMajorUint {
|
||
|
} else if major == cborMajorNegInt {
|
||
|
neg = true
|
||
|
} else {
|
||
|
d.d.errorf("invalid integer %x (%s); got major %v, expected %v or %v",
|
||
|
d.bd, cbordesc(d.bd), major, cborMajorUint, cborMajorNegInt)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func cborDecInt64(ui uint64, neg bool) (i int64) {
|
||
|
if neg {
|
||
|
i = -(chkOvf.SignedIntV(ui + 1))
|
||
|
} else {
|
||
|
i = chkOvf.SignedIntV(ui)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) decLen() int {
|
||
|
return int(d.decUint())
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) decAppendIndefiniteBytes(bs []byte) []byte {
|
||
|
d.bdRead = false
|
||
|
for !d.CheckBreak() {
|
||
|
if major := d.bd >> 5; major != cborMajorBytes && major != cborMajorString {
|
||
|
d.d.errorf("invalid indefinite string/bytes %x (%s); got major %v, expected %v or %v",
|
||
|
d.bd, cbordesc(d.bd), major, cborMajorBytes, cborMajorString)
|
||
|
}
|
||
|
n := uint(d.decLen())
|
||
|
oldLen := uint(len(bs))
|
||
|
newLen := oldLen + n
|
||
|
if newLen > uint(cap(bs)) {
|
||
|
bs2 := make([]byte, newLen, 2*uint(cap(bs))+n)
|
||
|
copy(bs2, bs)
|
||
|
bs = bs2
|
||
|
} else {
|
||
|
bs = bs[:newLen]
|
||
|
}
|
||
|
d.d.decRd.readb(bs[oldLen:newLen])
|
||
|
d.bdRead = false
|
||
|
}
|
||
|
d.bdRead = false
|
||
|
return bs
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) DecodeInt64() (i int64) {
|
||
|
if d.advanceNil() {
|
||
|
return
|
||
|
}
|
||
|
neg := d.decCheckInteger()
|
||
|
ui := d.decUint()
|
||
|
d.bdRead = false
|
||
|
return cborDecInt64(ui, neg)
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) DecodeUint64() (ui uint64) {
|
||
|
if d.advanceNil() {
|
||
|
return
|
||
|
}
|
||
|
if d.decCheckInteger() {
|
||
|
d.d.errorf("cannot assign negative signed value to unsigned type")
|
||
|
}
|
||
|
ui = d.decUint()
|
||
|
d.bdRead = false
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) DecodeFloat64() (f float64) {
|
||
|
if d.advanceNil() {
|
||
|
return
|
||
|
}
|
||
|
if d.st {
|
||
|
d.skipTags()
|
||
|
}
|
||
|
switch d.bd {
|
||
|
case cborBdFloat16:
|
||
|
f = float64(math.Float32frombits(halfFloatToFloatBits(bigen.Uint16(d.d.decRd.readn2()))))
|
||
|
case cborBdFloat32:
|
||
|
f = float64(math.Float32frombits(bigen.Uint32(d.d.decRd.readn4())))
|
||
|
case cborBdFloat64:
|
||
|
f = math.Float64frombits(bigen.Uint64(d.d.decRd.readn8()))
|
||
|
default:
|
||
|
major := d.bd >> 5
|
||
|
if major == cborMajorUint {
|
||
|
f = float64(cborDecInt64(d.decUint(), false))
|
||
|
} else if major == cborMajorNegInt {
|
||
|
f = float64(cborDecInt64(d.decUint(), true))
|
||
|
} else {
|
||
|
d.d.errorf("invalid float descriptor; got %d/%s, expected float16/32/64 or (-)int", d.bd, cbordesc(d.bd))
|
||
|
}
|
||
|
}
|
||
|
d.bdRead = false
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// bool can be decoded from bool only (single byte).
|
||
|
func (d *cborDecDriver) DecodeBool() (b bool) {
|
||
|
if d.advanceNil() {
|
||
|
return
|
||
|
}
|
||
|
if d.st {
|
||
|
d.skipTags()
|
||
|
}
|
||
|
if d.bd == cborBdTrue {
|
||
|
b = true
|
||
|
} else if d.bd == cborBdFalse {
|
||
|
} else {
|
||
|
d.d.errorf("not bool - %s %x/%s", msgBadDesc, d.bd, cbordesc(d.bd))
|
||
|
}
|
||
|
d.bdRead = false
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) ReadMapStart() (length int) {
|
||
|
if d.advanceNil() {
|
||
|
return containerLenNil
|
||
|
}
|
||
|
if d.st {
|
||
|
d.skipTags()
|
||
|
}
|
||
|
d.bdRead = false
|
||
|
if d.bd == cborBdIndefiniteMap {
|
||
|
return containerLenUnknown
|
||
|
}
|
||
|
if d.bd>>5 != cborMajorMap {
|
||
|
d.d.errorf("error reading map; got major type: %x, expected %x/%s", d.bd>>5, cborMajorMap, cbordesc(d.bd))
|
||
|
}
|
||
|
return d.decLen()
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) ReadArrayStart() (length int) {
|
||
|
if d.advanceNil() {
|
||
|
return containerLenNil
|
||
|
}
|
||
|
if d.st {
|
||
|
d.skipTags()
|
||
|
}
|
||
|
d.bdRead = false
|
||
|
if d.bd == cborBdIndefiniteArray {
|
||
|
return containerLenUnknown
|
||
|
}
|
||
|
if d.bd>>5 != cborMajorArray {
|
||
|
d.d.errorf("invalid array; got major type: %x, expect: %x/%s", d.bd>>5, cborMajorArray, cbordesc(d.bd))
|
||
|
}
|
||
|
return d.decLen()
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) DecodeBytes(bs []byte) (bsOut []byte) {
|
||
|
d.d.decByteState = decByteStateNone
|
||
|
if d.advanceNil() {
|
||
|
return
|
||
|
}
|
||
|
if d.st {
|
||
|
d.skipTags()
|
||
|
}
|
||
|
if d.bd == cborBdIndefiniteBytes || d.bd == cborBdIndefiniteString {
|
||
|
d.bdRead = false
|
||
|
if bs == nil {
|
||
|
d.d.decByteState = decByteStateReuseBuf
|
||
|
return d.decAppendIndefiniteBytes(d.d.b[:0])
|
||
|
}
|
||
|
return d.decAppendIndefiniteBytes(bs[:0])
|
||
|
}
|
||
|
if d.bd == cborBdIndefiniteArray {
|
||
|
d.bdRead = false
|
||
|
if bs == nil {
|
||
|
d.d.decByteState = decByteStateReuseBuf
|
||
|
bs = d.d.b[:0]
|
||
|
} else {
|
||
|
bs = bs[:0]
|
||
|
}
|
||
|
for !d.CheckBreak() {
|
||
|
bs = append(bs, uint8(chkOvf.UintV(d.DecodeUint64(), 8)))
|
||
|
}
|
||
|
return bs
|
||
|
}
|
||
|
if d.bd>>5 == cborMajorArray {
|
||
|
d.bdRead = false
|
||
|
if bs == nil {
|
||
|
d.d.decByteState = decByteStateReuseBuf
|
||
|
bs = d.d.b[:]
|
||
|
}
|
||
|
slen := d.decLen()
|
||
|
var changed bool
|
||
|
if bs, changed = usableByteSlice(bs, slen); changed {
|
||
|
d.d.decByteState = decByteStateNone
|
||
|
}
|
||
|
for i := 0; i < len(bs); i++ {
|
||
|
bs[i] = uint8(chkOvf.UintV(d.DecodeUint64(), 8))
|
||
|
}
|
||
|
return bs
|
||
|
}
|
||
|
clen := d.decLen()
|
||
|
d.bdRead = false
|
||
|
if d.d.zerocopy() {
|
||
|
d.d.decByteState = decByteStateZerocopy
|
||
|
return d.d.decRd.rb.readx(uint(clen))
|
||
|
}
|
||
|
if bs == nil {
|
||
|
d.d.decByteState = decByteStateReuseBuf
|
||
|
bs = d.d.b[:]
|
||
|
}
|
||
|
return decByteSlice(d.d.r(), clen, d.h.MaxInitLen, bs)
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) DecodeStringAsBytes() (s []byte) {
|
||
|
return d.DecodeBytes(nil)
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) DecodeTime() (t time.Time) {
|
||
|
if d.advanceNil() {
|
||
|
return
|
||
|
}
|
||
|
if d.bd>>5 != cborMajorTag {
|
||
|
d.d.errorf("error reading tag; expected major type: %x, got: %x", cborMajorTag, d.bd>>5)
|
||
|
}
|
||
|
xtag := d.decUint()
|
||
|
d.bdRead = false
|
||
|
return d.decodeTime(xtag)
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) decodeTime(xtag uint64) (t time.Time) {
|
||
|
switch xtag {
|
||
|
case 0:
|
||
|
var err error
|
||
|
t, err = time.Parse(time.RFC3339, stringView(d.DecodeStringAsBytes()))
|
||
|
d.d.onerror(err)
|
||
|
case 1:
|
||
|
f1, f2 := math.Modf(d.DecodeFloat64())
|
||
|
t = time.Unix(int64(f1), int64(f2*1e9))
|
||
|
default:
|
||
|
d.d.errorf("invalid tag for time.Time - expecting 0 or 1, got 0x%x", xtag)
|
||
|
}
|
||
|
t = t.UTC().Round(time.Microsecond)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) {
|
||
|
if d.advanceNil() {
|
||
|
return
|
||
|
}
|
||
|
if d.bd>>5 != cborMajorTag {
|
||
|
d.d.errorf("error reading tag; expected major type: %x, got: %x", cborMajorTag, d.bd>>5)
|
||
|
}
|
||
|
realxtag := d.decUint()
|
||
|
d.bdRead = false
|
||
|
if ext == nil {
|
||
|
re := rv.(*RawExt)
|
||
|
re.Tag = realxtag
|
||
|
d.d.decode(&re.Value)
|
||
|
} else if xtag != realxtag {
|
||
|
d.d.errorf("Wrong extension tag. Got %b. Expecting: %v", realxtag, xtag)
|
||
|
} else if ext == SelfExt {
|
||
|
rv2 := baseRV(rv)
|
||
|
d.d.decodeValue(rv2, d.h.fnNoExt(rvType(rv2)))
|
||
|
} else {
|
||
|
d.d.interfaceExtConvertAndDecode(rv, ext)
|
||
|
}
|
||
|
d.bdRead = false
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) DecodeNaked() {
|
||
|
if !d.bdRead {
|
||
|
d.readNextBd()
|
||
|
}
|
||
|
|
||
|
n := d.d.naked()
|
||
|
var decodeFurther bool
|
||
|
|
||
|
switch d.bd >> 5 {
|
||
|
case cborMajorUint:
|
||
|
if d.h.SignedInteger {
|
||
|
n.v = valueTypeInt
|
||
|
n.i = d.DecodeInt64()
|
||
|
} else {
|
||
|
n.v = valueTypeUint
|
||
|
n.u = d.DecodeUint64()
|
||
|
}
|
||
|
case cborMajorNegInt:
|
||
|
n.v = valueTypeInt
|
||
|
n.i = d.DecodeInt64()
|
||
|
case cborMajorBytes:
|
||
|
d.d.fauxUnionReadRawBytes(false)
|
||
|
case cborMajorString:
|
||
|
n.v = valueTypeString
|
||
|
n.s = d.d.stringZC(d.DecodeStringAsBytes())
|
||
|
case cborMajorArray:
|
||
|
n.v = valueTypeArray
|
||
|
decodeFurther = true
|
||
|
case cborMajorMap:
|
||
|
n.v = valueTypeMap
|
||
|
decodeFurther = true
|
||
|
case cborMajorTag:
|
||
|
n.v = valueTypeExt
|
||
|
n.u = d.decUint()
|
||
|
n.l = nil
|
||
|
if n.u == 0 || n.u == 1 {
|
||
|
d.bdRead = false
|
||
|
n.v = valueTypeTime
|
||
|
n.t = d.decodeTime(n.u)
|
||
|
} else if d.st && d.h.getExtForTag(n.u) == nil {
|
||
|
// d.skipTags() // no need to call this - tags already skipped
|
||
|
d.bdRead = false
|
||
|
d.DecodeNaked()
|
||
|
return // return when done (as true recursive function)
|
||
|
}
|
||
|
case cborMajorSimpleOrFloat:
|
||
|
switch d.bd {
|
||
|
case cborBdNil, cborBdUndefined:
|
||
|
n.v = valueTypeNil
|
||
|
case cborBdFalse:
|
||
|
n.v = valueTypeBool
|
||
|
n.b = false
|
||
|
case cborBdTrue:
|
||
|
n.v = valueTypeBool
|
||
|
n.b = true
|
||
|
case cborBdFloat16, cborBdFloat32, cborBdFloat64:
|
||
|
n.v = valueTypeFloat
|
||
|
n.f = d.DecodeFloat64()
|
||
|
default:
|
||
|
d.d.errorf("decodeNaked: Unrecognized d.bd: 0x%x", d.bd)
|
||
|
}
|
||
|
default: // should never happen
|
||
|
d.d.errorf("decodeNaked: Unrecognized d.bd: 0x%x", d.bd)
|
||
|
}
|
||
|
if !decodeFurther {
|
||
|
d.bdRead = false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) uintBytes() (v []byte, ui uint64) {
|
||
|
// this is only used by nextValueBytes, so it's ok to
|
||
|
// use readx and bigenstd here.
|
||
|
switch vv := d.bd & 0x1f; vv {
|
||
|
case 0x18:
|
||
|
v = d.d.decRd.readx(1)
|
||
|
ui = uint64(v[0])
|
||
|
case 0x19:
|
||
|
v = d.d.decRd.readx(2)
|
||
|
ui = uint64(bigenstd.Uint16(v))
|
||
|
case 0x1a:
|
||
|
v = d.d.decRd.readx(4)
|
||
|
ui = uint64(bigenstd.Uint32(v))
|
||
|
case 0x1b:
|
||
|
v = d.d.decRd.readx(8)
|
||
|
ui = uint64(bigenstd.Uint64(v))
|
||
|
default:
|
||
|
if vv > 0x1b {
|
||
|
d.d.errorf("invalid descriptor decoding uint: %x/%s", d.bd, cbordesc(d.bd))
|
||
|
}
|
||
|
ui = uint64(vv)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) nextValueBytes(start []byte) (v []byte) {
|
||
|
if !d.bdRead {
|
||
|
d.readNextBd()
|
||
|
}
|
||
|
v = append(start, d.bd)
|
||
|
v = d.nextValueBytesBdReadR(v)
|
||
|
d.bdRead = false
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) nextValueBytesR(v0 []byte) (v []byte) {
|
||
|
d.readNextBd()
|
||
|
v = append(v0, d.bd)
|
||
|
return d.nextValueBytesBdReadR(v)
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) nextValueBytesBdReadR(v0 []byte) (v []byte) {
|
||
|
v = v0
|
||
|
var bs []byte
|
||
|
var ui uint64
|
||
|
|
||
|
switch d.bd >> 5 {
|
||
|
case cborMajorUint, cborMajorNegInt:
|
||
|
bs, _ = d.uintBytes()
|
||
|
v = append(v, bs...)
|
||
|
case cborMajorString, cborMajorBytes:
|
||
|
if d.bd == cborBdIndefiniteBytes || d.bd == cborBdIndefiniteString {
|
||
|
for {
|
||
|
d.readNextBd()
|
||
|
v = append(v, d.bd)
|
||
|
if d.bd == cborBdBreak {
|
||
|
break
|
||
|
}
|
||
|
bs, ui = d.uintBytes()
|
||
|
v = append(v, bs...)
|
||
|
v = append(v, d.d.decRd.readx(uint(ui))...)
|
||
|
}
|
||
|
} else {
|
||
|
bs, ui = d.uintBytes()
|
||
|
v = append(v, bs...)
|
||
|
v = append(v, d.d.decRd.readx(uint(ui))...)
|
||
|
}
|
||
|
case cborMajorArray:
|
||
|
if d.bd == cborBdIndefiniteArray {
|
||
|
for {
|
||
|
d.readNextBd()
|
||
|
v = append(v, d.bd)
|
||
|
if d.bd == cborBdBreak {
|
||
|
break
|
||
|
}
|
||
|
v = d.nextValueBytesBdReadR(v)
|
||
|
}
|
||
|
} else {
|
||
|
bs, ui = d.uintBytes()
|
||
|
v = append(v, bs...)
|
||
|
for i := uint64(0); i < ui; i++ {
|
||
|
v = d.nextValueBytesR(v)
|
||
|
}
|
||
|
}
|
||
|
case cborMajorMap:
|
||
|
if d.bd == cborBdIndefiniteMap {
|
||
|
for {
|
||
|
d.readNextBd()
|
||
|
v = append(v, d.bd)
|
||
|
if d.bd == cborBdBreak {
|
||
|
break
|
||
|
}
|
||
|
v = d.nextValueBytesBdReadR(v)
|
||
|
v = d.nextValueBytesR(v)
|
||
|
}
|
||
|
} else {
|
||
|
bs, ui = d.uintBytes()
|
||
|
v = append(v, bs...)
|
||
|
for i := uint64(0); i < ui; i++ {
|
||
|
v = d.nextValueBytesR(v)
|
||
|
v = d.nextValueBytesR(v)
|
||
|
}
|
||
|
}
|
||
|
case cborMajorTag:
|
||
|
bs, _ = d.uintBytes()
|
||
|
v = append(v, bs...)
|
||
|
v = d.nextValueBytesR(v)
|
||
|
case cborMajorSimpleOrFloat:
|
||
|
switch d.bd {
|
||
|
case cborBdNil, cborBdUndefined, cborBdFalse, cborBdTrue: // pass
|
||
|
case cborBdFloat16:
|
||
|
v = append(v, d.d.decRd.readx(2)...)
|
||
|
case cborBdFloat32:
|
||
|
v = append(v, d.d.decRd.readx(4)...)
|
||
|
case cborBdFloat64:
|
||
|
v = append(v, d.d.decRd.readx(8)...)
|
||
|
default:
|
||
|
d.d.errorf("nextValueBytes: Unrecognized d.bd: 0x%x", d.bd)
|
||
|
}
|
||
|
default: // should never happen
|
||
|
d.d.errorf("nextValueBytes: Unrecognized d.bd: 0x%x", d.bd)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// -------------------------
|
||
|
|
||
|
// CborHandle is a Handle for the CBOR encoding format,
|
||
|
// defined at http://tools.ietf.org/html/rfc7049 and documented further at http://cbor.io .
|
||
|
//
|
||
|
// CBOR is comprehensively supported, including support for:
|
||
|
// - indefinite-length arrays/maps/bytes/strings
|
||
|
// - (extension) tags in range 0..0xffff (0 .. 65535)
|
||
|
// - half, single and double-precision floats
|
||
|
// - all numbers (1, 2, 4 and 8-byte signed and unsigned integers)
|
||
|
// - nil, true, false, ...
|
||
|
// - arrays and maps, bytes and text strings
|
||
|
//
|
||
|
// None of the optional extensions (with tags) defined in the spec are supported out-of-the-box.
|
||
|
// Users can implement them as needed (using SetExt), including spec-documented ones:
|
||
|
// - timestamp, BigNum, BigFloat, Decimals,
|
||
|
// - Encoded Text (e.g. URL, regexp, base64, MIME Message), etc.
|
||
|
type CborHandle struct {
|
||
|
binaryEncodingType
|
||
|
// noElemSeparators
|
||
|
BasicHandle
|
||
|
|
||
|
// IndefiniteLength=true, means that we encode using indefinitelength
|
||
|
IndefiniteLength bool
|
||
|
|
||
|
// TimeRFC3339 says to encode time.Time using RFC3339 format.
|
||
|
// If unset, we encode time.Time using seconds past epoch.
|
||
|
TimeRFC3339 bool
|
||
|
|
||
|
// SkipUnexpectedTags says to skip over any tags for which extensions are
|
||
|
// not defined. This is in keeping with the cbor spec on "Optional Tagging of Items".
|
||
|
//
|
||
|
// Furthermore, this allows the skipping over of the Self Describing Tag 0xd9d9f7.
|
||
|
SkipUnexpectedTags bool
|
||
|
}
|
||
|
|
||
|
// Name returns the name of the handle: cbor
|
||
|
func (h *CborHandle) Name() string { return "cbor" }
|
||
|
|
||
|
func (h *CborHandle) desc(bd byte) string { return cbordesc(bd) }
|
||
|
|
||
|
func (h *CborHandle) newEncDriver() encDriver {
|
||
|
var e = &cborEncDriver{h: h}
|
||
|
e.e.e = e
|
||
|
e.e.init(h)
|
||
|
e.reset()
|
||
|
return e
|
||
|
}
|
||
|
|
||
|
func (h *CborHandle) newDecDriver() decDriver {
|
||
|
d := &cborDecDriver{h: h, st: h.SkipUnexpectedTags}
|
||
|
d.d.d = d
|
||
|
d.d.cbor = true
|
||
|
d.d.init(h)
|
||
|
d.reset()
|
||
|
return d
|
||
|
}
|
||
|
|
||
|
func (e *cborEncDriver) reset() {
|
||
|
}
|
||
|
|
||
|
func (d *cborDecDriver) reset() {
|
||
|
d.bd = 0
|
||
|
d.bdRead = false
|
||
|
d.st = d.h.SkipUnexpectedTags
|
||
|
}
|
||
|
|
||
|
var _ decDriver = (*cborDecDriver)(nil)
|
||
|
var _ encDriver = (*cborEncDriver)(nil)
|