forked from jshiffer/matterbridge
248 lines
6.5 KiB
Go
248 lines
6.5 KiB
Go
package gojay
|
|
|
|
import "reflect"
|
|
|
|
// DecodeArray reads the next JSON-encoded value from the decoder's input (io.Reader)
|
|
// and stores it in the value pointed to by v.
|
|
//
|
|
// v must implement UnmarshalerJSONArray.
|
|
//
|
|
// See the documentation for Unmarshal for details about the conversion of JSON into a Go value.
|
|
func (dec *Decoder) DecodeArray(v UnmarshalerJSONArray) error {
|
|
if dec.isPooled == 1 {
|
|
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
|
|
}
|
|
_, err := dec.decodeArray(v)
|
|
return err
|
|
}
|
|
func (dec *Decoder) decodeArray(arr UnmarshalerJSONArray) (int, error) {
|
|
// remember last array index in case of nested arrays
|
|
lastArrayIndex := dec.arrayIndex
|
|
dec.arrayIndex = 0
|
|
defer func() {
|
|
dec.arrayIndex = lastArrayIndex
|
|
}()
|
|
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
|
|
switch dec.data[dec.cursor] {
|
|
case ' ', '\n', '\t', '\r', ',':
|
|
continue
|
|
case '[':
|
|
dec.cursor = dec.cursor + 1
|
|
// array is open, char is not space start readings
|
|
for dec.nextChar() != 0 {
|
|
// closing array
|
|
if dec.data[dec.cursor] == ']' {
|
|
dec.cursor = dec.cursor + 1
|
|
return dec.cursor, nil
|
|
}
|
|
// calling unmarshall function for each element of the slice
|
|
err := arr.UnmarshalJSONArray(dec)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
dec.arrayIndex++
|
|
}
|
|
return 0, dec.raiseInvalidJSONErr(dec.cursor)
|
|
case 'n':
|
|
// is null
|
|
dec.cursor++
|
|
err := dec.assertNull()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return dec.cursor, nil
|
|
case '{', '"', 'f', 't', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
|
// can't unmarshall to struct
|
|
// we skip array and set Error
|
|
dec.err = dec.makeInvalidUnmarshalErr(arr)
|
|
err := dec.skipData()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return dec.cursor, nil
|
|
default:
|
|
return 0, dec.raiseInvalidJSONErr(dec.cursor)
|
|
}
|
|
}
|
|
return 0, dec.raiseInvalidJSONErr(dec.cursor)
|
|
}
|
|
func (dec *Decoder) decodeArrayNull(v interface{}) (int, error) {
|
|
// remember last array index in case of nested arrays
|
|
lastArrayIndex := dec.arrayIndex
|
|
dec.arrayIndex = 0
|
|
defer func() {
|
|
dec.arrayIndex = lastArrayIndex
|
|
}()
|
|
vv := reflect.ValueOf(v)
|
|
vvt := vv.Type()
|
|
if vvt.Kind() != reflect.Ptr || vvt.Elem().Kind() != reflect.Ptr {
|
|
dec.err = ErrUnmarshalPtrExpected
|
|
return 0, dec.err
|
|
}
|
|
// not an array not an error, but do not know what to do
|
|
// do not check syntax
|
|
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
|
|
switch dec.data[dec.cursor] {
|
|
case ' ', '\n', '\t', '\r', ',':
|
|
continue
|
|
case '[':
|
|
dec.cursor = dec.cursor + 1
|
|
// create our new type
|
|
elt := vv.Elem()
|
|
n := reflect.New(elt.Type().Elem())
|
|
var arr UnmarshalerJSONArray
|
|
var ok bool
|
|
if arr, ok = n.Interface().(UnmarshalerJSONArray); !ok {
|
|
dec.err = dec.makeInvalidUnmarshalErr((UnmarshalerJSONArray)(nil))
|
|
return 0, dec.err
|
|
}
|
|
// array is open, char is not space start readings
|
|
for dec.nextChar() != 0 {
|
|
// closing array
|
|
if dec.data[dec.cursor] == ']' {
|
|
elt.Set(n)
|
|
dec.cursor = dec.cursor + 1
|
|
return dec.cursor, nil
|
|
}
|
|
// calling unmarshall function for each element of the slice
|
|
err := arr.UnmarshalJSONArray(dec)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
dec.arrayIndex++
|
|
}
|
|
return 0, dec.raiseInvalidJSONErr(dec.cursor)
|
|
case 'n':
|
|
// is null
|
|
dec.cursor++
|
|
err := dec.assertNull()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return dec.cursor, nil
|
|
case '{', '"', 'f', 't', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
|
// can't unmarshall to struct
|
|
// we skip array and set Error
|
|
dec.err = dec.makeInvalidUnmarshalErr((UnmarshalerJSONArray)(nil))
|
|
err := dec.skipData()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return dec.cursor, nil
|
|
default:
|
|
return 0, dec.raiseInvalidJSONErr(dec.cursor)
|
|
}
|
|
}
|
|
return 0, dec.raiseInvalidJSONErr(dec.cursor)
|
|
}
|
|
|
|
func (dec *Decoder) skipArray() (int, error) {
|
|
var arraysOpen = 1
|
|
var arraysClosed = 0
|
|
// var stringOpen byte = 0
|
|
for j := dec.cursor; j < dec.length || dec.read(); j++ {
|
|
switch dec.data[j] {
|
|
case ']':
|
|
arraysClosed++
|
|
// everything is closed return
|
|
if arraysOpen == arraysClosed {
|
|
// add char to object data
|
|
return j + 1, nil
|
|
}
|
|
case '[':
|
|
arraysOpen++
|
|
case '"':
|
|
j++
|
|
var isInEscapeSeq bool
|
|
var isFirstQuote = true
|
|
for ; j < dec.length || dec.read(); j++ {
|
|
if dec.data[j] != '"' {
|
|
continue
|
|
}
|
|
if dec.data[j-1] != '\\' || (!isInEscapeSeq && !isFirstQuote) {
|
|
break
|
|
} else {
|
|
isInEscapeSeq = false
|
|
}
|
|
if isFirstQuote {
|
|
isFirstQuote = false
|
|
}
|
|
// loop backward and count how many anti slash found
|
|
// to see if string is effectively escaped
|
|
ct := 0
|
|
for i := j - 1; i > 0; i-- {
|
|
if dec.data[i] != '\\' {
|
|
break
|
|
}
|
|
ct++
|
|
}
|
|
// is pair number of slashes, quote is not escaped
|
|
if ct&1 == 0 {
|
|
break
|
|
}
|
|
isInEscapeSeq = true
|
|
}
|
|
default:
|
|
continue
|
|
}
|
|
}
|
|
return 0, dec.raiseInvalidJSONErr(dec.cursor)
|
|
}
|
|
|
|
// DecodeArrayFunc is a func type implementing UnmarshalerJSONArray.
|
|
// Use it to cast a `func(*Decoder) error` to Unmarshal an array on the fly.
|
|
|
|
type DecodeArrayFunc func(*Decoder) error
|
|
|
|
// UnmarshalJSONArray implements UnmarshalerJSONArray.
|
|
func (f DecodeArrayFunc) UnmarshalJSONArray(dec *Decoder) error {
|
|
return f(dec)
|
|
}
|
|
|
|
// IsNil implements UnmarshalerJSONArray.
|
|
func (f DecodeArrayFunc) IsNil() bool {
|
|
return f == nil
|
|
}
|
|
|
|
// Add Values functions
|
|
|
|
// AddArray decodes the JSON value within an object or an array to a UnmarshalerJSONArray.
|
|
func (dec *Decoder) AddArray(v UnmarshalerJSONArray) error {
|
|
return dec.Array(v)
|
|
}
|
|
|
|
// AddArrayNull decodes the JSON value within an object or an array to a UnmarshalerJSONArray.
|
|
func (dec *Decoder) AddArrayNull(v interface{}) error {
|
|
return dec.ArrayNull(v)
|
|
}
|
|
|
|
// Array decodes the JSON value within an object or an array to a UnmarshalerJSONArray.
|
|
func (dec *Decoder) Array(v UnmarshalerJSONArray) error {
|
|
newCursor, err := dec.decodeArray(v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
dec.cursor = newCursor
|
|
dec.called |= 1
|
|
return nil
|
|
}
|
|
|
|
// ArrayNull decodes the JSON value within an object or an array to a UnmarshalerJSONArray.
|
|
// v should be a pointer to an UnmarshalerJSONArray,
|
|
// if `null` value is encountered in JSON, it will leave the value v untouched,
|
|
// else it will create a new instance of the UnmarshalerJSONArray behind v.
|
|
func (dec *Decoder) ArrayNull(v interface{}) error {
|
|
newCursor, err := dec.decodeArrayNull(v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
dec.cursor = newCursor
|
|
dec.called |= 1
|
|
return nil
|
|
}
|
|
|
|
// Index returns the index of an array being decoded.
|
|
func (dec *Decoder) Index() int {
|
|
return dec.arrayIndex
|
|
}
|