1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
|
package quicktemplate
import (
"bytes"
"fmt"
"strings"
)
func hasSpecialChars(s string) bool {
if strings.IndexByte(s, '"') >= 0 || strings.IndexByte(s, '\\') >= 0 || strings.IndexByte(s, '<') >= 0 || strings.IndexByte(s, '\'') >= 0 {
return true
}
for i := 0; i < len(s); i++ {
if s[i] < 0x20 {
return true
}
}
return false
}
// AppendJSONString appends json-encoded string s to dst and returns the result.
//
// If addQuotes is true, then the appended json string is wrapped into double quotes.
func AppendJSONString(dst []byte, s string, addQuotes bool) []byte {
if !hasSpecialChars(s) {
// Fast path - nothing to escape.
if !addQuotes {
return append(dst, s...)
}
dst = append(dst, '"')
dst = append(dst, s...)
dst = append(dst, '"')
return dst
}
// Slow path - there are chars to escape.
if addQuotes {
dst = append(dst, '"')
}
dst = jsonReplacer.AppendReplace(dst, s)
if addQuotes {
dst = append(dst, '"')
}
return dst
}
var jsonReplacer = newByteReplacer(func() ([]byte, []string) {
oldChars := []byte("\n\r\t\b\f\"\\<'")
newStrings := []string{`\n`, `\r`, `\t`, `\b`, `\f`, `\"`, `\\`, `\u003c`, `\u0027`}
for i := 0; i < 0x20; i++ {
c := byte(i)
if n := bytes.IndexByte(oldChars, c); n >= 0 {
continue
}
oldChars = append(oldChars, byte(i))
newStrings = append(newStrings, fmt.Sprintf(`\u%04x`, i))
}
return oldChars, newStrings
}())
type byteReplacer struct {
m [256]byte
newStrings []string
}
func newByteReplacer(oldChars []byte, newStrings []string) *byteReplacer {
if len(oldChars) != len(newStrings) {
panic(fmt.Errorf("len(oldChars)=%d must be equal to len(newStrings)=%d", len(oldChars), len(newStrings)))
}
if len(oldChars) >= 255 {
panic(fmt.Errorf("len(oldChars)=%d must be smaller than 255", len(oldChars)))
}
var m [256]byte
for i := range m[:] {
m[i] = 255
}
for i, c := range oldChars {
m[c] = byte(i)
}
return &byteReplacer{
m: m,
newStrings: newStrings,
}
}
func (br *byteReplacer) AppendReplace(dst []byte, s string) []byte {
m := br.m
newStrings := br.newStrings
for i := 0; i < len(s); i++ {
c := s[i]
n := m[c]
if n == 255 {
dst = append(dst, c)
} else {
dst = append(dst, newStrings[n]...)
}
}
return dst
}
|