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, "%lu %c count=%u i=%d nt=%u\n", pee, js[parser->pos], count, i, num_tokens);
167 //fprintf(stdout, "token->start=%d\n", token->start);
174 if (tokens == NULL) {
177 token = jsmn_alloc_token(parser, tokens, num_tokens);
179 return JSMN_ERROR_NOMEM;
180 if (parser->toksuper != -1) {
181 tokens[parser->toksuper].size++;
182 #ifdef JSMN_PARENT_LINKS
183 token->parent = parser->toksuper;
186 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
187 token->start = parser->pos;
188 parser->toksuper = parser->toknext - 1;
193 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
194 #ifdef JSMN_PARENT_LINKS
195 if (parser->toknext < 1) {
196 return JSMN_ERROR_INVAL;
198 token = &tokens[parser->toknext - 1];
200 if (token->start != -1 && token->end == -1) {
201 if (token->type != type) {
202 return JSMN_ERROR_INVAL;
204 token->end = parser->pos + 1;
205 parser->toksuper = token->parent;
208 if (token->parent == -1) {
211 token = &tokens[token->parent];
214 for (i = parser->toknext - 1; i >= 0; i--) {
216 if (token->start != -1 && token->end == -1) {
217 if (token->type != type) {
218 return JSMN_ERROR_INVAL;
220 parser->toksuper = -1;
221 token->end = parser->pos + 1;
225 /* Error if unmatched closing bracket */
226 if (i == -1) return JSMN_ERROR_INVAL;
227 for (; i >= 0; i--) {
229 if (token->start != -1 && token->end == -1) {
230 parser->toksuper = i;
237 r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
240 if (parser->toksuper != -1 && tokens != NULL)
241 tokens[parser->toksuper].size++;
243 case '\t' : case '\r' : case '\n' : case ' ':
246 parser->toksuper = parser->toknext - 1;
249 if (tokens != NULL &&
250 tokens[parser->toksuper].type != JSMN_ARRAY &&
251 tokens[parser->toksuper].type != JSMN_OBJECT) {
252 #ifdef JSMN_PARENT_LINKS
253 parser->toksuper = tokens[parser->toksuper].parent;
255 for (i = parser->toknext - 1; i >= 0; i--) {
256 if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
257 if (tokens[i].start != -1 && tokens[i].end == -1) {
258 parser->toksuper = i;
267 /* In strict mode primitives are: numbers and booleans */
268 case '-': case '0': case '1' : case '2': case '3' : case '4':
269 case '5': case '6': case '7' : case '8': case '9':
270 case 't': case 'f': case 'n' :
271 /* And they must not be keys of the object */
272 if (tokens != NULL) {
273 jsmntok_t huge *t = &tokens[parser->toksuper];
274 if (t->type == JSMN_OBJECT ||
275 (t->type == JSMN_STRING && t->size != 0)) {
276 return JSMN_ERROR_INVAL;
280 /* In non-strict mode every unquoted value is a primitive */
283 r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
286 if (parser->toksuper != -1 && tokens != NULL)
287 tokens[parser->toksuper].size++;
291 /* Unexpected char in strict mode */
293 return JSMN_ERROR_INVAL;
298 for (i = parser->toknext - 1; i >= 0; i--) {
299 /* Unmatched opened object or array */
300 if (tokens[i].start != -1 && tokens[i].end == -1) {
301 return JSMN_ERROR_PART;
309 * Creates a new parser based over a given buffer with an array of tokens
312 void jsmn_init(jsmn_parser huge *parser) {
315 parser->toksuper = -1;