diff options
Diffstat (limited to 'vendor/github.com/yaegashi/msgraph.go/jsonx')
-rw-r--r-- | vendor/github.com/yaegashi/msgraph.go/jsonx/README.md | 55 | ||||
-rw-r--r-- | vendor/github.com/yaegashi/msgraph.go/jsonx/decode.go | 1376 | ||||
-rw-r--r-- | vendor/github.com/yaegashi/msgraph.go/jsonx/encode.go | 1317 | ||||
-rw-r--r-- | vendor/github.com/yaegashi/msgraph.go/jsonx/fold.go | 143 | ||||
-rw-r--r-- | vendor/github.com/yaegashi/msgraph.go/jsonx/indent.go | 141 | ||||
-rw-r--r-- | vendor/github.com/yaegashi/msgraph.go/jsonx/scanner.go | 573 | ||||
-rw-r--r-- | vendor/github.com/yaegashi/msgraph.go/jsonx/stream.go | 507 | ||||
-rw-r--r-- | vendor/github.com/yaegashi/msgraph.go/jsonx/tables.go | 218 | ||||
-rw-r--r-- | vendor/github.com/yaegashi/msgraph.go/jsonx/tags.go | 44 |
9 files changed, 0 insertions, 4374 deletions
diff --git a/vendor/github.com/yaegashi/msgraph.go/jsonx/README.md b/vendor/github.com/yaegashi/msgraph.go/jsonx/README.md deleted file mode 100644 index 575ce781..00000000 --- a/vendor/github.com/yaegashi/msgraph.go/jsonx/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# jsonx - -It's modified version of [encoding/json](https://golang.org/pkg/encoding/json/) -which enables extra map field (with `jsonx:"true"` tag) to catch all other fields not declared in the struct. - -`jsonx` is a code name for internal use -and not related to [JSONx](https://tools.ietf.org/html/draft-rsalz-jsonx-00). - -Example ([Run on playgroud](https://play.golang.org/p/TZi0JeHYG69)) -```go -package main - -import ( - "encoding/json" - "fmt" - - "github.com/yaegashi/msgraph.go/jsonx" -) - -type Extra struct { - X string - Y int - Extra map[string]interface{} `json:"-" jsonx:"true"` -} - -func main() { - var x1, x2 Extra - b := []byte(`{"X":"123","Y":123,"A":"123","B":123}`) - fmt.Printf("\nUnmarshal input: %s\n", string(b)) - json.Unmarshal(b, &x1) - fmt.Printf(" json.Unmarshal: %#v\n", x1) - jsonx.Unmarshal(b, &x2) - fmt.Printf("jsonx.Unmarshal: %#v\n", x2) - - x := Extra{X: "456", Y: 456, Extra: map[string]interface{}{"A": "456", "B": 456}} - fmt.Printf("\nMarshal input: %#v\n", x) - b1, _ := json.Marshal(x) - fmt.Printf(" json.Marshal: %s\n", string(b1)) - b2, _ := jsonx.Marshal(x) - fmt.Printf("jsonx.Marshal: %s\n", string(b2)) -} -``` - -Result - -```text -Unmarshal input: {"X":"123","Y":123,"A":"123","B":123} - json.Unmarshal: main.Extra{X:"123", Y:123, Extra:map[string]interface {}(nil)} -jsonx.Unmarshal: main.Extra{X:"123", Y:123, Extra:map[string]interface {}{"A":"123", "B":123}} - -Marshal input: main.Extra{X:"456", Y:456, Extra:map[string]interface {}{"A":"456", "B":456}} - json.Marshal: {"X":"456","Y":456} -jsonx.Marshal: {"X":"456","Y":456,"A":"456","B":456} -``` - diff --git a/vendor/github.com/yaegashi/msgraph.go/jsonx/decode.go b/vendor/github.com/yaegashi/msgraph.go/jsonx/decode.go deleted file mode 100644 index 081d7ad0..00000000 --- a/vendor/github.com/yaegashi/msgraph.go/jsonx/decode.go +++ /dev/null @@ -1,1376 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Represents JSON data structure using native Go types: booleans, floats, -// strings, arrays, and maps. - -package jsonx - -import ( - "encoding" - "encoding/base64" - "fmt" - "reflect" - "strconv" - "strings" - "unicode" - "unicode/utf16" - "unicode/utf8" -) - -// Unmarshal parses the JSON-encoded data and stores the result -// in the value pointed to by v. If v is nil or not a pointer, -// Unmarshal returns an InvalidUnmarshalError. -// -// Unmarshal uses the inverse of the encodings that -// Marshal uses, allocating maps, slices, and pointers as necessary, -// with the following additional rules: -// -// To unmarshal JSON into a pointer, Unmarshal first handles the case of -// the JSON being the JSON literal null. In that case, Unmarshal sets -// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into -// the value pointed at by the pointer. If the pointer is nil, Unmarshal -// allocates a new value for it to point to. -// -// To unmarshal JSON into a value implementing the Unmarshaler interface, -// Unmarshal calls that value's UnmarshalJSON method, including -// when the input is a JSON null. -// Otherwise, if the value implements encoding.TextUnmarshaler -// and the input is a JSON quoted string, Unmarshal calls that value's -// UnmarshalText method with the unquoted form of the string. -// -// To unmarshal JSON into a struct, Unmarshal matches incoming object -// keys to the keys used by Marshal (either the struct field name or its tag), -// preferring an exact match but also accepting a case-insensitive match. By -// default, object keys which don't have a corresponding struct field are -// ignored (see Decoder.DisallowUnknownFields for an alternative). -// -// To unmarshal JSON into an interface value, -// Unmarshal stores one of these in the interface value: -// -// bool, for JSON booleans -// float64, for JSON numbers -// string, for JSON strings -// []interface{}, for JSON arrays -// map[string]interface{}, for JSON objects -// nil for JSON null -// -// To unmarshal a JSON array into a slice, Unmarshal resets the slice length -// to zero and then appends each element to the slice. -// As a special case, to unmarshal an empty JSON array into a slice, -// Unmarshal replaces the slice with a new empty slice. -// -// To unmarshal a JSON array into a Go array, Unmarshal decodes -// JSON array elements into corresponding Go array elements. -// If the Go array is smaller than the JSON array, -// the additional JSON array elements are discarded. -// If the JSON array is smaller than the Go array, -// the additional Go array elements are set to zero values. -// -// To unmarshal a JSON object into a map, Unmarshal first establishes a map to -// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal -// reuses the existing map, keeping existing entries. Unmarshal then stores -// key-value pairs from the JSON object into the map. The map's key type must -// either be a string, an integer, or implement encoding.TextUnmarshaler. -// -// 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 unmarshaling as best it can. -// If no more serious errors are encountered, Unmarshal returns -// an UnmarshalTypeError describing the earliest such error. In any -// case, it's not guaranteed that all the remaining fields following -// the problematic one will be unmarshaled into the target object. -// -// The JSON null value unmarshals into an interface, map, pointer, or slice -// by setting that Go value to nil. Because null is often used in JSON to mean -// ``not present,'' unmarshaling a JSON null into any other Go type has no effect -// on the value and produces no error. -// -// When unmarshaling quoted strings, invalid UTF-8 or -// invalid UTF-16 surrogate pairs are not treated as an error. -// Instead, they are replaced by the Unicode replacement -// character U+FFFD. -// -func Unmarshal(data []byte, v interface{}) error { - // Check for well-formedness. - // Avoids filling out half a data structure - // before discovering a JSON syntax error. - var d decodeState - err := checkValid(data, &d.scan) - if err != nil { - return err - } - - d.init(data) - return d.unmarshal(v) -} - -// Unmarshaler is the interface implemented by types -// that can unmarshal a JSON description of themselves. -// The input can be assumed to be a valid encoding of -// a JSON value. UnmarshalJSON must copy the JSON data -// if it wishes to retain the data after returning. -// -// By convention, to approximate the behavior of Unmarshal itself, -// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op. -type Unmarshaler interface { - UnmarshalJSON([]byte) error -} - -// An UnmarshalTypeError describes a JSON value that was -// not appropriate for a value of a specific Go type. -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 - Struct string // name of the struct type containing the field - Field string // the full path from root node to the field -} - -func (e *UnmarshalTypeError) Error() string { - if e.Struct != "" || e.Field != "" { - return "json: cannot unmarshal " + e.Value + " into Go struct field " + e.Struct + "." + e.Field + " of type " + e.Type.String() - } - return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() -} - -// An UnmarshalFieldError describes a JSON object key that -// led to an unexported (and therefore unwritable) struct field. -// -// Deprecated: No longer used; kept for compatibility. -type UnmarshalFieldError struct { - Key string - Type reflect.Type - Field reflect.StructField -} - -func (e *UnmarshalFieldError) Error() string { - return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() -} - -// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. -// (The argument to Unmarshal must be a non-nil pointer.) -type InvalidUnmarshalError struct { - Type reflect.Type -} - -func (e *InvalidUnmarshalError) Error() string { - if e.Type == nil { - return "json: Unmarshal(nil)" - } - - if e.Type.Kind() != reflect.Ptr { - return "json: Unmarshal(non-pointer " + e.Type.String() + ")" - } - return "json: Unmarshal(nil " + e.Type.String() + ")" -} - -func (d *decodeState) unmarshal(v interface{}) error { - rv := reflect.ValueOf(v) - if rv.Kind() != reflect.Ptr || rv.IsNil() { - return &InvalidUnmarshalError{reflect.TypeOf(v)} - } - - d.scan.reset() - d.scanWhile(scanSkipSpace) - // We decode rv not rv.Elem because the Unmarshaler interface - // test must be applied at the top level of the value. - err := d.value(rv) - if err != nil { - return d.addErrorContext(err) - } - return d.savedError -} - -// A Number represents a JSON number literal. -type Number string - -// String returns the literal text of the number. -func (n Number) String() string { return string(n) } - -// Float64 returns the number as a float64. -func (n Number) Float64() (float64, error) { - return strconv.ParseFloat(string(n), 64) -} - -// Int64 returns the number as an int64. -func (n Number) Int64() (int64, error) { - return strconv.ParseInt(string(n), 10, 64) -} - -// isValidNumber reports whether s is a valid JSON number literal. -func isValidNumber(s string) bool { - // This function implements the JSON numbers grammar. - // See https://tools.ietf.org/html/rfc7159#section-6 - // and https://json.org/number.gif - - if s == "" { - return false - } - - // Optional - - if s[0] == '-' { - s = s[1:] - if s == "" { - return false - } - } - - // Digits - switch { - default: - return false - - case s[0] == '0': - s = s[1:] - - case '1' <= s[0] && s[0] <= '9': - s = s[1:] - for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { - s = s[1:] - } - } - - // . followed by 1 or more digits. - if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' { - s = s[2:] - for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { - s = s[1:] - } - } - - // e or E followed by an optional - or + and - // 1 or more digits. - if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') { - s = s[1:] - if s[0] == '+' || s[0] == '-' { - s = s[1:] - if s == "" { - return false - } - } - for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { - s = s[1:] - } - } - - // Make sure we are at the end. - return s == "" -} - -// decodeState represents the state while decoding a JSON value. -type decodeState struct { - data []byte - off int // next read offset in data - opcode int // last read result - scan scanner - errorContext struct { // provides context for type errors - Struct reflect.Type - FieldStack []string - } - savedError error - useNumber bool - disallowUnknownFields bool -} - -// readIndex returns the position of the last byte read. -func (d *decodeState) readIndex() int { - return d.off - 1 -} - -// phasePanicMsg is used as a panic message when we end up with something that -// shouldn't happen. It can indicate a bug in the JSON decoder, or that -// something is editing the data slice while the decoder executes. -const phasePanicMsg = "JSON decoder out of sync - data changing underfoot?" - -func (d *decodeState) init(data []byte) *decodeState { - d.data = data - d.off = 0 - d.savedError = nil - d.errorContext.Struct = nil - - // Reuse the allocated space for the FieldStack slice. - d.errorContext.FieldStack = d.errorContext.FieldStack[:0] - return d -} - -// saveError saves the first err it is called with, -// for reporting at the end of the unmarshal. -func (d *decodeState) saveError(err error) { - if d.savedError == nil { - d.savedError = d.addErrorContext(err) - } -} - -// addErrorContext returns a new error enhanced with information from d.errorContext -func (d *decodeState) addErrorContext(err error) error { - if d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0 { - switch err := err.(type) { - case *UnmarshalTypeError: - err.Struct = d.errorContext.Struct.Name() - err.Field = strings.Join(d.errorContext.FieldStack, ".") - return err - } - } - return err -} - -// skip scans to the end of what was started. -func (d *decodeState) skip() { - s, data, i := &d.scan, d.data, d.off - depth := len(s.parseState) - for { - op := s.step(s, data[i]) - i++ - if len(s.parseState) < depth { - d.off = i - d.opcode = op - return - } - } -} - -// scanNext processes the byte at d.data[d.off]. -func (d *decodeState) scanNext() { - if d.off < len(d.data) { - d.opcode = d.scan.step(&d.scan, d.data[d.off]) - d.off++ - } else { - d.opcode = d.scan.eof() - d.off = len(d.data) + 1 // mark processed EOF with len+1 - } -} - -// scanWhile processes bytes in d.data[d.off:] until it -// receives a scan code not equal to op. -func (d *decodeState) scanWhile(op int) { - s, data, i := &d.scan, d.data, d.off - for i < len(data) { - newOp := s.step(s, data[i]) - i++ - if newOp != op { - d.opcode = newOp - d.off = i - return - } - } - - d.off = len(data) + 1 // mark processed EOF with len+1 - d.opcode = d.scan.eof() -} - -// rescanLiteral is similar to scanWhile(scanContinue), but it specialises the -// common case where we're decoding a literal. The decoder scans the input -// twice, once for syntax errors and to check the length of the value, and the -// second to perform the decoding. -// -// Only in the second step do we use decodeState to tokenize literals, so we -// know there aren't any syntax errors. We can take advantage of that knowledge, -// and scan a literal's bytes much more quickly. -func (d *decodeState) rescanLiteral() { - data, i := d.data, d.off -Switch: - switch data[i-1] { - case '"': // string - for ; i < len(data); i++ { - switch data[i] { - case '\\': - i++ // escaped char - case '"': - i++ // tokenize the closing quote too - break Switch - } - } - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': // number - for ; i < len(data); i++ { - switch data[i] { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '.', 'e', 'E', '+', '-': - default: - break Switch - } - } - case 't': // true - i += len("rue") - case 'f': // false - i += len("alse") - case 'n': // null - i += len("ull") - } - if i < len(data) { - d.opcode = stateEndValue(&d.scan, data[i]) - } else { - d.opcode = scanEnd - } - d.off = i + 1 -} - -// value consumes a JSON value from d.data[d.off-1:], decoding into v, and -// reads the following byte ahead. If v is invalid, the value is discarded. -// The first byte of the value has been read already. -func (d *decodeState) value(v reflect.Value) error { - switch d.opcode { - default: - panic(phasePanicMsg) - - case scanBeginArray: - if v.IsValid() { - if err := d.array(v); err != nil { - return err - } - } else { - d.skip() - } - d.scanNext() - - case scanBeginObject: - if v.IsValid() { - if err := d.object(v); err != nil { - return err - } - } else { - d.skip() - } - d.scanNext() - - case scanBeginLiteral: - // All bytes inside literal return scanContinue op code. - start := d.readIndex() - d.rescanLiteral() - - if v.IsValid() { - if err := d.literalStore(d.data[start:d.readIndex()], v, false); err != nil { - return err - } - } - } - return nil -} - -type unquotedValue struct{} - -// valueQuoted is like value but decodes a -// quoted string literal or literal null into an interface value. -// If it finds anything other than a quoted string literal or null, -// valueQuoted returns unquotedValue{}. -func (d *decodeState) valueQuoted() interface{} { - switch d.opcode { - default: - panic(phasePanicMsg) - - case scanBeginArray, scanBeginObject: - d.skip() - d.scanNext() - - case scanBeginLiteral: - v := d.literalInterface() - switch v.(type) { - case nil, string: - return v - } - } - return unquotedValue{} -} - -// indirect walks down v allocating pointers as needed, -// until it gets to a non-pointer. -// if it encounters an Unmarshaler, indirect stops and returns that. -// if decodingNull is true, indirect stops at the last pointer so it can be set to nil. -func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { - // Issue #24153 indicates that it is generally not a guaranteed property - // that you may round-trip a reflect.Value by calling Value.Addr().Elem() - // and expect the value to still be settable for values derived from - // unexported embedded struct fields. - // - // The logic below effectively does this when it first addresses the value - // (to satisfy possible pointer methods) and continues to dereference - // subsequent pointers as necessary. - // - // After the first round-trip, we set v back to the original value to - // preserve the original RW flags contained in reflect.Value. - v0 := v - haveAddr := false - - // If v is a named type and is addressable, - // start with its address, so that if the type has pointer methods, - // we find them. - if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { - haveAddr = true - v = v.Addr() - } - for { - // Load value from interface, but only if the result will be - // usefully addressable. - if v.Kind() == reflect.Interface && !v.IsNil() { - e := v.Elem() - if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { - haveAddr = false - v = e - continue - } - } - - if v.Kind() != reflect.Ptr { - break - } - - if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() { - break - } - - // Prevent infinite loop if v is an interface pointing to its own address: - // var v interface{} - // v = &v - if v.Elem().Kind() == reflect.Interface && v.Elem().Elem() == v { - v = v.Elem() - break - } - if v.IsNil() { - v.Set(reflect.New(v.Type().Elem())) - } - if v.Type().NumMethod() > 0 && v.CanInterface() { - if u, ok := v.Interface().(Unmarshaler); ok { - return u, nil, reflect.Value{} - } - if !decodingNull { - if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { - return nil, u, reflect.Value{} - } - } - } - - if haveAddr { - v = v0 // restore original value after round-trip Value.Addr().Elem() - haveAddr = false - } else { - v = v.Elem() - } - } - return nil, nil, v -} - -// array consumes an array from d.data[d.off-1:], decoding into v. -// The first byte of the array ('[') has been read already. -func (d *decodeState) array(v reflect.Value) error { - // Check for unmarshaler. - u, ut, pv := indirect(v, false) - if u != nil { - start := d.readIndex() - d.skip() - return u.UnmarshalJSON(d.data[start:d.off]) - } - if ut != nil { - d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) - d.skip() - return nil - } - v = pv - - // Check type of target. - switch v.Kind() { - case reflect.Interface: - if v.NumMethod() == 0 { - // Decoding into nil interface? Switch to non-reflect code. - ai := d.arrayInterface() - v.Set(reflect.ValueOf(ai)) - return nil - } - // Otherwise it's invalid. - fallthrough - default: - d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) - d.skip() - return nil - case reflect.Array, reflect.Slice: - break - } - - i := 0 - for { - // Look ahead for ] - can only happen on first iteration. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndArray { - break - } - - // Get element of array, growing if necessary. - if v.Kind() == reflect.Slice { - // Grow slice if necessary - if i >= v.Cap() { - newcap := v.Cap() + v.Cap()/2 - if newcap < 4 { - newcap = 4 - } - newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) - reflect.Copy(newv, v) - v.Set(newv) - } - if i >= v.Len() { - v.SetLen(i + 1) - } - } - - if i < v.Len() { - // Decode into element. - if err := d.value(v.Index(i)); err != nil { - return err - } - } else { - // Ran out of fixed array: skip. - if err := d.value(reflect.Value{}); err != nil { - return err - } - } - i++ - - // Next token must be , or ]. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode == scanEndArray { - break - } - if d.opcode != scanArrayValue { - panic(phasePanicMsg) - } - } - - if i < v.Len() { - if v.Kind() == reflect.Array { - // Array. Zero the rest. - z := reflect.Zero(v.Type().Elem()) - for ; i < v.Len(); i++ { - v.Index(i).Set(z) - } - } else { - v.SetLen(i) - } - } - if i == 0 && v.Kind() == reflect.Slice { - v.Set(reflect.MakeSlice(v.Type(), 0, 0)) - } - return nil -} - -var nullLiteral = []byte("null") -var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() - -// object consumes an object from d.data[d.off-1:], decoding into v. -// The first byte ('{') of the object has been read already. -func (d *decodeState) object(v reflect.Value) error { - // Check for unmarshaler. - u, ut, pv := indirect(v, false) - if u != nil { - start := d.readIndex() - d.skip() - return u.UnmarshalJSON(d.data[start:d.off]) - } - if ut != nil { - d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)}) - d.skip() - return nil - } - v = pv - t := v.Type() - - // Decoding into nil interface? Switch to non-reflect code. - if v.Kind() == reflect.Interface && v.NumMethod() == 0 { - oi := d.objectInterface() - v.Set(reflect.ValueOf(oi)) - return nil - } - - var fields structFields - - // Check type of target: - // struct or - // map[T1]T2 where T1 is string, an integer type, - // or an encoding.TextUnmarshaler - switch v.Kind() { - case reflect.Map: - // Map key must either have string kind, have an integer kind, - // or be an encoding.TextUnmarshaler. - switch t.Key().Kind() { - case reflect.String, - reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - default: - if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { - d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) - d.skip() - return nil - } - } - if v.IsNil() { - v.Set(reflect.MakeMap(t)) - } - case reflect.Struct: - fields = cachedTypeFields(t) - // ok - default: - d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) - d.skip() - return nil - } - - var mapElem, extraMapElem reflect.Value - origErrorContext := d.errorContext - - for { - // Read opening " of string key or closing }. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndObject { - // closing } - can only happen on first iteration. - break - } - if d.opcode != scanBeginLiteral { - panic(phasePanicMsg) - } - - // Read key. - start := d.readIndex() - d.rescanLiteral() - item := d.data[start:d.readIndex()] - key, ok := unquoteBytes(item) - if !ok { - panic(phasePanicMsg) - } - - // Figure out field corresponding to key. - var subv, mapv reflect.Value - destring := false // whether the value is wrapped in a string to be decoded first - - if v.Kind() == reflect.Map { - elemType := t.Elem() - if !mapElem.IsValid() { - mapElem = reflect.New(elemType).Elem() - } else { - mapElem.Set(reflect.Zero(elemType)) - } - subv = mapElem - mapv = v - } else { - var f, extraf *field - if i, ok := fields.nameIndex[string(key)]; ok { - // Found an exact name match. - f = &fields.list[i] - } else { - // Fall back to the expensive case-insensitive - // linear search. - for i := range fields.list { - ff := &fields.list[i] - if ff.equalFold(ff.nameBytes, key) { - f = ff - break - } - if ff.extra && extraf == nil { - extraf = ff - } - } - } - if f == nil { - f = extraf - } - if f != nil { - subv = v - destring = f.quoted - for _, i := range f.index { - if subv.Kind() == reflect.Ptr { - if subv.IsNil() { - // If a struct embeds a pointer to an unexported type, - // it is not possible to set a newly allocated value - // since the field is unexported. - // - // See https://golang.org/issue/21357 - if !subv.CanSet() { - d.saveError(fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v", subv.Type().Elem())) - // Invalidate subv to ensure d.value(subv) skips over - // the JSON value without assigning it to subv. - subv = reflect.Value{} - destring = false - break - } - subv.Set(reflect.New(subv.Type().Elem())) - } - subv = subv.Elem() - } - subv = subv.Field(i) - } - if f == extraf { - // subv is extra map - mapv = subv - if mapv.IsNil() { - mapv.Set(reflect.MakeMap(mapv.Type())) - } - elemType := mapv.Type().Elem() - if !extraMapElem.IsValid() { - extraMapElem = reflect.New(elemType).Elem() - } else { - extraMapElem.Set(reflect.Zero(elemType)) - } - subv = extraMapElem - } - d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name) - d.errorContext.Struct = t - } else if d.disallowUnknownFields { - d.saveError(fmt.Errorf("json: unknown field %q", key)) - } - } - - // Read : before value. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode != scanObjectKey { - panic(phasePanicMsg) - } - d.scanWhile(scanSkipSpace) - - if destring { - switch qv := d.valueQuoted().(type) { - case nil: - if err := d.literalStore(nullLiteral, subv, false); err != nil { - return err - } - case string: - if err := d.literalStore([]byte(qv), subv, true); err != nil { - return err - } - default: - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) - } - } else { - if err := d.value(subv); err != nil { - return err - } - } - - // Write value back to map; - // if using struct, subv points into struct already. - if mapv.IsValid() { - kt := mapv.Type().Key() - var kv reflect.Value - switch { - case kt.Kind() == reflect.String: - kv = reflect.ValueOf(key).Convert(kt) - case reflect.PtrTo(kt).Implements(textUnmarshalerType): - kv = reflect.New(kt) - if err := d.literalStore(item, kv, true); err != nil { - return err - } - kv = kv.Elem() - default: - switch kt.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - s := string(key) - n, err := strconv.ParseInt(s, 10, 64) - if err != nil || reflect.Zero(kt).OverflowInt(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) - break - } - kv = reflect.ValueOf(n).Convert(kt) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - s := string(key) - n, err := strconv.ParseUint(s, 10, 64) - if err != nil || reflect.Zero(kt).OverflowUint(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) - break - } - kv = reflect.ValueOf(n).Convert(kt) - default: - panic("json: Unexpected key type") // should never occur - } - } - if kv.IsValid() { - mapv.SetMapIndex(kv, subv) - } - } - - // Next token must be , or }. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - // Reset errorContext to its original state. - // Keep the same underlying array for FieldStack, to reuse the - // space and avoid unnecessary allocs. - d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] - d.errorContext.Struct = origErrorContext.Struct - if d.opcode == scanEndObject { - break - } - if d.opcode != scanObjectValue { - panic(phasePanicMsg) - } - } - return nil -} - -// convertNumber converts the number literal s to a float64 or a Number -// depending on the setting of d.useNumber. -func (d *decodeState) convertNumber(s string) (interface{}, error) { - if d.useNumber { - return Number(s), nil - } - f, err := strconv.ParseFloat(s, 64) - if err != nil { - return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeOf(0.0), Offset: int64(d.off)} - } - return f, nil -} - -var numberType = reflect.TypeOf(Number("")) - -// literalStore decodes a literal stored in item into v. -// -// fromQuoted indicates whether this literal came from unwrapping a -// string from the ",string" struct tag option. this is used only to -// produce more helpful error messages. -func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) error { - // Check for unmarshaler. - if len(item) == 0 { - //Empty string given - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - return nil - } - isNull := item[0] == 'n' // null - u, ut, pv := indirect(v, isNull) - if u != nil { - return u.UnmarshalJSON(item) - } - if ut != nil { - if item[0] != '"' { - if fromQuoted { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - return nil - } - val := "number" - switch item[0] { - case 'n': - val = "null" - case 't', 'f': - val = "bool" - } - d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())}) - return nil - } - s, ok := unquoteBytes(item) - if !ok { - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - panic(phasePanicMsg) - } - return ut.UnmarshalText(s) - } - - v = pv - - switch c := item[0]; c { - case 'n': // null - // The main parser checks that only true and false can reach here, - // but if this was a quoted string input, it could be anything. - if fromQuoted && string(item) != "null" { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - break - } - switch v.Kind() { - case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: - v.Set(reflect.Zero(v.Type())) - // otherwise, ignore null for primitives/string - } - case 't', 'f': // true, false - value := item[0] == 't' - // The main parser checks that only true and false can reach here, - // but if this was a quoted string input, it could be anything. - if fromQuoted && string(item) != "true" && string(item) != "false" { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - break - } - switch v.Kind() { - default: - 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{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) - } - case reflect.Bool: - v.SetBool(value) - case reflect.Interface: - if v.NumMethod() == 0 { - v.Set(reflect.ValueOf(value)) - } else { - d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) - } - } - - case '"': // string - s, ok := unquoteBytes(item) - if !ok { - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - panic(phasePanicMsg) - } - switch v.Kind() { - default: - d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) - case reflect.Slice: - if v.Type().Elem().Kind() != reflect.Uint8 { - d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) - n, err := base64.StdEncoding.Decode(b, s) - if err != nil { - d.saveError(err) - break - } - v.SetBytes(b[:n]) - case reflect.String: - v.SetString(string(s)) - case reflect.Interface: - if v.NumMethod() == 0 { - v.Set(reflect.ValueOf(string(s))) - } else { - d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) - } - } - - default: // number - if c != '-' && (c < '0' || c > '9') { - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - panic(phasePanicMsg) - } - s := string(item) - switch v.Kind() { - default: - if v.Kind() == reflect.String && v.Type() == numberType { - v.SetString(s) - if !isValidNumber(s) { - return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item) - } - break - } - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) - case reflect.Interface: - n, err := d.convertNumber(s) - if err != nil { - d.saveError(err) - break - } - if v.NumMethod() != 0 { - d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.Set(reflect.ValueOf(n)) - - 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{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.SetInt(n) - - 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{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.SetUint(n) - - case reflect.Float32, reflect.Float64: - n, err := strconv.ParseFloat(s, v.Type().Bits()) - if err != nil || v.OverflowFloat(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.SetFloat(n) - } - } - return nil -} - -// The xxxInterface routines build up a value to be stored -// in an empty interface. They are not strictly necessary, -// but they avoid the weight of reflection in this common case. - -// valueInterface is like value but returns interface{} -func (d *decodeState) valueInterface() (val interface{}) { - switch d.opcode { - default: - panic(phasePanicMsg) - case scanBeginArray: - val = d.arrayInterface() - d.scanNext() - case scanBeginObject: - val = d.objectInterface() - d.scanNext() - case scanBeginLiteral: - val = d.literalInterface() - } - return -} - -// arrayInterface is like array but returns []interface{}. -func (d *decodeState) arrayInterface() []interface{} { - var v = make([]interface{}, 0) - for { - // Look ahead for ] - can only happen on first iteration. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndArray { - break - } - - v = append(v, d.valueInterface()) - - // Next token must be , or ]. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode == scanEndArray { - break - } - if d.opcode != scanArrayValue { - panic(phasePanicMsg) - } - } - return v -} - -// objectInterface is like object but returns map[string]interface{}. -func (d *decodeState) objectInterface() map[string]interface{} { - m := make(map[string]interface{}) - for { - // Read opening " of string key or closing }. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndObject { - // closing } - can only happen on first iteration. - break - } - if d.opcode != scanBeginLiteral { - panic(phasePanicMsg) - } - - // Read string key. - start := d.readIndex() - d.rescanLiteral() - item := d.data[start:d.readIndex()] - key, ok := unquote(item) - if !ok { - panic(phasePanicMsg) - } - - // Read : before value. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode != scanObjectKey { - panic(phasePanicMsg) - } - d.scanWhile(scanSkipSpace) - - // Read value. - m[key] = d.valueInterface() - - // Next token must be , or }. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode == scanEndObject { - break - } - if d.opcode != scanObjectValue { - panic(phasePanicMsg) - } - } - return m -} - -// literalInterface consumes and returns a literal from d.data[d.off-1:] and -// it reads the following byte ahead. The first byte of the literal has been -// read already (that's how the caller knows it's a literal). -func (d *decodeState) literalInterface() interface{} { - // All bytes inside literal return scanContinue op code. - start := d.readIndex() - d.rescanLiteral() - - item := d.data[start:d.readIndex()] - - switch c := item[0]; c { - case 'n': // null - return nil - - case 't', 'f': // true, false - return c == 't' - - case '"': // string - s, ok := unquote(item) - if !ok { - panic(phasePanicMsg) - } - return s - - default: // number - if c != '-' && (c < '0' || c > '9') { - panic(phasePanicMsg) - } - n, err := d.convertNumber(string(item)) - if err != nil { - d.saveError(err) - } - return n - } -} - -// getu4 decodes \uXXXX from the beginning of s, returning the hex value, -// or it returns -1. -func getu4(s []byte) rune { - if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { - return -1 - } - var r rune - for _, c := range s[2:6] { - switch { - case '0' <= c && c <= '9': - c = c - '0' - case 'a' <= c && c <= 'f': - c = c - 'a' + 10 - case 'A' <= c && c <= 'F': - c = c - 'A' + 10 - default: - return -1 - } - r = r*16 + rune(c) - } - return r -} - -// unquote converts a quoted JSON string literal s into an actual string t. -// The rules are different than for Go, so cannot use strconv.Unquote. -func unquote(s []byte) (t string, ok bool) { - s, ok = unquoteBytes(s) - t = string(s) - return -} - -func unquoteBytes(s []byte) (t []byte, ok bool) { - if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { - return - } - s = s[1 : len(s)-1] - - // Check for unusual characters. If there are none, - // then no unquoting is needed, so return a slice of the - // original bytes. - r := 0 - for r < len(s) { - c := s[r] - if c == '\\' || c == '"' || c < ' ' { - break - } - if c < utf8.RuneSelf { - r++ - continue - } - rr, size := utf8.DecodeRune(s[r:]) - if rr == utf8.RuneError && size == 1 { - break - } - r += size - } - if r == len(s) { - return s, true - } - - b := make([]byte, len(s)+2*utf8.UTFMax) - w := copy(b, s[0:r]) - for r < len(s) { - // Out of room? Can only happen if s is full of - // malformed UTF-8 and we're replacing each - // byte with RuneError. - if w >= len(b)-2*utf8.UTFMax { - nb := make([]byte, (len(b)+utf8.UTFMax)*2) - copy(nb, b[0:w]) - b = nb - } - switch c := s[r]; { - case c == '\\': - r++ - if r >= len(s) { - return - } - switch s[r] { - default: - return - case '"', '\\', '/', '\'': - b[w] = s[r] - r++ - w++ - case 'b': - b[w] = '\b' - r++ - w++ - case 'f': - b[w] = '\f' - r++ - w++ - case 'n': - b[w] = '\n' - r++ - w++ - case 'r': - b[w] = '\r' - r++ - w++ - case 't': - b[w] = '\t' - r++ - w++ - case 'u': - r-- - rr := getu4(s[r:]) - if rr < 0 { - return - } - r += 6 - if utf16.IsSurrogate(rr) { - rr1 := getu4(s[r:]) - if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { - // A valid pair; consume. - r += 6 - w += utf8.EncodeRune(b[w:], dec) - break - } - // Invalid surrogate; fall back to replacement rune. - rr = unicode.ReplacementChar - } - w += utf8.EncodeRune(b[w:], rr) - } - - // Quote, control characters are invalid. - case c == '"', c < ' ': - return - - // ASCII - case c < utf8.RuneSelf: - b[w] = c - r++ - w++ - - // Coerce to well-formed UTF-8. - default: - rr, size := utf8.DecodeRune(s[r:]) - r += size - w += utf8.EncodeRune(b[w:], rr) - } - } - return b[0:w], true -} diff --git a/vendor/github.com/yaegashi/msgraph.go/jsonx/encode.go b/vendor/github.com/yaegashi/msgraph.go/jsonx/encode.go deleted file mode 100644 index 7c155502..00000000 --- a/vendor/github.com/yaegashi/msgraph.go/jsonx/encode.go +++ /dev/null @@ -1,1317 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package json implements encoding and decoding of JSON as defined in -// RFC 7159. The mapping between JSON and Go values is described -// in the documentation for the Marshal and Unmarshal functions. -// -// See "JSON and Go" for an introduction to this package: -// https://golang.org/doc/articles/json_and_go.html -package jsonx - -import ( - "bytes" - "encoding" - "encoding/base64" - "fmt" - "math" - "reflect" - "sort" - "strconv" - "strings" - "sync" - "unicode" - "unicode/utf8" -) - -// Marshal returns the JSON encoding of v. -// -// Marshal traverses the value v recursively. -// If an encountered value implements the Marshaler interface -// and is not a nil pointer, Marshal calls its MarshalJSON method -// to produce JSON. If no MarshalJSON method is present but the -// value implements encoding.TextMarshaler instead, Marshal calls -// its MarshalText method and encodes the result as a JSON string. -// The nil pointer exception is not strictly necessary -// but mimics a similar, necessary exception in the behavior of -// UnmarshalJSON. -// -// Otherwise, Marshal uses the following type-dependent default encodings: -// -// Boolean values encode as JSON booleans. -// -// Floating point, integer, and Number values encode as JSON numbers. -// -// String values encode as JSON strings coerced to valid UTF-8, -// replacing invalid bytes with the Unicode replacement rune. -// So that the JSON will be safe to embed inside HTML <script> tags, -// the string is encoded using HTMLEscape, -// which replaces "<", ">", "&", U+2028, and U+2029 are escaped -// to "\u003c","\u003e", "\u0026", "\u2028", and "\u2029". -// This replacement can be disabled when using an Encoder, -// by calling SetEscapeHTML(false). -// -// Array and slice values encode as JSON arrays, except that -// []byte encodes as a base64-encoded string, and a nil slice -// encodes as the null JSON value. -// -// Struct values encode as JSON objects. -// Each exported struct field becomes a member of the object, using the -// field name as the object key, unless the field is omitted for one of the -// reasons given below. -// -// The encoding of each struct field can be customized by the format string -// stored under the "json" key in the struct field's tag. -// The format string gives the name of the field, possibly followed by a -// comma-separated list of options. The name may be empty in order to -// specify options without overriding the default field name. -// -// The "omitempty" option specifies that the field should be omitted -// from the encoding if the field has an empty value, defined as -// false, 0, a nil pointer, a nil interface value, and any empty array, -// slice, map, or string. -// -// As a special case, if the field tag is "-", the field is always omitted. -// Note that a field with name "-" can still be generated using the tag "-,". -// -// Examples of struct field tags and their meanings: -// -// // Field appears in JSON as key "myName". -// Field int `json:"myName"` -// -// // Field appears in JSON as key "myName" and -// // the field is omitted from the object if its value is empty, -// // as defined above. -// Field int `json:"myName,omitempty"` -// -// // Field appears in JSON as key "Field" (the default), but -// // the field is skipped if empty. -// // Note the leading comma. -// Field int `json:",omitempty"` -// -// // Field is ignored by this package. -// Field int `json:"-"` -// -// // Field appears in JSON as key "-". -// Field int `json:"-,"` -// -// 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, -// integer, or boolean types. This extra level of encoding is sometimes used -// when communicating with JavaScript programs: -// -// Int64String int64 `json:",string"` -// -// The key name will be used if it's a non-empty string consisting of -// only Unicode letters, digits, and ASCII punctuation except quotation -// marks, backslash, and comma. -// -// Anonymous struct fields are usually marshaled as if their inner exported fields -// were fields in the outer struct, subject to the usual Go visibility rules amended -// as described in the next paragraph. -// An anonymous struct field with a name given in its JSON tag is treated as -// having that name, rather than being anonymous. -// An anonymous struct field of interface type is treated the same as having -// that type as its name, rather than being anonymous. -// -// The Go visibility rules for struct fields are amended for JSON when -// deciding which field to marshal or unmarshal. If there are -// multiple fields at the same level, and that level is the least -// nested (and would therefore be the nesting level selected by the -// usual Go rules), the following extra rules apply: -// -// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered, -// even if there are multiple untagged fields that would otherwise conflict. -// -// 2) If there is exactly one field (tagged or not according to the first rule), that is selected. -// -// 3) Otherwise there are multiple fields, and all are ignored; no error occurs. -// -// Handling of anonymous struct fields is new in Go 1.1. -// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of -// an anonymous struct field in both current and earlier versions, give the field -// a JSON tag of "-". -// -// Map values encode as JSON objects. The map's key type must either be a -// string, an integer type, or implement encoding.TextMarshaler. The map keys -// are sorted and used as JSON object keys by applying the following rules, -// subject to the UTF-8 coercion described for string values above: -// - keys of any string type are used directly -// - encoding.TextMarshalers are marshaled -// - integer keys are converted to strings -// -// Pointer values encode as the value pointed to. -// A nil pointer encodes as the null JSON value. -// -// Interface values encode as the value contained in the interface. -// A nil interface value encodes as the null JSON value. -// -// Channel, complex, and function values cannot be encoded in JSON. -// Attempting to encode such a value causes Marshal to return -// an UnsupportedTypeError. -// -// JSON cannot represent cyclic data structures and Marshal does not -// handle them. Passing cyclic structures to Marshal will result in -// an infinite recursion. -// -func Marshal(v interface{}) ([]byte, error) { - e := newEncodeState() - - err := e.marshal(v, encOpts{escapeHTML: true}) - if err != nil { - return nil, err - } - buf := append([]byte(nil), e.Bytes()...) - - e.Reset() - encodeStatePool.Put(e) - - return buf, nil -} - -// MarshalIndent is like Marshal but applies Indent to format the output. -// Each JSON element in the output will begin on a new line beginning with prefix -// followed by one or more copies of indent according to the indentation nesting. -func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { - b, err := Marshal(v) - if err != nil { - return nil, err - } - var buf bytes.Buffer - err = Indent(&buf, b, prefix, indent) - if err != nil { - return nil, err - } - return buf.Bytes(), nil -} - -// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029 -// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029 -// so that the JSON will be safe to embed inside HTML <script> tags. -// For historical reasons, web browsers don't honor standard HTML -// escaping within <script> tags, so an alternative JSON encoding must -// be used. -func HTMLEscape(dst *bytes.Buffer, src []byte) { - // The characters can only appear in string literals, - // so just scan the string one byte at a time. - start := 0 - for i, c := range src { - if c == '<' || c == '>' || c == '&' { - if start < i { - dst.Write(src[start:i]) - } - dst.WriteString(`\u00`) - dst.WriteByte(hex[c>>4]) - dst.WriteByte(hex[c&0xF]) - start = i + 1 - } - // Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9). - if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 { - if start < i { - dst.Write(src[start:i]) - } - dst.WriteString(`\u202`) - dst.WriteByte(hex[src[i+2]&0xF]) - start = i + 3 - } - } - if start < len(src) { - dst.Write(src[start:]) - } -} - -// Marshaler is the interface implemented by types that -// can marshal themselves into valid JSON. -type Marshaler interface { - MarshalJSON() ([]byte, error) -} - -// An UnsupportedTypeError is returned by Marshal when attempting -// to encode an unsupported value type. -type UnsupportedTypeError struct { - Type reflect.Type -} - -func (e *UnsupportedTypeError) Error() string { - return "json: unsupported type: " + e.Type.String() -} - -type UnsupportedValueError struct { - Value reflect.Value - Str string -} - -func (e *UnsupportedValueError) Error() string { - return "json: unsupported value: " + e.Str -} - -// Before Go 1.2, an InvalidUTF8Error was returned by Marshal when -// attempting to encode a string value with invalid UTF-8 sequences. -// As of Go 1.2, Marshal instead coerces the string to valid UTF-8 by -// replacing invalid bytes with the Unicode replacement rune U+FFFD. -// -// Deprecated: No longer used; kept for compatibility. -type InvalidUTF8Error struct { - S string // the whole string value that caused the error -} - -func (e *InvalidUTF8Error) Error() string { - return "json: invalid UTF-8 in string: " + strconv.Quote(e.S) -} - -// A MarshalerError represents an error from calling a MarshalJSON or MarshalText method. -type MarshalerError struct { - Type reflect.Type - Err error -} - -func (e *MarshalerError) Error() string { - return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Err.Error() -} - -func (e *MarshalerError) Unwrap() error { return e.Err } - -var hex = "0123456789abcdef" - -// An encodeState encodes JSON into a bytes.Buffer. -type encodeState struct { - bytes.Buffer // accumulated output - scratch [64]byte -} - -var encodeStatePool sync.Pool - -func newEncodeState() *encodeState { - if v := encodeStatePool.Get(); v != nil { - e := v.(*encodeState) - e.Reset() - return e - } - return new(encodeState) -} - -// jsonError is an error wrapper type for internal use only. -// Panics with errors are wrapped in jsonError so that the top-level recover -// can distinguish intentional panics from this package. -type jsonError struct{ error } - -func (e *encodeState) marshal(v interface{}, opts encOpts) (err error) { - defer func() { - if r := recover(); r != nil { - if je, ok := r.(jsonError); ok { - err = je.error - } else { - panic(r) - } - } - }() - e.reflectValue(reflect.ValueOf(v), opts) - return nil -} - -// error aborts the encoding by panicking with err wrapped in jsonError. -func (e *encodeState) error(err error) { - panic(jsonError{err}) -} - -func isEmptyValue(v reflect.Value) bool { - switch v.Kind() { - case reflect.Array, reflect.Map, reflect.Slice, reflect.String: - return v.Len() == 0 - case reflect.Bool: - return !v.Bool() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.Interface, reflect.Ptr: - return v.IsNil() - } - return false -} - -func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) { - valueEncoder(v)(e, v, opts) -} - -type encOpts struct { - // quoted causes primitive fields to be encoded inside JSON strings. - quoted bool - // escapeHTML causes '<', '>', and '&' to be escaped in JSON strings. - escapeHTML bool -} - -type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts) - -var encoderCache sync.Map // map[reflect.Type]encoderFunc - -func valueEncoder(v reflect.Value) encoderFunc { - if !v.IsValid() { - return invalidValueEncoder - } - return typeEncoder(v.Type()) -} - -func typeEncoder(t reflect.Type) encoderFunc { - if fi, ok := encoderCache.Load(t); ok { - return fi.(encoderFunc) - } - - // To deal with recursive types, populate the map with an - // indirect func before we build it. This type waits on the - // real func (f) to be ready and then calls it. This indirect - // func is only used for recursive types. - var ( - wg sync.WaitGroup - f encoderFunc - ) - wg.Add(1) - fi, loaded := encoderCache.LoadOrStore(t, encoderFunc(func(e *encodeState, v reflect.Value, opts encOpts) { - wg.Wait() - f(e, v, opts) - })) - if loaded { - return fi.(encoderFunc) - } - - // Compute the real encoder and replace the indirect func with it. - f = newTypeEncoder(t, true) - wg.Done() - encoderCache.Store(t, f) - return f -} - -var ( - marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() - textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() -) - -// newTypeEncoder constructs an encoderFunc for a type. -// The returned encoder only checks CanAddr when allowAddr is true. -func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc { - if t.Implements(marshalerType) { - return marshalerEncoder - } - if t.Kind() != reflect.Ptr && allowAddr && reflect.PtrTo(t).Implements(marshalerType) { - return newCondAddrEncoder(addrMarshalerEncoder, newTypeEncoder(t, false)) - } - - if t.Implements(textMarshalerType) { - return textMarshalerEncoder - } - if t.Kind() != reflect.Ptr && allowAddr && reflect.PtrTo(t).Implements(textMarshalerType) { - return newCondAddrEncoder(addrTextMarshalerEncoder, newTypeEncoder(t, false)) - } - - switch t.Kind() { - case reflect.Bool: - return boolEncoder - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return intEncoder - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return uintEncoder - case reflect.Float32: - return float32Encoder - case reflect.Float64: - return float64Encoder - case reflect.String: - return stringEncoder - case reflect.Interface: - return interfaceEncoder - case reflect.Struct: - return newStructEncoder(t) - case reflect.Map: - return newMapEncoder(t) - case reflect.Slice: - return newSliceEncoder(t) - case reflect.Array: - return newArrayEncoder(t) - case reflect.Ptr: - return newPtrEncoder(t) - default: - return unsupportedTypeEncoder - } -} - -func invalidValueEncoder(e *encodeState, v reflect.Value, _ encOpts) { - e.WriteString("null") -} - -func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { - if v.Kind() == reflect.Ptr && v.IsNil() { - e.WriteString("null") - return - } - m, ok := v.Interface().(Marshaler) - if !ok { - e.WriteString("null") - return - } - b, err := m.MarshalJSON() - if err == nil { - // copy JSON into buffer, checking validity. - err = compact(&e.Buffer, b, opts.escapeHTML) - } - if err != nil { - e.error(&MarshalerError{v.Type(), err}) - } -} - -func addrMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { - va := v.Addr() - if va.IsNil() { - e.WriteString("null") - return - } - m := va.Interface().(Marshaler) - b, err := m.MarshalJSON() - if err == nil { - // copy JSON into buffer, checking validity. - err = compact(&e.Buffer, b, opts.escapeHTML) - } - if err != nil { - e.error(&MarshalerError{v.Type(), err}) - } -} - -func textMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { - if v.Kind() == reflect.Ptr && v.IsNil() { - e.WriteString("null") - return - } - m := v.Interface().(encoding.TextMarshaler) - b, err := m.MarshalText() - if err != nil { - e.error(&MarshalerError{v.Type(), err}) - } - e.stringBytes(b, opts.escapeHTML) -} - -func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { - va := v.Addr() - if va.IsNil() { - e.WriteString("null") - return - } - m := va.Interface().(encoding.TextMarshaler) - b, err := m.MarshalText() - if err != nil { - e.error(&MarshalerError{v.Type(), err}) - } - e.stringBytes(b, opts.escapeHTML) -} - -func boolEncoder(e *encodeState, v reflect.Value, opts encOpts) { - if opts.quoted { - e.WriteByte('"') - } - if v.Bool() { - e.WriteString("true") - } else { - e.WriteString("false") - } - if opts.quoted { - e.WriteByte('"') - } -} - -func intEncoder(e *encodeState, v reflect.Value, opts encOpts) { - b := strconv.AppendInt(e.scratch[:0], v.Int(), 10) - if opts.quoted { - e.WriteByte('"') - } - e.Write(b) - if opts.quoted { - e.WriteByte('"') - } -} - -func uintEncoder(e *encodeState, v reflect.Value, opts encOpts) { - b := strconv.AppendUint(e.scratch[:0], v.Uint(), 10) - if opts.quoted { - e.WriteByte('"') - } - e.Write(b) - if opts.quoted { - e.WriteByte('"') - } -} - -type floatEncoder int // number of bits - -func (bits floatEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { - f := v.Float() - if math.IsInf(f, 0) || math.IsNaN(f) { - e.error(&UnsupportedValueError{v, strconv.FormatFloat(f, 'g', -1, int(bits))}) - } - - // Convert as if by ES6 number to string conversion. - // This matches most other JSON generators. - // See golang.org/issue/6384 and golang.org/issue/14135. - // Like fmt %g, but the exponent cutoffs are different - // and exponents themselves are not padded to two digits. - b := e.scratch[:0] - abs := math.Abs(f) - fmt := byte('f') - // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. - if abs != 0 { - if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) { - fmt = 'e' - } - } - b = strconv.AppendFloat(b, f, fmt, -1, int(bits)) - if fmt == 'e' { - // clean up e-09 to e-9 - n := len(b) - if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' { - b[n-2] = b[n-1] - b = b[:n-1] - } - } - - if opts.quoted { - e.WriteByte('"') - } - e.Write(b) - if opts.quoted { - e.WriteByte('"') - } -} - -var ( - float32Encoder = (floatEncoder(32)).encode - float64Encoder = (floatEncoder(64)).encode -) - -func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) { - if v.Type() == numberType { - numStr := v.String() - // In Go1.5 the empty string encodes to "0", while this is not a valid number literal - // we keep compatibility so check validity after this. - if numStr == "" { - numStr = "0" // Number's zero-val - } - if !isValidNumber(numStr) { - e.error(fmt.Errorf("json: invalid number literal %q", numStr)) - } - e.WriteString(numStr) - return - } - if opts.quoted { - sb, err := Marshal(v.String()) - if err != nil { - e.error(err) - } - e.string(string(sb), opts.escapeHTML) - } else { - e.string(v.String(), opts.escapeHTML) - } -} - -func interfaceEncoder(e *encodeState, v reflect.Value, opts encOpts) { - if v.IsNil() { - e.WriteString("null") - return - } - e.reflectValue(v.Elem(), opts) -} - -func unsupportedTypeEncoder(e *encodeState, v reflect.Value, _ encOpts) { - e.error(&UnsupportedTypeError{v.Type()}) -} - -type structEncoder struct { - fields structFields -} - -type structFields struct { - list []field - nameIndex map[string]int -} - -func (se structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { - next := byte('{') -FieldLoop: - for i := range se.fields.list { - f := &se.fields.list[i] - - // Find the nested struct field by following f.index. - fv := v - for _, i := range f.index { - if fv.Kind() == reflect.Ptr { - if fv.IsNil() { - continue FieldLoop - } - fv = fv.Elem() - } - fv = fv.Field(i) - } - - if f.omitEmpty && isEmptyValue(fv) { - continue - } - if f.extra { - keys := fv.MapKeys() - sv := make([]reflectWithString, len(keys)) - for i, v := range keys { - sv[i].v = v - if err := sv[i].resolve(); err != nil { - e.error(&MarshalerError{v.Type(), err}) - } - } - sort.Slice(sv, func(i, j int) bool { return sv[i].s < sv[j].s }) - elemEnc := typeEncoder(fv.Type().Elem()) - for _, kv := range sv { - e.WriteByte(next) - next = ',' - e.string(kv.s, opts.escapeHTML) - e.WriteByte(':') - elemEnc(e, fv.MapIndex(kv.v), opts) - } - continue - } - e.WriteByte(next) - next = ',' - if opts.escapeHTML { - e.WriteString(f.nameEscHTML) - } else { - e.WriteString(f.nameNonEsc) - } - opts.quoted = f.quoted - f.encoder(e, fv, opts) - } - if next == '{' { - e.WriteString("{}") - } else { - e.WriteByte('}') - } -} - -func newStructEncoder(t reflect.Type) encoderFunc { - se := structEncoder{fields: cachedTypeFields(t)} - return se.encode -} - -type mapEncoder struct { - elemEnc encoderFunc -} - -func (me mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { - if v.IsNil() { - e.WriteString("null") - return - } - e.WriteByte('{') - - // Extract and sort the keys. - keys := v.MapKeys() - sv := make([]reflectWithString, len(keys)) - for i, v := range keys { - sv[i].v = v - if err := sv[i].resolve(); err != nil { - e.error(&MarshalerError{v.Type(), err}) - } - } - sort.Slice(sv, func(i, j int) bool { return sv[i].s < sv[j].s }) - - for i, kv := range sv { - if i > 0 { - e.WriteByte(',') - } - e.string(kv.s, opts.escapeHTML) - e.WriteByte(':') - me.elemEnc(e, v.MapIndex(kv.v), opts) - } - e.WriteByte('}') -} - -func newMapEncoder(t reflect.Type) encoderFunc { - switch t.Key().Kind() { - case reflect.String, - reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - default: - if !t.Key().Implements(textMarshalerType) { - return unsupportedTypeEncoder - } - } - me := mapEncoder{typeEncoder(t.Elem())} - return me.encode -} - -func encodeByteSlice(e *encodeState, v reflect.Value, _ encOpts) { - if v.IsNil() { - e.WriteString("null") - return - } - s := v.Bytes() - e.WriteByte('"') - encodedLen := base64.StdEncoding.EncodedLen(len(s)) - if encodedLen <= len(e.scratch) { - // If the encoded bytes fit in e.scratch, avoid an extra - // allocation and use the cheaper Encoding.Encode. - dst := e.scratch[:encodedLen] - base64.StdEncoding.Encode(dst, s) - e.Write(dst) - } else if encodedLen <= 1024 { - // The encoded bytes are short enough to allocate for, and - // Encoding.Encode is still cheaper. - dst := make([]byte, encodedLen) - base64.StdEncoding.Encode(dst, s) - e.Write(dst) - } else { - // The encoded bytes are too long to cheaply allocate, and - // Encoding.Encode is no longer noticeably cheaper. - enc := base64.NewEncoder(base64.StdEncoding, e) - enc.Write(s) - enc.Close() - } - e.WriteByte('"') -} - -// sliceEncoder just wraps an arrayEncoder, checking to make sure the value isn't nil. -type sliceEncoder struct { - arrayEnc encoderFunc -} - -func (se sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { - if v.IsNil() { - e.WriteString("null") - return - } - se.arrayEnc(e, v, opts) -} - -func newSliceEncoder(t reflect.Type) encoderFunc { - // Byte slices get special treatment; arrays don't. - if t.Elem().Kind() == reflect.Uint8 { - p := reflect.PtrTo(t.Elem()) - if !p.Implements(marshalerType) && !p.Implements(textMarshalerType) { - return encodeByteSlice - } - } - enc := sliceEncoder{newArrayEncoder(t)} - return enc.encode -} - -type arrayEncoder struct { - elemEnc encoderFunc -} - -func (ae arrayEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { - e.WriteByte('[') - n := v.Len() - for i := 0; i < n; i++ { - if i > 0 { - e.WriteByte(',') - } - ae.elemEnc(e, v.Index(i), opts) - } - e.WriteByte(']') -} - -func newArrayEncoder(t reflect.Type) encoderFunc { - enc := arrayEncoder{typeEncoder(t.Elem())} - return enc.encode -} - -type ptrEncoder struct { - elemEnc encoderFunc -} - -func (pe ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { - if v.IsNil() { - e.WriteString("null") - return - } - pe.elemEnc(e, v.Elem(), opts) -} - -func newPtrEncoder(t reflect.Type) encoderFunc { - enc := ptrEncoder{typeEncoder(t.Elem())} - return enc.encode -} - -type condAddrEncoder struct { - canAddrEnc, elseEnc encoderFunc -} - -func (ce condAddrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { - if v.CanAddr() { - ce.canAddrEnc(e, v, opts) - } else { - ce.elseEnc(e, v, opts) - } -} - -// newCondAddrEncoder returns an encoder that checks whether its value -// CanAddr and delegates to canAddrEnc if so, else to elseEnc. -func newCondAddrEncoder(canAddrEnc, elseEnc encoderFunc) encoderFunc { - enc := condAddrEncoder{canAddrEnc: canAddrEnc, elseEnc: elseEnc} - return enc.encode -} - -func isValidTag(s string) bool { - if s == "" { - return false - } - for _, c := range s { - switch { - case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): - // Backslash and quote chars are reserved, but - // otherwise any punctuation chars are allowed - // in a tag name. - case !unicode.IsLetter(c) && !unicode.IsDigit(c): - return false - } - } - return true -} - -func typeByIndex(t reflect.Type, index []int) reflect.Type { - for _, i := range index { - if t.Kind() == reflect.Ptr { - t = t.Elem() - } - t = t.Field(i).Type - } - return t -} - -type reflectWithString struct { - v reflect.Value - s string -} - -func (w *reflectWithString) resolve() error { - if w.v.Kind() == reflect.String { - w.s = w.v.String() - return nil - } - if tm, ok := w.v.Interface().(encoding.TextMarshaler); ok { - buf, err := tm.MarshalText() - w.s = string(buf) - return err - } - switch w.v.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - w.s = strconv.FormatInt(w.v.Int(), 10) - return nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - w.s = strconv.FormatUint(w.v.Uint(), 10) - return nil - } - panic("unexpected map key type") -} - -// NOTE: keep in sync with stringBytes below. -func (e *encodeState) string(s string, escapeHTML bool) { - e.WriteByte('"') - start := 0 - for i := 0; i < len(s); { - if b := s[i]; b < utf8.RuneSelf { - if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) { - i++ - continue - } - if start < i { - e.WriteString(s[start:i]) - } - e.WriteByte('\\') - switch b { - case '\\', '"': - e.WriteByte(b) - case '\n': - e.WriteByte('n') - case '\r': - e.WriteByte('r') - case '\t': - e.WriteByte('t') - default: - // This encodes bytes < 0x20 except for \t, \n and \r. - // If escapeHTML is set, it also escapes <, >, and & - // because they can lead to security holes when - // user-controlled strings are rendered into JSON - // and served to some browsers. - e.WriteString(`u00`) - e.WriteByte(hex[b>>4]) - e.WriteByte(hex[b&0xF]) - } - i++ - start = i - continue - } - c, size := utf8.DecodeRuneInString(s[i:]) - if c == utf8.RuneError && size == 1 { - if start < i { - e.WriteString(s[start:i]) - } - e.WriteString(`\ufffd`) - i += size - start = i - continue - } - // U+2028 is LINE SEPARATOR. - // U+2029 is PARAGRAPH SEPARATOR. - // They are both technically valid characters in JSON strings, - // but don't work in JSONP, which has to be evaluated as JavaScript, - // and can lead to security holes there. It is valid JSON to - // escape them, so we do so unconditionally. - // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. - if c == '\u2028' || c == '\u2029' { - if start < i { - e.WriteString(s[start:i]) - } - e.WriteString(`\u202`) - e.WriteByte(hex[c&0xF]) - i += size - start = i - continue - } - i += size - } - if start < len(s) { - e.WriteString(s[start:]) - } - e.WriteByte('"') -} - -// NOTE: keep in sync with string above. -func (e *encodeState) stringBytes(s []byte, escapeHTML bool) { - e.WriteByte('"') - start := 0 - for i := 0; i < len(s); { - if b := s[i]; b < utf8.RuneSelf { - if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) { - i++ - continue - } - if start < i { - e.Write(s[start:i]) - } - e.WriteByte('\\') - switch b { - case '\\', '"': - e.WriteByte(b) - case '\n': - e.WriteByte('n') - case '\r': - e.WriteByte('r') - case '\t': - e.WriteByte('t') - default: - // This encodes bytes < 0x20 except for \t, \n and \r. - // If escapeHTML is set, it also escapes <, >, and & - // because they can lead to security holes when - // user-controlled strings are rendered into JSON - // and served to some browsers. - e.WriteString(`u00`) - e.WriteByte(hex[b>>4]) - e.WriteByte(hex[b&0xF]) - } - i++ - start = i - continue - } - c, size := utf8.DecodeRune(s[i:]) - if c == utf8.RuneError && size == 1 { - if start < i { - e.Write(s[start:i]) - } - e.WriteString(`\ufffd`) - i += size - start = i - continue - } - // U+2028 is LINE SEPARATOR. - // U+2029 is PARAGRAPH SEPARATOR. - // They are both technically valid characters in JSON strings, - // but don't work in JSONP, which has to be evaluated as JavaScript, - // and can lead to security holes there. It is valid JSON to - // escape them, so we do so unconditionally. - // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. - if c == '\u2028' || c == '\u2029' { - if start < i { - e.Write(s[start:i]) - } - e.WriteString(`\u202`) - e.WriteByte(hex[c&0xF]) - i += size - start = i - continue - } - i += size - } - if start < len(s) { - e.Write(s[start:]) - } - e.WriteByte('"') -} - -// A field represents a single field found in a struct. -type field struct { - name string - nameBytes []byte // []byte(name) - equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent - - nameNonEsc string // `"` + name + `":` - nameEscHTML string // `"` + HTMLEscape(name) + `":` - - tag bool - index []int - typ reflect.Type - omitEmpty bool - extra bool - quoted bool - - encoder encoderFunc -} - -// byIndex sorts field by index sequence. -type byIndex []field - -func (x byIndex) Len() int { return len(x) } - -func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - -func (x byIndex) Less(i, j int) bool { - for k, xik := range x[i].index { - if k >= len(x[j].index) { - return false - } - if xik != x[j].index[k] { - return xik < x[j].index[k] - } - } - return len(x[i].index) < len(x[j].index) -} - -// typeFields returns a list of fields that JSON should recognize for the given type. -// The algorithm is breadth-first search over the set of structs to include - the top struct -// and then any reachable anonymous structs. -func typeFields(t reflect.Type) structFields { - // Anonymous fields to explore at the current level and the next. - current := []field{} - next := []field{{typ: t}} - - // Count of queued names for current level and the next. - var count, nextCount map[reflect.Type]int - - // Types already visited at an earlier level. - visited := map[reflect.Type]bool{} - - // Fields found. - var fields []field - - // Buffer to run HTMLEscape on field names. - var nameEscBuf bytes.Buffer - - for len(next) > 0 { - current, next = next, current[:0] - count, nextCount = nextCount, map[reflect.Type]int{} - - for _, f := range current { - if visited[f.typ] { - continue - } - visited[f.typ] = true - - // Scan f.typ for fields to include. - for i := 0; i < f.typ.NumField(); i++ { - sf := f.typ.Field(i) - isUnexported := sf.PkgPath != "" - if sf.Anonymous { - t := sf.Type - if t.Kind() == reflect.Ptr { - t = t.Elem() - } - if isUnexported && t.Kind() != reflect.Struct { - // Ignore embedded fields of unexported non-struct types. - continue - } - // Do not ignore embedded fields of unexported struct types - // since they may have exported fields. - } else if isUnexported { - // Ignore unexported non-embedded fields. - continue - } - tag := sf.Tag.Get("json") - tagx := sf.Tag.Get("jsonx") - if tag == "-" && tagx == "" { - continue - } - if tagx != "" { - tag = "" - } - name, opts := parseTag(tag) - if !isValidTag(name) { - name = "" - } - index := make([]int, len(f.index)+1) - copy(index, f.index) - index[len(f.index)] = i - - ft := sf.Type - if ft.Name() == "" && ft.Kind() == reflect.Ptr { - // Follow pointer. - ft = ft.Elem() - } - - // Only maps can be extra. - extra := false - if tagx != "" { - switch ft.Kind() { - case reflect.Map: - extra = true - default: - continue - } - } - - // 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.Uintptr, - reflect.Float32, reflect.Float64, - reflect.String: - quoted = true - } - } - - // Record found field and index sequence. - if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { - tagged := name != "" - if name == "" { - name = sf.Name - } - field := field{ - name: name, - tag: tagged, - index: index, - typ: ft, - omitEmpty: opts.Contains("omitempty"), - extra: extra, - quoted: quoted, - } - field.nameBytes = []byte(field.name) - field.equalFold = foldFunc(field.nameBytes) - - // Build nameEscHTML and nameNonEsc ahead of time. - nameEscBuf.Reset() - nameEscBuf.WriteString(`"`) - HTMLEscape(&nameEscBuf, field.nameBytes) - nameEscBuf.WriteString(`":`) - field.nameEscHTML = nameEscBuf.String() - field.nameNonEsc = `"` + field.name + `":` - - fields = append(fields, field) - if count[f.typ] > 1 { - // If there were multiple instances, add a second, - // so that the annihilation code will see a duplicate. - // It only cares about the distinction between 1 or 2, - // so don't bother generating any more copies. - fields = append(fields, fields[len(fields)-1]) - } - continue - } - - // Record new anonymous struct to explore in next round. - nextCount[ft]++ - if nextCount[ft] == 1 { - next = append(next, field{name: ft.Name(), index: index, typ: ft}) - } - } - } - } - - sort.Slice(fields, func(i, j int) bool { - x := fields - // sort field by name, breaking ties with depth, then - // breaking ties with "name came from json tag", then - // breaking ties with index sequence. - if x[i].name != x[j].name { - return x[i].name < x[j].name - } - if len(x[i].index) != len(x[j].index) { - return len(x[i].index) < len(x[j].index) - } - if x[i].tag != x[j].tag { - return x[i].tag - } - return byIndex(x).Less(i, j) - }) - - // Delete all fields that are hidden by the Go rules for embedded fields, - // except that fields with JSON tags are promoted. - - // The fields are sorted in primary order of name, secondary order - // of field index length. Loop over names; for each name, delete - // hidden fields by choosing the one dominant field that survives. - out := fields[:0] - for advance, i := 0, 0; i < len(fields); i += advance { - // One iteration per name. - // Find the sequence of fields with the name of this first field. - fi := fields[i] - name := fi.name - for advance = 1; i+advance < len(fields); advance++ { - fj := fields[i+advance] - if fj.name != name { - break - } - } - if advance == 1 { // Only one field with this name - out = append(out, fi) - continue - } - dominant, ok := dominantField(fields[i : i+advance]) - if ok { - out = append(out, dominant) - } - } - - fields = out - sort.Sort(byIndex(fields)) - - for i := range fields { - f := &fields[i] - f.encoder = typeEncoder(typeByIndex(t, f.index)) - } - nameIndex := make(map[string]int, len(fields)) - for i, field := range fields { - nameIndex[field.name] = i - } - return structFields{fields, nameIndex} -} - -// dominantField looks through the fields, all of which are known to -// have the same name, to find the single field that dominates the -// others using Go's embedding rules, modified by the presence of -// JSON tags. If there are multiple top-level fields, the boolean -// will be false: This condition is an error in Go and we skip all -// the fields. -func dominantField(fields []field) (field, bool) { - // The fields are sorted in increasing index-length order, then by presence of tag. - // That means that the first field is the dominant one. We need only check - // for error cases: two fields at top level, either both tagged or neither tagged. - if len(fields) > 1 && len(fields[0].index) == len(fields[1].index) && fields[0].tag == fields[1].tag { - return field{}, false - } - return fields[0], true -} - -var fieldCache sync.Map // map[reflect.Type]structFields - -// cachedTypeFields is like typeFields but uses a cache to avoid repeated work. -func cachedTypeFields(t reflect.Type) structFields { - if f, ok := fieldCache.Load(t); ok { - return f.(structFields) - } - f, _ := fieldCache.LoadOrStore(t, typeFields(t)) - return f.(structFields) -} diff --git a/vendor/github.com/yaegashi/msgraph.go/jsonx/fold.go b/vendor/github.com/yaegashi/msgraph.go/jsonx/fold.go deleted file mode 100644 index 316ea018..00000000 --- a/vendor/github.com/yaegashi/msgraph.go/jsonx/fold.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package jsonx - -import ( - "bytes" - "unicode/utf8" -) - -const ( - caseMask = ^byte(0x20) // Mask to ignore case in ASCII. - kelvin = '\u212a' - smallLongEss = '\u017f' -) - -// foldFunc returns one of four different case folding equivalence -// functions, from most general (and slow) to fastest: -// -// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8 -// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S') -// 3) asciiEqualFold, no special, but includes non-letters (including _) -// 4) simpleLetterEqualFold, no specials, no non-letters. -// -// 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 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. -func foldFunc(s []byte) func(s, t []byte) bool { - nonLetter := false - special := false // special letter - for _, b := range s { - if b >= utf8.RuneSelf { - return bytes.EqualFold - } - upper := b & caseMask - if upper < 'A' || upper > 'Z' { - nonLetter = true - } else if upper == 'K' || upper == 'S' { - // See above for why these letters are special. - special = true - } - } - if special { - return equalFoldRight - } - if nonLetter { - return asciiEqualFold - } - return simpleLetterEqualFold -} - -// equalFoldRight is a specialization of bytes.EqualFold when s is -// known to be all ASCII (including punctuation), but contains an 's', -// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t. -// See comments on foldFunc. -func equalFoldRight(s, t []byte) bool { - for _, sb := range s { - if len(t) == 0 { - return false - } - tb := t[0] - if tb < utf8.RuneSelf { - if sb != tb { - sbUpper := sb & caseMask - if 'A' <= sbUpper && sbUpper <= 'Z' { - if sbUpper != tb&caseMask { - return false - } - } else { - return false - } - } - t = t[1:] - continue - } - // sb is ASCII and t is not. t must be either kelvin - // sign or long s; sb must be s, S, k, or K. - tr, size := utf8.DecodeRune(t) - switch sb { - case 's', 'S': - if tr != smallLongEss { - return false - } - case 'k', 'K': - if tr != kelvin { - return false - } - default: - return false - } - t = t[size:] - - } - if len(t) > 0 { - return false - } - return true -} - -// asciiEqualFold is a specialization of bytes.EqualFold for use when -// s is all ASCII (but may contain non-letters) and contains no -// special-folding letters. -// See comments on foldFunc. -func asciiEqualFold(s, t []byte) bool { - if len(s) != len(t) { - return false - } - for i, sb := range s { - tb := t[i] - if sb == tb { - continue - } - if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') { - if sb&caseMask != tb&caseMask { - return false - } - } else { - return false - } - } - return true -} - -// simpleLetterEqualFold is a specialization of bytes.EqualFold for -// use when s is all ASCII letters (no underscores, etc) and also -// doesn't contain 'k', 'K', 's', or 'S'. -// See comments on foldFunc. -func simpleLetterEqualFold(s, t []byte) bool { - if len(s) != len(t) { - return false - } - for i, b := range s { - if b&caseMask != t[i]&caseMask { - return false - } - } - return true -} diff --git a/vendor/github.com/yaegashi/msgraph.go/jsonx/indent.go b/vendor/github.com/yaegashi/msgraph.go/jsonx/indent.go deleted file mode 100644 index 15d95cd1..00000000 --- a/vendor/github.com/yaegashi/msgraph.go/jsonx/indent.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package jsonx - -import "bytes" - -// Compact appends to dst the JSON-encoded src with -// insignificant space characters elided. -func Compact(dst *bytes.Buffer, src []byte) error { - return compact(dst, src, false) -} - -func compact(dst *bytes.Buffer, src []byte, escape bool) error { - origLen := dst.Len() - var scan scanner - scan.reset() - start := 0 - for i, c := range src { - if escape && (c == '<' || c == '>' || c == '&') { - if start < i { - dst.Write(src[start:i]) - } - dst.WriteString(`\u00`) - dst.WriteByte(hex[c>>4]) - dst.WriteByte(hex[c&0xF]) - start = i + 1 - } - // Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9). - if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 { - if start < i { - dst.Write(src[start:i]) - } - dst.WriteString(`\u202`) - dst.WriteByte(hex[src[i+2]&0xF]) - start = i + 3 - } - v := scan.step(&scan, c) - if v >= scanSkipSpace { - if v == scanError { - break - } - if start < i { - dst.Write(src[start:i]) - } - start = i + 1 - } - } - if scan.eof() == scanError { - dst.Truncate(origLen) - return scan.err - } - if start < len(src) { - dst.Write(src[start:]) - } - return nil -} - -func newline(dst *bytes.Buffer, prefix, indent string, depth int) { - dst.WriteByte('\n') - dst.WriteString(prefix) - for i := 0; i < depth; i++ { - dst.WriteString(indent) - } -} - -// Indent appends to dst an indented form of the JSON-encoded src. -// Each element in a JSON object or array begins on a new, -// indented line beginning with prefix followed by one or more -// copies of indent according to the indentation nesting. -// The data appended to dst does not begin with the prefix nor -// any indentation, to make it easier to embed inside other formatted JSON data. -// Although leading space characters (space, tab, carriage return, newline) -// at the beginning of src are dropped, trailing space characters -// at the end of src are preserved and copied to dst. -// For example, if src has no trailing spaces, neither will dst; -// if src ends in a trailing newline, so will dst. -func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error { - origLen := dst.Len() - var scan scanner - scan.reset() - needIndent := false - depth := 0 - for _, c := range src { - scan.bytes++ - v := scan.step(&scan, c) - if v == scanSkipSpace { - continue - } - if v == scanError { - break - } - if needIndent && v != scanEndObject && v != scanEndArray { - needIndent = false - depth++ - newline(dst, prefix, indent, depth) - } - - // Emit semantically uninteresting bytes - // (in particular, punctuation in strings) unmodified. - if v == scanContinue { - dst.WriteByte(c) - continue - } - - // Add spacing around real punctuation. - switch c { - case '{', '[': - // delay indent so that empty object and array are formatted as {} and []. - needIndent = true - dst.WriteByte(c) - - case ',': - dst.WriteByte(c) - newline(dst, prefix, indent, depth) - - case ':': - dst.WriteByte(c) - dst.WriteByte(' ') - - case '}', ']': - if needIndent { - // suppress indent in empty object/array - needIndent = false - } else { - depth-- - newline(dst, prefix, indent, depth) - } - dst.WriteByte(c) - - default: - dst.WriteByte(c) - } - } - if scan.eof() == scanError { - dst.Truncate(origLen) - return scan.err - } - return nil -} diff --git a/vendor/github.com/yaegashi/msgraph.go/jsonx/scanner.go b/vendor/github.com/yaegashi/msgraph.go/jsonx/scanner.go deleted file mode 100644 index 780c5e45..00000000 --- a/vendor/github.com/yaegashi/msgraph.go/jsonx/scanner.go +++ /dev/null @@ -1,573 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package jsonx - -// JSON value parser state machine. -// Just about at the limit of what is reasonable to write by hand. -// Some parts are a bit tedious, but overall it nicely factors out the -// otherwise common code from the multiple scanning functions -// in this package (Compact, Indent, checkValid, etc). -// -// This file starts with two simple examples using the scanner -// before diving into the scanner itself. - -import "strconv" - -// Valid reports whether data is a valid JSON encoding. -func Valid(data []byte) bool { - return checkValid(data, &scanner{}) == nil -} - -// checkValid verifies that data is valid JSON-encoded data. -// scan is passed in for use by checkValid to avoid an allocation. -func checkValid(data []byte, scan *scanner) error { - scan.reset() - for _, c := range data { - scan.bytes++ - if scan.step(scan, c) == scanError { - return scan.err - } - } - if scan.eof() == scanError { - return scan.err - } - return nil -} - -// A SyntaxError is a description of a JSON syntax error. -type SyntaxError struct { - msg string // description of error - Offset int64 // error occurred after reading Offset bytes -} - -func (e *SyntaxError) Error() string { return e.msg } - -// A scanner is a JSON scanning state machine. -// Callers call scan.reset() and then pass bytes in one at a time -// by calling scan.step(&scan, c) for each byte. -// The return value, referred to as an opcode, tells the -// caller about significant parsing events like beginning -// and ending literals, objects, and arrays, so that the -// caller can follow along if it wishes. -// The return value scanEnd indicates that a single top-level -// JSON value has been completed, *before* the byte that -// just got passed in. (The indication must be delayed in order -// to recognize the end of numbers: is 123 a whole value or -// the beginning of 12345e+6?). -type scanner struct { - // The step is a func to be called to execute the next transition. - // Also tried using an integer constant and a single func - // with a switch, but using the func directly was 10% faster - // on a 64-bit Mac Mini, and it's nicer to read. - step func(*scanner, byte) int - - // Reached end of top-level value. - endTop bool - - // Stack of what we're in the middle of - array values, object keys, object values. - parseState []int - - // Error that happened, if any. - err error - - // total bytes consumed, updated by decoder.Decode - bytes int64 -} - -// These values are returned by the state transition functions -// assigned to scanner.state and the method scanner.eof. -// They give details about the current state of the scan that -// callers might be interested to know about. -// It is okay to ignore the return value of any particular -// call to scanner.state: if one call returns scanError, -// every subsequent call will return scanError too. -const ( - // Continue. - scanContinue = iota // uninteresting byte - scanBeginLiteral // end implied by next result != scanContinue - scanBeginObject // begin object - scanObjectKey // just finished object key (string) - scanObjectValue // just finished non-last object value - scanEndObject // end object (implies scanObjectValue if possible) - scanBeginArray // begin array - scanArrayValue // just finished array value - scanEndArray // end array (implies scanArrayValue if possible) - scanSkipSpace // space byte; can skip; known to be last "continue" result - - // Stop. - scanEnd // top-level value ended *before* this byte; known to be first "stop" result - scanError // hit an error, scanner.err. -) - -// These values are stored in the parseState stack. -// They give the current state of a composite value -// being scanned. If the parser is inside a nested value -// the parseState describes the nested state, outermost at entry 0. -const ( - parseObjectKey = iota // parsing object key (before colon) - parseObjectValue // parsing object value (after colon) - parseArrayValue // parsing array value -) - -// reset prepares the scanner for use. -// It must be called before calling s.step. -func (s *scanner) reset() { - s.step = stateBeginValue - s.parseState = s.parseState[0:0] - s.err = nil - s.endTop = false -} - -// eof tells the scanner that the end of input has been reached. -// It returns a scan status just as s.step does. -func (s *scanner) eof() int { - if s.err != nil { - return scanError - } - if s.endTop { - return scanEnd - } - s.step(s, ' ') - if s.endTop { - return scanEnd - } - if s.err == nil { - s.err = &SyntaxError{"unexpected end of JSON input", s.bytes} - } - return scanError -} - -// pushParseState pushes a new parse state p onto the parse stack. -func (s *scanner) pushParseState(p int) { - s.parseState = append(s.parseState, p) -} - -// popParseState pops a parse state (already obtained) off the stack -// and updates s.step accordingly. -func (s *scanner) popParseState() { - n := len(s.parseState) - 1 - s.parseState = s.parseState[0:n] - if n == 0 { - s.step = stateEndTop - s.endTop = true - } else { - s.step = stateEndValue - } -} - -func isSpace(c byte) bool { - return c == ' ' || c == '\t' || c == '\r' || c == '\n' -} - -// stateBeginValueOrEmpty is the state after reading `[`. -func stateBeginValueOrEmpty(s *scanner, c byte) int { - if c <= ' ' && isSpace(c) { - return scanSkipSpace - } - if c == ']' { - return stateEndValue(s, c) - } - return stateBeginValue(s, c) -} - -// stateBeginValue is the state at the beginning of the input. -func stateBeginValue(s *scanner, c byte) int { - if c <= ' ' && isSpace(c) { - return scanSkipSpace - } - switch c { - case '{': - s.step = stateBeginStringOrEmpty - s.pushParseState(parseObjectKey) - return scanBeginObject - case '[': - s.step = stateBeginValueOrEmpty - s.pushParseState(parseArrayValue) - return scanBeginArray - case '"': - s.step = stateInString - return scanBeginLiteral - case '-': - s.step = stateNeg - return scanBeginLiteral - case '0': // beginning of 0.123 - s.step = state0 - return scanBeginLiteral - case 't': // beginning of true - s.step = stateT - return scanBeginLiteral - case 'f': // beginning of false - s.step = stateF - return scanBeginLiteral - case 'n': // beginning of null - s.step = stateN - return scanBeginLiteral - } - if '1' <= c && c <= '9' { // beginning of 1234.5 - s.step = state1 - return scanBeginLiteral - } - return s.error(c, "looking for beginning of value") -} - -// stateBeginStringOrEmpty is the state after reading `{`. -func stateBeginStringOrEmpty(s *scanner, c byte) int { - if c <= ' ' && isSpace(c) { - return scanSkipSpace - } - if c == '}' { - n := len(s.parseState) - s.parseState[n-1] = parseObjectValue - return stateEndValue(s, c) - } - return stateBeginString(s, c) -} - -// stateBeginString is the state after reading `{"key": value,`. -func stateBeginString(s *scanner, c byte) int { - if c <= ' ' && isSpace(c) { - return scanSkipSpace - } - if c == '"' { - s.step = stateInString - return scanBeginLiteral - } - return s.error(c, "looking for beginning of object key string") -} - -// stateEndValue is the state after completing a value, -// such as after reading `{}` or `true` or `["x"`. -func stateEndValue(s *scanner, c byte) int { - n := len(s.parseState) - if n == 0 { - // Completed top-level before the current byte. - s.step = stateEndTop - s.endTop = true - return stateEndTop(s, c) - } - if c <= ' ' && isSpace(c) { - s.step = stateEndValue - return scanSkipSpace - } - ps := s.parseState[n-1] - switch ps { - case parseObjectKey: - if c == ':' { - s.parseState[n-1] = parseObjectValue - s.step = stateBeginValue - return scanObjectKey - } - return s.error(c, "after object key") - case parseObjectValue: - if c == ',' { - s.parseState[n-1] = parseObjectKey - s.step = stateBeginString - return scanObjectValue - } - if c == '}' { - s.popParseState() - return scanEndObject - } - return s.error(c, "after object key:value pair") - case parseArrayValue: - if c == ',' { - s.step = stateBeginValue - return scanArrayValue - } - if c == ']' { - s.popParseState() - return scanEndArray - } - return s.error(c, "after array element") - } - return s.error(c, "") -} - -// stateEndTop is the state after finishing the top-level value, -// such as after reading `{}` or `[1,2,3]`. -// Only space characters should be seen now. -func stateEndTop(s *scanner, c byte) int { - if !isSpace(c) { - // Complain about non-space byte on next call. - s.error(c, "after top-level value") - } - return scanEnd -} - -// stateInString is the state after reading `"`. -func stateInString(s *scanner, c byte) int { - if c == '"' { - s.step = stateEndValue - return scanContinue - } - if c == '\\' { - s.step = stateInStringEsc - return scanContinue - } - if c < 0x20 { - return s.error(c, "in string literal") - } - return scanContinue -} - -// stateInStringEsc is the state after reading `"\` during a quoted string. -func stateInStringEsc(s *scanner, c byte) int { - switch c { - case 'b', 'f', 'n', 'r', 't', '\\', '/', '"': - s.step = stateInString - return scanContinue - case 'u': - s.step = stateInStringEscU - return scanContinue - } - return s.error(c, "in string escape code") -} - -// stateInStringEscU is the state after reading `"\u` during a quoted string. -func stateInStringEscU(s *scanner, c byte) int { - if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { - s.step = stateInStringEscU1 - return scanContinue - } - // numbers - return s.error(c, "in \\u hexadecimal character escape") -} - -// stateInStringEscU1 is the state after reading `"\u1` during a quoted string. -func stateInStringEscU1(s *scanner, c byte) int { - if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { - s.step = stateInStringEscU12 - return scanContinue - } - // numbers - return s.error(c, "in \\u hexadecimal character escape") -} - -// stateInStringEscU12 is the state after reading `"\u12` during a quoted string. -func stateInStringEscU12(s *scanner, c byte) int { - if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { - s.step = stateInStringEscU123 - return scanContinue - } - // numbers - return s.error(c, "in \\u hexadecimal character escape") -} - -// stateInStringEscU123 is the state after reading `"\u123` during a quoted string. -func stateInStringEscU123(s *scanner, c byte) int { - if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { - s.step = stateInString - return scanContinue - } - // numbers - return s.error(c, "in \\u hexadecimal character escape") -} - -// stateNeg is the state after reading `-` during a number. -func stateNeg(s *scanner, c byte) int { - if c == '0' { - s.step = state0 - return scanContinue - } - if '1' <= c && c <= '9' { - s.step = state1 - return scanContinue - } - return s.error(c, "in numeric literal") -} - -// state1 is the state after reading a non-zero integer during a number, -// such as after reading `1` or `100` but not `0`. -func state1(s *scanner, c byte) int { - if '0' <= c && c <= '9' { - s.step = state1 - return scanContinue - } - return state0(s, c) -} - -// state0 is the state after reading `0` during a number. -func state0(s *scanner, c byte) int { - if c == '.' { - s.step = stateDot - return scanContinue - } - if c == 'e' || c == 'E' { - s.step = stateE - return scanContinue - } - return stateEndValue(s, c) -} - -// stateDot is the state after reading the integer and decimal point in a number, -// such as after reading `1.`. -func stateDot(s *scanner, c byte) int { - if '0' <= c && c <= '9' { - s.step = stateDot0 - return scanContinue - } - return s.error(c, "after decimal point in numeric literal") -} - -// stateDot0 is the state after reading the integer, decimal point, and subsequent -// digits of a number, such as after reading `3.14`. -func stateDot0(s *scanner, c byte) int { - if '0' <= c && c <= '9' { - return scanContinue - } - if c == 'e' || c == 'E' { - s.step = stateE - return scanContinue - } - return stateEndValue(s, c) -} - -// stateE is the state after reading the mantissa and e in a number, -// such as after reading `314e` or `0.314e`. -func stateE(s *scanner, c byte) int { - if c == '+' || c == '-' { - s.step = stateESign - return scanContinue - } - return stateESign(s, c) -} - -// stateESign is the state after reading the mantissa, e, and sign in a number, -// such as after reading `314e-` or `0.314e+`. -func stateESign(s *scanner, c byte) int { - if '0' <= c && c <= '9' { - s.step = stateE0 - return scanContinue - } - return s.error(c, "in exponent of numeric literal") -} - -// stateE0 is the state after reading the mantissa, e, optional sign, -// and at least one digit of the exponent in a number, -// such as after reading `314e-2` or `0.314e+1` or `3.14e0`. -func stateE0(s *scanner, c byte) int { - if '0' <= c && c <= '9' { - return scanContinue - } - return stateEndValue(s, c) -} - -// stateT is the state after reading `t`. -func stateT(s *scanner, c byte) int { - if c == 'r' { - s.step = stateTr - return scanContinue - } - return s.error(c, "in literal true (expecting 'r')") -} - -// stateTr is the state after reading `tr`. -func stateTr(s *scanner, c byte) int { - if c == 'u' { - s.step = stateTru - return scanContinue - } - return s.error(c, "in literal true (expecting 'u')") -} - -// stateTru is the state after reading `tru`. -func stateTru(s *scanner, c byte) int { - if c == 'e' { - s.step = stateEndValue - return scanContinue - } - return s.error(c, "in literal true (expecting 'e')") -} - -// stateF is the state after reading `f`. -func stateF(s *scanner, c byte) int { - if c == 'a' { - s.step = stateFa - return scanContinue - } - return s.error(c, "in literal false (expecting 'a')") -} - -// stateFa is the state after reading `fa`. -func stateFa(s *scanner, c byte) int { - if c == 'l' { - s.step = stateFal - return scanContinue - } - return s.error(c, "in literal false (expecting 'l')") -} - -// stateFal is the state after reading `fal`. -func stateFal(s *scanner, c byte) int { - if c == 's' { - s.step = stateFals - return scanContinue - } - return s.error(c, "in literal false (expecting 's')") -} - -// stateFals is the state after reading `fals`. -func stateFals(s *scanner, c byte) int { - if c == 'e' { - s.step = stateEndValue - return scanContinue - } - return s.error(c, "in literal false (expecting 'e')") -} - -// stateN is the state after reading `n`. -func stateN(s *scanner, c byte) int { - if c == 'u' { - s.step = stateNu - return scanContinue - } - return s.error(c, "in literal null (expecting 'u')") -} - -// stateNu is the state after reading `nu`. -func stateNu(s *scanner, c byte) int { - if c == 'l' { - s.step = stateNul - return scanContinue - } - return s.error(c, "in literal null (expecting 'l')") -} - -// stateNul is the state after reading `nul`. -func stateNul(s *scanner, c byte) int { - if c == 'l' { - s.step = stateEndValue - return scanContinue - } - return s.error(c, "in literal null (expecting 'l')") -} - -// stateError is the state after reaching a syntax error, -// such as after reading `[1}` or `5.1.2`. -func stateError(s *scanner, c byte) int { - return scanError -} - -// error records an error and switches to the error state. -func (s *scanner) error(c byte, context string) int { - s.step = stateError - s.err = &SyntaxError{"invalid character " + quoteChar(c) + " " + context, s.bytes} - return scanError -} - -// quoteChar formats c as a quoted character literal -func quoteChar(c byte) string { - // special cases - different from quoted strings - if c == '\'' { - return `'\''` - } - if c == '"' { - return `'"'` - } - - // use quoted string with different quotation marks - s := strconv.Quote(string(c)) - return "'" + s[1:len(s)-1] + "'" -} diff --git a/vendor/github.com/yaegashi/msgraph.go/jsonx/stream.go b/vendor/github.com/yaegashi/msgraph.go/jsonx/stream.go deleted file mode 100644 index 0f00c037..00000000 --- a/vendor/github.com/yaegashi/msgraph.go/jsonx/stream.go +++ /dev/null @@ -1,507 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package jsonx - -import ( - "bytes" - "errors" - "io" -) - -// A Decoder reads and decodes JSON values from an input stream. -type Decoder struct { - r io.Reader - buf []byte - d decodeState - scanp int // start of unread data in buf - scanned int64 // amount of data already scanned - scan scanner - err error - - tokenState int - tokenStack []int -} - -// NewDecoder returns a new decoder that reads from r. -// -// The decoder introduces its own buffering and may -// read data from r beyond the JSON values requested. -func NewDecoder(r io.Reader) *Decoder { - return &Decoder{r: r} -} - -// UseNumber causes the Decoder to unmarshal a number into an interface{} as a -// Number instead of as a float64. -func (dec *Decoder) UseNumber() { dec.d.useNumber = true } - -// DisallowUnknownFields causes the Decoder to return an error when the destination -// is a struct and the input contains object keys which do not match any -// non-ignored, exported fields in the destination. -func (dec *Decoder) DisallowUnknownFields() { dec.d.disallowUnknownFields = true } - -// Decode reads the next JSON-encoded value from its -// input and stores it in the value pointed to by v. -// -// See the documentation for Unmarshal for details about -// the conversion of JSON into a Go value. -func (dec *Decoder) Decode(v interface{}) error { - if dec.err != nil { - return dec.err - } - - if err := dec.tokenPrepareForDecode(); err != nil { - return err - } - - if !dec.tokenValueAllowed() { - return &SyntaxError{msg: "not at beginning of value", Offset: dec.offset()} - } - - // 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. - err = dec.d.unmarshal(v) - - // fixup token streaming state - dec.tokenValueEnd() - - return err -} - -// 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[dec.scanp:]) -} - -// readValue reads a JSON value into dec.buf. -// It returns the length of the encoding. -func (dec *Decoder) readValue() (int, error) { - dec.scan.reset() - - scanp := dec.scanp - var err error -Input: - // help the compiler see that scanp is never negative, so it can remove - // some bounds checks below. - for scanp >= 0 { - - // Look in the buffer for a new value. - for ; scanp < len(dec.buf); scanp++ { - c := dec.buf[scanp] - dec.scan.bytes++ - switch dec.scan.step(&dec.scan, c) { - case scanEnd: - break Input - case scanEndObject, scanEndArray: - // scanEnd is delayed one byte. - // We might block trying to get that byte from src, - // so instead invent a space byte. - if stateEndValue(&dec.scan, ' ') == scanEnd { - scanp++ - break Input - } - case scanError: - dec.err = dec.scan.err - return 0, dec.scan.err - } - } - - // Did the last read have an error? - // Delayed until now to allow buffer scan. - if err != nil { - if err == io.EOF { - if dec.scan.step(&dec.scan, ' ') == scanEnd { - break Input - } - if nonSpace(dec.buf) { - err = io.ErrUnexpectedEOF - } - } - dec.err = err - 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 { - dec.scanned += int64(dec.scanp) - 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 { - for _, c := range b { - if !isSpace(c) { - return true - } - } - return false -} - -// An Encoder writes JSON values to an output stream. -type Encoder struct { - w io.Writer - err error - escapeHTML bool - - indentBuf *bytes.Buffer - indentPrefix string - indentValue string -} - -// NewEncoder returns a new encoder that writes to w. -func NewEncoder(w io.Writer) *Encoder { - return &Encoder{w: w, escapeHTML: true} -} - -// Encode writes the JSON encoding of v to the stream, -// followed by a newline character. -// -// See the documentation for Marshal for details about the -// conversion of Go values to JSON. -func (enc *Encoder) Encode(v interface{}) error { - if enc.err != nil { - return enc.err - } - e := newEncodeState() - err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML}) - if err != nil { - return err - } - - // Terminate each value with a newline. - // This makes the output look a little nicer - // when debugging, and some kind of space - // is required if the encoded value was a number, - // so that the reader knows there aren't more - // digits coming. - e.WriteByte('\n') - - b := e.Bytes() - if enc.indentPrefix != "" || enc.indentValue != "" { - if enc.indentBuf == nil { - enc.indentBuf = new(bytes.Buffer) - } - enc.indentBuf.Reset() - err = Indent(enc.indentBuf, b, enc.indentPrefix, enc.indentValue) - if err != nil { - return err - } - b = enc.indentBuf.Bytes() - } - if _, err = enc.w.Write(b); err != nil { - enc.err = err - } - encodeStatePool.Put(e) - return err -} - -// SetIndent instructs the encoder to format each subsequent encoded -// value as if indented by the package-level function Indent(dst, src, prefix, indent). -// Calling SetIndent("", "") disables indentation. -func (enc *Encoder) SetIndent(prefix, indent string) { - enc.indentPrefix = prefix - enc.indentValue = indent -} - -// SetEscapeHTML specifies whether problematic HTML characters -// should be escaped inside JSON quoted strings. -// The default behavior is to escape &, <, and > to \u0026, \u003c, and \u003e -// to avoid certain safety problems that can arise when embedding JSON in HTML. -// -// In non-HTML settings where the escaping interferes with the readability -// of the output, SetEscapeHTML(false) disables this behavior. -func (enc *Encoder) SetEscapeHTML(on bool) { - enc.escapeHTML = on -} - -// RawMessage is a raw encoded JSON value. -// It implements Marshaler and Unmarshaler and can -// be used to delay JSON decoding or precompute a JSON encoding. -type RawMessage []byte - -// MarshalJSON returns m as the JSON encoding of m. -func (m RawMessage) MarshalJSON() ([]byte, error) { - if m == nil { - return []byte("null"), nil - } - return m, nil -} - -// UnmarshalJSON sets *m to a copy of data. -func (m *RawMessage) UnmarshalJSON(data []byte) error { - if m == nil { - return errors.New("json.RawMessage: UnmarshalJSON on nil pointer") - } - *m = append((*m)[0:0], data...) - return nil -} - -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", dec.offset()} - } - 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", dec.offset()} - } - 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 { - 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 { - return nil, err - } - return x, nil - } - } -} - -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(c) + context, dec.offset()} -} - -// 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(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() - } -} - -func (dec *Decoder) offset() int64 { - return dec.scanned + int64(dec.scanp) -} diff --git a/vendor/github.com/yaegashi/msgraph.go/jsonx/tables.go b/vendor/github.com/yaegashi/msgraph.go/jsonx/tables.go deleted file mode 100644 index cb994a3e..00000000 --- a/vendor/github.com/yaegashi/msgraph.go/jsonx/tables.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package jsonx - -import "unicode/utf8" - -// safeSet holds the value true if the ASCII character with the given array -// position can be represented inside a JSON string without any further -// escaping. -// -// All values are true except for the ASCII control characters (0-31), the -// double quote ("), and the backslash character ("\"). -var safeSet = [utf8.RuneSelf]bool{ - ' ': true, - '!': true, - '"': false, - '#': true, - '$': true, - '%': true, - '&': true, - '\'': true, - '(': true, - ')': true, - '*': true, - '+': true, - ',': true, - '-': true, - '.': true, - '/': true, - '0': true, - '1': true, - '2': true, - '3': true, - '4': true, - '5': true, - '6': true, - '7': true, - '8': true, - '9': true, - ':': true, - ';': true, - '<': true, - '=': true, - '>': true, - '?': true, - '@': true, - 'A': true, - 'B': true, - 'C': true, - 'D': true, - 'E': true, - 'F': true, - 'G': true, - 'H': true, - 'I': true, - 'J': true, - 'K': true, - 'L': true, - 'M': true, - 'N': true, - 'O': true, - 'P': true, - 'Q': true, - 'R': true, - 'S': true, - 'T': true, - 'U': true, - 'V': true, - 'W': true, - 'X': true, - 'Y': true, - 'Z': true, - '[': true, - '\\': false, - ']': true, - '^': true, - '_': true, - '`': true, - 'a': true, - 'b': true, - 'c': true, - 'd': true, - 'e': true, - 'f': true, - 'g': true, - 'h': true, - 'i': true, - 'j': true, - 'k': true, - 'l': true, - 'm': true, - 'n': true, - 'o': true, - 'p': true, - 'q': true, - 'r': true, - 's': true, - 't': true, - 'u': true, - 'v': true, - 'w': true, - 'x': true, - 'y': true, - 'z': true, - '{': true, - '|': true, - '}': true, - '~': true, - '\u007f': true, -} - -// htmlSafeSet holds the value true if the ASCII character with the given -// array position can be safely represented inside a JSON string, embedded -// inside of HTML <script> tags, without any additional escaping. -// -// All values are true except for the ASCII control characters (0-31), the -// double quote ("), the backslash character ("\"), HTML opening and closing -// tags ("<" and ">"), and the ampersand ("&"). -var htmlSafeSet = [utf8.RuneSelf]bool{ - ' ': true, - '!': true, - '"': false, - '#': true, - '$': true, - '%': true, - '&': false, - '\'': true, - '(': true, - ')': true, - '*': true, - '+': true, - ',': true, - '-': true, - '.': true, - '/': true, - '0': true, - '1': true, - '2': true, - '3': true, - '4': true, - '5': true, - '6': true, - '7': true, - '8': true, - '9': true, - ':': true, - ';': true, - '<': false, - '=': true, - '>': false, - '?': true, - '@': true, - 'A': true, - 'B': true, - 'C': true, - 'D': true, - 'E': true, - 'F': true, - 'G': true, - 'H': true, - 'I': true, - 'J': true, - 'K': true, - 'L': true, - 'M': true, - 'N': true, - 'O': true, - 'P': true, - 'Q': true, - 'R': true, - 'S': true, - 'T': true, - 'U': true, - 'V': true, - 'W': true, - 'X': true, - 'Y': true, - 'Z': true, - '[': true, - '\\': false, - ']': true, - '^': true, - '_': true, - '`': true, - 'a': true, - 'b': true, - 'c': true, - 'd': true, - 'e': true, - 'f': true, - 'g': true, - 'h': true, - 'i': true, - 'j': true, - 'k': true, - 'l': true, - 'm': true, - 'n': true, - 'o': true, - 'p': true, - 'q': true, - 'r': true, - 's': true, - 't': true, - 'u': true, - 'v': true, - 'w': true, - 'x': true, - 'y': true, - 'z': true, - '{': true, - '|': true, - '}': true, - '~': true, - '\u007f': true, -} diff --git a/vendor/github.com/yaegashi/msgraph.go/jsonx/tags.go b/vendor/github.com/yaegashi/msgraph.go/jsonx/tags.go deleted file mode 100644 index e524e12e..00000000 --- a/vendor/github.com/yaegashi/msgraph.go/jsonx/tags.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package jsonx - -import ( - "strings" -) - -// tagOptions is the string following a comma in a struct field's "json" -// tag, or the empty string. It does not include the leading comma. -type tagOptions string - -// parseTag splits a struct field's json tag into its name and -// comma-separated options. -func parseTag(tag string) (string, tagOptions) { - if idx := strings.Index(tag, ","); idx != -1 { - return tag[:idx], tagOptions(tag[idx+1:]) - } - return tag, tagOptions("") -} - -// Contains reports whether a comma-separated list of options -// contains a particular substr flag. substr must be surrounded by a -// string boundary or commas. -func (o tagOptions) Contains(optionName string) bool { - if len(o) == 0 { - return false - } - s := string(o) - for s != "" { - var next string - i := strings.Index(s, ",") - if i >= 0 { - s, next = s[:i], s[i+1:] - } - if s == optionName { - return true - } - s = next - } - return false -} |