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}