1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

rebased canonical/json off go 1.5.1

Signed-off-by: Jessica Frazelle <acidburn@docker.com>
This commit is contained in:
Jessica Frazelle 2015-11-02 10:23:02 -08:00
parent 6563b7d2e8
commit 0d881349e8
No known key found for this signature in database
GPG key ID: 18F3685C0022BFF3
7 changed files with 390 additions and 56 deletions

View file

@ -44,7 +44,7 @@ clone git github.com/vbatts/tar-split v0.9.10
clone git github.com/docker/notary 089d8450d8928aa1c58fd03f09cabbde9bcb4590 clone git github.com/docker/notary 089d8450d8928aa1c58fd03f09cabbde9bcb4590
clone git github.com/endophage/gotuf 2df1c8e0a7b7e10ae2113bf37aaa1bf1c1de8cc5 clone git github.com/endophage/gotuf 2df1c8e0a7b7e10ae2113bf37aaa1bf1c1de8cc5
clone git github.com/jfrazelle/go 6e461eb70cb4187b41a84e9a567d7137bdbe0f16 clone git github.com/jfrazelle/go v1.5.1-1
clone git github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c clone git github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
clone git github.com/opencontainers/runc 6c198ae2d065c37f44316e0de3df7f3b88950923 # libcontainer clone git github.com/opencontainers/runc 6c198ae2d065c37f44316e0de3df7f3b88950923 # libcontainer

View file

