Vergil Cola
/
MQTTGateway2
Fork of my original MQTTGateway
Embed:
(wiki syntax)
Show/hide line numbers
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 Tue Jul 12 2022 18:06:46 by 1.7.2