sslobodr | d046be8 | 2019-01-16 10:02:22 -0500 | [diff] [blame] | 1 | // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. |
| 2 | // Use of this source code is governed by a MIT license found in the LICENSE file. |
| 3 | |
| 4 | package codec |
| 5 | |
| 6 | // By default, this json support uses base64 encoding for bytes, because you cannot |
| 7 | // store and read any arbitrary string in json (only unicode). |
| 8 | // However, the user can configre how to encode/decode bytes. |
| 9 | // |
| 10 | // This library specifically supports UTF-8 for encoding and decoding only. |
| 11 | // |
| 12 | // Note that the library will happily encode/decode things which are not valid |
| 13 | // json e.g. a map[int64]string. We do it for consistency. With valid json, |
| 14 | // we will encode and decode appropriately. |
| 15 | // Users can specify their map type if necessary to force it. |
| 16 | // |
| 17 | // Note: |
| 18 | // - we cannot use strconv.Quote and strconv.Unquote because json quotes/unquotes differently. |
| 19 | // We implement it here. |
| 20 | |
| 21 | // Top-level methods of json(End|Dec)Driver (which are implementations of (en|de)cDriver |
| 22 | // MUST not call one-another. |
| 23 | |
| 24 | import ( |
| 25 | "bytes" |
| 26 | "encoding/base64" |
| 27 | "math" |
| 28 | "reflect" |
| 29 | "strconv" |
| 30 | "time" |
| 31 | "unicode" |
| 32 | "unicode/utf16" |
| 33 | "unicode/utf8" |
| 34 | ) |
| 35 | |
| 36 | //-------------------------------- |
| 37 | |
| 38 | var jsonLiterals = [...]byte{ |
| 39 | '"', 't', 'r', 'u', 'e', '"', |
| 40 | '"', 'f', 'a', 'l', 's', 'e', '"', |
| 41 | '"', 'n', 'u', 'l', 'l', '"', |
| 42 | } |
| 43 | |
| 44 | const ( |
| 45 | jsonLitTrueQ = 0 |
| 46 | jsonLitTrue = 1 |
| 47 | jsonLitFalseQ = 6 |
| 48 | jsonLitFalse = 7 |
| 49 | jsonLitNullQ = 13 |
| 50 | jsonLitNull = 14 |
| 51 | ) |
| 52 | |
| 53 | const ( |
| 54 | jsonU4Chk2 = '0' |
| 55 | jsonU4Chk1 = 'a' - 10 |
| 56 | jsonU4Chk0 = 'A' - 10 |
| 57 | |
| 58 | jsonScratchArrayLen = 64 |
| 59 | ) |
| 60 | |
| 61 | const ( |
| 62 | // If !jsonValidateSymbols, decoding will be faster, by skipping some checks: |
| 63 | // - If we see first character of null, false or true, |
| 64 | // do not validate subsequent characters. |
| 65 | // - e.g. if we see a n, assume null and skip next 3 characters, |
| 66 | // and do not validate they are ull. |
| 67 | // P.S. Do not expect a significant decoding boost from this. |
| 68 | jsonValidateSymbols = true |
| 69 | |
| 70 | jsonSpacesOrTabsLen = 128 |
| 71 | |
| 72 | jsonAlwaysReturnInternString = false |
| 73 | ) |
| 74 | |
| 75 | var ( |
| 76 | // jsonTabs and jsonSpaces are used as caches for indents |
| 77 | jsonTabs, jsonSpaces [jsonSpacesOrTabsLen]byte |
| 78 | |
| 79 | jsonCharHtmlSafeSet bitset128 |
| 80 | jsonCharSafeSet bitset128 |
| 81 | jsonCharWhitespaceSet bitset256 |
| 82 | jsonNumSet bitset256 |
| 83 | ) |
| 84 | |
| 85 | func init() { |
| 86 | for i := 0; i < jsonSpacesOrTabsLen; i++ { |
| 87 | jsonSpaces[i] = ' ' |
| 88 | jsonTabs[i] = '\t' |
| 89 | } |
| 90 | |
| 91 | // populate the safe values as true: note: ASCII control characters are (0-31) |
| 92 | // jsonCharSafeSet: all true except (0-31) " \ |
| 93 | // jsonCharHtmlSafeSet: all true except (0-31) " \ < > & |
| 94 | var i byte |
| 95 | for i = 32; i < utf8.RuneSelf; i++ { |
| 96 | switch i { |
| 97 | case '"', '\\': |
| 98 | case '<', '>', '&': |
| 99 | jsonCharSafeSet.set(i) // = true |
| 100 | default: |
| 101 | jsonCharSafeSet.set(i) |
| 102 | jsonCharHtmlSafeSet.set(i) |
| 103 | } |
| 104 | } |
| 105 | for i = 0; i <= utf8.RuneSelf; i++ { |
| 106 | switch i { |
| 107 | case ' ', '\t', '\r', '\n': |
| 108 | jsonCharWhitespaceSet.set(i) |
| 109 | case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'e', 'E', '.', '+', '-': |
| 110 | jsonNumSet.set(i) |
| 111 | } |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | // ---------------- |
| 116 | |
| 117 | type jsonEncDriverTypical struct { |
| 118 | w encWriter |
| 119 | // w *encWriterSwitch |
| 120 | b *[jsonScratchArrayLen]byte |
| 121 | tw bool // term white space |
| 122 | c containerState |
| 123 | } |
| 124 | |
| 125 | func (e *jsonEncDriverTypical) typical() {} |
| 126 | |
| 127 | func (e *jsonEncDriverTypical) reset(ee *jsonEncDriver) { |
| 128 | e.w = ee.ew |
| 129 | // e.w = &ee.e.encWriterSwitch |
| 130 | e.b = &ee.b |
| 131 | e.tw = ee.h.TermWhitespace |
| 132 | e.c = 0 |
| 133 | } |
| 134 | |
| 135 | func (e *jsonEncDriverTypical) WriteArrayStart(length int) { |
| 136 | e.w.writen1('[') |
| 137 | e.c = containerArrayStart |
| 138 | } |
| 139 | |
| 140 | func (e *jsonEncDriverTypical) WriteArrayElem() { |
| 141 | if e.c != containerArrayStart { |
| 142 | e.w.writen1(',') |
| 143 | } |
| 144 | e.c = containerArrayElem |
| 145 | } |
| 146 | |
| 147 | func (e *jsonEncDriverTypical) WriteArrayEnd() { |
| 148 | e.w.writen1(']') |
| 149 | e.c = containerArrayEnd |
| 150 | } |
| 151 | |
| 152 | func (e *jsonEncDriverTypical) WriteMapStart(length int) { |
| 153 | e.w.writen1('{') |
| 154 | e.c = containerMapStart |
| 155 | } |
| 156 | |
| 157 | func (e *jsonEncDriverTypical) WriteMapElemKey() { |
| 158 | if e.c != containerMapStart { |
| 159 | e.w.writen1(',') |
| 160 | } |
| 161 | e.c = containerMapKey |
| 162 | } |
| 163 | |
| 164 | func (e *jsonEncDriverTypical) WriteMapElemValue() { |
| 165 | e.w.writen1(':') |
| 166 | e.c = containerMapValue |
| 167 | } |
| 168 | |
| 169 | func (e *jsonEncDriverTypical) WriteMapEnd() { |
| 170 | e.w.writen1('}') |
| 171 | e.c = containerMapEnd |
| 172 | } |
| 173 | |
| 174 | func (e *jsonEncDriverTypical) EncodeBool(b bool) { |
| 175 | if b { |
| 176 | e.w.writeb(jsonLiterals[jsonLitTrue : jsonLitTrue+4]) |
| 177 | } else { |
| 178 | e.w.writeb(jsonLiterals[jsonLitFalse : jsonLitFalse+5]) |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | func (e *jsonEncDriverTypical) EncodeFloat64(f float64) { |
| 183 | fmt, prec := jsonFloatStrconvFmtPrec(f) |
| 184 | e.w.writeb(strconv.AppendFloat(e.b[:0], f, fmt, prec, 64)) |
| 185 | } |
| 186 | |
| 187 | func (e *jsonEncDriverTypical) EncodeInt(v int64) { |
| 188 | e.w.writeb(strconv.AppendInt(e.b[:0], v, 10)) |
| 189 | } |
| 190 | |
| 191 | func (e *jsonEncDriverTypical) EncodeUint(v uint64) { |
| 192 | e.w.writeb(strconv.AppendUint(e.b[:0], v, 10)) |
| 193 | } |
| 194 | |
| 195 | func (e *jsonEncDriverTypical) EncodeFloat32(f float32) { |
| 196 | e.EncodeFloat64(float64(f)) |
| 197 | } |
| 198 | |
| 199 | func (e *jsonEncDriverTypical) atEndOfEncode() { |
| 200 | if e.tw { |
| 201 | e.w.writen1(' ') |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | // ---------------- |
| 206 | |
| 207 | type jsonEncDriverGeneric struct { |
| 208 | w encWriter // encWriter // *encWriterSwitch |
| 209 | b *[jsonScratchArrayLen]byte |
| 210 | c containerState |
| 211 | // ds string // indent string |
| 212 | di int8 // indent per |
| 213 | d bool // indenting? |
| 214 | dt bool // indent using tabs |
| 215 | dl uint16 // indent level |
| 216 | ks bool // map key as string |
| 217 | is byte // integer as string |
| 218 | tw bool // term white space |
| 219 | _ [7]byte // padding |
| 220 | } |
| 221 | |
| 222 | // indent is done as below: |
| 223 | // - newline and indent are added before each mapKey or arrayElem |
| 224 | // - newline and indent are added before each ending, |
| 225 | // except there was no entry (so we can have {} or []) |
| 226 | |
| 227 | func (e *jsonEncDriverGeneric) reset(ee *jsonEncDriver) { |
| 228 | e.w = ee.ew |
| 229 | e.b = &ee.b |
| 230 | e.tw = ee.h.TermWhitespace |
| 231 | e.c = 0 |
| 232 | e.d, e.dt, e.dl, e.di = false, false, 0, 0 |
| 233 | h := ee.h |
| 234 | if h.Indent > 0 { |
| 235 | e.d = true |
| 236 | e.di = int8(h.Indent) |
| 237 | } else if h.Indent < 0 { |
| 238 | e.d = true |
| 239 | e.dt = true |
| 240 | e.di = int8(-h.Indent) |
| 241 | } |
| 242 | e.ks = h.MapKeyAsString |
| 243 | e.is = h.IntegerAsString |
| 244 | } |
| 245 | |
| 246 | func (e *jsonEncDriverGeneric) WriteArrayStart(length int) { |
| 247 | if e.d { |
| 248 | e.dl++ |
| 249 | } |
| 250 | e.w.writen1('[') |
| 251 | e.c = containerArrayStart |
| 252 | } |
| 253 | |
| 254 | func (e *jsonEncDriverGeneric) WriteArrayElem() { |
| 255 | if e.c != containerArrayStart { |
| 256 | e.w.writen1(',') |
| 257 | } |
| 258 | if e.d { |
| 259 | e.writeIndent() |
| 260 | } |
| 261 | e.c = containerArrayElem |
| 262 | } |
| 263 | |
| 264 | func (e *jsonEncDriverGeneric) WriteArrayEnd() { |
| 265 | if e.d { |
| 266 | e.dl-- |
| 267 | if e.c != containerArrayStart { |
| 268 | e.writeIndent() |
| 269 | } |
| 270 | } |
| 271 | e.w.writen1(']') |
| 272 | e.c = containerArrayEnd |
| 273 | } |
| 274 | |
| 275 | func (e *jsonEncDriverGeneric) WriteMapStart(length int) { |
| 276 | if e.d { |
| 277 | e.dl++ |
| 278 | } |
| 279 | e.w.writen1('{') |
| 280 | e.c = containerMapStart |
| 281 | } |
| 282 | |
| 283 | func (e *jsonEncDriverGeneric) WriteMapElemKey() { |
| 284 | if e.c != containerMapStart { |
| 285 | e.w.writen1(',') |
| 286 | } |
| 287 | if e.d { |
| 288 | e.writeIndent() |
| 289 | } |
| 290 | e.c = containerMapKey |
| 291 | } |
| 292 | |
| 293 | func (e *jsonEncDriverGeneric) WriteMapElemValue() { |
| 294 | if e.d { |
| 295 | e.w.writen2(':', ' ') |
| 296 | } else { |
| 297 | e.w.writen1(':') |
| 298 | } |
| 299 | e.c = containerMapValue |
| 300 | } |
| 301 | |
| 302 | func (e *jsonEncDriverGeneric) WriteMapEnd() { |
| 303 | if e.d { |
| 304 | e.dl-- |
| 305 | if e.c != containerMapStart { |
| 306 | e.writeIndent() |
| 307 | } |
| 308 | } |
| 309 | e.w.writen1('}') |
| 310 | e.c = containerMapEnd |
| 311 | } |
| 312 | |
| 313 | func (e *jsonEncDriverGeneric) writeIndent() { |
| 314 | e.w.writen1('\n') |
| 315 | x := int(e.di) * int(e.dl) |
| 316 | if e.dt { |
| 317 | for x > jsonSpacesOrTabsLen { |
| 318 | e.w.writeb(jsonTabs[:]) |
| 319 | x -= jsonSpacesOrTabsLen |
| 320 | } |
| 321 | e.w.writeb(jsonTabs[:x]) |
| 322 | } else { |
| 323 | for x > jsonSpacesOrTabsLen { |
| 324 | e.w.writeb(jsonSpaces[:]) |
| 325 | x -= jsonSpacesOrTabsLen |
| 326 | } |
| 327 | e.w.writeb(jsonSpaces[:x]) |
| 328 | } |
| 329 | } |
| 330 | |
| 331 | func (e *jsonEncDriverGeneric) EncodeBool(b bool) { |
| 332 | if e.ks && e.c == containerMapKey { |
| 333 | if b { |
| 334 | e.w.writeb(jsonLiterals[jsonLitTrueQ : jsonLitTrueQ+6]) |
| 335 | } else { |
| 336 | e.w.writeb(jsonLiterals[jsonLitFalseQ : jsonLitFalseQ+7]) |
| 337 | } |
| 338 | } else { |
| 339 | if b { |
| 340 | e.w.writeb(jsonLiterals[jsonLitTrue : jsonLitTrue+4]) |
| 341 | } else { |
| 342 | e.w.writeb(jsonLiterals[jsonLitFalse : jsonLitFalse+5]) |
| 343 | } |
| 344 | } |
| 345 | } |
| 346 | |
| 347 | func (e *jsonEncDriverGeneric) EncodeFloat64(f float64) { |
| 348 | // instead of using 'g', specify whether to use 'e' or 'f' |
| 349 | fmt, prec := jsonFloatStrconvFmtPrec(f) |
| 350 | |
| 351 | var blen int |
| 352 | if e.ks && e.c == containerMapKey { |
| 353 | blen = 2 + len(strconv.AppendFloat(e.b[1:1], f, fmt, prec, 64)) |
| 354 | e.b[0] = '"' |
| 355 | e.b[blen-1] = '"' |
| 356 | } else { |
| 357 | blen = len(strconv.AppendFloat(e.b[:0], f, fmt, prec, 64)) |
| 358 | } |
| 359 | e.w.writeb(e.b[:blen]) |
| 360 | } |
| 361 | |
| 362 | func (e *jsonEncDriverGeneric) EncodeInt(v int64) { |
| 363 | x := e.is |
| 364 | if x == 'A' || x == 'L' && (v > 1<<53 || v < -(1<<53)) || (e.ks && e.c == containerMapKey) { |
| 365 | blen := 2 + len(strconv.AppendInt(e.b[1:1], v, 10)) |
| 366 | e.b[0] = '"' |
| 367 | e.b[blen-1] = '"' |
| 368 | e.w.writeb(e.b[:blen]) |
| 369 | return |
| 370 | } |
| 371 | e.w.writeb(strconv.AppendInt(e.b[:0], v, 10)) |
| 372 | } |
| 373 | |
| 374 | func (e *jsonEncDriverGeneric) EncodeUint(v uint64) { |
| 375 | x := e.is |
| 376 | if x == 'A' || x == 'L' && v > 1<<53 || (e.ks && e.c == containerMapKey) { |
| 377 | blen := 2 + len(strconv.AppendUint(e.b[1:1], v, 10)) |
| 378 | e.b[0] = '"' |
| 379 | e.b[blen-1] = '"' |
| 380 | e.w.writeb(e.b[:blen]) |
| 381 | return |
| 382 | } |
| 383 | e.w.writeb(strconv.AppendUint(e.b[:0], v, 10)) |
| 384 | } |
| 385 | |
| 386 | func (e *jsonEncDriverGeneric) EncodeFloat32(f float32) { |
| 387 | // e.encodeFloat(float64(f), 32) |
| 388 | // always encode all floats as IEEE 64-bit floating point. |
| 389 | // It also ensures that we can decode in full precision even if into a float32, |
| 390 | // as what is written is always to float64 precision. |
| 391 | e.EncodeFloat64(float64(f)) |
| 392 | } |
| 393 | |
| 394 | func (e *jsonEncDriverGeneric) atEndOfEncode() { |
| 395 | if e.tw { |
| 396 | if e.d { |
| 397 | e.w.writen1('\n') |
| 398 | } else { |
| 399 | e.w.writen1(' ') |
| 400 | } |
| 401 | } |
| 402 | } |
| 403 | |
| 404 | // -------------------- |
| 405 | |
| 406 | type jsonEncDriver struct { |
| 407 | noBuiltInTypes |
| 408 | e *Encoder |
| 409 | h *JsonHandle |
| 410 | ew encWriter // encWriter // *encWriterSwitch |
| 411 | se extWrapper |
| 412 | // ---- cpu cache line boundary? |
| 413 | bs []byte // scratch |
| 414 | // ---- cpu cache line boundary? |
| 415 | b [jsonScratchArrayLen]byte // scratch (encode time, |
| 416 | } |
| 417 | |
| 418 | func (e *jsonEncDriver) EncodeNil() { |
| 419 | // We always encode nil as just null (never in quotes) |
| 420 | // This allows us to easily decode if a nil in the json stream |
| 421 | // ie if initial token is n. |
| 422 | e.ew.writeb(jsonLiterals[jsonLitNull : jsonLitNull+4]) |
| 423 | |
| 424 | // if e.h.MapKeyAsString && e.c == containerMapKey { |
| 425 | // e.ew.writeb(jsonLiterals[jsonLitNullQ : jsonLitNullQ+6]) |
| 426 | // } else { |
| 427 | // e.ew.writeb(jsonLiterals[jsonLitNull : jsonLitNull+4]) |
| 428 | // } |
| 429 | } |
| 430 | |
| 431 | func (e *jsonEncDriver) EncodeTime(t time.Time) { |
| 432 | // Do NOT use MarshalJSON, as it allocates internally. |
| 433 | // instead, we call AppendFormat directly, using our scratch buffer (e.b) |
| 434 | if t.IsZero() { |
| 435 | e.EncodeNil() |
| 436 | } else { |
| 437 | e.b[0] = '"' |
| 438 | b := t.AppendFormat(e.b[1:1], time.RFC3339Nano) |
| 439 | e.b[len(b)+1] = '"' |
| 440 | e.ew.writeb(e.b[:len(b)+2]) |
| 441 | } |
| 442 | // v, err := t.MarshalJSON(); if err != nil { e.e.error(err) } e.ew.writeb(v) |
| 443 | } |
| 444 | |
| 445 | func (e *jsonEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext, en *Encoder) { |
| 446 | if v := ext.ConvertExt(rv); v == nil { |
| 447 | e.EncodeNil() |
| 448 | } else { |
| 449 | en.encode(v) |
| 450 | } |
| 451 | } |
| 452 | |
| 453 | func (e *jsonEncDriver) EncodeRawExt(re *RawExt, en *Encoder) { |
| 454 | // only encodes re.Value (never re.Data) |
| 455 | if re.Value == nil { |
| 456 | e.EncodeNil() |
| 457 | } else { |
| 458 | en.encode(re.Value) |
| 459 | } |
| 460 | } |
| 461 | |
| 462 | func (e *jsonEncDriver) EncodeString(c charEncoding, v string) { |
| 463 | e.quoteStr(v) |
| 464 | } |
| 465 | |
| 466 | func (e *jsonEncDriver) EncodeStringBytes(c charEncoding, v []byte) { |
| 467 | // if encoding raw bytes and RawBytesExt is configured, use it to encode |
| 468 | if v == nil { |
| 469 | e.EncodeNil() |
| 470 | return |
| 471 | } |
| 472 | if c == cRAW { |
| 473 | if e.se.InterfaceExt != nil { |
| 474 | e.EncodeExt(v, 0, &e.se, e.e) |
| 475 | return |
| 476 | } |
| 477 | |
| 478 | slen := base64.StdEncoding.EncodedLen(len(v)) |
| 479 | if cap(e.bs) >= slen+2 { |
| 480 | e.bs = e.bs[:slen+2] |
| 481 | } else { |
| 482 | e.bs = make([]byte, slen+2) |
| 483 | } |
| 484 | e.bs[0] = '"' |
| 485 | base64.StdEncoding.Encode(e.bs[1:], v) |
| 486 | e.bs[slen+1] = '"' |
| 487 | e.ew.writeb(e.bs) |
| 488 | } else { |
| 489 | e.quoteStr(stringView(v)) |
| 490 | } |
| 491 | } |
| 492 | |
| 493 | func (e *jsonEncDriver) EncodeAsis(v []byte) { |
| 494 | e.ew.writeb(v) |
| 495 | } |
| 496 | |
| 497 | func (e *jsonEncDriver) quoteStr(s string) { |
| 498 | // adapted from std pkg encoding/json |
| 499 | const hex = "0123456789abcdef" |
| 500 | w := e.ew |
| 501 | htmlasis := e.h.HTMLCharsAsIs |
| 502 | w.writen1('"') |
| 503 | var start int |
| 504 | for i, slen := 0, len(s); i < slen; { |
| 505 | // encode all bytes < 0x20 (except \r, \n). |
| 506 | // also encode < > & to prevent security holes when served to some browsers. |
| 507 | if b := s[i]; b < utf8.RuneSelf { |
| 508 | // if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' { |
| 509 | // if (htmlasis && jsonCharSafeSet.isset(b)) || jsonCharHtmlSafeSet.isset(b) { |
| 510 | if jsonCharHtmlSafeSet.isset(b) || (htmlasis && jsonCharSafeSet.isset(b)) { |
| 511 | i++ |
| 512 | continue |
| 513 | } |
| 514 | if start < i { |
| 515 | w.writestr(s[start:i]) |
| 516 | } |
| 517 | switch b { |
| 518 | case '\\', '"': |
| 519 | w.writen2('\\', b) |
| 520 | case '\n': |
| 521 | w.writen2('\\', 'n') |
| 522 | case '\r': |
| 523 | w.writen2('\\', 'r') |
| 524 | case '\b': |
| 525 | w.writen2('\\', 'b') |
| 526 | case '\f': |
| 527 | w.writen2('\\', 'f') |
| 528 | case '\t': |
| 529 | w.writen2('\\', 't') |
| 530 | default: |
| 531 | w.writestr(`\u00`) |
| 532 | w.writen2(hex[b>>4], hex[b&0xF]) |
| 533 | } |
| 534 | i++ |
| 535 | start = i |
| 536 | continue |
| 537 | } |
| 538 | c, size := utf8.DecodeRuneInString(s[i:]) |
| 539 | if c == utf8.RuneError && size == 1 { |
| 540 | if start < i { |
| 541 | w.writestr(s[start:i]) |
| 542 | } |
| 543 | w.writestr(`\ufffd`) |
| 544 | i += size |
| 545 | start = i |
| 546 | continue |
| 547 | } |
| 548 | // U+2028 is LINE SEPARATOR. U+2029 is PARAGRAPH SEPARATOR. |
| 549 | // Both technically valid JSON, but bomb on JSONP, so fix here unconditionally. |
| 550 | if c == '\u2028' || c == '\u2029' { |
| 551 | if start < i { |
| 552 | w.writestr(s[start:i]) |
| 553 | } |
| 554 | w.writestr(`\u202`) |
| 555 | w.writen1(hex[c&0xF]) |
| 556 | i += size |
| 557 | start = i |
| 558 | continue |
| 559 | } |
| 560 | i += size |
| 561 | } |
| 562 | if start < len(s) { |
| 563 | w.writestr(s[start:]) |
| 564 | } |
| 565 | w.writen1('"') |
| 566 | } |
| 567 | |
| 568 | type jsonDecDriver struct { |
| 569 | noBuiltInTypes |
| 570 | d *Decoder |
| 571 | h *JsonHandle |
| 572 | r decReader // *decReaderSwitch // decReader |
| 573 | se extWrapper |
| 574 | |
| 575 | // ---- writable fields during execution --- *try* to keep in sep cache line |
| 576 | |
| 577 | c containerState |
| 578 | // tok is used to store the token read right after skipWhiteSpace. |
| 579 | tok uint8 |
| 580 | fnull bool // found null from appendStringAsBytes |
| 581 | bs []byte // scratch. Initialized from b. Used for parsing strings or numbers. |
| 582 | bstr [8]byte // scratch used for string \UXXX parsing |
| 583 | // ---- cpu cache line boundary? |
| 584 | b [jsonScratchArrayLen]byte // scratch 1, used for parsing strings or numbers or time.Time |
| 585 | b2 [jsonScratchArrayLen]byte // scratch 2, used only for readUntil, decNumBytes |
| 586 | |
| 587 | _ [3]uint64 // padding |
| 588 | // n jsonNum |
| 589 | } |
| 590 | |
| 591 | // func jsonIsWS(b byte) bool { |
| 592 | // // return b == ' ' || b == '\t' || b == '\r' || b == '\n' |
| 593 | // return jsonCharWhitespaceSet.isset(b) |
| 594 | // } |
| 595 | |
| 596 | func (d *jsonDecDriver) uncacheRead() { |
| 597 | if d.tok != 0 { |
| 598 | d.r.unreadn1() |
| 599 | d.tok = 0 |
| 600 | } |
| 601 | } |
| 602 | |
| 603 | func (d *jsonDecDriver) ReadMapStart() int { |
| 604 | if d.tok == 0 { |
| 605 | d.tok = d.r.skip(&jsonCharWhitespaceSet) |
| 606 | } |
| 607 | const xc uint8 = '{' |
| 608 | if d.tok != xc { |
| 609 | d.d.errorf("read map - expect char '%c' but got char '%c'", xc, d.tok) |
| 610 | } |
| 611 | d.tok = 0 |
| 612 | d.c = containerMapStart |
| 613 | return -1 |
| 614 | } |
| 615 | |
| 616 | func (d *jsonDecDriver) ReadArrayStart() int { |
| 617 | if d.tok == 0 { |
| 618 | d.tok = d.r.skip(&jsonCharWhitespaceSet) |
| 619 | } |
| 620 | const xc uint8 = '[' |
| 621 | if d.tok != xc { |
| 622 | d.d.errorf("read array - expect char '%c' but got char '%c'", xc, d.tok) |
| 623 | } |
| 624 | d.tok = 0 |
| 625 | d.c = containerArrayStart |
| 626 | return -1 |
| 627 | } |
| 628 | |
| 629 | func (d *jsonDecDriver) CheckBreak() bool { |
| 630 | if d.tok == 0 { |
| 631 | d.tok = d.r.skip(&jsonCharWhitespaceSet) |
| 632 | } |
| 633 | return d.tok == '}' || d.tok == ']' |
| 634 | } |
| 635 | |
| 636 | // For the ReadXXX methods below, we could just delegate to helper functions |
| 637 | // readContainerState(c containerState, xc uint8, check bool) |
| 638 | // - ReadArrayElem would become: |
| 639 | // readContainerState(containerArrayElem, ',', d.c != containerArrayStart) |
| 640 | // |
| 641 | // However, until mid-stack inlining comes in go1.11 which supports inlining of |
| 642 | // one-liners, we explicitly write them all 5 out to elide the extra func call. |
| 643 | // |
| 644 | // TODO: For Go 1.11, if inlined, consider consolidating these. |
| 645 | |
| 646 | func (d *jsonDecDriver) ReadArrayElem() { |
| 647 | const xc uint8 = ',' |
| 648 | if d.tok == 0 { |
| 649 | d.tok = d.r.skip(&jsonCharWhitespaceSet) |
| 650 | } |
| 651 | if d.c != containerArrayStart { |
| 652 | if d.tok != xc { |
| 653 | d.d.errorf("read array element - expect char '%c' but got char '%c'", xc, d.tok) |
| 654 | } |
| 655 | d.tok = 0 |
| 656 | } |
| 657 | d.c = containerArrayElem |
| 658 | } |
| 659 | |
| 660 | func (d *jsonDecDriver) ReadArrayEnd() { |
| 661 | const xc uint8 = ']' |
| 662 | if d.tok == 0 { |
| 663 | d.tok = d.r.skip(&jsonCharWhitespaceSet) |
| 664 | } |
| 665 | if d.tok != xc { |
| 666 | d.d.errorf("read array end - expect char '%c' but got char '%c'", xc, d.tok) |
| 667 | } |
| 668 | d.tok = 0 |
| 669 | d.c = containerArrayEnd |
| 670 | } |
| 671 | |
| 672 | func (d *jsonDecDriver) ReadMapElemKey() { |
| 673 | const xc uint8 = ',' |
| 674 | if d.tok == 0 { |
| 675 | d.tok = d.r.skip(&jsonCharWhitespaceSet) |
| 676 | } |
| 677 | if d.c != containerMapStart { |
| 678 | if d.tok != xc { |
| 679 | d.d.errorf("read map key - expect char '%c' but got char '%c'", xc, d.tok) |
| 680 | } |
| 681 | d.tok = 0 |
| 682 | } |
| 683 | d.c = containerMapKey |
| 684 | } |
| 685 | |
| 686 | func (d *jsonDecDriver) ReadMapElemValue() { |
| 687 | const xc uint8 = ':' |
| 688 | if d.tok == 0 { |
| 689 | d.tok = d.r.skip(&jsonCharWhitespaceSet) |
| 690 | } |
| 691 | if d.tok != xc { |
| 692 | d.d.errorf("read map value - expect char '%c' but got char '%c'", xc, d.tok) |
| 693 | } |
| 694 | d.tok = 0 |
| 695 | d.c = containerMapValue |
| 696 | } |
| 697 | |
| 698 | func (d *jsonDecDriver) ReadMapEnd() { |
| 699 | const xc uint8 = '}' |
| 700 | if d.tok == 0 { |
| 701 | d.tok = d.r.skip(&jsonCharWhitespaceSet) |
| 702 | } |
| 703 | if d.tok != xc { |
| 704 | d.d.errorf("read map end - expect char '%c' but got char '%c'", xc, d.tok) |
| 705 | } |
| 706 | d.tok = 0 |
| 707 | d.c = containerMapEnd |
| 708 | } |
| 709 | |
| 710 | func (d *jsonDecDriver) readLit(length, fromIdx uint8) { |
| 711 | bs := d.r.readx(int(length)) |
| 712 | d.tok = 0 |
| 713 | if jsonValidateSymbols && !bytes.Equal(bs, jsonLiterals[fromIdx:fromIdx+length]) { |
| 714 | d.d.errorf("expecting %s: got %s", jsonLiterals[fromIdx:fromIdx+length], bs) |
| 715 | return |
| 716 | } |
| 717 | } |
| 718 | |
| 719 | func (d *jsonDecDriver) TryDecodeAsNil() bool { |
| 720 | if d.tok == 0 { |
| 721 | d.tok = d.r.skip(&jsonCharWhitespaceSet) |
| 722 | } |
| 723 | // we shouldn't try to see if "null" was here, right? |
| 724 | // only the plain string: `null` denotes a nil (ie not quotes) |
| 725 | if d.tok == 'n' { |
| 726 | d.readLit(3, jsonLitNull+1) // (n)ull |
| 727 | return true |
| 728 | } |
| 729 | return false |
| 730 | } |
| 731 | |
| 732 | func (d *jsonDecDriver) DecodeBool() (v bool) { |
| 733 | if d.tok == 0 { |
| 734 | d.tok = d.r.skip(&jsonCharWhitespaceSet) |
| 735 | } |
| 736 | fquot := d.c == containerMapKey && d.tok == '"' |
| 737 | if fquot { |
| 738 | d.tok = d.r.readn1() |
| 739 | } |
| 740 | switch d.tok { |
| 741 | case 'f': |
| 742 | d.readLit(4, jsonLitFalse+1) // (f)alse |
| 743 | // v = false |
| 744 | case 't': |
| 745 | d.readLit(3, jsonLitTrue+1) // (t)rue |
| 746 | v = true |
| 747 | default: |
| 748 | d.d.errorf("decode bool: got first char %c", d.tok) |
| 749 | // v = false // "unreachable" |
| 750 | } |
| 751 | if fquot { |
| 752 | d.r.readn1() |
| 753 | } |
| 754 | return |
| 755 | } |
| 756 | |
| 757 | func (d *jsonDecDriver) DecodeTime() (t time.Time) { |
| 758 | // read string, and pass the string into json.unmarshal |
| 759 | d.appendStringAsBytes() |
| 760 | if d.fnull { |
| 761 | return |
| 762 | } |
| 763 | t, err := time.Parse(time.RFC3339, stringView(d.bs)) |
| 764 | if err != nil { |
| 765 | d.d.errorv(err) |
| 766 | } |
| 767 | return |
| 768 | } |
| 769 | |
| 770 | func (d *jsonDecDriver) ContainerType() (vt valueType) { |
| 771 | // check container type by checking the first char |
| 772 | if d.tok == 0 { |
| 773 | d.tok = d.r.skip(&jsonCharWhitespaceSet) |
| 774 | } |
| 775 | |
| 776 | // optimize this, so we don't do 4 checks but do one computation. |
| 777 | // return jsonContainerSet[d.tok] |
| 778 | |
| 779 | // ContainerType is mostly called for Map and Array, |
| 780 | // so this conditional is good enough (max 2 checks typically) |
| 781 | if b := d.tok; b == '{' { |
| 782 | return valueTypeMap |
| 783 | } else if b == '[' { |
| 784 | return valueTypeArray |
| 785 | } else if b == 'n' { |
| 786 | return valueTypeNil |
| 787 | } else if b == '"' { |
| 788 | return valueTypeString |
| 789 | } |
| 790 | return valueTypeUnset |
| 791 | } |
| 792 | |
| 793 | func (d *jsonDecDriver) decNumBytes() (bs []byte) { |
| 794 | // stores num bytes in d.bs |
| 795 | if d.tok == 0 { |
| 796 | d.tok = d.r.skip(&jsonCharWhitespaceSet) |
| 797 | } |
| 798 | if d.tok == '"' { |
| 799 | bs = d.r.readUntil(d.b2[:0], '"') |
| 800 | bs = bs[:len(bs)-1] |
| 801 | } else { |
| 802 | d.r.unreadn1() |
| 803 | bs = d.r.readTo(d.bs[:0], &jsonNumSet) |
| 804 | } |
| 805 | d.tok = 0 |
| 806 | return bs |
| 807 | } |
| 808 | |
| 809 | func (d *jsonDecDriver) DecodeUint64() (u uint64) { |
| 810 | bs := d.decNumBytes() |
| 811 | n, neg, badsyntax, overflow := jsonParseInteger(bs) |
| 812 | if overflow { |
| 813 | d.d.errorf("overflow parsing unsigned integer: %s", bs) |
| 814 | } else if neg { |
| 815 | d.d.errorf("minus found parsing unsigned integer: %s", bs) |
| 816 | } else if badsyntax { |
| 817 | // fallback: try to decode as float, and cast |
| 818 | n = d.decUint64ViaFloat(stringView(bs)) |
| 819 | } |
| 820 | return n |
| 821 | } |
| 822 | |
| 823 | func (d *jsonDecDriver) DecodeInt64() (i int64) { |
| 824 | const cutoff = uint64(1 << uint(64-1)) |
| 825 | bs := d.decNumBytes() |
| 826 | n, neg, badsyntax, overflow := jsonParseInteger(bs) |
| 827 | if overflow { |
| 828 | d.d.errorf("overflow parsing integer: %s", bs) |
| 829 | } else if badsyntax { |
| 830 | // d.d.errorf("invalid syntax for integer: %s", bs) |
| 831 | // fallback: try to decode as float, and cast |
| 832 | if neg { |
| 833 | n = d.decUint64ViaFloat(stringView(bs[1:])) |
| 834 | } else { |
| 835 | n = d.decUint64ViaFloat(stringView(bs)) |
| 836 | } |
| 837 | } |
| 838 | if neg { |
| 839 | if n > cutoff { |
| 840 | d.d.errorf("overflow parsing integer: %s", bs) |
| 841 | } |
| 842 | i = -(int64(n)) |
| 843 | } else { |
| 844 | if n >= cutoff { |
| 845 | d.d.errorf("overflow parsing integer: %s", bs) |
| 846 | } |
| 847 | i = int64(n) |
| 848 | } |
| 849 | return |
| 850 | } |
| 851 | |
| 852 | func (d *jsonDecDriver) decUint64ViaFloat(s string) (u uint64) { |
| 853 | f, err := strconv.ParseFloat(s, 64) |
| 854 | if err != nil { |
| 855 | d.d.errorf("invalid syntax for integer: %s", s) |
| 856 | // d.d.errorv(err) |
| 857 | } |
| 858 | fi, ff := math.Modf(f) |
| 859 | if ff > 0 { |
| 860 | d.d.errorf("fractional part found parsing integer: %s", s) |
| 861 | } else if fi > float64(math.MaxUint64) { |
| 862 | d.d.errorf("overflow parsing integer: %s", s) |
| 863 | } |
| 864 | return uint64(fi) |
| 865 | } |
| 866 | |
| 867 | func (d *jsonDecDriver) DecodeFloat64() (f float64) { |
| 868 | bs := d.decNumBytes() |
| 869 | f, err := strconv.ParseFloat(stringView(bs), 64) |
| 870 | if err != nil { |
| 871 | d.d.errorv(err) |
| 872 | } |
| 873 | return |
| 874 | } |
| 875 | |
| 876 | func (d *jsonDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) { |
| 877 | if ext == nil { |
| 878 | re := rv.(*RawExt) |
| 879 | re.Tag = xtag |
| 880 | d.d.decode(&re.Value) |
| 881 | } else { |
| 882 | var v interface{} |
| 883 | d.d.decode(&v) |
| 884 | ext.UpdateExt(rv, v) |
| 885 | } |
| 886 | return |
| 887 | } |
| 888 | |
| 889 | func (d *jsonDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) { |
| 890 | // if decoding into raw bytes, and the RawBytesExt is configured, use it to decode. |
| 891 | if d.se.InterfaceExt != nil { |
| 892 | bsOut = bs |
| 893 | d.DecodeExt(&bsOut, 0, &d.se) |
| 894 | return |
| 895 | } |
| 896 | if d.tok == 0 { |
| 897 | d.tok = d.r.skip(&jsonCharWhitespaceSet) |
| 898 | } |
| 899 | // check if an "array" of uint8's (see ContainerType for how to infer if an array) |
| 900 | if d.tok == '[' { |
| 901 | bsOut, _ = fastpathTV.DecSliceUint8V(bs, true, d.d) |
| 902 | return |
| 903 | } |
| 904 | d.appendStringAsBytes() |
| 905 | // base64 encodes []byte{} as "", and we encode nil []byte as null. |
| 906 | // Consequently, base64 should decode null as a nil []byte, and "" as an empty []byte{}. |
| 907 | // appendStringAsBytes returns a zero-len slice for both, so as not to reset d.bs. |
| 908 | // However, it sets a fnull field to true, so we can check if a null was found. |
| 909 | if len(d.bs) == 0 { |
| 910 | if d.fnull { |
| 911 | return nil |
| 912 | } |
| 913 | return []byte{} |
| 914 | } |
| 915 | bs0 := d.bs |
| 916 | slen := base64.StdEncoding.DecodedLen(len(bs0)) |
| 917 | if slen <= cap(bs) { |
| 918 | bsOut = bs[:slen] |
| 919 | } else if zerocopy && slen <= cap(d.b2) { |
| 920 | bsOut = d.b2[:slen] |
| 921 | } else { |
| 922 | bsOut = make([]byte, slen) |
| 923 | } |
| 924 | slen2, err := base64.StdEncoding.Decode(bsOut, bs0) |
| 925 | if err != nil { |
| 926 | d.d.errorf("error decoding base64 binary '%s': %v", bs0, err) |
| 927 | return nil |
| 928 | } |
| 929 | if slen != slen2 { |
| 930 | bsOut = bsOut[:slen2] |
| 931 | } |
| 932 | return |
| 933 | } |
| 934 | |
| 935 | func (d *jsonDecDriver) DecodeString() (s string) { |
| 936 | d.appendStringAsBytes() |
| 937 | return d.bsToString() |
| 938 | } |
| 939 | |
| 940 | func (d *jsonDecDriver) DecodeStringAsBytes() (s []byte) { |
| 941 | d.appendStringAsBytes() |
| 942 | return d.bs |
| 943 | } |
| 944 | |
| 945 | func (d *jsonDecDriver) appendStringAsBytes() { |
| 946 | if d.tok == 0 { |
| 947 | d.tok = d.r.skip(&jsonCharWhitespaceSet) |
| 948 | } |
| 949 | |
| 950 | d.fnull = false |
| 951 | if d.tok != '"' { |
| 952 | // d.d.errorf("expect char '%c' but got char '%c'", '"', d.tok) |
| 953 | // handle non-string scalar: null, true, false or a number |
| 954 | switch d.tok { |
| 955 | case 'n': |
| 956 | d.readLit(3, jsonLitNull+1) // (n)ull |
| 957 | d.bs = d.bs[:0] |
| 958 | d.fnull = true |
| 959 | case 'f': |
| 960 | d.readLit(4, jsonLitFalse+1) // (f)alse |
| 961 | d.bs = d.bs[:5] |
| 962 | copy(d.bs, "false") |
| 963 | case 't': |
| 964 | d.readLit(3, jsonLitTrue+1) // (t)rue |
| 965 | d.bs = d.bs[:4] |
| 966 | copy(d.bs, "true") |
| 967 | default: |
| 968 | // try to parse a valid number |
| 969 | bs := d.decNumBytes() |
| 970 | if len(bs) <= cap(d.bs) { |
| 971 | d.bs = d.bs[:len(bs)] |
| 972 | } else { |
| 973 | d.bs = make([]byte, len(bs)) |
| 974 | } |
| 975 | copy(d.bs, bs) |
| 976 | } |
| 977 | return |
| 978 | } |
| 979 | |
| 980 | d.tok = 0 |
| 981 | r := d.r |
| 982 | var cs = r.readUntil(d.b2[:0], '"') |
| 983 | var cslen = len(cs) |
| 984 | var c uint8 |
| 985 | v := d.bs[:0] |
| 986 | // append on each byte seen can be expensive, so we just |
| 987 | // keep track of where we last read a contiguous set of |
| 988 | // non-special bytes (using cursor variable), |
| 989 | // and when we see a special byte |
| 990 | // e.g. end-of-slice, " or \, |
| 991 | // we will append the full range into the v slice before proceeding |
| 992 | for i, cursor := 0, 0; ; { |
| 993 | if i == cslen { |
| 994 | v = append(v, cs[cursor:]...) |
| 995 | cs = r.readUntil(d.b2[:0], '"') |
| 996 | cslen = len(cs) |
| 997 | i, cursor = 0, 0 |
| 998 | } |
| 999 | c = cs[i] |
| 1000 | if c == '"' { |
| 1001 | v = append(v, cs[cursor:i]...) |
| 1002 | break |
| 1003 | } |
| 1004 | if c != '\\' { |
| 1005 | i++ |
| 1006 | continue |
| 1007 | } |
| 1008 | v = append(v, cs[cursor:i]...) |
| 1009 | i++ |
| 1010 | c = cs[i] |
| 1011 | switch c { |
| 1012 | case '"', '\\', '/', '\'': |
| 1013 | v = append(v, c) |
| 1014 | case 'b': |
| 1015 | v = append(v, '\b') |
| 1016 | case 'f': |
| 1017 | v = append(v, '\f') |
| 1018 | case 'n': |
| 1019 | v = append(v, '\n') |
| 1020 | case 'r': |
| 1021 | v = append(v, '\r') |
| 1022 | case 't': |
| 1023 | v = append(v, '\t') |
| 1024 | case 'u': |
| 1025 | var r rune |
| 1026 | var rr uint32 |
| 1027 | if len(cs) < i+4 { // may help reduce bounds-checking |
| 1028 | d.d.errorf("need at least 4 more bytes for unicode sequence") |
| 1029 | } |
| 1030 | // c = cs[i+4] // may help reduce bounds-checking |
| 1031 | for j := 1; j < 5; j++ { |
| 1032 | // best to use explicit if-else |
| 1033 | // - not a table, etc which involve memory loads, array lookup with bounds checks, etc |
| 1034 | c = cs[i+j] |
| 1035 | if c >= '0' && c <= '9' { |
| 1036 | rr = rr*16 + uint32(c-jsonU4Chk2) |
| 1037 | } else if c >= 'a' && c <= 'f' { |
| 1038 | rr = rr*16 + uint32(c-jsonU4Chk1) |
| 1039 | } else if c >= 'A' && c <= 'F' { |
| 1040 | rr = rr*16 + uint32(c-jsonU4Chk0) |
| 1041 | } else { |
| 1042 | r = unicode.ReplacementChar |
| 1043 | i += 4 |
| 1044 | goto encode_rune |
| 1045 | } |
| 1046 | } |
| 1047 | r = rune(rr) |
| 1048 | i += 4 |
| 1049 | if utf16.IsSurrogate(r) { |
| 1050 | if len(cs) >= i+6 && cs[i+2] == 'u' && cs[i+1] == '\\' { |
| 1051 | i += 2 |
| 1052 | // c = cs[i+4] // may help reduce bounds-checking |
| 1053 | var rr1 uint32 |
| 1054 | for j := 1; j < 5; j++ { |
| 1055 | c = cs[i+j] |
| 1056 | if c >= '0' && c <= '9' { |
| 1057 | rr = rr*16 + uint32(c-jsonU4Chk2) |
| 1058 | } else if c >= 'a' && c <= 'f' { |
| 1059 | rr = rr*16 + uint32(c-jsonU4Chk1) |
| 1060 | } else if c >= 'A' && c <= 'F' { |
| 1061 | rr = rr*16 + uint32(c-jsonU4Chk0) |
| 1062 | } else { |
| 1063 | r = unicode.ReplacementChar |
| 1064 | i += 4 |
| 1065 | goto encode_rune |
| 1066 | } |
| 1067 | } |
| 1068 | r = utf16.DecodeRune(r, rune(rr1)) |
| 1069 | i += 4 |
| 1070 | } else { |
| 1071 | r = unicode.ReplacementChar |
| 1072 | goto encode_rune |
| 1073 | } |
| 1074 | } |
| 1075 | encode_rune: |
| 1076 | w2 := utf8.EncodeRune(d.bstr[:], r) |
| 1077 | v = append(v, d.bstr[:w2]...) |
| 1078 | default: |
| 1079 | d.d.errorf("unsupported escaped value: %c", c) |
| 1080 | } |
| 1081 | i++ |
| 1082 | cursor = i |
| 1083 | } |
| 1084 | d.bs = v |
| 1085 | } |
| 1086 | |
| 1087 | func (d *jsonDecDriver) nakedNum(z *decNaked, bs []byte) (err error) { |
| 1088 | const cutoff = uint64(1 << uint(64-1)) |
| 1089 | var n uint64 |
| 1090 | var neg, badsyntax, overflow bool |
| 1091 | |
| 1092 | if d.h.PreferFloat { |
| 1093 | goto F |
| 1094 | } |
| 1095 | n, neg, badsyntax, overflow = jsonParseInteger(bs) |
| 1096 | if badsyntax || overflow { |
| 1097 | goto F |
| 1098 | } |
| 1099 | if neg { |
| 1100 | if n > cutoff { |
| 1101 | goto F |
| 1102 | } |
| 1103 | z.v = valueTypeInt |
| 1104 | z.i = -(int64(n)) |
| 1105 | } else if d.h.SignedInteger { |
| 1106 | if n >= cutoff { |
| 1107 | goto F |
| 1108 | } |
| 1109 | z.v = valueTypeInt |
| 1110 | z.i = int64(n) |
| 1111 | } else { |
| 1112 | z.v = valueTypeUint |
| 1113 | z.u = n |
| 1114 | } |
| 1115 | return |
| 1116 | F: |
| 1117 | z.v = valueTypeFloat |
| 1118 | z.f, err = strconv.ParseFloat(stringView(bs), 64) |
| 1119 | return |
| 1120 | } |
| 1121 | |
| 1122 | func (d *jsonDecDriver) bsToString() string { |
| 1123 | // if x := d.s.sc; x != nil && x.so && x.st == '}' { // map key |
| 1124 | if jsonAlwaysReturnInternString || d.c == containerMapKey { |
| 1125 | return d.d.string(d.bs) |
| 1126 | } |
| 1127 | return string(d.bs) |
| 1128 | } |
| 1129 | |
| 1130 | func (d *jsonDecDriver) DecodeNaked() { |
| 1131 | z := d.d.n |
| 1132 | // var decodeFurther bool |
| 1133 | |
| 1134 | if d.tok == 0 { |
| 1135 | d.tok = d.r.skip(&jsonCharWhitespaceSet) |
| 1136 | } |
| 1137 | switch d.tok { |
| 1138 | case 'n': |
| 1139 | d.readLit(3, jsonLitNull+1) // (n)ull |
| 1140 | z.v = valueTypeNil |
| 1141 | case 'f': |
| 1142 | d.readLit(4, jsonLitFalse+1) // (f)alse |
| 1143 | z.v = valueTypeBool |
| 1144 | z.b = false |
| 1145 | case 't': |
| 1146 | d.readLit(3, jsonLitTrue+1) // (t)rue |
| 1147 | z.v = valueTypeBool |
| 1148 | z.b = true |
| 1149 | case '{': |
| 1150 | z.v = valueTypeMap // don't consume. kInterfaceNaked will call ReadMapStart |
| 1151 | case '[': |
| 1152 | z.v = valueTypeArray // don't consume. kInterfaceNaked will call ReadArrayStart |
| 1153 | case '"': |
| 1154 | // if a string, and MapKeyAsString, then try to decode it as a nil, bool or number first |
| 1155 | d.appendStringAsBytes() |
| 1156 | if len(d.bs) > 0 && d.c == containerMapKey && d.h.MapKeyAsString { |
| 1157 | switch stringView(d.bs) { |
| 1158 | case "null": |
| 1159 | z.v = valueTypeNil |
| 1160 | case "true": |
| 1161 | z.v = valueTypeBool |
| 1162 | z.b = true |
| 1163 | case "false": |
| 1164 | z.v = valueTypeBool |
| 1165 | z.b = false |
| 1166 | default: |
| 1167 | // check if a number: float, int or uint |
| 1168 | if err := d.nakedNum(z, d.bs); err != nil { |
| 1169 | z.v = valueTypeString |
| 1170 | z.s = d.bsToString() |
| 1171 | } |
| 1172 | } |
| 1173 | } else { |
| 1174 | z.v = valueTypeString |
| 1175 | z.s = d.bsToString() |
| 1176 | } |
| 1177 | default: // number |
| 1178 | bs := d.decNumBytes() |
| 1179 | if len(bs) == 0 { |
| 1180 | d.d.errorf("decode number from empty string") |
| 1181 | return |
| 1182 | } |
| 1183 | if err := d.nakedNum(z, bs); err != nil { |
| 1184 | d.d.errorf("decode number from %s: %v", bs, err) |
| 1185 | return |
| 1186 | } |
| 1187 | } |
| 1188 | // if decodeFurther { |
| 1189 | // d.s.sc.retryRead() |
| 1190 | // } |
| 1191 | return |
| 1192 | } |
| 1193 | |
| 1194 | //---------------------- |
| 1195 | |
| 1196 | // JsonHandle is a handle for JSON encoding format. |
| 1197 | // |
| 1198 | // Json is comprehensively supported: |
| 1199 | // - decodes numbers into interface{} as int, uint or float64 |
| 1200 | // based on how the number looks and some config parameters e.g. PreferFloat, SignedInt, etc. |
| 1201 | // - decode integers from float formatted numbers e.g. 1.27e+8 |
| 1202 | // - decode any json value (numbers, bool, etc) from quoted strings |
| 1203 | // - configurable way to encode/decode []byte . |
| 1204 | // by default, encodes and decodes []byte using base64 Std Encoding |
| 1205 | // - UTF-8 support for encoding and decoding |
| 1206 | // |
| 1207 | // It has better performance than the json library in the standard library, |
| 1208 | // by leveraging the performance improvements of the codec library. |
| 1209 | // |
| 1210 | // In addition, it doesn't read more bytes than necessary during a decode, which allows |
| 1211 | // reading multiple values from a stream containing json and non-json content. |
| 1212 | // For example, a user can read a json value, then a cbor value, then a msgpack value, |
| 1213 | // all from the same stream in sequence. |
| 1214 | // |
| 1215 | // Note that, when decoding quoted strings, invalid UTF-8 or invalid UTF-16 surrogate pairs are |
| 1216 | // not treated as an error. Instead, they are replaced by the Unicode replacement character U+FFFD. |
| 1217 | type JsonHandle struct { |
| 1218 | textEncodingType |
| 1219 | BasicHandle |
| 1220 | |
| 1221 | // Indent indicates how a value is encoded. |
| 1222 | // - If positive, indent by that number of spaces. |
| 1223 | // - If negative, indent by that number of tabs. |
| 1224 | Indent int8 |
| 1225 | |
| 1226 | // IntegerAsString controls how integers (signed and unsigned) are encoded. |
| 1227 | // |
| 1228 | // Per the JSON Spec, JSON numbers are 64-bit floating point numbers. |
| 1229 | // Consequently, integers > 2^53 cannot be represented as a JSON number without losing precision. |
| 1230 | // This can be mitigated by configuring how to encode integers. |
| 1231 | // |
| 1232 | // IntegerAsString interpretes the following values: |
| 1233 | // - if 'L', then encode integers > 2^53 as a json string. |
| 1234 | // - if 'A', then encode all integers as a json string |
| 1235 | // containing the exact integer representation as a decimal. |
| 1236 | // - else encode all integers as a json number (default) |
| 1237 | IntegerAsString byte |
| 1238 | |
| 1239 | // HTMLCharsAsIs controls how to encode some special characters to html: < > & |
| 1240 | // |
| 1241 | // By default, we encode them as \uXXX |
| 1242 | // to prevent security holes when served from some browsers. |
| 1243 | HTMLCharsAsIs bool |
| 1244 | |
| 1245 | // PreferFloat says that we will default to decoding a number as a float. |
| 1246 | // If not set, we will examine the characters of the number and decode as an |
| 1247 | // integer type if it doesn't have any of the characters [.eE]. |
| 1248 | PreferFloat bool |
| 1249 | |
| 1250 | // TermWhitespace says that we add a whitespace character |
| 1251 | // at the end of an encoding. |
| 1252 | // |
| 1253 | // The whitespace is important, especially if using numbers in a context |
| 1254 | // where multiple items are written to a stream. |
| 1255 | TermWhitespace bool |
| 1256 | |
| 1257 | // MapKeyAsString says to encode all map keys as strings. |
| 1258 | // |
| 1259 | // Use this to enforce strict json output. |
| 1260 | // The only caveat is that nil value is ALWAYS written as null (never as "null") |
| 1261 | MapKeyAsString bool |
| 1262 | |
| 1263 | // _ [2]byte // padding |
| 1264 | |
| 1265 | // Note: below, we store hardly-used items e.g. RawBytesExt is cached in the (en|de)cDriver. |
| 1266 | |
| 1267 | // RawBytesExt, if configured, is used to encode and decode raw bytes in a custom way. |
| 1268 | // If not configured, raw bytes are encoded to/from base64 text. |
| 1269 | RawBytesExt InterfaceExt |
| 1270 | |
| 1271 | _ [2]uint64 // padding |
| 1272 | } |
| 1273 | |
| 1274 | // Name returns the name of the handle: json |
| 1275 | func (h *JsonHandle) Name() string { return "json" } |
| 1276 | func (h *JsonHandle) hasElemSeparators() bool { return true } |
| 1277 | func (h *JsonHandle) typical() bool { |
| 1278 | return h.Indent == 0 && !h.MapKeyAsString && h.IntegerAsString != 'A' && h.IntegerAsString != 'L' |
| 1279 | } |
| 1280 | |
| 1281 | type jsonTypical interface { |
| 1282 | typical() |
| 1283 | } |
| 1284 | |
| 1285 | func (h *JsonHandle) recreateEncDriver(ed encDriver) (v bool) { |
| 1286 | _, v = ed.(jsonTypical) |
| 1287 | return v != h.typical() |
| 1288 | } |
| 1289 | |
| 1290 | // SetInterfaceExt sets an extension |
| 1291 | func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) { |
| 1292 | return h.SetExt(rt, tag, &extWrapper{bytesExtFailer{}, ext}) |
| 1293 | } |
| 1294 | |
| 1295 | type jsonEncDriverTypicalImpl struct { |
| 1296 | jsonEncDriver |
| 1297 | jsonEncDriverTypical |
| 1298 | _ [1]uint64 // padding |
| 1299 | } |
| 1300 | |
| 1301 | func (x *jsonEncDriverTypicalImpl) reset() { |
| 1302 | x.jsonEncDriver.reset() |
| 1303 | x.jsonEncDriverTypical.reset(&x.jsonEncDriver) |
| 1304 | } |
| 1305 | |
| 1306 | type jsonEncDriverGenericImpl struct { |
| 1307 | jsonEncDriver |
| 1308 | jsonEncDriverGeneric |
| 1309 | } |
| 1310 | |
| 1311 | func (x *jsonEncDriverGenericImpl) reset() { |
| 1312 | x.jsonEncDriver.reset() |
| 1313 | x.jsonEncDriverGeneric.reset(&x.jsonEncDriver) |
| 1314 | } |
| 1315 | |
| 1316 | func (h *JsonHandle) newEncDriver(e *Encoder) (ee encDriver) { |
| 1317 | var hd *jsonEncDriver |
| 1318 | if h.typical() { |
| 1319 | var v jsonEncDriverTypicalImpl |
| 1320 | ee = &v |
| 1321 | hd = &v.jsonEncDriver |
| 1322 | } else { |
| 1323 | var v jsonEncDriverGenericImpl |
| 1324 | ee = &v |
| 1325 | hd = &v.jsonEncDriver |
| 1326 | } |
| 1327 | hd.e, hd.h, hd.bs = e, h, hd.b[:0] |
| 1328 | hd.se.BytesExt = bytesExtFailer{} |
| 1329 | ee.reset() |
| 1330 | return |
| 1331 | } |
| 1332 | |
| 1333 | func (h *JsonHandle) newDecDriver(d *Decoder) decDriver { |
| 1334 | // d := jsonDecDriver{r: r.(*bytesDecReader), h: h} |
| 1335 | hd := jsonDecDriver{d: d, h: h} |
| 1336 | hd.se.BytesExt = bytesExtFailer{} |
| 1337 | hd.bs = hd.b[:0] |
| 1338 | hd.reset() |
| 1339 | return &hd |
| 1340 | } |
| 1341 | |
| 1342 | func (e *jsonEncDriver) reset() { |
| 1343 | e.ew = e.e.w // e.e.w // &e.e.encWriterSwitch |
| 1344 | e.se.InterfaceExt = e.h.RawBytesExt |
| 1345 | if e.bs != nil { |
| 1346 | e.bs = e.bs[:0] |
| 1347 | } |
| 1348 | } |
| 1349 | |
| 1350 | func (d *jsonDecDriver) reset() { |
| 1351 | d.r = d.d.r // &d.d.decReaderSwitch // d.d.r |
| 1352 | d.se.InterfaceExt = d.h.RawBytesExt |
| 1353 | if d.bs != nil { |
| 1354 | d.bs = d.bs[:0] |
| 1355 | } |
| 1356 | d.c, d.tok = 0, 0 |
| 1357 | // d.n.reset() |
| 1358 | } |
| 1359 | |
| 1360 | func jsonFloatStrconvFmtPrec(f float64) (fmt byte, prec int) { |
| 1361 | prec = -1 |
| 1362 | var abs = math.Abs(f) |
| 1363 | if abs != 0 && (abs < 1e-6 || abs >= 1e21) { |
| 1364 | fmt = 'e' |
| 1365 | } else { |
| 1366 | fmt = 'f' |
| 1367 | // set prec to 1 iff mod is 0. |
| 1368 | // better than using jsonIsFloatBytesB2 to check if a . or E in the float bytes. |
| 1369 | // this ensures that every float has an e or .0 in it. |
| 1370 | if abs <= 1 { |
| 1371 | if abs == 0 || abs == 1 { |
| 1372 | prec = 1 |
| 1373 | } |
| 1374 | } else if _, mod := math.Modf(abs); mod == 0 { |
| 1375 | prec = 1 |
| 1376 | } |
| 1377 | } |
| 1378 | return |
| 1379 | } |
| 1380 | |
| 1381 | // custom-fitted version of strconv.Parse(Ui|I)nt. |
| 1382 | // Also ensures we don't have to search for .eE to determine if a float or not. |
| 1383 | func jsonParseInteger(s []byte) (n uint64, neg, badSyntax, overflow bool) { |
| 1384 | const maxUint64 = (1<<64 - 1) |
| 1385 | const cutoff = maxUint64/10 + 1 |
| 1386 | |
| 1387 | if len(s) == 0 { |
| 1388 | badSyntax = true |
| 1389 | return |
| 1390 | } |
| 1391 | switch s[0] { |
| 1392 | case '+': |
| 1393 | s = s[1:] |
| 1394 | case '-': |
| 1395 | s = s[1:] |
| 1396 | neg = true |
| 1397 | } |
| 1398 | for _, c := range s { |
| 1399 | if c < '0' || c > '9' { |
| 1400 | badSyntax = true |
| 1401 | return |
| 1402 | } |
| 1403 | // unsigned integers don't overflow well on multiplication, so check cutoff here |
| 1404 | // e.g. (maxUint64-5)*10 doesn't overflow well ... |
| 1405 | if n >= cutoff { |
| 1406 | overflow = true |
| 1407 | return |
| 1408 | } |
| 1409 | n *= 10 |
| 1410 | n1 := n + uint64(c-'0') |
| 1411 | if n1 < n || n1 > maxUint64 { |
| 1412 | overflow = true |
| 1413 | return |
| 1414 | } |
| 1415 | n = n1 |
| 1416 | } |
| 1417 | return |
| 1418 | } |
| 1419 | |
| 1420 | var _ decDriver = (*jsonDecDriver)(nil) |
| 1421 | var _ encDriver = (*jsonEncDriverGenericImpl)(nil) |
| 1422 | var _ encDriver = (*jsonEncDriverTypicalImpl)(nil) |
| 1423 | var _ jsonTypical = (*jsonEncDriverTypical)(nil) |