6 * Allocates a fresh unused token from the token pull.
8 static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
9 jsmntok_t *tokens, size_t num_tokens) {
11 if (parser->toknext >= num_tokens) {
14 tok = &tokens[parser->toknext++];
15 tok->start = tok->end = -1;
17 #ifdef JSMN_PARENT_LINKS
24 * Fills token type and boundaries.
26 static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
35 * Fills next available token with JSON primitive.
37 static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
38 size_t len, jsmntok_t *tokens, size_t num_tokens) {
44 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
45 switch (js[parser->pos]) {
47 /* In strict mode primitive must be followed by "," or "}" or "]" */
50 case '\t' : case '\r' : case '\n' : case ' ' :
51 case ',' : case ']' : case '}' :
54 if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
56 return JSMN_ERROR_INVAL;
60 /* In strict mode primitive must be followed by a comma/object/array */
62 return JSMN_ERROR_PART;
70 token = jsmn_alloc_token(parser, tokens, num_tokens);
73 return JSMN_ERROR_NOMEM;
75 jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
76 #ifdef JSMN_PARENT_LINKS
77 token->parent = parser->toksuper;
84 * Filsl next token with JSON string.
86 static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
87 size_t len, jsmntok_t *tokens, size_t num_tokens) {
90 int start = parser->pos;
94 /* Skip starting quote */
95 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
96 char c = js[parser->pos];
98 /* Quote: end of string */
100 if (tokens == NULL) {
103 token = jsmn_alloc_token(parser, tokens, num_tokens);
106 return JSMN_ERROR_NOMEM;
108 jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
109 #ifdef JSMN_PARENT_LINKS
110 token->parent = parser->toksuper;
115 /* Backslash: Quoted symbol expected */
116 if (c == '\\' && parser->pos + 1 < len) {
119 switch (js[parser->pos]) {
120 /* Allowed escaped symbols */
121 case '\"': case '/' : case '\\' : case 'b' :
122 case 'f' : case 'r' : case 'n' : case 't' :
124 /* Allows escaped symbol \uXXXX */
127 for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
128 /* If it isn't a hex character we have an error */
129 if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
130 (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
131 (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
133 return JSMN_ERROR_INVAL;
139 /* Unexpected symbol */
142 return JSMN_ERROR_INVAL;
147 return JSMN_ERROR_PART;
151 * Parse JSON string and fill tokens.
153 jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
154 jsmntok_t *tokens, unsigned int num_tokens) {
160 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
168 if (tokens == NULL) {
171 token = jsmn_alloc_token(parser, tokens, num_tokens);
173 return JSMN_ERROR_NOMEM;
174 if (parser->toksuper != -1) {
175 tokens[parser->toksuper].size++;
176 #ifdef JSMN_PARENT_LINKS
177 token->parent = parser->toksuper;
180 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
181 token->start = parser->pos;
182 parser->toksuper = parser->toknext - 1;
187 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
188 #ifdef JSMN_PARENT_LINKS
189 if (parser->toknext < 1) {
190 return JSMN_ERROR_INVAL;
192 token = &tokens[parser->toknext - 1];
194 if (token->start != -1 && token->end == -1) {
195 if (token->type != type) {
196 return JSMN_ERROR_INVAL;
198 token->end = parser->pos + 1;
199 parser->toksuper = token->parent;
202 if (token->parent == -1) {
205 token = &tokens[token->parent];
208 for (i = parser->toknext - 1; i >= 0; i--) {
210 if (token->start != -1 && token->end == -1) {
211 if (token->type != type) {
212 return JSMN_ERROR_INVAL;
214 parser->toksuper = -1;
215 token->end = parser->pos + 1;
219 /* Error if unmatched closing bracket */
220 if (i == -1) return JSMN_ERROR_INVAL;
221 for (; i >= 0; i--) {
223 if (token->start != -1 && token->end == -1) {
224 parser->toksuper = i;
231 r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
234 if (parser->toksuper != -1 && tokens != NULL)
235 tokens[parser->toksuper].size++;
237 case '\t' : case '\r' : case '\n' : case ' ':
240 parser->toksuper = parser->toknext - 1;
243 if (tokens != NULL &&
244 tokens[parser->toksuper].type != JSMN_ARRAY &&
245 tokens[parser->toksuper].type != JSMN_OBJECT) {
246 #ifdef JSMN_PARENT_LINKS
247 parser->toksuper = tokens[parser->toksuper].parent;
249 for (i = parser->toknext - 1; i >= 0; i--) {
250 if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
251 if (tokens[i].start != -1 && tokens[i].end == -1) {
252 parser->toksuper = i;
261 /* In strict mode primitives are: numbers and booleans */
262 case '-': case '0': case '1' : case '2': case '3' : case '4':
263 case '5': case '6': case '7' : case '8': case '9':
264 case 't': case 'f': case 'n' :
265 /* And they must not be keys of the object */
266 if (tokens != NULL) {
267 jsmntok_t *t = &tokens[parser->toksuper];
268 if (t->type == JSMN_OBJECT ||
269 (t->type == JSMN_STRING && t->size != 0)) {
270 return JSMN_ERROR_INVAL;
274 /* In non-strict mode every unquoted value is a primitive */
277 r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
280 if (parser->toksuper != -1 && tokens != NULL)
281 tokens[parser->toksuper].size++;
285 /* Unexpected char in strict mode */
287 return JSMN_ERROR_INVAL;
292 for (i = parser->toknext - 1; i >= 0; i--) {
293 /* Unmatched opened object or array */
294 if (tokens[i].start != -1 && tokens[i].end == -1) {
295 return JSMN_ERROR_PART;
303 * Creates a new parser based over a given buffer with an array of tokens
306 void jsmn_init(jsmn_parser *parser) {
309 parser->toksuper = -1;