LCOV - code coverage report
Current view: top level - common - jsmn.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 0 132 0.0 %
Date: 2018-01-11 Functions: 0 6 0.0 %

          Line data    Source code
       1             : /** @file jsmn.c https://github.com/zserge/jsmn.
       2             : Copyright (c) 2010 Serge A. Zaitsev
       3             : 
       4             : Permission is hereby granted, free of charge, to any person obtaining a copy
       5             : of this software and associated documentation files (the "Software"), to deal
       6             : in the Software without restriction, including without limitation the rights
       7             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             : copies of the Software, and to permit persons to whom the Software is
       9             : furnished to do so, subject to the following conditions:
      10             : 
      11             : The above copyright notice and this permission notice shall be included in
      12             : all copies or substantial portions of the Software.
      13             : 
      14             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             : THE SOFTWARE.
      21             : */
      22             : 
      23             : #include "jsmn.h"
      24             : 
      25             : /**
      26             :  * Allocates a fresh unused token from the token pull.
      27             :  */
      28           0 : static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
      29             :                 jsmntok_t *tokens, size_t num_tokens) {
      30             :         jsmntok_t *tok;
      31           0 :         if (parser->toknext >= num_tokens) {
      32           0 :                 return NULL;
      33             :         }
      34           0 :         tok = &tokens[parser->toknext++];
      35           0 :         tok->start = tok->end = -1;
      36           0 :         tok->size = 0;
      37             : #ifdef JSMN_PARENT_LINKS
      38             :         tok->parent = -1;
      39             : #endif
      40           0 :         return tok;
      41             : }
      42             : 
      43             : /**
      44             :  * Fills token type and boundaries.
      45             :  */
      46           0 : static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
      47             :                             int start, int end) {
      48           0 :         token->type = type;
      49           0 :         token->start = start;
      50           0 :         token->end = end;
      51           0 :         token->size = 0;
      52           0 : }
      53             : 
      54             : /**
      55             :  * Fills next available token with JSON primitive.
      56             :  */
      57           0 : static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
      58             :                 size_t len, jsmntok_t *tokens, size_t num_tokens) {
      59             :         jsmntok_t *token;
      60             :         int start;
      61             : 
      62           0 :         start = parser->pos;
      63             : 
      64           0 :         for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
      65           0 :                 switch (js[parser->pos]) {
      66             : #ifndef JSMN_STRICT
      67             :                         /* In strict mode primitive must be followed by "," or "}" or "]" */
      68             :                         case ':':
      69             : #endif
      70             :                         case '\t' : case '\r' : case '\n' : case ' ' :
      71             :                         case ','  : case ']'  : case '}' :
      72           0 :                                 goto found;
      73             :                 }
      74           0 :                 if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
      75           0 :                         parser->pos = start;
      76           0 :                         return JSMN_ERROR_INVAL;
      77             :                 }
      78             :         }
      79             : #ifdef JSMN_STRICT
      80             :         /* In strict mode primitive must be followed by a comma/object/array */
      81             :         parser->pos = start;
      82             :         return JSMN_ERROR_PART;
      83             : #endif
      84             : 
      85             : found:
      86           0 :         if (tokens == NULL) {
      87           0 :                 parser->pos--;
      88           0 :                 return 0;
      89             :         }
      90           0 :         token = jsmn_alloc_token(parser, tokens, num_tokens);
      91           0 :         if (token == NULL) {
      92           0 :                 parser->pos = start;
      93           0 :                 return JSMN_ERROR_NOMEM;
      94             :         }
      95           0 :         jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
      96             : #ifdef JSMN_PARENT_LINKS
      97             :         token->parent = parser->toksuper;
      98             : #endif
      99           0 :         parser->pos--;
     100           0 :         return 0;
     101             : }
     102             : 
     103             : /**
     104             :  * Fills next token with JSON string.
     105             :  */
     106           0 : static int jsmn_parse_string(jsmn_parser *parser, const char *js,
     107             :                 size_t len, jsmntok_t *tokens, size_t num_tokens) {
     108             :         jsmntok_t *token;
     109             : 
     110           0 :         int start = parser->pos;
     111             : 
     112           0 :         parser->pos++;
     113             : 
     114             :         /* Skip starting quote */
     115           0 :         for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
     116           0 :                 char c = js[parser->pos];
     117             : 
     118             :                 /* Quote: end of string */
     119           0 :                 if (c == '\"') {
     120           0 :                         if (tokens == NULL) {
     121           0 :                                 return 0;
     122             :                         }
     123           0 :                         token = jsmn_alloc_token(parser, tokens, num_tokens);
     124           0 :                         if (token == NULL) {
     125           0 :                                 parser->pos = start;
     126           0 :                                 return JSMN_ERROR_NOMEM;
     127             :                         }
     128           0 :                         jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
     129             : #ifdef JSMN_PARENT_LINKS
     130             :                         token->parent = parser->toksuper;
     131             : #endif
     132           0 :                         return 0;
     133             :                 }
     134             : 
     135             :                 /* Backslash: Quoted symbol expected */
     136           0 :                 if (c == '\\' && parser->pos + 1 < len) {
     137             :                         int i;
     138           0 :                         parser->pos++;
     139           0 :                         switch (js[parser->pos]) {
     140             :                                 /* Allowed escaped symbols */
     141             :                                 case '\"': case '/' : case '\\' : case 'b' :
     142             :                                 case 'f' : case 'r' : case 'n'  : case 't' :
     143           0 :                                         break;
     144             :                                 /* Allows escaped symbol \uXXXX */
     145             :                                 case 'u':
     146           0 :                                         parser->pos++;
     147           0 :                                         for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
     148             :                                                 /* If it isn't a hex character we have an error */
     149           0 :                                                 if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
     150           0 :                                                                         (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
     151           0 :                                                                         (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
     152           0 :                                                         parser->pos = start;
     153           0 :                                                         return JSMN_ERROR_INVAL;
     154             :                                                 }
     155           0 :                                                 parser->pos++;
     156             :                                         }
     157           0 :                                         parser->pos--;
     158           0 :                                         break;
     159             :                                 /* Unexpected symbol */
     160             :                                 default:
     161           0 :                                         parser->pos = start;
     162           0 :                                         return JSMN_ERROR_INVAL;
     163             :                         }
     164             :                 }
     165             :         }
     166           0 :         parser->pos = start;
     167           0 :         return JSMN_ERROR_PART;
     168             : }
     169             : 
     170             : /**
     171             :  * Parse JSON string and fill tokens.
     172             :  */
     173           0 : int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
     174             :                 jsmntok_t *tokens, unsigned int num_tokens) {
     175             :         int r;
     176             :         int i;
     177             :         jsmntok_t *token;
     178           0 :         int count = parser->toknext;
     179             : 
     180           0 :         for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
     181             :                 char c;
     182             :                 jsmntype_t type;
     183             : 
     184           0 :                 c = js[parser->pos];
     185           0 :                 switch (c) {
     186             :                         case '{': case '[':
     187           0 :                                 count++;
     188           0 :                                 if (tokens == NULL) {
     189           0 :                                         break;
     190             :                                 }
     191           0 :                                 token = jsmn_alloc_token(parser, tokens, num_tokens);
     192           0 :                                 if (token == NULL)
     193           0 :                                         return JSMN_ERROR_NOMEM;
     194           0 :                                 if (parser->toksuper != -1) {
     195           0 :                                         tokens[parser->toksuper].size++;
     196             : #ifdef JSMN_PARENT_LINKS
     197             :                                         token->parent = parser->toksuper;
     198             : #endif
     199             :                                 }
     200           0 :                                 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
     201           0 :                                 token->start = parser->pos;
     202           0 :                                 parser->toksuper = parser->toknext - 1;
     203           0 :                                 break;
     204             :                         case '}': case ']':
     205           0 :                                 if (tokens == NULL)
     206           0 :                                         break;
     207           0 :                                 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
     208             : #ifdef JSMN_PARENT_LINKS
     209             :                                 if (parser->toknext < 1) {
     210             :                                         return JSMN_ERROR_INVAL;
     211             :                                 }
     212             :                                 token = &tokens[parser->toknext - 1];
     213             :                                 for (;;) {
     214             :                                         if (token->start != -1 && token->end == -1) {
     215             :                                                 if (token->type != type) {
     216             :                                                         return JSMN_ERROR_INVAL;
     217             :                                                 }
     218             :                                                 token->end = parser->pos + 1;
     219             :                                                 parser->toksuper = token->parent;
     220             :                                                 break;
     221             :                                         }
     222             :                                         if (token->parent == -1) {
     223             :                                                 if(token->type != type || parser->toksuper == -1) {
     224             :                                                         return JSMN_ERROR_INVAL;
     225             :                                                 }
     226             :                                                 break;
     227             :                                         }
     228             :                                         token = &tokens[token->parent];
     229             :                                 }
     230             : #else
     231           0 :                                 for (i = parser->toknext - 1; i >= 0; i--) {
     232           0 :                                         token = &tokens[i];
     233           0 :                                         if (token->start != -1 && token->end == -1) {
     234           0 :                                                 if (token->type != type) {
     235           0 :                                                         return JSMN_ERROR_INVAL;
     236             :                                                 }
     237           0 :                                                 parser->toksuper = -1;
     238           0 :                                                 token->end = parser->pos + 1;
     239           0 :                                                 break;
     240             :                                         }
     241             :                                 }
     242             :                                 /* Error if unmatched closing bracket */
     243           0 :                                 if (i == -1) return JSMN_ERROR_INVAL;
     244           0 :                                 for (; i >= 0; i--) {
     245           0 :                                         token = &tokens[i];
     246           0 :                                         if (token->start != -1 && token->end == -1) {
     247           0 :                                                 parser->toksuper = i;
     248           0 :                                                 break;
     249             :                                         }
     250             :                                 }
     251             : #endif
     252           0 :                                 break;
     253             :                         case '\"':
     254           0 :                                 r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
     255           0 :                                 if (r < 0) return r;
     256           0 :                                 count++;
     257           0 :                                 if (parser->toksuper != -1 && tokens != NULL)
     258           0 :                                         tokens[parser->toksuper].size++;
     259           0 :                                 break;
     260             :                         case '\t' : case '\r' : case '\n' : case ' ':
     261           0 :                                 break;
     262             :                         case ':':
     263           0 :                                 parser->toksuper = parser->toknext - 1;
     264           0 :                                 break;
     265             :                         case ',':
     266           0 :                                 if (tokens != NULL && parser->toksuper != -1 &&
     267           0 :                                                 tokens[parser->toksuper].type != JSMN_ARRAY &&
     268           0 :                                                 tokens[parser->toksuper].type != JSMN_OBJECT) {
     269             : #ifdef JSMN_PARENT_LINKS
     270             :                                         parser->toksuper = tokens[parser->toksuper].parent;
     271             : #else
     272           0 :                                         for (i = parser->toknext - 1; i >= 0; i--) {
     273           0 :                                                 if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
     274           0 :                                                         if (tokens[i].start != -1 && tokens[i].end == -1) {
     275           0 :                                                                 parser->toksuper = i;
     276           0 :                                                                 break;
     277             :                                                         }
     278             :                                                 }
     279             :                                         }
     280             : #endif
     281             :                                 }
     282           0 :                                 break;
     283             : #ifdef JSMN_STRICT
     284             :                         /* In strict mode primitives are: numbers and booleans */
     285             :                         case '-': case '0': case '1' : case '2': case '3' : case '4':
     286             :                         case '5': case '6': case '7' : case '8': case '9':
     287             :                         case 't': case 'f': case 'n' :
     288             :                                 /* And they must not be keys of the object */
     289             :                                 if (tokens != NULL && parser->toksuper != -1) {
     290             :                                         jsmntok_t *t = &tokens[parser->toksuper];
     291             :                                         if (t->type == JSMN_OBJECT ||
     292             :                                                         (t->type == JSMN_STRING && t->size != 0)) {
     293             :                                                 return JSMN_ERROR_INVAL;
     294             :                                         }
     295             :                                 }
     296             : #else
     297             :                         /* In non-strict mode every unquoted value is a primitive */
     298             :                         default:
     299             : #endif
     300           0 :                                 r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
     301           0 :                                 if (r < 0) return r;
     302           0 :                                 count++;
     303           0 :                                 if (parser->toksuper != -1 && tokens != NULL)
     304           0 :                                         tokens[parser->toksuper].size++;
     305           0 :                                 break;
     306             : 
     307             : #ifdef JSMN_STRICT
     308             :                         /* Unexpected char in strict mode */
     309             :                         default:
     310             :                                 return JSMN_ERROR_INVAL;
     311             : #endif
     312             :                 }
     313             :         }
     314             : 
     315           0 :         if (tokens != NULL) {
     316           0 :                 for (i = parser->toknext - 1; i >= 0; i--) {
     317             :                         /* Unmatched opened object or array */
     318           0 :                         if (tokens[i].start != -1 && tokens[i].end == -1) {
     319           0 :                                 return JSMN_ERROR_PART;
     320             :                         }
     321             :                 }
     322             :         }
     323             : 
     324           0 :         return count;
     325             : }
     326             : 
     327             : /**
     328             :  * Creates a new parser based over a given  buffer with an array of tokens
     329             :  * available.
     330             :  */
     331           0 : void jsmn_init(jsmn_parser *parser) {
     332           0 :         parser->pos = 0;
     333           0 :         parser->toknext = 0;
     334           0 :         parser->toksuper = -1;
     335           0 : }
     336             : 

Generated by: LCOV version 1.10