in writer.go [113:176]
func (w *Writer) StringContents(s string) {
// Portions of the string that contain no escapes are appended as byte slices.
p := 0 // last non-escape symbol
for i := 0; i < len(s); {
if c := s[i]; c < utf8.RuneSelf {
if htmlSafeSet[c] {
i++
continue
}
// single-with character, need to escape
w.RawString(s[p:i])
switch c {
case '\\':
w.RawString(`\\`)
case '"':
w.RawString(`\"`)
case '\b':
w.RawString(`\b`)
case '\f':
w.RawString(`\f`)
case '\n':
w.RawString(`\n`)
case '\r':
w.RawString(`\r`)
case '\t':
w.RawString(`\t`)
default:
w.RawString(`\u00`)
w.RawByte(chars[c>>4])
w.RawByte(chars[c&0xf])
}
i++
p = i
continue
}
// broken utf
runeValue, runeWidth := utf8.DecodeRuneInString(s[i:])
if runeValue == utf8.RuneError && runeWidth == 1 {
w.RawString(s[p:i])
w.RawString(`\ufffd`)
i++
p = i
continue
}
// jsonp stuff - tab separator and line separator
if runeValue == '\u2028' || runeValue == '\u2029' {
w.RawString(s[p:i])
w.RawString(`\u202`)
w.RawByte(chars[runeValue&0xf])
i += runeWidth
p = i
continue
}
i += runeWidth
}
w.RawString(s[p:])
}