xref: /aosp_15_r20/external/jsmn/jsmn.h (revision 420d848fb01a502d3186bd0f49f4e0beb321f5cd)
1*420d848fSAndroid Build Coastguard Worker /*
2*420d848fSAndroid Build Coastguard Worker  * MIT License
3*420d848fSAndroid Build Coastguard Worker  *
4*420d848fSAndroid Build Coastguard Worker  * Copyright (c) 2010 Serge Zaitsev
5*420d848fSAndroid Build Coastguard Worker  *
6*420d848fSAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a copy
7*420d848fSAndroid Build Coastguard Worker  * of this software and associated documentation files (the "Software"), to deal
8*420d848fSAndroid Build Coastguard Worker  * in the Software without restriction, including without limitation the rights
9*420d848fSAndroid Build Coastguard Worker  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10*420d848fSAndroid Build Coastguard Worker  * copies of the Software, and to permit persons to whom the Software is
11*420d848fSAndroid Build Coastguard Worker  * furnished to do so, subject to the following conditions:
12*420d848fSAndroid Build Coastguard Worker  *
13*420d848fSAndroid Build Coastguard Worker  * The above copyright notice and this permission notice shall be included in
14*420d848fSAndroid Build Coastguard Worker  * all copies or substantial portions of the Software.
15*420d848fSAndroid Build Coastguard Worker  *
16*420d848fSAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*420d848fSAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*420d848fSAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19*420d848fSAndroid Build Coastguard Worker  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*420d848fSAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21*420d848fSAndroid Build Coastguard Worker  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22*420d848fSAndroid Build Coastguard Worker  * SOFTWARE.
23*420d848fSAndroid Build Coastguard Worker  */
24*420d848fSAndroid Build Coastguard Worker // ANDROID CHANGE: Default to header only.
25*420d848fSAndroid Build Coastguard Worker #ifndef JSMN_IMPL
26*420d848fSAndroid Build Coastguard Worker #define JSMN_HEADER
27*420d848fSAndroid Build Coastguard Worker #endif
28*420d848fSAndroid Build Coastguard Worker // END ANDROID CHANGE
29*420d848fSAndroid Build Coastguard Worker 
30*420d848fSAndroid Build Coastguard Worker #ifndef JSMN_H
31*420d848fSAndroid Build Coastguard Worker #define JSMN_H
32*420d848fSAndroid Build Coastguard Worker 
33*420d848fSAndroid Build Coastguard Worker #include <stddef.h>
34*420d848fSAndroid Build Coastguard Worker 
35*420d848fSAndroid Build Coastguard Worker #ifdef __cplusplus
36*420d848fSAndroid Build Coastguard Worker extern "C" {
37*420d848fSAndroid Build Coastguard Worker #endif
38*420d848fSAndroid Build Coastguard Worker 
39*420d848fSAndroid Build Coastguard Worker #ifdef JSMN_STATIC
40*420d848fSAndroid Build Coastguard Worker #define JSMN_API static
41*420d848fSAndroid Build Coastguard Worker #else
42*420d848fSAndroid Build Coastguard Worker #define JSMN_API extern
43*420d848fSAndroid Build Coastguard Worker #endif
44*420d848fSAndroid Build Coastguard Worker 
45*420d848fSAndroid Build Coastguard Worker /**
46*420d848fSAndroid Build Coastguard Worker  * JSON type identifier. Basic types are:
47*420d848fSAndroid Build Coastguard Worker  * 	o Object
48*420d848fSAndroid Build Coastguard Worker  * 	o Array
49*420d848fSAndroid Build Coastguard Worker  * 	o String
50*420d848fSAndroid Build Coastguard Worker  * 	o Other primitive: number, boolean (true/false) or null
51*420d848fSAndroid Build Coastguard Worker  */
52*420d848fSAndroid Build Coastguard Worker typedef enum {
53*420d848fSAndroid Build Coastguard Worker   JSMN_UNDEFINED = 0,
54*420d848fSAndroid Build Coastguard Worker   JSMN_OBJECT = 1,
55*420d848fSAndroid Build Coastguard Worker   JSMN_ARRAY = 2,
56*420d848fSAndroid Build Coastguard Worker   JSMN_STRING = 3,
57*420d848fSAndroid Build Coastguard Worker   JSMN_PRIMITIVE = 4
58*420d848fSAndroid Build Coastguard Worker } jsmntype_t;
59*420d848fSAndroid Build Coastguard Worker 
60*420d848fSAndroid Build Coastguard Worker enum jsmnerr {
61*420d848fSAndroid Build Coastguard Worker   /* Not enough tokens were provided */
62*420d848fSAndroid Build Coastguard Worker   JSMN_ERROR_NOMEM = -1,
63*420d848fSAndroid Build Coastguard Worker   /* Invalid character inside JSON string */
64*420d848fSAndroid Build Coastguard Worker   JSMN_ERROR_INVAL = -2,
65*420d848fSAndroid Build Coastguard Worker   /* The string is not a full JSON packet, more bytes expected */
66*420d848fSAndroid Build Coastguard Worker   JSMN_ERROR_PART = -3
67*420d848fSAndroid Build Coastguard Worker };
68*420d848fSAndroid Build Coastguard Worker 
69*420d848fSAndroid Build Coastguard Worker /**
70*420d848fSAndroid Build Coastguard Worker  * JSON token description.
71*420d848fSAndroid Build Coastguard Worker  * type		type (object, array, string etc.)
72*420d848fSAndroid Build Coastguard Worker  * start	start position in JSON data string
73*420d848fSAndroid Build Coastguard Worker  * end		end position in JSON data string
74*420d848fSAndroid Build Coastguard Worker  */
75*420d848fSAndroid Build Coastguard Worker typedef struct {
76*420d848fSAndroid Build Coastguard Worker   jsmntype_t type;
77*420d848fSAndroid Build Coastguard Worker   int start;
78*420d848fSAndroid Build Coastguard Worker   int end;
79*420d848fSAndroid Build Coastguard Worker   int size;
80*420d848fSAndroid Build Coastguard Worker #ifdef JSMN_PARENT_LINKS
81*420d848fSAndroid Build Coastguard Worker   int parent;
82*420d848fSAndroid Build Coastguard Worker #endif
83*420d848fSAndroid Build Coastguard Worker } jsmntok_t;
84*420d848fSAndroid Build Coastguard Worker 
85*420d848fSAndroid Build Coastguard Worker /**
86*420d848fSAndroid Build Coastguard Worker  * JSON parser. Contains an array of token blocks available. Also stores
87*420d848fSAndroid Build Coastguard Worker  * the string being parsed now and current position in that string.
88*420d848fSAndroid Build Coastguard Worker  */
89*420d848fSAndroid Build Coastguard Worker typedef struct {
90*420d848fSAndroid Build Coastguard Worker   unsigned int pos;     /* offset in the JSON string */
91*420d848fSAndroid Build Coastguard Worker   unsigned int toknext; /* next token to allocate */
92*420d848fSAndroid Build Coastguard Worker   int toksuper;         /* superior token node, e.g. parent object or array */
93*420d848fSAndroid Build Coastguard Worker } jsmn_parser;
94*420d848fSAndroid Build Coastguard Worker 
95*420d848fSAndroid Build Coastguard Worker /**
96*420d848fSAndroid Build Coastguard Worker  * Create JSON parser over an array of tokens
97*420d848fSAndroid Build Coastguard Worker  */
98*420d848fSAndroid Build Coastguard Worker JSMN_API void jsmn_init(jsmn_parser *parser);
99*420d848fSAndroid Build Coastguard Worker 
100*420d848fSAndroid Build Coastguard Worker /**
101*420d848fSAndroid Build Coastguard Worker  * Run JSON parser. It parses a JSON data string into and array of tokens, each
102*420d848fSAndroid Build Coastguard Worker  * describing
103*420d848fSAndroid Build Coastguard Worker  * a single JSON object.
104*420d848fSAndroid Build Coastguard Worker  */
105*420d848fSAndroid Build Coastguard Worker JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
106*420d848fSAndroid Build Coastguard Worker                         jsmntok_t *tokens, const unsigned int num_tokens);
107*420d848fSAndroid Build Coastguard Worker 
108*420d848fSAndroid Build Coastguard Worker #ifndef JSMN_HEADER
109*420d848fSAndroid Build Coastguard Worker /**
110*420d848fSAndroid Build Coastguard Worker  * Allocates a fresh unused token from the token pool.
111*420d848fSAndroid Build Coastguard Worker  */
jsmn_alloc_token(jsmn_parser * parser,jsmntok_t * tokens,const size_t num_tokens)112*420d848fSAndroid Build Coastguard Worker static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens,
113*420d848fSAndroid Build Coastguard Worker                                    const size_t num_tokens) {
114*420d848fSAndroid Build Coastguard Worker   jsmntok_t *tok;
115*420d848fSAndroid Build Coastguard Worker   if (parser->toknext >= num_tokens) {
116*420d848fSAndroid Build Coastguard Worker     return NULL;
117*420d848fSAndroid Build Coastguard Worker   }
118*420d848fSAndroid Build Coastguard Worker   tok = &tokens[parser->toknext++];
119*420d848fSAndroid Build Coastguard Worker   tok->start = tok->end = -1;
120*420d848fSAndroid Build Coastguard Worker   tok->size = 0;
121*420d848fSAndroid Build Coastguard Worker #ifdef JSMN_PARENT_LINKS
122*420d848fSAndroid Build Coastguard Worker   tok->parent = -1;
123*420d848fSAndroid Build Coastguard Worker #endif
124*420d848fSAndroid Build Coastguard Worker   return tok;
125*420d848fSAndroid Build Coastguard Worker }
126*420d848fSAndroid Build Coastguard Worker 
127*420d848fSAndroid Build Coastguard Worker /**
128*420d848fSAndroid Build Coastguard Worker  * Fills token type and boundaries.
129*420d848fSAndroid Build Coastguard Worker  */
jsmn_fill_token(jsmntok_t * token,const jsmntype_t type,const int start,const int end)130*420d848fSAndroid Build Coastguard Worker static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type,
131*420d848fSAndroid Build Coastguard Worker                             const int start, const int end) {
132*420d848fSAndroid Build Coastguard Worker   token->type = type;
133*420d848fSAndroid Build Coastguard Worker   token->start = start;
134*420d848fSAndroid Build Coastguard Worker   token->end = end;
135*420d848fSAndroid Build Coastguard Worker   token->size = 0;
136*420d848fSAndroid Build Coastguard Worker }
137*420d848fSAndroid Build Coastguard Worker 
138*420d848fSAndroid Build Coastguard Worker /**
139*420d848fSAndroid Build Coastguard Worker  * Fills next available token with JSON primitive.
140*420d848fSAndroid Build Coastguard Worker  */
jsmn_parse_primitive(jsmn_parser * parser,const char * js,const size_t len,jsmntok_t * tokens,const size_t num_tokens)141*420d848fSAndroid Build Coastguard Worker static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
142*420d848fSAndroid Build Coastguard Worker                                 const size_t len, jsmntok_t *tokens,
143*420d848fSAndroid Build Coastguard Worker                                 const size_t num_tokens) {
144*420d848fSAndroid Build Coastguard Worker   jsmntok_t *token;
145*420d848fSAndroid Build Coastguard Worker   int start;
146*420d848fSAndroid Build Coastguard Worker 
147*420d848fSAndroid Build Coastguard Worker   start = parser->pos;
148*420d848fSAndroid Build Coastguard Worker 
149*420d848fSAndroid Build Coastguard Worker   for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
150*420d848fSAndroid Build Coastguard Worker     switch (js[parser->pos]) {
151*420d848fSAndroid Build Coastguard Worker #ifndef JSMN_STRICT
152*420d848fSAndroid Build Coastguard Worker     /* In strict mode primitive must be followed by "," or "}" or "]" */
153*420d848fSAndroid Build Coastguard Worker     case ':':
154*420d848fSAndroid Build Coastguard Worker #endif
155*420d848fSAndroid Build Coastguard Worker     case '\t':
156*420d848fSAndroid Build Coastguard Worker     case '\r':
157*420d848fSAndroid Build Coastguard Worker     case '\n':
158*420d848fSAndroid Build Coastguard Worker     case ' ':
159*420d848fSAndroid Build Coastguard Worker     case ',':
160*420d848fSAndroid Build Coastguard Worker     case ']':
161*420d848fSAndroid Build Coastguard Worker     case '}':
162*420d848fSAndroid Build Coastguard Worker       goto found;
163*420d848fSAndroid Build Coastguard Worker     }
164*420d848fSAndroid Build Coastguard Worker     if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
165*420d848fSAndroid Build Coastguard Worker       parser->pos = start;
166*420d848fSAndroid Build Coastguard Worker       return JSMN_ERROR_INVAL;
167*420d848fSAndroid Build Coastguard Worker     }
168*420d848fSAndroid Build Coastguard Worker   }
169*420d848fSAndroid Build Coastguard Worker #ifdef JSMN_STRICT
170*420d848fSAndroid Build Coastguard Worker   /* In strict mode primitive must be followed by a comma/object/array */
171*420d848fSAndroid Build Coastguard Worker   parser->pos = start;
172*420d848fSAndroid Build Coastguard Worker   return JSMN_ERROR_PART;
173*420d848fSAndroid Build Coastguard Worker #endif
174*420d848fSAndroid Build Coastguard Worker 
175*420d848fSAndroid Build Coastguard Worker found:
176*420d848fSAndroid Build Coastguard Worker   if (tokens == NULL) {
177*420d848fSAndroid Build Coastguard Worker     parser->pos--;
178*420d848fSAndroid Build Coastguard Worker     return 0;
179*420d848fSAndroid Build Coastguard Worker   }
180*420d848fSAndroid Build Coastguard Worker   token = jsmn_alloc_token(parser, tokens, num_tokens);
181*420d848fSAndroid Build Coastguard Worker   if (token == NULL) {
182*420d848fSAndroid Build Coastguard Worker     parser->pos = start;
183*420d848fSAndroid Build Coastguard Worker     return JSMN_ERROR_NOMEM;
184*420d848fSAndroid Build Coastguard Worker   }
185*420d848fSAndroid Build Coastguard Worker   jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
186*420d848fSAndroid Build Coastguard Worker #ifdef JSMN_PARENT_LINKS
187*420d848fSAndroid Build Coastguard Worker   token->parent = parser->toksuper;
188*420d848fSAndroid Build Coastguard Worker #endif
189*420d848fSAndroid Build Coastguard Worker   parser->pos--;
190*420d848fSAndroid Build Coastguard Worker   return 0;
191*420d848fSAndroid Build Coastguard Worker }
192*420d848fSAndroid Build Coastguard Worker 
193*420d848fSAndroid Build Coastguard Worker /**
194*420d848fSAndroid Build Coastguard Worker  * Fills next token with JSON string.
195*420d848fSAndroid Build Coastguard Worker  */
jsmn_parse_string(jsmn_parser * parser,const char * js,const size_t len,jsmntok_t * tokens,const size_t num_tokens)196*420d848fSAndroid Build Coastguard Worker static int jsmn_parse_string(jsmn_parser *parser, const char *js,
197*420d848fSAndroid Build Coastguard Worker                              const size_t len, jsmntok_t *tokens,
198*420d848fSAndroid Build Coastguard Worker                              const size_t num_tokens) {
199*420d848fSAndroid Build Coastguard Worker   jsmntok_t *token;
200*420d848fSAndroid Build Coastguard Worker 
201*420d848fSAndroid Build Coastguard Worker   int start = parser->pos;
202*420d848fSAndroid Build Coastguard Worker 
203*420d848fSAndroid Build Coastguard Worker   parser->pos++;
204*420d848fSAndroid Build Coastguard Worker 
205*420d848fSAndroid Build Coastguard Worker   /* Skip starting quote */
206*420d848fSAndroid Build Coastguard Worker   for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
207*420d848fSAndroid Build Coastguard Worker     char c = js[parser->pos];
208*420d848fSAndroid Build Coastguard Worker 
209*420d848fSAndroid Build Coastguard Worker     /* Quote: end of string */
210*420d848fSAndroid Build Coastguard Worker     if (c == '\"') {
211*420d848fSAndroid Build Coastguard Worker       if (tokens == NULL) {
212*420d848fSAndroid Build Coastguard Worker         return 0;
213*420d848fSAndroid Build Coastguard Worker       }
214*420d848fSAndroid Build Coastguard Worker       token = jsmn_alloc_token(parser, tokens, num_tokens);
215*420d848fSAndroid Build Coastguard Worker       if (token == NULL) {
216*420d848fSAndroid Build Coastguard Worker         parser->pos = start;
217*420d848fSAndroid Build Coastguard Worker         return JSMN_ERROR_NOMEM;
218*420d848fSAndroid Build Coastguard Worker       }
219*420d848fSAndroid Build Coastguard Worker       jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);
220*420d848fSAndroid Build Coastguard Worker #ifdef JSMN_PARENT_LINKS
221*420d848fSAndroid Build Coastguard Worker       token->parent = parser->toksuper;
222*420d848fSAndroid Build Coastguard Worker #endif
223*420d848fSAndroid Build Coastguard Worker       return 0;
224*420d848fSAndroid Build Coastguard Worker     }
225*420d848fSAndroid Build Coastguard Worker 
226*420d848fSAndroid Build Coastguard Worker     /* Backslash: Quoted symbol expected */
227*420d848fSAndroid Build Coastguard Worker     if (c == '\\' && parser->pos + 1 < len) {
228*420d848fSAndroid Build Coastguard Worker       int i;
229*420d848fSAndroid Build Coastguard Worker       parser->pos++;
230*420d848fSAndroid Build Coastguard Worker       switch (js[parser->pos]) {
231*420d848fSAndroid Build Coastguard Worker       /* Allowed escaped symbols */
232*420d848fSAndroid Build Coastguard Worker       case '\"':
233*420d848fSAndroid Build Coastguard Worker       case '/':
234*420d848fSAndroid Build Coastguard Worker       case '\\':
235*420d848fSAndroid Build Coastguard Worker       case 'b':
236*420d848fSAndroid Build Coastguard Worker       case 'f':
237*420d848fSAndroid Build Coastguard Worker       case 'r':
238*420d848fSAndroid Build Coastguard Worker       case 'n':
239*420d848fSAndroid Build Coastguard Worker       case 't':
240*420d848fSAndroid Build Coastguard Worker         break;
241*420d848fSAndroid Build Coastguard Worker       /* Allows escaped symbol \uXXXX */
242*420d848fSAndroid Build Coastguard Worker       case 'u':
243*420d848fSAndroid Build Coastguard Worker         parser->pos++;
244*420d848fSAndroid Build Coastguard Worker         for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0';
245*420d848fSAndroid Build Coastguard Worker              i++) {
246*420d848fSAndroid Build Coastguard Worker           /* If it isn't a hex character we have an error */
247*420d848fSAndroid Build Coastguard Worker           if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) ||   /* 0-9 */
248*420d848fSAndroid Build Coastguard Worker                 (js[parser->pos] >= 65 && js[parser->pos] <= 70) ||   /* A-F */
249*420d848fSAndroid Build Coastguard Worker                 (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
250*420d848fSAndroid Build Coastguard Worker             parser->pos = start;
251*420d848fSAndroid Build Coastguard Worker             return JSMN_ERROR_INVAL;
252*420d848fSAndroid Build Coastguard Worker           }
253*420d848fSAndroid Build Coastguard Worker           parser->pos++;
254*420d848fSAndroid Build Coastguard Worker         }
255*420d848fSAndroid Build Coastguard Worker         parser->pos--;
256*420d848fSAndroid Build Coastguard Worker         break;
257*420d848fSAndroid Build Coastguard Worker       /* Unexpected symbol */
258*420d848fSAndroid Build Coastguard Worker       default:
259*420d848fSAndroid Build Coastguard Worker         parser->pos = start;
260*420d848fSAndroid Build Coastguard Worker         return JSMN_ERROR_INVAL;
261*420d848fSAndroid Build Coastguard Worker       }
262*420d848fSAndroid Build Coastguard Worker     }
263*420d848fSAndroid Build Coastguard Worker   }
264*420d848fSAndroid Build Coastguard Worker   parser->pos = start;
265*420d848fSAndroid Build Coastguard Worker   return JSMN_ERROR_PART;
266*420d848fSAndroid Build Coastguard Worker }
267*420d848fSAndroid Build Coastguard Worker 
268*420d848fSAndroid Build Coastguard Worker /**
269*420d848fSAndroid Build Coastguard Worker  * Parse JSON string and fill tokens.
270*420d848fSAndroid Build Coastguard Worker  */
jsmn_parse(jsmn_parser * parser,const char * js,const size_t len,jsmntok_t * tokens,const unsigned int num_tokens)271*420d848fSAndroid Build Coastguard Worker JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
272*420d848fSAndroid Build Coastguard Worker                         jsmntok_t *tokens, const unsigned int num_tokens) {
273*420d848fSAndroid Build Coastguard Worker   int r;
274*420d848fSAndroid Build Coastguard Worker   int i;
275*420d848fSAndroid Build Coastguard Worker   jsmntok_t *token;
276*420d848fSAndroid Build Coastguard Worker   int count = parser->toknext;
277*420d848fSAndroid Build Coastguard Worker 
278*420d848fSAndroid Build Coastguard Worker   for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
279*420d848fSAndroid Build Coastguard Worker     char c;
280*420d848fSAndroid Build Coastguard Worker     jsmntype_t type;
281*420d848fSAndroid Build Coastguard Worker 
282*420d848fSAndroid Build Coastguard Worker     c = js[parser->pos];
283*420d848fSAndroid Build Coastguard Worker     switch (c) {
284*420d848fSAndroid Build Coastguard Worker     case '{':
285*420d848fSAndroid Build Coastguard Worker     case '[':
286*420d848fSAndroid Build Coastguard Worker       count++;
287*420d848fSAndroid Build Coastguard Worker       if (tokens == NULL) {
288*420d848fSAndroid Build Coastguard Worker         break;
289*420d848fSAndroid Build Coastguard Worker       }
290*420d848fSAndroid Build Coastguard Worker       token = jsmn_alloc_token(parser, tokens, num_tokens);
291*420d848fSAndroid Build Coastguard Worker       if (token == NULL) {
292*420d848fSAndroid Build Coastguard Worker         return JSMN_ERROR_NOMEM;
293*420d848fSAndroid Build Coastguard Worker       }
294*420d848fSAndroid Build Coastguard Worker       if (parser->toksuper != -1) {
295*420d848fSAndroid Build Coastguard Worker         jsmntok_t *t = &tokens[parser->toksuper];
296*420d848fSAndroid Build Coastguard Worker #ifdef JSMN_STRICT
297*420d848fSAndroid Build Coastguard Worker         /* In strict mode an object or array can't become a key */
298*420d848fSAndroid Build Coastguard Worker         if (t->type == JSMN_OBJECT) {
299*420d848fSAndroid Build Coastguard Worker           return JSMN_ERROR_INVAL;
300*420d848fSAndroid Build Coastguard Worker         }
301*420d848fSAndroid Build Coastguard Worker #endif
302*420d848fSAndroid Build Coastguard Worker         t->size++;
303*420d848fSAndroid Build Coastguard Worker #ifdef JSMN_PARENT_LINKS
304*420d848fSAndroid Build Coastguard Worker         token->parent = parser->toksuper;
305*420d848fSAndroid Build Coastguard Worker #endif
306*420d848fSAndroid Build Coastguard Worker       }
307*420d848fSAndroid Build Coastguard Worker       token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
308*420d848fSAndroid Build Coastguard Worker       token->start = parser->pos;
309*420d848fSAndroid Build Coastguard Worker       parser->toksuper = parser->toknext - 1;
310*420d848fSAndroid Build Coastguard Worker       break;
311*420d848fSAndroid Build Coastguard Worker     case '}':
312*420d848fSAndroid Build Coastguard Worker     case ']':
313*420d848fSAndroid Build Coastguard Worker       if (tokens == NULL) {
314*420d848fSAndroid Build Coastguard Worker         break;
315*420d848fSAndroid Build Coastguard Worker       }
316*420d848fSAndroid Build Coastguard Worker       type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
317*420d848fSAndroid Build Coastguard Worker #ifdef JSMN_PARENT_LINKS
318*420d848fSAndroid Build Coastguard Worker       if (parser->toknext < 1) {
319*420d848fSAndroid Build Coastguard Worker         return JSMN_ERROR_INVAL;
320*420d848fSAndroid Build Coastguard Worker       }
321*420d848fSAndroid Build Coastguard Worker       token = &tokens[parser->toknext - 1];
322*420d848fSAndroid Build Coastguard Worker       for (;;) {
323*420d848fSAndroid Build Coastguard Worker         if (token->start != -1 && token->end == -1) {
324*420d848fSAndroid Build Coastguard Worker           if (token->type != type) {
325*420d848fSAndroid Build Coastguard Worker             return JSMN_ERROR_INVAL;
326*420d848fSAndroid Build Coastguard Worker           }
327*420d848fSAndroid Build Coastguard Worker           token->end = parser->pos + 1;
328*420d848fSAndroid Build Coastguard Worker           parser->toksuper = token->parent;
329*420d848fSAndroid Build Coastguard Worker           break;
330*420d848fSAndroid Build Coastguard Worker         }
331*420d848fSAndroid Build Coastguard Worker         if (token->parent == -1) {
332*420d848fSAndroid Build Coastguard Worker           if (token->type != type || parser->toksuper == -1) {
333*420d848fSAndroid Build Coastguard Worker             return JSMN_ERROR_INVAL;
334*420d848fSAndroid Build Coastguard Worker           }
335*420d848fSAndroid Build Coastguard Worker           break;
336*420d848fSAndroid Build Coastguard Worker         }
337*420d848fSAndroid Build Coastguard Worker         token = &tokens[token->parent];
338*420d848fSAndroid Build Coastguard Worker       }
339*420d848fSAndroid Build Coastguard Worker #else
340*420d848fSAndroid Build Coastguard Worker       for (i = parser->toknext - 1; i >= 0; i--) {
341*420d848fSAndroid Build Coastguard Worker         token = &tokens[i];
342*420d848fSAndroid Build Coastguard Worker         if (token->start != -1 && token->end == -1) {
343*420d848fSAndroid Build Coastguard Worker           if (token->type != type) {
344*420d848fSAndroid Build Coastguard Worker             return JSMN_ERROR_INVAL;
345*420d848fSAndroid Build Coastguard Worker           }
346*420d848fSAndroid Build Coastguard Worker           parser->toksuper = -1;
347*420d848fSAndroid Build Coastguard Worker           token->end = parser->pos + 1;
348*420d848fSAndroid Build Coastguard Worker           break;
349*420d848fSAndroid Build Coastguard Worker         }
350*420d848fSAndroid Build Coastguard Worker       }
351*420d848fSAndroid Build Coastguard Worker       /* Error if unmatched closing bracket */
352*420d848fSAndroid Build Coastguard Worker       if (i == -1) {
353*420d848fSAndroid Build Coastguard Worker         return JSMN_ERROR_INVAL;
354*420d848fSAndroid Build Coastguard Worker       }
355*420d848fSAndroid Build Coastguard Worker       for (; i >= 0; i--) {
356*420d848fSAndroid Build Coastguard Worker         token = &tokens[i];
357*420d848fSAndroid Build Coastguard Worker         if (token->start != -1 && token->end == -1) {
358*420d848fSAndroid Build Coastguard Worker           parser->toksuper = i;
359*420d848fSAndroid Build Coastguard Worker           break;
360*420d848fSAndroid Build Coastguard Worker         }
361*420d848fSAndroid Build Coastguard Worker       }
362*420d848fSAndroid Build Coastguard Worker #endif
363*420d848fSAndroid Build Coastguard Worker       break;
364*420d848fSAndroid Build Coastguard Worker     case '\"':
365*420d848fSAndroid Build Coastguard Worker       r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
366*420d848fSAndroid Build Coastguard Worker       if (r < 0) {
367*420d848fSAndroid Build Coastguard Worker         return r;
368*420d848fSAndroid Build Coastguard Worker       }
369*420d848fSAndroid Build Coastguard Worker       count++;
370*420d848fSAndroid Build Coastguard Worker       if (parser->toksuper != -1 && tokens != NULL) {
371*420d848fSAndroid Build Coastguard Worker         tokens[parser->toksuper].size++;
372*420d848fSAndroid Build Coastguard Worker       }
373*420d848fSAndroid Build Coastguard Worker       break;
374*420d848fSAndroid Build Coastguard Worker     case '\t':
375*420d848fSAndroid Build Coastguard Worker     case '\r':
376*420d848fSAndroid Build Coastguard Worker     case '\n':
377*420d848fSAndroid Build Coastguard Worker     case ' ':
378*420d848fSAndroid Build Coastguard Worker       break;
379*420d848fSAndroid Build Coastguard Worker     case ':':
380*420d848fSAndroid Build Coastguard Worker       parser->toksuper = parser->toknext - 1;
381*420d848fSAndroid Build Coastguard Worker       break;
382*420d848fSAndroid Build Coastguard Worker     case ',':
383*420d848fSAndroid Build Coastguard Worker       if (tokens != NULL && parser->toksuper != -1 &&
384*420d848fSAndroid Build Coastguard Worker           tokens[parser->toksuper].type != JSMN_ARRAY &&
385*420d848fSAndroid Build Coastguard Worker           tokens[parser->toksuper].type != JSMN_OBJECT) {
386*420d848fSAndroid Build Coastguard Worker #ifdef JSMN_PARENT_LINKS
387*420d848fSAndroid Build Coastguard Worker         parser->toksuper = tokens[parser->toksuper].parent;
388*420d848fSAndroid Build Coastguard Worker #else
389*420d848fSAndroid Build Coastguard Worker         for (i = parser->toknext - 1; i >= 0; i--) {
390*420d848fSAndroid Build Coastguard Worker           if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
391*420d848fSAndroid Build Coastguard Worker             if (tokens[i].start != -1 && tokens[i].end == -1) {
392*420d848fSAndroid Build Coastguard Worker               parser->toksuper = i;
393*420d848fSAndroid Build Coastguard Worker               break;
394*420d848fSAndroid Build Coastguard Worker             }
395*420d848fSAndroid Build Coastguard Worker           }
396*420d848fSAndroid Build Coastguard Worker         }
397*420d848fSAndroid Build Coastguard Worker #endif
398*420d848fSAndroid Build Coastguard Worker       }
399*420d848fSAndroid Build Coastguard Worker       break;
400*420d848fSAndroid Build Coastguard Worker #ifdef JSMN_STRICT
401*420d848fSAndroid Build Coastguard Worker     /* In strict mode primitives are: numbers and booleans */
402*420d848fSAndroid Build Coastguard Worker     case '-':
403*420d848fSAndroid Build Coastguard Worker     case '0':
404*420d848fSAndroid Build Coastguard Worker     case '1':
405*420d848fSAndroid Build Coastguard Worker     case '2':
406*420d848fSAndroid Build Coastguard Worker     case '3':
407*420d848fSAndroid Build Coastguard Worker     case '4':
408*420d848fSAndroid Build Coastguard Worker     case '5':
409*420d848fSAndroid Build Coastguard Worker     case '6':
410*420d848fSAndroid Build Coastguard Worker     case '7':
411*420d848fSAndroid Build Coastguard Worker     case '8':
412*420d848fSAndroid Build Coastguard Worker     case '9':
413*420d848fSAndroid Build Coastguard Worker     case 't':
414*420d848fSAndroid Build Coastguard Worker     case 'f':
415*420d848fSAndroid Build Coastguard Worker     case 'n':
416*420d848fSAndroid Build Coastguard Worker       /* And they must not be keys of the object */
417*420d848fSAndroid Build Coastguard Worker       if (tokens != NULL && parser->toksuper != -1) {
418*420d848fSAndroid Build Coastguard Worker         const jsmntok_t *t = &tokens[parser->toksuper];
419*420d848fSAndroid Build Coastguard Worker         if (t->type == JSMN_OBJECT ||
420*420d848fSAndroid Build Coastguard Worker             (t->type == JSMN_STRING && t->size != 0)) {
421*420d848fSAndroid Build Coastguard Worker           return JSMN_ERROR_INVAL;
422*420d848fSAndroid Build Coastguard Worker         }
423*420d848fSAndroid Build Coastguard Worker       }
424*420d848fSAndroid Build Coastguard Worker #else
425*420d848fSAndroid Build Coastguard Worker     /* In non-strict mode every unquoted value is a primitive */
426*420d848fSAndroid Build Coastguard Worker     default:
427*420d848fSAndroid Build Coastguard Worker #endif
428*420d848fSAndroid Build Coastguard Worker       r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
429*420d848fSAndroid Build Coastguard Worker       if (r < 0) {
430*420d848fSAndroid Build Coastguard Worker         return r;
431*420d848fSAndroid Build Coastguard Worker       }
432*420d848fSAndroid Build Coastguard Worker       count++;
433*420d848fSAndroid Build Coastguard Worker       if (parser->toksuper != -1 && tokens != NULL) {
434*420d848fSAndroid Build Coastguard Worker         tokens[parser->toksuper].size++;
435*420d848fSAndroid Build Coastguard Worker       }
436*420d848fSAndroid Build Coastguard Worker       break;
437*420d848fSAndroid Build Coastguard Worker 
438*420d848fSAndroid Build Coastguard Worker #ifdef JSMN_STRICT
439*420d848fSAndroid Build Coastguard Worker     /* Unexpected char in strict mode */
440*420d848fSAndroid Build Coastguard Worker     default:
441*420d848fSAndroid Build Coastguard Worker       return JSMN_ERROR_INVAL;
442*420d848fSAndroid Build Coastguard Worker #endif
443*420d848fSAndroid Build Coastguard Worker     }
444*420d848fSAndroid Build Coastguard Worker   }
445*420d848fSAndroid Build Coastguard Worker 
446*420d848fSAndroid Build Coastguard Worker   if (tokens != NULL) {
447*420d848fSAndroid Build Coastguard Worker     for (i = parser->toknext - 1; i >= 0; i--) {
448*420d848fSAndroid Build Coastguard Worker       /* Unmatched opened object or array */
449*420d848fSAndroid Build Coastguard Worker       if (tokens[i].start != -1 && tokens[i].end == -1) {
450*420d848fSAndroid Build Coastguard Worker         return JSMN_ERROR_PART;
451*420d848fSAndroid Build Coastguard Worker       }
452*420d848fSAndroid Build Coastguard Worker     }
453*420d848fSAndroid Build Coastguard Worker   }
454*420d848fSAndroid Build Coastguard Worker 
455*420d848fSAndroid Build Coastguard Worker   return count;
456*420d848fSAndroid Build Coastguard Worker }
457*420d848fSAndroid Build Coastguard Worker 
458*420d848fSAndroid Build Coastguard Worker /**
459*420d848fSAndroid Build Coastguard Worker  * Creates a new parser based over a given buffer with an array of tokens
460*420d848fSAndroid Build Coastguard Worker  * available.
461*420d848fSAndroid Build Coastguard Worker  */
jsmn_init(jsmn_parser * parser)462*420d848fSAndroid Build Coastguard Worker JSMN_API void jsmn_init(jsmn_parser *parser) {
463*420d848fSAndroid Build Coastguard Worker   parser->pos = 0;
464*420d848fSAndroid Build Coastguard Worker   parser->toknext = 0;
465*420d848fSAndroid Build Coastguard Worker   parser->toksuper = -1;
466*420d848fSAndroid Build Coastguard Worker }
467*420d848fSAndroid Build Coastguard Worker 
468*420d848fSAndroid Build Coastguard Worker #endif /* JSMN_HEADER */
469*420d848fSAndroid Build Coastguard Worker 
470*420d848fSAndroid Build Coastguard Worker #ifdef __cplusplus
471*420d848fSAndroid Build Coastguard Worker }
472*420d848fSAndroid Build Coastguard Worker #endif
473*420d848fSAndroid Build Coastguard Worker 
474*420d848fSAndroid Build Coastguard Worker #endif /* JSMN_H */
475