jsonsax.c
changeset 1 ef7abb48573b
parent 0 d187e7fc9970
equal deleted inserted replaced
0:d187e7fc9970 1:ef7abb48573b
       
     1 /*
       
     2 Copyright (c) Fabien Ninoles <fabien@tzone.org>
       
     3 All rights reserved.
       
     4 
       
     5 Redistribution and use in source and binary forms, with or without
       
     6 modification, are permitted provided that the following conditions
       
     7 are met:
       
     8 1. Redistributions of source code must retain the above copyright
       
     9    notice, this list of conditions and the following disclaimer.
       
    10 2. Redistributions in binary form must reproduce the above copyright
       
    11    notice, this list of conditions and the following disclaimer in the
       
    12    documentation and/or other materials provided with the distribution.
       
    13 3. Neither the name of the University nor the names of its contributors
       
    14    may be used to endorse or promote products derived from this software
       
    15    without specific prior written permission.
       
    16 
       
    17 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
       
    18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
       
    20 ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
       
    21 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
       
    22 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
       
    23 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
       
    24 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
       
    25 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
       
    26 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
       
    27 SUCH DAMAGE.
       
    28 */
       
    29 
       
    30 #include "jsonsax.h"
       
    31 
       
    32 #include <assert.h>
       
    33 
       
    34 #define CASE_IS_SPACE   \
       
    35     case ' ':           \
       
    36 case '\n':              \
       
    37 case '\t':              \
       
    38 case '\r'
       
    39 
       
    40 #define CASE_IS_DIGIT  \
       
    41     case '0':          \
       
    42 case '1':              \
       
    43 case '2':              \
       
    44 case '3':              \
       
    45 case '4':              \
       
    46 case '5':              \
       
    47 case '6':              \
       
    48 case '7':              \
       
    49 case '8':              \
       
    50 case '9'
       
    51 
       
    52 
       
    53 struct _jsonsax_state
       
    54 {
       
    55   struct jsonsax_backend  m_backend;
       
    56   char                    m_lastchar;
       
    57   void*                   m_data;
       
    58 };
       
    59 
       
    60 #define JSONSAX_GETCHAR(state) \
       
    61   (state)->m_backend.m_getchar((state)->m_data)
       
    62 #define JSONSAX_ONERROR(state, err) \
       
    63   (state)->m_backend.m_onerror((state)->m_data, err)
       
    64 #define JSONSAX_ONSTART(state,type) \
       
    65   (state)->m_backend.m_onstart((state)->m_data, type)
       
    66 #define JSONSAX_ONSTOP(state,type) \
       
    67   (state)->m_backend.m_onstop((state)->m_data, type)
       
    68 
       
    69 static int jsonsax_parsevalue(struct _jsonsax_state* state);
       
    70 
       
    71 static int _jsonsax_getc(struct _jsonsax_state* state)
       
    72 {
       
    73   int c = JSONSAX_GETCHAR(state);
       
    74   if (c > 0)
       
    75   {
       
    76     state->m_lastchar = c;
       
    77     return 0;
       
    78   };
       
    79   return -1;
       
    80 }
       
    81 
       
    82 static int _jsonsax_trim(struct _jsonsax_state* state)
       
    83 {
       
    84   do
       
    85     {
       
    86       switch(state->m_lastchar)
       
    87         {
       
    88         CASE_IS_SPACE:
       
    89           break;
       
    90         default:
       
    91           return 0;
       
    92         }
       
    93     }
       
    94   while(_jsonsax_getc(state) == 0);
       
    95   return -1;
       
    96 }
       
    97 
       
    98 static int jsonsax_getc(struct _jsonsax_state* state)
       
    99 {
       
   100   int err = _jsonsax_getc(state);
       
   101   if (err == 0)
       
   102   {
       
   103     return _jsonsax_trim(state);
       
   104   }
       
   105   return err;
       
   106 }
       
   107 
       
   108 int jsonsax_parsearray(struct _jsonsax_state* state)
       
   109 {
       
   110     assert(state->m_lastchar == '[');
       
   111     int err = jsonsax_getc(state);
       
   112     if (err != 0) return err;
       
   113     while(jsonsax_parsevalue(state))
       
   114     {
       
   115         switch(state->m_lastchar)
       
   116         {
       
   117         case ',':
       
   118           jsonsax_getc(state);
       
   119           break;
       
   120         case ']':
       
   121           JSONSAX_ONSTOP(state, EJSONSAX_ARRAY);
       
   122           jsonsax_getc(state);
       
   123           return 0;
       
   124         default:
       
   125           JSONSAX_ONERROR(state, -1);
       
   126           return -1;
       
   127         }
       
   128     }
       
   129     if (state->m_lastchar != ']')
       
   130     {
       
   131       JSONSAX_ONERROR(state, -1);
       
   132       return -1;
       
   133     }
       
   134     JSONSAX_ONSTOP(state, EJSONSAX_ARRAY);
       
   135     jsonsax_getc(state);
       
   136     return 0;
       
   137 }
       
   138 
       
   139 int jsonsax_parsestring(struct _jsonsax_state* state)
       
   140 {
       
   141     assert(state->m_lastchar == '"');
       
   142     JSONSAX_ONSTART(state, EJSONSAX_STRING);
       
   143     while(jsonsax_getc(state) == 0)
       
   144     {
       
   145         switch(state->m_lastchar)
       
   146         {
       
   147         case '\\':
       
   148           jsonsax_getc(state);
       
   149           break;
       
   150         case '"':
       
   151           JSONSAX_ONSTOP(state, EJSONSAX_STRING);
       
   152           jsonsax_getc(state);
       
   153           return 0;
       
   154         }
       
   155     }
       
   156     return -1;
       
   157 }
       
   158 
       
   159 int jsonsax_parsenumber(struct _jsonsax_state* state)
       
   160 {
       
   161     assert(state->m_lastchar == '-' ||
       
   162            state->m_lastchar == '0' ||
       
   163            state->m_lastchar == '1' ||
       
   164            state->m_lastchar == '2' ||
       
   165            state->m_lastchar == '3' ||
       
   166            state->m_lastchar == '4' ||
       
   167            state->m_lastchar == '5' ||
       
   168            state->m_lastchar == '6' ||
       
   169            state->m_lastchar == '7' ||
       
   170            state->m_lastchar == '8' ||
       
   171            state->m_lastchar == '9');
       
   172 
       
   173     JSONSAX_ONSTART(state, EJSONSAX_NUMBER);
       
   174     while(jsonsax_getc(state) == 0)
       
   175     {
       
   176         switch(state->m_lastchar)
       
   177         {
       
   178             // TODO: lookup for correct number format.
       
   179         case 'e':
       
   180         case '-':
       
   181         case '.':
       
   182         CASE_IS_DIGIT:
       
   183             break;
       
   184         default:
       
   185           JSONSAX_ONSTOP(state, EJSONSAX_NUMBER);
       
   186           return -1;
       
   187         }
       
   188     }
       
   189     return 0;
       
   190 }
       
   191 
       
   192 int jsonsax_parseconstant(struct _jsonsax_state* state,
       
   193                           const char* constant,
       
   194                           enum EJSONSAX_TYPE etype)
       
   195 {
       
   196     assert(state->m_lastchar == constant[0]);
       
   197     ++constant;
       
   198     while(jsonsax_getc(state) == 0)
       
   199     {
       
   200       if (*constant == '\0') break;
       
   201       if (*constant != state->m_lastchar) break;
       
   202       constant++;
       
   203     }
       
   204 
       
   205     if (*constant == '\0')
       
   206     {
       
   207       JSONSAX_ONSTOP(state, etype);
       
   208       return 0;
       
   209     }
       
   210     else
       
   211     {
       
   212       JSONSAX_ONERROR(state, -1);
       
   213       return -1;
       
   214     }
       
   215 }
       
   216 
       
   217 int jsonsax_parsenull(struct _jsonsax_state* state)
       
   218 {
       
   219   return jsonsax_parseconstant(state, "null", EJSONSAX_NULL);
       
   220 }
       
   221 
       
   222 int jsonsax_parsetrue(struct _jsonsax_state* state)
       
   223 {
       
   224   return jsonsax_parseconstant(state, "true", EJSONSAX_TRUE);
       
   225 }
       
   226 
       
   227 int jsonsax_parsefalse(struct _jsonsax_state* state)
       
   228 {
       
   229   return jsonsax_parseconstant(state, "false", EJSONSAX_FALSE);
       
   230 }
       
   231 
       
   232 int jsonsax_parsepair(struct _jsonsax_state* state)
       
   233 {
       
   234     if (state->m_lastchar != '"')
       
   235     {
       
   236       JSONSAX_ONERROR(state, -1);
       
   237       return -1;
       
   238     }
       
   239     if (jsonsax_parsestring(state) != 0)
       
   240     {
       
   241       JSONSAX_ONERROR(state, -1);
       
   242       return -1;
       
   243     }
       
   244     if (state->m_lastchar != ':')
       
   245     {
       
   246       JSONSAX_ONERROR(state, -1);
       
   247       return -1;
       
   248     }
       
   249     if (jsonsax_getc(state) != 0)
       
   250     {
       
   251       JSONSAX_ONERROR(state, -1);
       
   252       return -1;
       
   253     }
       
   254     return jsonsax_parsevalue(state);
       
   255 }
       
   256 
       
   257 static int jsonsax_parseobject(struct _jsonsax_state* state)
       
   258 {
       
   259     assert(state->m_lastchar == '{');
       
   260     JSONSAX_ONSTART(state, EJSONSAX_OBJECT);
       
   261     jsonsax_getc(state);
       
   262     while(jsonsax_parsepair(state) == 0)
       
   263     {
       
   264         switch(state->m_lastchar)
       
   265         {
       
   266         case ',':
       
   267           jsonsax_getc(state);
       
   268           break;
       
   269         case '}':
       
   270           JSONSAX_ONSTOP(state, EJSONSAX_OBJECT);
       
   271           jsonsax_getc(state);
       
   272           return 0;
       
   273         default:
       
   274           JSONSAX_ONERROR(state, -1);
       
   275           return -1;
       
   276         }
       
   277     }
       
   278     if (state->m_lastchar != '}')
       
   279     {
       
   280       JSONSAX_ONERROR(state, -1);
       
   281       return -1;
       
   282     }
       
   283     JSONSAX_ONSTOP(state, EJSONSAX_OBJECT);
       
   284     jsonsax_getc(state);
       
   285     return 0;
       
   286 }
       
   287 
       
   288 static int jsonsax_parsevalue(struct _jsonsax_state* state)
       
   289 {
       
   290     switch(state->m_lastchar)
       
   291     {
       
   292     case '[':
       
   293         return jsonsax_parsearray(state);
       
   294     case '{':
       
   295         return jsonsax_parseobject(state);
       
   296     case '"':
       
   297         return jsonsax_parsestring(state);
       
   298     case '-':
       
   299     CASE_IS_DIGIT:
       
   300         return jsonsax_parsenumber(state);
       
   301     case 'n':
       
   302         return jsonsax_parsenull(state);
       
   303     case 't':
       
   304         return jsonsax_parsetrue(state);
       
   305     case 'f':
       
   306         return jsonsax_parsefalse(state);
       
   307     default:
       
   308         return -1;
       
   309     }
       
   310 }
       
   311 
       
   312 static int default_onevent(void* data, enum EJSONSAX_TYPE type)
       
   313 {
       
   314   return 0;
       
   315 }
       
   316 
       
   317 static void default_onerror(void* data, int error)
       
   318 {
       
   319   (void)data;
       
   320   (void)error;
       
   321 }
       
   322 
       
   323 int jsonsax_parse(struct jsonsax_backend* backend, void* data)
       
   324 {
       
   325   assert(backend != 0);
       
   326   assert(backend->m_getchar != 0);
       
   327   struct _jsonsax_state state;
       
   328   state.m_backend.m_getchar = backend->m_getchar;
       
   329   state.m_backend.m_onstart = backend->m_onstart ? backend->m_onstart : default_onevent;
       
   330   state.m_backend.m_onstop  = backend->m_onstop  ? backend->m_onstop  : default_onevent;
       
   331   state.m_backend.m_onerror = backend->m_onerror ? backend->m_onerror : default_onerror;
       
   332   state.m_data = data;
       
   333   state.m_lastchar = '\0';
       
   334   int err = jsonsax_getc(&state);
       
   335   if (err != 0) return err;
       
   336   err = jsonsax_parsevalue(&state);
       
   337   return err;
       
   338 }
       
   339 
       
   340 #undef CASE_IS_DIGIT
       
   341 #undef CASE_IS_SPACE