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