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