V.06 11/3

Dependencies:   FT6206 SDFileSystem SPI_TFT_ILI9341 TFT_fonts

Fork of ATT_AWS_IoT_demo by attiot

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers jsmn.cpp Source File

jsmn.cpp

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