in json/parse.go [515:657]
func (p *Parser) unquote(in []byte) ([]byte, bool, error) {
if len(in) == 0 {
return in, false, nil
}
// Check for unusual characters and escape sequence. If none is found,
// return slice as is:
i := 0
for i < len(in) {
c := in[i]
if c == '\\' || c == '"' || c < ' ' {
break
}
if c < utf8.RuneSelf {
i++
continue
}
r, sz := utf8.DecodeRune(in[i:])
if r == utf8.RuneError && sz == 1 {
break
}
i += sz
}
// no special character found -> return as is
if i == len(in) {
return in, false, nil
}
// found escape character (or other unusual character) ->
// allocate output buffer (try to use literalBuffer)
out := p.literalBuffer[:0]
allocated := false
utf8Delta := 2 * utf8.UTFMax
minLen := len(in) + utf8Delta
if cap(out) < minLen {
// TODO: is minLen < some upper bound, store in literalBuffer
out = make([]byte, minLen)
allocated = true
} else {
out = out[:minLen]
}
// init output buffer
written := copy(out, in[:i])
for i < len(in) {
if written > len(out)-utf8Delta {
// out of room -> increase write buffer
newLen := len(out) * 2
if cap(out) < newLen {
tmp := make([]byte, len(out)*2)
copy(tmp, out[:written])
out = tmp
allocated = true
} else {
out = out[:newLen]
}
}
c := in[i]
switch {
case c == '\\':
i++
if i >= len(in) {
return nil, false, errUnquoteInEscape
}
switch in[i] {
default:
return nil, false, errUnquoteUnknownEscape
case '"', '\\', '/', '\'':
out[written] = in[i]
i++
written++
case 'b':
out[written] = '\b'
i++
written++
case 'f':
out[written] = '\f'
i++
written++
case 'n':
out[written] = '\n'
i++
written++
case 'r':
out[written] = '\r'
i++
written++
case 't':
out[written] = '\t'
i++
written++
case 'u':
i++
code, err := strconv.ParseUint(string(in[i:i+4]), 16, 64)
if err != nil {
return nil, false, errUnquoteInvalidUnicode
}
i += 4
r := rune(code)
if utf16.IsSurrogate(r) {
var dec rune = unicode.ReplacementChar
valid := in[i] == '\\' && in[i+1] == 'u'
if valid {
code, err := strconv.ParseUint(string(in[i+2:i+6]), 16, 64)
if err == nil {
dec = utf16.DecodeRune(r, rune(code))
if dec != unicode.ReplacementChar {
i += 6
}
}
}
r = dec
}
written += utf8.EncodeRune(out[written:], r)
}
case c == '"', c < ' ':
return nil, false, errUnquoteInvalidChar
case c < utf8.RuneSelf:
out[written] = c
i++
written++
default:
_, sz := utf8.DecodeRune(in[i:])
i += sz
written += copy(out[written:], in[i:i+sz])
}
}
return out[:written], allocated, nil
}