4 * Allocates a fresh unused token from the token pull.
6 static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
7 jsmntok_t *tokens, size_t num_tokens) {
9 if (parser->toknext >= num_tokens) {
12 tok = &tokens[parser->toknext++];
13 tok->start = tok->end = -1;
15 #ifdef JSMN_PARENT_LINKS
22 * Fills token type and boundaries.
24 static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
33 * Fills next available token with JSON primitive.
35 static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
36 size_t len, jsmntok_t *tokens, size_t num_tokens) {
42 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
43 switch (js[parser->pos]) {
45 /* In strict mode primitive must be followed by "," or "}" or "]" */
48 case '\t' : case '\r' : case '\n' : case ' ' :
49 case ',' : case ']' : case '}' :
52 if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
54 return JSMN_ERROR_INVAL;
58 /* In strict mode primitive must be followed by a comma/object/array */
60 return JSMN_ERROR_PART;
68 token = jsmn_alloc_token(parser, tokens, num_tokens);
71 return JSMN_ERROR_NOMEM;
73 jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
74 #ifdef JSMN_PARENT_LINKS
75 token->parent = parser->toksuper;
82 * Filsl next token with JSON string.
84 static int jsmn_parse_string(jsmn_parser *parser, const char *js,
85 size_t len, jsmntok_t *tokens, size_t num_tokens) {
88 int start = parser->pos;
92 /* Skip starting quote */
93 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
94 char c = js[parser->pos];
96 /* Quote: end of string */
101 token = jsmn_alloc_token(parser, tokens, num_tokens);
104 return JSMN_ERROR_NOMEM;
106 jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
107 #ifdef JSMN_PARENT_LINKS
108 token->parent = parser->toksuper;
113 /* Backslash: Quoted symbol expected */
114 if (c == '\\' && parser->pos + 1 < len) {
117 switch (js[parser->pos]) {
118 /* Allowed escaped symbols */
119 case '\"': case '/' : case '\\' : case 'b' :
120 case 'f' : case 'r' : case 'n' : case 't' :
122 /* Allows escaped symbol \uXXXX */
125 for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
126 /* If it isn't a hex character we have an error */
127 if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
128 (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
129 (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
131 return JSMN_ERROR_INVAL;
137 /* Unexpected symbol */
140 return JSMN_ERROR_INVAL;
145 return JSMN_ERROR_PART;
149 * Parse JSON string and fill tokens.
151 int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
152 jsmntok_t *tokens, unsigned int num_tokens) {
156 int count = parser->toknext;
158 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
166 if (tokens == NULL) {
169 token = jsmn_alloc_token(parser, tokens, num_tokens);
171 return JSMN_ERROR_NOMEM;
172 if (parser->toksuper != -1) {
173 tokens[parser->toksuper].size++;
174 #ifdef JSMN_PARENT_LINKS
175 token->parent = parser->toksuper;
178 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
179 token->start = parser->pos;
180 parser->toksuper = parser->toknext - 1;
185 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
186 #ifdef JSMN_PARENT_LINKS
187 if (parser->toknext < 1) {
188 return JSMN_ERROR_INVAL;
190 token = &tokens[parser->toknext - 1];
192 if (token->start != -1 && token->end == -1) {
193 if (token->type != type) {
194 return JSMN_ERROR_INVAL;
196 token->end = parser->pos + 1;
197 parser->toksuper = token->parent;
200 if (token->parent == -1) {
203 token = &tokens[token->parent];
206 for (i = parser->toknext - 1; i >= 0; i--) {
208 if (token->start != -1 && token->end == -1) {
209 if (token->type != type) {
210 return JSMN_ERROR_INVAL;
212 parser->toksuper = -1;
213 token->end = parser->pos + 1;
217 /* Error if unmatched closing bracket */
218 if (i == -1) return JSMN_ERROR_INVAL;
219 for (; i >= 0; i--) {
221 if (token->start != -1 && token->end == -1) {
222 parser->toksuper = i;
229 r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
232 if (parser->toksuper != -1 && tokens != NULL)
233 tokens[parser->toksuper].size++;
235 case '\t' : case '\r' : case '\n' : case ' ':
238 parser->toksuper = parser->toknext - 1;
241 if (tokens != NULL && parser->toksuper != -1 &&
242 tokens[parser->toksuper].type != JSMN_ARRAY &&
243 tokens[parser->toksuper].type != JSMN_OBJECT) {
244 #ifdef JSMN_PARENT_LINKS
245 parser->toksuper = tokens[parser->toksuper].parent;
247 for (i = parser->toknext - 1; i >= 0; i--) {
248 if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
249 if (tokens[i].start != -1 && tokens[i].end == -1) {
250 parser->toksuper = i;
259 /* In strict mode primitives are: numbers and booleans */
260 case '-': case '0': case '1' : case '2': case '3' : case '4':
261 case '5': case '6': case '7' : case '8': case '9':
262 case 't': case 'f': case 'n' :
263 /* And they must not be keys of the object */
264 if (tokens != NULL && parser->toksuper != -1) {
265 jsmntok_t *t = &tokens[parser->toksuper];
266 if (t->type == JSMN_OBJECT ||
267 (t->type == JSMN_STRING && t->size != 0)) {
268 return JSMN_ERROR_INVAL;
272 /* In non-strict mode every unquoted value is a primitive */
275 r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
278 if (parser->toksuper != -1 && tokens != NULL)
279 tokens[parser->toksuper].size++;
283 /* Unexpected char in strict mode */
285 return JSMN_ERROR_INVAL;
290 if (tokens != NULL) {
291 for (i = parser->toknext - 1; i >= 0; i--) {
292 /* Unmatched opened object or array */
293 if (tokens[i].start != -1 && tokens[i].end == -1) {
294 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;