602 lines
14 KiB
Go
602 lines
14 KiB
Go
// Copyright (c) 2012-2015 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"
|
|
"reflect"
|
|
)
|
|
|
|
const (
|
|
cborMajorUint byte = iota
|
|
cborMajorNegInt
|
|
cborMajorBytes
|
|
cborMajorText
|
|
cborMajorArray
|
|
cborMajorMap
|
|
cborMajorTag
|
|
cborMajorOther
|
|
)
|
|
|
|
const (
|
|
cborBdFalse byte = 0xf4 + iota
|
|
cborBdTrue
|
|
cborBdNil
|
|
cborBdUndefined
|
|
cborBdExt
|
|
cborBdFloat16
|
|
cborBdFloat32
|
|
cborBdFloat64
|
|
)
|
|
|
|
const (
|
|
cborBdIndefiniteBytes byte = 0x5f
|
|
cborBdIndefiniteString = 0x7f
|
|
cborBdIndefiniteArray = 0x9f
|
|
cborBdIndefiniteMap = 0xbf
|
|
cborBdBreak = 0xff
|
|
)
|
|
|
|
const (
|
|
CborStreamBytes byte = 0x5f
|
|
CborStreamString = 0x7f
|
|
CborStreamArray = 0x9f
|
|
CborStreamMap = 0xbf
|
|
CborStreamBreak = 0xff
|
|
)
|
|
|
|
const (
|
|
cborBaseUint byte = 0x00
|
|
cborBaseNegInt = 0x20
|
|
cborBaseBytes = 0x40
|
|
cborBaseString = 0x60
|
|
cborBaseArray = 0x80
|
|
cborBaseMap = 0xa0
|
|
cborBaseTag = 0xc0
|
|
cborBaseSimple = 0xe0
|
|
)
|
|
|
|
// -------------------
|
|
|
|
type cborEncDriver struct {
|
|
noBuiltInTypes
|
|
encNoSeparator
|
|
e *Encoder
|
|
w encWriter
|
|
h *CborHandle
|
|
x [8]byte
|
|
}
|
|
|
|
func (e *cborEncDriver) EncodeNil() {
|
|
e.w.writen1(cborBdNil)
|
|
}
|
|
|
|
func (e *cborEncDriver) EncodeBool(b bool) {
|
|
if b {
|
|
e.w.writen1(cborBdTrue)
|
|
} else {
|
|
e.w.writen1(cborBdFalse)
|
|
}
|
|
}
|
|
|
|
func (e *cborEncDriver) EncodeFloat32(f float32) {
|
|
e.w.writen1(cborBdFloat32)
|
|
bigenHelper{e.x[:4], e.w}.writeUint32(math.Float32bits(f))
|
|
}
|
|
|
|
func (e *cborEncDriver) EncodeFloat64(f float64) {
|
|
e.w.writen1(cborBdFloat64)
|
|
bigenHelper{e.x[:8], e.w}.writeUint64(math.Float64bits(f))
|
|
}
|
|
|
|
func (e *cborEncDriver) encUint(v uint64, bd byte) {
|
|
if v <= 0x17 {
|
|
e.w.writen1(byte(v) + bd)
|
|
} else if v <= math.MaxUint8 {
|
|
e.w.writen2(bd+0x18, uint8(v))
|
|
} else if v <= math.MaxUint16 {
|
|
e.w.writen1(bd + 0x19)
|
|
bigenHelper{e.x[:2], e.w}.writeUint16(uint16(v))
|
|
} else if v <= math.MaxUint32 {
|
|
e.w.writen1(bd + 0x1a)
|
|
bigenHelper{e.x[:4], e.w}.writeUint32(uint32(v))
|
|
} else { // if v <= math.MaxUint64 {
|
|
e.w.writen1(bd + 0x1b)
|
|
bigenHelper{e.x[:8], e.w}.writeUint64(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) EncodeExt(rv interface{}, xtag uint64, ext Ext, en *Encoder) {
|
|
e.encUint(uint64(xtag), cborBaseTag)
|
|
if v := ext.ConvertExt(rv); v == nil {
|
|
e.EncodeNil()
|
|
} else {
|
|
en.encode(v)
|
|
}
|
|
}
|
|
|
|
func (e *cborEncDriver) EncodeRawExt(re *RawExt, en *Encoder) {
|
|
e.encUint(uint64(re.Tag), cborBaseTag)
|
|
if re.Data != nil {
|
|
en.encode(re.Data)
|
|
} else if re.Value == nil {
|
|
e.EncodeNil()
|
|
} else {
|
|
en.encode(re.Value)
|
|
}
|
|
}
|
|
|
|
func (e *cborEncDriver) EncodeArrayStart(length int) {
|
|
e.encLen(cborBaseArray, length)
|
|
}
|
|
|
|
func (e *cborEncDriver) EncodeMapStart(length int) {
|
|
e.encLen(cborBaseMap, length)
|
|
}
|
|
|
|
func (e *cborEncDriver) EncodeString(c charEncoding, v string) {
|
|
e.encLen(cborBaseString, len(v))
|
|
e.w.writestr(v)
|
|
}
|
|
|
|
func (e *cborEncDriver) EncodeSymbol(v string) {
|
|
e.EncodeString(c_UTF8, v)
|
|
}
|
|
|
|
func (e *cborEncDriver) EncodeStringBytes(c charEncoding, v []byte) {
|
|
if c == c_RAW {
|
|
e.encLen(cborBaseBytes, len(v))
|
|
} else {
|
|
e.encLen(cborBaseString, len(v))
|
|
}
|
|
e.w.writeb(v)
|
|
}
|
|
|
|
// ----------------------
|
|
|
|
type cborDecDriver struct {
|
|
d *Decoder
|
|
h *CborHandle
|
|
r decReader
|
|
b [scratchByteArrayLen]byte
|
|
br bool // bytes reader
|
|
bdRead bool
|
|
bd byte
|
|
noBuiltInTypes
|
|
decNoSeparator
|
|
}
|
|
|
|
func (d *cborDecDriver) readNextBd() {
|
|
d.bd = d.r.readn1()
|
|
d.bdRead = true
|
|
}
|
|
|
|
func (d *cborDecDriver) uncacheRead() {
|
|
if d.bdRead {
|
|
d.r.unreadn1()
|
|
d.bdRead = false
|
|
}
|
|
}
|
|
|
|
func (d *cborDecDriver) ContainerType() (vt valueType) {
|
|
if !d.bdRead {
|
|
d.readNextBd()
|
|
}
|
|
if d.bd == cborBdNil {
|
|
return valueTypeNil
|
|
} else if d.bd == cborBdIndefiniteBytes || (d.bd >= cborBaseBytes && d.bd < cborBaseString) {
|
|
return valueTypeBytes
|
|
} else if d.bd == cborBdIndefiniteString || (d.bd >= cborBaseString && d.bd < cborBaseArray) {
|
|
return valueTypeString
|
|
} else if d.bd == cborBdIndefiniteArray || (d.bd >= cborBaseArray && d.bd < cborBaseMap) {
|
|
return valueTypeArray
|
|
} else if d.bd == cborBdIndefiniteMap || (d.bd >= cborBaseMap && d.bd < cborBaseTag) {
|
|
return valueTypeMap
|
|
} else {
|
|
// d.d.errorf("isContainerType: unsupported parameter: %v", vt)
|
|
}
|
|
return valueTypeUnset
|
|
}
|
|
|
|
func (d *cborDecDriver) TryDecodeAsNil() bool {
|
|
if !d.bdRead {
|
|
d.readNextBd()
|
|
}
|
|
// treat Nil and Undefined as nil values
|
|
if d.bd == cborBdNil || d.bd == cborBdUndefined {
|
|
d.bdRead = false
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (d *cborDecDriver) CheckBreak() bool {
|
|
if !d.bdRead {
|
|
d.readNextBd()
|
|
}
|
|
if d.bd == cborBdBreak {
|
|
d.bdRead = false
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (d *cborDecDriver) decUint() (ui uint64) {
|
|
v := d.bd & 0x1f
|
|
if v <= 0x17 {
|
|
ui = uint64(v)
|
|
} else {
|
|
if v == 0x18 {
|
|
ui = uint64(d.r.readn1())
|
|
} else if v == 0x19 {
|
|
ui = uint64(bigen.Uint16(d.r.readx(2)))
|
|
} else if v == 0x1a {
|
|
ui = uint64(bigen.Uint32(d.r.readx(4)))
|
|
} else if v == 0x1b {
|
|
ui = uint64(bigen.Uint64(d.r.readx(8)))
|
|
} else {
|
|
d.d.errorf("decUint: Invalid descriptor: %v", d.bd)
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (d *cborDecDriver) decCheckInteger() (neg bool) {
|
|
if !d.bdRead {
|
|
d.readNextBd()
|
|
}
|
|
major := d.bd >> 5
|
|
if major == cborMajorUint {
|
|
} else if major == cborMajorNegInt {
|
|
neg = true
|
|
} else {
|
|
d.d.errorf("invalid major: %v (bd: %v)", major, d.bd)
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
func (d *cborDecDriver) DecodeInt(bitsize uint8) (i int64) {
|
|
neg := d.decCheckInteger()
|
|
ui := d.decUint()
|
|
// check if this number can be converted to an int without overflow
|
|
var overflow bool
|
|
if neg {
|
|
if i, overflow = chkOvf.SignedInt(ui + 1); overflow {
|
|
d.d.errorf("cbor: overflow converting %v to signed integer", ui+1)
|
|
return
|
|
}
|
|
i = -i
|
|
} else {
|
|
if i, overflow = chkOvf.SignedInt(ui); overflow {
|
|
d.d.errorf("cbor: overflow converting %v to signed integer", ui)
|
|
return
|
|
}
|
|
}
|
|
if chkOvf.Int(i, bitsize) {
|
|
d.d.errorf("cbor: overflow integer: %v", i)
|
|
return
|
|
}
|
|
d.bdRead = false
|
|
return
|
|
}
|
|
|
|
func (d *cborDecDriver) DecodeUint(bitsize uint8) (ui uint64) {
|
|
if d.decCheckInteger() {
|
|
d.d.errorf("Assigning negative signed value to unsigned type")
|
|
return
|
|
}
|
|
ui = d.decUint()
|
|
if chkOvf.Uint(ui, bitsize) {
|
|
d.d.errorf("cbor: overflow integer: %v", ui)
|
|
return
|
|
}
|
|
d.bdRead = false
|
|
return
|
|
}
|
|
|
|
func (d *cborDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) {
|
|
if !d.bdRead {
|
|
d.readNextBd()
|
|
}
|
|
if bd := d.bd; bd == cborBdFloat16 {
|
|
f = float64(math.Float32frombits(halfFloatToFloatBits(bigen.Uint16(d.r.readx(2)))))
|
|
} else if bd == cborBdFloat32 {
|
|
f = float64(math.Float32frombits(bigen.Uint32(d.r.readx(4))))
|
|
} else if bd == cborBdFloat64 {
|
|
f = math.Float64frombits(bigen.Uint64(d.r.readx(8)))
|
|
} else if bd >= cborBaseUint && bd < cborBaseBytes {
|
|
f = float64(d.DecodeInt(64))
|
|
} else {
|
|
d.d.errorf("Float only valid from float16/32/64: Invalid descriptor: %v", bd)
|
|
return
|
|
}
|
|
if chkOverflow32 && chkOvf.Float32(f) {
|
|
d.d.errorf("cbor: float32 overflow: %v", f)
|
|
return
|
|
}
|
|
d.bdRead = false
|
|
return
|
|
}
|
|
|
|
// bool can be decoded from bool only (single byte).
|
|
func (d *cborDecDriver) DecodeBool() (b bool) {
|
|
if !d.bdRead {
|
|
d.readNextBd()
|
|
}
|
|
if bd := d.bd; bd == cborBdTrue {
|
|
b = true
|
|
} else if bd == cborBdFalse {
|
|
} else {
|
|
d.d.errorf("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd)
|
|
return
|
|
}
|
|
d.bdRead = false
|
|
return
|
|
}
|
|
|
|
func (d *cborDecDriver) ReadMapStart() (length int) {
|
|
if !d.bdRead {
|
|
d.readNextBd()
|
|
}
|
|
d.bdRead = false
|
|
if d.bd == cborBdIndefiniteMap {
|
|
return -1
|
|
}
|
|
return d.decLen()
|
|
}
|
|
|
|
func (d *cborDecDriver) ReadArrayStart() (length int) {
|
|
if !d.bdRead {
|
|
d.readNextBd()
|
|
}
|
|
d.bdRead = false
|
|
if d.bd == cborBdIndefiniteArray {
|
|
return -1
|
|
}
|
|
return d.decLen()
|
|
}
|
|
|
|
func (d *cborDecDriver) decLen() int {
|
|
return int(d.decUint())
|
|
}
|
|
|
|
func (d *cborDecDriver) decAppendIndefiniteBytes(bs []byte) []byte {
|
|
d.bdRead = false
|
|
for {
|
|
if d.CheckBreak() {
|
|
break
|
|
}
|
|
if major := d.bd >> 5; major != cborMajorBytes && major != cborMajorText {
|
|
d.d.errorf("cbor: expect bytes or string major type in indefinite string/bytes; got: %v, byte: %v", major, d.bd)
|
|
return nil
|
|
}
|
|
n := d.decLen()
|
|
oldLen := len(bs)
|
|
newLen := oldLen + n
|
|
if newLen > cap(bs) {
|
|
bs2 := make([]byte, newLen, 2*cap(bs)+n)
|
|
copy(bs2, bs)
|
|
bs = bs2
|
|
} else {
|
|
bs = bs[:newLen]
|
|
}
|
|
d.r.readb(bs[oldLen:newLen])
|
|
// bs = append(bs, d.r.readn()...)
|
|
d.bdRead = false
|
|
}
|
|
d.bdRead = false
|
|
return bs
|
|
}
|
|
|
|
func (d *cborDecDriver) DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte) {
|
|
if !d.bdRead {
|
|
d.readNextBd()
|
|
}
|
|
if d.bd == cborBdNil || d.bd == cborBdUndefined {
|
|
d.bdRead = false
|
|
return nil
|
|
}
|
|
if d.bd == cborBdIndefiniteBytes || d.bd == cborBdIndefiniteString {
|
|
if bs == nil {
|
|
return d.decAppendIndefiniteBytes(nil)
|
|
}
|
|
return d.decAppendIndefiniteBytes(bs[:0])
|
|
}
|
|
clen := d.decLen()
|
|
d.bdRead = false
|
|
if zerocopy {
|
|
if d.br {
|
|
return d.r.readx(clen)
|
|
} else if len(bs) == 0 {
|
|
bs = d.b[:]
|
|
}
|
|
}
|
|
return decByteSlice(d.r, clen, d.d.h.MaxInitLen, bs)
|
|
}
|
|
|
|
func (d *cborDecDriver) DecodeString() (s string) {
|
|
return string(d.DecodeBytes(d.b[:], true, true))
|
|
}
|
|
|
|
func (d *cborDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) {
|
|
if !d.bdRead {
|
|
d.readNextBd()
|
|
}
|
|
u := d.decUint()
|
|
d.bdRead = false
|
|
realxtag = u
|
|
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)
|
|
return
|
|
} else {
|
|
var v interface{}
|
|
d.d.decode(&v)
|
|
ext.UpdateExt(rv, v)
|
|
}
|
|
d.bdRead = false
|
|
return
|
|
}
|
|
|
|
func (d *cborDecDriver) DecodeNaked() {
|
|
if !d.bdRead {
|
|
d.readNextBd()
|
|
}
|
|
|
|
n := &d.d.n
|
|
var decodeFurther bool
|
|
|
|
switch d.bd {
|
|
case cborBdNil:
|
|
n.v = valueTypeNil
|
|
case cborBdFalse:
|
|
n.v = valueTypeBool
|
|
n.b = false
|
|
case cborBdTrue:
|
|
n.v = valueTypeBool
|
|
n.b = true
|
|
case cborBdFloat16, cborBdFloat32:
|
|
n.v = valueTypeFloat
|
|
n.f = d.DecodeFloat(true)
|
|
case cborBdFloat64:
|
|
n.v = valueTypeFloat
|
|
n.f = d.DecodeFloat(false)
|
|
case cborBdIndefiniteBytes:
|
|
n.v = valueTypeBytes
|
|
n.l = d.DecodeBytes(nil, false, false)
|
|
case cborBdIndefiniteString:
|
|
n.v = valueTypeString
|
|
n.s = d.DecodeString()
|
|
case cborBdIndefiniteArray:
|
|
n.v = valueTypeArray
|
|
decodeFurther = true
|
|
case cborBdIndefiniteMap:
|
|
n.v = valueTypeMap
|
|
decodeFurther = true
|
|
default:
|
|
switch {
|
|
case d.bd >= cborBaseUint && d.bd < cborBaseNegInt:
|
|
if d.h.SignedInteger {
|
|
n.v = valueTypeInt
|
|
n.i = d.DecodeInt(64)
|
|
} else {
|
|
n.v = valueTypeUint
|
|
n.u = d.DecodeUint(64)
|
|
}
|
|
case d.bd >= cborBaseNegInt && d.bd < cborBaseBytes:
|
|
n.v = valueTypeInt
|
|
n.i = d.DecodeInt(64)
|
|
case d.bd >= cborBaseBytes && d.bd < cborBaseString:
|
|
n.v = valueTypeBytes
|
|
n.l = d.DecodeBytes(nil, false, false)
|
|
case d.bd >= cborBaseString && d.bd < cborBaseArray:
|
|
n.v = valueTypeString
|
|
n.s = d.DecodeString()
|
|
case d.bd >= cborBaseArray && d.bd < cborBaseMap:
|
|
n.v = valueTypeArray
|
|
decodeFurther = true
|
|
case d.bd >= cborBaseMap && d.bd < cborBaseTag:
|
|
n.v = valueTypeMap
|
|
decodeFurther = true
|
|
case d.bd >= cborBaseTag && d.bd < cborBaseSimple:
|
|
n.v = valueTypeExt
|
|
n.u = d.decUint()
|
|
n.l = nil
|
|
// d.bdRead = false
|
|
// d.d.decode(&re.Value) // handled by decode itself.
|
|
// decodeFurther = true
|
|
default:
|
|
d.d.errorf("decodeNaked: Unrecognized d.bd: 0x%x", d.bd)
|
|
return
|
|
}
|
|
}
|
|
|
|
if !decodeFurther {
|
|
d.bdRead = false
|
|
}
|
|
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.
|
|
//
|
|
// To encode with indefinite lengths (streaming), users will use
|
|
// (Must)Encode methods of *Encoder, along with writing CborStreamXXX constants.
|
|
//
|
|
// For example, to encode "one-byte" as an indefinite length string:
|
|
// var buf bytes.Buffer
|
|
// e := NewEncoder(&buf, new(CborHandle))
|
|
// buf.WriteByte(CborStreamString)
|
|
// e.MustEncode("one-")
|
|
// e.MustEncode("byte")
|
|
// buf.WriteByte(CborStreamBreak)
|
|
// encodedBytes := buf.Bytes()
|
|
// var vv interface{}
|
|
// NewDecoderBytes(buf.Bytes(), new(CborHandle)).MustDecode(&vv)
|
|
// // Now, vv contains the same string "one-byte"
|
|
//
|
|
type CborHandle struct {
|
|
binaryEncodingType
|
|
BasicHandle
|
|
}
|
|
|
|
func (h *CborHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) {
|
|
return h.SetExt(rt, tag, &setExtWrapper{i: ext})
|
|
}
|
|
|
|
func (h *CborHandle) newEncDriver(e *Encoder) encDriver {
|
|
return &cborEncDriver{e: e, w: e.w, h: h}
|
|
}
|
|
|
|
func (h *CborHandle) newDecDriver(d *Decoder) decDriver {
|
|
return &cborDecDriver{d: d, h: h, r: d.r, br: d.bytes}
|
|
}
|
|
|
|
func (e *cborEncDriver) reset() {
|
|
e.w = e.e.w
|
|
}
|
|
|
|
func (d *cborDecDriver) reset() {
|
|
d.r, d.br = d.d.r, d.d.bytes
|
|
d.bd, d.bdRead = 0, false
|
|
}
|
|
|
|
var _ decDriver = (*cborDecDriver)(nil)
|
|
var _ encDriver = (*cborEncDriver)(nil)
|