github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/util/jsonbytes/jsonbytes.go (about)

     1  // Copyright 2020 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package jsonbytes
    12  
    13  import "unicode/utf8"
    14  
    15  const hexAlphabet = "0123456789abcdef"
    16  
    17  // EncodeString writes a string literal to b as a JSON string.
    18  // Note that the delimiting double quotes are not included.
    19  // Cribbed from https://github.com/golang/go/blob/7badae85f20f1bce4cc344f9202447618d45d414/src/encoding/json/encode.go.
    20  func EncodeString(buf []byte, s string) []byte {
    21  	start := 0
    22  	for i := 0; i < len(s); {
    23  		if b := s[i]; b < utf8.RuneSelf {
    24  			if b >= ' ' && b != '"' && b != '\\' {
    25  				i++
    26  				continue
    27  			}
    28  			if start < i {
    29  				buf = append(buf, s[start:i]...)
    30  			}
    31  			switch b {
    32  			case '\\', '"':
    33  				buf = append(buf, '\\', b)
    34  			case '\n':
    35  				buf = append(buf, '\\', 'n')
    36  			case '\r':
    37  				buf = append(buf, '\\', 'r')
    38  			case '\t':
    39  				buf = append(buf, '\\', 't')
    40  			default:
    41  				// This encodes bytes < 0x20 except for \t, \n and \r.
    42  				// If escapeHTML is set, it also escapes <, >, and &
    43  				// because they can lead to security holes when
    44  				// user-controlled strings are rendered into JSON
    45  				// and served to some browsers.
    46  				buf = append(buf, '\\', 'u', '0', '0', hexAlphabet[b>>4], hexAlphabet[b&0xF])
    47  			}
    48  			i++
    49  			start = i
    50  			continue
    51  		}
    52  		c, size := utf8.DecodeRuneInString(s[i:])
    53  		if c == utf8.RuneError && size == 1 {
    54  			if start < i {
    55  				buf = append(buf, s[start:i]...)
    56  			}
    57  			buf = append(buf, `\ufffd`...)
    58  			i += size
    59  			start = i
    60  			continue
    61  		}
    62  		i += size
    63  	}
    64  	if start < len(s) {
    65  		buf = append(buf, s[start:]...)
    66  	}
    67  	return buf
    68  }