package jsoniter
import (
"fmt"
"unicode/utf16"
)
func (iter *Iterator ) ReadString () (ret string ) {
c := iter .nextToken ()
if c == '"' {
for i := iter .head ; i < iter .tail ; i ++ {
c := iter .buf [i ]
if c == '"' {
ret = string (iter .buf [iter .head :i ])
iter .head = i + 1
return ret
} else if c == '\\' {
break
} else if c < ' ' {
iter .ReportError ("ReadString" ,
fmt .Sprintf (`invalid control character found: %d` , c ))
return
}
}
return iter .readStringSlowPath ()
} else if c == 'n' {
iter .skipThreeBytes ('u' , 'l' , 'l' )
return ""
}
iter .ReportError ("ReadString" , `expects " or n, but found ` +string ([]byte {c }))
return
}
func (iter *Iterator ) readStringSlowPath () (ret string ) {
var str []byte
var c byte
for iter .Error == nil {
c = iter .readByte ()
if c == '"' {
return string (str )
}
if c == '\\' {
c = iter .readByte ()
str = iter .readEscapedChar (c , str )
} else {
str = append (str , c )
}
}
iter .ReportError ("readStringSlowPath" , "unexpected end of input" )
return
}
func (iter *Iterator ) readEscapedChar (c byte , str []byte ) []byte {
switch c {
case 'u' :
r := iter .readU4 ()
if utf16 .IsSurrogate (r ) {
c = iter .readByte ()
if iter .Error != nil {
return nil
}
if c != '\\' {
iter .unreadByte ()
str = appendRune (str , r )
return str
}
c = iter .readByte ()
if iter .Error != nil {
return nil
}
if c != 'u' {
str = appendRune (str , r )
return iter .readEscapedChar (c , str )
}
r2 := iter .readU4 ()
if iter .Error != nil {
return nil
}
combined := utf16 .DecodeRune (r , r2 )
if combined == '\uFFFD' {
str = appendRune (str , r )
str = appendRune (str , r2 )
} else {
str = appendRune (str , combined )
}
} else {
str = appendRune (str , r )
}
case '"' :
str = append (str , '"' )
case '\\' :
str = append (str , '\\' )
case '/' :
str = append (str , '/' )
case 'b' :
str = append (str , '\b' )
case 'f' :
str = append (str , '\f' )
case 'n' :
str = append (str , '\n' )
case 'r' :
str = append (str , '\r' )
case 't' :
str = append (str , '\t' )
default :
iter .ReportError ("readEscapedChar" ,
`invalid escape char after \` )
return nil
}
return str
}
func (iter *Iterator ) ReadStringAsSlice () (ret []byte ) {
c := iter .nextToken ()
if c == '"' {
for i := iter .head ; i < iter .tail ; i ++ {
if iter .buf [i ] == '"' {
ret = iter .buf [iter .head :i ]
iter .head = i + 1
return ret
}
}
readLen := iter .tail - iter .head
copied := make ([]byte , readLen , readLen *2 )
copy (copied , iter .buf [iter .head :iter .tail ])
iter .head = iter .tail
for iter .Error == nil {
c := iter .readByte ()
if c == '"' {
return copied
}
copied = append (copied , c )
}
return copied
}
iter .ReportError ("ReadStringAsSlice" , `expects " or n, but found ` +string ([]byte {c }))
return
}
func (iter *Iterator ) readU4 () (ret rune ) {
for i := 0 ; i < 4 ; i ++ {
c := iter .readByte ()
if iter .Error != nil {
return
}
if c >= '0' && c <= '9' {
ret = ret *16 + rune (c -'0' )
} else if c >= 'a' && c <= 'f' {
ret = ret *16 + rune (c -'a' +10 )
} else if c >= 'A' && c <= 'F' {
ret = ret *16 + rune (c -'A' +10 )
} else {
iter .ReportError ("readU4" , "expects 0~9 or a~f, but found " +string ([]byte {c }))
return
}
}
return ret
}
const (
t1 = 0x00
tx = 0x80
t2 = 0xC0
t3 = 0xE0
t4 = 0xF0
t5 = 0xF8
maskx = 0x3F
mask2 = 0x1F
mask3 = 0x0F
mask4 = 0x07
rune1Max = 1 <<7 - 1
rune2Max = 1 <<11 - 1
rune3Max = 1 <<16 - 1
surrogateMin = 0xD800
surrogateMax = 0xDFFF
maxRune = '\U0010FFFF'
runeError = '\uFFFD'
)
func appendRune(p []byte , r rune ) []byte {
switch i := uint32 (r ); {
case i <= rune1Max :
p = append (p , byte (r ))
return p
case i <= rune2Max :
p = append (p , t2 |byte (r >>6 ))
p = append (p , tx |byte (r )&maskx )
return p
case i > maxRune , surrogateMin <= i && i <= surrogateMax :
r = runeError
fallthrough
case i <= rune3Max :
p = append (p , t3 |byte (r >>12 ))
p = append (p , tx |byte (r >>6 )&maskx )
p = append (p , tx |byte (r )&maskx )
return p
default :
p = append (p , t4 |byte (r >>18 ))
p = append (p , tx |byte (r >>12 )&maskx )
p = append (p , tx |byte (r >>6 )&maskx )
p = append (p , tx |byte (r )&maskx )
return p
}
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .