LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/geojson/jsonc - json_tokener.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 284 132 46.5 %
Date: 2010-01-09 Functions: 6 5 83.3 %

       1                 : /*
       2                 :  * $Id: json_tokener.c,v 1.20 2006/07/25 03:24:50 mclark Exp $
       3                 :  *
       4                 :  * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
       5                 :  * Michael Clark <michael@metaparadigm.com>
       6                 :  *
       7                 :  * This library is free software; you can redistribute it and/or modify
       8                 :  * it under the terms of the MIT license. See COPYING for details.
       9                 :  *
      10                 :  */
      11                 : 
      12                 : #include "config.h"
      13                 : 
      14                 : #include <stdio.h>
      15                 : #include <stdlib.h>
      16                 : #include <ctype.h>
      17                 : #include <string.h>
      18                 : 
      19                 : #include "bits.h"
      20                 : #include "debug.h"
      21                 : #include "printbuf.h"
      22                 : #include "arraylist.h"
      23                 : #include "json_object.h"
      24                 : #include "json_tokener.h"
      25                 : 
      26                 : #include <cpl_port.h> /* MIN and MAX macros */
      27                 : 
      28                 : #if !HAVE_STRNCASECMP && defined(_MSC_VER)
      29                 :   /* MSC has the version as _strnicmp */
      30                 : # define strncasecmp _strnicmp
      31                 : #endif /* HAVE_STRNCASECMP */
      32                 : 
      33                 : 
      34                 : static const char* json_null_str = "null";
      35                 : static const char* json_true_str = "true";
      36                 : static const char* json_false_str = "false";
      37                 : 
      38                 : const char* json_tokener_errors[] = {
      39                 :   "success",
      40                 :   "continue",
      41                 :   "nesting to deep",
      42                 :   "unexpected end of data",
      43                 :   "unexpected character",
      44                 :   "null expected",
      45                 :   "boolean expected",
      46                 :   "number expected",
      47                 :   "array value separator ',' expected",
      48                 :   "quoted object property name expected",
      49                 :   "object property name separator ':' expected",
      50                 :   "object value separator ',' expected",
      51                 :   "invalid string sequence",
      52                 :   "expected comment",
      53                 : };
      54                 : 
      55                 : 
      56              14 : struct json_tokener* json_tokener_new()
      57                 : {
      58              14 :   struct json_tokener *tok = calloc(1, sizeof(struct json_tokener));
      59              14 :   tok->pb = printbuf_new();
      60              14 :   json_tokener_reset(tok);
      61              14 :   return tok;
      62                 : }
      63                 : 
      64              14 : void json_tokener_free(struct json_tokener *tok)
      65                 : {
      66              14 :   json_tokener_reset(tok);
      67              14 :   if(tok) printbuf_free(tok->pb);
      68              14 :   free(tok);
      69              14 : }
      70                 : 
      71             630 : static void json_tokener_reset_level(struct json_tokener *tok, int depth)
      72                 : {
      73             630 :   tok->stack[depth].state = json_tokener_state_eatws;
      74             630 :   tok->stack[depth].saved_state = json_tokener_state_start;
      75             630 :   json_object_put(tok->stack[depth].current);
      76             630 :   tok->stack[depth].current = NULL;
      77             630 :   free(tok->stack[depth].obj_field_name);
      78             630 :   tok->stack[depth].obj_field_name = NULL;
      79             630 : }
      80                 : 
      81              28 : void json_tokener_reset(struct json_tokener *tok)
      82                 : {
      83                 :   int i;
      84              56 :   for(i = tok->depth; i >= 0; i--)
      85              28 :     json_tokener_reset_level(tok, i);
      86              28 :   tok->depth = 0;
      87              28 :   tok->err = json_tokener_success;
      88              28 : }
      89                 : 
      90               0 : struct json_object* json_tokener_parse(const char *str)
      91                 : {
      92                 :   struct json_tokener* tok;
      93                 :   struct json_object* obj;
      94                 : 
      95               0 :   tok = json_tokener_new();
      96               0 :   obj = json_tokener_parse_ex(tok, str, -1);
      97               0 :   if(tok->err != json_tokener_success)
      98               0 :     obj = error_ptr(-tok->err);
      99               0 :   json_tokener_free(tok);
     100               0 :   return obj;
     101                 : }
     102                 : 
     103                 : 
     104                 : #if !HAVE_STRNDUP
     105                 : /* CAW: compliant version of strndup() */
     106                 : char* strndup(const char* str, size_t n)
     107                 : {
     108               0 :   if(str) {
     109               0 :     size_t len = strlen(str);
     110               0 :     size_t nn = MIN(len,n);
     111               0 :     char* s = (char*)malloc(sizeof(char) * (nn + 1));
     112                 : 
     113               0 :     if(s) {
     114               0 :       memcpy(s, str, nn);
     115               0 :       s[nn] = '\0';
     116                 :     }
     117                 : 
     118               0 :     return s;
     119                 :   }
     120                 : 
     121               0 :   return NULL;
     122                 : }
     123                 : #endif
     124                 : 
     125                 : 
     126                 : #define state  tok->stack[tok->depth].state
     127                 : #define saved_state  tok->stack[tok->depth].saved_state
     128                 : #define current tok->stack[tok->depth].current
     129                 : #define obj_field_name tok->stack[tok->depth].obj_field_name
     130                 : 
     131              14 : struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
     132                 :             const char *str, int len)
     133                 : {
     134              14 :   struct json_object *obj = NULL;
     135                 :   char c;
     136                 : 
     137              14 :   tok->char_offset = 0;
     138              14 :   tok->err = json_tokener_success;
     139                 : 
     140                 :   do {
     141            3629 :     if(tok->char_offset == len) {
     142               0 :       if(tok->depth == 0 && state == json_tokener_state_eatws &&
     143               0 :    saved_state == json_tokener_state_finish)
     144               0 :   tok->err = json_tokener_success;
     145                 :       else
     146               0 :   tok->err = json_tokener_continue;
     147               0 :       goto out;
     148                 :     }
     149                 : 
     150            3629 :     c = *str;
     151                 :   redo_char:
     152            6204 :     switch(state) {
     153                 : 
     154                 :     case json_tokener_state_eatws:
     155            2387 :       if(isspace((unsigned char)c)) {
     156                 :   /* okay */
     157            1404 :       } else if(c == '/') {
     158               0 :   printbuf_reset(tok->pb);
     159               0 :   printbuf_memappend(tok->pb, &c, 1);
     160               0 :   state = json_tokener_state_comment_start;
     161                 :       } else {
     162            1404 :   state = saved_state;
     163            1404 :   goto redo_char;
     164                 :       }
     165             983 :       break;
     166                 : 
     167                 :     case json_tokener_state_start:
     168             315 :       switch(c) {
     169                 :       case '{':
     170              40 :   state = json_tokener_state_eatws;
     171              40 :   saved_state = json_tokener_state_object_field_start;
     172              40 :   current = json_object_new_object();
     173              40 :   break;
     174                 :       case '[':
     175             101 :   state = json_tokener_state_eatws;
     176             101 :   saved_state = json_tokener_state_array;
     177             101 :   current = json_object_new_array();
     178             101 :   break;
     179                 :       case 'N':
     180                 :       case 'n':
     181               0 :   state = json_tokener_state_null;
     182               0 :   printbuf_reset(tok->pb);
     183               0 :   tok->st_pos = 0;
     184               0 :   goto redo_char;
     185                 :       case '"':
     186                 :       case '\'':
     187              40 :   state = json_tokener_state_string;
     188              40 :   printbuf_reset(tok->pb);
     189              40 :   tok->quote_char = c;
     190              40 :   break;
     191                 :       case 'T':
     192                 :       case 't':
     193                 :       case 'F':
     194                 :       case 'f':
     195               0 :   state = json_tokener_state_boolean;
     196               0 :   printbuf_reset(tok->pb);
     197               0 :   tok->st_pos = 0;
     198               0 :   goto redo_char;
     199                 : #if defined(__GNUC__)
     200                 :     case '0' ... '9':
     201                 : #else
     202                 :     case '0':
     203                 :       case '1':
     204                 :       case '2':
     205                 :       case '3':
     206                 :       case '4':
     207                 :       case '5':
     208                 :       case '6':
     209                 :       case '7':
     210                 :       case '8':
     211                 :       case '9':
     212                 : #endif
     213                 :       case '-':
     214             134 :   state = json_tokener_state_number;
     215             134 :   printbuf_reset(tok->pb);
     216             134 :   tok->is_double = 0;
     217             134 :   goto redo_char;
     218                 :       default:
     219               0 :   tok->err = json_tokener_error_parse_unexpected;
     220               0 :   goto out;
     221                 :       }
     222             181 :       break;
     223                 : 
     224                 :     case json_tokener_state_finish:
     225             315 :       if(tok->depth == 0) goto out;
     226             301 :       obj = json_object_get(current);
     227             301 :       json_tokener_reset_level(tok, tok->depth);
     228             301 :       tok->depth--;
     229             301 :       goto redo_char;
     230                 : 
     231                 :     case json_tokener_state_null:
     232               0 :       printbuf_memappend(tok->pb, &c, 1);
     233               0 :       if(strncasecmp(json_null_str, tok->pb->buf,
     234               0 :          MIN(tok->st_pos+1, (int)strlen(json_null_str))) == 0) {
     235               0 :   if(tok->st_pos == (int)strlen(json_null_str)) {
     236               0 :     current = NULL;
     237               0 :     saved_state = json_tokener_state_finish;
     238               0 :     state = json_tokener_state_eatws;
     239               0 :     goto redo_char;
     240                 :   }
     241                 :       } else {
     242               0 :   tok->err = json_tokener_error_parse_null;
     243               0 :   goto out;
     244                 :       }
     245               0 :       tok->st_pos++;
     246               0 :       break;
     247                 : 
     248                 :     case json_tokener_state_comment_start:
     249               0 :       if(c == '*') {
     250               0 :   state = json_tokener_state_comment;
     251               0 :       } else if(c == '/') {
     252               0 :   state = json_tokener_state_comment_eol;
     253                 :       } else {
     254               0 :   tok->err = json_tokener_error_parse_comment;
     255               0 :   goto out;
     256                 :       }
     257               0 :       printbuf_memappend(tok->pb, &c, 1);
     258               0 :       break;
     259                 : 
     260                 :     case json_tokener_state_comment:
     261               0 :       if(c == '*') state = json_tokener_state_comment_end;
     262               0 :       printbuf_memappend(tok->pb, &c, 1);
     263               0 :       break;
     264                 : 
     265                 :     case json_tokener_state_comment_eol:
     266               0 :       if(c == '\n') {
     267               0 :   mc_debug("json_tokener_comment: %s\n", tok->pb->buf);
     268               0 :   state = json_tokener_state_eatws;
     269                 :       } else {
     270               0 :   printbuf_memappend(tok->pb, &c, 1);
     271                 :       }
     272               0 :       break;
     273                 : 
     274                 :     case json_tokener_state_comment_end:
     275               0 :       printbuf_memappend(tok->pb, &c, 1);
     276               0 :       if(c == '/') {
     277               0 :   mc_debug("json_tokener_comment: %s\n", tok->pb->buf);
     278               0 :   state = json_tokener_state_eatws;
     279                 :       } else {
     280               0 :   state = json_tokener_state_comment;
     281                 :       }
     282               0 :       break;
     283                 : 
     284                 :     case json_tokener_state_string:
     285             486 :       if(c == tok->quote_char) {
     286              40 :   current = json_object_new_string(tok->pb->buf);
     287              40 :   saved_state = json_tokener_state_finish;
     288              40 :   state = json_tokener_state_eatws;
     289             446 :       } else if(c == '\\') {
     290               0 :   saved_state = json_tokener_state_string;
     291               0 :   state = json_tokener_state_string_escape;
     292                 :       } else {
     293             446 :   printbuf_memappend(tok->pb, &c, 1);
     294                 :       }
     295             486 :       break;
     296                 : 
     297                 :     case json_tokener_state_string_escape:
     298               0 :       switch(c) {
     299                 :       case '"':
     300                 :       case '\\':
     301                 :       case '/':
     302               0 :   printbuf_memappend(tok->pb, &c, 1);
     303               0 :   state = saved_state;
     304               0 :   break;
     305                 :       case 'b':
     306                 :       case 'n':
     307                 :       case 'r':
     308                 :       case 't':
     309               0 :   if(c == 'b') printbuf_memappend(tok->pb, "\b", 1);
     310               0 :   else if(c == 'n') printbuf_memappend(tok->pb, "\n", 1);
     311               0 :   else if(c == 'r') printbuf_memappend(tok->pb, "\r", 1);
     312               0 :   else if(c == 't') printbuf_memappend(tok->pb, "\t", 1);
     313               0 :   state = saved_state;
     314               0 :   break;
     315                 :       case 'u':
     316               0 :   tok->ucs_char = 0;
     317               0 :   tok->st_pos = 0;
     318               0 :   state = json_tokener_state_escape_unicode;
     319               0 :   break;
     320                 :       default:
     321               0 :   tok->err = json_tokener_error_parse_string;
     322               0 :   goto out;
     323                 :       }
     324               0 :       break;
     325                 : 
     326                 :     case json_tokener_state_escape_unicode:
     327               0 :       if(strchr(json_hex_chars, c)) {
     328               0 :   tok->ucs_char += ((unsigned int)hexdigit(c) << ((3-tok->st_pos++)*4));
     329               0 :   if(tok->st_pos == 4) {
     330                 :     unsigned char utf_out[3];
     331               0 :     if (tok->ucs_char < 0x80) {
     332               0 :       utf_out[0] = (unsigned char)tok->ucs_char;
     333               0 :       printbuf_memappend(tok->pb, (char*)utf_out, 1);
     334               0 :     } else if (tok->ucs_char < 0x800) {
     335               0 :       utf_out[0] = (unsigned char)(0xc0 | (tok->ucs_char >> 6));
     336               0 :       utf_out[1] = (unsigned char)(0x80 | (tok->ucs_char & 0x3f));
     337               0 :       printbuf_memappend(tok->pb, (char*)utf_out, 2);
     338                 :     } else {
     339               0 :       utf_out[0] = (unsigned char)(0xe0 | (tok->ucs_char >> 12));
     340               0 :       utf_out[1] = (unsigned char)(0x80 | ((tok->ucs_char >> 6) & 0x3f));
     341               0 :       utf_out[2] = (unsigned char)(0x80 | (tok->ucs_char & 0x3f));
     342               0 :       printbuf_memappend(tok->pb, (char*)utf_out, 3);
     343                 :     }
     344               0 :     state = saved_state;
     345                 :   }
     346                 :       } else {
     347               0 :   tok->err = json_tokener_error_parse_string;
     348               0 :   goto out;
     349                 :       }
     350               0 :       break;
     351                 : 
     352                 :     case json_tokener_state_boolean:
     353               0 :       printbuf_memappend(tok->pb, &c, 1);
     354               0 :       if(strncasecmp(json_true_str, tok->pb->buf,
     355               0 :          MIN(tok->st_pos+1, (int)strlen(json_true_str))) == 0) {
     356               0 :   if(tok->st_pos == (int)strlen(json_true_str)) {
     357               0 :     current = json_object_new_boolean(1);
     358               0 :     saved_state = json_tokener_state_finish;
     359               0 :     state = json_tokener_state_eatws;
     360               0 :     goto redo_char;
     361                 :   }
     362               0 :       } else if(strncasecmp(json_false_str, tok->pb->buf,
     363               0 :           MIN(tok->st_pos+1, (int)strlen(json_false_str))) == 0) {
     364               0 :   if(tok->st_pos == (int)strlen(json_false_str)) {
     365               0 :     current = json_object_new_boolean(0);
     366               0 :     saved_state = json_tokener_state_finish;
     367               0 :     state = json_tokener_state_eatws;
     368               0 :     goto redo_char;
     369                 :   }
     370                 :       } else {
     371               0 :   tok->err = json_tokener_error_parse_boolean;
     372               0 :   goto out;
     373                 :       }
     374               0 :       tok->st_pos++;
     375               0 :       break;
     376                 : 
     377                 :     case json_tokener_state_number:
     378             984 :       if(c && strchr(json_number_chars, c)) {
     379             850 :   printbuf_memappend(tok->pb, &c, 1);  
     380             850 :   if(c == '.' || c == 'e' || c == 'E')
     381             134 :         tok->is_double = 1;
     382                 :       } else {
     383                 :   int numi;
     384                 :   double numd;
     385             134 :   if(!tok->is_double && sscanf(tok->pb->buf, "%d", &numi) == 1) {
     386               0 :     current = json_object_new_int(numi);
     387             268 :   } else if(tok->is_double && sscanf(tok->pb->buf, "%lf", &numd) == 1) {
     388             134 :     current = json_object_new_double(numd);
     389                 :   } else {
     390               0 :     tok->err = json_tokener_error_parse_number;
     391               0 :     goto out;
     392                 :   }
     393             134 :   saved_state = json_tokener_state_finish;
     394             134 :   state = json_tokener_state_eatws;
     395             134 :   goto redo_char;
     396                 :       }
     397             850 :       break;
     398                 : 
     399                 :     case json_tokener_state_array:
     400             215 :       if(c == ']') {
     401               0 :   saved_state = json_tokener_state_finish;
     402               0 :   state = json_tokener_state_eatws;
     403                 :       } else {
     404             215 :   if(tok->depth >= JSON_TOKENER_MAX_DEPTH-1) {
     405               0 :     tok->err = json_tokener_error_depth;
     406               0 :     goto out;
     407                 :   }
     408             215 :   state = json_tokener_state_array_add;
     409             215 :   tok->depth++;
     410             215 :   json_tokener_reset_level(tok, tok->depth);
     411             215 :   goto redo_char;
     412                 :       }
     413               0 :       break;
     414                 : 
     415                 :     case json_tokener_state_array_add:
     416             215 :       json_object_array_add(current, obj);
     417             215 :       saved_state = json_tokener_state_array_sep;
     418             215 :       state = json_tokener_state_eatws;
     419             215 :       goto redo_char;
     420                 : 
     421                 :     case json_tokener_state_array_sep:
     422             215 :       if(c == ']') {
     423             101 :   saved_state = json_tokener_state_finish;
     424             101 :   state = json_tokener_state_eatws;
     425             114 :       } else if(c == ',') {
     426             114 :   saved_state = json_tokener_state_array;
     427             114 :   state = json_tokener_state_eatws;
     428                 :       } else {
     429               0 :   tok->err = json_tokener_error_parse_array;
     430               0 :   goto out;
     431                 :       }
     432             215 :       break;
     433                 : 
     434                 :     case json_tokener_state_object_field_start:
     435              86 :       if(c == '}') {
     436               0 :   saved_state = json_tokener_state_finish;
     437               0 :   state = json_tokener_state_eatws;
     438             172 :       } else if (c == '"' || c == '\'') {
     439              86 :   tok->quote_char = c;
     440              86 :   printbuf_reset(tok->pb);
     441              86 :   state = json_tokener_state_object_field;
     442                 :       } else {
     443               0 :   tok->err = json_tokener_error_parse_object_key_name;
     444               0 :   goto out;
     445                 :       }
     446              86 :       break;
     447                 : 
     448                 :     case json_tokener_state_object_field:
     449             642 :       if(c == tok->quote_char) {
     450              86 :   obj_field_name = strdup(tok->pb->buf);
     451              86 :   saved_state = json_tokener_state_object_field_end;
     452              86 :   state = json_tokener_state_eatws;
     453             556 :       } else if(c == '\\') {
     454               0 :   saved_state = json_tokener_state_object_field;
     455               0 :   state = json_tokener_state_string_escape;
     456                 :       } else {
     457             556 :   printbuf_memappend(tok->pb, &c, 1);
     458                 :       }
     459             642 :       break;
     460                 : 
     461                 :     case json_tokener_state_object_field_end:
     462              86 :       if(c == ':') {
     463              86 :   saved_state = json_tokener_state_object_value;
     464              86 :   state = json_tokener_state_eatws;
     465                 :       } else {
     466               0 :   tok->err = json_tokener_error_parse_object_key_sep;
     467               0 :   goto out;
     468                 :       }
     469              86 :       break;
     470                 : 
     471                 :     case json_tokener_state_object_value:
     472              86 :       if(tok->depth >= JSON_TOKENER_MAX_DEPTH-1) {
     473               0 :   tok->err = json_tokener_error_depth;
     474               0 :   goto out;
     475                 :       }
     476              86 :       state = json_tokener_state_object_value_add;
     477              86 :       tok->depth++;
     478              86 :       json_tokener_reset_level(tok, tok->depth);
     479              86 :       goto redo_char;
     480                 : 
     481                 :     case json_tokener_state_object_value_add:
     482              86 :       json_object_object_add(current, obj_field_name, obj);
     483              86 :       free(obj_field_name);
     484              86 :       obj_field_name = NULL;
     485              86 :       saved_state = json_tokener_state_object_sep;
     486              86 :       state = json_tokener_state_eatws;
     487              86 :       goto redo_char;
     488                 : 
     489                 :     case json_tokener_state_object_sep:
     490              86 :       if(c == '}') {
     491              40 :   saved_state = json_tokener_state_finish;
     492              40 :   state = json_tokener_state_eatws;
     493              46 :       } else if(c == ',') {
     494              46 :   saved_state = json_tokener_state_object_field_start;
     495              46 :   state = json_tokener_state_eatws;
     496                 :       } else {
     497               0 :   tok->err = json_tokener_error_parse_object_value_sep;
     498               0 :   goto out;
     499                 :       }
     500                 :       break;
     501                 : 
     502                 :     }
     503            3615 :     str++;
     504            3615 :     tok->char_offset++;
     505            3615 :   } while(c);
     506                 : 
     507               0 :   if(state != json_tokener_state_finish &&
     508               0 :      saved_state != json_tokener_state_finish)
     509               0 :     tok->err = json_tokener_error_parse_eof;
     510                 : 
     511                 :  out:
     512              14 :   if(tok->err == json_tokener_success) return json_object_get(current);
     513               0 :   mc_debug("json_tokener_parse_ex: error %s at offset %d\n",
     514               0 :      json_tokener_errors[tok->err], tok->char_offset);
     515               0 :   return NULL;
     516                 : }

Generated by: LCOV version 1.7