blob: 1c575767130dc4771cd562b9a2a05f47ea6ccee8 [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 == '{' {
115 c = iter.nextToken()
116 if c == '"' {
117 iter.unreadByte()
118 field = iter.ReadString()
119 c = iter.nextToken()
120 if c != ':' {
121 iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
122 }
123 if !callback(iter, field) {
124 return false
125 }
126 c = iter.nextToken()
127 for c == ',' {
128 field = iter.ReadString()
129 c = iter.nextToken()
130 if c != ':' {
131 iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
132 }
133 if !callback(iter, field) {
134 return false
135 }
136 c = iter.nextToken()
137 }
138 if c != '}' {
139 iter.ReportError("ReadObjectCB", `object not ended with }`)
140 return false
141 }
142 return true
143 }
144 if c == '}' {
145 return true
146 }
147 iter.ReportError("ReadObjectCB", `expect " after }, but found `+string([]byte{c}))
148 return false
149 }
150 if c == 'n' {
151 iter.skipThreeBytes('u', 'l', 'l')
152 return true // null
153 }
154 iter.ReportError("ReadObjectCB", `expect { or n, but found `+string([]byte{c}))
155 return false
156}
157
158// ReadMapCB read map with callback, the key can be any string
159func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool {
160 c := iter.nextToken()
161 if c == '{' {
162 c = iter.nextToken()
163 if c == '"' {
164 iter.unreadByte()
165 field := iter.ReadString()
166 if iter.nextToken() != ':' {
167 iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
168 return false
169 }
170 if !callback(iter, field) {
171 return false
172 }
173 c = iter.nextToken()
174 for c == ',' {
175 field = iter.ReadString()
176 if iter.nextToken() != ':' {
177 iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
178 return false
179 }
180 if !callback(iter, field) {
181 return false
182 }
183 c = iter.nextToken()
184 }
185 if c != '}' {
186 iter.ReportError("ReadMapCB", `object not ended with }`)
187 return false
188 }
189 return true
190 }
191 if c == '}' {
192 return true
193 }
194 iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c}))
195 return false
196 }
197 if c == 'n' {
198 iter.skipThreeBytes('u', 'l', 'l')
199 return true // null
200 }
201 iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c}))
202 return false
203}
204
205func (iter *Iterator) readObjectStart() bool {
206 c := iter.nextToken()
207 if c == '{' {
208 c = iter.nextToken()
209 if c == '}' {
210 return false
211 }
212 iter.unreadByte()
213 return true
214 } else if c == 'n' {
215 iter.skipThreeBytes('u', 'l', 'l')
216 return false
217 }
218 iter.ReportError("readObjectStart", "expect { or n, but found "+string([]byte{c}))
219 return false
220}
221
222func (iter *Iterator) readObjectFieldAsBytes() (ret []byte) {
223 str := iter.ReadStringAsSlice()
224 if iter.skipWhitespacesWithoutLoadMore() {
225 if ret == nil {
226 ret = make([]byte, len(str))
227 copy(ret, str)
228 }
229 if !iter.loadMore() {
230 return
231 }
232 }
233 if iter.buf[iter.head] != ':' {
234 iter.ReportError("readObjectFieldAsBytes", "expect : after object field, but found "+string([]byte{iter.buf[iter.head]}))
235 return
236 }
237 iter.head++
238 if iter.skipWhitespacesWithoutLoadMore() {
239 if ret == nil {
240 ret = make([]byte, len(str))
241 copy(ret, str)
242 }
243 if !iter.loadMore() {
244 return
245 }
246 }
247 if ret == nil {
248 return str
249 }
250 return ret
251}