@ -0,0 +1,27 @@
Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -48,6 +48,13 @@ import (
// map[string]interface{}, for JSON objects // map[string]interface{}, for JSON objects
// nil for JSON null // nil for JSON null
// //
// To unmarshal a JSON array into a slice, Unmarshal resets the slice to nil
// and then appends each element to the slice.
//
// To unmarshal a JSON object into a map, Unmarshal replaces the map
// with an empty map and then adds key-value pairs from the object to
// the map.
//
// If a JSON value is not appropriate for a given target type, // If a JSON value is not appropriate for a given target type,
// or if a JSON number overflows the target type, Unmarshal // or if a JSON number overflows the target type, Unmarshal
// skips that field and completes the unmarshalling as best it can. // skips that field and completes the unmarshalling as best it can.
@ -90,8 +97,9 @@ type Unmarshaler interface {
// An UnmarshalTypeError describes a JSON value that was // An UnmarshalTypeError describes a JSON value that was
// not appropriate for a value of a specific Go type. // not appropriate for a value of a specific Go type.
type UnmarshalTypeError struct { type UnmarshalTypeError struct {
Value string // description of JSON value - "bool", "array", "number -5" Value string // description of JSON value - "bool", "array", "number -5"
Type reflect.Type // type of Go value it could not be assigned to Type reflect.Type // type of Go value it could not be assigned to
Offset int64 // error occurred after reading Offset bytes
} }
func (e *UnmarshalTypeError) Error() string { func (e *UnmarshalTypeError) Error() string {
@ -378,7 +386,7 @@ func (d *decodeState) array(v reflect.Value) {
return return
} }
if ut != nil { if ut != nil {
d.saveError(&UnmarshalTypeError{"array", v.Type()}) d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
d.off-- d.off--
d.next() d.next()
return return
@ -397,7 +405,7 @@ func (d *decodeState) array(v reflect.Value) {
// Otherwise it's invalid. // Otherwise it's invalid.
fallthrough fallthrough
default: default:
d.saveError(&UnmarshalTypeError{"array", v.Type()}) d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
d.off-- d.off--
d.next() d.next()
return return
@ -486,7 +494,7 @@ func (d *decodeState) object(v reflect.Value) {
return return
} }
if ut != nil { if ut != nil {
d.saveError(&UnmarshalTypeError{"object", v.Type()}) d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
d.off-- d.off--
d.next() // skip over { } in input d.next() // skip over { } in input
return return
@ -505,7 +513,7 @@ func (d *decodeState) object(v reflect.Value) {
// map must have string kind // map must have string kind
t := v.Type() t := v.Type()
if t.Key().Kind() != reflect.String { if t.Key().Kind() != reflect.String {
d.saveError(&UnmarshalTypeError{"object", v.Type()}) d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
d.off-- d.off--
d.next() // skip over { } in input d.next() // skip over { } in input
return return
@ -516,7 +524,7 @@ func (d *decodeState) object(v reflect.Value) {
case reflect.Struct: case reflect.Struct:
default: default:
d.saveError(&UnmarshalTypeError{"object", v.Type()}) d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
d.off-- d.off--
d.next() // skip over { } in input d.next() // skip over { } in input
return return
@ -600,7 +608,7 @@ func (d *decodeState) object(v reflect.Value) {
case string: case string:
d.literalStore([]byte(qv), subv, true) d.literalStore([]byte(qv), subv, true)
default: default:
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", item, v.Type())) d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type()))
} }
} else { } else {
d.value(subv) d.value(subv)
@ -647,7 +655,7 @@ func (d *decodeState) convertNumber(s string) (interface{}, error) {
} }
f, err := strconv.ParseFloat(s, 64) f, err := strconv.ParseFloat(s, 64)
if err != nil { if err != nil {
return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0)} return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)}
} }
return f, nil return f, nil
} }
@ -680,8 +688,9 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
if fromQuoted { if fromQuoted {
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
} else { } else {
d.saveError(&UnmarshalTypeError{"string", v.Type()}) d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
} }
return
} }
s, ok := unquoteBytes(item) s, ok := unquoteBytes(item)
if !ok { if !ok {
@ -714,7 +723,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
if fromQuoted { if fromQuoted {
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
} else { } else {
d.saveError(&UnmarshalTypeError{"bool", v.Type()}) d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)})
} }
case reflect.Bool: case reflect.Bool:
v.SetBool(value) v.SetBool(value)
@ -722,7 +731,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
if v.NumMethod() == 0 { if v.NumMethod() == 0 {
v.Set(reflect.ValueOf(value)) v.Set(reflect.ValueOf(value))
} else { } else {
d.saveError(&UnmarshalTypeError{"bool", v.Type()}) d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)})
} }
} }
@ -737,10 +746,10 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
} }
switch v.Kind() { switch v.Kind() {
default: default:
d.saveError(&UnmarshalTypeError{"string", v.Type()}) d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
case reflect.Slice: case reflect.Slice:
if v.Type() != byteSliceType { if v.Type().Elem().Kind() != reflect.Uint8 {
d.saveError(&UnmarshalTypeError{"string", v.Type()}) d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
break break
} }
b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
@ -756,7 +765,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
if v.NumMethod() == 0 { if v.NumMethod() == 0 {
v.Set(reflect.ValueOf(string(s))) v.Set(reflect.ValueOf(string(s)))
} else { } else {
d.saveError(&UnmarshalTypeError{"string", v.Type()}) d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
} }
} }
@ -778,7 +787,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
if fromQuoted { if fromQuoted {
d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
} else { } else {
d.error(&UnmarshalTypeError{"number", v.Type()}) d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
} }
case reflect.Interface: case reflect.Interface:
n, err := d.convertNumber(s) n, err := d.convertNumber(s)
@ -787,7 +796,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
break break
} }
if v.NumMethod() != 0 { if v.NumMethod() != 0 {
d.saveError(&UnmarshalTypeError{"number", v.Type()}) d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
break break
} }
v.Set(reflect.ValueOf(n)) v.Set(reflect.ValueOf(n))
@ -795,7 +804,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n, err := strconv.ParseInt(s, 10, 64) n, err := strconv.ParseInt(s, 10, 64)
if err != nil || v.OverflowInt(n) { if err != nil || v.OverflowInt(n) {
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()}) d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
break break
} }
v.SetInt(n) v.SetInt(n)
@ -803,7 +812,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n, err := strconv.ParseUint(s, 10, 64) n, err := strconv.ParseUint(s, 10, 64)
if err != nil || v.OverflowUint(n) { if err != nil || v.OverflowUint(n) {
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()}) d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
break break
} }
v.SetUint(n) v.SetUint(n)
@ -811,7 +820,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
case reflect.Float32, reflect.Float64: case reflect.Float32, reflect.Float64:
n, err := strconv.ParseFloat(s, v.Type().Bits()) n, err := strconv.ParseFloat(s, v.Type().Bits())
if err != nil || v.OverflowFloat(n) { if err != nil || v.OverflowFloat(n) {
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()}) d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
break break
} }
v.SetFloat(n) v.SetFloat(n)

