this is fork and i will modify for STM32

Fork of AWS-test by Pierre-Marie Ancèle

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers jsmn.c Source File

jsmn.c

Go to the documentation of this file.
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