2017-01-05 07:53:38 +02:00
|
|
|
package jsoniter
|
|
|
|
|
2017-05-24 07:16:09 +02:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"unicode"
|
|
|
|
)
|
2017-05-02 04:15:21 +02:00
|
|
|
|
2017-07-09 10:09:23 +02:00
|
|
|
// ReadObject read one field from object.
|
|
|
|
// If object ended, returns empty string.
|
|
|
|
// Otherwise, returns the field name.
|
2017-01-05 07:53:38 +02:00
|
|
|
func (iter *Iterator) ReadObject() (ret string) {
|
|
|
|
c := iter.nextToken()
|
|
|
|
switch c {
|
2017-01-05 15:23:08 +02:00
|
|
|
case 'n':
|
2017-07-10 09:23:35 +02:00
|
|
|
iter.skipThreeBytes('u', 'l', 'l')
|
2017-01-05 07:53:38 +02:00
|
|
|
return "" // null
|
2017-01-05 15:23:08 +02:00
|
|
|
case '{':
|
2017-01-05 07:53:38 +02:00
|
|
|
c = iter.nextToken()
|
2017-01-20 06:56:49 +02:00
|
|
|
if c == '"' {
|
2017-01-05 07:53:38 +02:00
|
|
|
iter.unreadByte()
|
2018-02-14 04:31:55 +02:00
|
|
|
field := iter.ReadString()
|
|
|
|
c = iter.nextToken()
|
|
|
|
if c != ':' {
|
|
|
|
iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
|
2017-10-31 16:38:41 +02:00
|
|
|
}
|
2018-02-14 04:31:55 +02:00
|
|
|
return field
|
2017-01-05 07:53:38 +02:00
|
|
|
}
|
2017-01-20 06:56:49 +02:00
|
|
|
if c == '}' {
|
|
|
|
return "" // end of object
|
|
|
|
}
|
2017-10-10 02:57:02 +02:00
|
|
|
iter.ReportError("ReadObject", `expect " after {, but found `+string([]byte{c}))
|
2017-01-20 06:56:49 +02:00
|
|
|
return
|
2017-01-05 07:53:38 +02:00
|
|
|
case ',':
|
2018-02-14 04:31:55 +02:00
|
|
|
field := iter.ReadString()
|
|
|
|
c = iter.nextToken()
|
|
|
|
if c != ':' {
|
|
|
|
iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
|
2017-10-31 16:38:41 +02:00
|
|
|
}
|
2018-02-14 04:31:55 +02:00
|
|
|
return field
|
2017-01-05 07:53:38 +02:00
|
|
|
case '}':
|
|
|
|
return "" // end of object
|
|
|
|
default:
|
2017-06-20 09:11:01 +02:00
|
|
|
iter.ReportError("ReadObject", fmt.Sprintf(`expect { or , or } or n, but found %s`, string([]byte{c})))
|
2017-01-05 07:53:38 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-14 05:33:17 +02:00
|
|
|
// CaseInsensitive
|
|
|
|
func (iter *Iterator) readFieldHash() int64 {
|
2017-02-09 07:35:58 +02:00
|
|
|
hash := int64(0x811c9dc5)
|
2017-02-08 07:46:28 +02:00
|
|
|
c := iter.nextToken()
|
2018-02-14 05:33:17 +02:00
|
|
|
if c != '"' {
|
|
|
|
iter.ReportError("readFieldHash", `expect ", but found `+string([]byte{c}))
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
for {
|
|
|
|
for i := iter.head; i < iter.tail; i++ {
|
|
|
|
// require ascii string and no escape
|
|
|
|
b := iter.buf[i]
|
|
|
|
if b == '\\' {
|
|
|
|
iter.head = i
|
|
|
|
for _, b := range iter.readStringSlowPath() {
|
|
|
|
if 'A' <= b && b <= 'Z' {
|
|
|
|
b += 'a' - 'A'
|
2017-10-31 16:38:41 +02:00
|
|
|
}
|
2018-02-14 05:33:17 +02:00
|
|
|
hash ^= int64(b)
|
|
|
|
hash *= 0x1000193
|
2017-05-24 07:16:09 +02:00
|
|
|
}
|
2018-02-14 05:33:17 +02:00
|
|
|
c = iter.nextToken()
|
|
|
|
if c != ':' {
|
|
|
|
iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c}))
|
|
|
|
return 0
|
2017-02-08 07:46:28 +02:00
|
|
|
}
|
2018-02-14 05:33:17 +02:00
|
|
|
return hash
|
|
|
|
}
|
|
|
|
if b == '"' {
|
|
|
|
iter.head = i + 1
|
|
|
|
c = iter.nextToken()
|
|
|
|
if c != ':' {
|
|
|
|
iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c}))
|
|
|
|
return 0
|
2017-10-31 16:38:41 +02:00
|
|
|
}
|
2018-02-14 05:33:17 +02:00
|
|
|
return hash
|
2017-02-08 07:46:28 +02:00
|
|
|
}
|
2018-02-14 05:33:17 +02:00
|
|
|
if 'A' <= b && b <= 'Z' {
|
|
|
|
b += 'a' - 'A'
|
2017-02-08 07:46:28 +02:00
|
|
|
}
|
2018-02-14 05:33:17 +02:00
|
|
|
hash ^= int64(b)
|
|
|
|
hash *= 0x1000193
|
|
|
|
}
|
|
|
|
if !iter.loadMore() {
|
|
|
|
iter.ReportError("readFieldHash", `incomplete field name`)
|
|
|
|
return 0
|
2017-02-08 07:46:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-14 05:33:17 +02:00
|
|
|
func calcHash(str string) int64 {
|
2017-02-09 07:35:58 +02:00
|
|
|
hash := int64(0x811c9dc5)
|
2017-02-08 07:46:28 +02:00
|
|
|
for _, b := range str {
|
2017-05-24 07:16:09 +02:00
|
|
|
hash ^= int64(unicode.ToLower(b))
|
2017-02-08 07:46:28 +02:00
|
|
|
hash *= 0x1000193
|
|
|
|
}
|
2018-02-14 05:33:17 +02:00
|
|
|
return int64(hash)
|
2017-02-08 07:46:28 +02:00
|
|
|
}
|
|
|
|
|
2017-07-09 10:09:23 +02:00
|
|
|
// ReadObjectCB read object with callback, the key is ascii only and field name not copied
|
2017-01-20 06:56:49 +02:00
|
|
|
func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
|
|
|
|
c := iter.nextToken()
|
2017-10-31 16:38:41 +02:00
|
|
|
var field string
|
2017-01-20 06:56:49 +02:00
|
|
|
if c == '{' {
|
|
|
|
c = iter.nextToken()
|
|
|
|
if c == '"' {
|
|
|
|
iter.unreadByte()
|
2018-02-14 04:31:55 +02:00
|
|
|
field = iter.ReadString()
|
|
|
|
c = iter.nextToken()
|
|
|
|
if c != ':' {
|
|
|
|
iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
|
2017-10-31 16:38:41 +02:00
|
|
|
}
|
|
|
|
if !callback(iter, field) {
|
2017-01-20 06:56:49 +02:00
|
|
|
return false
|
|
|
|
}
|
2017-07-18 03:45:25 +02:00
|
|
|
c = iter.nextToken()
|
|
|
|
for c == ',' {
|
2018-02-14 04:31:55 +02:00
|
|
|
field = iter.ReadString()
|
|
|
|
c = iter.nextToken()
|
|
|
|
if c != ':' {
|
|
|
|
iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
|
2017-10-31 16:38:41 +02:00
|
|
|
}
|
|
|
|
if !callback(iter, field) {
|
2017-01-20 06:56:49 +02:00
|
|
|
return false
|
|
|
|
}
|
2017-07-18 03:45:25 +02:00
|
|
|
c = iter.nextToken()
|
|
|
|
}
|
|
|
|
if c != '}' {
|
|
|
|
iter.ReportError("ReadObjectCB", `object not ended with }`)
|
|
|
|
return false
|
2017-01-20 06:56:49 +02:00
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if c == '}' {
|
|
|
|
return true
|
|
|
|
}
|
2017-10-10 02:57:02 +02:00
|
|
|
iter.ReportError("ReadObjectCB", `expect " after }, but found `+string([]byte{c}))
|
2017-01-20 06:56:49 +02:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
if c == 'n' {
|
2017-07-10 09:23:35 +02:00
|
|
|
iter.skipThreeBytes('u', 'l', 'l')
|
2017-01-20 06:56:49 +02:00
|
|
|
return true // null
|
|
|
|
}
|
2017-10-10 02:57:02 +02:00
|
|
|
iter.ReportError("ReadObjectCB", `expect { or n, but found `+string([]byte{c}))
|
2017-01-20 06:56:49 +02:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2017-07-09 10:09:23 +02:00
|
|
|
// ReadMapCB read map with callback, the key can be any string
|
2017-06-12 04:13:13 +02:00
|
|
|
func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool {
|
|
|
|
c := iter.nextToken()
|
|
|
|
if c == '{' {
|
|
|
|
c = iter.nextToken()
|
|
|
|
if c == '"' {
|
|
|
|
iter.unreadByte()
|
|
|
|
field := iter.ReadString()
|
|
|
|
if iter.nextToken() != ':' {
|
2017-10-10 02:57:02 +02:00
|
|
|
iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
|
2017-06-12 04:13:13 +02:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
if !callback(iter, field) {
|
|
|
|
return false
|
|
|
|
}
|
2017-07-18 03:45:25 +02:00
|
|
|
c = iter.nextToken()
|
|
|
|
for c == ',' {
|
2017-06-12 04:13:13 +02:00
|
|
|
field = iter.ReadString()
|
|
|
|
if iter.nextToken() != ':' {
|
2017-10-10 02:57:02 +02:00
|
|
|
iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
|
2017-06-12 04:13:13 +02:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
if !callback(iter, field) {
|
|
|
|
return false
|
|
|
|
}
|
2017-07-18 03:45:25 +02:00
|
|
|
c = iter.nextToken()
|
|
|
|
}
|
|
|
|
if c != '}' {
|
|
|
|
iter.ReportError("ReadMapCB", `object not ended with }`)
|
|
|
|
return false
|
2017-06-12 04:13:13 +02:00
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if c == '}' {
|
|
|
|
return true
|
|
|
|
}
|
2017-10-10 02:57:02 +02:00
|
|
|
iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c}))
|
2017-06-12 04:13:13 +02:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
if c == 'n' {
|
2017-07-10 09:23:35 +02:00
|
|
|
iter.skipThreeBytes('u', 'l', 'l')
|
2017-06-12 04:13:13 +02:00
|
|
|
return true // null
|
|
|
|
}
|
2017-10-10 02:57:02 +02:00
|
|
|
iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c}))
|
2017-06-12 04:13:13 +02:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2017-01-05 07:53:38 +02:00
|
|
|
func (iter *Iterator) readObjectStart() bool {
|
|
|
|
c := iter.nextToken()
|
|
|
|
if c == '{' {
|
|
|
|
c = iter.nextToken()
|
|
|
|
if c == '}' {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
iter.unreadByte()
|
|
|
|
return true
|
2017-05-23 12:46:11 +02:00
|
|
|
} else if c == 'n' {
|
2017-07-10 09:23:35 +02:00
|
|
|
iter.skipThreeBytes('u', 'l', 'l')
|
2017-05-23 12:46:11 +02:00
|
|
|
return false
|
2017-01-05 07:53:38 +02:00
|
|
|
}
|
2017-10-10 02:57:02 +02:00
|
|
|
iter.ReportError("readObjectStart", "expect { or n, but found "+string([]byte{c}))
|
2017-01-05 07:53:38 +02:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2017-01-20 06:40:52 +02:00
|
|
|
func (iter *Iterator) readObjectFieldAsBytes() (ret []byte) {
|
2017-01-16 17:57:09 +02:00
|
|
|
str := iter.ReadStringAsSlice()
|
2017-01-05 07:53:38 +02:00
|
|
|
if iter.skipWhitespacesWithoutLoadMore() {
|
2017-01-20 06:40:52 +02:00
|
|
|
if ret == nil {
|
|
|
|
ret = make([]byte, len(str))
|
|
|
|
copy(ret, str)
|
2017-01-05 07:53:38 +02:00
|
|
|
}
|
|
|
|
if !iter.loadMore() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if iter.buf[iter.head] != ':' {
|
2017-10-10 02:57:02 +02:00
|
|
|
iter.ReportError("readObjectFieldAsBytes", "expect : after object field, but found "+string([]byte{iter.buf[iter.head]}))
|
2017-01-05 07:53:38 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
iter.head++
|
|
|
|
if iter.skipWhitespacesWithoutLoadMore() {
|
2017-01-20 06:40:52 +02:00
|
|
|
if ret == nil {
|
|
|
|
ret = make([]byte, len(str))
|
|
|
|
copy(ret, str)
|
2017-01-05 07:53:38 +02:00
|
|
|
}
|
|
|
|
if !iter.loadMore() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2017-01-20 06:40:52 +02:00
|
|
|
if ret == nil {
|
|
|
|
return str
|
2017-01-05 07:53:38 +02:00
|
|
|
}
|
|
|
|
return ret
|
2017-01-05 15:23:08 +02:00
|
|
|
}
|