7 * Allocates a fresh unused token from the token pull.
9 static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
10 jsmntok_t *tokens, size_t num_tokens) {
12 if ((size_t)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 *token, jsmntype_t type,
36 * Fills next available token with JSON primitive.
38 static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
39 jsmntok_t *tokens, size_t num_tokens) {
45 for (; 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;
67 token = jsmn_alloc_token(parser, tokens, num_tokens);
70 return JSMN_ERROR_NOMEM;
72 jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
73 #ifdef JSMN_PARENT_LINKS
74 token->parent = parser->toksuper;
81 * Filsl next token with JSON string.
83 static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
84 jsmntok_t *tokens, size_t num_tokens) {
87 int start = parser->pos;
91 /* Skip starting quote */
92 for (; js[parser->pos] != '\0'; parser->pos++) {
93 char c = js[parser->pos];
95 /* Quote: end of string */
97 token = jsmn_alloc_token(parser, tokens, num_tokens);
100 return JSMN_ERROR_NOMEM;
102 jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
103 #ifdef JSMN_PARENT_LINKS
104 token->parent = parser->toksuper;
109 /* Backslash: Quoted symbol expected */
114 switch (js[parser->pos]) {
115 /* Allowed escaped symbols */
116 case '\"': case '/' : case '\\' : case 'b' :
117 case 'f' : case 'r' : case 'n' : case 't' :
119 /* Allows escaped symbol \uXXXX */
122 for(; i < 4 && js[parser->pos] != '\0'; i++) {
123 /* If it isn't a hex character we have an error */
124 if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
125 (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
126 (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
128 return JSMN_ERROR_INVAL;
134 /* Unexpected symbol */
137 return JSMN_ERROR_INVAL;
142 return JSMN_ERROR_PART;
146 * Parse JSON string and fill tokens.
148 jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens,
149 unsigned int num_tokens) {
154 for (; js[parser->pos] != '\0'; parser->pos++) {
161 token = jsmn_alloc_token(parser, tokens, num_tokens);
163 return JSMN_ERROR_NOMEM;
164 if (parser->toksuper != -1) {
165 tokens[parser->toksuper].size++;
166 #ifdef JSMN_PARENT_LINKS
167 token->parent = parser->toksuper;
170 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
171 token->start = parser->pos;
172 parser->toksuper = parser->toknext - 1;
175 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
176 #ifdef JSMN_PARENT_LINKS
177 if (parser->toknext < 1) {
178 return JSMN_ERROR_INVAL;
180 token = &tokens[parser->toknext - 1];
182 if (token->start != -1 && token->end == -1) {
183 if (token->type != type) {
184 return JSMN_ERROR_INVAL;
186 token->end = parser->pos + 1;
187 parser->toksuper = token->parent;
190 if (token->parent == -1) {
193 token = &tokens[token->parent];
196 for (i = parser->toknext - 1; i >= 0; i--) {
198 if (token->start != -1 && token->end == -1) {
199 if (token->type != type) {
200 return JSMN_ERROR_INVAL;
202 parser->toksuper = -1;
203 token->end = parser->pos + 1;
207 /* Error if unmatched closing bracket */
208 if (i == -1) return JSMN_ERROR_INVAL;
209 for (; i >= 0; i--) {
211 if (token->start != -1 && token->end == -1) {
212 parser->toksuper = i;
219 r = jsmn_parse_string(parser, js, tokens, num_tokens);
221 if (parser->toksuper != -1)
222 tokens[parser->toksuper].size++;
224 case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ':
227 /* In strict mode primitives are: numbers and booleans */
228 case '-': case '0': case '1' : case '2': case '3' : case '4':
229 case '5': case '6': case '7' : case '8': case '9':
230 case 't': case 'f': case 'n' :
232 /* In non-strict mode every unquoted value is a primitive */
235 r = jsmn_parse_primitive(parser, js, tokens, num_tokens);
237 if (parser->toksuper != -1)
238 tokens[parser->toksuper].size++;
242 /* Unexpected char in strict mode */
244 return JSMN_ERROR_INVAL;
250 for (i = parser->toknext - 1; i >= 0; i--) {
251 /* Unmatched opened object or array */
252 if (tokens[i].start != -1 && tokens[i].end == -1) {
253 return JSMN_ERROR_PART;
261 * Creates a new parser based over a given buffer with an array of tokens
264 void jsmn_init(jsmn_parser *parser) {
267 parser->toksuper = -1;