2 #include <stdio.h> //fprintf for noisy debugging wwww
7 * Allocates a fresh unused token from the token pull.
9 static jsmntok_t huge *jsmn_alloc_token(jsmn_parser huge *parser,
10 jsmntok_t huge *tokens, size_t num_tokens) {
12 if (parser->toknext >= num_tokens) {
15 tok = &tokens[parser->toknext++];
16 tok->start = tok->end = -1;
18 #ifdef JSMN_PARENT_LINKS
25 * Fills token type and boundaries.
27 static void jsmn_fill_token(jsmntok_t huge *token, jsmntype_t type,
36 * Fills next available token with JSON primitive.
38 static jsmnerr_t jsmn_parse_primitive(jsmn_parser huge *parser, const char huge *js,
39 size_t len, jsmntok_t huge *tokens, size_t num_tokens) {
40 jsmntok_t huge *token;
45 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
46 switch (js[parser->pos]) {
48 /* In strict mode primitive must be followed by "," or "}" or "]" */
51 case '\t' : case '\r' : case '\n' : case ' ' :
52 case ',' : case ']' : case '}' :
55 if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
57 return JSMN_ERROR_INVAL;
61 /* In strict mode primitive must be followed by a comma/object/array */
63 return JSMN_ERROR_PART;
71 token = jsmn_alloc_token(parser, tokens, num_tokens);
74 return JSMN_ERROR_NOMEM;
76 jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
77 #ifdef JSMN_PARENT_LINKS
78 token->parent = parser->toksuper;
85 * Filsl next token with JSON string.
87 static jsmnerr_t jsmn_parse_string(jsmn_parser huge *parser, const char huge *js,
88 size_t len, jsmntok_t huge *tokens, size_t num_tokens) {
89 jsmntok_t huge *token;
91 int start = parser->pos;
95 /* Skip starting quote */
96 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
97 char c = js[parser->pos];
99 /* Quote: end of string */
101 if (tokens == NULL) {
104 token = jsmn_alloc_token(parser, tokens, num_tokens);
107 return JSMN_ERROR_NOMEM;
109 jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
110 #ifdef JSMN_PARENT_LINKS
111 token->parent = parser->toksuper;
116 /* Backslash: Quoted symbol expected */
117 if (c == '\\' && parser->pos + 1 < len) {
120 switch (js[parser->pos]) {
121 /* Allowed escaped symbols */
122 case '\"': case '/' : case '\\' : case 'b' :
123 case 'f' : case 'r' : case 'n' : case 't' :
125 /* Allows escaped symbol \uXXXX */
128 for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
129 /* If it isn't a hex character we have an error */
130 if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
131 (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
132 (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
134 return JSMN_ERROR_INVAL;
140 /* Unexpected symbol */
143 return JSMN_ERROR_INVAL;
148 return JSMN_ERROR_PART;
152 * Parse JSON string and fill tokens.
154 jsmnerr_t jsmn_parse(jsmn_parser huge *parser, const char huge *js, size_t len,
155 jsmntok_t huge *tokens, unsigned int num_tokens) {
158 jsmntok_t huge *token;
160 //static unsigned long pee=0;
162 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
166 //fprintf(stdout, "pee=%lu count=%u i=%d nt=%u\n", pee, count, i, num_tokens);
173 if (tokens == NULL) {
176 token = jsmn_alloc_token(parser, tokens, num_tokens);
178 return JSMN_ERROR_NOMEM;
179 if (parser->toksuper != -1) {
180 tokens[parser->toksuper].size++;
181 #ifdef JSMN_PARENT_LINKS
182 token->parent = parser->toksuper;
185 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
186 token->start = parser->pos;
187 parser->toksuper = parser->toknext - 1;
192 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
193 #ifdef JSMN_PARENT_LINKS
194 if (parser->toknext < 1) {
195 return JSMN_ERROR_INVAL;
197 token = &tokens[parser->toknext - 1];
199 if (token->start != -1 && token->end == -1) {
200 if (token->type != type) {
201 return JSMN_ERROR_INVAL;
203 token->end = parser->pos + 1;
204 parser->toksuper = token->parent;
207 if (token->parent == -1) {
210 token = &tokens[token->parent];
213 for (i = parser->toknext - 1; i >= 0; i--) {
215 if (token->start != -1 && token->end == -1) {
216 if (token->type != type) {
217 return JSMN_ERROR_INVAL;
219 parser->toksuper = -1;
220 token->end = parser->pos + 1;
224 /* Error if unmatched closing bracket */
225 if (i == -1) return JSMN_ERROR_INVAL;
226 for (; i >= 0; i--) {
228 if (token->start != -1 && token->end == -1) {
229 parser->toksuper = i;
236 r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
239 if (parser->toksuper != -1 && tokens != NULL)
240 tokens[parser->toksuper].size++;
242 case '\t' : case '\r' : case '\n' : case ' ':
245 parser->toksuper = parser->toknext - 1;
248 if (tokens != NULL &&
249 tokens[parser->toksuper].type != JSMN_ARRAY &&
250 tokens[parser->toksuper].type != JSMN_OBJECT) {
251 #ifdef JSMN_PARENT_LINKS
252 parser->toksuper = tokens[parser->toksuper].parent;
254 for (i = parser->toknext - 1; i >= 0; i--) {
255 if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
256 if (tokens[i].start != -1 && tokens[i].end == -1) {
257 parser->toksuper = i;
266 /* In strict mode primitives are: numbers and booleans */
267 case '-': case '0': case '1' : case '2': case '3' : case '4':
268 case '5': case '6': case '7' : case '8': case '9':
269 case 't': case 'f': case 'n' :
270 /* And they must not be keys of the object */
271 if (tokens != NULL) {
272 jsmntok_t huge *t = &tokens[parser->toksuper];
273 if (t->type == JSMN_OBJECT ||
274 (t->type == JSMN_STRING && t->size != 0)) {
275 return JSMN_ERROR_INVAL;
279 /* In non-strict mode every unquoted value is a primitive */
282 r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
285 if (parser->toksuper != -1 && tokens != NULL)
286 tokens[parser->toksuper].size++;
290 /* Unexpected char in strict mode */
292 return JSMN_ERROR_INVAL;
297 for (i = parser->toknext - 1; i >= 0; i--) {
298 /* Unmatched opened object or array */
299 if (tokens[i].start != -1 && tokens[i].end == -1) {
300 return JSMN_ERROR_PART;
308 * Creates a new parser based over a given buffer with an array of tokens
311 void jsmn_init(jsmn_parser huge *parser) {
314 parser->toksuper = -1;