Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of AWS-test by
jsmn.c
00001 /* 00002 * Copyright (c) 2010 Serge A. Zaitsev 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a copy 00005 * of this software and associated documentation files (the "Software"), to deal 00006 * in the Software without restriction, including without limitation the rights 00007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00008 * copies of the Software, and to permit persons to whom the Software is 00009 * furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included in 00012 * all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00020 * THE SOFTWARE. 00021 */ 00022 00023 /** 00024 * @file jsmn.c 00025 * @brief Implementation of the JSMN (Jasmine) JSON parser. 00026 * 00027 * For more information on JSMN: 00028 * @see http://zserge.com/jsmn.html 00029 */ 00030 00031 #include "jsmn.h" 00032 00033 /** 00034 * Allocates a fresh unused token from the token pull. 00035 */ 00036 static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, 00037 jsmntok_t *tokens, size_t num_tokens) { 00038 jsmntok_t *tok; 00039 if (parser->toknext >= num_tokens) { 00040 return NULL; 00041 } 00042 tok = &tokens[parser->toknext++]; 00043 tok->start = tok->end = -1; 00044 tok->size = 0; 00045 #ifdef JSMN_PARENT_LINKS 00046 tok->parent = -1; 00047 #endif 00048 return tok; 00049 } 00050 00051 /** 00052 * Fills token type and boundaries. 00053 */ 00054 static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, 00055 int start, int end) { 00056 token->type = type; 00057 token->start = start; 00058 token->end = end; 00059 token->size = 0; 00060 } 00061 00062 /** 00063 * Fills next available token with JSON primitive. 00064 */ 00065 static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, 00066 size_t len, jsmntok_t *tokens, size_t num_tokens) { 00067 jsmntok_t *token; 00068 int start; 00069 00070 start = parser->pos; 00071 00072 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { 00073 switch (js[parser->pos]) { 00074 #ifndef JSMN_STRICT 00075 /* In strict mode primitive must be followed by "," or "}" or "]" */ 00076 case ':': 00077 #endif 00078 case '\t' : case '\r' : case '\n' : case ' ' : 00079 case ',' : case ']' : case '}' : 00080 goto found; 00081 } 00082 if (js[parser->pos] < 32 || js[parser->pos] >= 127) { 00083 parser->pos = start; 00084 return JSMN_ERROR_INVAL; 00085 } 00086 } 00087 #ifdef JSMN_STRICT 00088 /* In strict mode primitive must be followed by a comma/object/array */ 00089 parser->pos = start; 00090 return JSMN_ERROR_PART; 00091 #endif 00092 00093 found: 00094 if (tokens == NULL) { 00095 parser->pos--; 00096 return 0; 00097 } 00098 token = jsmn_alloc_token(parser, tokens, num_tokens); 00099 if (token == NULL) { 00100 parser->pos = start; 00101 return JSMN_ERROR_NOMEM; 00102 } 00103 jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); 00104 #ifdef JSMN_PARENT_LINKS 00105 token->parent = parser->toksuper; 00106 #endif 00107 parser->pos--; 00108 return 0; 00109 } 00110 00111 /** 00112 * Fills next token with JSON string. 00113 */ 00114 static int jsmn_parse_string(jsmn_parser *parser, const char *js, 00115 size_t len, jsmntok_t *tokens, size_t num_tokens) { 00116 jsmntok_t *token; 00117 00118 int start = parser->pos; 00119 00120 parser->pos++; 00121 00122 /* Skip starting quote */ 00123 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { 00124 char c = js[parser->pos]; 00125 00126 /* Quote: end of string */ 00127 if (c == '\"') { 00128 if (tokens == NULL) { 00129 return 0; 00130 } 00131 token = jsmn_alloc_token(parser, tokens, num_tokens); 00132 if (token == NULL) { 00133 parser->pos = start; 00134 return JSMN_ERROR_NOMEM; 00135 } 00136 jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos); 00137 #ifdef JSMN_PARENT_LINKS 00138 token->parent = parser->toksuper; 00139 #endif 00140 return 0; 00141 } 00142 00143 /* Backslash: Quoted symbol expected */ 00144 if (c == '\\' && parser->pos + 1 < len) { 00145 int i; 00146 parser->pos++; 00147 switch (js[parser->pos]) { 00148 /* Allowed escaped symbols */ 00149 case '\"': case '/' : case '\\' : case 'b' : 00150 case 'f' : case 'r' : case 'n' : case 't' : 00151 break; 00152 /* Allows escaped symbol \uXXXX */ 00153 case 'u': 00154 parser->pos++; 00155 for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) { 00156 /* If it isn't a hex character we have an error */ 00157 if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ 00158 (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ 00159 (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ 00160 parser->pos = start; 00161 return JSMN_ERROR_INVAL; 00162 } 00163 parser->pos++; 00164 } 00165 parser->pos--; 00166 break; 00167 /* Unexpected symbol */ 00168 default: 00169 parser->pos = start; 00170 return JSMN_ERROR_INVAL; 00171 } 00172 } 00173 } 00174 parser->pos = start; 00175 return JSMN_ERROR_PART; 00176 } 00177 00178 /** 00179 * Parse JSON string and fill tokens. 00180 */ 00181 int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, 00182 jsmntok_t *tokens, unsigned int num_tokens) { 00183 int r; 00184 int i; 00185 jsmntok_t *token; 00186 int count = parser->toknext; 00187 00188 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { 00189 char c; 00190 jsmntype_t type; 00191 00192 c = js[parser->pos]; 00193 switch (c) { 00194 case '{': case '[': 00195 count++; 00196 if (tokens == NULL) { 00197 break; 00198 } 00199 token = jsmn_alloc_token(parser, tokens, num_tokens); 00200 if (token == NULL) 00201 return JSMN_ERROR_NOMEM; 00202 if (parser->toksuper != -1) { 00203 tokens[parser->toksuper].size++; 00204 #ifdef JSMN_PARENT_LINKS 00205 token->parent = parser->toksuper; 00206 #endif 00207 } 00208 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); 00209 token->start = parser->pos; 00210 parser->toksuper = parser->toknext - 1; 00211 break; 00212 case '}': case ']': 00213 if (tokens == NULL) 00214 break; 00215 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); 00216 #ifdef JSMN_PARENT_LINKS 00217 if (parser->toknext < 1) { 00218 return JSMN_ERROR_INVAL; 00219 } 00220 token = &tokens[parser->toknext - 1]; 00221 for (;;) { 00222 if (token->start != -1 && token->end == -1) { 00223 if (token->type != type) { 00224 return JSMN_ERROR_INVAL; 00225 } 00226 token->end = parser->pos + 1; 00227 parser->toksuper = token->parent; 00228 break; 00229 } 00230 if (token->parent == -1) { 00231 break; 00232 } 00233 token = &tokens[token->parent]; 00234 } 00235 #else 00236 for (i = parser->toknext - 1; i >= 0; i--) { 00237 token = &tokens[i]; 00238 if (token->start != -1 && token->end == -1) { 00239 if (token->type != type) { 00240 return JSMN_ERROR_INVAL; 00241 } 00242 parser->toksuper = -1; 00243 token->end = parser->pos + 1; 00244 break; 00245 } 00246 } 00247 /* Error if unmatched closing bracket */ 00248 if (i == -1) return JSMN_ERROR_INVAL; 00249 for (; i >= 0; i--) { 00250 token = &tokens[i]; 00251 if (token->start != -1 && token->end == -1) { 00252 parser->toksuper = i; 00253 break; 00254 } 00255 } 00256 #endif 00257 break; 00258 case '\"': 00259 r = jsmn_parse_string(parser, js, len, tokens, num_tokens); 00260 if (r < 0) return r; 00261 count++; 00262 if (parser->toksuper != -1 && tokens != NULL) 00263 tokens[parser->toksuper].size++; 00264 break; 00265 case '\t' : case '\r' : case '\n' : case ' ': 00266 break; 00267 case ':': 00268 parser->toksuper = parser->toknext - 1; 00269 break; 00270 case ',': 00271 if (tokens != NULL && parser->toksuper != -1 && 00272 tokens[parser->toksuper].type != JSMN_ARRAY && 00273 tokens[parser->toksuper].type != JSMN_OBJECT) { 00274 #ifdef JSMN_PARENT_LINKS 00275 parser->toksuper = tokens[parser->toksuper].parent; 00276 #else 00277 for (i = parser->toknext - 1; i >= 0; i--) { 00278 if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { 00279 if (tokens[i].start != -1 && tokens[i].end == -1) { 00280 parser->toksuper = i; 00281 break; 00282 } 00283 } 00284 } 00285 #endif 00286 } 00287 break; 00288 #ifdef JSMN_STRICT 00289 /* In strict mode primitives are: numbers and booleans */ 00290 case '-': case '0': case '1' : case '2': case '3' : case '4': 00291 case '5': case '6': case '7' : case '8': case '9': 00292 case 't': case 'f': case 'n' : 00293 /* And they must not be keys of the object */ 00294 if (tokens != NULL && parser->toksuper != -1) { 00295 jsmntok_t *t = &tokens[parser->toksuper]; 00296 if (t->type == JSMN_OBJECT || 00297 (t->type == JSMN_STRING && t->size != 0)) { 00298 return JSMN_ERROR_INVAL; 00299 } 00300 } 00301 #else 00302 /* In non-strict mode every unquoted value is a primitive */ 00303 default: 00304 #endif 00305 r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); 00306 if (r < 0) return r; 00307 count++; 00308 if (parser->toksuper != -1 && tokens != NULL) 00309 tokens[parser->toksuper].size++; 00310 break; 00311 00312 #ifdef JSMN_STRICT 00313 /* Unexpected char in strict mode */ 00314 default: 00315 return JSMN_ERROR_INVAL; 00316 #endif 00317 } 00318 } 00319 00320 if (tokens != NULL) { 00321 for (i = parser->toknext - 1; i >= 0; i--) { 00322 /* Unmatched opened object or array */ 00323 if (tokens[i].start != -1 && tokens[i].end == -1) { 00324 return JSMN_ERROR_PART; 00325 } 00326 } 00327 } 00328 00329 return count; 00330 } 00331 00332 /** 00333 * Creates a new parser based over a given buffer with an array of tokens 00334 * available. 00335 */ 00336 void jsmn_init(jsmn_parser *parser) { 00337 parser->pos = 0; 00338 parser->toknext = 0; 00339 parser->toksuper = -1; 00340 } 00341
Generated on Tue Jul 12 2022 11:16:37 by
