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.
jsmn.c
00001 #include "jsmn.h" 00002 00003 /** 00004 * Allocates a fresh unused token from the token pull. 00005 */ 00006 static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, 00007 jsmntok_t *tokens, size_t num_tokens) { 00008 jsmntok_t *tok; 00009 if (parser->toknext >= num_tokens) { 00010 return NULL; 00011 } 00012 tok = &tokens[parser->toknext++]; 00013 tok->start = tok->end = -1; 00014 tok->size = 0; 00015 #ifdef JSMN_PARENT_LINKS 00016 tok->parent = -1; 00017 #endif 00018 return tok; 00019 } 00020 00021 /** 00022 * Fills token type and boundaries. 00023 */ 00024 static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, 00025 int start, int end) { 00026 token->type = type; 00027 token->start = start; 00028 token->end = end; 00029 token->size = 0; 00030 } 00031 00032 /** 00033 * Fills next available token with JSON primitive. 00034 */ 00035 static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, 00036 size_t len, jsmntok_t *tokens, size_t num_tokens) { 00037 jsmntok_t *token; 00038 int start; 00039 00040 start = parser->pos; 00041 00042 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { 00043 switch (js[parser->pos]) { 00044 #ifndef JSMN_STRICT 00045 /* In strict mode primitive must be followed by "," or "}" or "]" */ 00046 case ':': 00047 #endif 00048 case '\t' : case '\r' : case '\n' : case ' ' : 00049 case ',' : case ']' : case '}' : 00050 goto found; 00051 } 00052 if (js[parser->pos] < 32 || js[parser->pos] >= 127) { 00053 parser->pos = start; 00054 return JSMN_ERROR_INVAL; 00055 } 00056 } 00057 #ifdef JSMN_STRICT 00058 /* In strict mode primitive must be followed by a comma/object/array */ 00059 parser->pos = start; 00060 return JSMN_ERROR_PART; 00061 #endif 00062 00063 found: 00064 if (tokens == NULL) { 00065 parser->pos--; 00066 return 0; 00067 } 00068 token = jsmn_alloc_token(parser, tokens, num_tokens); 00069 if (token == NULL) { 00070 parser->pos = start; 00071 return JSMN_ERROR_NOMEM; 00072 } 00073 jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); 00074 #ifdef JSMN_PARENT_LINKS 00075 token->parent = parser->toksuper; 00076 #endif 00077 parser->pos--; 00078 return 0; 00079 } 00080 00081 /** 00082 * Fills next token with JSON string. 00083 */ 00084 static int jsmn_parse_string(jsmn_parser *parser, const char *js, 00085 size_t len, jsmntok_t *tokens, size_t num_tokens) { 00086 jsmntok_t *token; 00087 00088 int start = parser->pos; 00089 00090 parser->pos++; 00091 00092 /* Skip starting quote */ 00093 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { 00094 char c = js[parser->pos]; 00095 00096 /* Quote: end of string */ 00097 if (c == '\"') { 00098 if (tokens == NULL) { 00099 return 0; 00100 } 00101 token = jsmn_alloc_token(parser, tokens, num_tokens); 00102 if (token == NULL) { 00103 parser->pos = start; 00104 return JSMN_ERROR_NOMEM; 00105 } 00106 jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos); 00107 #ifdef JSMN_PARENT_LINKS 00108 token->parent = parser->toksuper; 00109 #endif 00110 return 0; 00111 } 00112 00113 /* Backslash: Quoted symbol expected */ 00114 if (c == '\\' && parser->pos + 1 < len) { 00115 int i; 00116 parser->pos++; 00117 switch (js[parser->pos]) { 00118 /* Allowed escaped symbols */ 00119 case '\"': case '/' : case '\\' : case 'b' : 00120 case 'f' : case 'r' : case 'n' : case 't' : 00121 break; 00122 /* Allows escaped symbol \uXXXX */ 00123 case 'u': 00124 parser->pos++; 00125 for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) { 00126 /* If it isn't a hex character we have an error */ 00127 if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ 00128 (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ 00129 (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ 00130 parser->pos = start; 00131 return JSMN_ERROR_INVAL; 00132 } 00133 parser->pos++; 00134 } 00135 parser->pos--; 00136 break; 00137 /* Unexpected symbol */ 00138 default: 00139 parser->pos = start; 00140 return JSMN_ERROR_INVAL; 00141 } 00142 } 00143 } 00144 parser->pos = start; 00145 return JSMN_ERROR_PART; 00146 } 00147 00148 /** 00149 * Parse JSON string and fill tokens. 00150 */ 00151 int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, 00152 jsmntok_t *tokens, unsigned int num_tokens) { 00153 int r; 00154 int i; 00155 jsmntok_t *token; 00156 int count = parser->toknext; 00157 00158 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { 00159 char c; 00160 jsmntype_t type; 00161 00162 c = js[parser->pos]; 00163 switch (c) { 00164 case '{': case '[': 00165 count++; 00166 if (tokens == NULL) { 00167 break; 00168 } 00169 token = jsmn_alloc_token(parser, tokens, num_tokens); 00170 if (token == NULL) 00171 return JSMN_ERROR_NOMEM; 00172 if (parser->toksuper != -1) { 00173 tokens[parser->toksuper].size++; 00174 #ifdef JSMN_PARENT_LINKS 00175 token->parent = parser->toksuper; 00176 #endif 00177 } 00178 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); 00179 token->start = parser->pos; 00180 parser->toksuper = parser->toknext - 1; 00181 break; 00182 case '}': case ']': 00183 if (tokens == NULL) 00184 break; 00185 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); 00186 #ifdef JSMN_PARENT_LINKS 00187 if (parser->toknext < 1) { 00188 return JSMN_ERROR_INVAL; 00189 } 00190 token = &tokens[parser->toknext - 1]; 00191 for (;;) { 00192 if (token->start != -1 && token->end == -1) { 00193 if (token->type != type) { 00194 return JSMN_ERROR_INVAL; 00195 } 00196 token->end = parser->pos + 1; 00197 parser->toksuper = token->parent; 00198 break; 00199 } 00200 if (token->parent == -1) { 00201 if(token->type != type || parser->toksuper == -1) { 00202 return JSMN_ERROR_INVAL; 00203 } 00204 break; 00205 } 00206 token = &tokens[token->parent]; 00207 } 00208 #else 00209 for (i = parser->toknext - 1; i >= 0; i--) { 00210 token = &tokens[i]; 00211 if (token->start != -1 && token->end == -1) { 00212 if (token->type != type) { 00213 return JSMN_ERROR_INVAL; 00214 } 00215 parser->toksuper = -1; 00216 token->end = parser->pos + 1; 00217 break; 00218 } 00219 } 00220 /* Error if unmatched closing bracket */ 00221 if (i == -1) return JSMN_ERROR_INVAL; 00222 for (; i >= 0; i--) { 00223 token = &tokens[i]; 00224 if (token->start != -1 && token->end == -1) { 00225 parser->toksuper = i; 00226 break; 00227 } 00228 } 00229 #endif 00230 break; 00231 case '\"': 00232 r = jsmn_parse_string(parser, js, len, tokens, num_tokens); 00233 if (r < 0) return r; 00234 count++; 00235 if (parser->toksuper != -1 && tokens != NULL) 00236 tokens[parser->toksuper].size++; 00237 break; 00238 case '\t' : case '\r' : case '\n' : case ' ': 00239 break; 00240 case ':': 00241 parser->toksuper = parser->toknext - 1; 00242 break; 00243 case ',': 00244 if (tokens != NULL && parser->toksuper != -1 && 00245 tokens[parser->toksuper].type != JSMN_ARRAY && 00246 tokens[parser->toksuper].type != JSMN_OBJECT) { 00247 #ifdef JSMN_PARENT_LINKS 00248 parser->toksuper = tokens[parser->toksuper].parent; 00249 #else 00250 for (i = parser->toknext - 1; i >= 0; i--) { 00251 if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { 00252 if (tokens[i].start != -1 && tokens[i].end == -1) { 00253 parser->toksuper = i; 00254 break; 00255 } 00256 } 00257 } 00258 #endif 00259 } 00260 break; 00261 #ifdef JSMN_STRICT 00262 /* In strict mode primitives are: numbers and booleans */ 00263 case '-': case '0': case '1' : case '2': case '3' : case '4': 00264 case '5': case '6': case '7' : case '8': case '9': 00265 case 't': case 'f': case 'n' : 00266 /* And they must not be keys of the object */ 00267 if (tokens != NULL && parser->toksuper != -1) { 00268 jsmntok_t *t = &tokens[parser->toksuper]; 00269 if (t->type == JSMN_OBJECT || 00270 (t->type == JSMN_STRING && t->size != 0)) { 00271 return JSMN_ERROR_INVAL; 00272 } 00273 } 00274 #else 00275 /* In non-strict mode every unquoted value is a primitive */ 00276 default: 00277 #endif 00278 r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); 00279 if (r < 0) return r; 00280 count++; 00281 if (parser->toksuper != -1 && tokens != NULL) 00282 tokens[parser->toksuper].size++; 00283 break; 00284 00285 #ifdef JSMN_STRICT 00286 /* Unexpected char in strict mode */ 00287 default: 00288 return JSMN_ERROR_INVAL; 00289 #endif 00290 } 00291 } 00292 00293 if (tokens != NULL) { 00294 for (i = parser->toknext - 1; i >= 0; i--) { 00295 /* Unmatched opened object or array */ 00296 if (tokens[i].start != -1 && tokens[i].end == -1) { 00297 return JSMN_ERROR_PART; 00298 } 00299 } 00300 } 00301 00302 return count; 00303 } 00304 00305 /** 00306 * Creates a new parser based over a given buffer with an array of tokens 00307 * available. 00308 */ 00309 void jsmn_init(jsmn_parser *parser) { 00310 parser->pos = 0; 00311 parser->toknext = 0; 00312 parser->toksuper = -1; 00313 } 00314
Generated on Fri Jul 15 2022 09:49:20 by
