├── .github └── workflows │ └── ci.yml ├── LICENSE ├── README.md ├── decode.go ├── decode_test.go ├── fold.go ├── fold_test.go ├── go.mod ├── go.sum ├── json5_test.go ├── number_test.go ├── scanner.go ├── scanner_test.go ├── stream.go ├── stream_test.go ├── tags.go ├── tags_test.go ├── testdata ├── arrays │ ├── empty-array.json │ ├── leading-comma-array.js │ ├── lone-trailing-comma-array.js │ ├── no-comma-array.errorSpec │ ├── no-comma-array.txt │ ├── regular-array.json │ └── trailing-comma-array.json5 ├── comments │ ├── block-comment-following-array-element.json5 │ ├── block-comment-following-top-level-value.json5 │ ├── block-comment-in-string.json │ ├── block-comment-preceding-top-level-value.json5 │ ├── block-comment-with-asterisks.json5 │ ├── inline-comment-following-array-element.json5 │ ├── inline-comment-following-top-level-value.json5 │ ├── inline-comment-in-string.json │ ├── inline-comment-preceding-top-level-value.json5 │ ├── top-level-block-comment.errorSpec │ ├── top-level-block-comment.txt │ ├── top-level-inline-comment.errorSpec │ └── top-level-inline-comment.txt ├── misc │ ├── empty.txt │ ├── npm-package.json │ ├── npm-package.json5 │ ├── readme-example.json5 │ └── valid-whitespace.json5 ├── new-lines │ ├── .editorconfig │ ├── .gitattributes │ ├── comment-cr.json5 │ ├── comment-crlf.json5 │ ├── comment-lf.json5 │ ├── escaped-cr.json5 │ ├── escaped-crlf.json5 │ └── escaped-lf.json5 ├── numbers │ ├── float-leading-decimal-point.json5 │ ├── float-leading-zero.json │ ├── float-trailing-decimal-point-with-integer-exponent.json5 │ ├── float-trailing-decimal-point.json5 │ ├── float-with-integer-exponent.json │ ├── float.json │ ├── hexadecimal-empty.txt │ ├── hexadecimal-lowercase-letter.json5 │ ├── hexadecimal-uppercase-x.json5 │ ├── hexadecimal-with-integer-exponent.json5 │ ├── hexadecimal.json5 │ ├── infinity.json5 │ ├── integer-with-float-exponent.txt │ ├── integer-with-hexadecimal-exponent.txt │ ├── integer-with-integer-exponent.json │ ├── integer-with-negative-float-exponent.txt │ ├── integer-with-negative-hexadecimal-exponent.txt │ ├── integer-with-negative-integer-exponent.json │ ├── integer-with-negative-zero-integer-exponent.json │ ├── integer-with-positive-float-exponent.txt │ ├── integer-with-positive-hexadecimal-exponent.txt │ ├── integer-with-positive-integer-exponent.json │ ├── integer-with-positive-zero-integer-exponent.json │ ├── integer-with-zero-integer-exponent.json │ ├── integer.json │ ├── lone-decimal-point.txt │ ├── nan.json5 │ ├── negative-float-leading-decimal-point.json5 │ ├── negative-float-leading-zero.json │ ├── negative-float-trailing-decimal-point.json5 │ ├── negative-float.json │ ├── negative-hexadecimal.json5 │ ├── negative-infinity.json5 │ ├── negative-integer.json │ ├── negative-octal.txt │ ├── negative-zero-float-leading-decimal-point.json5 │ ├── negative-zero-float-trailing-decimal-point.json5 │ ├── negative-zero-float.json │ ├── negative-zero-hexadecimal.json5 │ ├── negative-zero-integer.json │ ├── negative-zero-octal.txt │ ├── octal.txt │ ├── positive-float-leading-decimal-point.json5 │ ├── positive-float-leading-zero.json5 │ ├── positive-float-trailing-decimal-point.json5 │ ├── positive-float.json5 │ ├── positive-hexadecimal.json5 │ ├── positive-infinity.json5 │ ├── positive-integer.json5 │ ├── positive-octal.txt │ ├── positive-zero-float-leading-decimal-point.json5 │ ├── positive-zero-float-trailing-decimal-point.json5 │ ├── positive-zero-float.json5 │ ├── positive-zero-hexadecimal.json5 │ ├── positive-zero-integer.json5 │ ├── positive-zero-octal.txt │ ├── zero-float-leading-decimal-point.json5 │ ├── zero-float-trailing-decimal-point.json5 │ ├── zero-float.json │ ├── zero-hexadecimal.json5 │ ├── zero-integer-with-integer-exponent.json │ ├── zero-integer.json │ └── zero-octal.txt ├── objects │ ├── duplicate-keys.json │ ├── empty-object.json │ ├── illegal-unquoted-key-number.errorSpec │ ├── illegal-unquoted-key-number.txt │ ├── illegal-unquoted-key-symbol.errorSpec │ ├── illegal-unquoted-key-symbol.txt │ ├── leading-comma-object.errorSpec │ ├── leading-comma-object.txt │ ├── lone-trailing-comma-object.txt │ ├── no-comma-object.txt │ ├── reserved-unquoted-key.json5 │ ├── single-quoted-key.json5 │ ├── trailing-comma-object.json5 │ └── unquoted-keys.json5 └── strings │ ├── escaped-single-quoted-string.json5 │ ├── multi-line-string.json5 │ ├── no-comma-array.errorSpec │ ├── single-quoted-string.json5 │ ├── unescaped-multi-line-string.errorSpec │ └── unescaped-multi-line-string.txt └── types.go /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v3 10 | 11 | - name: Setup Go 12 | uses: actions/setup-go@v3 13 | with: 14 | go-version: "stable" 15 | 16 | - name: Test 17 | run: go test -v ./... 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Decoder code based on package encoding/json from the Go language. 2 | 3 | Copyright (c) 2012 The Go Authors. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following disclaimer 13 | in the documentation and/or other materials provided with the 14 | distribution. 15 | * Neither the name of Google Inc. nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | 32 | 33 | Test data based on the parse cases from https://github.com/json5/json5 34 | 35 | Copyright (c) 2012-2016 Aseem Kishore, and others. 36 | 37 | Permission is hereby granted, free of charge, to any person obtaining 38 | a copy of this software and associated documentation files (the 39 | "Software"), to deal in the Software without restriction, including 40 | without limitation the rights to use, copy, modify, merge, publish, 41 | distribute, sublicense, and/or sell copies of the Software, and to 42 | permit persons to whom the Software is furnished to do so, subject to 43 | the following conditions: 44 | 45 | The above copyright notice and this permission notice shall be 46 | included in all copies or substantial portions of the Software. 47 | 48 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 49 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 50 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 51 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 52 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 53 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 54 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # json5 [![GoDoc](https://godoc.org/github.com/titanous/json5?status.svg)](https://godoc.org/github.com/titanous/json5) [![Build Status](https://github.com/titanous/json5/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/titanous/json5/actions/workflows/ci.yml) 2 | 3 | This is a Go package that implements decoding of 4 | [JSON5](https://github.com/json5/json5). See [the 5 | documentation](https://godoc.org/github.com/titanous/json5) for usage information. 6 | -------------------------------------------------------------------------------- /decode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package json5 implements decoding of JSON5 values. 6 | package json5 7 | 8 | import ( 9 | "bytes" 10 | "encoding" 11 | "encoding/base64" 12 | "errors" 13 | "fmt" 14 | "math" 15 | "reflect" 16 | "runtime" 17 | "strconv" 18 | "unicode" 19 | "unicode/utf16" 20 | "unicode/utf8" 21 | ) 22 | 23 | // Unmarshal parses the JSON-encoded data and stores the result 24 | // in the value pointed to by v. 25 | // 26 | // Unmarshal uses the inverse of the encodings that 27 | // Marshal uses, allocating maps, slices, and pointers as necessary, 28 | // with the following additional rules: 29 | // 30 | // To unmarshal JSON into a pointer, Unmarshal first handles the case of 31 | // the JSON being the JSON literal null. In that case, Unmarshal sets 32 | // the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into 33 | // the value pointed at by the pointer. If the pointer is nil, Unmarshal 34 | // allocates a new value for it to point to. 35 | // 36 | // To unmarshal JSON into a struct, Unmarshal matches incoming object 37 | // keys to the keys used by Marshal (either the struct field name or its tag), 38 | // preferring an exact match but also accepting a case-insensitive match. 39 | // Unmarshal will only set exported fields of the struct. 40 | // 41 | // To unmarshal JSON into an interface value, 42 | // Unmarshal stores one of these in the interface value: 43 | // 44 | // bool, for JSON booleans 45 | // float64, for JSON numbers 46 | // string, for JSON strings 47 | // []interface{}, for JSON arrays 48 | // map[string]interface{}, for JSON objects 49 | // nil for JSON null 50 | // 51 | // To unmarshal a JSON array into a slice, Unmarshal resets the slice length 52 | // to zero and then appends each element to the slice. 53 | // As a special case, to unmarshal an empty JSON array into a slice, 54 | // Unmarshal replaces the slice with a new empty slice. 55 | // 56 | // To unmarshal a JSON array into a Go array, Unmarshal decodes 57 | // JSON array elements into corresponding Go array elements. 58 | // If the Go array is smaller than the JSON array, 59 | // the additional JSON array elements are discarded. 60 | // If the JSON array is smaller than the Go array, 61 | // the additional Go array elements are set to zero values. 62 | // 63 | // To unmarshal a JSON object into a map, Unmarshal first establishes a map to 64 | // use, If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal 65 | // reuses the existing map, keeping existing entries. Unmarshal then stores key- 66 | // value pairs from the JSON object into the map. The map's key type must 67 | // either be a string or implement encoding.TextUnmarshaler. 68 | // 69 | // If a JSON value is not appropriate for a given target type, 70 | // or if a JSON number overflows the target type, Unmarshal 71 | // skips that field and completes the unmarshaling as best it can. 72 | // If no more serious errors are encountered, Unmarshal returns 73 | // an UnmarshalTypeError describing the earliest such error. 74 | // 75 | // The JSON null value unmarshals into an interface, map, pointer, or slice 76 | // by setting that Go value to nil. Because null is often used in JSON to mean 77 | // “not present,” unmarshaling a JSON null into any other Go type has no effect 78 | // on the value and produces no error. 79 | // 80 | // When unmarshaling quoted strings, invalid UTF-8 or 81 | // invalid UTF-16 surrogate pairs are not treated as an error. 82 | // Instead, they are replaced by the Unicode replacement 83 | // character U+FFFD. 84 | func Unmarshal(data []byte, v interface{}) error { 85 | // Check for well-formedness. 86 | // Avoids filling out half a data structure 87 | // before discovering a JSON syntax error. 88 | var d decodeState 89 | err := checkValid(data, &d.scan) 90 | if err != nil { 91 | return err 92 | } 93 | 94 | d.init(data) 95 | return d.unmarshal(v) 96 | } 97 | 98 | // Unmarshaler is the interface implemented by types 99 | // that can unmarshal a JSON description of themselves. 100 | // The input can be assumed to be a valid encoding of 101 | // a JSON value. UnmarshalJSON must copy the JSON data 102 | // if it wishes to retain the data after returning. 103 | type Unmarshaler interface { 104 | UnmarshalJSON([]byte) error 105 | } 106 | 107 | // An UnmarshalTypeError describes a JSON value that was 108 | // not appropriate for a value of a specific Go type. 109 | type UnmarshalTypeError struct { 110 | Value string // description of JSON value - "bool", "array", "number -5" 111 | Type reflect.Type // type of Go value it could not be assigned to 112 | Offset int64 // error occurred after reading Offset bytes 113 | } 114 | 115 | func (e *UnmarshalTypeError) Error() string { 116 | return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() 117 | } 118 | 119 | // An UnmarshalFieldError describes a JSON object key that 120 | // led to an unexported (and therefore unwritable) struct field. 121 | // (No longer used; kept for compatibility.) 122 | type UnmarshalFieldError struct { 123 | Key string 124 | Type reflect.Type 125 | Field reflect.StructField 126 | } 127 | 128 | func (e *UnmarshalFieldError) Error() string { 129 | return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() 130 | } 131 | 132 | // An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. 133 | // (The argument to Unmarshal must be a non-nil pointer.) 134 | type InvalidUnmarshalError struct { 135 | Type reflect.Type 136 | } 137 | 138 | func (e *InvalidUnmarshalError) Error() string { 139 | if e.Type == nil { 140 | return "json: Unmarshal(nil)" 141 | } 142 | 143 | if e.Type.Kind() != reflect.Ptr { 144 | return "json: Unmarshal(non-pointer " + e.Type.String() + ")" 145 | } 146 | return "json: Unmarshal(nil " + e.Type.String() + ")" 147 | } 148 | 149 | func (d *decodeState) unmarshal(v interface{}) (err error) { 150 | defer func() { 151 | if r := recover(); r != nil { 152 | if _, ok := r.(runtime.Error); ok { 153 | panic(r) 154 | } 155 | err = r.(error) 156 | } 157 | }() 158 | 159 | rv := reflect.ValueOf(v) 160 | if rv.Kind() != reflect.Ptr || rv.IsNil() { 161 | return &InvalidUnmarshalError{reflect.TypeOf(v)} 162 | } 163 | 164 | d.scan.reset() 165 | // We decode rv not rv.Elem because the Unmarshaler interface 166 | // test must be applied at the top level of the value. 167 | d.value(rv) 168 | return d.savedError 169 | } 170 | 171 | // A Number represents a JSON number literal. 172 | type Number string 173 | 174 | // String returns the literal text of the number. 175 | func (n Number) String() string { return string(n) } 176 | 177 | // Float64 returns the number as a float64. 178 | func (n Number) Float64() (float64, error) { 179 | if h, ok := hexString(string(n)); ok { 180 | n, err := strconv.ParseInt(h, 16, 64) 181 | if err != nil { 182 | return 0, err 183 | } 184 | f := float64(n) 185 | if h[0] == '-' && n == 0 { 186 | f = -f 187 | } 188 | return f, nil 189 | } 190 | return strconv.ParseFloat(string(n), 64) 191 | } 192 | 193 | // Int64 returns the number as an int64. 194 | func (n Number) Int64() (int64, error) { 195 | if h, ok := hexString(string(n)); ok { 196 | return strconv.ParseInt(h, 16, 64) 197 | } 198 | return strconv.ParseInt(string(n), 10, 64) 199 | } 200 | 201 | // isValidNumber reports whether s is a valid JSON number literal. 202 | func isValidNumber(s string) bool { 203 | // This function implements the JSON numbers grammar. 204 | // See https://tools.ietf.org/html/rfc7159#section-6 205 | // and http://json.org/number.gif 206 | 207 | if s == "" { 208 | return false 209 | } 210 | 211 | if s == "NaN" { 212 | return true 213 | } 214 | 215 | // Optional -/+ 216 | if s[0] == '-' || s[0] == '+' { 217 | s = s[1:] 218 | if s == "" { 219 | return false 220 | } 221 | } 222 | 223 | if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') { 224 | s = s[2:] 225 | for len(s) > 0 { 226 | if (s[0] >= '0' && s[0] <= '9') || (s[0] >= 'a' && s[0] <= 'f') || (s[0] >= 'A' && s[0] <= 'F') { 227 | s = s[1:] 228 | continue 229 | } 230 | return false 231 | } 232 | return true 233 | } 234 | 235 | // Digits 236 | switch { 237 | default: 238 | return false 239 | 240 | case s == "Infinity": 241 | return true 242 | 243 | case s[0] == '0': 244 | s = s[1:] 245 | 246 | case s[0] == '.': 247 | if len(s) == 1 { 248 | return false 249 | } 250 | 251 | case '1' <= s[0] && s[0] <= '9': 252 | s = s[1:] 253 | for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { 254 | s = s[1:] 255 | } 256 | } 257 | 258 | // decimal followed by 0 or more digits 259 | if len(s) > 0 && s[0] == '.' { 260 | s = s[1:] 261 | for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { 262 | s = s[1:] 263 | } 264 | } 265 | 266 | // e or E followed by an optional - or + and 267 | // 1 or more digits. 268 | if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') { 269 | s = s[1:] 270 | if s[0] == '+' || s[0] == '-' { 271 | s = s[1:] 272 | if s == "" { 273 | return false 274 | } 275 | } 276 | for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { 277 | s = s[1:] 278 | } 279 | } 280 | 281 | // Make sure we are at the end. 282 | return s == "" 283 | } 284 | 285 | // decodeState represents the state while decoding a JSON value. 286 | type decodeState struct { 287 | data []byte 288 | off int // read offset in data 289 | scan scanner 290 | nextscan scanner // for calls to nextValue 291 | 292 | savedError error 293 | useNumber bool 294 | disallowUnknownFields bool 295 | } 296 | 297 | // errPhase is used for errors that should not happen unless 298 | // there is a bug in the JSON decoder or something is editing 299 | // the data slice while the decoder executes. 300 | var errPhase = errors.New("JSON decoder out of sync - data changing underfoot?") 301 | 302 | func (d *decodeState) init(data []byte) *decodeState { 303 | d.data = data 304 | d.off = 0 305 | d.savedError = nil 306 | return d 307 | } 308 | 309 | // error aborts the decoding by panicking with err. 310 | func (d *decodeState) error(err error) { 311 | panic(err) 312 | } 313 | 314 | // saveError saves the first err it is called with, 315 | // for reporting at the end of the unmarshal. 316 | func (d *decodeState) saveError(err error) { 317 | if d.savedError == nil { 318 | d.savedError = err 319 | } 320 | } 321 | 322 | // next cuts off and returns the next full JSON value in d.data[d.off:]. 323 | // The next value is known to be an object or array, not a literal. 324 | func (d *decodeState) next() []byte { 325 | c := d.data[d.off] 326 | item, rest, err := nextValue(d.data[d.off:], &d.nextscan) 327 | if err != nil { 328 | d.error(err) 329 | } 330 | d.off = len(d.data) - len(rest) 331 | 332 | // Our scanner has seen the opening brace/bracket 333 | // and thinks we're still in the middle of the object. 334 | // invent a closing brace/bracket to get it out. 335 | if c == '{' { 336 | d.scan.step(&d.scan, '}') 337 | } else { 338 | d.scan.step(&d.scan, ']') 339 | } 340 | 341 | return item 342 | } 343 | 344 | // scanWhile processes bytes in d.data[d.off:] until it 345 | // receives a scan code not equal to op. 346 | // It updates d.off and returns the new scan code. 347 | func (d *decodeState) scanWhile(op int) int { 348 | var newOp int 349 | for { 350 | if d.off >= len(d.data) { 351 | newOp = d.scan.eof() 352 | d.off = len(d.data) + 1 // mark processed EOF with len+1 353 | } else { 354 | c := d.data[d.off] 355 | d.off++ 356 | newOp = d.scan.step(&d.scan, c) 357 | } 358 | if newOp != op { 359 | break 360 | } 361 | } 362 | return newOp 363 | } 364 | 365 | // value decodes a JSON value from d.data[d.off:] into the value. 366 | // it updates d.off to point past the decoded value. 367 | func (d *decodeState) value(v reflect.Value) { 368 | if !v.IsValid() { 369 | _, rest, err := nextValue(d.data[d.off:], &d.nextscan) 370 | if err != nil { 371 | d.error(err) 372 | } 373 | d.off = len(d.data) - len(rest) 374 | 375 | // d.scan thinks we're still at the beginning of the item. 376 | // Feed in an empty string - the shortest, simplest value - 377 | // so that it knows we got to the end of the value. 378 | if d.scan.redo { 379 | // rewind. 380 | d.scan.redo = false 381 | d.scan.step = stateBeginValue 382 | } 383 | d.scan.step(&d.scan, '"') 384 | d.scan.step(&d.scan, '"') 385 | 386 | n := len(d.scan.parseState) 387 | if n > 0 && d.scan.parseState[n-1] == parseObjectKey { 388 | // d.scan thinks we just read an object key; finish the object 389 | d.scan.step(&d.scan, ':') 390 | d.scan.step(&d.scan, '"') 391 | d.scan.step(&d.scan, '"') 392 | d.scan.step(&d.scan, '}') 393 | } 394 | 395 | return 396 | } 397 | 398 | switch op := d.scanWhile(scanSkipSpace); op { 399 | default: 400 | d.error(errPhase) 401 | 402 | case scanBeginArray: 403 | d.array(v) 404 | 405 | case scanBeginObject: 406 | d.object(v) 407 | 408 | case scanBeginLiteral: 409 | d.literal(v) 410 | } 411 | } 412 | 413 | type unquotedValue struct{} 414 | 415 | // valueQuoted is like value but decodes a 416 | // quoted string literal or literal null into an interface value. 417 | // If it finds anything other than a quoted string literal or null, 418 | // valueQuoted returns unquotedValue{}. 419 | func (d *decodeState) valueQuoted() interface{} { 420 | switch op := d.scanWhile(scanSkipSpace); op { 421 | default: 422 | d.error(errPhase) 423 | 424 | case scanBeginArray: 425 | d.array(reflect.Value{}) 426 | 427 | case scanBeginObject: 428 | d.object(reflect.Value{}) 429 | 430 | case scanBeginLiteral: 431 | switch v := d.literalInterface().(type) { 432 | case nil, string: 433 | return v 434 | } 435 | } 436 | return unquotedValue{} 437 | } 438 | 439 | // indirect walks down v allocating pointers as needed, 440 | // until it gets to a non-pointer. 441 | // if it encounters an Unmarshaler, indirect stops and returns that. 442 | // if decodingNull is true, indirect stops at the last pointer so it can be set to nil. 443 | func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { 444 | // If v is a named type and is addressable, 445 | // start with its address, so that if the type has pointer methods, 446 | // we find them. 447 | if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { 448 | v = v.Addr() 449 | } 450 | for { 451 | // Load value from interface, but only if the result will be 452 | // usefully addressable. 453 | if v.Kind() == reflect.Interface && !v.IsNil() { 454 | e := v.Elem() 455 | if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { 456 | v = e 457 | continue 458 | } 459 | } 460 | 461 | if v.Kind() != reflect.Ptr { 462 | break 463 | } 464 | 465 | if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() { 466 | break 467 | } 468 | if v.IsNil() { 469 | v.Set(reflect.New(v.Type().Elem())) 470 | } 471 | if v.Type().NumMethod() > 0 { 472 | if u, ok := v.Interface().(Unmarshaler); ok { 473 | return u, nil, reflect.Value{} 474 | } 475 | if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { 476 | return nil, u, reflect.Value{} 477 | } 478 | } 479 | v = v.Elem() 480 | } 481 | return nil, nil, v 482 | } 483 | 484 | // array consumes an array from d.data[d.off-1:], decoding into the value v. 485 | // the first byte of the array ('[') has been read already. 486 | func (d *decodeState) array(v reflect.Value) { 487 | // Check for unmarshaler. 488 | u, ut, pv := d.indirect(v, false) 489 | if u != nil { 490 | d.off-- 491 | err := u.UnmarshalJSON(d.next()) 492 | if err != nil { 493 | d.error(err) 494 | } 495 | return 496 | } 497 | if ut != nil { 498 | d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) 499 | d.off-- 500 | d.next() 501 | return 502 | } 503 | 504 | v = pv 505 | 506 | // Check type of target. 507 | switch v.Kind() { 508 | case reflect.Interface: 509 | if v.NumMethod() == 0 { 510 | // Decoding into nil interface? Switch to non-reflect code. 511 | v.Set(reflect.ValueOf(d.arrayInterface())) 512 | return 513 | } 514 | // Otherwise it's invalid. 515 | fallthrough 516 | default: 517 | d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) 518 | d.off-- 519 | d.next() 520 | return 521 | case reflect.Array: 522 | case reflect.Slice: 523 | break 524 | } 525 | 526 | i := 0 527 | for { 528 | // Look ahead for ] - can only happen on first iteration. 529 | op := d.scanWhile(scanSkipSpace) 530 | if op == scanEndArray { 531 | break 532 | } 533 | 534 | // Back up so d.value can have the byte we just read. 535 | d.off-- 536 | d.scan.undo(op) 537 | 538 | // Get element of array, growing if necessary. 539 | if v.Kind() == reflect.Slice { 540 | // Grow slice if necessary 541 | if i >= v.Cap() { 542 | newcap := v.Cap() + v.Cap()/2 543 | if newcap < 4 { 544 | newcap = 4 545 | } 546 | newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) 547 | reflect.Copy(newv, v) 548 | v.Set(newv) 549 | } 550 | if i >= v.Len() { 551 | v.SetLen(i + 1) 552 | } 553 | } 554 | 555 | if i < v.Len() { 556 | // Decode into element. 557 | d.value(v.Index(i)) 558 | } else { 559 | // Ran out of fixed array: skip. 560 | d.value(reflect.Value{}) 561 | } 562 | i++ 563 | 564 | // Next token must be , or ]. 565 | op = d.scanWhile(scanSkipSpace) 566 | if op == scanEndArray { 567 | break 568 | } 569 | if op != scanArrayValue { 570 | d.error(errPhase) 571 | } 572 | } 573 | 574 | if i < v.Len() { 575 | if v.Kind() == reflect.Array { 576 | // Array. Zero the rest. 577 | z := reflect.Zero(v.Type().Elem()) 578 | for ; i < v.Len(); i++ { 579 | v.Index(i).Set(z) 580 | } 581 | } else { 582 | v.SetLen(i) 583 | } 584 | } 585 | if i == 0 && v.Kind() == reflect.Slice { 586 | v.Set(reflect.MakeSlice(v.Type(), 0, 0)) 587 | } 588 | } 589 | 590 | var nullLiteral = []byte("null") 591 | var textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem() 592 | 593 | // object consumes an object from d.data[d.off-1:], decoding into the value v. 594 | // the first byte ('{') of the object has been read already. 595 | func (d *decodeState) object(v reflect.Value) { 596 | // Check for unmarshaler. 597 | u, ut, pv := d.indirect(v, false) 598 | if u != nil { 599 | d.off-- 600 | err := u.UnmarshalJSON(d.next()) 601 | if err != nil { 602 | d.error(err) 603 | } 604 | return 605 | } 606 | if ut != nil { 607 | d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) 608 | d.off-- 609 | d.next() // skip over { } in input 610 | return 611 | } 612 | v = pv 613 | 614 | // Decoding into nil interface? Switch to non-reflect code. 615 | if v.Kind() == reflect.Interface && v.NumMethod() == 0 { 616 | v.Set(reflect.ValueOf(d.objectInterface())) 617 | return 618 | } 619 | 620 | // Check type of target: 621 | // struct or 622 | // map[string]T or map[encoding.TextUnmarshaler]T 623 | switch v.Kind() { 624 | case reflect.Map: 625 | // Map key must either have string kind or be an encoding.TextUnmarshaler. 626 | t := v.Type() 627 | if t.Key().Kind() != reflect.String && 628 | !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { 629 | d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) 630 | d.off-- 631 | d.next() // skip over { } in input 632 | return 633 | } 634 | if v.IsNil() { 635 | v.Set(reflect.MakeMap(t)) 636 | } 637 | case reflect.Struct: 638 | 639 | default: 640 | d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) 641 | d.off-- 642 | d.next() // skip over { } in input 643 | return 644 | } 645 | 646 | var mapElem reflect.Value 647 | 648 | for { 649 | // Read opening " of string key or closing }. 650 | op := d.scanWhile(scanSkipSpace) 651 | if op == scanEndObject { 652 | // closing } - can only happen on first iteration. 653 | break 654 | } 655 | if op != scanBeginLiteral { 656 | d.error(errPhase) 657 | } 658 | 659 | // Read key. 660 | start := d.off - 1 661 | op = d.scanWhile(scanContinue) 662 | key := d.data[start : d.off-1] 663 | if key[0] == '"' || key[0] == '\'' { 664 | var ok bool 665 | key, ok = unquoteBytes(key) 666 | if !ok { 667 | d.error(errPhase) 668 | } 669 | } 670 | 671 | // Figure out field corresponding to key. 672 | var subv reflect.Value 673 | destring := false // whether the value is wrapped in a string to be decoded first 674 | 675 | if v.Kind() == reflect.Map { 676 | elemType := v.Type().Elem() 677 | if !mapElem.IsValid() { 678 | mapElem = reflect.New(elemType).Elem() 679 | } else { 680 | mapElem.Set(reflect.Zero(elemType)) 681 | } 682 | subv = mapElem 683 | } else { 684 | var f *field 685 | fields := cachedTypeFields(v.Type()) 686 | for i := range fields { 687 | ff := &fields[i] 688 | if bytes.Equal(ff.nameBytes, key) { 689 | f = ff 690 | break 691 | } 692 | if f == nil && ff.equalFold(ff.nameBytes, key) { 693 | f = ff 694 | } 695 | } 696 | if f != nil { 697 | subv = v 698 | destring = f.quoted 699 | for _, i := range f.index { 700 | if subv.Kind() == reflect.Ptr { 701 | if subv.IsNil() { 702 | subv.Set(reflect.New(subv.Type().Elem())) 703 | } 704 | subv = subv.Elem() 705 | } 706 | subv = subv.Field(i) 707 | } 708 | } else if d.disallowUnknownFields { 709 | d.saveError(fmt.Errorf("json: unknown field %q", key)) 710 | } 711 | } 712 | 713 | // Read : before value. 714 | if op == scanSkipSpace { 715 | op = d.scanWhile(scanSkipSpace) 716 | } 717 | if op != scanObjectKey { 718 | d.error(errPhase) 719 | } 720 | 721 | // Read value. 722 | if destring { 723 | switch qv := d.valueQuoted().(type) { 724 | case nil: 725 | d.literalStore(nullLiteral, subv, false, false) 726 | case string: 727 | d.literalStore([]byte(qv), subv, true, false) 728 | default: 729 | d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) 730 | } 731 | } else { 732 | d.value(subv) 733 | } 734 | 735 | // Write value back to map; 736 | // if using struct, subv points into struct already. 737 | if v.Kind() == reflect.Map { 738 | kt := v.Type().Key() 739 | var kv reflect.Value 740 | switch { 741 | case kt.Kind() == reflect.String: 742 | kv = reflect.ValueOf(key).Convert(v.Type().Key()) 743 | case reflect.PtrTo(kt).Implements(textUnmarshalerType): 744 | kv = reflect.New(v.Type().Key()) 745 | d.literalStore(key, kv, true, true) 746 | kv = kv.Elem() 747 | default: 748 | panic("json: Unexpected key type") // should never occur 749 | } 750 | v.SetMapIndex(kv, subv) 751 | } 752 | 753 | // Next token must be , or }. 754 | op = d.scanWhile(scanSkipSpace) 755 | if op == scanEndObject { 756 | break 757 | } 758 | if op != scanObjectValue { 759 | d.error(errPhase) 760 | } 761 | } 762 | } 763 | 764 | // literal consumes a literal from d.data[d.off-1:], decoding into the value v. 765 | // The first byte of the literal has been read already 766 | // (that's how the caller knows it's a literal). 767 | func (d *decodeState) literal(v reflect.Value) { 768 | // All bytes inside literal return scanContinue op code. 769 | start := d.off - 1 770 | op := d.scanWhile(scanContinue) 771 | 772 | // Scan read one byte too far; back up. 773 | d.off-- 774 | d.scan.undo(op) 775 | 776 | d.literalStore(d.data[start:d.off], v, false, false) 777 | } 778 | 779 | // convertNumber converts the number literal s to a float64 or a Number 780 | // depending on the setting of d.useNumber. 781 | func (d *decodeState) convertNumber(s string) (interface{}, error) { 782 | if d.useNumber { 783 | return Number(s), nil 784 | } 785 | if h, ok := hexString(s); ok { 786 | n, err := strconv.ParseInt(h, 16, 64) 787 | if err != nil { 788 | return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)} 789 | } 790 | f := float64(n) 791 | if h[0] == '-' && n == 0 { 792 | f = -f 793 | } 794 | return f, nil 795 | } 796 | f, err := strconv.ParseFloat(s, 64) 797 | if err != nil { 798 | return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)} 799 | } 800 | return f, nil 801 | } 802 | 803 | func hexString(s string) (res string, ok bool) { 804 | if len(s) < 3 { 805 | return 806 | } 807 | if len(s) > 3 && (s[0] == '-' || s[0] == '+') && s[1] == '0' && (s[2] == 'x' || s[2] == 'X') { 808 | return s[:1] + s[3:], true 809 | } 810 | if s[0] == '0' && (s[1] == 'x' || s[1] == 'X') { 811 | return s[2:], true 812 | } 813 | return 814 | } 815 | 816 | var numberType = reflect.TypeOf(Number("")) 817 | 818 | // literalStore decodes a literal stored in item into v. 819 | // 820 | // fromQuoted indicates whether this literal came from unwrapping a 821 | // string from the ",string" struct tag option. this is used only to 822 | // produce more helpful error messages. 823 | func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted, unquotedString bool) { 824 | // Check for unmarshaler. 825 | if len(item) == 0 { 826 | //Empty string given 827 | d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) 828 | return 829 | } 830 | wantptr := item[0] == 'n' // null 831 | u, ut, pv := d.indirect(v, wantptr) 832 | if u != nil { 833 | if unquotedString { 834 | item = append(append([]byte{'"'}, item...), '"') 835 | } 836 | err := u.UnmarshalJSON(item) 837 | if err != nil { 838 | d.error(err) 839 | } 840 | return 841 | } 842 | if ut != nil { 843 | s := item 844 | if !unquotedString { 845 | if item[0] != '"' && item[0] != '\'' { 846 | if fromQuoted { 847 | d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) 848 | } else { 849 | d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) 850 | } 851 | return 852 | } 853 | var ok bool 854 | s, ok = unquoteBytes(item) 855 | if !ok { 856 | if fromQuoted { 857 | d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) 858 | } else { 859 | d.error(errPhase) 860 | } 861 | } 862 | } 863 | err := ut.UnmarshalText(s) 864 | if err != nil { 865 | d.error(err) 866 | } 867 | return 868 | } 869 | 870 | v = pv 871 | 872 | c := item[0] 873 | if unquotedString { 874 | c = '"' 875 | } 876 | switch c { 877 | case 'n': // null 878 | switch v.Kind() { 879 | case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: 880 | v.Set(reflect.Zero(v.Type())) 881 | // otherwise, ignore null for primitives/string 882 | } 883 | case 't', 'f': // true, false 884 | value := c == 't' 885 | switch v.Kind() { 886 | default: 887 | if fromQuoted { 888 | d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) 889 | } else { 890 | d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) 891 | } 892 | case reflect.Bool: 893 | v.SetBool(value) 894 | case reflect.Interface: 895 | if v.NumMethod() == 0 { 896 | v.Set(reflect.ValueOf(value)) 897 | } else { 898 | d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) 899 | } 900 | } 901 | 902 | case '"', '\'': // string 903 | s := item 904 | if !unquotedString { 905 | var ok bool 906 | s, ok = unquoteBytes(item) 907 | if !ok { 908 | if fromQuoted { 909 | d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) 910 | } else { 911 | d.error(errPhase) 912 | } 913 | } 914 | } 915 | switch v.Kind() { 916 | default: 917 | d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) 918 | case reflect.Slice: 919 | if v.Type().Elem().Kind() != reflect.Uint8 { 920 | d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) 921 | break 922 | } 923 | b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) 924 | n, err := base64.StdEncoding.Decode(b, s) 925 | if err != nil { 926 | d.saveError(err) 927 | break 928 | } 929 | v.SetBytes(b[:n]) 930 | case reflect.String: 931 | v.SetString(string(s)) 932 | case reflect.Interface: 933 | if v.NumMethod() == 0 { 934 | v.Set(reflect.ValueOf(string(s))) 935 | } else { 936 | d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) 937 | } 938 | } 939 | 940 | default: // number 941 | if c != '-' && c != '+' && c != '.' && c != 'I' && c != 'N' && (c < '0' || c > '9') { 942 | if fromQuoted { 943 | d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) 944 | } else { 945 | d.error(errPhase) 946 | } 947 | } 948 | s := string(item) 949 | switch v.Kind() { 950 | default: 951 | if v.Kind() == reflect.String && v.Type() == numberType { 952 | v.SetString(s) 953 | if !isValidNumber(s) { 954 | d.error(fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item)) 955 | } 956 | break 957 | } 958 | if fromQuoted { 959 | d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) 960 | } else { 961 | d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) 962 | } 963 | case reflect.Interface: 964 | n, err := d.convertNumber(s) 965 | if err != nil { 966 | d.saveError(err) 967 | break 968 | } 969 | if v.NumMethod() != 0 { 970 | d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) 971 | break 972 | } 973 | v.Set(reflect.ValueOf(n)) 974 | 975 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 976 | var n int64 977 | var err error 978 | if h, ok := hexString(s); ok { 979 | n, err = strconv.ParseInt(h, 16, 64) 980 | } else { 981 | n, err = strconv.ParseInt(s, 10, 64) 982 | } 983 | if err != nil || v.OverflowInt(n) { 984 | d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) 985 | break 986 | } 987 | v.SetInt(n) 988 | 989 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 990 | var n uint64 991 | var err error 992 | if h, ok := hexString(s); ok { 993 | n, err = strconv.ParseUint(h, 16, 64) 994 | } else { 995 | n, err = strconv.ParseUint(s, 10, 64) 996 | } 997 | if err != nil || v.OverflowUint(n) { 998 | d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) 999 | break 1000 | } 1001 | v.SetUint(n) 1002 | 1003 | case reflect.Float32, reflect.Float64: 1004 | var n float64 1005 | var err error 1006 | if h, ok := hexString(s); ok { 1007 | var nn int64 1008 | nn, err = strconv.ParseInt(h, 16, 64) 1009 | n = float64(nn) 1010 | if s[0] == '-' && nn == 0 { 1011 | n = -n 1012 | } 1013 | } else { 1014 | n, err = strconv.ParseFloat(s, v.Type().Bits()) 1015 | } 1016 | if err != nil || v.OverflowFloat(n) { 1017 | d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) 1018 | break 1019 | } 1020 | v.SetFloat(n) 1021 | } 1022 | } 1023 | } 1024 | 1025 | // The xxxInterface routines build up a value to be stored 1026 | // in an empty interface. They are not strictly necessary, 1027 | // but they avoid the weight of reflection in this common case. 1028 | 1029 | // valueInterface is like value but returns interface{} 1030 | func (d *decodeState) valueInterface() interface{} { 1031 | switch d.scanWhile(scanSkipSpace) { 1032 | default: 1033 | d.error(errPhase) 1034 | panic("unreachable") 1035 | case scanBeginArray: 1036 | return d.arrayInterface() 1037 | case scanBeginObject: 1038 | return d.objectInterface() 1039 | case scanBeginLiteral: 1040 | return d.literalInterface() 1041 | } 1042 | } 1043 | 1044 | // arrayInterface is like array but returns []interface{}. 1045 | func (d *decodeState) arrayInterface() []interface{} { 1046 | var v = make([]interface{}, 0) 1047 | for { 1048 | // Look ahead for ] - can only happen on first iteration. 1049 | op := d.scanWhile(scanSkipSpace) 1050 | if op == scanEndArray { 1051 | break 1052 | } 1053 | 1054 | // Back up so d.value can have the byte we just read. 1055 | d.off-- 1056 | d.scan.undo(op) 1057 | 1058 | v = append(v, d.valueInterface()) 1059 | 1060 | // Next token must be , or ]. 1061 | op = d.scanWhile(scanSkipSpace) 1062 | if op == scanEndArray { 1063 | break 1064 | } 1065 | if op != scanArrayValue { 1066 | d.error(errPhase) 1067 | } 1068 | } 1069 | return v 1070 | } 1071 | 1072 | // objectInterface is like object but returns map[string]interface{}. 1073 | func (d *decodeState) objectInterface() map[string]interface{} { 1074 | m := make(map[string]interface{}) 1075 | for { 1076 | // Read opening " of string key or closing }. 1077 | op := d.scanWhile(scanSkipSpace) 1078 | if op == scanEndObject { 1079 | // closing } - can only happen on first iteration. 1080 | break 1081 | } 1082 | if op != scanBeginLiteral { 1083 | d.error(errPhase) 1084 | } 1085 | 1086 | // Read string key. 1087 | start := d.off - 1 1088 | op = d.scanWhile(scanContinue) 1089 | key := d.data[start : d.off-1] 1090 | if key[0] == '"' || key[0] == '\'' { 1091 | var ok bool 1092 | key, ok = unquoteBytes(key) 1093 | if !ok { 1094 | d.error(errPhase) 1095 | } 1096 | } 1097 | 1098 | // Read : before value. 1099 | if op == scanSkipSpace { 1100 | op = d.scanWhile(scanSkipSpace) 1101 | } 1102 | if op != scanObjectKey { 1103 | d.error(errPhase) 1104 | } 1105 | 1106 | // Read value. 1107 | m[string(key)] = d.valueInterface() 1108 | 1109 | // Next token must be , or }. 1110 | op = d.scanWhile(scanSkipSpace) 1111 | if op == scanEndObject { 1112 | break 1113 | } 1114 | if op != scanObjectValue { 1115 | d.error(errPhase) 1116 | } 1117 | } 1118 | return m 1119 | } 1120 | 1121 | // literalInterface is like literal but returns an interface value. 1122 | func (d *decodeState) literalInterface() interface{} { 1123 | // All bytes inside literal return scanContinue op code. 1124 | start := d.off - 1 1125 | op := d.scanWhile(scanContinue) 1126 | 1127 | // Scan read one byte too far; back up. 1128 | d.off-- 1129 | d.scan.undo(op) 1130 | item := d.data[start:d.off] 1131 | 1132 | switch c := item[0]; c { 1133 | case 'n': // null 1134 | return nil 1135 | 1136 | case 't', 'f': // true, false 1137 | return c == 't' 1138 | 1139 | case 'I': // Infinity 1140 | return math.Inf(0) 1141 | 1142 | case 'N': // NaN 1143 | return math.NaN() 1144 | 1145 | case '"', '\'': // string 1146 | s, ok := unquote(item) 1147 | if !ok { 1148 | d.error(errPhase) 1149 | } 1150 | return s 1151 | 1152 | default: // number 1153 | if c != '-' && c != '+' && c != '.' && (c < '0' || c > '9') { 1154 | d.error(errPhase) 1155 | } 1156 | if c == '-' && item[1] == 'I' { 1157 | return math.Inf(-1) 1158 | } 1159 | if c == '+' && item[1] == 'I' { 1160 | return math.Inf(+1) 1161 | } 1162 | n, err := d.convertNumber(string(item)) 1163 | if err != nil { 1164 | d.saveError(err) 1165 | } 1166 | return n 1167 | } 1168 | } 1169 | 1170 | // getu4 decodes \uXXXX from the beginning of s, returning the hex value, 1171 | // or it returns -1. 1172 | func getu4(s []byte) rune { 1173 | if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { 1174 | return -1 1175 | } 1176 | r, err := strconv.ParseUint(string(s[2:6]), 16, 64) 1177 | if err != nil { 1178 | return -1 1179 | } 1180 | return rune(r) 1181 | } 1182 | 1183 | // unquote converts a quoted JSON string literal s into an actual string t. 1184 | // The rules are different than for Go, so cannot use strconv.Unquote. 1185 | func unquote(s []byte) (t string, ok bool) { 1186 | s, ok = unquoteBytes(s) 1187 | t = string(s) 1188 | return 1189 | } 1190 | 1191 | func unquoteBytes(s []byte) (t []byte, ok bool) { 1192 | if len(s) < 2 || (s[0] != '"' && s[0] != '\'') || (s[len(s)-1] != '"' && s[len(s)-1] != '\'') { 1193 | return 1194 | } 1195 | orig := s 1196 | s = s[1 : len(s)-1] 1197 | 1198 | // Check for unusual characters. If there are none, 1199 | // then no unquoting is needed, so return a slice of the 1200 | // original bytes. 1201 | r := 0 1202 | for r < len(s) { 1203 | c := s[r] 1204 | if c == '\\' || c == '"' || c == '\'' || c < ' ' { 1205 | break 1206 | } 1207 | if c < utf8.RuneSelf { 1208 | r++ 1209 | continue 1210 | } 1211 | rr, size := utf8.DecodeRune(s[r:]) 1212 | if rr == utf8.RuneError && size == 1 { 1213 | break 1214 | } 1215 | r += size 1216 | } 1217 | if r == len(s) { 1218 | return s, true 1219 | } 1220 | 1221 | b := make([]byte, len(s)+2*utf8.UTFMax) 1222 | w := copy(b, s[0:r]) 1223 | for r < len(s) { 1224 | // Out of room? Can only happen if s is full of 1225 | // malformed UTF-8 and we're replacing each 1226 | // byte with RuneError. 1227 | if w >= len(b)-2*utf8.UTFMax { 1228 | nb := make([]byte, (len(b)+utf8.UTFMax)*2) 1229 | copy(nb, b[0:w]) 1230 | b = nb 1231 | } 1232 | switch c := s[r]; { 1233 | case c == '\\': 1234 | r++ 1235 | if r >= len(s) { 1236 | return 1237 | } 1238 | switch s[r] { 1239 | default: 1240 | return 1241 | case '"', '\\', '/', '\'': 1242 | b[w] = s[r] 1243 | r++ 1244 | w++ 1245 | case 'b': 1246 | b[w] = '\b' 1247 | r++ 1248 | w++ 1249 | case '\n': 1250 | r++ 1251 | case '\r': 1252 | r++ 1253 | if r < len(s) && s[r] == '\n' { 1254 | r++ 1255 | } 1256 | case 'f': 1257 | b[w] = '\f' 1258 | r++ 1259 | w++ 1260 | case 'n': 1261 | b[w] = '\n' 1262 | r++ 1263 | w++ 1264 | case 'r': 1265 | b[w] = '\r' 1266 | r++ 1267 | w++ 1268 | case 't': 1269 | b[w] = '\t' 1270 | r++ 1271 | w++ 1272 | case 'u': 1273 | r-- 1274 | rr := getu4(s[r:]) 1275 | if rr < 0 { 1276 | return 1277 | } 1278 | r += 6 1279 | if utf16.IsSurrogate(rr) { 1280 | rr1 := getu4(s[r:]) 1281 | if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { 1282 | // A valid pair; consume. 1283 | r += 6 1284 | w += utf8.EncodeRune(b[w:], dec) 1285 | break 1286 | } 1287 | // Invalid surrogate; fall back to replacement rune. 1288 | rr = unicode.ReplacementChar 1289 | } 1290 | w += utf8.EncodeRune(b[w:], rr) 1291 | } 1292 | 1293 | // Quote, control characters are invalid. 1294 | case orig[0] == '"' && c == '"', orig[0] == '\'' && c == '\'', c < ' ': 1295 | return 1296 | 1297 | // ASCII 1298 | case c < utf8.RuneSelf: 1299 | b[w] = c 1300 | r++ 1301 | w++ 1302 | 1303 | // Coerce to well-formed UTF-8. 1304 | default: 1305 | rr, size := utf8.DecodeRune(s[r:]) 1306 | r += size 1307 | w += utf8.EncodeRune(b[w:], rr) 1308 | } 1309 | } 1310 | return b[0:w], true 1311 | } 1312 | -------------------------------------------------------------------------------- /decode_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package json5 6 | 7 | import ( 8 | "bytes" 9 | "encoding" 10 | "errors" 11 | "fmt" 12 | "image" 13 | "net" 14 | "reflect" 15 | "strings" 16 | "testing" 17 | "time" 18 | ) 19 | 20 | // Ref has Marshaler and Unmarshaler methods with pointer receiver. 21 | type Ref int 22 | 23 | func (r *Ref) UnmarshalJSON([]byte) error { 24 | *r = 12 25 | return nil 26 | } 27 | 28 | // RefText has Marshaler and Unmarshaler methods with pointer receiver. 29 | type RefText int 30 | 31 | func (r *RefText) UnmarshalText([]byte) error { 32 | *r = 13 33 | return nil 34 | } 35 | 36 | type T struct { 37 | X string 38 | Y int 39 | Z int `json:"-"` 40 | } 41 | 42 | type U struct { 43 | Alphabet string `json:"alpha"` 44 | } 45 | 46 | type V struct { 47 | F1 interface{} 48 | F2 int32 49 | F3 Number 50 | } 51 | 52 | // ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and 53 | // without UseNumber 54 | var ifaceNumAsFloat64 = map[string]interface{}{ 55 | "k1": float64(1), 56 | "k2": "s", 57 | "k3": []interface{}{float64(1), float64(2.0), float64(3e-3)}, 58 | "k4": map[string]interface{}{"kk1": "s", "kk2": float64(2)}, 59 | } 60 | 61 | var ifaceNumAsNumber = map[string]interface{}{ 62 | "k1": Number("1"), 63 | "k2": "s", 64 | "k3": []interface{}{Number("1"), Number("2.0"), Number("3e-3")}, 65 | "k4": map[string]interface{}{"kk1": "s", "kk2": Number("2")}, 66 | } 67 | 68 | type tx struct { 69 | x int 70 | } 71 | 72 | // A type that can unmarshal itself. 73 | 74 | type unmarshaler struct { 75 | T bool 76 | } 77 | 78 | func (u *unmarshaler) UnmarshalJSON(b []byte) error { 79 | *u = unmarshaler{true} // All we need to see that UnmarshalJSON is called. 80 | return nil 81 | } 82 | 83 | type ustruct struct { 84 | M unmarshaler 85 | } 86 | 87 | type unmarshalerText struct { 88 | A, B string 89 | } 90 | 91 | func (u *unmarshalerText) UnmarshalText(b []byte) error { 92 | pos := bytes.Index(b, []byte(":")) 93 | if pos == -1 { 94 | return errors.New("missing separator") 95 | } 96 | u.A, u.B = string(b[:pos]), string(b[pos+1:]) 97 | return nil 98 | } 99 | 100 | var _ encoding.TextUnmarshaler = (*unmarshalerText)(nil) 101 | 102 | type ustructText struct { 103 | M unmarshalerText 104 | } 105 | 106 | var ( 107 | um0, um1 unmarshaler // target2 of unmarshaling 108 | ump = &um1 109 | umtrue = unmarshaler{true} 110 | umslice = []unmarshaler{{true}} 111 | umslicep = new([]unmarshaler) 112 | umstruct = ustruct{unmarshaler{true}} 113 | 114 | um0T, um1T unmarshalerText // target2 of unmarshaling 115 | umpType = &um1T 116 | umtrueXY = unmarshalerText{"x", "y"} 117 | umsliceXY = []unmarshalerText{{"x", "y"}} 118 | umslicepType = new([]unmarshalerText) 119 | umstructType = new(ustructText) 120 | umstructXY = ustructText{unmarshalerText{"x", "y"}} 121 | 122 | ummapType = map[unmarshalerText]bool{} 123 | ummapXY = map[unmarshalerText]bool{unmarshalerText{"x", "y"}: true} 124 | ) 125 | 126 | // Test data structures for anonymous fields. 127 | 128 | type Point struct { 129 | Z int 130 | } 131 | 132 | type Top struct { 133 | Level0 int 134 | Embed0 135 | *Embed0a 136 | *Embed0b `json:"e,omitempty"` // treated as named 137 | Embed0c `json:"-"` // ignored 138 | Loop 139 | Embed0p // has Point with X, Y, used 140 | Embed0q // has Point with Z, used 141 | embed // contains exported field 142 | } 143 | 144 | type Embed0 struct { 145 | Level1a int // overridden by Embed0a's Level1a with json tag 146 | Level1b int // used because Embed0a's Level1b is renamed 147 | Level1c int // used because Embed0a's Level1c is ignored 148 | Level1d int // annihilated by Embed0a's Level1d 149 | Level1e int `json:"x"` // annihilated by Embed0a.Level1e 150 | } 151 | 152 | type Embed0a struct { 153 | Level1a int `json:"Level1a,omitempty"` 154 | Level1b int `json:"LEVEL1B,omitempty"` 155 | Level1c int `json:"-"` 156 | Level1d int // annihilated by Embed0's Level1d 157 | Level1f int `json:"x"` // annihilated by Embed0's Level1e 158 | } 159 | 160 | type Embed0b Embed0 161 | 162 | type Embed0c Embed0 163 | 164 | type Embed0p struct { 165 | image.Point 166 | } 167 | 168 | type Embed0q struct { 169 | Point 170 | } 171 | 172 | type embed struct { 173 | Q int 174 | } 175 | 176 | type Loop struct { 177 | Loop1 int `json:",omitempty"` 178 | Loop2 int `json:",omitempty"` 179 | *Loop 180 | } 181 | 182 | // From reflect test: 183 | // The X in S6 and S7 annihilate, but they also block the X in S8.S9. 184 | type S5 struct { 185 | S6 186 | S7 187 | S8 188 | } 189 | 190 | type S6 struct { 191 | X int 192 | } 193 | 194 | type S7 S6 195 | 196 | type S8 struct { 197 | S9 198 | } 199 | 200 | type S9 struct { 201 | X int 202 | Y int 203 | } 204 | 205 | // From reflect test: 206 | // The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9. 207 | type S10 struct { 208 | S11 209 | S12 210 | S13 211 | } 212 | 213 | type S11 struct { 214 | S6 215 | } 216 | 217 | type S12 struct { 218 | S6 219 | } 220 | 221 | type S13 struct { 222 | S8 223 | } 224 | 225 | type unmarshalTest struct { 226 | in string 227 | ptr interface{} 228 | out interface{} 229 | err error 230 | useNumber bool 231 | disallowUnknownFields bool 232 | } 233 | 234 | type Ambig struct { 235 | // Given "hello", the first match should win. 236 | First int `json:"HELLO"` 237 | Second int `json:"Hello"` 238 | } 239 | 240 | type XYZ struct { 241 | X interface{} 242 | Y interface{} 243 | Z interface{} 244 | } 245 | 246 | func sliceAddr(x []int) *[]int { return &x } 247 | func mapAddr(x map[string]int) *map[string]int { return &x } 248 | 249 | var unmarshalTests = []unmarshalTest{ 250 | // basic types 251 | {in: `true`, ptr: new(bool), out: true}, 252 | {in: `1`, ptr: new(int), out: 1}, 253 | {in: `1.2`, ptr: new(float64), out: 1.2}, 254 | {in: `-5`, ptr: new(int16), out: int16(-5)}, 255 | {in: `2`, ptr: new(Number), out: Number("2"), useNumber: true}, 256 | {in: `2`, ptr: new(Number), out: Number("2")}, 257 | {in: `2`, ptr: new(interface{}), out: float64(2.0)}, 258 | {in: `2`, ptr: new(interface{}), out: Number("2"), useNumber: true}, 259 | {in: `"a\u1234"`, ptr: new(string), out: "a\u1234"}, 260 | {in: `"http:\/\/"`, ptr: new(string), out: "http://"}, 261 | {in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"}, 262 | {in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"}, 263 | {in: "null", ptr: new(interface{}), out: nil}, 264 | {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7}}, 265 | {in: `{"x": 1}`, ptr: new(tx), out: tx{}}, 266 | {in: `{"x": 1}`, ptr: new(tx), err: fmt.Errorf("json: unknown field \"x\""), disallowUnknownFields: true}, 267 | {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}}, 268 | {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true}, 269 | {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64}, 270 | {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsNumber, useNumber: true}, 271 | 272 | // raw values with whitespace 273 | {in: "\n true ", ptr: new(bool), out: true}, 274 | {in: "\t 1 ", ptr: new(int), out: 1}, 275 | {in: "\r 1.2 ", ptr: new(float64), out: 1.2}, 276 | {in: "\t -5 \n", ptr: new(int16), out: int16(-5)}, 277 | {in: "\t \"a\\u1234\" \n", ptr: new(string), out: "a\u1234"}, 278 | 279 | // Z has a "-" tag. 280 | {in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}}, 281 | {in: `{"Y": 1, "Z": 2}`, ptr: new(T), err: fmt.Errorf("json: unknown field \"Z\""), disallowUnknownFields: true}, 282 | 283 | {in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}}, 284 | {in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true}, 285 | {in: `{"alpha": "abc"}`, ptr: new(U), out: U{Alphabet: "abc"}}, 286 | {in: `{"alphabet": "xyz"}`, ptr: new(U), out: U{}}, 287 | {in: `{"alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true}, 288 | 289 | // syntax errors 290 | {in: `{"X": "foo", "Y"}`, err: &SyntaxError{"invalid character '}' after object key", 17}}, 291 | {in: `[1, 2, 3+]`, err: &SyntaxError{"invalid character '+' after array element", 9}}, 292 | {in: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object key:value pair", 8}, useNumber: true}, 293 | 294 | // raw value errors 295 | {in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, 296 | {in: " 42 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 5}}, 297 | {in: "\x01 true", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, 298 | {in: " false \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 8}}, 299 | {in: "\x01 1.2", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, 300 | {in: " 3.4 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 6}}, 301 | {in: "\x01 \"string\"", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, 302 | {in: " \"string\" \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 11}}, 303 | 304 | // array tests 305 | {in: `[1, 2, 3]`, ptr: new([3]int), out: [3]int{1, 2, 3}}, 306 | {in: `[1, 2, 3]`, ptr: new([1]int), out: [1]int{1}}, 307 | {in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}}, 308 | 309 | // empty array to interface test 310 | {in: `[]`, ptr: new([]interface{}), out: []interface{}{}}, 311 | {in: `null`, ptr: new([]interface{}), out: []interface{}(nil)}, 312 | {in: `{"T":[]}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": []interface{}{}}}, 313 | {in: `{"T":null}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": interface{}(nil)}}, 314 | 315 | // composite tests 316 | {in: allValueIndent, ptr: new(All), out: allValue}, 317 | {in: allValueCompact, ptr: new(All), out: allValue}, 318 | {in: allValueIndent, ptr: new(*All), out: &allValue}, 319 | {in: allValueCompact, ptr: new(*All), out: &allValue}, 320 | {in: pallValueIndent, ptr: new(All), out: pallValue}, 321 | {in: pallValueCompact, ptr: new(All), out: pallValue}, 322 | {in: pallValueIndent, ptr: new(*All), out: &pallValue}, 323 | {in: pallValueCompact, ptr: new(*All), out: &pallValue}, 324 | 325 | // unmarshal interface test 326 | {in: `{"T":false}`, ptr: &um0, out: umtrue}, // use "false" so test will fail if custom unmarshaler is not called 327 | {in: `{"T":false}`, ptr: &ump, out: &umtrue}, 328 | {in: `[{"T":false}]`, ptr: &umslice, out: umslice}, 329 | {in: `[{"T":false}]`, ptr: &umslicep, out: &umslice}, 330 | {in: `{"M":{"T":"x:y"}}`, ptr: &umstruct, out: umstruct}, 331 | 332 | // UnmarshalText interface test 333 | {in: `"x:y"`, ptr: &um0T, out: umtrueXY}, 334 | {in: `"x:y"`, ptr: &umpType, out: &umtrueXY}, 335 | {in: `["x:y"]`, ptr: &umsliceXY, out: umsliceXY}, 336 | {in: `["x:y"]`, ptr: &umslicepType, out: &umsliceXY}, 337 | {in: `{"M":"x:y"}`, ptr: umstructType, out: umstructXY}, 338 | 339 | // Map keys can be encoding.TextUnmarshalers 340 | {in: `{"x:y":true}`, ptr: &ummapType, out: ummapXY}, 341 | // If multiple values for the same key exists, only the most recent value is used. 342 | {in: `{"x:y":false,"x:y":true}`, ptr: &ummapType, out: ummapXY}, 343 | 344 | // Overwriting of data. 345 | // This is different from package xml, but it's what we've always done. 346 | // Now documented and tested. 347 | {in: `[2]`, ptr: sliceAddr([]int{1}), out: []int{2}}, 348 | {in: `{"key": 2}`, ptr: mapAddr(map[string]int{"old": 0, "key": 1}), out: map[string]int{"key": 2}}, 349 | 350 | { 351 | in: `{ 352 | "Level0": 1, 353 | "Level1b": 2, 354 | "Level1c": 3, 355 | "x": 4, 356 | "Level1a": 5, 357 | "LEVEL1B": 6, 358 | "e": { 359 | "Level1a": 8, 360 | "Level1b": 9, 361 | "Level1c": 10, 362 | "Level1d": 11, 363 | "x": 12 364 | }, 365 | "Loop1": 13, 366 | "Loop2": 14, 367 | "X": 15, 368 | "Y": 16, 369 | "Z": 17, 370 | "Q": 18 371 | }`, 372 | ptr: new(Top), 373 | out: Top{ 374 | Level0: 1, 375 | Embed0: Embed0{ 376 | Level1b: 2, 377 | Level1c: 3, 378 | }, 379 | Embed0a: &Embed0a{ 380 | Level1a: 5, 381 | Level1b: 6, 382 | }, 383 | Embed0b: &Embed0b{ 384 | Level1a: 8, 385 | Level1b: 9, 386 | Level1c: 10, 387 | Level1d: 11, 388 | Level1e: 12, 389 | }, 390 | Loop: Loop{ 391 | Loop1: 13, 392 | Loop2: 14, 393 | }, 394 | Embed0p: Embed0p{ 395 | Point: image.Point{X: 15, Y: 16}, 396 | }, 397 | Embed0q: Embed0q{ 398 | Point: Point{Z: 17}, 399 | }, 400 | embed: embed{ 401 | Q: 18, 402 | }, 403 | }, 404 | }, 405 | { 406 | in: `{"hello": 1}`, 407 | ptr: new(Ambig), 408 | out: Ambig{First: 1}, 409 | }, 410 | 411 | { 412 | in: `{"X": 1,"Y":2}`, 413 | ptr: new(S5), 414 | out: S5{S8: S8{S9: S9{Y: 2}}}, 415 | }, 416 | { 417 | in: `{"X": 1,"Y":2}`, 418 | ptr: new(S5), 419 | err: fmt.Errorf("json: unknown field \"X\""), 420 | disallowUnknownFields: true, 421 | }, 422 | { 423 | in: `{"X": 1,"Y":2}`, 424 | ptr: new(S10), 425 | out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}}, 426 | }, 427 | { 428 | in: `{"X": 1,"Y":2}`, 429 | ptr: new(S10), 430 | err: fmt.Errorf("json: unknown field \"X\""), 431 | disallowUnknownFields: true, 432 | }, 433 | 434 | // invalid UTF-8 is coerced to valid UTF-8. 435 | { 436 | in: "\"hello\xffworld\"", 437 | ptr: new(string), 438 | out: "hello\ufffdworld", 439 | }, 440 | { 441 | in: "\"hello\xc2\xc2world\"", 442 | ptr: new(string), 443 | out: "hello\ufffd\ufffdworld", 444 | }, 445 | { 446 | in: "\"hello\xc2\xffworld\"", 447 | ptr: new(string), 448 | out: "hello\ufffd\ufffdworld", 449 | }, 450 | { 451 | in: "\"hello\\ud800world\"", 452 | ptr: new(string), 453 | out: "hello\ufffdworld", 454 | }, 455 | { 456 | in: "\"hello\\ud800\\ud800world\"", 457 | ptr: new(string), 458 | out: "hello\ufffd\ufffdworld", 459 | }, 460 | { 461 | in: "\"hello\\ud800\\ud800world\"", 462 | ptr: new(string), 463 | out: "hello\ufffd\ufffdworld", 464 | }, 465 | { 466 | in: "\"hello\xed\xa0\x80\xed\xb0\x80world\"", 467 | ptr: new(string), 468 | out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld", 469 | }, 470 | 471 | // Used to be issue 8305, but time.Time implements encoding.TextUnmarshaler so this works now. 472 | { 473 | in: `{"2009-11-10T23:00:00Z": "hello world"}`, 474 | ptr: &map[time.Time]string{}, 475 | out: map[time.Time]string{time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC): "hello world"}, 476 | }, 477 | 478 | // issue 8305 479 | { 480 | in: `{"2009-11-10T23:00:00Z": "hello world"}`, 481 | ptr: &map[Point]string{}, 482 | err: &UnmarshalTypeError{"object", reflect.TypeOf(map[Point]string{}), 1}, 483 | }, 484 | { 485 | in: `{"asdf": "hello world"}`, 486 | ptr: &map[unmarshaler]string{}, 487 | err: &UnmarshalTypeError{"object", reflect.TypeOf(map[unmarshaler]string{}), 1}, 488 | }, 489 | 490 | // additional tests for disallowUnknownFields 491 | { 492 | in: `{ 493 | "Level0": 1, 494 | "Level1b": 2, 495 | "Level1c": 3, 496 | "x": 4, 497 | "Level1a": 5, 498 | "LEVEL1B": 6, 499 | "e": { 500 | "Level1a": 8, 501 | "Level1b": 9, 502 | "Level1c": 10, 503 | "Level1d": 11, 504 | "x": 12 505 | }, 506 | "Loop1": 13, 507 | "Loop2": 14, 508 | "X": 15, 509 | "Y": 16, 510 | "Z": 17, 511 | "Q": 18, 512 | "extra": true 513 | }`, 514 | ptr: new(Top), 515 | err: fmt.Errorf("json: unknown field \"extra\""), 516 | disallowUnknownFields: true, 517 | }, 518 | { 519 | in: `{ 520 | "Level0": 1, 521 | "Level1b": 2, 522 | "Level1c": 3, 523 | "x": 4, 524 | "Level1a": 5, 525 | "LEVEL1B": 6, 526 | "e": { 527 | "Level1a": 8, 528 | "Level1b": 9, 529 | "Level1c": 10, 530 | "Level1d": 11, 531 | "x": 12, 532 | "extra": null 533 | }, 534 | "Loop1": 13, 535 | "Loop2": 14, 536 | "X": 15, 537 | "Y": 16, 538 | "Z": 17, 539 | "Q": 18 540 | }`, 541 | ptr: new(Top), 542 | err: fmt.Errorf("json: unknown field \"extra\""), 543 | disallowUnknownFields: true, 544 | }, 545 | } 546 | 547 | var badUTF8 = []struct { 548 | in, out string 549 | }{ 550 | {"hello\xffworld", `"hello\ufffdworld"`}, 551 | {"", `""`}, 552 | {"\xff", `"\ufffd"`}, 553 | {"\xff\xff", `"\ufffd\ufffd"`}, 554 | {"a\xffb", `"a\ufffdb"`}, 555 | {"\xe6\x97\xa5\xe6\x9c\xac\xff\xaa\x9e", `"日本\ufffd\ufffd\ufffd"`}, 556 | } 557 | 558 | func TestUnmarshal(t *testing.T) { 559 | for i, tt := range unmarshalTests { 560 | var scan scanner 561 | in := []byte(tt.in) 562 | if err := checkValid(in, &scan); err != nil { 563 | if !reflect.DeepEqual(err, tt.err) { 564 | t.Errorf("#%d: checkValid: %#v", i, err) 565 | continue 566 | } 567 | } 568 | if tt.ptr == nil { 569 | continue 570 | } 571 | 572 | // v = new(right-type) 573 | v := reflect.New(reflect.TypeOf(tt.ptr).Elem()) 574 | dec := NewDecoder(bytes.NewReader(in)) 575 | if tt.useNumber { 576 | dec.UseNumber() 577 | } 578 | if tt.disallowUnknownFields { 579 | dec.DisallowUnknownFields() 580 | } 581 | if err := dec.Decode(v.Interface()); !reflect.DeepEqual(err, tt.err) { 582 | t.Errorf("#%d: %v, want %v", i, err, tt.err) 583 | continue 584 | } else if err != nil { 585 | continue 586 | } 587 | if !reflect.DeepEqual(v.Elem().Interface(), tt.out) { 588 | t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out) 589 | continue 590 | } 591 | } 592 | } 593 | 594 | var numberTests = []struct { 595 | in string 596 | i int64 597 | intErr string 598 | f float64 599 | floatErr string 600 | }{ 601 | {in: "-1.23e1", intErr: "strconv.ParseInt: parsing \"-1.23e1\": invalid syntax", f: -1.23e1}, 602 | {in: "-12", i: -12, f: -12.0}, 603 | {in: "1e1000", intErr: "strconv.ParseInt: parsing \"1e1000\": invalid syntax", floatErr: "strconv.ParseFloat: parsing \"1e1000\": value out of range"}, 604 | } 605 | 606 | // Independent of Decode, basic coverage of the accessors in Number 607 | func TestNumberAccessors(t *testing.T) { 608 | for _, tt := range numberTests { 609 | n := Number(tt.in) 610 | if s := n.String(); s != tt.in { 611 | t.Errorf("Number(%q).String() is %q", tt.in, s) 612 | } 613 | if i, err := n.Int64(); err == nil && tt.intErr == "" && i != tt.i { 614 | t.Errorf("Number(%q).Int64() is %d", tt.in, i) 615 | } else if (err == nil && tt.intErr != "") || (err != nil && err.Error() != tt.intErr) { 616 | t.Errorf("Number(%q).Int64() wanted error %q but got: %v", tt.in, tt.intErr, err) 617 | } 618 | if f, err := n.Float64(); err == nil && tt.floatErr == "" && f != tt.f { 619 | t.Errorf("Number(%q).Float64() is %g", tt.in, f) 620 | } else if (err == nil && tt.floatErr != "") || (err != nil && err.Error() != tt.floatErr) { 621 | t.Errorf("Number(%q).Float64() wanted error %q but got: %v", tt.in, tt.floatErr, err) 622 | } 623 | } 624 | } 625 | 626 | type Xint struct { 627 | X int 628 | } 629 | 630 | func TestUnmarshalInterface(t *testing.T) { 631 | var xint Xint 632 | var i interface{} = &xint 633 | if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil { 634 | t.Fatalf("Unmarshal: %v", err) 635 | } 636 | if xint.X != 1 { 637 | t.Fatalf("Did not write to xint") 638 | } 639 | } 640 | 641 | func TestUnmarshalPtrPtr(t *testing.T) { 642 | var xint Xint 643 | pxint := &xint 644 | if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil { 645 | t.Fatalf("Unmarshal: %v", err) 646 | } 647 | if xint.X != 1 { 648 | t.Fatalf("Did not write to xint") 649 | } 650 | } 651 | 652 | // WrongString is a struct that's misusing the ,string modifier. 653 | type WrongString struct { 654 | Message string `json:"result,string"` 655 | } 656 | 657 | type wrongStringTest struct { 658 | in, err string 659 | } 660 | 661 | var wrongStringTests = []wrongStringTest{ 662 | {`{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`}, 663 | {`{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`}, 664 | {`{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`}, 665 | {`{"result":123}`, `json: invalid use of ,string struct tag, trying to unmarshal unquoted value into string`}, 666 | } 667 | 668 | // If people misuse the ,string modifier, the error message should be 669 | // helpful, telling the user that they're doing it wrong. 670 | func TestErrorMessageFromMisusedString(t *testing.T) { 671 | for n, tt := range wrongStringTests { 672 | r := strings.NewReader(tt.in) 673 | var s WrongString 674 | err := NewDecoder(r).Decode(&s) 675 | got := fmt.Sprintf("%v", err) 676 | if got != tt.err { 677 | t.Errorf("%d. got err = %q, want %q", n, got, tt.err) 678 | } 679 | } 680 | } 681 | 682 | func noSpace(c rune) rune { 683 | if isSpace(byte(c)) { //only used for ascii 684 | return -1 685 | } 686 | return c 687 | } 688 | 689 | type All struct { 690 | Bool bool 691 | Int int 692 | Int8 int8 693 | Int16 int16 694 | Int32 int32 695 | Int64 int64 696 | Uint uint 697 | Uint8 uint8 698 | Uint16 uint16 699 | Uint32 uint32 700 | Uint64 uint64 701 | Uintptr uintptr 702 | Float32 float32 703 | Float64 float64 704 | 705 | Foo string `json:"bar"` 706 | Foo2 string `json:"bar2,dummyopt"` 707 | 708 | IntStr int64 `json:",string"` 709 | 710 | PBool *bool 711 | PInt *int 712 | PInt8 *int8 713 | PInt16 *int16 714 | PInt32 *int32 715 | PInt64 *int64 716 | PUint *uint 717 | PUint8 *uint8 718 | PUint16 *uint16 719 | PUint32 *uint32 720 | PUint64 *uint64 721 | PUintptr *uintptr 722 | PFloat32 *float32 723 | PFloat64 *float64 724 | 725 | String string 726 | PString *string 727 | 728 | Map map[string]Small 729 | MapP map[string]*Small 730 | PMap *map[string]Small 731 | PMapP *map[string]*Small 732 | 733 | EmptyMap map[string]Small 734 | NilMap map[string]Small 735 | 736 | Slice []Small 737 | SliceP []*Small 738 | PSlice *[]Small 739 | PSliceP *[]*Small 740 | 741 | EmptySlice []Small 742 | NilSlice []Small 743 | 744 | StringSlice []string 745 | ByteSlice []byte 746 | 747 | Small Small 748 | PSmall *Small 749 | PPSmall **Small 750 | 751 | Interface interface{} 752 | PInterface *interface{} 753 | 754 | unexported int 755 | } 756 | 757 | type Small struct { 758 | Tag string 759 | } 760 | 761 | var allValue = All{ 762 | Bool: true, 763 | Int: 2, 764 | Int8: 3, 765 | Int16: 4, 766 | Int32: 5, 767 | Int64: 6, 768 | Uint: 7, 769 | Uint8: 8, 770 | Uint16: 9, 771 | Uint32: 10, 772 | Uint64: 11, 773 | Uintptr: 12, 774 | Float32: 14.1, 775 | Float64: 15.1, 776 | Foo: "foo", 777 | Foo2: "foo2", 778 | IntStr: 42, 779 | String: "16", 780 | Map: map[string]Small{ 781 | "17": {Tag: "tag17"}, 782 | "18": {Tag: "tag18"}, 783 | }, 784 | MapP: map[string]*Small{ 785 | "19": {Tag: "tag19"}, 786 | "20": nil, 787 | }, 788 | EmptyMap: map[string]Small{}, 789 | Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}}, 790 | SliceP: []*Small{{Tag: "tag22"}, nil, {Tag: "tag23"}}, 791 | EmptySlice: []Small{}, 792 | StringSlice: []string{"str24", "str25", "str26"}, 793 | ByteSlice: []byte{27, 28, 29}, 794 | Small: Small{Tag: "tag30"}, 795 | PSmall: &Small{Tag: "tag31"}, 796 | Interface: 5.2, 797 | } 798 | 799 | var pallValue = All{ 800 | PBool: &allValue.Bool, 801 | PInt: &allValue.Int, 802 | PInt8: &allValue.Int8, 803 | PInt16: &allValue.Int16, 804 | PInt32: &allValue.Int32, 805 | PInt64: &allValue.Int64, 806 | PUint: &allValue.Uint, 807 | PUint8: &allValue.Uint8, 808 | PUint16: &allValue.Uint16, 809 | PUint32: &allValue.Uint32, 810 | PUint64: &allValue.Uint64, 811 | PUintptr: &allValue.Uintptr, 812 | PFloat32: &allValue.Float32, 813 | PFloat64: &allValue.Float64, 814 | PString: &allValue.String, 815 | PMap: &allValue.Map, 816 | PMapP: &allValue.MapP, 817 | PSlice: &allValue.Slice, 818 | PSliceP: &allValue.SliceP, 819 | PPSmall: &allValue.PSmall, 820 | PInterface: &allValue.Interface, 821 | } 822 | 823 | var allValueIndent = `{ 824 | "Bool": true, 825 | "Int": 2, 826 | "Int8": 3, 827 | "Int16": 4, 828 | "Int32": 5, 829 | "Int64": 6, 830 | "Uint": 7, 831 | "Uint8": 8, 832 | "Uint16": 9, 833 | "Uint32": 10, 834 | "Uint64": 11, 835 | "Uintptr": 12, 836 | "Float32": 14.1, 837 | "Float64": 15.1, 838 | "bar": "foo", 839 | "bar2": "foo2", 840 | "IntStr": "42", 841 | "PBool": null, 842 | "PInt": null, 843 | "PInt8": null, 844 | "PInt16": null, 845 | "PInt32": null, 846 | "PInt64": null, 847 | "PUint": null, 848 | "PUint8": null, 849 | "PUint16": null, 850 | "PUint32": null, 851 | "PUint64": null, 852 | "PUintptr": null, 853 | "PFloat32": null, 854 | "PFloat64": null, 855 | "String": "16", 856 | "PString": null, 857 | "Map": { 858 | "17": { 859 | "Tag": "tag17" 860 | }, 861 | "18": { 862 | "Tag": "tag18" 863 | } 864 | }, 865 | "MapP": { 866 | "19": { 867 | "Tag": "tag19" 868 | }, 869 | "20": null 870 | }, 871 | "PMap": null, 872 | "PMapP": null, 873 | "EmptyMap": {}, 874 | "NilMap": null, 875 | "Slice": [ 876 | { 877 | "Tag": "tag20" 878 | }, 879 | { 880 | "Tag": "tag21" 881 | } 882 | ], 883 | "SliceP": [ 884 | { 885 | "Tag": "tag22" 886 | }, 887 | null, 888 | { 889 | "Tag": "tag23" 890 | } 891 | ], 892 | "PSlice": null, 893 | "PSliceP": null, 894 | "EmptySlice": [], 895 | "NilSlice": null, 896 | "StringSlice": [ 897 | "str24", 898 | "str25", 899 | "str26" 900 | ], 901 | "ByteSlice": "Gxwd", 902 | "Small": { 903 | "Tag": "tag30" 904 | }, 905 | "PSmall": { 906 | "Tag": "tag31" 907 | }, 908 | "PPSmall": null, 909 | "Interface": 5.2, 910 | "PInterface": null 911 | }` 912 | 913 | var allValueCompact = strings.Map(noSpace, allValueIndent) 914 | 915 | var pallValueIndent = `{ 916 | "Bool": false, 917 | "Int": 0, 918 | "Int8": 0, 919 | "Int16": 0, 920 | "Int32": 0, 921 | "Int64": 0, 922 | "Uint": 0, 923 | "Uint8": 0, 924 | "Uint16": 0, 925 | "Uint32": 0, 926 | "Uint64": 0, 927 | "Uintptr": 0, 928 | "Float32": 0, 929 | "Float64": 0, 930 | "bar": "", 931 | "bar2": "", 932 | "IntStr": "0", 933 | "PBool": true, 934 | "PInt": 2, 935 | "PInt8": 3, 936 | "PInt16": 4, 937 | "PInt32": 5, 938 | "PInt64": 6, 939 | "PUint": 7, 940 | "PUint8": 8, 941 | "PUint16": 9, 942 | "PUint32": 10, 943 | "PUint64": 11, 944 | "PUintptr": 12, 945 | "PFloat32": 14.1, 946 | "PFloat64": 15.1, 947 | "String": "", 948 | "PString": "16", 949 | "Map": null, 950 | "MapP": null, 951 | "PMap": { 952 | "17": { 953 | "Tag": "tag17" 954 | }, 955 | "18": { 956 | "Tag": "tag18" 957 | } 958 | }, 959 | "PMapP": { 960 | "19": { 961 | "Tag": "tag19" 962 | }, 963 | "20": null 964 | }, 965 | "EmptyMap": null, 966 | "NilMap": null, 967 | "Slice": null, 968 | "SliceP": null, 969 | "PSlice": [ 970 | { 971 | "Tag": "tag20" 972 | }, 973 | { 974 | "Tag": "tag21" 975 | } 976 | ], 977 | "PSliceP": [ 978 | { 979 | "Tag": "tag22" 980 | }, 981 | null, 982 | { 983 | "Tag": "tag23" 984 | } 985 | ], 986 | "EmptySlice": null, 987 | "NilSlice": null, 988 | "StringSlice": null, 989 | "ByteSlice": null, 990 | "Small": { 991 | "Tag": "" 992 | }, 993 | "PSmall": null, 994 | "PPSmall": { 995 | "Tag": "tag31" 996 | }, 997 | "Interface": null, 998 | "PInterface": 5.2 999 | }` 1000 | 1001 | var pallValueCompact = strings.Map(noSpace, pallValueIndent) 1002 | 1003 | func TestRefUnmarshal(t *testing.T) { 1004 | type S struct { 1005 | // Ref is defined in encode_test.go. 1006 | R0 Ref 1007 | R1 *Ref 1008 | R2 RefText 1009 | R3 *RefText 1010 | } 1011 | want := S{ 1012 | R0: 12, 1013 | R1: new(Ref), 1014 | R2: 13, 1015 | R3: new(RefText), 1016 | } 1017 | *want.R1 = 12 1018 | *want.R3 = 13 1019 | 1020 | var got S 1021 | if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref","R2":"ref","R3":"ref"}`), &got); err != nil { 1022 | t.Fatalf("Unmarshal: %v", err) 1023 | } 1024 | if !reflect.DeepEqual(got, want) { 1025 | t.Errorf("got %+v, want %+v", got, want) 1026 | } 1027 | } 1028 | 1029 | // Test that the empty string doesn't panic decoding when ,string is specified 1030 | // Issue 3450 1031 | func TestEmptyString(t *testing.T) { 1032 | type T2 struct { 1033 | Number1 int `json:",string"` 1034 | Number2 int `json:",string"` 1035 | } 1036 | data := `{"Number1":"1", "Number2":""}` 1037 | dec := NewDecoder(strings.NewReader(data)) 1038 | var t2 T2 1039 | err := dec.Decode(&t2) 1040 | if err == nil { 1041 | t.Fatal("Decode: did not return error") 1042 | } 1043 | if t2.Number1 != 1 { 1044 | t.Fatal("Decode: did not set Number1") 1045 | } 1046 | } 1047 | 1048 | // Test that a null for ,string is not replaced with the previous quoted string (issue 7046). 1049 | // It should also not be an error (issue 2540, issue 8587). 1050 | func TestNullString(t *testing.T) { 1051 | type T struct { 1052 | A int `json:",string"` 1053 | B int `json:",string"` 1054 | C *int `json:",string"` 1055 | } 1056 | data := []byte(`{"A": "1", "B": null, "C": null}`) 1057 | var s T 1058 | s.B = 1 1059 | s.C = new(int) 1060 | *s.C = 2 1061 | err := Unmarshal(data, &s) 1062 | if err != nil { 1063 | t.Fatalf("Unmarshal: %v", err) 1064 | } 1065 | if s.B != 1 || s.C != nil { 1066 | t.Fatalf("after Unmarshal, s.B=%d, s.C=%p, want 1, nil", s.B, s.C) 1067 | } 1068 | } 1069 | 1070 | func intp(x int) *int { 1071 | p := new(int) 1072 | *p = x 1073 | return p 1074 | } 1075 | 1076 | func intpp(x *int) **int { 1077 | pp := new(*int) 1078 | *pp = x 1079 | return pp 1080 | } 1081 | 1082 | var interfaceSetTests = []struct { 1083 | pre interface{} 1084 | json string 1085 | post interface{} 1086 | }{ 1087 | {"foo", `"bar"`, "bar"}, 1088 | {"foo", `2`, 2.0}, 1089 | {"foo", `true`, true}, 1090 | {"foo", `null`, nil}, 1091 | 1092 | {nil, `null`, nil}, 1093 | {new(int), `null`, nil}, 1094 | {(*int)(nil), `null`, nil}, 1095 | {new(*int), `null`, new(*int)}, 1096 | {(**int)(nil), `null`, nil}, 1097 | {intp(1), `null`, nil}, 1098 | {intpp(nil), `null`, intpp(nil)}, 1099 | {intpp(intp(1)), `null`, intpp(nil)}, 1100 | } 1101 | 1102 | func TestInterfaceSet(t *testing.T) { 1103 | for _, tt := range interfaceSetTests { 1104 | b := struct{ X interface{} }{tt.pre} 1105 | blob := `{"X":` + tt.json + `}` 1106 | if err := Unmarshal([]byte(blob), &b); err != nil { 1107 | t.Errorf("Unmarshal %#q: %v", blob, err) 1108 | continue 1109 | } 1110 | if !reflect.DeepEqual(b.X, tt.post) { 1111 | t.Errorf("Unmarshal %#q into %#v: X=%#v, want %#v", blob, tt.pre, b.X, tt.post) 1112 | } 1113 | } 1114 | } 1115 | 1116 | // JSON null values should be ignored for primitives and string values instead of resulting in an error. 1117 | // Issue 2540 1118 | func TestUnmarshalNulls(t *testing.T) { 1119 | jsonData := []byte(`{ 1120 | "Bool" : null, 1121 | "Int" : null, 1122 | "Int8" : null, 1123 | "Int16" : null, 1124 | "Int32" : null, 1125 | "Int64" : null, 1126 | "Uint" : null, 1127 | "Uint8" : null, 1128 | "Uint16" : null, 1129 | "Uint32" : null, 1130 | "Uint64" : null, 1131 | "Float32" : null, 1132 | "Float64" : null, 1133 | "String" : null}`) 1134 | 1135 | nulls := All{ 1136 | Bool: true, 1137 | Int: 2, 1138 | Int8: 3, 1139 | Int16: 4, 1140 | Int32: 5, 1141 | Int64: 6, 1142 | Uint: 7, 1143 | Uint8: 8, 1144 | Uint16: 9, 1145 | Uint32: 10, 1146 | Uint64: 11, 1147 | Float32: 12.1, 1148 | Float64: 13.1, 1149 | String: "14"} 1150 | 1151 | err := Unmarshal(jsonData, &nulls) 1152 | if err != nil { 1153 | t.Errorf("Unmarshal of null values failed: %v", err) 1154 | } 1155 | if !nulls.Bool || nulls.Int != 2 || nulls.Int8 != 3 || nulls.Int16 != 4 || nulls.Int32 != 5 || nulls.Int64 != 6 || 1156 | nulls.Uint != 7 || nulls.Uint8 != 8 || nulls.Uint16 != 9 || nulls.Uint32 != 10 || nulls.Uint64 != 11 || 1157 | nulls.Float32 != 12.1 || nulls.Float64 != 13.1 || nulls.String != "14" { 1158 | 1159 | t.Errorf("Unmarshal of null values affected primitives") 1160 | } 1161 | } 1162 | 1163 | var decodeTypeErrorTests = []struct { 1164 | dest interface{} 1165 | src string 1166 | }{ 1167 | {new(string), `{"user": "name"}`}, // issue 4628. 1168 | {new(error), `{}`}, // issue 4222 1169 | {new(error), `[]`}, 1170 | {new(error), `""`}, 1171 | {new(error), `123`}, 1172 | {new(error), `true`}, 1173 | } 1174 | 1175 | func TestUnmarshalTypeError(t *testing.T) { 1176 | for _, item := range decodeTypeErrorTests { 1177 | err := Unmarshal([]byte(item.src), item.dest) 1178 | if _, ok := err.(*UnmarshalTypeError); !ok { 1179 | t.Errorf("expected type error for Unmarshal(%q, type %T): got %T", 1180 | item.src, item.dest, err) 1181 | } 1182 | } 1183 | } 1184 | 1185 | var unmarshalSyntaxTests = []string{ 1186 | "tru", 1187 | "fals", 1188 | "nul", 1189 | "123e", 1190 | `"hello`, 1191 | `[1,2,3`, 1192 | `{"key":1`, 1193 | `{"key":1,`, 1194 | } 1195 | 1196 | func TestUnmarshalSyntax(t *testing.T) { 1197 | var x interface{} 1198 | for _, src := range unmarshalSyntaxTests { 1199 | err := Unmarshal([]byte(src), &x) 1200 | if _, ok := err.(*SyntaxError); !ok { 1201 | t.Errorf("expected syntax error for Unmarshal(%q): got %T", src, err) 1202 | } 1203 | } 1204 | } 1205 | 1206 | // Test handling of unexported fields that should be ignored. 1207 | // Issue 4660 1208 | type unexportedFields struct { 1209 | Name string 1210 | m map[string]interface{} `json:"-"` 1211 | m2 map[string]interface{} `json:"abcd"` 1212 | } 1213 | 1214 | func TestUnmarshalUnexported(t *testing.T) { 1215 | input := `{"Name": "Bob", "m": {"x": 123}, "m2": {"y": 456}, "abcd": {"z": 789}}` 1216 | want := &unexportedFields{Name: "Bob"} 1217 | 1218 | out := &unexportedFields{} 1219 | err := Unmarshal([]byte(input), out) 1220 | if err != nil { 1221 | t.Errorf("got error %v, expected nil", err) 1222 | } 1223 | if !reflect.DeepEqual(out, want) { 1224 | t.Errorf("got %q, want %q", out, want) 1225 | } 1226 | } 1227 | 1228 | // Time3339 is a time.Time which encodes to and from JSON 1229 | // as an RFC 3339 time in UTC. 1230 | type Time3339 time.Time 1231 | 1232 | func (t *Time3339) UnmarshalJSON(b []byte) error { 1233 | if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' { 1234 | return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time", b) 1235 | } 1236 | tm, err := time.Parse(time.RFC3339, string(b[1:len(b)-1])) 1237 | if err != nil { 1238 | return err 1239 | } 1240 | *t = Time3339(tm) 1241 | return nil 1242 | } 1243 | 1244 | func TestUnmarshalJSONLiteralError(t *testing.T) { 1245 | var t3 Time3339 1246 | err := Unmarshal([]byte(`"0000-00-00T00:00:00Z"`), &t3) 1247 | if err == nil { 1248 | t.Fatalf("expected error; got time %v", time.Time(t3)) 1249 | } 1250 | if !strings.Contains(err.Error(), "range") { 1251 | t.Errorf("got err = %v; want out of range error", err) 1252 | } 1253 | } 1254 | 1255 | // Test that extra object elements in an array do not result in a 1256 | // "data changing underfoot" error. 1257 | // Issue 3717 1258 | func TestSkipArrayObjects(t *testing.T) { 1259 | json := `[{}]` 1260 | var dest [0]interface{} 1261 | 1262 | err := Unmarshal([]byte(json), &dest) 1263 | if err != nil { 1264 | t.Errorf("got error %q, want nil", err) 1265 | } 1266 | } 1267 | 1268 | // Test semantics of pre-filled struct fields and pre-filled map fields. 1269 | // Issue 4900. 1270 | func TestPrefilled(t *testing.T) { 1271 | ptrToMap := func(m map[string]interface{}) *map[string]interface{} { return &m } 1272 | 1273 | // Values here change, cannot reuse table across runs. 1274 | var prefillTests = []struct { 1275 | in string 1276 | ptr interface{} 1277 | out interface{} 1278 | }{ 1279 | { 1280 | in: `{"X": 1, "Y": 2}`, 1281 | ptr: &XYZ{X: float32(3), Y: int16(4), Z: 1.5}, 1282 | out: &XYZ{X: float64(1), Y: float64(2), Z: 1.5}, 1283 | }, 1284 | { 1285 | in: `{"X": 1, "Y": 2}`, 1286 | ptr: ptrToMap(map[string]interface{}{"X": float32(3), "Y": int16(4), "Z": 1.5}), 1287 | out: ptrToMap(map[string]interface{}{"X": float64(1), "Y": float64(2), "Z": 1.5}), 1288 | }, 1289 | } 1290 | 1291 | for _, tt := range prefillTests { 1292 | ptrstr := fmt.Sprintf("%v", tt.ptr) 1293 | err := Unmarshal([]byte(tt.in), tt.ptr) // tt.ptr edited here 1294 | if err != nil { 1295 | t.Errorf("Unmarshal: %v", err) 1296 | } 1297 | if !reflect.DeepEqual(tt.ptr, tt.out) { 1298 | t.Errorf("Unmarshal(%#q, %s): have %v, want %v", tt.in, ptrstr, tt.ptr, tt.out) 1299 | } 1300 | } 1301 | } 1302 | 1303 | var invalidUnmarshalTests = []struct { 1304 | v interface{} 1305 | want string 1306 | }{ 1307 | {nil, "json: Unmarshal(nil)"}, 1308 | {struct{}{}, "json: Unmarshal(non-pointer struct {})"}, 1309 | {(*int)(nil), "json: Unmarshal(nil *int)"}, 1310 | } 1311 | 1312 | func TestInvalidUnmarshal(t *testing.T) { 1313 | buf := []byte(`{"a":"1"}`) 1314 | for _, tt := range invalidUnmarshalTests { 1315 | err := Unmarshal(buf, tt.v) 1316 | if err == nil { 1317 | t.Errorf("Unmarshal expecting error, got nil") 1318 | continue 1319 | } 1320 | if got := err.Error(); got != tt.want { 1321 | t.Errorf("Unmarshal = %q; want %q", got, tt.want) 1322 | } 1323 | } 1324 | } 1325 | 1326 | var invalidUnmarshalTextTests = []struct { 1327 | v interface{} 1328 | want string 1329 | }{ 1330 | {nil, "json: Unmarshal(nil)"}, 1331 | {struct{}{}, "json: Unmarshal(non-pointer struct {})"}, 1332 | {(*int)(nil), "json: Unmarshal(nil *int)"}, 1333 | {new(net.IP), "json: cannot unmarshal string into Go value of type *net.IP"}, 1334 | } 1335 | 1336 | func TestInvalidUnmarshalText(t *testing.T) { 1337 | buf := []byte(`123`) 1338 | for _, tt := range invalidUnmarshalTextTests { 1339 | err := Unmarshal(buf, tt.v) 1340 | if err == nil { 1341 | t.Errorf("Unmarshal expecting error, got nil") 1342 | continue 1343 | } 1344 | if got := err.Error(); got != tt.want { 1345 | t.Errorf("Unmarshal = %q; want %q", got, tt.want) 1346 | } 1347 | } 1348 | } 1349 | 1350 | func TestDecodeSingleQuoteStringInterface(t *testing.T) { 1351 | buf := []byte(`{ 'key': 'value' }`) 1352 | got := make(map[string]interface{}) 1353 | err := Unmarshal(buf, &got) 1354 | if err != nil { 1355 | t.Errorf("Unmarshal: %v", err) 1356 | } 1357 | want := map[string]interface{}{"key": "value"} 1358 | if !reflect.DeepEqual(got, want) { 1359 | t.Errorf("Unmarshal = %q; want %q", got, want) 1360 | } 1361 | } 1362 | -------------------------------------------------------------------------------- /fold.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package json5 6 | 7 | import ( 8 | "bytes" 9 | "unicode/utf8" 10 | ) 11 | 12 | const ( 13 | caseMask = ^byte(0x20) // Mask to ignore case in ASCII. 14 | kelvin = '\u212a' 15 | smallLongEss = '\u017f' 16 | ) 17 | 18 | // foldFunc returns one of four different case folding equivalence 19 | // functions, from most general (and slow) to fastest: 20 | // 21 | // 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8 22 | // 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S') 23 | // 3) asciiEqualFold, no special, but includes non-letters (including _) 24 | // 4) simpleLetterEqualFold, no specials, no non-letters. 25 | // 26 | // The letters S and K are special because they map to 3 runes, not just 2: 27 | // - S maps to s and to U+017F 'ſ' Latin small letter long s 28 | // - k maps to K and to U+212A 'K' Kelvin sign 29 | // 30 | // See https://play.golang.org/p/tTxjOc0OGo 31 | // 32 | // The returned function is specialized for matching against s and 33 | // should only be given s. It's not curried for performance reasons. 34 | func foldFunc(s []byte) func(s, t []byte) bool { 35 | nonLetter := false 36 | special := false // special letter 37 | for _, b := range s { 38 | if b >= utf8.RuneSelf { 39 | return bytes.EqualFold 40 | } 41 | upper := b & caseMask 42 | if upper < 'A' || upper > 'Z' { 43 | nonLetter = true 44 | } else if upper == 'K' || upper == 'S' { 45 | // See above for why these letters are special. 46 | special = true 47 | } 48 | } 49 | if special { 50 | return equalFoldRight 51 | } 52 | if nonLetter { 53 | return asciiEqualFold 54 | } 55 | return simpleLetterEqualFold 56 | } 57 | 58 | // equalFoldRight is a specialization of bytes.EqualFold when s is 59 | // known to be all ASCII (including punctuation), but contains an 's', 60 | // 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t. 61 | // See comments on foldFunc. 62 | func equalFoldRight(s, t []byte) bool { 63 | for _, sb := range s { 64 | if len(t) == 0 { 65 | return false 66 | } 67 | tb := t[0] 68 | if tb < utf8.RuneSelf { 69 | if sb != tb { 70 | sbUpper := sb & caseMask 71 | if 'A' <= sbUpper && sbUpper <= 'Z' { 72 | if sbUpper != tb&caseMask { 73 | return false 74 | } 75 | } else { 76 | return false 77 | } 78 | } 79 | t = t[1:] 80 | continue 81 | } 82 | // sb is ASCII and t is not. t must be either kelvin 83 | // sign or long s; sb must be s, S, k, or K. 84 | tr, size := utf8.DecodeRune(t) 85 | switch sb { 86 | case 's', 'S': 87 | if tr != smallLongEss { 88 | return false 89 | } 90 | case 'k', 'K': 91 | if tr != kelvin { 92 | return false 93 | } 94 | default: 95 | return false 96 | } 97 | t = t[size:] 98 | 99 | } 100 | if len(t) > 0 { 101 | return false 102 | } 103 | return true 104 | } 105 | 106 | // asciiEqualFold is a specialization of bytes.EqualFold for use when 107 | // s is all ASCII (but may contain non-letters) and contains no 108 | // special-folding letters. 109 | // See comments on foldFunc. 110 | func asciiEqualFold(s, t []byte) bool { 111 | if len(s) != len(t) { 112 | return false 113 | } 114 | for i, sb := range s { 115 | tb := t[i] 116 | if sb == tb { 117 | continue 118 | } 119 | if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') { 120 | if sb&caseMask != tb&caseMask { 121 | return false 122 | } 123 | } else { 124 | return false 125 | } 126 | } 127 | return true 128 | } 129 | 130 | // simpleLetterEqualFold is a specialization of bytes.EqualFold for 131 | // use when s is all ASCII letters (no underscores, etc) and also 132 | // doesn't contain 'k', 'K', 's', or 'S'. 133 | // See comments on foldFunc. 134 | func simpleLetterEqualFold(s, t []byte) bool { 135 | if len(s) != len(t) { 136 | return false 137 | } 138 | for i, b := range s { 139 | if b&caseMask != t[i]&caseMask { 140 | return false 141 | } 142 | } 143 | return true 144 | } 145 | -------------------------------------------------------------------------------- /fold_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package json5 6 | 7 | import ( 8 | "bytes" 9 | "strings" 10 | "testing" 11 | "unicode/utf8" 12 | ) 13 | 14 | var foldTests = []struct { 15 | fn func(s, t []byte) bool 16 | s, t string 17 | want bool 18 | }{ 19 | {equalFoldRight, "", "", true}, 20 | {equalFoldRight, "a", "a", true}, 21 | {equalFoldRight, "", "a", false}, 22 | {equalFoldRight, "a", "", false}, 23 | {equalFoldRight, "a", "A", true}, 24 | {equalFoldRight, "AB", "ab", true}, 25 | {equalFoldRight, "AB", "ac", false}, 26 | {equalFoldRight, "sbkKc", "ſbKKc", true}, 27 | {equalFoldRight, "SbKkc", "ſbKKc", true}, 28 | {equalFoldRight, "SbKkc", "ſbKK", false}, 29 | {equalFoldRight, "e", "é", false}, 30 | {equalFoldRight, "s", "S", true}, 31 | 32 | {simpleLetterEqualFold, "", "", true}, 33 | {simpleLetterEqualFold, "abc", "abc", true}, 34 | {simpleLetterEqualFold, "abc", "ABC", true}, 35 | {simpleLetterEqualFold, "abc", "ABCD", false}, 36 | {simpleLetterEqualFold, "abc", "xxx", false}, 37 | 38 | {asciiEqualFold, "a_B", "A_b", true}, 39 | {asciiEqualFold, "aa@", "aa`", false}, // verify 0x40 and 0x60 aren't case-equivalent 40 | } 41 | 42 | func TestFold(t *testing.T) { 43 | for i, tt := range foldTests { 44 | if got := tt.fn([]byte(tt.s), []byte(tt.t)); got != tt.want { 45 | t.Errorf("%d. %q, %q = %v; want %v", i, tt.s, tt.t, got, tt.want) 46 | } 47 | truth := strings.EqualFold(tt.s, tt.t) 48 | if truth != tt.want { 49 | t.Errorf("strings.EqualFold doesn't agree with case %d", i) 50 | } 51 | } 52 | } 53 | 54 | func TestFoldAgainstUnicode(t *testing.T) { 55 | const bufSize = 5 56 | buf1 := make([]byte, 0, bufSize) 57 | buf2 := make([]byte, 0, bufSize) 58 | var runes []rune 59 | for i := 0x20; i <= 0x7f; i++ { 60 | runes = append(runes, rune(i)) 61 | } 62 | runes = append(runes, kelvin, smallLongEss) 63 | 64 | funcs := []struct { 65 | name string 66 | fold func(s, t []byte) bool 67 | letter bool // must be ASCII letter 68 | simple bool // must be simple ASCII letter (not 'S' or 'K') 69 | }{ 70 | { 71 | name: "equalFoldRight", 72 | fold: equalFoldRight, 73 | }, 74 | { 75 | name: "asciiEqualFold", 76 | fold: asciiEqualFold, 77 | simple: true, 78 | }, 79 | { 80 | name: "simpleLetterEqualFold", 81 | fold: simpleLetterEqualFold, 82 | simple: true, 83 | letter: true, 84 | }, 85 | } 86 | 87 | for _, ff := range funcs { 88 | for _, r := range runes { 89 | if r >= utf8.RuneSelf { 90 | continue 91 | } 92 | if ff.letter && !isASCIILetter(byte(r)) { 93 | continue 94 | } 95 | if ff.simple && (r == 's' || r == 'S' || r == 'k' || r == 'K') { 96 | continue 97 | } 98 | for _, r2 := range runes { 99 | buf1 := append(buf1[:0], 'x') 100 | buf2 := append(buf2[:0], 'x') 101 | buf1 = buf1[:1+utf8.EncodeRune(buf1[1:bufSize], r)] 102 | buf2 = buf2[:1+utf8.EncodeRune(buf2[1:bufSize], r2)] 103 | buf1 = append(buf1, 'x') 104 | buf2 = append(buf2, 'x') 105 | want := bytes.EqualFold(buf1, buf2) 106 | if got := ff.fold(buf1, buf2); got != want { 107 | t.Errorf("%s(%q, %q) = %v; want %v", ff.name, buf1, buf2, got, want) 108 | } 109 | } 110 | } 111 | } 112 | } 113 | 114 | func isASCIILetter(b byte) bool { 115 | return ('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z') 116 | } 117 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/titanous/json5 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/kylelemons/godebug v1.1.0 7 | github.com/robertkrimen/otto v0.2.1 8 | ) 9 | 10 | require ( 11 | golang.org/x/text v0.4.0 // indirect 12 | gopkg.in/sourcemap.v1 v1.0.5 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= 3 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 4 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 5 | github.com/robertkrimen/otto v0.2.1 h1:FVP0PJ0AHIjC+N4pKCG9yCDz6LHNPCwi/GKID5pGGF0= 6 | github.com/robertkrimen/otto v0.2.1/go.mod h1:UPwtJ1Xu7JrLcZjNWN8orJaM5n5YEtqL//farB5FlRY= 7 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= 8 | golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= 9 | golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 10 | gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= 11 | gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= 12 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 13 | -------------------------------------------------------------------------------- /json5_test.go: -------------------------------------------------------------------------------- 1 | package json5 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | "strings" 9 | "testing" 10 | 11 | "github.com/kylelemons/godebug/pretty" 12 | "github.com/robertkrimen/otto" 13 | ) 14 | 15 | type ErrorSpec struct { 16 | At int 17 | LineNumber int 18 | ColumnNumber int 19 | Message string 20 | } 21 | 22 | func TestJSON5Decode(t *testing.T) { 23 | filepath.Walk("testdata", func(path string, info os.FileInfo, err error) error { 24 | if err != nil { 25 | return err 26 | } 27 | if info.IsDir() { 28 | return nil 29 | } 30 | 31 | data, err := ioutil.ReadFile(path) 32 | if err != nil { 33 | t.Errorf("error reading file: %s", err) 34 | return nil 35 | } 36 | 37 | parseJSON5 := func() (interface{}, error) { 38 | var res interface{} 39 | return res, Unmarshal(data, &res) 40 | } 41 | parseJSON := func() (interface{}, error) { 42 | var res interface{} 43 | return res, json.Unmarshal(data, &res) 44 | } 45 | parseES5 := func() (interface{}, error) { 46 | vm := otto.New() 47 | _, err := vm.Run("x=" + string(data)) 48 | if err != nil { 49 | return nil, err 50 | } 51 | v, err := vm.Get("x") 52 | if err != nil { 53 | return nil, err 54 | } 55 | return v.Export() 56 | } 57 | 58 | t.Logf("file: %s", path) 59 | switch filepath.Ext(path) { 60 | case ".json": 61 | jd, err := parseJSON() 62 | if err != nil { 63 | t.Errorf("unexpected error from json decoder: %s", err) 64 | return nil 65 | } 66 | j5d, err := parseJSON5() 67 | if err != nil { 68 | t.Errorf("unexpected error from json5 decoder: %s", err) 69 | return nil 70 | } 71 | if diff := pretty.Compare(jd, j5d); diff != "" { 72 | t.Errorf("data is not equal\n%s", diff) 73 | return nil 74 | } 75 | case ".json5": 76 | if _, err := parseJSON(); err == nil { 77 | t.Errorf("expected JSON parsing to fail") 78 | return nil 79 | } 80 | es5d, err := parseES5() 81 | if err != nil { 82 | t.Errorf("unexpected error from ES5 decoder: %s", err) 83 | return nil 84 | } 85 | j5d, err := parseJSON5() 86 | if err != nil { 87 | t.Errorf("unexpected error from json5 decoder: %s", err) 88 | return nil 89 | } 90 | if diff := pretty.Compare(j5d, es5d); diff != "" { 91 | t.Errorf("data is not equal\n%s", diff) 92 | return nil 93 | } 94 | case ".js": 95 | if _, err := parseJSON(); err == nil { 96 | t.Errorf("expected JSON parsing to fail") 97 | return nil 98 | } 99 | if _, err := parseES5(); err != nil { 100 | t.Errorf("unexected error from ES5 decoder: %s", err) 101 | return nil 102 | } 103 | if _, err := parseJSON5(); err == nil { 104 | t.Errorf("expected JSON5 parsing to fail") 105 | return nil 106 | } 107 | case ".txt": 108 | var expectedErr *ErrorSpec 109 | specName := strings.TrimRight(path, filepath.Ext(path)) + ".errorSpec" 110 | specFile, err := os.Open(specName) 111 | if err != nil && !os.IsNotExist(err) { 112 | t.Errorf("error trying to open errorSpec file %s: %s", specName, err) 113 | return nil 114 | } 115 | if specFile != nil { 116 | defer specFile.Close() 117 | expectedErr = &ErrorSpec{} 118 | if err := NewDecoder(specFile).Decode(expectedErr); err != nil { 119 | t.Errorf("error decoding %s: %s", specName, err) 120 | return nil 121 | } 122 | } 123 | _, err = parseJSON5() 124 | if err == nil { 125 | t.Errorf("expected JSON5 parsing to fail") 126 | return nil 127 | } 128 | } 129 | 130 | return nil 131 | }) 132 | } 133 | 134 | // The tests below this comment were found with go-fuzz 135 | 136 | func TestQuotedQuote(t *testing.T) { 137 | var v struct { 138 | E string 139 | } 140 | if err := Unmarshal([]byte(`{e:"'"}`), &v); err != nil { 141 | t.Error(err) 142 | } 143 | if v.E != "'" { 144 | t.Errorf(`expected "'", got %q`, v.E) 145 | } 146 | } 147 | 148 | func TestInvalidNewline(t *testing.T) { 149 | expected := "invalid character '\\n' in string literal" 150 | var v interface{} 151 | if err := Unmarshal([]byte("{a:'\\\r0\n'}"), &v); err == nil || err.Error() != expected { 152 | t.Errorf("expected error %q, got %s", expected, err) 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /number_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package json5 6 | 7 | import ( 8 | "math" 9 | "testing" 10 | ) 11 | 12 | func TestNumberIsValid(t *testing.T) { 13 | validTests := []string{ 14 | "0", 15 | "-0", 16 | "1", 17 | "+1", 18 | "-1", 19 | "0.1", 20 | "-0.1", 21 | "+0.1", 22 | "1234", 23 | "-1234", 24 | "+1234", 25 | "12.34", 26 | "-12.34", 27 | "+12.34", 28 | "12E0", 29 | "12E1", 30 | "12e34", 31 | "12E-0", 32 | "12e+1", 33 | "12e-34", 34 | "-12E0", 35 | "-12E1", 36 | "-12e34", 37 | "-12E-0", 38 | "-12e+1", 39 | "-12e-34", 40 | "+12E0", 41 | "+12E1", 42 | "+12e34", 43 | "+12E-0", 44 | "+12e+1", 45 | "+12e-34", 46 | "1.2E0", 47 | "1.2E1", 48 | "1.2e34", 49 | "1.2E-0", 50 | "1.2e+1", 51 | "1.2e-34", 52 | "-1.2E0", 53 | "-1.2E1", 54 | "-1.2e34", 55 | "-1.2E-0", 56 | "-1.2e+1", 57 | "-1.2e-34", 58 | "+1.2E0", 59 | "+1.2E1", 60 | "+1.2e34", 61 | "+1.2E-0", 62 | "+1.2e+1", 63 | "+1.2e-34", 64 | "0E0", 65 | "0E1", 66 | "0e34", 67 | "0E-0", 68 | "0e+1", 69 | "0e-34", 70 | "-0E0", 71 | "-0E1", 72 | "-0e34", 73 | "-0E-0", 74 | "-0e+1", 75 | "-0e-34", 76 | "+0E0", 77 | "+0E1", 78 | "+0e34", 79 | "+0E-0", 80 | "+0e+1", 81 | "+0e-34", 82 | "1.", 83 | "+1.", 84 | "-1.", 85 | "1.e1", 86 | "+1.e1", 87 | "-1.e1", 88 | ".5", 89 | "-.5", 90 | "+.5", 91 | "0xa", 92 | "0xA", 93 | "0XA", 94 | "-0XA", 95 | "+0XA", 96 | "0x0", 97 | "0x0", 98 | "0X0", 99 | "-0X0", 100 | "+0X0", 101 | "0x2", 102 | "0x2", 103 | "0X2", 104 | "-0X2", 105 | "+0X2", 106 | "0xDEADBeef", 107 | "-0xDEADBeef", 108 | "+0xDEADBeef", 109 | "0XDEADBeef", 110 | "-0XDEADBeef", 111 | "+0XDEADBeef", 112 | "0xDEAD3eef", 113 | "-0xDEAD3eef", 114 | "+0xDEAD3eef", 115 | "0XDEAD3eef", 116 | "-0XDEAD3eef", 117 | "+0XDEAD3eef", 118 | "NaN", 119 | "+Infinity", 120 | "-Infinity", 121 | "Infinity", 122 | } 123 | 124 | for _, test := range validTests { 125 | if !isValidNumber(test) { 126 | t.Errorf("%s should be valid", test) 127 | } 128 | 129 | var f float64 130 | if err := Unmarshal([]byte(test), &f); err != nil { 131 | t.Errorf("%s should be valid but Unmarshal failed: %v", test, err) 132 | } 133 | } 134 | 135 | invalidTests := []string{ 136 | "", 137 | "invalid", 138 | "1.0.1", 139 | "1..1", 140 | "-1-2", 141 | "012a42", 142 | "01.2", 143 | "012", 144 | "12E12.12", 145 | "1e2e3", 146 | "1e+-2", 147 | "1e--23", 148 | "1e", 149 | "e1", 150 | "1e+", 151 | "1ea", 152 | "1a", 153 | "1.a", 154 | "01", 155 | "0xDsADBeef", 156 | ".0xDEADBeef", 157 | "0XDsADBeef", 158 | ".0XDEADBeef", 159 | "+NaN", 160 | "-NaN", 161 | ".NaN", 162 | ".Infinity", 163 | "0xs", 164 | } 165 | 166 | for _, test := range invalidTests { 167 | if isValidNumber(test) { 168 | t.Errorf("%s should be invalid", test) 169 | } 170 | 171 | var f float64 172 | if err := Unmarshal([]byte(test), &f); err == nil { 173 | t.Errorf("%s should be invalid but unmarshal wrote %v", test, f) 174 | } 175 | } 176 | } 177 | 178 | func BenchmarkNumberIsValid(b *testing.B) { 179 | s := "-61657.61667E+61673" 180 | for i := 0; i < b.N; i++ { 181 | isValidNumber(s) 182 | } 183 | } 184 | 185 | func TestNumberFloat64(t *testing.T) { 186 | tests := map[string]float64{ 187 | "0xDeADb": 0xdeadb, 188 | "+0xDeADb": 0xdeadb, 189 | "-0xDeADb": -0xdeadb, 190 | "-0XDeADb": -0xdeadb, 191 | "-0x0": math.Copysign(0, -1), 192 | ".5": 0.5, 193 | "-.5": -0.5, 194 | "+1.e1": 1.e1, 195 | "-1.e1": -1.e1, 196 | "-0": math.Copysign(0, -1), 197 | "-Infinity": math.Inf(-1), 198 | "Infinity": math.Inf(0), 199 | "+Infinity": math.Inf(1), 200 | "NaN": math.NaN(), 201 | } 202 | 203 | for s, f := range tests { 204 | res, err := Number(s).Float64() 205 | if err != nil { 206 | t.Errorf("failed to parse %s: %s", s, err) 207 | } 208 | if s == "NaN" { 209 | if !math.IsNaN(res) { 210 | t.Errorf("expected NaN") 211 | } 212 | } else { 213 | if res != f { 214 | t.Errorf("wanted %v, got %v", f, res) 215 | } 216 | } 217 | } 218 | } 219 | 220 | func TestNumberInt64(t *testing.T) { 221 | tests := map[string]int64{ 222 | "0xDeADb": 0xdeadb, 223 | "+0xDeADb": 0xdeadb, 224 | "-0xDeADb": -0xdeadb, 225 | "-0XDeADb": -0xdeadb, 226 | "0x0": 0, 227 | } 228 | 229 | for s, i := range tests { 230 | res, err := Number(s).Int64() 231 | if err != nil { 232 | t.Errorf("failed to parse %s: %s", s, err) 233 | } 234 | if res != i { 235 | t.Errorf("wanted %v, got %v", i, res) 236 | } 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /scanner.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package json5 6 | 7 | // JSON value parser state machine. 8 | // Just about at the limit of what is reasonable to write by hand. 9 | // Some parts are a bit tedious, but overall it nicely factors out the 10 | // otherwise common code from the multiple scanning functions 11 | // in this package (Compact, Indent, checkValid, nextValue, etc). 12 | // 13 | // This file starts with two simple examples using the scanner 14 | // before diving into the scanner itself. 15 | 16 | import "strconv" 17 | 18 | // checkValid verifies that data is valid JSON-encoded data. 19 | // scan is passed in for use by checkValid to avoid an allocation. 20 | func checkValid(data []byte, scan *scanner) error { 21 | scan.reset() 22 | for _, c := range data { 23 | scan.bytes++ 24 | if scan.step(scan, c) == scanError { 25 | return scan.err 26 | } 27 | } 28 | if scan.eof() == scanError { 29 | return scan.err 30 | } 31 | return nil 32 | } 33 | 34 | // nextValue splits data after the next whole JSON value, 35 | // returning that value and the bytes that follow it as separate slices. 36 | // scan is passed in for use by nextValue to avoid an allocation. 37 | func nextValue(data []byte, scan *scanner) (value, rest []byte, err error) { 38 | scan.reset() 39 | for i, c := range data { 40 | v := scan.step(scan, c) 41 | if v >= scanEndObject { 42 | switch v { 43 | // probe the scanner with a space to determine whether we will 44 | // get scanEnd on the next character. Otherwise, if the next character 45 | // is not a space, scanEndTop allocates a needless error. 46 | case scanEndObject, scanEndArray: 47 | if scan.step(scan, ' ') == scanEnd { 48 | return data[:i+1], data[i+1:], nil 49 | } 50 | case scanError: 51 | return nil, nil, scan.err 52 | case scanEnd: 53 | return data[:i], data[i:], nil 54 | } 55 | } 56 | } 57 | if scan.eof() == scanError { 58 | return nil, nil, scan.err 59 | } 60 | return data, nil, nil 61 | } 62 | 63 | // A SyntaxError is a description of a JSON syntax error. 64 | type SyntaxError struct { 65 | msg string // description of error 66 | Offset int64 // error occurred after reading Offset bytes 67 | } 68 | 69 | func (e *SyntaxError) Error() string { return e.msg } 70 | 71 | // A scanner is a JSON scanning state machine. 72 | // Callers call scan.reset() and then pass bytes in one at a time 73 | // by calling scan.step(&scan, c) for each byte. 74 | // The return value, referred to as an opcode, tells the 75 | // caller about significant parsing events like beginning 76 | // and ending literals, objects, and arrays, so that the 77 | // caller can follow along if it wishes. 78 | // The return value scanEnd indicates that a single top-level 79 | // JSON value has been completed, *before* the byte that 80 | // just got passed in. (The indication must be delayed in order 81 | // to recognize the end of numbers: is 123 a whole value or 82 | // the beginning of 12345e+6?). 83 | type scanner struct { 84 | // The step is a func to be called to execute the next transition. 85 | // Also tried using an integer constant and a single func 86 | // with a switch, but using the func directly was 10% faster 87 | // on a 64-bit Mac Mini, and it's nicer to read. 88 | step func(*scanner, byte) int 89 | 90 | // Comments are hidden from callers of the scanner, commentEndStep is used 91 | // to resume normal parsing when a comment ends. 92 | commentEndStep func(*scanner, byte) int 93 | 94 | // Reached end of top-level value. 95 | endTop bool 96 | 97 | // Stack of what we're in the middle of - array values, object keys, object values. 98 | parseState []int 99 | 100 | // Error that happened, if any. 101 | err error 102 | 103 | // 1-byte redo (see undo method) 104 | redo bool 105 | redoCode int 106 | redoState func(*scanner, byte) int 107 | 108 | // total bytes consumed, updated by decoder.Decode 109 | bytes int64 110 | } 111 | 112 | // These values are returned by the state transition functions 113 | // assigned to scanner.state and the method scanner.eof. 114 | // They give details about the current state of the scan that 115 | // callers might be interested to know about. 116 | // It is okay to ignore the return value of any particular 117 | // call to scanner.state: if one call returns scanError, 118 | // every subsequent call will return scanError too. 119 | const ( 120 | // Continue. 121 | scanContinue = iota // uninteresting byte 122 | scanBeginLiteral // end implied by next result != scanContinue 123 | scanBeginObject // begin object 124 | scanObjectKey // just finished object key (string) 125 | scanObjectValue // just finished non-last object value 126 | scanEndObject // end object (implies scanObjectValue if possible) 127 | scanBeginArray // begin array 128 | scanArrayValue // just finished array value 129 | scanEndArray // end array (implies scanArrayValue if possible) 130 | scanSkipSpace // space byte; can skip; known to be last "continue" result 131 | 132 | // Stop. 133 | scanEnd // top-level value ended *before* this byte; known to be first "stop" result 134 | scanError // hit an error, scanner.err. 135 | ) 136 | 137 | // These values are stored in the parseState stack. 138 | // They give the current state of a composite value 139 | // being scanned. If the parser is inside a nested value 140 | // the parseState describes the nested state, outermost at entry 0. 141 | const ( 142 | parseObjectKey = iota // parsing object key (before colon) 143 | parseObjectValue // parsing object value (after colon) 144 | parseArrayValue // parsing array value 145 | ) 146 | 147 | // reset prepares the scanner for use. 148 | // It must be called before calling s.step. 149 | func (s *scanner) reset() { 150 | s.step = stateBeginValue 151 | s.parseState = s.parseState[0:0] 152 | s.err = nil 153 | s.redo = false 154 | s.endTop = false 155 | } 156 | 157 | // eof tells the scanner that the end of input has been reached. 158 | // It returns a scan status just as s.step does. 159 | func (s *scanner) eof() int { 160 | if s.err != nil { 161 | return scanError 162 | } 163 | if s.endTop { 164 | return scanEnd 165 | } 166 | s.step(s, ' ') 167 | if s.endTop { 168 | return scanEnd 169 | } 170 | if s.err == nil { 171 | s.err = &SyntaxError{"unexpected end of JSON input", s.bytes} 172 | } 173 | return scanError 174 | } 175 | 176 | // pushParseState pushes a new parse state p onto the parse stack. 177 | func (s *scanner) pushParseState(p int) { 178 | s.parseState = append(s.parseState, p) 179 | } 180 | 181 | // popParseState pops a parse state (already obtained) off the stack 182 | // and updates s.step accordingly. 183 | func (s *scanner) popParseState() { 184 | n := len(s.parseState) - 1 185 | s.parseState = s.parseState[0:n] 186 | s.redo = false 187 | if n == 0 { 188 | s.step = stateEndTop 189 | s.endTop = true 190 | } else { 191 | s.step = stateEndValue 192 | } 193 | } 194 | 195 | func isSpace(c byte) bool { 196 | return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' 197 | } 198 | 199 | // stateBeginValueOrEmpty is the state after reading `[`. 200 | func stateBeginValueOrEmpty(s *scanner, c byte) int { 201 | if c <= ' ' && isSpace(c) { 202 | return scanSkipSpace 203 | } 204 | if c == ']' { 205 | return stateEndValue(s, c) 206 | } 207 | if c == '/' { 208 | s.step = stateBeginComment 209 | s.commentEndStep = stateBeginValueOrEmpty 210 | return scanSkipSpace 211 | } 212 | return stateBeginValue(s, c) 213 | } 214 | 215 | // stateBeginValue is the state at the beginning of the input. 216 | func stateBeginValue(s *scanner, c byte) int { 217 | if c <= ' ' && isSpace(c) { 218 | return scanSkipSpace 219 | } 220 | switch c { 221 | case '{': 222 | s.step = stateBeginObjectKeyOrEmpty 223 | s.pushParseState(parseObjectKey) 224 | return scanBeginObject 225 | case '[': 226 | s.step = stateBeginValueOrEmpty 227 | s.pushParseState(parseArrayValue) 228 | return scanBeginArray 229 | case '"': 230 | s.step = stateInStringDouble 231 | return scanBeginLiteral 232 | case '\'': 233 | s.step = stateInStringSingle 234 | return scanBeginLiteral 235 | case '-', '+': 236 | s.step = stateSign 237 | return scanBeginLiteral 238 | case '.': 239 | s.step = stateDot 240 | return scanBeginLiteral 241 | case '0': // beginning of 0.123 242 | s.step = stateFirst0 243 | return scanBeginLiteral 244 | case 't': // beginning of true 245 | s.step = stateT 246 | return scanBeginLiteral 247 | case 'f': // beginning of false 248 | s.step = stateF 249 | return scanBeginLiteral 250 | case 'n': // beginning of null 251 | s.step = stateN 252 | return scanBeginLiteral 253 | case 'I': // beginning of Infinity 254 | s.step = stateInfinity 255 | return scanBeginLiteral 256 | case 'N': // beginning of NaN 257 | s.step = stateNaN 258 | return scanBeginLiteral 259 | case '/': 260 | s.step = stateBeginComment 261 | s.commentEndStep = stateBeginValue 262 | return scanSkipSpace 263 | } 264 | if '1' <= c && c <= '9' { // beginning of 1234.5 265 | s.step = state1 266 | return scanBeginLiteral 267 | } 268 | return s.error(c, "looking for beginning of value") 269 | } 270 | 271 | func stateBeginComment(s *scanner, c byte) int { 272 | if c == '/' { 273 | s.step = stateInLineComment 274 | return scanSkipSpace 275 | } 276 | if c == '*' { 277 | s.step = stateInBlockComment 278 | return scanSkipSpace 279 | } 280 | return s.error(c, "potentially starting comment") 281 | } 282 | 283 | func stateInLineComment(s *scanner, c byte) int { 284 | if c == '\r' { 285 | s.step = stateInLineCommentCR 286 | } 287 | if c == '\n' { 288 | s.step = s.commentEndStep 289 | s.commentEndStep = nil 290 | } 291 | return scanSkipSpace 292 | } 293 | 294 | func stateInLineCommentCR(s *scanner, c byte) int { 295 | if c == '\n' { 296 | s.step = s.commentEndStep 297 | s.commentEndStep = nil 298 | return scanSkipSpace 299 | } 300 | return s.commentEndStep(s, c) 301 | } 302 | 303 | func stateInBlockComment(s *scanner, c byte) int { 304 | if c == '*' { 305 | s.step = stateMaybeEndBlockComment 306 | } 307 | return scanSkipSpace 308 | } 309 | 310 | func stateMaybeEndBlockComment(s *scanner, c byte) int { 311 | if c == '/' { 312 | s.step = s.commentEndStep 313 | s.commentEndStep = nil 314 | } 315 | return scanSkipSpace 316 | } 317 | 318 | // stateBeginObjectKeyOrEmpty is the state after reading `{`. 319 | func stateBeginObjectKeyOrEmpty(s *scanner, c byte) int { 320 | if c <= ' ' && isSpace(c) { 321 | return scanSkipSpace 322 | } 323 | if c == '}' { 324 | n := len(s.parseState) 325 | s.parseState[n-1] = parseObjectValue 326 | return stateEndValue(s, c) 327 | } 328 | if c == '/' { 329 | s.step = stateBeginComment 330 | s.commentEndStep = stateBeginObjectKeyOrEmpty 331 | return scanSkipSpace 332 | } 333 | return stateBeginObjectKey(s, c) 334 | } 335 | 336 | // stateBeginObjectKey is the state after reading `{"key": value,`. 337 | func stateBeginObjectKey(s *scanner, c byte) int { 338 | if c <= ' ' && isSpace(c) { 339 | return scanSkipSpace 340 | } 341 | if c == '"' { 342 | s.step = stateInStringDouble 343 | return scanBeginLiteral 344 | } 345 | if c == '\'' { 346 | s.step = stateInStringSingle 347 | return scanBeginLiteral 348 | } 349 | if isValidKeyLiteralFirstByte(c) { 350 | s.step = stateInKeyLiteral 351 | return scanBeginLiteral 352 | } 353 | if c == '/' { 354 | s.step = stateBeginComment 355 | s.commentEndStep = stateBeginObjectKey 356 | return scanSkipSpace 357 | } 358 | 359 | return s.error(c, "looking for beginning of object key") 360 | } 361 | 362 | // stateInKeyLiteral is the state when starting to read an object key with no quotes 363 | func stateInKeyLiteral(s *scanner, c byte) int { 364 | if c == ':' || isSpace(c) { 365 | return stateEndValue(s, c) 366 | } 367 | if !isValidKeyLiteralByte(c) { 368 | return s.error(c, "in key literal") 369 | } 370 | return scanContinue 371 | } 372 | 373 | func isValidKeyLiteralFirstByte(c byte) bool { 374 | return isValidKeyLiteralByte(c) && (c < '0' || c > '9') 375 | } 376 | 377 | func isValidKeyLiteralByte(c byte) bool { 378 | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '$' 379 | } 380 | 381 | // stateEndValue is the state after completing a value, 382 | // such as after reading `{}` or `true` or `["x"`. 383 | func stateEndValue(s *scanner, c byte) int { 384 | n := len(s.parseState) 385 | if n == 0 { 386 | // Completed top-level before the current byte. 387 | s.step = stateEndTop 388 | s.endTop = true 389 | return stateEndTop(s, c) 390 | } 391 | if c <= ' ' && isSpace(c) { 392 | s.step = stateEndValue 393 | return scanSkipSpace 394 | } 395 | if c == '/' { 396 | s.step = stateBeginComment 397 | s.commentEndStep = stateEndValue 398 | return scanSkipSpace 399 | } 400 | ps := s.parseState[n-1] 401 | switch ps { 402 | case parseObjectKey: 403 | if c == ':' { 404 | s.parseState[n-1] = parseObjectValue 405 | s.step = stateBeginValue 406 | return scanObjectKey 407 | } 408 | return s.error(c, "after object key") 409 | case parseObjectValue: 410 | if c == ',' { 411 | s.parseState[n-1] = parseObjectKey 412 | s.step = stateBeginObjectKeyOrEmpty 413 | return scanObjectValue 414 | } 415 | if c == '}' { 416 | s.popParseState() 417 | return scanEndObject 418 | } 419 | return s.error(c, "after object key:value pair") 420 | case parseArrayValue: 421 | if c == ',' { 422 | s.step = stateBeginValueOrEmpty 423 | return scanArrayValue 424 | } 425 | if c == ']' { 426 | s.popParseState() 427 | return scanEndArray 428 | } 429 | return s.error(c, "after array element") 430 | } 431 | return s.error(c, "") 432 | } 433 | 434 | // stateEndTop is the state after finishing the top-level value, 435 | // such as after reading `{}` or `[1,2,3]`. 436 | // Only space characters should be seen now. 437 | func stateEndTop(s *scanner, c byte) int { 438 | if c == '/' { 439 | s.step = stateBeginComment 440 | s.commentEndStep = stateEndTop 441 | return scanSkipSpace 442 | } 443 | if c != ' ' && c != '\t' && c != '\r' && c != '\n' { 444 | // Complain about non-space byte on next call. 445 | s.error(c, "after top-level value") 446 | } 447 | return scanEnd 448 | } 449 | 450 | // stateInStringDouble is the state after reading `"`. 451 | func stateInStringDouble(s *scanner, c byte) int { 452 | if c == '"' { 453 | s.step = stateEndValue 454 | return scanContinue 455 | } 456 | if c == '\\' { 457 | s.step = stateInStringEsc(stateInStringDouble) 458 | return scanContinue 459 | } 460 | if c < 0x20 { 461 | return s.error(c, "in string literal") 462 | } 463 | return scanContinue 464 | } 465 | 466 | // stateInStringSingle is the state after reading `"`. 467 | func stateInStringSingle(s *scanner, c byte) int { 468 | if c == '\'' { 469 | s.step = stateEndValue 470 | return scanContinue 471 | } 472 | if c == '\\' { 473 | s.step = stateInStringEsc(stateInStringSingle) 474 | return scanContinue 475 | } 476 | if c < 0x20 { 477 | return s.error(c, "in string literal") 478 | } 479 | return scanContinue 480 | } 481 | 482 | // stateInStringEsc is the state after reading `"\` during a quoted string. 483 | func stateInStringEsc(resume func(s *scanner, c byte) int) func(s *scanner, c byte) int { 484 | return func(s *scanner, c byte) int { 485 | switch c { 486 | case 'b', 'f', 'n', 'r', 't', '\\', '/', '"', '\'', '\n': 487 | s.step = resume 488 | return scanContinue 489 | case 'u': 490 | s.step = stateInStringEscU(resume) 491 | return scanContinue 492 | case '\r': 493 | s.step = stateInStringEscCR(resume) 494 | return scanContinue 495 | } 496 | return s.error(c, "in string escape code") 497 | } 498 | } 499 | 500 | // stateInStringEscCR is the state after reading `"\\r` during a quoted string. 501 | func stateInStringEscCR(resume func(s *scanner, c byte) int) func(s *scanner, c byte) int { 502 | return func(s *scanner, c byte) int { 503 | s.step = resume 504 | if c == '\n' { 505 | return scanContinue 506 | } 507 | return resume(s, c) 508 | } 509 | } 510 | 511 | // stateInStringEscU is the state after reading `"\u` during a quoted string. 512 | func stateInStringEscU(resume func(s *scanner, c byte) int) func(s *scanner, c byte) int { 513 | return func(s *scanner, c byte) int { 514 | if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { 515 | s.step = stateInStringEscU1(resume) 516 | return scanContinue 517 | } 518 | // numbers 519 | return s.error(c, "in \\u hexadecimal character escape") 520 | } 521 | } 522 | 523 | // stateInStringEscU1 is the state after reading `"\u1` during a quoted string. 524 | func stateInStringEscU1(resume func(s *scanner, c byte) int) func(s *scanner, c byte) int { 525 | return func(s *scanner, c byte) int { 526 | if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { 527 | s.step = stateInStringEscU12(resume) 528 | return scanContinue 529 | } 530 | // numbers 531 | return s.error(c, "in \\u hexadecimal character escape") 532 | } 533 | } 534 | 535 | // stateInStringEscU12 is the state after reading `"\u12` during a quoted string. 536 | func stateInStringEscU12(resume func(s *scanner, c byte) int) func(s *scanner, c byte) int { 537 | return func(s *scanner, c byte) int { 538 | if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { 539 | s.step = stateInStringEscU123(resume) 540 | return scanContinue 541 | } 542 | // numbers 543 | return s.error(c, "in \\u hexadecimal character escape") 544 | } 545 | } 546 | 547 | // stateInStringEscU123 is the state after reading `"\u123` during a quoted string. 548 | func stateInStringEscU123(resume func(s *scanner, c byte) int) func(s *scanner, c byte) int { 549 | return func(s *scanner, c byte) int { 550 | if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { 551 | s.step = resume 552 | return scanContinue 553 | } 554 | // numbers 555 | return s.error(c, "in \\u hexadecimal character escape") 556 | } 557 | } 558 | 559 | // stateSign is the state after reading `+` or `-` during a number. 560 | func stateSign(s *scanner, c byte) int { 561 | switch { 562 | case c == '0': 563 | s.step = stateFirst0 564 | return scanContinue 565 | case '1' <= c && c <= '9': 566 | s.step = state1 567 | return scanContinue 568 | case c == '.': 569 | s.step = stateSign 570 | return scanContinue 571 | case c == 'I': 572 | s.step = stateInfinity 573 | return scanContinue 574 | default: 575 | return s.error(c, "in numeric literal") 576 | } 577 | } 578 | 579 | // state1 is the state after reading a non-zero integer during a number, 580 | // such as after reading `1` or `100` but not `0`. 581 | func state1(s *scanner, c byte) int { 582 | if '0' <= c && c <= '9' { 583 | s.step = state1 584 | return scanContinue 585 | } 586 | return state0(s, c) 587 | } 588 | 589 | // stateFirst0 is the state after the first integer in a number is `0` 590 | func stateFirst0(s *scanner, c byte) int { 591 | switch c { 592 | case '.': 593 | s.step = stateDot 594 | return scanContinue 595 | case 'e', 'E': 596 | s.step = stateE 597 | return scanContinue 598 | case 'x', 'X': 599 | s.step = stateFirstHex 600 | return scanContinue 601 | default: 602 | return stateEndValue(s, c) 603 | } 604 | } 605 | 606 | // stateFirstHex is the state after reading 0x in a number 607 | func stateFirstHex(s *scanner, c byte) int { 608 | if (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') { 609 | s.step = stateHex 610 | return scanContinue 611 | } 612 | return s.error(c, "in hex number") 613 | } 614 | 615 | // stateHex is the state after reading the first hex digit in a number 616 | func stateHex(s *scanner, c byte) int { 617 | if (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') { 618 | return scanContinue 619 | } 620 | return stateEndValue(s, c) 621 | } 622 | 623 | // state0 is the state after reading `0` during a number. 624 | func state0(s *scanner, c byte) int { 625 | if c == '.' { 626 | s.step = stateDot 627 | return scanContinue 628 | } 629 | if c == 'e' || c == 'E' { 630 | s.step = stateE 631 | return scanContinue 632 | } 633 | return stateEndValue(s, c) 634 | } 635 | 636 | // stateDot is the state after reading the integer and decimal point in a number, 637 | // such as after reading `1.`. 638 | func stateDot(s *scanner, c byte) int { 639 | if '0' <= c && c <= '9' { 640 | s.step = stateDot0 641 | return scanContinue 642 | } 643 | if c == 'e' || c == 'E' { 644 | s.step = stateE 645 | return scanContinue 646 | } 647 | return stateEndValue(s, c) 648 | } 649 | 650 | // stateDot0 is the state after reading the integer, decimal point, and subsequent 651 | // digits of a number, such as after reading `3.14`. 652 | func stateDot0(s *scanner, c byte) int { 653 | if '0' <= c && c <= '9' { 654 | return scanContinue 655 | } 656 | if c == 'e' || c == 'E' { 657 | s.step = stateE 658 | return scanContinue 659 | } 660 | return stateEndValue(s, c) 661 | } 662 | 663 | // stateE is the state after reading the mantissa and e in a number, 664 | // such as after reading `314e` or `0.314e`. 665 | func stateE(s *scanner, c byte) int { 666 | if c == '+' || c == '-' { 667 | s.step = stateESign 668 | return scanContinue 669 | } 670 | return stateESign(s, c) 671 | } 672 | 673 | // stateESign is the state after reading the mantissa, e, and sign in a number, 674 | // such as after reading `314e-` or `0.314e+`. 675 | func stateESign(s *scanner, c byte) int { 676 | if '0' <= c && c <= '9' { 677 | s.step = stateE0 678 | return scanContinue 679 | } 680 | return s.error(c, "in exponent of numeric literal") 681 | } 682 | 683 | // stateE0 is the state after reading the mantissa, e, optional sign, 684 | // and at least one digit of the exponent in a number, 685 | // such as after reading `314e-2` or `0.314e+1` or `3.14e0`. 686 | func stateE0(s *scanner, c byte) int { 687 | if '0' <= c && c <= '9' { 688 | return scanContinue 689 | } 690 | return stateEndValue(s, c) 691 | } 692 | 693 | // stateT is the state after reading `t`. 694 | func stateT(s *scanner, c byte) int { 695 | if c == 'r' { 696 | s.step = stateTr 697 | return scanContinue 698 | } 699 | return s.error(c, "in literal true (expecting 'r')") 700 | } 701 | 702 | // stateTr is the state after reading `tr`. 703 | func stateTr(s *scanner, c byte) int { 704 | if c == 'u' { 705 | s.step = stateTru 706 | return scanContinue 707 | } 708 | return s.error(c, "in literal true (expecting 'u')") 709 | } 710 | 711 | // stateTru is the state after reading `tru`. 712 | func stateTru(s *scanner, c byte) int { 713 | if c == 'e' { 714 | s.step = stateEndValue 715 | return scanContinue 716 | } 717 | return s.error(c, "in literal true (expecting 'e')") 718 | } 719 | 720 | // stateF is the state after reading `f`. 721 | func stateF(s *scanner, c byte) int { 722 | if c == 'a' { 723 | s.step = stateFa 724 | return scanContinue 725 | } 726 | return s.error(c, "in literal false (expecting 'a')") 727 | } 728 | 729 | // stateFa is the state after reading `fa`. 730 | func stateFa(s *scanner, c byte) int { 731 | if c == 'l' { 732 | s.step = stateFal 733 | return scanContinue 734 | } 735 | return s.error(c, "in literal false (expecting 'l')") 736 | } 737 | 738 | // stateFal is the state after reading `fal`. 739 | func stateFal(s *scanner, c byte) int { 740 | if c == 's' { 741 | s.step = stateFals 742 | return scanContinue 743 | } 744 | return s.error(c, "in literal false (expecting 's')") 745 | } 746 | 747 | // stateFals is the state after reading `fals`. 748 | func stateFals(s *scanner, c byte) int { 749 | if c == 'e' { 750 | s.step = stateEndValue 751 | return scanContinue 752 | } 753 | return s.error(c, "in literal false (expecting 'e')") 754 | } 755 | 756 | // stateN is the state after reading `n`. 757 | func stateN(s *scanner, c byte) int { 758 | if c == 'u' { 759 | s.step = stateNu 760 | return scanContinue 761 | } 762 | return s.error(c, "in literal null (expecting 'u')") 763 | } 764 | 765 | // stateNu is the state after reading `nu`. 766 | func stateNu(s *scanner, c byte) int { 767 | if c == 'l' { 768 | s.step = stateNul 769 | return scanContinue 770 | } 771 | return s.error(c, "in literal null (expecting 'l')") 772 | } 773 | 774 | // stateNul is the state after reading `nul`. 775 | func stateNul(s *scanner, c byte) int { 776 | if c == 'l' { 777 | s.step = stateEndValue 778 | return scanContinue 779 | } 780 | return s.error(c, "in literal null (expecting 'l')") 781 | } 782 | 783 | func stateInfinity(s *scanner, c byte) int { 784 | str := "nfinity" 785 | nextState := func(s *scanner, c byte) int { 786 | if c == str[0] { 787 | str = str[1:] 788 | if str == "" { 789 | s.step = stateEndValue 790 | } 791 | return scanContinue 792 | } 793 | return s.error(c, "in literal Infinity (expecting "+quoteChar(str[0])+")") 794 | } 795 | s.step = nextState 796 | return nextState(s, c) 797 | } 798 | 799 | func stateNaN(s *scanner, c byte) int { 800 | str := "aN" 801 | nextState := func(s *scanner, c byte) int { 802 | if c == str[0] { 803 | str = str[1:] 804 | if str == "" { 805 | s.step = stateEndValue 806 | } 807 | return scanContinue 808 | } 809 | return s.error(c, "in literal NaN (expecting "+quoteChar(str[0])+")") 810 | } 811 | s.step = nextState 812 | return nextState(s, c) 813 | } 814 | 815 | // stateError is the state after reaching a syntax error, 816 | // such as after reading `[1}` or `5.1.2`. 817 | func stateError(s *scanner, c byte) int { 818 | return scanError 819 | } 820 | 821 | // error records an error and switches to the error state. 822 | func (s *scanner) error(c byte, context string) int { 823 | s.step = stateError 824 | s.err = &SyntaxError{"invalid character " + quoteChar(c) + " " + context, s.bytes} 825 | return scanError 826 | } 827 | 828 | // quoteChar formats c as a quoted character literal 829 | func quoteChar(c byte) string { 830 | // special cases - different from quoted strings 831 | if c == '\'' { 832 | return `'\''` 833 | } 834 | if c == '"' { 835 | return `'"'` 836 | } 837 | 838 | // use quoted string with different quotation marks 839 | s := strconv.Quote(string(c)) 840 | return "'" + s[1:len(s)-1] + "'" 841 | } 842 | 843 | // undo causes the scanner to return scanCode from the next state transition. 844 | // This gives callers a simple 1-byte undo mechanism. 845 | func (s *scanner) undo(scanCode int) { 846 | if s.redo { 847 | panic("json: invalid use of scanner") 848 | } 849 | s.redoCode = scanCode 850 | s.redoState = s.step 851 | s.step = stateRedo 852 | s.redo = true 853 | } 854 | 855 | // stateRedo helps implement the scanner's 1-byte undo. 856 | func stateRedo(s *scanner, c byte) int { 857 | s.redo = false 858 | s.step = s.redoState 859 | return s.redoCode 860 | } 861 | -------------------------------------------------------------------------------- /scanner_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package json5 6 | 7 | import ( 8 | "math" 9 | "math/rand" 10 | "testing" 11 | ) 12 | 13 | // Tests of simple examples. 14 | 15 | type example struct { 16 | compact string 17 | indent string 18 | } 19 | 20 | var examples = []example{ 21 | {`1`, `1`}, 22 | {`{}`, `{}`}, 23 | {`[]`, `[]`}, 24 | {`{"":2}`, "{\n\t\"\": 2\n}"}, 25 | {`[3]`, "[\n\t3\n]"}, 26 | {`[1,2,3]`, "[\n\t1,\n\t2,\n\t3\n]"}, 27 | {`{"x":1}`, "{\n\t\"x\": 1\n}"}, 28 | {ex1, ex1i}, 29 | } 30 | 31 | var ex1 = `[true,false,null,"x",1,1.5,0,-5e+2]` 32 | 33 | var ex1i = `[ 34 | true, 35 | false, 36 | null, 37 | "x", 38 | 1, 39 | 1.5, 40 | 0, 41 | -5e+2 42 | ]` 43 | 44 | func diff(t *testing.T, a, b []byte) { 45 | for i := 0; ; i++ { 46 | if i >= len(a) || i >= len(b) || a[i] != b[i] { 47 | j := i - 10 48 | if j < 0 { 49 | j = 0 50 | } 51 | t.Errorf("diverge at %d: «%s» vs «%s»", i, trim(a[j:]), trim(b[j:])) 52 | return 53 | } 54 | } 55 | } 56 | 57 | func trim(b []byte) []byte { 58 | if len(b) > 20 { 59 | return b[0:20] 60 | } 61 | return b 62 | } 63 | 64 | func genValue(n int) interface{} { 65 | if n > 1 { 66 | switch rand.Intn(2) { 67 | case 0: 68 | return genArray(n) 69 | case 1: 70 | return genMap(n) 71 | } 72 | } 73 | switch rand.Intn(3) { 74 | case 0: 75 | return rand.Intn(2) == 0 76 | case 1: 77 | return rand.NormFloat64() 78 | case 2: 79 | return genString(30) 80 | } 81 | panic("unreachable") 82 | } 83 | 84 | func genString(stddev float64) string { 85 | n := int(math.Abs(rand.NormFloat64()*stddev + stddev/2)) 86 | c := make([]rune, n) 87 | for i := range c { 88 | f := math.Abs(rand.NormFloat64()*64 + 32) 89 | if f > 0x10ffff { 90 | f = 0x10ffff 91 | } 92 | c[i] = rune(f) 93 | } 94 | return string(c) 95 | } 96 | 97 | func genArray(n int) []interface{} { 98 | f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2))) 99 | if f > n { 100 | f = n 101 | } 102 | if f < 1 { 103 | f = 1 104 | } 105 | x := make([]interface{}, f) 106 | for i := range x { 107 | x[i] = genValue(((i+1)*n)/f - (i*n)/f) 108 | } 109 | return x 110 | } 111 | 112 | func genMap(n int) map[string]interface{} { 113 | f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2))) 114 | if f > n { 115 | f = n 116 | } 117 | if n > 0 && f == 0 { 118 | f = 1 119 | } 120 | x := make(map[string]interface{}) 121 | for i := 0; i < f; i++ { 122 | x[genString(10)] = genValue(((i+1)*n)/f - (i*n)/f) 123 | } 124 | return x 125 | } 126 | -------------------------------------------------------------------------------- /stream.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package json5 6 | 7 | import ( 8 | "bytes" 9 | "errors" 10 | "io" 11 | ) 12 | 13 | // A Decoder reads and decodes JSON values from an input stream. 14 | type Decoder struct { 15 | r io.Reader 16 | buf []byte 17 | d decodeState 18 | scanp int // start of unread data in buf 19 | scan scanner 20 | err error 21 | 22 | tokenState int 23 | tokenStack []int 24 | } 25 | 26 | // NewDecoder returns a new decoder that reads from r. 27 | // 28 | // The decoder introduces its own buffering and may 29 | // read data from r beyond the JSON values requested. 30 | func NewDecoder(r io.Reader) *Decoder { 31 | return &Decoder{r: r} 32 | } 33 | 34 | // UseNumber causes the Decoder to unmarshal a number into an interface{} as a 35 | // Number instead of as a float64. 36 | func (dec *Decoder) UseNumber() { dec.d.useNumber = true } 37 | 38 | // DisallowUnknownFields causes the Decoder to return an error when the destination 39 | // is a struct and the input contains object keys which do not match any 40 | // non-ignored, exported fields in the destination. 41 | func (dec *Decoder) DisallowUnknownFields() { dec.d.disallowUnknownFields = true } 42 | 43 | // Decode reads the next JSON-encoded value from its 44 | // input and stores it in the value pointed to by v. 45 | // 46 | // See the documentation for Unmarshal for details about 47 | // the conversion of JSON into a Go value. 48 | func (dec *Decoder) Decode(v interface{}) error { 49 | if dec.err != nil { 50 | return dec.err 51 | } 52 | 53 | // Read whole value into buffer. 54 | n, err := dec.readValue() 55 | if err != nil { 56 | return err 57 | } 58 | dec.d.init(dec.buf[dec.scanp : dec.scanp+n]) 59 | dec.scanp += n 60 | 61 | // Don't save err from unmarshal into dec.err: 62 | // the connection is still usable since we read a complete JSON 63 | // object from it before the error happened. 64 | err = dec.d.unmarshal(v) 65 | 66 | return err 67 | } 68 | 69 | // Buffered returns a reader of the data remaining in the Decoder's 70 | // buffer. The reader is valid until the next call to Decode. 71 | func (dec *Decoder) Buffered() io.Reader { 72 | return bytes.NewReader(dec.buf[dec.scanp:]) 73 | } 74 | 75 | // readValue reads a JSON value into dec.buf. 76 | // It returns the length of the encoding. 77 | func (dec *Decoder) readValue() (int, error) { 78 | dec.scan.reset() 79 | 80 | scanp := dec.scanp 81 | var err error 82 | Input: 83 | for { 84 | // Look in the buffer for a new value. 85 | for i, c := range dec.buf[scanp:] { 86 | dec.scan.bytes++ 87 | v := dec.scan.step(&dec.scan, c) 88 | if v == scanEnd { 89 | scanp += i 90 | break Input 91 | } 92 | // scanEnd is delayed one byte. 93 | // We might block trying to get that byte from src, 94 | // so instead invent a space byte. 95 | if (v == scanEndObject || v == scanEndArray) && dec.scan.step(&dec.scan, ' ') == scanEnd { 96 | scanp += i + 1 97 | break Input 98 | } 99 | if v == scanError { 100 | dec.err = dec.scan.err 101 | return 0, dec.scan.err 102 | } 103 | } 104 | scanp = len(dec.buf) 105 | 106 | // Did the last read have an error? 107 | // Delayed until now to allow buffer scan. 108 | if err != nil { 109 | if err == io.EOF { 110 | if dec.scan.step(&dec.scan, ' ') == scanEnd { 111 | break Input 112 | } 113 | if nonSpace(dec.buf) { 114 | err = io.ErrUnexpectedEOF 115 | } 116 | } 117 | dec.err = err 118 | return 0, err 119 | } 120 | 121 | n := scanp - dec.scanp 122 | err = dec.refill() 123 | scanp = dec.scanp + n 124 | } 125 | return scanp - dec.scanp, nil 126 | } 127 | 128 | func (dec *Decoder) refill() error { 129 | // Make room to read more into the buffer. 130 | // First slide down data already consumed. 131 | if dec.scanp > 0 { 132 | n := copy(dec.buf, dec.buf[dec.scanp:]) 133 | dec.buf = dec.buf[:n] 134 | dec.scanp = 0 135 | } 136 | 137 | // Grow buffer if not large enough. 138 | const minRead = 512 139 | if cap(dec.buf)-len(dec.buf) < minRead { 140 | newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead) 141 | copy(newBuf, dec.buf) 142 | dec.buf = newBuf 143 | } 144 | 145 | // Read. Delay error for next iteration (after scan). 146 | n, err := dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)]) 147 | dec.buf = dec.buf[0 : len(dec.buf)+n] 148 | 149 | return err 150 | } 151 | 152 | func nonSpace(b []byte) bool { 153 | for _, c := range b { 154 | if !isSpace(c) { 155 | return true 156 | } 157 | } 158 | return false 159 | } 160 | 161 | // RawMessage is a raw encoded JSON value. 162 | // It implements Marshaler and Unmarshaler and can 163 | // be used to delay JSON decoding or precompute a JSON encoding. 164 | type RawMessage []byte 165 | 166 | // UnmarshalJSON sets *m to a copy of data. 167 | func (m *RawMessage) UnmarshalJSON(data []byte) error { 168 | if m == nil { 169 | return errors.New("json.RawMessage: UnmarshalJSON on nil pointer") 170 | } 171 | *m = append((*m)[0:0], data...) 172 | return nil 173 | } 174 | 175 | var _ Unmarshaler = (*RawMessage)(nil) 176 | -------------------------------------------------------------------------------- /stream_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package json5 6 | 7 | import ( 8 | "bytes" 9 | "io/ioutil" 10 | "net" 11 | "reflect" 12 | "strings" 13 | "testing" 14 | ) 15 | 16 | // Test values for the stream test. 17 | // One of each JSON kind. 18 | var streamTest = []interface{}{ 19 | 0.1, 20 | "hello", 21 | nil, 22 | true, 23 | false, 24 | []interface{}{"a", "b", "c"}, 25 | map[string]interface{}{"K": "Kelvin", "ß": "long s"}, 26 | 3.14, // another value to make sure something can follow map 27 | } 28 | 29 | var streamEncoded = `0.1 30 | "hello" 31 | null 32 | true 33 | false 34 | ["a","b","c"] 35 | {"ß":"long s","K":"Kelvin"} 36 | 3.14 37 | ` 38 | 39 | func TestDecoder(t *testing.T) { 40 | for i := 0; i <= len(streamTest); i++ { 41 | // Use stream without newlines as input, 42 | // just to stress the decoder even more. 43 | // Our test input does not include back-to-back numbers. 44 | // Otherwise stripping the newlines would 45 | // merge two adjacent JSON values. 46 | var buf bytes.Buffer 47 | for _, c := range nlines(streamEncoded, i) { 48 | if c != '\n' { 49 | buf.WriteRune(c) 50 | } 51 | } 52 | out := make([]interface{}, i) 53 | dec := NewDecoder(&buf) 54 | for j := range out { 55 | if err := dec.Decode(&out[j]); err != nil { 56 | t.Fatalf("decode #%d/%d: %v", j, i, err) 57 | } 58 | } 59 | if !reflect.DeepEqual(out, streamTest[0:i]) { 60 | t.Errorf("decoding %d items: mismatch", i) 61 | for j := range out { 62 | if !reflect.DeepEqual(out[j], streamTest[j]) { 63 | t.Errorf("#%d: have %v want %v", j, out[j], streamTest[j]) 64 | } 65 | } 66 | break 67 | } 68 | } 69 | } 70 | 71 | func TestDecoderBuffered(t *testing.T) { 72 | r := strings.NewReader(`{"Name": "Gopher"} extra `) 73 | var m struct { 74 | Name string 75 | } 76 | d := NewDecoder(r) 77 | err := d.Decode(&m) 78 | if err != nil { 79 | t.Fatal(err) 80 | } 81 | if m.Name != "Gopher" { 82 | t.Errorf("Name = %q; want Gopher", m.Name) 83 | } 84 | rest, err := ioutil.ReadAll(d.Buffered()) 85 | if err != nil { 86 | t.Fatal(err) 87 | } 88 | if g, w := string(rest), " extra "; g != w { 89 | t.Errorf("Remaining = %q; want %q", g, w) 90 | } 91 | } 92 | 93 | func nlines(s string, n int) string { 94 | if n <= 0 { 95 | return "" 96 | } 97 | for i, c := range s { 98 | if c == '\n' { 99 | if n--; n == 0 { 100 | return s[0 : i+1] 101 | } 102 | } 103 | } 104 | return s 105 | } 106 | 107 | func TestRawMessage(t *testing.T) { 108 | // TODO(rsc): Should not need the * in *RawMessage 109 | var data struct { 110 | X float64 111 | Id *RawMessage 112 | Y float32 113 | } 114 | const raw = `["\u0056",null]` 115 | const msg = `{"X":0.1,"Id":["\u0056",null],"Y":0.2}` 116 | err := Unmarshal([]byte(msg), &data) 117 | if err != nil { 118 | t.Fatalf("Unmarshal: %v", err) 119 | } 120 | if string([]byte(*data.Id)) != raw { 121 | t.Fatalf("Raw mismatch: have %#q want %#q", []byte(*data.Id), raw) 122 | } 123 | } 124 | 125 | func TestNullRawMessage(t *testing.T) { 126 | // TODO(rsc): Should not need the * in *RawMessage 127 | var data struct { 128 | X float64 129 | Id *RawMessage 130 | Y float32 131 | } 132 | data.Id = new(RawMessage) 133 | const msg = `{"X":0.1,"Id":null,"Y":0.2}` 134 | err := Unmarshal([]byte(msg), &data) 135 | if err != nil { 136 | t.Fatalf("Unmarshal: %v", err) 137 | } 138 | if data.Id != nil { 139 | t.Fatalf("Raw mismatch: have non-nil, want nil") 140 | } 141 | } 142 | 143 | var blockingTests = []string{ 144 | `{"x": 1}`, 145 | `[1, 2, 3]`, 146 | } 147 | 148 | func TestBlocking(t *testing.T) { 149 | for _, enc := range blockingTests { 150 | r, w := net.Pipe() 151 | go w.Write([]byte(enc)) 152 | var val interface{} 153 | 154 | // If Decode reads beyond what w.Write writes above, 155 | // it will block, and the test will deadlock. 156 | if err := NewDecoder(r).Decode(&val); err != nil { 157 | t.Errorf("decoding %s: %v", enc, err) 158 | } 159 | r.Close() 160 | w.Close() 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /tags.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package json5 6 | 7 | import ( 8 | "strings" 9 | ) 10 | 11 | // tagOptions is the string following a comma in a struct field's "json" 12 | // tag, or the empty string. It does not include the leading comma. 13 | type tagOptions string 14 | 15 | // parseTag splits a struct field's json tag into its name and 16 | // comma-separated options. 17 | func parseTag(tag string) (string, tagOptions) { 18 | if idx := strings.Index(tag, ","); idx != -1 { 19 | return tag[:idx], tagOptions(tag[idx+1:]) 20 | } 21 | return tag, tagOptions("") 22 | } 23 | 24 | // Contains reports whether a comma-separated list of options 25 | // contains a particular substr flag. substr must be surrounded by a 26 | // string boundary or commas. 27 | func (o tagOptions) Contains(optionName string) bool { 28 | if len(o) == 0 { 29 | return false 30 | } 31 | s := string(o) 32 | for s != "" { 33 | var next string 34 | i := strings.Index(s, ",") 35 | if i >= 0 { 36 | s, next = s[:i], s[i+1:] 37 | } 38 | if s == optionName { 39 | return true 40 | } 41 | s = next 42 | } 43 | return false 44 | } 45 | -------------------------------------------------------------------------------- /tags_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package json5 6 | 7 | import ( 8 | "testing" 9 | ) 10 | 11 | func TestTagParsing(t *testing.T) { 12 | name, opts := parseTag("field,foobar,foo") 13 | if name != "field" { 14 | t.Fatalf("name = %q, want field", name) 15 | } 16 | for _, tt := range []struct { 17 | opt string 18 | want bool 19 | }{ 20 | {"foobar", true}, 21 | {"foo", true}, 22 | {"bar", false}, 23 | } { 24 | if opts.Contains(tt.opt) != tt.want { 25 | t.Errorf("Contains(%q) = %v", tt.opt, !tt.want) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /testdata/arrays/empty-array.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/arrays/leading-comma-array.js: -------------------------------------------------------------------------------- 1 | [ 2 | ,null 3 | ] -------------------------------------------------------------------------------- /testdata/arrays/lone-trailing-comma-array.js: -------------------------------------------------------------------------------- 1 | [ 2 | , 3 | ] -------------------------------------------------------------------------------- /testdata/arrays/no-comma-array.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 16, 3 | lineNumber: 3, 4 | columnNumber: 5, 5 | message: "Expected ']' instead of 'f'" 6 | } -------------------------------------------------------------------------------- /testdata/arrays/no-comma-array.txt: -------------------------------------------------------------------------------- 1 | [ 2 | true 3 | false 4 | ] -------------------------------------------------------------------------------- /testdata/arrays/regular-array.json: -------------------------------------------------------------------------------- 1 | [ 2 | true, 3 | false, 4 | null 5 | ] -------------------------------------------------------------------------------- /testdata/arrays/trailing-comma-array.json5: -------------------------------------------------------------------------------- 1 | [ 2 | null, 3 | ] -------------------------------------------------------------------------------- /testdata/comments/block-comment-following-array-element.json5: -------------------------------------------------------------------------------- 1 | [ 2 | false 3 | /* 4 | true 5 | */ 6 | ] -------------------------------------------------------------------------------- /testdata/comments/block-comment-following-top-level-value.json5: -------------------------------------------------------------------------------- 1 | null 2 | /* 3 | Some non-comment top-level value is needed; 4 | we use null above. 5 | */ -------------------------------------------------------------------------------- /testdata/comments/block-comment-in-string.json: -------------------------------------------------------------------------------- 1 | "This /* block comment */ isn't really a block comment." -------------------------------------------------------------------------------- /testdata/comments/block-comment-preceding-top-level-value.json5: -------------------------------------------------------------------------------- 1 | /* 2 | Some non-comment top-level value is needed; 3 | we use null below. 4 | */ 5 | null -------------------------------------------------------------------------------- /testdata/comments/block-comment-with-asterisks.json5: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a JavaDoc-like block comment. 3 | * It contains asterisks inside of it. 4 | * It might also be closed with multiple asterisks. 5 | * Like this: 6 | **/ 7 | true -------------------------------------------------------------------------------- /testdata/comments/inline-comment-following-array-element.json5: -------------------------------------------------------------------------------- 1 | [ 2 | false // true 3 | ] -------------------------------------------------------------------------------- /testdata/comments/inline-comment-following-top-level-value.json5: -------------------------------------------------------------------------------- 1 | null // Some non-comment top-level value is needed; we use null here. -------------------------------------------------------------------------------- /testdata/comments/inline-comment-in-string.json: -------------------------------------------------------------------------------- 1 | "This inline comment // isn't really an inline comment." -------------------------------------------------------------------------------- /testdata/comments/inline-comment-preceding-top-level-value.json5: -------------------------------------------------------------------------------- 1 | // Some non-comment top-level value is needed; we use null below. 2 | null -------------------------------------------------------------------------------- /testdata/comments/top-level-block-comment.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 77, 3 | lineNumber: 4, 4 | columnNumber: 3, 5 | message: "Unexpected EOF" 6 | } -------------------------------------------------------------------------------- /testdata/comments/top-level-block-comment.txt: -------------------------------------------------------------------------------- 1 | /* 2 | This should fail; 3 | comments cannot be the only top-level value. 4 | */ -------------------------------------------------------------------------------- /testdata/comments/top-level-inline-comment.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 66, 3 | lineNumber: 1, 4 | columnNumber: 67, 5 | message: "Unexpected EOF" 6 | } -------------------------------------------------------------------------------- /testdata/comments/top-level-inline-comment.txt: -------------------------------------------------------------------------------- 1 | // This should fail; comments cannot be the only top-level value. -------------------------------------------------------------------------------- /testdata/misc/empty.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/titanous/json5/5f74668fe3ed2dc3cc990224d823e5dfa0a678ac/testdata/misc/empty.txt -------------------------------------------------------------------------------- /testdata/misc/npm-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm", 3 | "publishConfig": { 4 | "proprietary-attribs": false 5 | }, 6 | "description": "A package manager for node", 7 | "keywords": [ 8 | "package manager", 9 | "modules", 10 | "install", 11 | "package.json" 12 | ], 13 | "version": "1.1.22", 14 | "preferGlobal": true, 15 | "config": { 16 | "publishtest": false 17 | }, 18 | "homepage": "http://npmjs.org/", 19 | "author": "Isaac Z. Schlueter (http://blog.izs.me)", 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/isaacs/npm" 23 | }, 24 | "bugs": { 25 | "email": "npm-@googlegroups.com", 26 | "url": "http://github.com/isaacs/npm/issues" 27 | }, 28 | "directories": { 29 | "doc": "./doc", 30 | "man": "./man", 31 | "lib": "./lib", 32 | "bin": "./bin" 33 | }, 34 | "main": "./lib/npm.js", 35 | "bin": "./bin/npm-cli.js", 36 | "dependencies": { 37 | "semver": "~1.0.14", 38 | "ini": "1", 39 | "slide": "1", 40 | "abbrev": "1", 41 | "graceful-fs": "~1.1.1", 42 | "minimatch": "~0.2", 43 | "nopt": "1", 44 | "node-uuid": "~1.3", 45 | "proto-list": "1", 46 | "rimraf": "2", 47 | "request": "~2.9", 48 | "which": "1", 49 | "tar": "~0.1.12", 50 | "fstream": "~0.1.17", 51 | "block-stream": "*", 52 | "inherits": "1", 53 | "mkdirp": "0.3", 54 | "read": "0", 55 | "lru-cache": "1", 56 | "node-gyp": "~0.4.1", 57 | "fstream-npm": "0 >=0.0.5", 58 | "uid-number": "0", 59 | "archy": "0", 60 | "chownr": "0" 61 | }, 62 | "bundleDependencies": [ 63 | "slide", 64 | "ini", 65 | "semver", 66 | "abbrev", 67 | "graceful-fs", 68 | "minimatch", 69 | "nopt", 70 | "node-uuid", 71 | "rimraf", 72 | "request", 73 | "proto-list", 74 | "which", 75 | "tar", 76 | "fstream", 77 | "block-stream", 78 | "inherits", 79 | "mkdirp", 80 | "read", 81 | "lru-cache", 82 | "node-gyp", 83 | "fstream-npm", 84 | "uid-number", 85 | "archy", 86 | "chownr" 87 | ], 88 | "devDependencies": { 89 | "ronn": "https://github.com/isaacs/ronnjs/tarball/master" 90 | }, 91 | "engines": { 92 | "node": "0.6 || 0.7 || 0.8", 93 | "npm": "1" 94 | }, 95 | "scripts": { 96 | "test": "node ./test/run.js", 97 | "prepublish": "npm prune; rm -rf node_modules/*/{test,example,bench}*; make -j4 doc", 98 | "dumpconf": "env | grep npm | sort | uniq" 99 | }, 100 | "licenses": [ 101 | { 102 | "type": "MIT +no-false-attribs", 103 | "url": "http://github.com/isaacs/npm/raw/master/LICENSE" 104 | } 105 | ] 106 | } 107 | -------------------------------------------------------------------------------- /testdata/misc/npm-package.json5: -------------------------------------------------------------------------------- 1 | { 2 | name: 'npm', 3 | publishConfig: { 4 | 'proprietary-attribs': false, 5 | }, 6 | description: 'A package manager for node', 7 | keywords: [ 8 | 'package manager', 9 | 'modules', 10 | 'install', 11 | 'package.json', 12 | ], 13 | version: '1.1.22', 14 | preferGlobal: true, 15 | config: { 16 | publishtest: false, 17 | }, 18 | homepage: 'http://npmjs.org/', 19 | author: 'Isaac Z. Schlueter (http://blog.izs.me)', 20 | repository: { 21 | type: 'git', 22 | url: 'https://github.com/isaacs/npm', 23 | }, 24 | bugs: { 25 | email: 'npm-@googlegroups.com', 26 | url: 'http://github.com/isaacs/npm/issues', 27 | }, 28 | directories: { 29 | doc: './doc', 30 | man: './man', 31 | lib: './lib', 32 | bin: './bin', 33 | }, 34 | main: './lib/npm.js', 35 | bin: './bin/npm-cli.js', 36 | dependencies: { 37 | semver: '~1.0.14', 38 | ini: '1', 39 | slide: '1', 40 | abbrev: '1', 41 | 'graceful-fs': '~1.1.1', 42 | minimatch: '~0.2', 43 | nopt: '1', 44 | 'node-uuid': '~1.3', 45 | 'proto-list': '1', 46 | rimraf: '2', 47 | request: '~2.9', 48 | which: '1', 49 | tar: '~0.1.12', 50 | fstream: '~0.1.17', 51 | 'block-stream': '*', 52 | inherits: '1', 53 | mkdirp: '0.3', 54 | read: '0', 55 | 'lru-cache': '1', 56 | 'node-gyp': '~0.4.1', 57 | 'fstream-npm': '0 >=0.0.5', 58 | 'uid-number': '0', 59 | archy: '0', 60 | chownr: '0', 61 | }, 62 | bundleDependencies: [ 63 | 'slide', 64 | 'ini', 65 | 'semver', 66 | 'abbrev', 67 | 'graceful-fs', 68 | 'minimatch', 69 | 'nopt', 70 | 'node-uuid', 71 | 'rimraf', 72 | 'request', 73 | 'proto-list', 74 | 'which', 75 | 'tar', 76 | 'fstream', 77 | 'block-stream', 78 | 'inherits', 79 | 'mkdirp', 80 | 'read', 81 | 'lru-cache', 82 | 'node-gyp', 83 | 'fstream-npm', 84 | 'uid-number', 85 | 'archy', 86 | 'chownr', 87 | ], 88 | devDependencies: { 89 | ronn: 'https://github.com/isaacs/ronnjs/tarball/master', 90 | }, 91 | engines: { 92 | node: '0.6 || 0.7 || 0.8', 93 | npm: '1', 94 | }, 95 | scripts: { 96 | test: 'node ./test/run.js', 97 | prepublish: 'npm prune; rm -rf node_modules/*/{test,example,bench}*; make -j4 doc', 98 | dumpconf: 'env | grep npm | sort | uniq', 99 | }, 100 | licenses: [ 101 | { 102 | type: 'MIT +no-false-attribs', 103 | url: 'http://github.com/isaacs/npm/raw/master/LICENSE', 104 | }, 105 | ], 106 | } 107 | -------------------------------------------------------------------------------- /testdata/misc/readme-example.json5: -------------------------------------------------------------------------------- 1 | { 2 | foo: 'bar', 3 | while: true, 4 | 5 | this: 'is a \ 6 | multi-line string', 7 | 8 | // this is an inline comment 9 | here: 'is another', // inline comment 10 | 11 | /* this is a block comment 12 | that continues on another line */ 13 | 14 | hex: 0xDeADb, 15 | half: .5, 16 | delta: +10, 17 | to: Infinity, // and beyond! 18 | 19 | finally: 'a trailing comma', 20 | oh: [ 21 | "we shouldn't forget", 22 | 'arrays can have', 23 | 'trailing commas too', 24 | ], 25 | } 26 | -------------------------------------------------------------------------------- /testdata/misc/valid-whitespace.json5: -------------------------------------------------------------------------------- 1 | { 2 | // An invalid form feed character (\x0c) has been entered before this comment. 3 | // Be careful not to delete it. 4 | "a": true 5 | } 6 | -------------------------------------------------------------------------------- /testdata/new-lines/.editorconfig: -------------------------------------------------------------------------------- 1 | # Since we're testing different representations of new lines, 2 | # make sure the editor doesn't mangle line endings. 3 | # Don't commit files in this directory unless you've checked 4 | # their escaped new lines. 5 | 6 | [*-lf.*] 7 | end_of_line = lf 8 | 9 | [*-cr.*] 10 | end_of_line = cr 11 | 12 | [*-crlf.*] 13 | end_of_line = crlf 14 | -------------------------------------------------------------------------------- /testdata/new-lines/.gitattributes: -------------------------------------------------------------------------------- 1 | # Since we're testing different representations of new lines, 2 | # treat all tests in this folder as binary files. 3 | 4 | * binary 5 | -------------------------------------------------------------------------------- /testdata/new-lines/comment-cr.json5: -------------------------------------------------------------------------------- 1 | { // This comment is terminated with `\r`. } -------------------------------------------------------------------------------- /testdata/new-lines/comment-crlf.json5: -------------------------------------------------------------------------------- 1 | { 2 | // This comment is terminated with `\r\n`. 3 | } 4 | -------------------------------------------------------------------------------- /testdata/new-lines/comment-lf.json5: -------------------------------------------------------------------------------- 1 | { 2 | // This comment is terminated with `\n`. 3 | } 4 | -------------------------------------------------------------------------------- /testdata/new-lines/escaped-cr.json5: -------------------------------------------------------------------------------- 1 | { // the following string contains an escaped `\r` a: 'line 1 \ line 2' } -------------------------------------------------------------------------------- /testdata/new-lines/escaped-crlf.json5: -------------------------------------------------------------------------------- 1 | { 2 | // the following string contains an escaped `\r\n` 3 | a: 'line 1 \ 4 | line 2' 5 | } 6 | -------------------------------------------------------------------------------- /testdata/new-lines/escaped-lf.json5: -------------------------------------------------------------------------------- 1 | { 2 | // the following string contains an escaped `\n` 3 | a: 'line 1 \ 4 | line 2' 5 | } 6 | -------------------------------------------------------------------------------- /testdata/numbers/float-leading-decimal-point.json5: -------------------------------------------------------------------------------- 1 | .5 2 | -------------------------------------------------------------------------------- /testdata/numbers/float-leading-zero.json: -------------------------------------------------------------------------------- 1 | 0.5 2 | -------------------------------------------------------------------------------- /testdata/numbers/float-trailing-decimal-point-with-integer-exponent.json5: -------------------------------------------------------------------------------- 1 | 5.e4 2 | -------------------------------------------------------------------------------- /testdata/numbers/float-trailing-decimal-point.json5: -------------------------------------------------------------------------------- 1 | 5. 2 | -------------------------------------------------------------------------------- /testdata/numbers/float-with-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 1.2e3 2 | -------------------------------------------------------------------------------- /testdata/numbers/float.json: -------------------------------------------------------------------------------- 1 | 1.2 2 | -------------------------------------------------------------------------------- /testdata/numbers/hexadecimal-empty.txt: -------------------------------------------------------------------------------- 1 | 0x 2 | -------------------------------------------------------------------------------- /testdata/numbers/hexadecimal-lowercase-letter.json5: -------------------------------------------------------------------------------- 1 | 0xc8 2 | -------------------------------------------------------------------------------- /testdata/numbers/hexadecimal-uppercase-x.json5: -------------------------------------------------------------------------------- 1 | 0XC8 2 | -------------------------------------------------------------------------------- /testdata/numbers/hexadecimal-with-integer-exponent.json5: -------------------------------------------------------------------------------- 1 | 0xc8e4 2 | -------------------------------------------------------------------------------- /testdata/numbers/hexadecimal.json5: -------------------------------------------------------------------------------- 1 | 0xC8 2 | -------------------------------------------------------------------------------- /testdata/numbers/infinity.json5: -------------------------------------------------------------------------------- 1 | Infinity 2 | -------------------------------------------------------------------------------- /testdata/numbers/integer-with-float-exponent.txt: -------------------------------------------------------------------------------- 1 | 1e2.3 2 | -------------------------------------------------------------------------------- /testdata/numbers/integer-with-hexadecimal-exponent.txt: -------------------------------------------------------------------------------- 1 | 1e0x4 2 | -------------------------------------------------------------------------------- /testdata/numbers/integer-with-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 2e23 2 | -------------------------------------------------------------------------------- /testdata/numbers/integer-with-negative-float-exponent.txt: -------------------------------------------------------------------------------- 1 | 1e-2.3 2 | -------------------------------------------------------------------------------- /testdata/numbers/integer-with-negative-hexadecimal-exponent.txt: -------------------------------------------------------------------------------- 1 | 1e-0x4 2 | -------------------------------------------------------------------------------- /testdata/numbers/integer-with-negative-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 2e-23 2 | -------------------------------------------------------------------------------- /testdata/numbers/integer-with-negative-zero-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 5e-0 2 | -------------------------------------------------------------------------------- /testdata/numbers/integer-with-positive-float-exponent.txt: -------------------------------------------------------------------------------- 1 | 1e+2.3 2 | -------------------------------------------------------------------------------- /testdata/numbers/integer-with-positive-hexadecimal-exponent.txt: -------------------------------------------------------------------------------- 1 | 1e+0x4 2 | -------------------------------------------------------------------------------- /testdata/numbers/integer-with-positive-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 1e+2 2 | -------------------------------------------------------------------------------- /testdata/numbers/integer-with-positive-zero-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 5e+0 2 | -------------------------------------------------------------------------------- /testdata/numbers/integer-with-zero-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 5e0 2 | -------------------------------------------------------------------------------- /testdata/numbers/integer.json: -------------------------------------------------------------------------------- 1 | 15 2 | -------------------------------------------------------------------------------- /testdata/numbers/lone-decimal-point.txt: -------------------------------------------------------------------------------- 1 | . 2 | -------------------------------------------------------------------------------- /testdata/numbers/nan.json5: -------------------------------------------------------------------------------- 1 | NaN 2 | -------------------------------------------------------------------------------- /testdata/numbers/negative-float-leading-decimal-point.json5: -------------------------------------------------------------------------------- 1 | -.5 2 | -------------------------------------------------------------------------------- /testdata/numbers/negative-float-leading-zero.json: -------------------------------------------------------------------------------- 1 | -0.5 2 | -------------------------------------------------------------------------------- /testdata/numbers/negative-float-trailing-decimal-point.json5: -------------------------------------------------------------------------------- 1 | -5. 2 | -------------------------------------------------------------------------------- /testdata/numbers/negative-float.json: -------------------------------------------------------------------------------- 1 | -1.2 2 | -------------------------------------------------------------------------------- /testdata/numbers/negative-hexadecimal.json5: -------------------------------------------------------------------------------- 1 | -0xC8 2 | -------------------------------------------------------------------------------- /testdata/numbers/negative-infinity.json5: -------------------------------------------------------------------------------- 1 | -Infinity 2 | -------------------------------------------------------------------------------- /testdata/numbers/negative-integer.json: -------------------------------------------------------------------------------- 1 | -15 2 | -------------------------------------------------------------------------------- /testdata/numbers/negative-octal.txt: -------------------------------------------------------------------------------- 1 | -0123 2 | -------------------------------------------------------------------------------- /testdata/numbers/negative-zero-float-leading-decimal-point.json5: -------------------------------------------------------------------------------- 1 | -.0 2 | -------------------------------------------------------------------------------- /testdata/numbers/negative-zero-float-trailing-decimal-point.json5: -------------------------------------------------------------------------------- 1 | -0. 2 | -------------------------------------------------------------------------------- /testdata/numbers/negative-zero-float.json: -------------------------------------------------------------------------------- 1 | -0.0 2 | -------------------------------------------------------------------------------- /testdata/numbers/negative-zero-hexadecimal.json5: -------------------------------------------------------------------------------- 1 | -0x0 2 | -------------------------------------------------------------------------------- /testdata/numbers/negative-zero-integer.json: -------------------------------------------------------------------------------- 1 | -0 2 | -------------------------------------------------------------------------------- /testdata/numbers/negative-zero-octal.txt: -------------------------------------------------------------------------------- 1 | -00 2 | -------------------------------------------------------------------------------- /testdata/numbers/octal.txt: -------------------------------------------------------------------------------- 1 | 010 2 | -------------------------------------------------------------------------------- /testdata/numbers/positive-float-leading-decimal-point.json5: -------------------------------------------------------------------------------- 1 | +.5 2 | -------------------------------------------------------------------------------- /testdata/numbers/positive-float-leading-zero.json5: -------------------------------------------------------------------------------- 1 | +0.5 2 | -------------------------------------------------------------------------------- /testdata/numbers/positive-float-trailing-decimal-point.json5: -------------------------------------------------------------------------------- 1 | +5. 2 | -------------------------------------------------------------------------------- /testdata/numbers/positive-float.json5: -------------------------------------------------------------------------------- 1 | +1.2 2 | -------------------------------------------------------------------------------- /testdata/numbers/positive-hexadecimal.json5: -------------------------------------------------------------------------------- 1 | +0xC8 2 | -------------------------------------------------------------------------------- /testdata/numbers/positive-infinity.json5: -------------------------------------------------------------------------------- 1 | +Infinity 2 | -------------------------------------------------------------------------------- /testdata/numbers/positive-integer.json5: -------------------------------------------------------------------------------- 1 | +15 2 | -------------------------------------------------------------------------------- /testdata/numbers/positive-octal.txt: -------------------------------------------------------------------------------- 1 | +0123 2 | -------------------------------------------------------------------------------- /testdata/numbers/positive-zero-float-leading-decimal-point.json5: -------------------------------------------------------------------------------- 1 | +.0 2 | -------------------------------------------------------------------------------- /testdata/numbers/positive-zero-float-trailing-decimal-point.json5: -------------------------------------------------------------------------------- 1 | +0. 2 | -------------------------------------------------------------------------------- /testdata/numbers/positive-zero-float.json5: -------------------------------------------------------------------------------- 1 | +0.0 2 | -------------------------------------------------------------------------------- /testdata/numbers/positive-zero-hexadecimal.json5: -------------------------------------------------------------------------------- 1 | +0x0 2 | -------------------------------------------------------------------------------- /testdata/numbers/positive-zero-integer.json5: -------------------------------------------------------------------------------- 1 | +0 2 | -------------------------------------------------------------------------------- /testdata/numbers/positive-zero-octal.txt: -------------------------------------------------------------------------------- 1 | +00 2 | -------------------------------------------------------------------------------- /testdata/numbers/zero-float-leading-decimal-point.json5: -------------------------------------------------------------------------------- 1 | .0 2 | -------------------------------------------------------------------------------- /testdata/numbers/zero-float-trailing-decimal-point.json5: -------------------------------------------------------------------------------- 1 | 0. 2 | -------------------------------------------------------------------------------- /testdata/numbers/zero-float.json: -------------------------------------------------------------------------------- 1 | 0.0 2 | -------------------------------------------------------------------------------- /testdata/numbers/zero-hexadecimal.json5: -------------------------------------------------------------------------------- 1 | 0x0 2 | -------------------------------------------------------------------------------- /testdata/numbers/zero-integer-with-integer-exponent.json: -------------------------------------------------------------------------------- 1 | 0e23 2 | -------------------------------------------------------------------------------- /testdata/numbers/zero-integer.json: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /testdata/numbers/zero-octal.txt: -------------------------------------------------------------------------------- 1 | 00 2 | -------------------------------------------------------------------------------- /testdata/objects/duplicate-keys.json: -------------------------------------------------------------------------------- 1 | { 2 | "a": true, 3 | "a": false 4 | } 5 | -------------------------------------------------------------------------------- /testdata/objects/empty-object.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /testdata/objects/illegal-unquoted-key-number.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 7, 3 | lineNumber: 2, 4 | columnNumber: 5, 5 | message: "Bad identifier as unquoted key" 6 | } -------------------------------------------------------------------------------- /testdata/objects/illegal-unquoted-key-number.txt: -------------------------------------------------------------------------------- 1 | { 2 | 10twenty: "ten twenty" 3 | } -------------------------------------------------------------------------------- /testdata/objects/illegal-unquoted-key-symbol.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 12, 3 | lineNumber: 2, 4 | columnNumber: 10, 5 | message: "Expected ':' instead of '-'" 6 | } -------------------------------------------------------------------------------- /testdata/objects/illegal-unquoted-key-symbol.txt: -------------------------------------------------------------------------------- 1 | { 2 | multi-word: "multi-word" 3 | } -------------------------------------------------------------------------------- /testdata/objects/leading-comma-object.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 7, 3 | lineNumber: 2, 4 | columnNumber: 5, 5 | message: "Bad identifier as unquoted key" 6 | } -------------------------------------------------------------------------------- /testdata/objects/leading-comma-object.txt: -------------------------------------------------------------------------------- 1 | { 2 | ,"foo": "bar" 3 | } -------------------------------------------------------------------------------- /testdata/objects/lone-trailing-comma-object.txt: -------------------------------------------------------------------------------- 1 | { 2 | , 3 | } -------------------------------------------------------------------------------- /testdata/objects/no-comma-object.txt: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar" 3 | "hello": "world" 4 | } -------------------------------------------------------------------------------- /testdata/objects/reserved-unquoted-key.json5: -------------------------------------------------------------------------------- 1 | { 2 | while: true 3 | } -------------------------------------------------------------------------------- /testdata/objects/single-quoted-key.json5: -------------------------------------------------------------------------------- 1 | { 2 | 'hello': "world" 3 | } -------------------------------------------------------------------------------- /testdata/objects/trailing-comma-object.json5: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar", 3 | } -------------------------------------------------------------------------------- /testdata/objects/unquoted-keys.json5: -------------------------------------------------------------------------------- 1 | { 2 | hello: "world", 3 | _: "underscore", 4 | $: "dollar sign", 5 | one1: "numerals", 6 | _$_: "multiple symbols", 7 | $_$hello123world_$_: "mixed" 8 | } -------------------------------------------------------------------------------- /testdata/strings/escaped-single-quoted-string.json5: -------------------------------------------------------------------------------- 1 | 'I can\'t wait' -------------------------------------------------------------------------------- /testdata/strings/multi-line-string.json5: -------------------------------------------------------------------------------- 1 | 'hello\ 2 | world' -------------------------------------------------------------------------------- /testdata/strings/no-comma-array.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 16, 3 | lineNumber: 3, 4 | columNumber: 5, 5 | message: "Expected ']' instead of 'f'" 6 | } -------------------------------------------------------------------------------- /testdata/strings/single-quoted-string.json5: -------------------------------------------------------------------------------- 1 | 'hello world' -------------------------------------------------------------------------------- /testdata/strings/unescaped-multi-line-string.errorSpec: -------------------------------------------------------------------------------- 1 | { 2 | at: 5, 3 | lineNumber: 2, 4 | columnNumber: 0, 5 | message: "Bad string" 6 | } -------------------------------------------------------------------------------- /testdata/strings/unescaped-multi-line-string.txt: -------------------------------------------------------------------------------- 1 | "foo 2 | bar" 3 | -------------------------------------------------------------------------------- /types.go: -------------------------------------------------------------------------------- 1 | package json5 2 | 3 | import ( 4 | "reflect" 5 | "sort" 6 | "strings" 7 | "sync" 8 | "unicode" 9 | ) 10 | 11 | var hex = "0123456789abcdef" 12 | 13 | // A field represents a single field found in a struct. 14 | type field struct { 15 | name string 16 | nameBytes []byte // []byte(name) 17 | equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent 18 | 19 | tag bool 20 | index []int 21 | typ reflect.Type 22 | omitEmpty bool 23 | quoted bool 24 | } 25 | 26 | func fillField(f field) field { 27 | f.nameBytes = []byte(f.name) 28 | f.equalFold = foldFunc(f.nameBytes) 29 | return f 30 | } 31 | 32 | // byName sorts field by name, breaking ties with depth, 33 | // then breaking ties with "name came from json tag", then 34 | // breaking ties with index sequence. 35 | type byName []field 36 | 37 | func (x byName) Len() int { return len(x) } 38 | 39 | func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 40 | 41 | func (x byName) Less(i, j int) bool { 42 | if x[i].name != x[j].name { 43 | return x[i].name < x[j].name 44 | } 45 | if len(x[i].index) != len(x[j].index) { 46 | return len(x[i].index) < len(x[j].index) 47 | } 48 | if x[i].tag != x[j].tag { 49 | return x[i].tag 50 | } 51 | return byIndex(x).Less(i, j) 52 | } 53 | 54 | // byIndex sorts field by index sequence. 55 | type byIndex []field 56 | 57 | func (x byIndex) Len() int { return len(x) } 58 | 59 | func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 60 | 61 | func (x byIndex) Less(i, j int) bool { 62 | for k, xik := range x[i].index { 63 | if k >= len(x[j].index) { 64 | return false 65 | } 66 | if xik != x[j].index[k] { 67 | return xik < x[j].index[k] 68 | } 69 | } 70 | return len(x[i].index) < len(x[j].index) 71 | } 72 | 73 | func isValidTag(s string) bool { 74 | if s == "" { 75 | return false 76 | } 77 | for _, c := range s { 78 | switch { 79 | case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): 80 | // Backslash and quote chars are reserved, but 81 | // otherwise any punctuation chars are allowed 82 | // in a tag name. 83 | default: 84 | if !unicode.IsLetter(c) && !unicode.IsDigit(c) { 85 | return false 86 | } 87 | } 88 | } 89 | return true 90 | } 91 | 92 | // typeFields returns a list of fields that JSON should recognize for the given type. 93 | // The algorithm is breadth-first search over the set of structs to include - the top struct 94 | // and then any reachable anonymous structs. 95 | func typeFields(t reflect.Type) []field { 96 | // Anonymous fields to explore at the current level and the next. 97 | current := []field{} 98 | next := []field{{typ: t}} 99 | 100 | // Count of queued names for current level and the next. 101 | count := map[reflect.Type]int{} 102 | nextCount := map[reflect.Type]int{} 103 | 104 | // Types already visited at an earlier level. 105 | visited := map[reflect.Type]bool{} 106 | 107 | // Fields found. 108 | var fields []field 109 | 110 | for len(next) > 0 { 111 | current, next = next, current[:0] 112 | count, nextCount = nextCount, map[reflect.Type]int{} 113 | 114 | for _, f := range current { 115 | if visited[f.typ] { 116 | continue 117 | } 118 | visited[f.typ] = true 119 | 120 | // Scan f.typ for fields to include. 121 | for i := 0; i < f.typ.NumField(); i++ { 122 | sf := f.typ.Field(i) 123 | if sf.PkgPath != "" && !sf.Anonymous { // unexported 124 | continue 125 | } 126 | tag := sf.Tag.Get("json") 127 | if tag == "-" { 128 | continue 129 | } 130 | name, opts := parseTag(tag) 131 | if !isValidTag(name) { 132 | name = "" 133 | } 134 | index := make([]int, len(f.index)+1) 135 | copy(index, f.index) 136 | index[len(f.index)] = i 137 | 138 | ft := sf.Type 139 | if ft.Name() == "" && ft.Kind() == reflect.Ptr { 140 | // Follow pointer. 141 | ft = ft.Elem() 142 | } 143 | 144 | // Only strings, floats, integers, and booleans can be quoted. 145 | quoted := false 146 | if opts.Contains("string") { 147 | switch ft.Kind() { 148 | case reflect.Bool, 149 | reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 150 | reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, 151 | reflect.Float32, reflect.Float64, 152 | reflect.String: 153 | quoted = true 154 | } 155 | } 156 | 157 | // Record found field and index sequence. 158 | if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { 159 | tagged := name != "" 160 | if name == "" { 161 | name = sf.Name 162 | } 163 | fields = append(fields, fillField(field{ 164 | name: name, 165 | tag: tagged, 166 | index: index, 167 | typ: ft, 168 | omitEmpty: opts.Contains("omitempty"), 169 | quoted: quoted, 170 | })) 171 | if count[f.typ] > 1 { 172 | // If there were multiple instances, add a second, 173 | // so that the annihilation code will see a duplicate. 174 | // It only cares about the distinction between 1 or 2, 175 | // so don't bother generating any more copies. 176 | fields = append(fields, fields[len(fields)-1]) 177 | } 178 | continue 179 | } 180 | 181 | // Record new anonymous struct to explore in next round. 182 | nextCount[ft]++ 183 | if nextCount[ft] == 1 { 184 | next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft})) 185 | } 186 | } 187 | } 188 | } 189 | 190 | sort.Sort(byName(fields)) 191 | 192 | // Delete all fields that are hidden by the Go rules for embedded fields, 193 | // except that fields with JSON tags are promoted. 194 | 195 | // The fields are sorted in primary order of name, secondary order 196 | // of field index length. Loop over names; for each name, delete 197 | // hidden fields by choosing the one dominant field that survives. 198 | out := fields[:0] 199 | for advance, i := 0, 0; i < len(fields); i += advance { 200 | // One iteration per name. 201 | // Find the sequence of fields with the name of this first field. 202 | fi := fields[i] 203 | name := fi.name 204 | for advance = 1; i+advance < len(fields); advance++ { 205 | fj := fields[i+advance] 206 | if fj.name != name { 207 | break 208 | } 209 | } 210 | if advance == 1 { // Only one field with this name 211 | out = append(out, fi) 212 | continue 213 | } 214 | dominant, ok := dominantField(fields[i : i+advance]) 215 | if ok { 216 | out = append(out, dominant) 217 | } 218 | } 219 | 220 | fields = out 221 | sort.Sort(byIndex(fields)) 222 | 223 | return fields 224 | } 225 | 226 | // dominantField looks through the fields, all of which are known to 227 | // have the same name, to find the single field that dominates the 228 | // others using Go's embedding rules, modified by the presence of 229 | // JSON tags. If there are multiple top-level fields, the boolean 230 | // will be false: This condition is an error in Go and we skip all 231 | // the fields. 232 | func dominantField(fields []field) (field, bool) { 233 | // The fields are sorted in increasing index-length order. The winner 234 | // must therefore be one with the shortest index length. Drop all 235 | // longer entries, which is easy: just truncate the slice. 236 | length := len(fields[0].index) 237 | tagged := -1 // Index of first tagged field. 238 | for i, f := range fields { 239 | if len(f.index) > length { 240 | fields = fields[:i] 241 | break 242 | } 243 | if f.tag { 244 | if tagged >= 0 { 245 | // Multiple tagged fields at the same level: conflict. 246 | // Return no field. 247 | return field{}, false 248 | } 249 | tagged = i 250 | } 251 | } 252 | if tagged >= 0 { 253 | return fields[tagged], true 254 | } 255 | // All remaining fields have the same length. If there's more than one, 256 | // we have a conflict (two fields named "X" at the same level) and we 257 | // return no field. 258 | if len(fields) > 1 { 259 | return field{}, false 260 | } 261 | return fields[0], true 262 | } 263 | 264 | var fieldCache struct { 265 | sync.RWMutex 266 | m map[reflect.Type][]field 267 | } 268 | 269 | // cachedTypeFields is like typeFields but uses a cache to avoid repeated work. 270 | func cachedTypeFields(t reflect.Type) []field { 271 | fieldCache.RLock() 272 | f := fieldCache.m[t] 273 | fieldCache.RUnlock() 274 | if f != nil { 275 | return f 276 | } 277 | 278 | // Compute fields without lock. 279 | // Might duplicate effort but won't hold other computations back. 280 | f = typeFields(t) 281 | if f == nil { 282 | f = []field{} 283 | } 284 | 285 | fieldCache.Lock() 286 | if fieldCache.m == nil { 287 | fieldCache.m = map[reflect.Type][]field{} 288 | } 289 | fieldCache.m[t] = f 290 | fieldCache.Unlock() 291 | return f 292 | } 293 | --------------------------------------------------------------------------------