зеркало из https://github.com/microsoft/docker.git
Merge pull request #17619 from jfrazelle/canonical-update
rebased canonical/json off go 1.5.1
This commit is contained in:
Коммит
b95048758a
|
@ -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/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/opencontainers/runc 6c198ae2d065c37f44316e0de3df7f3b88950923 # libcontainer
|
||||
|
|
|
@ -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.
|
|
@ -48,6 +48,13 @@ import (
|
|||
// map[string]interface{}, for JSON objects
|
||||
// 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,
|
||||
// or if a JSON number overflows the target type, Unmarshal
|
||||
// skips that field and completes the unmarshalling as best it can.
|
||||
|
@ -92,6 +99,7 @@ type Unmarshaler interface {
|
|||
type UnmarshalTypeError struct {
|
||||
Value string // description of JSON value - "bool", "array", "number -5"
|
||||
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 {
|
||||
|
@ -378,7 +386,7 @@ func (d *decodeState) array(v reflect.Value) {
|
|||
return
|
||||
}
|
||||
if ut != nil {
|
||||
d.saveError(&UnmarshalTypeError{"array", v.Type()})
|
||||
d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
|
||||
d.off--
|
||||
d.next()
|
||||
return
|
||||
|
@ -397,7 +405,7 @@ func (d *decodeState) array(v reflect.Value) {
|
|||
// Otherwise it's invalid.
|
||||
fallthrough
|
||||
default:
|
||||
d.saveError(&UnmarshalTypeError{"array", v.Type()})
|
||||
d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
|
||||
d.off--
|
||||
d.next()
|
||||
return
|
||||
|
@ -486,7 +494,7 @@ func (d *decodeState) object(v reflect.Value) {
|
|||
return
|
||||
}
|
||||
if ut != nil {
|
||||
d.saveError(&UnmarshalTypeError{"object", v.Type()})
|
||||
d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
|
||||
d.off--
|
||||
d.next() // skip over { } in input
|
||||
return
|
||||
|
@ -505,7 +513,7 @@ func (d *decodeState) object(v reflect.Value) {
|
|||
// map must have string kind
|
||||
t := v.Type()
|
||||
if t.Key().Kind() != reflect.String {
|
||||
d.saveError(&UnmarshalTypeError{"object", v.Type()})
|
||||
d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
|
||||
d.off--
|
||||
d.next() // skip over { } in input
|
||||
return
|
||||
|
@ -516,7 +524,7 @@ func (d *decodeState) object(v reflect.Value) {
|
|||
case reflect.Struct:
|
||||
|
||||
default:
|
||||
d.saveError(&UnmarshalTypeError{"object", v.Type()})
|
||||
d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
|
||||
d.off--
|
||||
d.next() // skip over { } in input
|
||||
return
|
||||
|
@ -600,7 +608,7 @@ func (d *decodeState) object(v reflect.Value) {
|
|||
case string:
|
||||
d.literalStore([]byte(qv), subv, true)
|
||||
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 {
|
||||
d.value(subv)
|
||||
|
@ -647,7 +655,7 @@ func (d *decodeState) convertNumber(s string) (interface{}, error) {
|
|||
}
|
||||
f, err := strconv.ParseFloat(s, 64)
|
||||
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
|
||||
}
|
||||
|
@ -680,8 +688,9 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
|||
if fromQuoted {
|
||||
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
||||
} else {
|
||||
d.saveError(&UnmarshalTypeError{"string", v.Type()})
|
||||
d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
|
||||
}
|
||||
return
|
||||
}
|
||||
s, ok := unquoteBytes(item)
|
||||
if !ok {
|
||||
|
@ -714,7 +723,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
|||
if fromQuoted {
|
||||
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
||||
} else {
|
||||
d.saveError(&UnmarshalTypeError{"bool", v.Type()})
|
||||
d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)})
|
||||
}
|
||||
case reflect.Bool:
|
||||
v.SetBool(value)
|
||||
|
@ -722,7 +731,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
|||
if v.NumMethod() == 0 {
|
||||
v.Set(reflect.ValueOf(value))
|
||||
} 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() {
|
||||
default:
|
||||
d.saveError(&UnmarshalTypeError{"string", v.Type()})
|
||||
d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
|
||||
case reflect.Slice:
|
||||
if v.Type() != byteSliceType {
|
||||
d.saveError(&UnmarshalTypeError{"string", v.Type()})
|
||||
if v.Type().Elem().Kind() != reflect.Uint8 {
|
||||
d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
|
||||
break
|
||||
}
|
||||
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 {
|
||||
v.Set(reflect.ValueOf(string(s)))
|
||||
} 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 {
|
||||
d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
||||
} else {
|
||||
d.error(&UnmarshalTypeError{"number", v.Type()})
|
||||
d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
|
||||
}
|
||||
case reflect.Interface:
|
||||
n, err := d.convertNumber(s)
|
||||
|
@ -787,7 +796,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
|||
break
|
||||
}
|
||||
if v.NumMethod() != 0 {
|
||||
d.saveError(&UnmarshalTypeError{"number", v.Type()})
|
||||
d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
|
||||
break
|
||||
}
|
||||
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:
|
||||
n, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil || v.OverflowInt(n) {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
|
||||
break
|
||||
}
|
||||
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:
|
||||
n, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil || v.OverflowUint(n) {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
|
||||
break
|
||||
}
|
||||
v.SetUint(n)
|
||||
|
@ -811,7 +820,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
|||
case reflect.Float32, reflect.Float64:
|
||||
n, err := strconv.ParseFloat(s, v.Type().Bits())
|
||||
if err != nil || v.OverflowFloat(n) {
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
|
||||
d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
|
||||
break
|
||||
}
|
||||
v.SetFloat(n)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
// in the documentation for the Marshal and Unmarshal functions.
|
||||
//
|
||||
// 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
|
||||
|
||||
import (
|
||||
|
@ -79,8 +79,8 @@ import (
|
|||
//
|
||||
// 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,
|
||||
// or integer types. This extra level of encoding is sometimes used when
|
||||
// communicating with JavaScript programs:
|
||||
// integer, or boolean types. This extra level of encoding is sometimes used
|
||||
// when communicating with JavaScript programs:
|
||||
//
|
||||
// Int64String int64 `json:",string"`
|
||||
//
|
||||
|
@ -113,8 +113,8 @@ import (
|
|||
// a JSON tag of "-".
|
||||
//
|
||||
// Map values encode as JSON objects.
|
||||
// The map's key type must be string; the object keys are used directly
|
||||
// as map keys.
|
||||
// The map's key type must be string; the map keys are used as JSON object
|
||||
// keys, subject to the UTF-8 coercion described for string values above.
|
||||
//
|
||||
// Pointer values encode as the value pointed to.
|
||||
// A nil pointer encodes as the null JSON object.
|
||||
|
@ -287,8 +287,6 @@ func (e *encodeState) error(err error) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
var byteSliceType = reflect.TypeOf([]byte(nil))
|
||||
|
||||
func isEmptyValue(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
|
@ -1075,6 +1073,19 @@ func typeFields(t reflect.Type) []field {
|
|||
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.
|
||||
if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
|
||||
tagged := name != ""
|
||||
|
@ -1087,7 +1098,7 @@ func typeFields(t reflect.Type) []field {
|
|||
index: index,
|
||||
typ: ft,
|
||||
omitEmpty: opts.Contains("omitempty"),
|
||||
quoted: opts.Contains("string"),
|
||||
quoted: quoted,
|
||||
}))
|
||||
if count[f.typ] > 1 {
|
||||
// If there were multiple instances, add a second,
|
||||
|
|
|
@ -26,7 +26,7 @@ const (
|
|||
// 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
|
||||
// * k maps to K and to U+212A 'K' 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
|
||||
// should only be given s. It's not curried for performance reasons.
|
||||
|
|
|
@ -38,8 +38,15 @@ func nextValue(data []byte, scan *scanner) (value, rest []byte, err error) {
|
|||
scan.reset()
|
||||
for i, c := range data {
|
||||
v := scan.step(scan, int(c))
|
||||
if v >= scanEnd {
|
||||
if v >= scanEndObject {
|
||||
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:
|
||||
return nil, nil, scan.err
|
||||
case scanEnd:
|
||||
|
|
|
@ -15,8 +15,12 @@ type Decoder struct {
|
|||
r io.Reader
|
||||
buf []byte
|
||||
d decodeState
|
||||
scanp int // start of unread data in buf
|
||||
scan scanner
|
||||
err error
|
||||
|
||||
tokenState int
|
||||
tokenStack []int
|
||||
}
|
||||
|
||||
// NewDecoder returns a new decoder that reads from r.
|
||||
|
@ -41,20 +45,29 @@ func (dec *Decoder) Decode(v interface{}) error {
|
|||
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()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dec.d.init(dec.buf[dec.scanp : dec.scanp+n])
|
||||
dec.scanp += n
|
||||
|
||||
// Don't save err from unmarshal into dec.err:
|
||||
// the connection is still usable since we read a complete JSON
|
||||
// object from it before the error happened.
|
||||
dec.d.init(dec.buf[0:n])
|
||||
err = dec.d.unmarshal(v)
|
||||
|
||||
// Slide rest of data down.
|
||||
rest := copy(dec.buf, dec.buf[n:])
|
||||
dec.buf = dec.buf[0:rest]
|
||||
// fixup token streaming state
|
||||
dec.tokenValueEnd()
|
||||
|
||||
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
|
||||
// buffer. The reader is valid until the next call to Decode.
|
||||
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.
|
||||
|
@ -70,7 +83,7 @@ func (dec *Decoder) Buffered() io.Reader {
|
|||
func (dec *Decoder) readValue() (int, error) {
|
||||
dec.scan.reset()
|
||||
|
||||
scanp := 0
|
||||
scanp := dec.scanp
|
||||
var err error
|
||||
Input:
|
||||
for {
|
||||
|
@ -111,7 +124,23 @@ Input:
|
|||
return 0, err
|
||||
}
|
||||
|
||||
n := scanp - dec.scanp
|
||||
err = dec.refill()
|
||||
scanp = dec.scanp + n
|
||||
}
|
||||
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)
|
||||
|
@ -120,11 +149,10 @@ Input:
|
|||
}
|
||||
|
||||
// Read. Delay error for next iteration (after scan).
|
||||
var n int
|
||||
n, err = dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)])
|
||||
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 err
|
||||
}
|
||||
|
||||
func nonSpace(b []byte) bool {
|
||||
|
@ -205,3 +233,255 @@ func (m *RawMessage) UnmarshalJSON(data []byte) error {
|
|||
|
||||
var _ Marshaler = (*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 {
|
||||
...
|
||||
}
|
||||
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче