12b15cb3dSCy Schubert #include <stdlib.h>
22b15cb3dSCy Schubert
32b15cb3dSCy Schubert #include "jsmn.h"
42b15cb3dSCy Schubert
52b15cb3dSCy Schubert /**
62b15cb3dSCy Schubert * Allocates a fresh unused token from the token pull.
72b15cb3dSCy Schubert */
jsmn_alloc_token(jsmn_parser * parser,jsmntok_t * tokens,size_t num_tokens)82b15cb3dSCy Schubert static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
92b15cb3dSCy Schubert jsmntok_t *tokens, size_t num_tokens) {
102b15cb3dSCy Schubert jsmntok_t *tok;
11*276da39aSCy Schubert if (parser->toknext >= num_tokens) {
122b15cb3dSCy Schubert return NULL;
132b15cb3dSCy Schubert }
142b15cb3dSCy Schubert tok = &tokens[parser->toknext++];
152b15cb3dSCy Schubert tok->start = tok->end = -1;
162b15cb3dSCy Schubert tok->size = 0;
172b15cb3dSCy Schubert #ifdef JSMN_PARENT_LINKS
182b15cb3dSCy Schubert tok->parent = -1;
192b15cb3dSCy Schubert #endif
202b15cb3dSCy Schubert return tok;
212b15cb3dSCy Schubert }
222b15cb3dSCy Schubert
232b15cb3dSCy Schubert /**
242b15cb3dSCy Schubert * Fills token type and boundaries.
252b15cb3dSCy Schubert */
jsmn_fill_token(jsmntok_t * token,jsmntype_t type,int start,int end)262b15cb3dSCy Schubert static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
272b15cb3dSCy Schubert int start, int end) {
282b15cb3dSCy Schubert token->type = type;
292b15cb3dSCy Schubert token->start = start;
302b15cb3dSCy Schubert token->end = end;
312b15cb3dSCy Schubert token->size = 0;
322b15cb3dSCy Schubert }
332b15cb3dSCy Schubert
342b15cb3dSCy Schubert /**
352b15cb3dSCy Schubert * Fills next available token with JSON primitive.
362b15cb3dSCy Schubert */
jsmn_parse_primitive(jsmn_parser * parser,const char * js,size_t len,jsmntok_t * tokens,size_t num_tokens)372b15cb3dSCy Schubert static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
38*276da39aSCy Schubert size_t len, jsmntok_t *tokens, size_t num_tokens) {
392b15cb3dSCy Schubert jsmntok_t *token;
402b15cb3dSCy Schubert int start;
412b15cb3dSCy Schubert
422b15cb3dSCy Schubert start = parser->pos;
432b15cb3dSCy Schubert
44*276da39aSCy Schubert for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
452b15cb3dSCy Schubert switch (js[parser->pos]) {
462b15cb3dSCy Schubert #ifndef JSMN_STRICT
472b15cb3dSCy Schubert /* In strict mode primitive must be followed by "," or "}" or "]" */
482b15cb3dSCy Schubert case ':':
492b15cb3dSCy Schubert #endif
502b15cb3dSCy Schubert case '\t' : case '\r' : case '\n' : case ' ' :
512b15cb3dSCy Schubert case ',' : case ']' : case '}' :
522b15cb3dSCy Schubert goto found;
532b15cb3dSCy Schubert }
542b15cb3dSCy Schubert if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
552b15cb3dSCy Schubert parser->pos = start;
562b15cb3dSCy Schubert return JSMN_ERROR_INVAL;
572b15cb3dSCy Schubert }
582b15cb3dSCy Schubert }
592b15cb3dSCy Schubert #ifdef JSMN_STRICT
602b15cb3dSCy Schubert /* In strict mode primitive must be followed by a comma/object/array */
612b15cb3dSCy Schubert parser->pos = start;
622b15cb3dSCy Schubert return JSMN_ERROR_PART;
632b15cb3dSCy Schubert #endif
642b15cb3dSCy Schubert
652b15cb3dSCy Schubert found:
66*276da39aSCy Schubert if (tokens == NULL) {
67*276da39aSCy Schubert parser->pos--;
68*276da39aSCy Schubert return 0;
69*276da39aSCy Schubert }
702b15cb3dSCy Schubert token = jsmn_alloc_token(parser, tokens, num_tokens);
712b15cb3dSCy Schubert if (token == NULL) {
722b15cb3dSCy Schubert parser->pos = start;
732b15cb3dSCy Schubert return JSMN_ERROR_NOMEM;
742b15cb3dSCy Schubert }
752b15cb3dSCy Schubert jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
762b15cb3dSCy Schubert #ifdef JSMN_PARENT_LINKS
772b15cb3dSCy Schubert token->parent = parser->toksuper;
782b15cb3dSCy Schubert #endif
792b15cb3dSCy Schubert parser->pos--;
80*276da39aSCy Schubert return 0;
812b15cb3dSCy Schubert }
822b15cb3dSCy Schubert
832b15cb3dSCy Schubert /**
842b15cb3dSCy Schubert * Filsl next token with JSON string.
852b15cb3dSCy Schubert */
jsmn_parse_string(jsmn_parser * parser,const char * js,size_t len,jsmntok_t * tokens,size_t num_tokens)862b15cb3dSCy Schubert static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
87*276da39aSCy Schubert size_t len, jsmntok_t *tokens, size_t num_tokens) {
882b15cb3dSCy Schubert jsmntok_t *token;
892b15cb3dSCy Schubert
902b15cb3dSCy Schubert int start = parser->pos;
912b15cb3dSCy Schubert
922b15cb3dSCy Schubert parser->pos++;
932b15cb3dSCy Schubert
942b15cb3dSCy Schubert /* Skip starting quote */
95*276da39aSCy Schubert for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
962b15cb3dSCy Schubert char c = js[parser->pos];
972b15cb3dSCy Schubert
982b15cb3dSCy Schubert /* Quote: end of string */
992b15cb3dSCy Schubert if (c == '\"') {
100*276da39aSCy Schubert if (tokens == NULL) {
101*276da39aSCy Schubert return 0;
102*276da39aSCy Schubert }
1032b15cb3dSCy Schubert token = jsmn_alloc_token(parser, tokens, num_tokens);
1042b15cb3dSCy Schubert if (token == NULL) {
1052b15cb3dSCy Schubert parser->pos = start;
1062b15cb3dSCy Schubert return JSMN_ERROR_NOMEM;
1072b15cb3dSCy Schubert }
1082b15cb3dSCy Schubert jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
1092b15cb3dSCy Schubert #ifdef JSMN_PARENT_LINKS
1102b15cb3dSCy Schubert token->parent = parser->toksuper;
1112b15cb3dSCy Schubert #endif
112*276da39aSCy Schubert return 0;
1132b15cb3dSCy Schubert }
1142b15cb3dSCy Schubert
1152b15cb3dSCy Schubert /* Backslash: Quoted symbol expected */
116*276da39aSCy Schubert if (c == '\\' && parser->pos + 1 < len) {
117*276da39aSCy Schubert int i;
1182b15cb3dSCy Schubert parser->pos++;
1192b15cb3dSCy Schubert switch (js[parser->pos]) {
1202b15cb3dSCy Schubert /* Allowed escaped symbols */
1212b15cb3dSCy Schubert case '\"': case '/' : case '\\' : case 'b' :
1222b15cb3dSCy Schubert case 'f' : case 'r' : case 'n' : case 't' :
1232b15cb3dSCy Schubert break;
1242b15cb3dSCy Schubert /* Allows escaped symbol \uXXXX */
1252b15cb3dSCy Schubert case 'u':
1262b15cb3dSCy Schubert parser->pos++;
127*276da39aSCy Schubert for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
1282b15cb3dSCy Schubert /* If it isn't a hex character we have an error */
1292b15cb3dSCy Schubert if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
1302b15cb3dSCy Schubert (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
1312b15cb3dSCy Schubert (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
1322b15cb3dSCy Schubert parser->pos = start;
1332b15cb3dSCy Schubert return JSMN_ERROR_INVAL;
1342b15cb3dSCy Schubert }
1352b15cb3dSCy Schubert parser->pos++;
1362b15cb3dSCy Schubert }
1372b15cb3dSCy Schubert parser->pos--;
1382b15cb3dSCy Schubert break;
1392b15cb3dSCy Schubert /* Unexpected symbol */
1402b15cb3dSCy Schubert default:
1412b15cb3dSCy Schubert parser->pos = start;
1422b15cb3dSCy Schubert return JSMN_ERROR_INVAL;
1432b15cb3dSCy Schubert }
1442b15cb3dSCy Schubert }
1452b15cb3dSCy Schubert }
1462b15cb3dSCy Schubert parser->pos = start;
1472b15cb3dSCy Schubert return JSMN_ERROR_PART;
1482b15cb3dSCy Schubert }
1492b15cb3dSCy Schubert
1502b15cb3dSCy Schubert /**
1512b15cb3dSCy Schubert * Parse JSON string and fill tokens.
1522b15cb3dSCy Schubert */
jsmn_parse(jsmn_parser * parser,const char * js,size_t len,jsmntok_t * tokens,unsigned int num_tokens)153*276da39aSCy Schubert jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
154*276da39aSCy Schubert jsmntok_t *tokens, unsigned int num_tokens) {
1552b15cb3dSCy Schubert jsmnerr_t r;
1562b15cb3dSCy Schubert int i;
1572b15cb3dSCy Schubert jsmntok_t *token;
158*276da39aSCy Schubert int count = 0;
1592b15cb3dSCy Schubert
160*276da39aSCy Schubert for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
1612b15cb3dSCy Schubert char c;
1622b15cb3dSCy Schubert jsmntype_t type;
1632b15cb3dSCy Schubert
1642b15cb3dSCy Schubert c = js[parser->pos];
1652b15cb3dSCy Schubert switch (c) {
1662b15cb3dSCy Schubert case '{': case '[':
167*276da39aSCy Schubert count++;
168*276da39aSCy Schubert if (tokens == NULL) {
169*276da39aSCy Schubert break;
170*276da39aSCy Schubert }
1712b15cb3dSCy Schubert token = jsmn_alloc_token(parser, tokens, num_tokens);
1722b15cb3dSCy Schubert if (token == NULL)
1732b15cb3dSCy Schubert return JSMN_ERROR_NOMEM;
1742b15cb3dSCy Schubert if (parser->toksuper != -1) {
1752b15cb3dSCy Schubert tokens[parser->toksuper].size++;
1762b15cb3dSCy Schubert #ifdef JSMN_PARENT_LINKS
1772b15cb3dSCy Schubert token->parent = parser->toksuper;
1782b15cb3dSCy Schubert #endif
1792b15cb3dSCy Schubert }
1802b15cb3dSCy Schubert token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
1812b15cb3dSCy Schubert token->start = parser->pos;
1822b15cb3dSCy Schubert parser->toksuper = parser->toknext - 1;
1832b15cb3dSCy Schubert break;
1842b15cb3dSCy Schubert case '}': case ']':
185*276da39aSCy Schubert if (tokens == NULL)
186*276da39aSCy Schubert break;
1872b15cb3dSCy Schubert type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
1882b15cb3dSCy Schubert #ifdef JSMN_PARENT_LINKS
1892b15cb3dSCy Schubert if (parser->toknext < 1) {
1902b15cb3dSCy Schubert return JSMN_ERROR_INVAL;
1912b15cb3dSCy Schubert }
1922b15cb3dSCy Schubert token = &tokens[parser->toknext - 1];
1932b15cb3dSCy Schubert for (;;) {
1942b15cb3dSCy Schubert if (token->start != -1 && token->end == -1) {
1952b15cb3dSCy Schubert if (token->type != type) {
1962b15cb3dSCy Schubert return JSMN_ERROR_INVAL;
1972b15cb3dSCy Schubert }
1982b15cb3dSCy Schubert token->end = parser->pos + 1;
1992b15cb3dSCy Schubert parser->toksuper = token->parent;
2002b15cb3dSCy Schubert break;
2012b15cb3dSCy Schubert }
2022b15cb3dSCy Schubert if (token->parent == -1) {
2032b15cb3dSCy Schubert break;
2042b15cb3dSCy Schubert }
2052b15cb3dSCy Schubert token = &tokens[token->parent];
2062b15cb3dSCy Schubert }
2072b15cb3dSCy Schubert #else
2082b15cb3dSCy Schubert for (i = parser->toknext - 1; i >= 0; i--) {
2092b15cb3dSCy Schubert token = &tokens[i];
2102b15cb3dSCy Schubert if (token->start != -1 && token->end == -1) {
2112b15cb3dSCy Schubert if (token->type != type) {
2122b15cb3dSCy Schubert return JSMN_ERROR_INVAL;
2132b15cb3dSCy Schubert }
2142b15cb3dSCy Schubert parser->toksuper = -1;
2152b15cb3dSCy Schubert token->end = parser->pos + 1;
2162b15cb3dSCy Schubert break;
2172b15cb3dSCy Schubert }
2182b15cb3dSCy Schubert }
2192b15cb3dSCy Schubert /* Error if unmatched closing bracket */
2202b15cb3dSCy Schubert if (i == -1) return JSMN_ERROR_INVAL;
2212b15cb3dSCy Schubert for (; i >= 0; i--) {
2222b15cb3dSCy Schubert token = &tokens[i];
2232b15cb3dSCy Schubert if (token->start != -1 && token->end == -1) {
2242b15cb3dSCy Schubert parser->toksuper = i;
2252b15cb3dSCy Schubert break;
2262b15cb3dSCy Schubert }
2272b15cb3dSCy Schubert }
2282b15cb3dSCy Schubert #endif
2292b15cb3dSCy Schubert break;
2302b15cb3dSCy Schubert case '\"':
231*276da39aSCy Schubert r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
2322b15cb3dSCy Schubert if (r < 0) return r;
233*276da39aSCy Schubert count++;
234*276da39aSCy Schubert if (parser->toksuper != -1 && tokens != NULL)
2352b15cb3dSCy Schubert tokens[parser->toksuper].size++;
2362b15cb3dSCy Schubert break;
237*276da39aSCy Schubert case '\t' : case '\r' : case '\n' : case ' ':
238*276da39aSCy Schubert break;
239*276da39aSCy Schubert case ':':
240*276da39aSCy Schubert parser->toksuper = parser->toknext - 1;
241*276da39aSCy Schubert break;
242*276da39aSCy Schubert case ',':
243*276da39aSCy Schubert if (tokens != NULL &&
244*276da39aSCy Schubert tokens[parser->toksuper].type != JSMN_ARRAY &&
245*276da39aSCy Schubert tokens[parser->toksuper].type != JSMN_OBJECT) {
246*276da39aSCy Schubert #ifdef JSMN_PARENT_LINKS
247*276da39aSCy Schubert parser->toksuper = tokens[parser->toksuper].parent;
248*276da39aSCy Schubert #else
249*276da39aSCy Schubert for (i = parser->toknext - 1; i >= 0; i--) {
250*276da39aSCy Schubert if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
251*276da39aSCy Schubert if (tokens[i].start != -1 && tokens[i].end == -1) {
252*276da39aSCy Schubert parser->toksuper = i;
253*276da39aSCy Schubert break;
254*276da39aSCy Schubert }
255*276da39aSCy Schubert }
256*276da39aSCy Schubert }
257*276da39aSCy Schubert #endif
258*276da39aSCy Schubert }
2592b15cb3dSCy Schubert break;
2602b15cb3dSCy Schubert #ifdef JSMN_STRICT
2612b15cb3dSCy Schubert /* In strict mode primitives are: numbers and booleans */
2622b15cb3dSCy Schubert case '-': case '0': case '1' : case '2': case '3' : case '4':
2632b15cb3dSCy Schubert case '5': case '6': case '7' : case '8': case '9':
2642b15cb3dSCy Schubert case 't': case 'f': case 'n' :
265*276da39aSCy Schubert /* And they must not be keys of the object */
266*276da39aSCy Schubert if (tokens != NULL) {
267*276da39aSCy Schubert jsmntok_t *t = &tokens[parser->toksuper];
268*276da39aSCy Schubert if (t->type == JSMN_OBJECT ||
269*276da39aSCy Schubert (t->type == JSMN_STRING && t->size != 0)) {
270*276da39aSCy Schubert return JSMN_ERROR_INVAL;
271*276da39aSCy Schubert }
272*276da39aSCy Schubert }
2732b15cb3dSCy Schubert #else
2742b15cb3dSCy Schubert /* In non-strict mode every unquoted value is a primitive */
2752b15cb3dSCy Schubert default:
2762b15cb3dSCy Schubert #endif
277*276da39aSCy Schubert r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
2782b15cb3dSCy Schubert if (r < 0) return r;
279*276da39aSCy Schubert count++;
280*276da39aSCy Schubert if (parser->toksuper != -1 && tokens != NULL)
2812b15cb3dSCy Schubert tokens[parser->toksuper].size++;
2822b15cb3dSCy Schubert break;
2832b15cb3dSCy Schubert
2842b15cb3dSCy Schubert #ifdef JSMN_STRICT
2852b15cb3dSCy Schubert /* Unexpected char in strict mode */
2862b15cb3dSCy Schubert default:
2872b15cb3dSCy Schubert return JSMN_ERROR_INVAL;
2882b15cb3dSCy Schubert #endif
2892b15cb3dSCy Schubert }
2902b15cb3dSCy Schubert }
291*276da39aSCy Schubert if (tokens != NULL) {
2922b15cb3dSCy Schubert for (i = parser->toknext - 1; i >= 0; i--) {
2932b15cb3dSCy Schubert /* Unmatched opened object or array */
2942b15cb3dSCy Schubert if (tokens[i].start != -1 && tokens[i].end == -1) {
2952b15cb3dSCy Schubert return JSMN_ERROR_PART;
2962b15cb3dSCy Schubert }
2972b15cb3dSCy Schubert }
298*276da39aSCy Schubert }
2992b15cb3dSCy Schubert
300*276da39aSCy Schubert return count;
3012b15cb3dSCy Schubert }
3022b15cb3dSCy Schubert
3032b15cb3dSCy Schubert /**
3042b15cb3dSCy Schubert * Creates a new parser based over a given buffer with an array of tokens
3052b15cb3dSCy Schubert * available.
3062b15cb3dSCy Schubert */
jsmn_init(jsmn_parser * parser)3072b15cb3dSCy Schubert void jsmn_init(jsmn_parser *parser) {
3082b15cb3dSCy Schubert parser->pos = 0;
3092b15cb3dSCy Schubert parser->toknext = 0;
3102b15cb3dSCy Schubert parser->toksuper = -1;
3112b15cb3dSCy Schubert }
3122b15cb3dSCy Schubert
313