package stt import "unicode/utf8" // safeSet holds the value true if the ASCII character with the given array // position can be represented inside a JSON string without any further // escaping. // // All values are true except for the ASCII control characters (0-31), the // double quote ("), and the backslash character ("\"). var safeSet = [utf8.RuneSelf]bool{ ' ': true, '!': true, '"': false, '#': true, '$': true, '%': true, '&': true, '\'': true, '(': true, ')': true, '*': true, '+': true, ',': true, '-': true, '.': true, '/': true, '0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true, '7': true, '8': true, '9': true, ':': true, ';': true, '<': true, '=': true, '>': true, '?': true, '@': true, 'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true, 'G': true, 'H': true, 'I': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true, 'O': true, 'P': true, 'Q': true, 'R': true, 'S': true, 'T': true, 'U': true, 'V': true, 'W': true, 'X': true, 'Y': true, 'Z': true, '[': true, '\\': true, ']': true, '^': true, '_': true, '`': true, 'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true, 'h': true, 'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'o': true, 'p': true, 'q': true, 'r': true, 's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true, 'y': true, 'z': true, '{': true, '|': true, '}': true, '~': true, '\u007f': true, } var hex = "0123456789abcdef" // WriteString write string to stream without html escape func (stream *Stream) WriteString(s string) { valLen := len(s) // write string, the fast path, without utf8 and escape support i := 0 for ; i < valLen; i++ { c := s[i] if c > 31 { switch c { case '@': stream.buf = append(stream.buf, '@', 'A') case '/': stream.buf = append(stream.buf, '@', 'S') default: stream.buf = append(stream.buf, c) } } else { break } } if i == valLen { return } writeStringSlowPath(stream, i, s, valLen) } func writeStringSlowPath(stream *Stream, i int, s string, valLen int) { start := i // for the remaining parts, we process them char by char for i < valLen { if b := s[i]; b < utf8.RuneSelf { if safeSet[b] { i++ continue } if start < i { stream.WriteRaw(s[start:i]) } switch b { case '\\', '"': stream.writeBytes('\\', b) case '\n': stream.writeBytes('\\', 'n') case '\r': stream.writeBytes('\\', 'r') case '\t': stream.writeBytes('\\', 't') default: // This encodes bytes < 0x20 except for \t, \n and \r. // If escapeHTML is set, it also escapes <, >, and & // because they can lead to security holes when // user-controlled strings are rendered into JSON // and served to some browsers. stream.WriteRaw(`\u00`) stream.writeBytes(hex[b>>4], hex[b&0xF]) } i++ start = i continue } i++ continue } if start < len(s) { stream.WriteRaw(s[start:]) } }