github.com/tobgu/qframe@v0.4.0/internal/strings/serialize.go (about) 1 package strings 2 3 import ( 4 "unicode/utf8" 5 ) 6 7 const chars = "0123456789abcdef" 8 9 func AppendQuotedString(buf []byte, str string) []byte { 10 // String escape code is highly inspired by the escape code in easyjson. 11 buf = append(buf, '"') 12 p := 0 13 // last non-escape symbol 14 for i := 0; i < len(str); { 15 c := str[i] 16 17 if c != '\\' && c != '"' && c >= 0x20 && c < utf8.RuneSelf { 18 // single-width character, no escaping is required 19 i++ 20 continue 21 } 22 23 if c < utf8.RuneSelf { 24 // single-with character, need to escape 25 buf = append(buf, str[p:i]...) 26 27 switch c { 28 case '\t': 29 buf = append(buf, `\t`...) 30 case '\r': 31 buf = append(buf, `\r`...) 32 case '\n': 33 buf = append(buf, `\n`...) 34 case '\\': 35 buf = append(buf, `\\`...) 36 case '"': 37 buf = append(buf, `\"`...) 38 default: 39 buf = append(buf, `\u00`...) 40 buf = append(buf, chars[c>>4]) 41 buf = append(buf, chars[c&0xf]) 42 } 43 44 i++ 45 p = i 46 continue 47 } 48 49 // broken utf 50 runeValue, runeWidth := utf8.DecodeRuneInString(str[i:]) 51 if runeValue == utf8.RuneError && runeWidth == 1 { 52 buf = append(buf, str[p:i]...) 53 buf = append(buf, `\ufffd`...) 54 i++ 55 p = i 56 continue 57 } 58 59 // jsonp stuff - tab separator and line separator 60 if runeValue == '\u2028' || runeValue == '\u2029' { 61 buf = append(buf, str[p:i]...) 62 buf = append(buf, `\u202`...) 63 buf = append(buf, chars[runeValue&0xf]) 64 i += runeWidth 65 p = i 66 continue 67 } 68 i += runeWidth 69 } 70 71 buf = append(buf, str[p:]...) 72 buf = append(buf, '"') 73 return buf 74 }