blob: 58ee89c849e7bbff01577ce657502f34b8125c85 [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001package jsoniter
2
3import (
4 "fmt"
5 "strings"
6)
7
8// ReadObject read one field from object.
9// If object ended, returns empty string.
10// Otherwise, returns the field name.
11func (iter *Iterator) ReadObject() (ret string) {
12 c := iter.nextToken()
13 switch c {
14 case 'n':
15 iter.skipThreeBytes('u', 'l', 'l')
16 return "" // null
17 case '{':
18 c = iter.nextToken()
19 if c == '"' {
20 iter.unreadByte()
21 field := iter.ReadString()
22 c = iter.nextToken()
23 if c != ':' {
24 iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
25 }
26 return field
27 }
28 if c == '}' {
29 return "" // end of object
30 }
31 iter.ReportError("ReadObject", `expect " after {, but found `+string([]byte{c}))
32 return
33 case ',':
34 field := iter.ReadString()
35 c = iter.nextToken()
36 if c != ':' {
37 iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
38 }
39 return field
40 case '}':
41 return "" // end of object
42 default:
43 iter.ReportError("ReadObject", fmt.Sprintf(`expect { or , or } or n, but found %s`, string([]byte{c})))
44 return
45 }
46}
47
48// CaseInsensitive
49func (iter *Iterator) readFieldHash() int64 {
50 hash := int64(0x811c9dc5)
51 c := iter.nextToken()
52 if c != '"' {
53 iter.ReportError("readFieldHash", `expect ", but found `+string([]byte{c}))
54 return 0
55 }
56 for {
57 for i := iter.head; i < iter.tail; i++ {
58 // require ascii string and no escape
59 b := iter.buf[i]
60 if b == '\\' {
61 iter.head = i
62 for _, b := range iter.readStringSlowPath() {
63 if 'A' <= b && b <= 'Z' && !iter.cfg.caseSensitive {
64 b += 'a' - 'A'
65 }
66 hash ^= int64(b)
67 hash *= 0x1000193
68 }
69 c = iter.nextToken()
70 if c != ':' {
71 iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c}))
72 return 0
73 }
74 return hash
75 }
76 if b == '"' {
77 iter.head = i + 1
78 c = iter.nextToken()
79 if c != ':' {
80 iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c}))
81 return 0
82 }
83 return hash
84 }
85 if 'A' <= b && b <= 'Z' && !iter.cfg.caseSensitive {
86 b += 'a' - 'A'
87 }
88 hash ^= int64(b)
89 hash *= 0x1000193
90 }
91 if !iter.loadMore() {
92 iter.ReportError("readFieldHash", `incomplete field name`)
93 return 0
94 }
95 }
96}
97
98func calcHash(str string, caseSensitive bool) int64 {
99 if !caseSensitive {
100 str = strings.ToLower(str)
101 }
102 hash := int64(0x811c9dc5)
103 for _, b := range []byte(str) {
104 hash ^= int64(b)
105 hash *= 0x1000193
106 }
107 return int64(hash)
108}
109
110// ReadObjectCB read object with callback, the key is ascii only and field name not copied
111func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
112 c := iter.nextToken()
113 var field string
114 if c == '{' {
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000115 if !iter.incrementDepth() {
116 return false
117 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700118 c = iter.nextToken()
119 if c == '"' {
120 iter.unreadByte()
121 field = iter.ReadString()
122 c = iter.nextToken()
123 if c != ':' {
124 iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
125 }
126 if !callback(iter, field) {
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000127 iter.decrementDepth()
Zack Williamse940c7a2019-08-21 14:25:39 -0700128 return false
129 }
130 c = iter.nextToken()
131 for c == ',' {
132 field = iter.ReadString()
133 c = iter.nextToken()
134 if c != ':' {
135 iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
136 }
137 if !callback(iter, field) {
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000138 iter.decrementDepth()
Zack Williamse940c7a2019-08-21 14:25:39 -0700139 return false
140 }
141 c = iter.nextToken()
142 }
143 if c != '}' {
144 iter.ReportError("ReadObjectCB", `object not ended with }`)
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000145 iter.decrementDepth()
Zack Williamse940c7a2019-08-21 14:25:39 -0700146 return false
147 }
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000148 return iter.decrementDepth()
Zack Williamse940c7a2019-08-21 14:25:39 -0700149 }
150 if c == '}' {
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000151 return iter.decrementDepth()
Zack Williamse940c7a2019-08-21 14:25:39 -0700152 }
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000153 iter.ReportError("ReadObjectCB", `expect " after {, but found `+string([]byte{c}))
154 iter.decrementDepth()
Zack Williamse940c7a2019-08-21 14:25:39 -0700155 return false
156 }
157 if c == 'n' {
158 iter.skipThreeBytes('u', 'l', 'l')
159 return true // null
160 }
161 iter.ReportError("ReadObjectCB", `expect { or n, but found `+string([]byte{c}))
162 return false
163}
164
165// ReadMapCB read map with callback, the key can be any string
166func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool {
167 c := iter.nextToken()
168 if c == '{' {
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000169 if !iter.incrementDepth() {
170 return false
171 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700172 c = iter.nextToken()
173 if c == '"' {
174 iter.unreadByte()
175 field := iter.ReadString()
176 if iter.nextToken() != ':' {
177 iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000178 iter.decrementDepth()
Zack Williamse940c7a2019-08-21 14:25:39 -0700179 return false
180 }
181 if !callback(iter, field) {
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000182 iter.decrementDepth()
Zack Williamse940c7a2019-08-21 14:25:39 -0700183 return false
184 }
185 c = iter.nextToken()
186 for c == ',' {
187 field = iter.ReadString()
188 if iter.nextToken() != ':' {
189 iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000190 iter.decrementDepth()
Zack Williamse940c7a2019-08-21 14:25:39 -0700191 return false
192 }
193 if !callback(iter, field) {
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000194 iter.decrementDepth()
Zack Williamse940c7a2019-08-21 14:25:39 -0700195 return false
196 }
197 c = iter.nextToken()
198 }
199 if c != '}' {
200 iter.ReportError("ReadMapCB", `object not ended with }`)
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000201 iter.decrementDepth()
Zack Williamse940c7a2019-08-21 14:25:39 -0700202 return false
203 }
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000204 return iter.decrementDepth()
Zack Williamse940c7a2019-08-21 14:25:39 -0700205 }
206 if c == '}' {
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000207 return iter.decrementDepth()
Zack Williamse940c7a2019-08-21 14:25:39 -0700208 }
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000209 iter.ReportError("ReadMapCB", `expect " after {, but found `+string([]byte{c}))
210 iter.decrementDepth()
Zack Williamse940c7a2019-08-21 14:25:39 -0700211 return false
212 }
213 if c == 'n' {
214 iter.skipThreeBytes('u', 'l', 'l')
215 return true // null
216 }
217 iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c}))
218 return false
219}
220
221func (iter *Iterator) readObjectStart() bool {
222 c := iter.nextToken()
223 if c == '{' {
224 c = iter.nextToken()
225 if c == '}' {
226 return false
227 }
228 iter.unreadByte()
229 return true
230 } else if c == 'n' {
231 iter.skipThreeBytes('u', 'l', 'l')
232 return false
233 }
234 iter.ReportError("readObjectStart", "expect { or n, but found "+string([]byte{c}))
235 return false
236}
237
238func (iter *Iterator) readObjectFieldAsBytes() (ret []byte) {
239 str := iter.ReadStringAsSlice()
240 if iter.skipWhitespacesWithoutLoadMore() {
241 if ret == nil {
242 ret = make([]byte, len(str))
243 copy(ret, str)
244 }
245 if !iter.loadMore() {
246 return
247 }
248 }
249 if iter.buf[iter.head] != ':' {
250 iter.ReportError("readObjectFieldAsBytes", "expect : after object field, but found "+string([]byte{iter.buf[iter.head]}))
251 return
252 }
253 iter.head++
254 if iter.skipWhitespacesWithoutLoadMore() {
255 if ret == nil {
256 ret = make([]byte, len(str))
257 copy(ret, str)
258 }
259 if !iter.loadMore() {
260 return
261 }
262 }
263 if ret == nil {
264 return str
265 }
266 return ret
267}