github.com/wI2L/jettison@v0.7.4/encode.go (about) 1 package jettison 2 3 import ( 4 "encoding" 5 "encoding/base64" 6 "encoding/json" 7 "errors" 8 "fmt" 9 "math" 10 "reflect" 11 "runtime" 12 "sort" 13 "strconv" 14 "sync" 15 "time" 16 "unicode/utf8" 17 "unsafe" 18 ) 19 20 const hex = "0123456789abcdef" 21 22 //nolint:unparam 23 func encodeBool(p unsafe.Pointer, dst []byte, _ encOpts) ([]byte, error) { 24 if *(*bool)(p) { 25 return append(dst, "true"...), nil 26 } 27 return append(dst, "false"...), nil 28 } 29 30 // encodeString appends the escaped bytes of the string 31 // pointed by p to dst. If quoted is true, escaped double 32 // quote characters are added at the beginning and the 33 // end of the JSON string. 34 // nolint:unparam 35 func encodeString(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) { 36 dst = append(dst, '"') 37 dst = appendEscapedBytes(dst, sp2b(p), opts) 38 dst = append(dst, '"') 39 40 return dst, nil 41 } 42 43 //nolint:unparam 44 func encodeQuotedString(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) { 45 dst = append(dst, `"\"`...) 46 dst = appendEscapedBytes(dst, sp2b(p), opts) 47 dst = append(dst, `\""`...) 48 49 return dst, nil 50 } 51 52 // encodeFloat32 appends the textual representation of 53 // the 32-bits floating point number pointed by p to dst. 54 func encodeFloat32(p unsafe.Pointer, dst []byte, _ encOpts) ([]byte, error) { 55 return appendFloat(dst, float64(*(*float32)(p)), 32) 56 } 57 58 // encodeFloat64 appends the textual representation of 59 // the 64-bits floating point number pointed by p to dst. 60 func encodeFloat64(p unsafe.Pointer, dst []byte, _ encOpts) ([]byte, error) { 61 return appendFloat(dst, *(*float64)(p), 64) 62 } 63 64 func encodeInterface(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) { 65 v := *(*interface{})(p) 66 if v == nil { 67 return append(dst, "null"...), nil 68 } 69 typ := reflect.TypeOf(v) 70 ins := cachedInstr(typ) 71 72 return ins(unpackEface(v).word, dst, opts) 73 } 74 75 func encodeNumber(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) { 76 // Cast pointer to string directly to avoid 77 // a useless conversion. 78 num := *(*string)(p) 79 80 // In Go1.5 the empty string encodes to "0". 81 // While this is not a valid number literal, 82 // we keep compatibility, so check validity 83 // after this. 84 if num == "" { 85 num = "0" // Number's zero-val 86 } 87 if !opts.flags.has(noNumberValidation) && !isValidNumber(num) { 88 return dst, fmt.Errorf("json: invalid number literal %q", num) 89 } 90 return append(dst, num...), nil 91 } 92 93 func encodeRawMessage(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) { 94 v := *(*json.RawMessage)(p) 95 if v == nil { 96 return append(dst, "null"...), nil 97 } 98 if opts.flags.has(noCompact) { 99 return append(dst, v...), nil 100 } 101 return appendCompactJSON(dst, v, !opts.flags.has(noHTMLEscaping)) 102 } 103 104 // encodeTime appends the time.Time value pointed by 105 // p to dst based on the format configured in opts. 106 func encodeTime(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) { 107 t := *(*time.Time)(p) 108 y := t.Year() 109 110 if y < 0 || y >= 10000 { 111 // See comment golang.org/issue/4556#c15. 112 return dst, errors.New("time: year outside of range [0,9999]") 113 } 114 if opts.flags.has(unixTime) { 115 return strconv.AppendInt(dst, t.Unix(), 10), nil 116 } 117 switch opts.timeLayout { 118 case time.RFC3339: 119 return appendRFC3339Time(t, dst, false), nil 120 case time.RFC3339Nano: 121 return appendRFC3339Time(t, dst, true), nil 122 default: 123 dst = append(dst, '"') 124 dst = t.AppendFormat(dst, opts.timeLayout) 125 dst = append(dst, '"') 126 return dst, nil 127 } 128 } 129 130 // encodeDuration appends the time.Duration value pointed 131 // by p to dst based on the format configured in opts. 132 func encodeDuration(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) { 133 d := *(*time.Duration)(p) 134 135 switch opts.durationFmt { 136 default: // DurationNanoseconds 137 return strconv.AppendInt(dst, d.Nanoseconds(), 10), nil 138 case DurationMinutes: 139 return appendFloat(dst, d.Minutes(), 64) 140 case DurationSeconds: 141 return appendFloat(dst, d.Seconds(), 64) 142 case DurationMicroseconds: 143 return strconv.AppendInt(dst, int64(d)/1e3, 10), nil 144 case DurationMilliseconds: 145 return strconv.AppendInt(dst, int64(d)/1e6, 10), nil 146 case DurationString: 147 dst = append(dst, '"') 148 dst = appendDuration(dst, d) 149 dst = append(dst, '"') 150 return dst, nil 151 } 152 } 153 154 func appendFloat(dst []byte, f float64, bs int) ([]byte, error) { 155 if math.IsInf(f, 0) || math.IsNaN(f) { 156 return dst, &UnsupportedValueError{ 157 reflect.ValueOf(f), 158 strconv.FormatFloat(f, 'g', -1, bs), 159 } 160 } 161 // Convert as it was an ES6 number to string conversion. 162 // This matches most other JSON generators. The following 163 // code is taken from the floatEncoder implementation of 164 // the encoding/json package of the Go standard library. 165 abs := math.Abs(f) 166 format := byte('f') 167 if abs != 0 { 168 if bs == 64 && (abs < 1e-6 || abs >= 1e21) || 169 bs == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) { 170 format = 'e' 171 } 172 } 173 dst = strconv.AppendFloat(dst, f, format, -1, bs) 174 if format == 'e' { 175 n := len(dst) 176 if n >= 4 && dst[n-4] == 'e' && dst[n-3] == '-' && dst[n-2] == '0' { 177 dst[n-2] = dst[n-1] 178 dst = dst[:n-1] 179 } 180 } 181 return dst, nil 182 } 183 184 func encodePointer(p unsafe.Pointer, dst []byte, opts encOpts, ins instruction) ([]byte, error) { 185 if p = *(*unsafe.Pointer)(p); p != nil { 186 return ins(p, dst, opts) 187 } 188 return append(dst, "null"...), nil 189 } 190 191 func encodeStruct( 192 p unsafe.Pointer, dst []byte, opts encOpts, flds []field, 193 ) ([]byte, error) { 194 var ( 195 nxt = byte('{') 196 key []byte // key of the field 197 ) 198 noHTMLEscape := opts.flags.has(noHTMLEscaping) 199 200 fieldLoop: 201 for i := 0; i < len(flds); i++ { 202 f := &flds[i] // get pointer to prevent copy 203 if opts.isDeniedField(f.name) { 204 continue 205 } 206 v := p 207 208 // Find the nested struct field by following 209 // the offset sequence, indirecting encountered 210 // pointers as needed. 211 for i := 0; i < len(f.embedSeq); i++ { 212 s := &f.embedSeq[i] 213 v = unsafe.Pointer(uintptr(v) + s.offset) 214 if s.indir { 215 if v = *(*unsafe.Pointer)(v); v == nil { 216 // When we encounter a nil pointer 217 // in the chain, we have no choice 218 // but to ignore the field. 219 continue fieldLoop 220 } 221 } 222 } 223 // Ignore the field if it is a nil pointer and has 224 // the omitnil option in his tag. 225 if f.omitNil && *(*unsafe.Pointer)(v) == nil { 226 continue 227 } 228 // Ignore the field if it represents the zero-value 229 // of its type and has the omitempty option in his tag. 230 // Empty func is non-nil only if the field has the 231 // omitempty option in its tag. 232 if f.omitEmpty && f.empty(v) { 233 continue 234 } 235 key = f.keyEscHTML 236 if noHTMLEscape { 237 key = f.keyNonEsc 238 } 239 dst = append(dst, nxt) 240 nxt = ',' 241 dst = append(dst, key...) 242 243 var err error 244 if dst, err = f.instr(v, dst, opts); err != nil { 245 return dst, err 246 } 247 } 248 if nxt == '{' { 249 return append(dst, "{}"...), nil 250 } 251 return append(dst, '}'), nil 252 } 253 254 func encodeSlice( 255 p unsafe.Pointer, dst []byte, opts encOpts, ins instruction, es uintptr, 256 ) ([]byte, error) { 257 shdr := (*sliceHeader)(p) 258 if shdr.Data == nil { 259 if opts.flags.has(nilSliceEmpty) { 260 return append(dst, "[]"...), nil 261 } 262 return append(dst, "null"...), nil 263 } 264 if shdr.Len == 0 { 265 return append(dst, "[]"...), nil 266 } 267 return encodeArray(shdr.Data, dst, opts, ins, es, shdr.Len, false) 268 } 269 270 // encodeByteSlice appends a byte slice to dst as 271 // a JSON string. If the options flag rawByteSlice 272 // is set, the escaped bytes are appended to the 273 // buffer directly, otherwise in base64 form. 274 // nolint:unparam 275 func encodeByteSlice(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) { 276 b := *(*[]byte)(p) 277 if b == nil { 278 return append(dst, "null"...), nil 279 } 280 dst = append(dst, '"') 281 282 if opts.flags.has(rawByteSlice) { 283 dst = appendEscapedBytes(dst, b, opts) 284 } else { 285 n := base64.StdEncoding.EncodedLen(len(b)) 286 if a := cap(dst) - len(dst); a < n { 287 new := make([]byte, cap(dst)+(n-a)) 288 copy(new, dst) 289 dst = new[:len(dst)] 290 } 291 end := len(dst) + n 292 base64.StdEncoding.Encode(dst[len(dst):end], b) 293 294 dst = dst[:end] 295 } 296 return append(dst, '"'), nil 297 } 298 299 func encodeArray( 300 p unsafe.Pointer, dst []byte, opts encOpts, ins instruction, es uintptr, len int, isByteArray bool, 301 ) ([]byte, error) { 302 if isByteArray && opts.flags.has(byteArrayAsString) { 303 return encodeByteArrayAsString(p, dst, opts, len), nil 304 } 305 var err error 306 nxt := byte('[') 307 308 for i := 0; i < len; i++ { 309 dst = append(dst, nxt) 310 nxt = ',' 311 v := unsafe.Pointer(uintptr(p) + (uintptr(i) * es)) 312 if dst, err = ins(v, dst, opts); err != nil { 313 return dst, err 314 } 315 } 316 if nxt == '[' { 317 return append(dst, "[]"...), nil 318 } 319 return append(dst, ']'), nil 320 } 321 322 // encodeByteArrayAsString appends the escaped 323 // bytes of the byte array pointed by p to dst 324 // as a JSON string. 325 func encodeByteArrayAsString(p unsafe.Pointer, dst []byte, opts encOpts, len int) []byte { 326 // For byte type, size is guaranteed to be 1, 327 // so the slice length is the same as the array's. 328 // see golang.org/ref/spec#Size_and_alignment_guarantees 329 b := *(*[]byte)(unsafe.Pointer(&sliceHeader{ 330 Data: p, 331 Len: len, 332 Cap: len, 333 })) 334 dst = append(dst, '"') 335 dst = appendEscapedBytes(dst, b, opts) 336 dst = append(dst, '"') 337 338 return dst 339 } 340 341 func encodeMap( 342 p unsafe.Pointer, dst []byte, opts encOpts, t reflect.Type, ki, vi instruction, 343 ) ([]byte, error) { 344 m := *(*unsafe.Pointer)(p) 345 if m == nil { 346 if opts.flags.has(nilMapEmpty) { 347 return append(dst, "{}"...), nil 348 } 349 return append(dst, "null"...), nil 350 } 351 ml := maplen(m) 352 if ml == 0 { 353 return append(dst, "{}"...), nil 354 } 355 dst = append(dst, '{') 356 357 rt := unpackEface(t).word 358 it := newHiter(rt, m) 359 360 var err error 361 if opts.flags.has(unsortedMap) { 362 dst, err = encodeUnsortedMap(it, dst, opts, ki, vi) 363 } else { 364 dst, err = encodeSortedMap(it, dst, opts, ki, vi, ml) 365 } 366 hiterPool.Put(it) 367 368 if err != nil { 369 return dst, err 370 } 371 return append(dst, '}'), err 372 } 373 374 // encodeUnsortedMap appends the elements of the map 375 // pointed by p as comma-separated k/v pairs to dst, 376 // in unspecified order. 377 func encodeUnsortedMap( 378 it *hiter, dst []byte, opts encOpts, ki, vi instruction, 379 ) ([]byte, error) { 380 var ( 381 n int 382 err error 383 ) 384 for ; it.key != nil; mapiternext(it) { 385 if n != 0 { 386 dst = append(dst, ',') 387 } 388 // Encode entry's key. 389 if dst, err = ki(it.key, dst, opts); err != nil { 390 return dst, err 391 } 392 dst = append(dst, ':') 393 394 // Encode entry's value. 395 if dst, err = vi(it.val, dst, opts); err != nil { 396 return dst, err 397 } 398 n++ 399 } 400 return dst, nil 401 } 402 403 // encodeUnsortedMap appends the elements of the map 404 // pointed by p as comma-separated k/v pairs to dst, 405 // sorted by key in lexicographical order. 406 func encodeSortedMap( 407 it *hiter, dst []byte, opts encOpts, ki, vi instruction, ml int, 408 ) ([]byte, error) { 409 var ( 410 off int 411 err error 412 buf = cachedBuffer() 413 mel *mapElems 414 ) 415 if v := mapElemsPool.Get(); v != nil { 416 mel = v.(*mapElems) 417 } else { 418 mel = &mapElems{s: make([]kv, 0, ml)} 419 } 420 for ; it.key != nil; mapiternext(it) { 421 kv := kv{} 422 423 // Encode the key and store the buffer 424 // portion to use during sort. 425 if buf.B, err = ki(it.key, buf.B, opts); err != nil { 426 break 427 } 428 // Omit quotes of keys. 429 kv.key = buf.B[off+1 : len(buf.B)-1] 430 431 // Add separator after key. 432 buf.B = append(buf.B, ':') 433 434 // Encode the value and store the buffer 435 // portion corresponding to the semicolon 436 // delimited key/value pair. 437 if buf.B, err = vi(it.val, buf.B, opts); err != nil { 438 break 439 } 440 kv.keyval = buf.B[off:len(buf.B)] 441 mel.s = append(mel.s, kv) 442 off = len(buf.B) 443 } 444 if err == nil { 445 // Sort map entries by key in 446 // lexicographical order. 447 sort.Sort(mel) 448 449 // Append sorted comma-delimited k/v 450 // pairs to the given buffer. 451 for i, kv := range mel.s { 452 if i != 0 { 453 dst = append(dst, ',') 454 } 455 dst = append(dst, kv.keyval...) 456 } 457 } 458 // The map elements must be released before 459 // the buffer, because each k/v pair holds 460 // two sublices that points to the buffer's 461 // backing array. 462 releaseMapElems(mel) 463 bufferPool.Put(buf) 464 465 return dst, err 466 } 467 468 // encodeSyncMap appends the elements of a sync.Map pointed 469 // to by p to dst and returns the extended buffer. 470 // This function replicates the behavior of encoding Go maps, 471 // by returning an error for keys that are not of type string 472 // or int, or that does not implement encoding.TextMarshaler. 473 func encodeSyncMap(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) { 474 sm := (*sync.Map)(p) 475 dst = append(dst, '{') 476 477 // The sync.Map type does not have a Len() method to 478 // determine if it has no entries, to bail out early, 479 // so we just range over it to encode all available 480 // entries. 481 // If an error arises while encoding a key or a value, 482 // the error is stored and the method used by Range() 483 // returns false to stop the map's iteration. 484 var err error 485 if opts.flags.has(unsortedMap) { 486 dst, err = encodeUnsortedSyncMap(sm, dst, opts) 487 } else { 488 dst, err = encodeSortedSyncMap(sm, dst, opts) 489 } 490 if err != nil { 491 return dst, err 492 } 493 return append(dst, '}'), nil 494 } 495 496 // encodeUnsortedSyncMap is similar to encodeUnsortedMap 497 // but operates on a sync.Map type instead of a Go map. 498 func encodeUnsortedSyncMap(sm *sync.Map, dst []byte, opts encOpts) ([]byte, error) { 499 var ( 500 n int 501 err error 502 ) 503 sm.Range(func(key, value interface{}) bool { 504 if n != 0 { 505 dst = append(dst, ',') 506 } 507 // Encode the key. 508 if dst, err = appendSyncMapKey(dst, key, opts); err != nil { 509 return false 510 } 511 dst = append(dst, ':') 512 513 // Encode the value. 514 if dst, err = appendJSON(dst, value, opts); err != nil { 515 return false 516 } 517 n++ 518 return true 519 }) 520 return dst, err 521 } 522 523 // encodeSortedSyncMap is similar to encodeSortedMap 524 // but operates on a sync.Map type instead of a Go map. 525 func encodeSortedSyncMap(sm *sync.Map, dst []byte, opts encOpts) ([]byte, error) { 526 var ( 527 off int 528 err error 529 buf = cachedBuffer() 530 mel *mapElems 531 ) 532 if v := mapElemsPool.Get(); v != nil { 533 mel = v.(*mapElems) 534 } else { 535 mel = &mapElems{s: make([]kv, 0)} 536 } 537 sm.Range(func(key, value interface{}) bool { 538 kv := kv{} 539 540 // Encode the key and store the buffer 541 // portion to use during the later sort. 542 if buf.B, err = appendSyncMapKey(buf.B, key, opts); err != nil { 543 return false 544 } 545 // Omit quotes of keys. 546 kv.key = buf.B[off+1 : len(buf.B)-1] 547 548 // Add separator after key. 549 buf.B = append(buf.B, ':') 550 551 // Encode the value and store the buffer 552 // portion corresponding to the semicolon 553 // delimited key/value pair. 554 if buf.B, err = appendJSON(buf.B, value, opts); err != nil { 555 return false 556 } 557 kv.keyval = buf.B[off:len(buf.B)] 558 mel.s = append(mel.s, kv) 559 off = len(buf.B) 560 561 return true 562 }) 563 if err == nil { 564 // Sort map entries by key in 565 // lexicographical order. 566 sort.Sort(mel) 567 568 // Append sorted comma-delimited k/v 569 // pairs to the given buffer. 570 for i, kv := range mel.s { 571 if i != 0 { 572 dst = append(dst, ',') 573 } 574 dst = append(dst, kv.keyval...) 575 } 576 } 577 releaseMapElems(mel) 578 bufferPool.Put(buf) 579 580 return dst, err 581 } 582 583 func appendSyncMapKey(dst []byte, key interface{}, opts encOpts) ([]byte, error) { 584 if key == nil { 585 return dst, errors.New("unsupported nil key in sync.Map") 586 } 587 kt := reflect.TypeOf(key) 588 var ( 589 isStr = isString(kt) 590 isInt = isInteger(kt) 591 isTxt = kt.Implements(textMarshalerType) 592 ) 593 if !isStr && !isInt && !isTxt { 594 return dst, fmt.Errorf("unsupported key of type %s in sync.Map", kt) 595 } 596 var err error 597 598 // Quotes the key if the type is not 599 // encoded with quotes by default. 600 quoted := !isStr && !isTxt 601 602 // Ensure map key precedence for keys of type 603 // string by using the encodeString function 604 // directly instead of the generic appendJSON. 605 if isStr { 606 dst, err = encodeString(unpackEface(key).word, dst, opts) 607 runtime.KeepAlive(key) 608 } else { 609 if quoted { 610 dst = append(dst, '"') 611 } 612 dst, err = appendJSON(dst, key, opts) 613 } 614 if err != nil { 615 return dst, err 616 } 617 if quoted { 618 dst = append(dst, '"') 619 } 620 return dst, nil 621 } 622 623 func encodeMarshaler( 624 p unsafe.Pointer, dst []byte, opts encOpts, t reflect.Type, canAddr bool, fn marshalerEncodeFunc, 625 ) ([]byte, error) { 626 // The content of this function and packEface 627 // is similar to the following code using the 628 // reflect package. 629 // 630 // v := reflect.NewAt(t, p) 631 // if !canAddr { 632 // v = v.Elem() 633 // k := v.Kind() 634 // if (k == reflect.Ptr || k == reflect.Interface) && v.IsNil() { 635 // return append(dst, "null"...), nil 636 // } 637 // } else if v.IsNil() { 638 // return append(dst, "null"...), nil 639 // } 640 // return fn(v.Interface(), dst, opts, t) 641 // 642 if !canAddr { 643 if t.Kind() == reflect.Ptr || t.Kind() == reflect.Interface { 644 if *(*unsafe.Pointer)(p) == nil { 645 return append(dst, "null"...), nil 646 } 647 } 648 } else { 649 if p == nil { 650 return append(dst, "null"...), nil 651 } 652 t = reflect.PtrTo(t) 653 } 654 var i interface{} 655 656 if t.Kind() == reflect.Interface { 657 // Special case: return the element inside the 658 // interface. The empty interface has one layout, 659 // all interfaces with methods have another one. 660 if t.NumMethod() == 0 { 661 i = *(*interface{})(p) 662 } else { 663 i = *(*interface{ M() })(p) 664 } 665 } else { 666 i = packEface(p, t, t.Kind() == reflect.Ptr && !canAddr) 667 } 668 return fn(i, dst, opts, t) 669 } 670 671 func encodeAppendMarshalerCtx( 672 i interface{}, dst []byte, opts encOpts, t reflect.Type, 673 ) ([]byte, error) { 674 dst2, err := i.(AppendMarshalerCtx).AppendJSONContext(opts.ctx, dst) 675 if err != nil { 676 return dst, &MarshalerError{t, err, marshalerAppendJSONCtx} 677 } 678 return dst2, nil 679 } 680 681 func encodeAppendMarshaler( 682 i interface{}, dst []byte, _ encOpts, t reflect.Type, 683 ) ([]byte, error) { 684 dst2, err := i.(AppendMarshaler).AppendJSON(dst) 685 if err != nil { 686 return dst, &MarshalerError{t, err, marshalerAppendJSON} 687 } 688 return dst2, nil 689 } 690 691 func encodeJSONMarshaler(i interface{}, dst []byte, opts encOpts, t reflect.Type) ([]byte, error) { 692 b, err := i.(json.Marshaler).MarshalJSON() 693 if err != nil { 694 return dst, &MarshalerError{t, err, marshalerJSON} 695 } 696 if opts.flags.has(noCompact) { 697 return append(dst, b...), nil 698 } 699 // This is redundant with the parsing done 700 // by appendCompactJSON, but for the time 701 // being, we can't use the scanner of the 702 // standard library. 703 if !json.Valid(b) { 704 return dst, &MarshalerError{t, &SyntaxError{ 705 msg: "json: invalid value", 706 }, marshalerJSON} 707 } 708 return appendCompactJSON(dst, b, !opts.flags.has(noHTMLEscaping)) 709 } 710 711 func encodeTextMarshaler(i interface{}, dst []byte, _ encOpts, t reflect.Type) ([]byte, error) { 712 b, err := i.(encoding.TextMarshaler).MarshalText() 713 if err != nil { 714 return dst, &MarshalerError{t, err, marshalerText} 715 } 716 dst = append(dst, '"') 717 dst = append(dst, b...) 718 dst = append(dst, '"') 719 720 return dst, nil 721 } 722 723 // appendCompactJSON appends to dst the JSON-encoded src 724 // with insignificant space characters elided. If escHTML 725 // is true, HTML-characters are also escaped. 726 func appendCompactJSON(dst, src []byte, escHTML bool) ([]byte, error) { 727 var ( 728 inString bool 729 skipNext bool 730 ) 731 at := 0 // accumulated bytes start index 732 733 for i, c := range src { 734 if escHTML { 735 // Escape HTML characters. 736 if c == '<' || c == '>' || c == '&' { 737 if at < i { 738 dst = append(dst, src[at:i]...) 739 } 740 dst = append(dst, `\u00`...) 741 dst = append(dst, hex[c>>4], hex[c&0xF]) 742 at = i + 1 743 continue 744 } 745 } 746 // Convert U+2028 and U+2029. 747 // (E2 80 A8 and E2 80 A9). 748 if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 { 749 if at < i { 750 dst = append(dst, src[at:i]...) 751 } 752 dst = append(dst, `\u202`...) 753 dst = append(dst, hex[src[i+2]&0xF]) 754 at = i + 3 755 continue 756 } 757 if !inString { 758 switch c { 759 case '"': 760 // Within a string, we don't elide 761 // insignificant space characters. 762 inString = true 763 case ' ', '\n', '\r', '\t': 764 // Append the accumulated bytes, 765 // and skip the current character. 766 if at < i { 767 dst = append(dst, src[at:i]...) 768 } 769 at = i + 1 770 } 771 continue 772 } 773 // Next character is escaped, and must 774 // not be interpreted as the end of a 775 // string by mistake. 776 if skipNext { 777 skipNext = false 778 continue 779 } 780 // Next character must be skipped. 781 if c == '\\' { 782 skipNext = true 783 continue 784 } 785 // Leaving a string value. 786 if c == '"' { 787 inString = false 788 } 789 } 790 if at < len(src) { 791 dst = append(dst, src[at:]...) 792 } 793 return dst, nil 794 } 795 796 func appendEscapedBytes(dst []byte, b []byte, opts encOpts) []byte { 797 if opts.flags.has(noStringEscaping) { 798 return append(dst, b...) 799 } 800 var ( 801 i = 0 802 at = 0 803 ) 804 noCoerce := opts.flags.has(noUTF8Coercion) 805 noEscape := opts.flags.has(noHTMLEscaping) 806 807 for i < len(b) { 808 if c := b[i]; c < utf8.RuneSelf { 809 // Check whether c can be used in a JSON string 810 // without escaping, or it is a problematic HTML 811 // character. 812 if c >= ' ' && c != '\\' && c != '"' && (noEscape || (c != '<' && c != '>' && c != '&')) { 813 // If the current character doesn't need 814 // to be escaped, accumulate the bytes to 815 // save some operations. 816 i++ 817 continue 818 } 819 // Write accumulated single-byte characters. 820 if at < i { 821 dst = append(dst, b[at:i]...) 822 } 823 // The encoding/json package implements only 824 // a few of the special two-character escape 825 // sequence described in the RFC 8259, Section 7. 826 // \b and \f were ignored on purpose, see 827 // https://codereview.appspot.com/4678046. 828 switch c { 829 case '"', '\\': 830 dst = append(dst, '\\', c) 831 case '\n': // 0xA, line feed 832 dst = append(dst, '\\', 'n') 833 case '\r': // 0xD, carriage return 834 dst = append(dst, '\\', 'r') 835 case '\t': // 0x9, horizontal tab 836 dst = append(dst, '\\', 't') 837 default: 838 dst = append(dst, `\u00`...) 839 dst = append(dst, hex[c>>4]) 840 dst = append(dst, hex[c&0xF]) 841 } 842 i++ 843 at = i 844 continue 845 } 846 r, size := utf8.DecodeRune(b[i:]) 847 848 if !noCoerce { 849 // Coerce to valid UTF-8, by replacing invalid 850 // bytes with the Unicode replacement rune. 851 if r == utf8.RuneError && size == 1 { 852 if at < i { 853 dst = append(dst, b[at:i]...) 854 } 855 dst = append(dst, `\ufffd`...) 856 i += size 857 at = i 858 continue 859 } 860 // U+2028 is LINE SEPARATOR. 861 // U+2029 is PARAGRAPH SEPARATOR. 862 // They are both technically valid characters in 863 // JSON strings, but don't work in JSONP, which has 864 // to be evaluated as JavaScript, and can lead to 865 // security holes there. It is valid JSON to escape 866 // them, so we do so unconditionally. 867 // See http://timelessrepo.com/json-isnt-a-javascript-subset. 868 if r == '\u2028' || r == '\u2029' { 869 if at < i { 870 dst = append(dst, b[at:i]...) 871 } 872 dst = append(dst, `\u202`...) 873 dst = append(dst, hex[r&0xF]) 874 i += size 875 at = i 876 continue 877 } 878 i += size 879 continue 880 } 881 i += size 882 } 883 if at < len(b) { 884 dst = append(dst, b[at:]...) 885 } 886 return dst 887 }