sgdk
jsmn.h
00001 /*
00002  * MIT License
00003  *
00004  * Copyright (c) 2010 Serge Zaitsev
00005  *
00006  * Permission is hereby granted, free of charge, to any person obtaining a copy
00007  * of this software and associated documentation files (the "Software"), to deal
00008  * in the Software without restriction, including without limitation the rights
00009  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00010  * copies of the Software, and to permit persons to whom the Software is
00011  * furnished to do so, subject to the following conditions:
00012  *
00013  * The above copyright notice and this permission notice shall be included in
00014  * all copies or substantial portions of the Software.
00015  *
00016  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00019  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00020  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00021  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00022  * SOFTWARE.
00023  */
00024 #ifndef JSMN_H
00025 #define JSMN_H
00026 
00027 #include "types.h"
00028 
00029 #if (MODULE_MEGAWIFI != 0)
00030 
00031 #ifdef __cplusplus
00032 extern "C" {
00033 #endif
00034 
00035 #ifdef JSMN_STATIC
00036 #define JSMN_API static
00037 #else
00038 #define JSMN_API extern
00039 #endif
00040 
00048 typedef enum {
00049   JSMN_UNDEFINED = 0,
00050   JSMN_OBJECT = 1,
00051   JSMN_ARRAY = 2,
00052   JSMN_STRING = 3,
00053   JSMN_PRIMITIVE = 4
00054 } jsmntype_t;
00055 
00056 enum jsmnerr {
00057   /* Not enough tokens were provided */
00058   JSMN_ERROR_NOMEM = -1,
00059   /* Invalid character inside JSON string */
00060   JSMN_ERROR_INVAL = -2,
00061   /* The string is not a full JSON packet, more bytes expected */
00062   JSMN_ERROR_PART = -3
00063 };
00064 
00071 typedef struct {
00072   jsmntype_t type;
00073   int start;
00074   int end;
00075   int size;
00076 #ifdef JSMN_PARENT_LINKS
00077   int parent;
00078 #endif
00079 } jsmntok_t;
00080 
00085 typedef struct {
00086   unsigned int pos;     /* offset in the JSON string */
00087   unsigned int toknext; /* next token to allocate */
00088   int toksuper;         /* superior token node, e.g. parent object or array */
00089 } jsmn_parser;
00090 
00094 JSMN_API void jsmn_init(jsmn_parser *parser);
00095 
00101 JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const unsigned int len,
00102                         jsmntok_t *tokens, const unsigned int num_tokens);
00103 
00104 #ifndef JSMN_HEADER
00105 
00108 static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens,
00109                                    const unsigned int num_tokens) {
00110   jsmntok_t *tok;
00111   if (parser->toknext >= num_tokens) {
00112     return NULL;
00113   }
00114   tok = &tokens[parser->toknext++];
00115   tok->start = tok->end = -1;
00116   tok->size = 0;
00117 #ifdef JSMN_PARENT_LINKS
00118   tok->parent = -1;
00119 #endif
00120   return tok;
00121 }
00122 
00126 static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type,
00127                             const int start, const int end) {
00128   token->type = type;
00129   token->start = start;
00130   token->end = end;
00131   token->size = 0;
00132 }
00133 
00137 static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
00138                                 const unsigned int len, jsmntok_t *tokens,
00139                                 const unsigned int num_tokens) {
00140   jsmntok_t *token;
00141   int start;
00142 
00143   start = parser->pos;
00144 
00145   for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
00146     switch (js[parser->pos]) {
00147 #ifndef JSMN_STRICT
00148     /* In strict mode primitive must be followed by "," or "}" or "]" */
00149     case ':':
00150 #endif
00151     case '\t':
00152     case '\r':
00153     case '\n':
00154     case ' ':
00155     case ',':
00156     case ']':
00157     case '}':
00158       goto found;
00159     default:
00160                    /* to quiet a warning from gcc*/
00161       break;
00162     }
00163     if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
00164       parser->pos = start;
00165       return JSMN_ERROR_INVAL;
00166     }
00167   }
00168 #ifdef JSMN_STRICT
00169   /* In strict mode primitive must be followed by a comma/object/array */
00170   parser->pos = start;
00171   return JSMN_ERROR_PART;
00172 #endif
00173 
00174 found:
00175   if (tokens == NULL) {
00176     parser->pos--;
00177     return 0;
00178   }
00179   token = jsmn_alloc_token(parser, tokens, num_tokens);
00180   if (token == NULL) {
00181     parser->pos = start;
00182     return JSMN_ERROR_NOMEM;
00183   }
00184   jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
00185 #ifdef JSMN_PARENT_LINKS
00186   token->parent = parser->toksuper;
00187 #endif
00188   parser->pos--;
00189   return 0;
00190 }
00191 
00195 static int jsmn_parse_string(jsmn_parser *parser, const char *js,
00196                              const unsigned int len, jsmntok_t *tokens,
00197                              const unsigned int num_tokens) {
00198   jsmntok_t *token;
00199 
00200   int start = parser->pos;
00201 
00202   parser->pos++;
00203 
00204   /* Skip starting quote */
00205   for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
00206     char c = js[parser->pos];
00207 
00208     /* Quote: end of string */
00209     if (c == '\"') {
00210       if (tokens == NULL) {
00211         return 0;
00212       }
00213       token = jsmn_alloc_token(parser, tokens, num_tokens);
00214       if (token == NULL) {
00215         parser->pos = start;
00216         return JSMN_ERROR_NOMEM;
00217       }
00218       jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);
00219 #ifdef JSMN_PARENT_LINKS
00220       token->parent = parser->toksuper;
00221 #endif
00222       return 0;
00223     }
00224 
00225     /* Backslash: Quoted symbol expected */
00226     if (c == '\\' && parser->pos + 1 < len) {
00227       int i;
00228       parser->pos++;
00229       switch (js[parser->pos]) {
00230       /* Allowed escaped symbols */
00231       case '\"':
00232       case '/':
00233       case '\\':
00234       case 'b':
00235       case 'f':
00236       case 'r':
00237       case 'n':
00238       case 't':
00239         break;
00240       /* Allows escaped symbol \uXXXX */
00241       case 'u':
00242         parser->pos++;
00243         for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0';
00244              i++) {
00245           /* If it isn't a hex character we have an error */
00246           if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) ||   /* 0-9 */
00247                 (js[parser->pos] >= 65 && js[parser->pos] <= 70) ||   /* A-F */
00248                 (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
00249             parser->pos = start;
00250             return JSMN_ERROR_INVAL;
00251           }
00252           parser->pos++;
00253         }
00254         parser->pos--;
00255         break;
00256       /* Unexpected symbol */
00257       default:
00258         parser->pos = start;
00259         return JSMN_ERROR_INVAL;
00260       }
00261     }
00262   }
00263   parser->pos = start;
00264   return JSMN_ERROR_PART;
00265 }
00266 
00270 JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const unsigned int len,
00271                         jsmntok_t *tokens, const unsigned int num_tokens) {
00272   int r;
00273   int i;
00274   jsmntok_t *token;
00275   int count = parser->toknext;
00276 
00277   for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
00278     char c;
00279     jsmntype_t type;
00280 
00281     c = js[parser->pos];
00282     switch (c) {
00283     case '{':
00284     case '[':
00285       count++;
00286       if (tokens == NULL) {
00287         break;
00288       }
00289       token = jsmn_alloc_token(parser, tokens, num_tokens);
00290       if (token == NULL) {
00291         return JSMN_ERROR_NOMEM;
00292       }
00293       if (parser->toksuper != -1) {
00294         jsmntok_t *t = &tokens[parser->toksuper];
00295 #ifdef JSMN_STRICT
00296         /* In strict mode an object or array can't become a key */
00297         if (t->type == JSMN_OBJECT) {
00298           return JSMN_ERROR_INVAL;
00299         }
00300 #endif
00301         t->size++;
00302 #ifdef JSMN_PARENT_LINKS
00303         token->parent = parser->toksuper;
00304 #endif
00305       }
00306       token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
00307       token->start = parser->pos;
00308       parser->toksuper = parser->toknext - 1;
00309       break;
00310     case '}':
00311     case ']':
00312       if (tokens == NULL) {
00313         break;
00314       }
00315       type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
00316 #ifdef JSMN_PARENT_LINKS
00317       if (parser->toknext < 1) {
00318         return JSMN_ERROR_INVAL;
00319       }
00320       token = &tokens[parser->toknext - 1];
00321       for (;;) {
00322         if (token->start != -1 && token->end == -1) {
00323           if (token->type != type) {
00324             return JSMN_ERROR_INVAL;
00325           }
00326           token->end = parser->pos + 1;
00327           parser->toksuper = token->parent;
00328           break;
00329         }
00330         if (token->parent == -1) {
00331           if (token->type != type || parser->toksuper == -1) {
00332             return JSMN_ERROR_INVAL;
00333           }
00334           break;
00335         }
00336         token = &tokens[token->parent];
00337       }
00338 #else
00339       for (i = parser->toknext - 1; i >= 0; i--) {
00340         token = &tokens[i];
00341         if (token->start != -1 && token->end == -1) {
00342           if (token->type != type) {
00343             return JSMN_ERROR_INVAL;
00344           }
00345           parser->toksuper = -1;
00346           token->end = parser->pos + 1;
00347           break;
00348         }
00349       }
00350       /* Error if unmatched closing bracket */
00351       if (i == -1) {
00352         return JSMN_ERROR_INVAL;
00353       }
00354       for (; i >= 0; i--) {
00355         token = &tokens[i];
00356         if (token->start != -1 && token->end == -1) {
00357           parser->toksuper = i;
00358           break;
00359         }
00360       }
00361 #endif
00362       break;
00363     case '\"':
00364       r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
00365       if (r < 0) {
00366         return r;
00367       }
00368       count++;
00369       if (parser->toksuper != -1 && tokens != NULL) {
00370         tokens[parser->toksuper].size++;
00371       }
00372       break;
00373     case '\t':
00374     case '\r':
00375     case '\n':
00376     case ' ':
00377       break;
00378     case ':':
00379       parser->toksuper = parser->toknext - 1;
00380       break;
00381     case ',':
00382       if (tokens != NULL && parser->toksuper != -1 &&
00383           tokens[parser->toksuper].type != JSMN_ARRAY &&
00384           tokens[parser->toksuper].type != JSMN_OBJECT) {
00385 #ifdef JSMN_PARENT_LINKS
00386         parser->toksuper = tokens[parser->toksuper].parent;
00387 #else
00388         for (i = parser->toknext - 1; i >= 0; i--) {
00389           if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
00390             if (tokens[i].start != -1 && tokens[i].end == -1) {
00391               parser->toksuper = i;
00392               break;
00393             }
00394           }
00395         }
00396 #endif
00397       }
00398       break;
00399 #ifdef JSMN_STRICT
00400     /* In strict mode primitives are: numbers and booleans */
00401     case '-':
00402     case '0':
00403     case '1':
00404     case '2':
00405     case '3':
00406     case '4':
00407     case '5':
00408     case '6':
00409     case '7':
00410     case '8':
00411     case '9':
00412     case 't':
00413     case 'f':
00414     case 'n':
00415       /* And they must not be keys of the object */
00416       if (tokens != NULL && parser->toksuper != -1) {
00417         const jsmntok_t *t = &tokens[parser->toksuper];
00418         if (t->type == JSMN_OBJECT ||
00419             (t->type == JSMN_STRING && t->size != 0)) {
00420           return JSMN_ERROR_INVAL;
00421         }
00422       }
00423 #else
00424     /* In non-strict mode every unquoted value is a primitive */
00425     default:
00426 #endif
00427       r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
00428       if (r < 0) {
00429         return r;
00430       }
00431       count++;
00432       if (parser->toksuper != -1 && tokens != NULL) {
00433         tokens[parser->toksuper].size++;
00434       }
00435       break;
00436 
00437 #ifdef JSMN_STRICT
00438     /* Unexpected char in strict mode */
00439     default:
00440       return JSMN_ERROR_INVAL;
00441 #endif
00442     }
00443   }
00444 
00445   if (tokens != NULL) {
00446     for (i = parser->toknext - 1; i >= 0; i--) {
00447       /* Unmatched opened object or array */
00448       if (tokens[i].start != -1 && tokens[i].end == -1) {
00449         return JSMN_ERROR_PART;
00450       }
00451     }
00452   }
00453 
00454   return count;
00455 }
00456 
00461 JSMN_API void jsmn_init(jsmn_parser *parser) {
00462   parser->pos = 0;
00463   parser->toknext = 0;
00464   parser->toksuper = -1;
00465 }
00466 
00467 #endif /* JSMN_HEADER */
00468 
00469 #ifdef __cplusplus
00470 }
00471 #endif
00472 
00473 #endif // MODULE_MEGAWIFI
00474 
00475 #endif /* JSMN_H */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines