decode.gno
8.21 Kb ยท 370 lines
1// ref: https://github.com/spyzhov/ajson/blob/master/decode.go
2
3package json
4
5import (
6 "errors"
7 "io"
8
9 "gno.land/p/demo/ufmt"
10)
11
12// This limits the max nesting depth to prevent stack overflow.
13// This is permitted by https://tools.ietf.org/html/rfc7159#section-9
14const maxNestingDepth = 10000
15
16// Unmarshal parses the JSON-encoded data and returns a Node.
17// The data must be a valid JSON-encoded value.
18//
19// Usage:
20//
21// node, err := json.Unmarshal([]byte(`{"key": "value"}`))
22// if err != nil {
23// ufmt.Println(err)
24// }
25// println(node) // {"key": "value"}
26func Unmarshal(data []byte) (*Node, error) {
27 buf := newBuffer(data)
28
29 var (
30 state States
31 key *string
32 current *Node
33 nesting int
34 useKey = func() **string {
35 tmp := cptrs(key)
36 key = nil
37 return &tmp
38 }
39 err error
40 )
41
42 if _, err = buf.first(); err != nil {
43 return nil, io.EOF
44 }
45
46 for {
47 state = buf.getState()
48 if state == __ {
49 return nil, unexpectedTokenError(buf.data, buf.index)
50 }
51
52 // region state machine
53 if state >= GO {
54 switch buf.state {
55 case ST: // string
56 if current != nil && current.IsObject() && key == nil {
57 // key detected
58 if key, err = getString(buf); err != nil {
59 return nil, err
60 }
61
62 buf.state = CO
63 } else {
64 current, nesting, err = createNestedNode(current, buf, String, nesting, useKey())
65 if err != nil {
66 return nil, err
67 }
68
69 err = buf.string(doubleQuote, false)
70 if err != nil {
71 return nil, err
72 }
73
74 current, nesting = updateNode(current, buf, nesting, true)
75 buf.state = OK
76 }
77
78 case MI, ZE, IN: // number
79 current, err = processNumericNode(current, buf, useKey())
80 if err != nil {
81 return nil, err
82 }
83
84 case T1, F1: // boolean
85 literal := falseLiteral
86 if buf.state == T1 {
87 literal = trueLiteral
88 }
89
90 current, nesting, err = processLiteralNode(current, buf, Boolean, literal, useKey(), nesting)
91 if err != nil {
92 return nil, err
93 }
94
95 case N1: // null
96 current, nesting, err = processLiteralNode(current, buf, Null, nullLiteral, useKey(), nesting)
97 if err != nil {
98 return nil, err
99 }
100 }
101 } else {
102 // region action
103 switch state {
104 case ec, cc: // <empty> }
105 if key != nil {
106 return nil, unexpectedTokenError(buf.data, buf.index)
107 }
108
109 current, nesting, err = updateNodeAndSetBufferState(current, buf, nesting, Object)
110 if err != nil {
111 return nil, err
112 }
113
114 case bc: // ]
115 current, nesting, err = updateNodeAndSetBufferState(current, buf, nesting, Array)
116 if err != nil {
117 return nil, err
118 }
119
120 case co, bo: // { [
121 valTyp, bState := Object, OB
122 if state == bo {
123 valTyp, bState = Array, AR
124 }
125
126 current, nesting, err = createNestedNode(current, buf, valTyp, nesting, useKey())
127 if err != nil {
128 return nil, err
129 }
130
131 buf.state = bState
132
133 case cm: // ,
134 if current == nil {
135 return nil, unexpectedTokenError(buf.data, buf.index)
136 }
137
138 if !current.isContainer() {
139 return nil, unexpectedTokenError(buf.data, buf.index)
140 }
141
142 if current.IsObject() {
143 buf.state = KE // key expected
144 } else {
145 buf.state = VA // value expected
146 }
147
148 case cl: // :
149 if current == nil || !current.IsObject() || key == nil {
150 return nil, unexpectedTokenError(buf.data, buf.index)
151 }
152
153 buf.state = VA
154
155 default:
156 return nil, unexpectedTokenError(buf.data, buf.index)
157 }
158 }
159
160 if buf.step() != nil {
161 break
162 }
163
164 if _, err = buf.first(); err != nil {
165 err = nil
166 break
167 }
168 }
169
170 if current == nil || buf.state != OK {
171 return nil, io.EOF
172 }
173
174 root := current.root()
175 if !root.ready() {
176 return nil, io.EOF
177 }
178
179 return root, err
180}
181
182// UnmarshalSafe parses the JSON-encoded data and returns a Node.
183func UnmarshalSafe(data []byte) (*Node, error) {
184 var safe []byte
185 safe = append(safe, data...)
186 return Unmarshal(safe)
187}
188
189// processNumericNode creates a new node, processes a numeric value,
190// sets the node's borders, and moves to the previous node.
191func processNumericNode(current *Node, buf *buffer, key **string) (*Node, error) {
192 var err error
193 current, err = createNode(current, buf, Number, key)
194 if err != nil {
195 return nil, err
196 }
197
198 if err = buf.numeric(false); err != nil {
199 return nil, err
200 }
201
202 current.borders[1] = buf.index
203 if current.prev != nil {
204 current = current.prev
205 }
206
207 buf.index -= 1
208 buf.state = OK
209
210 return current, nil
211}
212
213// processLiteralNode creates a new node, processes a literal value,
214// sets the node's borders, and moves to the previous node.
215func processLiteralNode(
216 current *Node,
217 buf *buffer,
218 literalType ValueType,
219 literalValue []byte,
220 useKey **string,
221 nesting int,
222) (*Node, int, error) {
223 var err error
224 current, nesting, err = createLiteralNode(current, buf, literalType, literalValue, useKey, nesting)
225 if err != nil {
226 return nil, nesting, err
227 }
228 return current, nesting, nil
229}
230
231// isValidContainerType checks if the current node is a valid container (object or array).
232// The container must satisfy the following conditions:
233// 1. The current node must not be nil.
234// 2. The current node must be an object or array.
235// 3. The current node must not be ready.
236func isValidContainerType(current *Node, nodeType ValueType) bool {
237 switch nodeType {
238 case Object:
239 return current != nil && current.IsObject() && !current.ready()
240 case Array:
241 return current != nil && current.IsArray() && !current.ready()
242 default:
243 return false
244 }
245}
246
247// getString extracts a string from the buffer and advances the buffer index past the string.
248func getString(b *buffer) (*string, error) {
249 start := b.index
250 if err := b.string(doubleQuote, false); err != nil {
251 return nil, err
252 }
253
254 value, ok := Unquote(b.data[start:b.index+1], doubleQuote)
255 if !ok {
256 return nil, unexpectedTokenError(b.data, start)
257 }
258
259 return &value, nil
260}
261
262// createNode creates a new node and sets the key if it is not nil.
263func createNode(
264 current *Node,
265 buf *buffer,
266 nodeType ValueType,
267 key **string,
268) (*Node, error) {
269 var err error
270 current, err = NewNode(current, buf, nodeType, key)
271 if err != nil {
272 return nil, err
273 }
274
275 return current, nil
276}
277
278// createNestedNode creates a new nested node (array or object) and sets the key if it is not nil.
279func createNestedNode(
280 current *Node,
281 buf *buffer,
282 nodeType ValueType,
283 nesting int,
284 key **string,
285) (*Node, int, error) {
286 var err error
287 if nesting, err = checkNestingDepth(nesting); err != nil {
288 return nil, nesting, err
289 }
290
291 if current, err = createNode(current, buf, nodeType, key); err != nil {
292 return nil, nesting, err
293 }
294
295 return current, nesting, nil
296}
297
298// createLiteralNode creates a new literal node and sets the key if it is not nil.
299// The literal is a byte slice that represents a boolean or null value.
300func createLiteralNode(
301 current *Node,
302 buf *buffer,
303 literalType ValueType,
304 literal []byte,
305 useKey **string,
306 nesting int,
307) (*Node, int, error) {
308 var err error
309 if current, err = createNode(current, buf, literalType, useKey); err != nil {
310 return nil, 0, err
311 }
312
313 if err = buf.word(literal); err != nil {
314 return nil, 0, err
315 }
316
317 current, nesting = updateNode(current, buf, nesting, false)
318 buf.state = OK
319
320 return current, nesting, nil
321}
322
323// updateNode updates the current node and returns the previous node.
324func updateNode(
325 current *Node, buf *buffer, nesting int, decreaseLevel bool,
326) (*Node, int) {
327 current.borders[1] = buf.index + 1
328
329 prev := current.prev
330 if prev == nil {
331 return current, nesting
332 }
333
334 current = prev
335 if decreaseLevel {
336 nesting--
337 }
338
339 return current, nesting
340}
341
342// updateNodeAndSetBufferState updates the current node and sets the buffer state to OK.
343func updateNodeAndSetBufferState(
344 current *Node,
345 buf *buffer,
346 nesting int,
347 typ ValueType,
348) (*Node, int, error) {
349 if !isValidContainerType(current, typ) {
350 return nil, nesting, unexpectedTokenError(buf.data, buf.index)
351 }
352
353 current, nesting = updateNode(current, buf, nesting, true)
354 buf.state = OK
355
356 return current, nesting, nil
357}
358
359// checkNestingDepth checks if the nesting depth is within the maximum allowed depth.
360func checkNestingDepth(nesting int) (int, error) {
361 if nesting >= maxNestingDepth {
362 return nesting, errors.New("maximum nesting depth exceeded")
363 }
364
365 return nesting + 1, nil
366}
367
368func unexpectedTokenError(data []byte, index int) error {
369 return ufmt.Errorf("unexpected token at index %d. data %b", index, data)
370}