Changes to enabled on-line compiler

Committer:
JMF
Date:
Wed May 30 20:59:51 2018 +0000
Revision:
0:082731ede69f
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
JMF 0:082731ede69f 1 /*
JMF 0:082731ede69f 2 * Copyright (c) 2010 Serge A. Zaitsev
JMF 0:082731ede69f 3 *
JMF 0:082731ede69f 4 * Permission is hereby granted, free of charge, to any person obtaining a copy
JMF 0:082731ede69f 5 * of this software and associated documentation files (the "Software"), to deal
JMF 0:082731ede69f 6 * in the Software without restriction, including without limitation the rights
JMF 0:082731ede69f 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
JMF 0:082731ede69f 8 * copies of the Software, and to permit persons to whom the Software is
JMF 0:082731ede69f 9 * furnished to do so, subject to the following conditions:
JMF 0:082731ede69f 10 *
JMF 0:082731ede69f 11 * The above copyright notice and this permission notice shall be included in
JMF 0:082731ede69f 12 * all copies or substantial portions of the Software.
JMF 0:082731ede69f 13 *
JMF 0:082731ede69f 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
JMF 0:082731ede69f 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
JMF 0:082731ede69f 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
JMF 0:082731ede69f 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
JMF 0:082731ede69f 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
JMF 0:082731ede69f 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
JMF 0:082731ede69f 20 * THE SOFTWARE.
JMF 0:082731ede69f 21 */
JMF 0:082731ede69f 22
JMF 0:082731ede69f 23 /**
JMF 0:082731ede69f 24 * @file jsmn.c
JMF 0:082731ede69f 25 * @brief Implementation of the JSMN (Jasmine) JSON parser.
JMF 0:082731ede69f 26 *
JMF 0:082731ede69f 27 * For more information on JSMN:
JMF 0:082731ede69f 28 * @see http://zserge.com/jsmn.html
JMF 0:082731ede69f 29 */
JMF 0:082731ede69f 30
JMF 0:082731ede69f 31 #include "jsmn.h"
JMF 0:082731ede69f 32
JMF 0:082731ede69f 33 /**
JMF 0:082731ede69f 34 * Allocates a fresh unused token from the token pull.
JMF 0:082731ede69f 35 */
JMF 0:082731ede69f 36 static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
JMF 0:082731ede69f 37 jsmntok_t *tokens, size_t num_tokens) {
JMF 0:082731ede69f 38 jsmntok_t *tok;
JMF 0:082731ede69f 39 if (parser->toknext >= num_tokens) {
JMF 0:082731ede69f 40 return NULL;
JMF 0:082731ede69f 41 }
JMF 0:082731ede69f 42 tok = &tokens[parser->toknext++];
JMF 0:082731ede69f 43 tok->start = tok->end = -1;
JMF 0:082731ede69f 44 tok->size = 0;
JMF 0:082731ede69f 45 #ifdef JSMN_PARENT_LINKS
JMF 0:082731ede69f 46 tok->parent = -1;
JMF 0:082731ede69f 47 #endif
JMF 0:082731ede69f 48 return tok;
JMF 0:082731ede69f 49 }
JMF 0:082731ede69f 50
JMF 0:082731ede69f 51 /**
JMF 0:082731ede69f 52 * Fills token type and boundaries.
JMF 0:082731ede69f 53 */
JMF 0:082731ede69f 54 static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
JMF 0:082731ede69f 55 int start, int end) {
JMF 0:082731ede69f 56 token->type = type;
JMF 0:082731ede69f 57 token->start = start;
JMF 0:082731ede69f 58 token->end = end;
JMF 0:082731ede69f 59 token->size = 0;
JMF 0:082731ede69f 60 }
JMF 0:082731ede69f 61
JMF 0:082731ede69f 62 /**
JMF 0:082731ede69f 63 * Fills next available token with JSON primitive.
JMF 0:082731ede69f 64 */
JMF 0:082731ede69f 65 static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
JMF 0:082731ede69f 66 size_t len, jsmntok_t *tokens, size_t num_tokens) {
JMF 0:082731ede69f 67 jsmntok_t *token;
JMF 0:082731ede69f 68 int start;
JMF 0:082731ede69f 69
JMF 0:082731ede69f 70 start = parser->pos;
JMF 0:082731ede69f 71
JMF 0:082731ede69f 72 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
JMF 0:082731ede69f 73 switch (js[parser->pos]) {
JMF 0:082731ede69f 74 #ifndef JSMN_STRICT
JMF 0:082731ede69f 75 /* In strict mode primitive must be followed by "," or "}" or "]" */
JMF 0:082731ede69f 76 case ':':
JMF 0:082731ede69f 77 #endif
JMF 0:082731ede69f 78 case '\t' : case '\r' : case '\n' : case ' ' :
JMF 0:082731ede69f 79 case ',' : case ']' : case '}' :
JMF 0:082731ede69f 80 goto found;
JMF 0:082731ede69f 81 }
JMF 0:082731ede69f 82 if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
JMF 0:082731ede69f 83 parser->pos = start;
JMF 0:082731ede69f 84 return JSMN_ERROR_INVAL;
JMF 0:082731ede69f 85 }
JMF 0:082731ede69f 86 }
JMF 0:082731ede69f 87 #ifdef JSMN_STRICT
JMF 0:082731ede69f 88 /* In strict mode primitive must be followed by a comma/object/array */
JMF 0:082731ede69f 89 parser->pos = start;
JMF 0:082731ede69f 90 return JSMN_ERROR_PART;
JMF 0:082731ede69f 91 #endif
JMF 0:082731ede69f 92
JMF 0:082731ede69f 93 found:
JMF 0:082731ede69f 94 if (tokens == NULL) {
JMF 0:082731ede69f 95 parser->pos--;
JMF 0:082731ede69f 96 return 0;
JMF 0:082731ede69f 97 }
JMF 0:082731ede69f 98 token = jsmn_alloc_token(parser, tokens, num_tokens);
JMF 0:082731ede69f 99 if (token == NULL) {
JMF 0:082731ede69f 100 parser->pos = start;
JMF 0:082731ede69f 101 return JSMN_ERROR_NOMEM;
JMF 0:082731ede69f 102 }
JMF 0:082731ede69f 103 jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
JMF 0:082731ede69f 104 #ifdef JSMN_PARENT_LINKS
JMF 0:082731ede69f 105 token->parent = parser->toksuper;
JMF 0:082731ede69f 106 #endif
JMF 0:082731ede69f 107 parser->pos--;
JMF 0:082731ede69f 108 return 0;
JMF 0:082731ede69f 109 }
JMF 0:082731ede69f 110
JMF 0:082731ede69f 111 /**
JMF 0:082731ede69f 112 * Fills next token with JSON string.
JMF 0:082731ede69f 113 */
JMF 0:082731ede69f 114 static int jsmn_parse_string(jsmn_parser *parser, const char *js,
JMF 0:082731ede69f 115 size_t len, jsmntok_t *tokens, size_t num_tokens) {
JMF 0:082731ede69f 116 jsmntok_t *token;
JMF 0:082731ede69f 117
JMF 0:082731ede69f 118 int start = parser->pos;
JMF 0:082731ede69f 119
JMF 0:082731ede69f 120 parser->pos++;
JMF 0:082731ede69f 121
JMF 0:082731ede69f 122 /* Skip starting quote */
JMF 0:082731ede69f 123 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
JMF 0:082731ede69f 124 char c = js[parser->pos];
JMF 0:082731ede69f 125
JMF 0:082731ede69f 126 /* Quote: end of string */
JMF 0:082731ede69f 127 if (c == '\"') {
JMF 0:082731ede69f 128 if (tokens == NULL) {
JMF 0:082731ede69f 129 return 0;
JMF 0:082731ede69f 130 }
JMF 0:082731ede69f 131 token = jsmn_alloc_token(parser, tokens, num_tokens);
JMF 0:082731ede69f 132 if (token == NULL) {
JMF 0:082731ede69f 133 parser->pos = start;
JMF 0:082731ede69f 134 return JSMN_ERROR_NOMEM;
JMF 0:082731ede69f 135 }
JMF 0:082731ede69f 136 jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
JMF 0:082731ede69f 137 #ifdef JSMN_PARENT_LINKS
JMF 0:082731ede69f 138 token->parent = parser->toksuper;
JMF 0:082731ede69f 139 #endif
JMF 0:082731ede69f 140 return 0;
JMF 0:082731ede69f 141 }
JMF 0:082731ede69f 142
JMF 0:082731ede69f 143 /* Backslash: Quoted symbol expected */
JMF 0:082731ede69f 144 if (c == '\\' && parser->pos + 1 < len) {
JMF 0:082731ede69f 145 int i;
JMF 0:082731ede69f 146 parser->pos++;
JMF 0:082731ede69f 147 switch (js[parser->pos]) {
JMF 0:082731ede69f 148 /* Allowed escaped symbols */
JMF 0:082731ede69f 149 case '\"': case '/' : case '\\' : case 'b' :
JMF 0:082731ede69f 150 case 'f' : case 'r' : case 'n' : case 't' :
JMF 0:082731ede69f 151 break;
JMF 0:082731ede69f 152 /* Allows escaped symbol \uXXXX */
JMF 0:082731ede69f 153 case 'u':
JMF 0:082731ede69f 154 parser->pos++;
JMF 0:082731ede69f 155 for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
JMF 0:082731ede69f 156 /* If it isn't a hex character we have an error */
JMF 0:082731ede69f 157 if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
JMF 0:082731ede69f 158 (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
JMF 0:082731ede69f 159 (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
JMF 0:082731ede69f 160 parser->pos = start;
JMF 0:082731ede69f 161 return JSMN_ERROR_INVAL;
JMF 0:082731ede69f 162 }
JMF 0:082731ede69f 163 parser->pos++;
JMF 0:082731ede69f 164 }
JMF 0:082731ede69f 165 parser->pos--;
JMF 0:082731ede69f 166 break;
JMF 0:082731ede69f 167 /* Unexpected symbol */
JMF 0:082731ede69f 168 default:
JMF 0:082731ede69f 169 parser->pos = start;
JMF 0:082731ede69f 170 return JSMN_ERROR_INVAL;
JMF 0:082731ede69f 171 }
JMF 0:082731ede69f 172 }
JMF 0:082731ede69f 173 }
JMF 0:082731ede69f 174 parser->pos = start;
JMF 0:082731ede69f 175 return JSMN_ERROR_PART;
JMF 0:082731ede69f 176 }
JMF 0:082731ede69f 177
JMF 0:082731ede69f 178 /**
JMF 0:082731ede69f 179 * Parse JSON string and fill tokens.
JMF 0:082731ede69f 180 */
JMF 0:082731ede69f 181 int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
JMF 0:082731ede69f 182 jsmntok_t *tokens, unsigned int num_tokens) {
JMF 0:082731ede69f 183 int r;
JMF 0:082731ede69f 184 int i;
JMF 0:082731ede69f 185 jsmntok_t *token;
JMF 0:082731ede69f 186 int count = parser->toknext;
JMF 0:082731ede69f 187
JMF 0:082731ede69f 188 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
JMF 0:082731ede69f 189 char c;
JMF 0:082731ede69f 190 jsmntype_t type;
JMF 0:082731ede69f 191
JMF 0:082731ede69f 192 c = js[parser->pos];
JMF 0:082731ede69f 193 switch (c) {
JMF 0:082731ede69f 194 case '{': case '[':
JMF 0:082731ede69f 195 count++;
JMF 0:082731ede69f 196 if (tokens == NULL) {
JMF 0:082731ede69f 197 break;
JMF 0:082731ede69f 198 }
JMF 0:082731ede69f 199 token = jsmn_alloc_token(parser, tokens, num_tokens);
JMF 0:082731ede69f 200 if (token == NULL)
JMF 0:082731ede69f 201 return JSMN_ERROR_NOMEM;
JMF 0:082731ede69f 202 if (parser->toksuper != -1) {
JMF 0:082731ede69f 203 tokens[parser->toksuper].size++;
JMF 0:082731ede69f 204 #ifdef JSMN_PARENT_LINKS
JMF 0:082731ede69f 205 token->parent = parser->toksuper;
JMF 0:082731ede69f 206 #endif
JMF 0:082731ede69f 207 }
JMF 0:082731ede69f 208 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
JMF 0:082731ede69f 209 token->start = parser->pos;
JMF 0:082731ede69f 210 parser->toksuper = parser->toknext - 1;
JMF 0:082731ede69f 211 break;
JMF 0:082731ede69f 212 case '}': case ']':
JMF 0:082731ede69f 213 if (tokens == NULL)
JMF 0:082731ede69f 214 break;
JMF 0:082731ede69f 215 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
JMF 0:082731ede69f 216 #ifdef JSMN_PARENT_LINKS
JMF 0:082731ede69f 217 if (parser->toknext < 1) {
JMF 0:082731ede69f 218 return JSMN_ERROR_INVAL;
JMF 0:082731ede69f 219 }
JMF 0:082731ede69f 220 token = &tokens[parser->toknext - 1];
JMF 0:082731ede69f 221 for (;;) {
JMF 0:082731ede69f 222 if (token->start != -1 && token->end == -1) {
JMF 0:082731ede69f 223 if (token->type != type) {
JMF 0:082731ede69f 224 return JSMN_ERROR_INVAL;
JMF 0:082731ede69f 225 }
JMF 0:082731ede69f 226 token->end = parser->pos + 1;
JMF 0:082731ede69f 227 parser->toksuper = token->parent;
JMF 0:082731ede69f 228 break;
JMF 0:082731ede69f 229 }
JMF 0:082731ede69f 230 if (token->parent == -1) {
JMF 0:082731ede69f 231 if(token->type != type || parser->toksuper == -1) {
JMF 0:082731ede69f 232 return JSMN_ERROR_INVAL;
JMF 0:082731ede69f 233 }
JMF 0:082731ede69f 234 break;
JMF 0:082731ede69f 235 }
JMF 0:082731ede69f 236 token = &tokens[token->parent];
JMF 0:082731ede69f 237 }
JMF 0:082731ede69f 238 #else
JMF 0:082731ede69f 239 for (i = parser->toknext - 1; i >= 0; i--) {
JMF 0:082731ede69f 240 token = &tokens[i];
JMF 0:082731ede69f 241 if (token->start != -1 && token->end == -1) {
JMF 0:082731ede69f 242 if (token->type != type) {
JMF 0:082731ede69f 243 return JSMN_ERROR_INVAL;
JMF 0:082731ede69f 244 }
JMF 0:082731ede69f 245 parser->toksuper = -1;
JMF 0:082731ede69f 246 token->end = parser->pos + 1;
JMF 0:082731ede69f 247 break;
JMF 0:082731ede69f 248 }
JMF 0:082731ede69f 249 }
JMF 0:082731ede69f 250 /* Error if unmatched closing bracket */
JMF 0:082731ede69f 251 if (i == -1) return JSMN_ERROR_INVAL;
JMF 0:082731ede69f 252 for (; i >= 0; i--) {
JMF 0:082731ede69f 253 token = &tokens[i];
JMF 0:082731ede69f 254 if (token->start != -1 && token->end == -1) {
JMF 0:082731ede69f 255 parser->toksuper = i;
JMF 0:082731ede69f 256 break;
JMF 0:082731ede69f 257 }
JMF 0:082731ede69f 258 }
JMF 0:082731ede69f 259 #endif
JMF 0:082731ede69f 260 break;
JMF 0:082731ede69f 261 case '\"':
JMF 0:082731ede69f 262 r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
JMF 0:082731ede69f 263 if (r < 0) return r;
JMF 0:082731ede69f 264 count++;
JMF 0:082731ede69f 265 if (parser->toksuper != -1 && tokens != NULL)
JMF 0:082731ede69f 266 tokens[parser->toksuper].size++;
JMF 0:082731ede69f 267 break;
JMF 0:082731ede69f 268 case '\t' : case '\r' : case '\n' : case ' ':
JMF 0:082731ede69f 269 break;
JMF 0:082731ede69f 270 case ':':
JMF 0:082731ede69f 271 parser->toksuper = parser->toknext - 1;
JMF 0:082731ede69f 272 break;
JMF 0:082731ede69f 273 case ',':
JMF 0:082731ede69f 274 if (tokens != NULL && parser->toksuper != -1 &&
JMF 0:082731ede69f 275 tokens[parser->toksuper].type != JSMN_ARRAY &&
JMF 0:082731ede69f 276 tokens[parser->toksuper].type != JSMN_OBJECT) {
JMF 0:082731ede69f 277 #ifdef JSMN_PARENT_LINKS
JMF 0:082731ede69f 278 parser->toksuper = tokens[parser->toksuper].parent;
JMF 0:082731ede69f 279 #else
JMF 0:082731ede69f 280 for (i = parser->toknext - 1; i >= 0; i--) {
JMF 0:082731ede69f 281 if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
JMF 0:082731ede69f 282 if (tokens[i].start != -1 && tokens[i].end == -1) {
JMF 0:082731ede69f 283 parser->toksuper = i;
JMF 0:082731ede69f 284 break;
JMF 0:082731ede69f 285 }
JMF 0:082731ede69f 286 }
JMF 0:082731ede69f 287 }
JMF 0:082731ede69f 288 #endif
JMF 0:082731ede69f 289 }
JMF 0:082731ede69f 290 break;
JMF 0:082731ede69f 291 #ifdef JSMN_STRICT
JMF 0:082731ede69f 292 /* In strict mode primitives are: numbers and booleans */
JMF 0:082731ede69f 293 case '-': case '0': case '1' : case '2': case '3' : case '4':
JMF 0:082731ede69f 294 case '5': case '6': case '7' : case '8': case '9':
JMF 0:082731ede69f 295 case 't': case 'f': case 'n' :
JMF 0:082731ede69f 296 /* And they must not be keys of the object */
JMF 0:082731ede69f 297 if (tokens != NULL && parser->toksuper != -1) {
JMF 0:082731ede69f 298 jsmntok_t *t = &tokens[parser->toksuper];
JMF 0:082731ede69f 299 if (t->type == JSMN_OBJECT ||
JMF 0:082731ede69f 300 (t->type == JSMN_STRING && t->size != 0)) {
JMF 0:082731ede69f 301 return JSMN_ERROR_INVAL;
JMF 0:082731ede69f 302 }
JMF 0:082731ede69f 303 }
JMF 0:082731ede69f 304 #else
JMF 0:082731ede69f 305 /* In non-strict mode every unquoted value is a primitive */
JMF 0:082731ede69f 306 default:
JMF 0:082731ede69f 307 #endif
JMF 0:082731ede69f 308 r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
JMF 0:082731ede69f 309 if (r < 0) return r;
JMF 0:082731ede69f 310 count++;
JMF 0:082731ede69f 311 if (parser->toksuper != -1 && tokens != NULL)
JMF 0:082731ede69f 312 tokens[parser->toksuper].size++;
JMF 0:082731ede69f 313 break;
JMF 0:082731ede69f 314
JMF 0:082731ede69f 315 #ifdef JSMN_STRICT
JMF 0:082731ede69f 316 /* Unexpected char in strict mode */
JMF 0:082731ede69f 317 default:
JMF 0:082731ede69f 318 return JSMN_ERROR_INVAL;
JMF 0:082731ede69f 319 #endif
JMF 0:082731ede69f 320 }
JMF 0:082731ede69f 321 }
JMF 0:082731ede69f 322
JMF 0:082731ede69f 323 if (tokens != NULL) {
JMF 0:082731ede69f 324 for (i = parser->toknext - 1; i >= 0; i--) {
JMF 0:082731ede69f 325 /* Unmatched opened object or array */
JMF 0:082731ede69f 326 if (tokens[i].start != -1 && tokens[i].end == -1) {
JMF 0:082731ede69f 327 return JSMN_ERROR_PART;
JMF 0:082731ede69f 328 }
JMF 0:082731ede69f 329 }
JMF 0:082731ede69f 330 }
JMF 0:082731ede69f 331
JMF 0:082731ede69f 332 return count;
JMF 0:082731ede69f 333 }
JMF 0:082731ede69f 334
JMF 0:082731ede69f 335 /**
JMF 0:082731ede69f 336 * Creates a new parser based over a given buffer with an array of tokens
JMF 0:082731ede69f 337 * available.
JMF 0:082731ede69f 338 */
JMF 0:082731ede69f 339 void jsmn_init(jsmn_parser *parser) {
JMF 0:082731ede69f 340 parser->pos = 0;
JMF 0:082731ede69f 341 parser->toknext = 0;
JMF 0:082731ede69f 342 parser->toksuper = -1;
JMF 0:082731ede69f 343 }
JMF 0:082731ede69f 344