package json
import (
"bytes"
"strconv"
"utf8"
)
func _UnHex(p string, r, l int) (v int, ok bool) {
v = 0
for i := r; i < l; i++ {
if i >= len(p) {
return 0, false
}
v *= 16
switch {
case '0' <= p[i] && p[i] <= '9':
v += int(p[i] - '0')
case 'a' <= p[i] && p[i] <= 'f':
v += int(p[i] - 'a' + 10)
case 'A' <= p[i] && p[i] <= 'F':
v += int(p[i] - 'A' + 10)
default:
return 0, false
}
}
return v, true
}
func _ToHex(b []byte, rune int) {
const hexDigits = "0123456789abcdef"
b[0] = hexDigits[rune>>12&0xf]
b[1] = hexDigits[rune>>8&0xf]
b[2] = hexDigits[rune>>4&0xf]
b[3] = hexDigits[rune&0xf]
}
func Unquote(s string) (t string, ok bool) {
if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
return
}
b := make([]byte, len(s))
w := 0
for r := 1; r < len(s)-1; {
switch {
case s[r] == '\\':
r++
if r >= len(s)-1 {
return
}
switch s[r] {
default:
return
case '"', '\\', '/', '\'':
b[w] = s[r]
r++
w++
case 'b':
b[w] = '\b'
r++
w++
case 'f':
b[w] = '\f'
r++
w++
case 'n':
b[w] = '\n'
r++
w++
case 'r':
b[w] = '\r'
r++
w++
case 't':
b[w] = '\t'
r++
w++
case 'u':
r++
rune, ok := _UnHex(s, r, r+4)
if !ok {
return
}
r += 4
w += utf8.EncodeRune(rune, b[w:])
}
case s[r] < ' ' && s[r] != '\n':
if s[r] == '\n' {
b[w] = '\n'
r++
w++
break
}
return
case s[r] < utf8.RuneSelf:
b[w] = s[r]
r++
w++
default:
rune, size := utf8.DecodeRuneInString(s[r:])
r += size
w += utf8.EncodeRune(rune, b[w:])
}
}
return string(b[0:w]), true
}
func Quote(s string) string {
chr := make([]byte, 6)
chr0 := chr[0:1]
b := new(bytes.Buffer)
chr[0] = '"'
b.Write(chr0)
for _, rune := range s {
switch {
case rune == '"' || rune == '\\':
chr[0] = '\\'
chr[1] = byte(rune)
b.Write(chr[0:2])
case rune == '\b':
chr[0] = '\\'
chr[1] = 'b'
b.Write(chr[0:2])
case rune == '\f':
chr[0] = '\\'
chr[1] = 'f'
b.Write(chr[0:2])
case rune == '\n':
chr[0] = '\\'
chr[1] = 'n'
b.Write(chr[0:2])
case rune == '\r':
chr[0] = '\\'
chr[1] = 'r'
b.Write(chr[0:2])
case rune == '\t':
chr[0] = '\\'
chr[1] = 't'
b.Write(chr[0:2])
case 0x20 <= rune && rune < utf8.RuneSelf:
chr[0] = byte(rune)
b.Write(chr0)
default:
chr[0] = '\\'
chr[1] = 'u'
_ToHex(chr[2:6], rune)
b.Write(chr)
}
}
chr[0] = '"'
b.Write(chr0)
return b.String()
}
type _Lexer struct {
s string
i int
kind int
token string
}
func punct(c byte) bool {
return c == '"' || c == '[' || c == ']' || c == ':' || c == '{' || c == '}' || c == ','
}
func white(c byte) bool { return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\v' }
func skipwhite(p string, i int) int {
for i < len(p) && white(p[i]) {
i++
}
return i
}
func skiptoken(p string, i int) int {
for i < len(p) && !punct(p[i]) && !white(p[i]) {
i++
}
return i
}
func skipstring(p string, i int) int {
for i++; i < len(p) && p[i] != '"'; i++ {
if p[i] == '\\' {
i++
}
}
if i >= len(p) {
return i
}
return i + 1
}
func (t *_Lexer) Next() {
i, s := t.i, t.s
i = skipwhite(s, i)
if i >= len(s) {
t.kind = 0
t.token = ""
t.i = len(s)
return
}
c := s[i]
switch {
case c == '-' || '0' <= c && c <= '9':
j := skiptoken(s, i)
t.kind = '1'
t.token = s[i:j]
i = j
case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
j := skiptoken(s, i)
t.kind = 'a'
t.token = s[i:j]
i = j
case c == '"':
j := skipstring(s, i)
t.kind = '"'
t.token = s[i:j]
i = j
case c == '[', c == ']', c == ':', c == '{', c == '}', c == ',':
t.kind = int(c)
t.token = s[i : i+1]
i++
default:
t.kind = '?'
t.token = s[i : i+1]
}
t.i = i
}
type _Value interface{}
type Builder interface {
Int64(i int64)
Uint64(i uint64)
Float64(f float64)
String(s string)
Bool(b bool)
Null()
Array()
Map()
Elem(i int) Builder
Key(s string) Builder
Flush()
}
func parse(lex *_Lexer, build Builder) bool {
ok := false
Switch:
switch lex.kind {
case 0:
break
case '1':
if i, err := strconv.Atoi64(lex.token); err == nil {
build.Int64(i)
ok = true
} else if i, err := strconv.Atoui64(lex.token); err == nil {
build.Uint64(i)
ok = true
} else
if f, err := strconv.Atof64(lex.token); err == nil {
build.Float64(f)
ok = true
}
case 'a':
switch lex.token {
case "true":
build.Bool(true)
ok = true
case "false":
build.Bool(false)
ok = true
case "null":
build.Null()
ok = true
}
case '"':
if str, ok1 := Unquote(lex.token); ok1 {
build.String(str)
ok = true
}
case '[':
build.Array()
lex.Next()
n := 0
for lex.kind != ']' {
if n > 0 {
if lex.kind != ',' {
break Switch
}
lex.Next()
}
if !parse(lex, build.Elem(n)) {
break Switch
}
n++
}
ok = true
case '{':
lex.Next()
build.Map()
n := 0
for lex.kind != '}' {
if n > 0 {
if lex.kind != ',' {
break Switch
}
lex.Next()
}
if lex.kind != '"' {
break Switch
}
key, ok := Unquote(lex.token)
if !ok {
break Switch
}
lex.Next()
if lex.kind != ':' {
break Switch
}
lex.Next()
if !parse(lex, build.Key(key)) {
break Switch
}
n++
}
ok = true
}
if ok {
lex.Next()
}
build.Flush()
return ok
}
func Parse(s string, builder Builder) (ok bool, errindx int, errtok string) {
lex := new(_Lexer)
lex.s = s
lex.Next()
if parse(lex, builder) {
if lex.kind == 0 {
return true, 0, ""
}
}
return false, lex.i, lex.token
}