View file

@ -7,7 +7,7 @@
// in the documentation for the Marshal and Unmarshal functions. // in the documentation for the Marshal and Unmarshal functions.
// //
// See "JSON and Go" for an introduction to this package: // See "JSON and Go" for an introduction to this package:
// http://golang.org/doc/articles/json_and_go.html // https://golang.org/doc/articles/json_and_go.html
package json package json
import ( import (
@ -79,8 +79,8 @@ import (
// //
// The "string" option signals that a field is stored as JSON inside a // The "string" option signals that a field is stored as JSON inside a
// JSON-encoded string. It applies only to fields of string, floating point, // JSON-encoded string. It applies only to fields of string, floating point,
// or integer types. This extra level of encoding is sometimes used when // integer, or boolean types. This extra level of encoding is sometimes used
// communicating with JavaScript programs: // when communicating with JavaScript programs:
// //
// Int64String int64 `json:",string"` // Int64String int64 `json:",string"`
// //
@ -113,8 +113,8 @@ import (
// a JSON tag of "-". // a JSON tag of "-".
// //
// Map values encode as JSON objects. // Map values encode as JSON objects.
// The map's key type must be string; the object keys are used directly // The map's key type must be string; the map keys are used as JSON object
// as map keys. // keys, subject to the UTF-8 coercion described for string values above.
// //
// Pointer values encode as the value pointed to. // Pointer values encode as the value pointed to.
// A nil pointer encodes as the null JSON object. // A nil pointer encodes as the null JSON object.
@ -287,8 +287,6 @@ func (e *encodeState) error(err error) {
panic(err) panic(err)
} }
var byteSliceType = reflect.TypeOf([]byte(nil))
func isEmptyValue(v reflect.Value) bool { func isEmptyValue(v reflect.Value) bool {
switch v.Kind() { switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String: case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
@ -1075,6 +1073,19 @@ func typeFields(t reflect.Type) []field {
ft = ft.Elem() ft = ft.Elem()
} }
// Only strings, floats, integers, and booleans can be quoted.
quoted := false
if opts.Contains("string") {
switch ft.Kind() {
case reflect.Bool,
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64,
reflect.String:
quoted = true
}
}
// Record found field and index sequence. // Record found field and index sequence.
if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
tagged := name != "" tagged := name != ""
@ -1087,7 +1098,7 @@ func typeFields(t reflect.Type) []field {
index: index, index: index,
typ: ft, typ: ft,
omitEmpty: opts.Contains("omitempty"), omitEmpty: opts.Contains("omitempty"),
quoted: opts.Contains("string"), quoted: quoted,
})) }))
if count[f.typ] > 1 { if count[f.typ] > 1 {
// If there were multiple instances, add a second, // If there were multiple instances, add a second,

View file

@ -26,7 +26,7 @@ const (
// The letters S and K are special because they map to 3 runes, not just 2: // The letters S and K are special because they map to 3 runes, not just 2:
// * S maps to s and to U+017F 'ſ' Latin small letter long s // * S maps to s and to U+017F 'ſ' Latin small letter long s
// * k maps to K and to U+212A '' Kelvin sign // * k maps to K and to U+212A '' Kelvin sign
// See http://play.golang.org/p/tTxjOc0OGo // See https://play.golang.org/p/tTxjOc0OGo
// //
// The returned function is specialized for matching against s and // The returned function is specialized for matching against s and
// should only be given s. It's not curried for performance reasons. // should only be given s. It's not curried for performance reasons.

View file

@ -38,8 +38,15 @@ func nextValue(data []byte, scan *scanner) (value, rest []byte, err error) {
scan.reset() scan.reset()
for i, c := range data { for i, c := range data {
v := scan.step(scan, int(c)) v := scan.step(scan, int(c))
if v >= scanEnd { if v >= scanEndObject {
switch v { switch v {
// probe the scanner with a space to determine whether we will
// get scanEnd on the next character. Otherwise, if the next character
// is not a space, scanEndTop allocates a needless error.
case scanEndObject, scanEndArray:
if scan.step(scan, ' ') == scanEnd {
return data[:i+1], data[i+1:], nil
}
case scanError: case scanError:
return nil, nil, scan.err return nil, nil, scan.err
case scanEnd: case scanEnd:

View file

@ -12,11 +12,15 @@ import (
// A Decoder reads and decodes JSON objects from an input stream. // A Decoder reads and decodes JSON objects from an input stream.
type Decoder struct { type Decoder struct {
r io.Reader r io.Reader
buf []byte buf []byte
d decodeState d decodeState
scan scanner scanp int // start of unread data in buf
err error scan scanner
err error
tokenState int
tokenStack []int
} }
// NewDecoder returns a new decoder that reads from r. // NewDecoder returns a new decoder that reads from r.
@ -41,20 +45,29 @@ func (dec *Decoder) Decode(v interface{}) error {
return dec.err return dec.err
} }
if err := dec.tokenPrepareForDecode(); err != nil {
return err
}
if !dec.tokenValueAllowed() {
return &SyntaxError{msg: "not at beginning of value"}
}
// Read whole value into buffer.
n, err := dec.readValue() n, err := dec.readValue()
if err != nil { if err != nil {
return err return err
} }
dec.d.init(dec.buf[dec.scanp : dec.scanp+n])
dec.scanp += n
// Don't save err from unmarshal into dec.err: // Don't save err from unmarshal into dec.err:
// the connection is still usable since we read a complete JSON // the connection is still usable since we read a complete JSON
// object from it before the error happened. // object from it before the error happened.
dec.d.init(dec.buf[0:n])
err = dec.d.unmarshal(v) err = dec.d.unmarshal(v)
// Slide rest of data down. // fixup token streaming state
rest := copy(dec.buf, dec.buf[n:]) dec.tokenValueEnd()
dec.buf = dec.buf[0:rest]
return err return err
} }
@ -62,7 +75,7 @@ func (dec *Decoder) Decode(v interface{}) error {
// Buffered returns a reader of the data remaining in the Decoder's // Buffered returns a reader of the data remaining in the Decoder's
// buffer. The reader is valid until the next call to Decode. // buffer. The reader is valid until the next call to Decode.
func (dec *Decoder) Buffered() io.Reader { func (dec *Decoder) Buffered() io.Reader {
return bytes.NewReader(dec.buf) return bytes.NewReader(dec.buf[dec.scanp:])
} }
// readValue reads a JSON value into dec.buf. // readValue reads a JSON value into dec.buf.
@ -70,7 +83,7 @@ func (dec *Decoder) Buffered() io.Reader {
func (dec *Decoder) readValue() (int, error) { func (dec *Decoder) readValue() (int, error) {
dec.scan.reset() dec.scan.reset()
scanp := 0 scanp := dec.scanp
var err error var err error
Input: Input:
for { for {
@ -111,20 +124,35 @@ Input:
return 0, err return 0, err
} }
// Make room to read more into the buffer. n := scanp - dec.scanp
const minRead = 512 err = dec.refill()
if cap(dec.buf)-len(dec.buf) < minRead { scanp = dec.scanp + n
newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead)
copy(newBuf, dec.buf)
dec.buf = newBuf
}
// Read. Delay error for next iteration (after scan).
var n int
n, err = dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)])
dec.buf = dec.buf[0 : len(dec.buf)+n]
} }
return scanp, nil return scanp - dec.scanp, nil
}
func (dec *Decoder) refill() error {
// Make room to read more into the buffer.
// First slide down data already consumed.
if dec.scanp > 0 {
n := copy(dec.buf, dec.buf[dec.scanp:])
dec.buf = dec.buf[:n]
dec.scanp = 0
}
// Grow buffer if not large enough.
const minRead = 512
if cap(dec.buf)-len(dec.buf) < minRead {
newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead)
copy(newBuf, dec.buf)
dec.buf = newBuf
}
// Read. Delay error for next iteration (after scan).
n, err := dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)])
dec.buf = dec.buf[0 : len(dec.buf)+n]
return err
} }
func nonSpace(b []byte) bool { func nonSpace(b []byte) bool {
@ -205,3 +233,255 @@ func (m *RawMessage) UnmarshalJSON(data []byte) error {
var _ Marshaler = (*RawMessage)(nil) var _ Marshaler = (*RawMessage)(nil)
var _ Unmarshaler = (*RawMessage)(nil) var _ Unmarshaler = (*RawMessage)(nil)
// A Token holds a value of one of these types:
//
// Delim, for the four JSON delimiters [ ] { }
// bool, for JSON booleans
// float64, for JSON numbers
// Number, for JSON numbers
// string, for JSON string literals
// nil, for JSON null
//
type Token interface{}
const (
tokenTopValue = iota
tokenArrayStart
tokenArrayValue
tokenArrayComma
tokenObjectStart
tokenObjectKey
tokenObjectColon
tokenObjectValue
tokenObjectComma
)
// advance tokenstate from a separator state to a value state
func (dec *Decoder) tokenPrepareForDecode() error {
// Note: Not calling peek before switch, to avoid
// putting peek into the standard Decode path.
// peek is only called when using the Token API.
switch dec.tokenState {
case tokenArrayComma:
c, err := dec.peek()
if err != nil {
return err
}
if c != ',' {
return &SyntaxError{"expected comma after array element", 0}
}
dec.scanp++
dec.tokenState = tokenArrayValue
case tokenObjectColon:
c, err := dec.peek()
if err != nil {
return err
}
if c != ':' {
return &SyntaxError{"expected colon after object key", 0}
}
dec.scanp++
dec.tokenState = tokenObjectValue
}
return nil
}
func (dec *Decoder) tokenValueAllowed() bool {
switch dec.tokenState {
case tokenTopValue, tokenArrayStart, tokenArrayValue, tokenObjectValue:
return true
}
return false
}
func (dec *Decoder) tokenValueEnd() {
switch dec.tokenState {
case tokenArrayStart, tokenArrayValue:
dec.tokenState = tokenArrayComma
case tokenObjectValue:
dec.tokenState = tokenObjectComma
}
}
// A Delim is a JSON array or object delimiter, one of [ ] { or }.
type Delim rune
func (d Delim) String() string {
return string(d)
}
// Token returns the next JSON token in the input stream.
// At the end of the input stream, Token returns nil, io.EOF.
//
// Token guarantees that the delimiters [ ] { } it returns are
// properly nested and matched: if Token encounters an unexpected
// delimiter in the input, it will return an error.
//
// The input stream consists of basic JSON values—bool, string,
// number, and null—along with delimiters [ ] { } of type Delim
// to mark the start and end of arrays and objects.
// Commas and colons are elided.
func (dec *Decoder) Token() (Token, error) {
for {
c, err := dec.peek()
if err != nil {
return nil, err
}
switch c {
case '[':
if !dec.tokenValueAllowed() {
return dec.tokenError(c)
}
dec.scanp++
dec.tokenStack = append(dec.tokenStack, dec.tokenState)
dec.tokenState = tokenArrayStart
return Delim('['), nil
case ']':
if dec.tokenState != tokenArrayStart && dec.tokenState != tokenArrayComma {
return dec.tokenError(c)
}
dec.scanp++
dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1]
dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1]
dec.tokenValueEnd()
return Delim(']'), nil
case '{':
if !dec.tokenValueAllowed() {
return dec.tokenError(c)
}
dec.scanp++
dec.tokenStack = append(dec.tokenStack, dec.tokenState)
dec.tokenState = tokenObjectStart
return Delim('{'), nil
case '}':
if dec.tokenState != tokenObjectStart && dec.tokenState != tokenObjectComma {
return dec.tokenError(c)
}
dec.scanp++
dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1]
dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1]
dec.tokenValueEnd()
return Delim('}'), nil
case ':':
if dec.tokenState != tokenObjectColon {
return dec.tokenError(c)
}
dec.scanp++
dec.tokenState = tokenObjectValue
continue
case ',':
if dec.tokenState == tokenArrayComma {
dec.scanp++
dec.tokenState = tokenArrayValue
continue
}
if dec.tokenState == tokenObjectComma {
dec.scanp++
dec.tokenState = tokenObjectKey
continue
}
return dec.tokenError(c)
case '"':
if dec.tokenState == tokenObjectStart || dec.tokenState == tokenObjectKey {
var x string
old := dec.tokenState
dec.tokenState = tokenTopValue
err := dec.Decode(&x)
dec.tokenState = old
if err != nil {
clearOffset(err)
return nil, err
}
dec.tokenState = tokenObjectColon
return x, nil
}
fallthrough
default:
if !dec.tokenValueAllowed() {
return dec.tokenError(c)
}
var x interface{}
if err := dec.Decode(&x); err != nil {
clearOffset(err)
return nil, err
}
return x, nil
}
}
}
func clearOffset(err error) {
if s, ok := err.(*SyntaxError); ok {
s.Offset = 0
}
}
func (dec *Decoder) tokenError(c byte) (Token, error) {
var context string
switch dec.tokenState {
case tokenTopValue:
context = " looking for beginning of value"
case tokenArrayStart, tokenArrayValue, tokenObjectValue:
context = " looking for beginning of value"
case tokenArrayComma:
context = " after array element"
case tokenObjectKey:
context = " looking for beginning of object key string"
case tokenObjectColon:
context = " after object key"
case tokenObjectComma:
context = " after object key:value pair"
}
return nil, &SyntaxError{"invalid character " + quoteChar(int(c)) + " " + context, 0}
}
// More reports whether there is another element in the
// current array or object being parsed.
func (dec *Decoder) More() bool {
c, err := dec.peek()
return err == nil && c != ']' && c != '}'
}
func (dec *Decoder) peek() (byte, error) {
var err error
for {
for i := dec.scanp; i < len(dec.buf); i++ {
c := dec.buf[i]
if isSpace(rune(c)) {
continue
}
dec.scanp = i
return c, nil
}
// buffer has been scanned, now report any error
if err != nil {
return 0, err
}
err = dec.refill()
}
}
/*
TODO
// EncodeToken writes the given JSON token to the stream.
// It returns an error if the delimiters [ ] { } are not properly used.
//
// EncodeToken does not call Flush, because usually it is part of
// a larger operation such as Encode, and those will call Flush when finished.
// Callers that create an Encoder and then invoke EncodeToken directly,
// without using Encode, need to call Flush when finished to ensure that
// the JSON is written to the underlying writer.
func (e *Encoder) EncodeToken(t Token) error {
...
}
*/