github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/json/decode.gno (about)

     1  // ref: https://github.com/spyzhov/ajson/blob/master/decode.go
     2  
     3  package json
     4  
     5  import (
     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
    14  const 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"}
    26  func 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.
   183  func 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.
   191  func 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.
   215  func 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.
   236  func 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.
   248  func 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.
   263  func 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.
   279  func 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.
   300  func 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.
   324  func 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.
   343  func 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.
   360  func 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  
   368  func unexpectedTokenError(data []byte, index int) error {
   369  	return ufmt.Errorf("unexpected token at index %d. data %b", index, data)
   370  }