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