- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

# json.c

    00001 /*********************************************************************************
    00002
    00003  Copyright 2006-2008 MakingThings
    00004
    00005  Licensed under the Apache License,
    00006  Version 2.0 (the "License"); you may not use this file except in compliance
    00007  with the License. You may obtain a copy of the License at
    00008
    00009  http://www.apache.org/licenses/LICENSE-2.0
    00010
    00011  Unless required by applicable law or agreed to in writing, software distributed
    00012  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    00013  CONDITIONS OF ANY KIND, either express or implied. See the License for
    00014  the specific language governing permissions and limitations under the License.
    00015
    00016 *********************************************************************************/
    00017
    00018 #include "json.h"
    00019 #include "string.h"
    00020 #include "stdio.h"
    00021 #include <stdlib.h>
    00022 #include <ctype.h>
    00023
    00024 /** \defgroup json JSON
    00025   The Make Controller JSON library provides a very small and very fast library for parsing and
    00026   generating json.
    00027
    00028   From http://www.json.org: "JSON (JavaScript Object Notation)
    00029   is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for
    00030   machines to parse and generate."
    00031
    00032   JSON is quite widely used when communicating with web servers, or other network enabled devices.
    00033   It's nice and small, and easy to work with.  It's quite well supported in many programming
    00034   environments, so it's not a bad option for a communication format when you need to talk to other
    00035   devices from the Make Controller.
    00036
    00037   \b Disclaimer - in an attempt to keep it as small and as simple as possible, this library is not
    00038   completely full featured at the moment.  It doesn't process escaped strings for you, and doesn't deal
    00039   with some of the more exotic numeric representations outlined in the JSON specification.
    00040   It does, however, work quite well for most other JSON tasks.
    00041
    00042   \section Generating
    00043   Generating JSON is pretty simple - just make successive calls to the API to add the desired
    00044   elements to your string.
    00045
    00046   You need to provide a few things:
    00047    - a JsonEncode_State variable
    00048    - the buffer in which to store the JSON string being built
    00049    - a count of how many bytes are left in that buffer
    00050    The API will update that count, so it's not too much trouble.
    00051
    00052   \code
    00053   #define MAX_JSON_LEN 256
    00054   char jsonbuf[MAX_JSON_LEN];
    00055   int remaining = MAX_JSON_LEN;
    00056   JsonEncode_State s;
    00057
    00058   char *p = jsonbuf; // keep a pointer to the current location
    00059   JsonEncode_Init(&s); // initialize our state variable
    00060   p = JsonEncode_ObjectOpen(&s, p, &remaining);
    00061   p = JsonEncode_String(&s, p, "hello", &remaining);
    00062   p = JsonEncode_Int(&s, p, 234, &remaining);
    00063   p = JsonEncode_ObjectClose(&s, p, &remaining);
    00064   // now the string in jsonbuf looks like {"hello":234} - beautifully formatted JSON
    00065   int json_len = MAX_JSON_LEN - remaining; // this is the total length of the string in jsonbuf
    00066   \endcode
    00067
    00068   \b Note - the library will add the appropriate separators (: or , usually) to the string,
    00069   depending on the context of the objects and arrays you've opened, or other data you've inserted.
    00070
    00071   \section Parsing
    00072   Parsing is done using an event-based mechanism.  This means you can register for any parse events you care
    00073   to hear about, and then be called back with their value as they're encountered in the JSON string.
    00074   Each parse process needs its own JsonDecode_State variable to keep track of where it is.
    00075
    00076   In each callback, return true to continue parsing, or return false and parsing will stop.
    00077
    00078   If you need to pass around some context that you would like available in each of the callbacks,
    00079   you can pass it to JsonDecode_Init() and it will be passed to each of the callbacks you've registered.
    00080   Otherwise, just pass 0 if you don't need it.
    00081
    00082   \code
    00083   // first, define the functions that we want to be called back on
    00084   bool on_obj_opened(void* ctx)
    00085   {
    00086     // will be called when an object has been opened...
    00087     return true; // keep parsing
    00088   }
    00089
    00090   bool on_int(void *ctx, int val)
    00091   {
    00092     iny my_json_int = val;
    00093     // called when an int is encountered...
    00094     return true; // keep parsing
    00095   }
    00096
    00097   bool on_string(void *ctx, char *string, int len)
    00098   {
    00099     // called when a string is encountered...
    00100     return true; // keep parsing
    00101   }
    00102
    00103   // Now, register these callbacks with the JSON parser.
    00104   JsonDecode_SetStartObjCallback(on_obj_opened);
    00105   JsonDecode_SetIntCallback(on_int);
    00106   JsonDecode_SetStringCallback(on_string);
    00107
    00108   // Finally, run the parser.
    00109   JsonDecode_State s;
    00110   JsonDecode_Init(&s, 0); // pass 0 if you don't need to use any special context
    00111   char jsonstr[] = "[{\"label\":\"value\",\"label2\":{\"nested\":234}}]";
    00112   JsonDecode(&s, jsonstr, strlen(jsonstr));
    00113   // now each of our callbacks will be triggered at the appropriate time
    00114   \endcode
    00115
    00116   Thanks to YAJL (http://code.google.com/p/yajl-c) for some design inspiration.
    00117   \par
    00118
    00119   \ingroup Libraries
    00120   @{
    00121 */
    00122
    00123 static void JsonEncode_AppendedAtom(JsonEncode_State* state);
    00124
    00125 /**
    00126   Initialize or reset the state of a JsonEncode_State variable.
    00127   Be sure to do this each time before you start parsing.
    00128 */
    00129 void JsonEncode_Init(JsonEncode_State* state)
    00130 {
    00131   state->depth = 0;
    00132   state->steps[0] = JSON_START;
    00133 }
    00134
    00135 /**
    00136   Open up a new JSON object.
    00137   This adds an opening '{' to the json string.
    00138   @param state A pointer to the JsonEncode_State variable being used for this encode process.
    00139   @param buf A pointer to the buffer holding the JSON string.
    00140   @param remaining A pointer to the count of how many bytes are left in your JSON buffer.
    00141   @return A pointer to the location in the JSON buffer after this element has been added, or NULL if there was no room.
    00142 */
    00143 char* JsonEncode_ObjectOpen(JsonEncode_State* state, char *buf, int *remaining)
    00144 {
    00145   if( !buf )
    00146     return 0;
    00147   int len = 1;
    00148   switch(state->steps[state->depth])
    00149   {
    00150     case JSON_ARRAY_START:
    00151     case JSON_OBJ_START:
    00152     case JSON_START:
    00153     {
    00154       if(*remaining < len)
    00155         return NULL;
    00156       memcpy(buf, "{", len);
    00157       break;
    00158     }
    00159     case JSON_OBJ_KEY:
    00160     case JSON_IN_ARRAY:
    00161     {
    00162       len += 1; // for ,
    00163       if(*remaining < len)
    00164         return NULL;
    00165       memcpy(buf, ",{", len);
    00166       break;
    00167     }
    00168     case JSON_OBJ_VALUE:
    00169     {
    00170       len += 1; // for :
    00171       if(*remaining < len)
    00172         return NULL;
    00173       memcpy(buf, ":{", len);
    00174       break;
    00175     }
    00176   }
    00177
    00178   if(++state->depth > JSON_MAX_DEPTH)
    00179     return NULL;
    00180   state->steps[state->depth] = JSON_OBJ_START;
    00181   (*remaining) -= len;
    00182   return buf + len;
    00183 }
    00184
    00185 /**
    00186   Set the key for a JSON object.
    00187   This is a convenience function that simply calls JsonEncode_String().
    00188   It is provided to help enforce the idea that the first member of a JSON
    00189   object pair must be a string.
    00190   @see JsonEncode_String()
    00191 */
    00192 char* JsonEncode_ObjectKey(JsonEncode_State* state, char *buf, const char *key, int *remaining)
    00193 {
    00194   return JsonEncode_String(state, buf, key, remaining);
    00195 }
    00196
    00197 /**
    00198   Close a JSON object.
    00199   Adds a closing '}' to the string.
    00200   @param state A pointer to the JsonEncode_State variable being used for this encode process.
    00201   @param buf A pointer to the buffer which contains your JSON string.
    00202   @param remaining A pointer to an integer keeping track of how many bytes are left in your JSON buffer.
    00203   @return A pointer to the location in the JSON buffer after this element has been added, or NULL if there was no room.
    00204 */
    00205 char* JsonEncode_ObjectClose(JsonEncode_State* state, char *buf, int *remaining)
    00206 {
    00207   if(*remaining < 1 || !buf )
    00208     return NULL;
    00209   memcpy(buf, "}", 1);
    00210   state->depth--;
    00211   JsonEncode_AppendedAtom(state);
    00212   (*remaining)--;
    00213   return buf + 1;
    00214 }
    00215
    00216 /**
    00217   Open up a new JSON array.
    00218   This adds an opening '[' to the json string.
    00219   @param state A pointer to the JsonEncode_State variable being used for this encode process.
    00220   @param buf A pointer to the buffer holding the JSON string.
    00221   @param remaining A pointer to the count of how many bytes are left in your JSON buffer.
    00222   @return A pointer to the location in the JSON buffer after this element has been added, or NULL if there was no room.
    00223 */
    00224 char* JsonEncode_ArrayOpen(JsonEncode_State* state, char *buf, int *remaining)
    00225 {
    00226   if( !buf )
    00227     return 0;
    00228   int len = 1;
    00229   switch(state->steps[state->depth])
    00230   {
    00231     case JSON_ARRAY_START:
    00232     case JSON_OBJ_START:
    00233     case JSON_START:
    00234     {
    00235       if(*remaining < len)
    00236         return NULL;
    00237       memcpy(buf, "[", len);
    00238       break;
    00239     }
    00240     case JSON_OBJ_KEY:
    00241     case JSON_IN_ARRAY:
    00242     {
    00243       len += 1; // for ,
    00244       if(*remaining < len)
    00245         return NULL;
    00246       memcpy(buf, ",[", len);
    00247       break;
    00248     }
    00249     case JSON_OBJ_VALUE:
    00250     {
    00251       len += 1; // for :
    00252       if(*remaining < len)
    00253         return NULL;
    00254       memcpy(buf, ":[", len);
    00255       break;
    00256     }
    00257   }
    00258   if(++state->depth > JSON_MAX_DEPTH)
    00259     return NULL;
    00260   state->steps[state->depth] = JSON_ARRAY_START;
    00261   (*remaining) -= len;
    00262   return buf + len;
    00263 }
    00264
    00265 /**
    00266   Close an array.
    00267   Adds a closing ']' to the string.
    00268   @param state A pointer to the JsonEncode_State variable being used for this encode process.
    00269   @param buf A pointer to the buffer which contains your JSON string.
    00270   @param remaining A pointer to the count of how many bytes are left in your JSON buffer.
    00271   @return A pointer to the JSON buffer after this element has been added, or NULL if there was no room.
    00272 */
    00273 char* JsonEncode_ArrayClose(JsonEncode_State* state, char *buf, int *remaining)
    00274 {
    00275   if(*remaining < 1 || !buf )
    00276     return NULL;
    00277   memcpy(buf, "]", 1);
    00278   state->depth--;
    00279   JsonEncode_AppendedAtom(state);
    00280   (*remaining)--;
    00281   return buf + 1;
    00282 }
    00283
    00284 /**
    00285   Add a string to the current JSON string.
    00286   Depending on whether you've opened objects, arrays, or other inserted
    00287   other data, the approprate separating symbols will be added to the string.
    00288
    00289   @param state A pointer to the JsonEncode_State variable being used for this encode process.
    00290   @param buf A pointer to the buffer containing the JSON string.
    00291   @param string The string to be added.
    00292   @param remaining A pointer to the count of bytes remaining in the JSON buffer.
    00293   @return A pointer to the JSON buffer after this element has been added, or NULL if there was no room.
    00294 */
    00295 char* JsonEncode_String(JsonEncode_State* state, char *buf, const char *string, int *remaining)
    00296 {
    00297   if( !buf )
    00298     return 0;
    00299   int string_len = strlen(string) + 2 /* quotes */;
    00300
    00301   switch(state->steps[state->depth])
    00302   {
    00303     case JSON_ARRAY_START:
    00304     case JSON_OBJ_START:
    00305     {
    00306       if(*remaining < string_len)
    00307         return NULL;
    00308       char temp[string_len+1];
    00309       snprintf(temp, string_len+1, "\"%s\"", string);
    00310       memcpy(buf, temp, string_len);
    00311       break;
    00312     }
    00313     case JSON_OBJ_KEY:
    00314     case JSON_IN_ARRAY:
    00315     {
    00316       string_len += 1; // for ,
    00317       if(*remaining < string_len)
    00318         return NULL;
    00319       char temp[string_len+1];
    00320       snprintf(temp, string_len+1, ",\"%s\"", string);
    00321       memcpy(buf, temp, string_len);
    00322       break;
    00323     }
    00324     case JSON_OBJ_VALUE:
    00325     {
    00326       string_len += 1; // for :
    00327       if(*remaining < string_len)
    00328         return NULL;
    00329       char temp[string_len+1];
    00330       snprintf(temp, string_len+1, ":\"%s\"", string);
    00331       memcpy(buf, temp, string_len);
    00332       break;
    00333     }
    00334     default:
    00335       return NULL;
    00336   }
    00337   JsonEncode_AppendedAtom(state);
    00338   (*remaining) -= string_len;
    00339   return buf + string_len;
    00340 }
    00341
    00342 /**
    00343   Add an int to a JSON string.
    00344
    00345   @param state A pointer to the JsonEncode_State variable being used for this encode process.
    00346   @param buf A pointer to the buffer containing the JSON string.
    00347   @param value The integer to be added.
    00348   @param remaining A pointer to the count of bytes remaining in the JSON buffer.
    00349   @return A pointer to the JSON buffer after this element has been added, or NULL if there was no room.
    00350 */
    00351 char* JsonEncode_Int(JsonEncode_State* state, char *buf, int value, int *remaining)
    00352 {
    00353   if( !buf )
    00354     return 0;
    00355   int int_as_str_len = 11; // largest 32-bit int is 10 digits long, and also leave room for a +/-
    00356   int int_len = 0;
    00357   switch(state->steps[state->depth])
    00358   {
    00359     case JSON_ARRAY_START:
    00360     {
    00361       char temp[int_as_str_len+1];
    00362       snprintf(temp, int_as_str_len+1, "%d", value);
    00363       int_len = strlen(temp);
    00364       if(*remaining < int_len)
    00365         return NULL;
    00366       memcpy(buf, temp, int_len);
    00367       break;
    00368     }
    00369     case JSON_IN_ARRAY:
    00370     {
    00371       int_as_str_len += 1; // for ,
    00372       char temp[int_as_str_len+1];
    00373       snprintf(temp, int_as_str_len+1, ",%d", value);
    00374       int_len = strlen(temp);
    00375       if(*remaining < int_len)
    00376         return NULL;
    00377       memcpy(buf, temp, int_len);
    00378       break;
    00379     }
    00380     case JSON_OBJ_VALUE:
    00381     {
    00382       int_as_str_len += 1; // for :
    00383       char temp[int_as_str_len+1];
    00384       snprintf(temp, int_as_str_len+1, ":%d", value);
    00385       int_len = strlen(temp);
    00386       if(*remaining < int_len)
    00387         return NULL;
    00388       memcpy(buf, temp, int_len);
    00389       break;
    00390     }
    00391     default:
    00392       return NULL; // bogus state
    00393   }
    00394   JsonEncode_AppendedAtom(state);
    00395   (*remaining) -= int_len;
    00396   return buf + int_len;
    00397 }
    00398
    00399 /**
    00400   Add a boolean value to a JSON string.
    00401
    00402   @param state A pointer to the JsonEncode_State variable being used for this encode process.
    00403   @param buf A pointer to the buffer containing the JSON string.
    00404   @param value The boolean value to be added.
    00405   @param remaining A pointer to the count of bytes remaining in the JSON buffer.
    00406   @return A pointer to the JSON buffer after this element has been added, or NULL if there was no room.
    00407 */
    00408 char* JsonEncode_Bool(JsonEncode_State* state, char *buf, bool value, int *remaining)
    00409 {
    00410   if( !buf )
    00411     return 0;
    00412   const char* boolval = (value) ? "true" : "false";
    00413   int bool_len = strlen(boolval);
    00414   switch(state->steps[state->depth])
    00415   {
    00416     case JSON_ARRAY_START:
    00417     {
    00418       if(*remaining < bool_len)
    00419         return NULL;
    00420       char temp[bool_len+1];
    00421       snprintf(temp, bool_len+1, "%s", boolval);
    00422       memcpy(buf, temp, bool_len);
    00423       break;
    00424     }
    00425     case JSON_IN_ARRAY:
    00426     {
    00427       bool_len += 1; // for ,
    00428       if(*remaining < bool_len)
    00429         return NULL;
    00430       char temp[bool_len+1];
    00431       snprintf(temp, bool_len+1, ",%s", boolval);
    00432       memcpy(buf, temp, bool_len);
    00433       break;
    00434     }
    00435     case JSON_OBJ_VALUE:
    00436     {
    00437       bool_len += 1; // for :
    00438       if(*remaining < bool_len)
    00439         return NULL;
    00440       char temp[bool_len+1];
    00441       snprintf(temp, bool_len+1, ":%s", boolval);
    00442       memcpy(buf, temp, bool_len);
    00443       break;
    00444     }
    00445     default:
    00446       return NULL; // bogus state
    00447   }
    00448   JsonEncode_AppendedAtom(state);
    00449   (*remaining) -= bool_len;
    00450   return buf + bool_len;
    00451 }
    00452
    00453 /*
    00454   Called after adding a new value (atom) to a string in order
    00455   to update the state appropriately.
    00456 */
    00457 // static
    00458 void JsonEncode_AppendedAtom(JsonEncode_State* state)
    00459 {
    00460   switch(state->steps[state->depth])
    00461   {
    00462     case JSON_OBJ_START:
    00463     case JSON_OBJ_KEY:
    00464       state->steps[state->depth] = JSON_OBJ_VALUE;
    00465       break;
    00466     case JSON_ARRAY_START:
    00467       state->steps[state->depth] = JSON_IN_ARRAY;
    00468       break;
    00469     case JSON_OBJ_VALUE:
    00470       state->steps[state->depth] = JSON_OBJ_KEY;
    00471       break;
    00472     default:
    00473       break;
    00474   }
    00475 }
    00476
    00477 /****************************************************************************
    00478  JsonDecode
    00479 ****************************************************************************/
    00480
    00481 typedef enum {
    00482     token_true,
    00483     token_false,
    00484     token_colon,
    00485     token_comma,
    00486     token_eof,
    00487     token_error,
    00488     token_left_brace,
    00489     token_left_bracket,
    00490     token_null,
    00491     token_right_brace,
    00492     token_right_bracket,
    00493     token_number,
    00494     token_maybe_negative,
    00495     token_string,
    00496     token_unknown
    00497 } JsonDecode_Token;
    00498
    00499 struct
    00500 {
    00501   bool(*null_callback)(void*);
    00502   bool(*bool_callback)(void*, bool);
    00503   bool(*int_callback)(void*, int);
    00504   bool(*float_callback)(void*, float);
    00505   bool(*string_callback)(void*, char*, int);
    00506   bool(*start_obj_callback)(void*);
    00507   bool(*obj_key_callback)(void*, char*, int);
    00508   bool(*end_obj_callback)(void*);
    00509   bool(*start_array_callback)(void*);
    00510   bool(*end_array_callback)(void*);
    00511 } JsonDecode_Callbacks;
    00512
    00513 static JsonDecode_Token JsonDecode_GetToken(char* text, int len);
    00514
    00515 /**
    00516   Set the function to be called back when an integer is parsed.
    00517   The function must have the format:
    00518   \code
    00519   bool on_int(void* context, int value);
    00520   \endcode
    00521   which would then be registered like so:
    00522   \code
    00523   JsonDecode_SetIntCallback(on_int);
    00524   \endcode
    00525   The \b context parameter will be set to whatever you originally passed to
    00526   JsonDecode_Init().  Since each JsonDecode_State can have a different context,
    00527   this makes it convenient to know in your callback which one you're currently parsing.
    00528
    00529   @param int_callback The function to be called back.
    00530 */
    00531 void JsonDecode_SetIntCallback(bool(*int_callback)(void *ctx, int val))
    00532 {
    00533   JsonDecode_Callbacks.int_callback = int_callback;
    00534 }
    00535
    00536 /**
    00537   Set the function to be called back when a float is parsed.
    00538   The function must have the format:
    00539   \code
    00540   bool on_float(void* context, float value);
    00541   \endcode
    00542   which would then be registered like so:
    00543   \code
    00544   JsonDecode_SetFloatCallback(on_float);
    00545   \endcode
    00546   The \b context parameter will be set to whatever you originally passed to
    00547   JsonDecode_Init().  Since each JsonDecode_State can have a different context,
    00548   this makes it convenient to know in your callback which one you're currently parsing.
    00549
    00550   @param float_callback The function to be called back.
    00551 */
    00552 void JsonDecode_SetFloatCallback(bool(*float_callback)(void *ctx, float val))
    00553 {
    00554   JsonDecode_Callbacks.float_callback = float_callback;
    00555 }
    00556
    00557 /**
    00558   Set the function to be called back when a boolean is parsed.
    00559   The function must have the format:
    00560   \code
    00561   bool on_bool(void* context, bool value);
    00562   \endcode
    00563   which would then be registered like so:
    00564   \code
    00565   JsonDecode_SetBoolCallback(on_bool);
    00566   \endcode
    00567   The \b context parameter will be set to whatever you originally passed to
    00568   JsonDecode_Init().  Since each JsonDecode_State can have a different context,
    00569   this makes it convenient to know in your callback which one you're currently parsing.
    00570
    00571   @param bool_callback The function to be called back.
    00572 */
    00573 void JsonDecode_SetBoolCallback(bool(*bool_callback)(void *ctx, bool val))
    00574 {
    00575   JsonDecode_Callbacks.bool_callback = bool_callback;
    00576 }
    00577
    00578 /**
    00579   Set the function to be called back when a string is parsed.
    00580
    00581   \b Note - escaped elements in strings are respected, but not processed/removed
    00582   from the string at the moment, since the internal implementation simply points
    00583   to the string in the original data.  If you have escaped data, you'll need to
    00584   handle it in your code.
    00585
    00586   The function must have the format:
    00587   \code
    00588   bool on_string(void* context, char* string);
    00589   \endcode
    00590   which would then be registered like so:
    00591   \code
    00592   JsonDecode_SetStringCallback(on_string);
    00593   \endcode
    00594   The \b context parameter will be set to whatever you originally passed to
    00595   JsonDecode_Init().  Since each JsonDecode_State can have a different context,
    00596   this makes it convenient to know in your callback which one you're currently parsing.
    00597
    00598   @param string_callback The function to be called back.
    00599 */
    00600 void JsonDecode_SetStringCallback(bool(*string_callback)(void *ctx, char *string, int len))
    00601 {
    00602   JsonDecode_Callbacks.string_callback = string_callback;
    00603 }
    00604
    00605 /**
    00606   Set the function to be called back when an object is started.
    00607   The left bracket - { - is the opening element of an object.
    00608   The function must have the format:
    00609   \code
    00610   bool on_obj_started(void* context);
    00611   \endcode
    00612   which would then be registered like so:
    00613   \code
    00614   JsonDecode_SetStartObjCallback(on_obj_started);
    00615   \endcode
    00616   The \b context parameter will be set to whatever you originally passed to
    00617   JsonDecode_Init().  Since each JsonDecode_State can have a different context,
    00618   this makes it convenient to know in your callback which one you're currently parsing.
    00619
    00620   @param start_obj_callback The function to be called back.
    00621 */
    00622 void JsonDecode_SetStartObjCallback(bool(*start_obj_callback)(void *ctx))
    00623 {
    00624   JsonDecode_Callbacks.start_obj_callback = start_obj_callback;
    00625 }
    00626
    00627 /**
    00628   Set the function to be called back when the key of a key-value pair has been encountered.
    00629   A key must always be a string in JSON, so you'll get the string back.  This is particularly
    00630   helpful for setting how the next element (the value in the key-value pair) should be handled.
    00631
    00632   The function must have the format:
    00633   \code
    00634   bool on_obj_key(void* context);
    00635   \endcode
    00636   which would then be registered like so:
    00637   \code
    00638   JsonDecode_SetObjKeyCallback(on_obj_key);
    00639   \endcode
    00640   The \b context parameter will be set to whatever you originally passed to
    00641   JsonDecode_Init().  Since each JsonDecode_State can have a different context,
    00642   this makes it convenient to know in your callback which one you're currently parsing.
    00643
    00644   @param obj_key_callback The function to be called back.
    00645 */
    00646 void JsonDecode_SetObjKeyCallback(bool(*obj_key_callback)(void *ctx, char *key, int len))
    00647 {
    00648   JsonDecode_Callbacks.obj_key_callback = obj_key_callback;
    00649 }
    00650
    00651 /**
    00652   Set the function to be called back when an object is ended.
    00653   The right bracket - } - is the closing element of an object.
    00654   The function must have the format:
    00655   \code
    00656   bool on_obj_ended(void* context);
    00657   \endcode
    00658   which would then be registered like so:
    00659   \code
    00660   JsonDecode_SetEndObjCallback(on_obj_ended);
    00661   \endcode
    00662   The \b context parameter will be set to whatever you originally passed to
    00663   JsonDecode_Init().  Since each JsonDecode_State can have a different context,
    00664   this makes it convenient to know in your callback which one you're currently parsing.
    00665
    00666   @param end_obj_callback The function to be called back.
    00667 */
    00668 void JsonDecode_SetEndObjCallback(bool(*end_obj_callback)(void *ctx))
    00669 {
    00670   JsonDecode_Callbacks.end_obj_callback = end_obj_callback;
    00671 }
    00672
    00673 /**
    00674   Set the function to be called back when an array is started.
    00675   The left brace - [ - is the starting element of an array.
    00676   The function must have the format:
    00677   \code
    00678   bool on_array_started(void* context);
    00679   \endcode
    00680   which would then be registered like so:
    00681   \code
    00682   JsonDecode_SetStartArrayCallback(on_array_started);
    00683   \endcode
    00684   The \b context parameter will be set to whatever you originally passed to
    00685   JsonDecode_Init().  Since each JsonDecode_State can have a different context,
    00686   this makes it convenient to know in your callback which one you're currently parsing.
    00687
    00688   @param start_array_callback The function to be called back.
    00689 */
    00690 void JsonDecode_SetStartArrayCallback(bool(*start_array_callback)(void *ctx))
    00691 {
    00692   JsonDecode_Callbacks.start_array_callback = start_array_callback;
    00693 }
    00694
    00695 /**
    00696   Set the function to be called back when an array is ended.
    00697   The right brace - ] - is the closing element of an array.
    00698   The function must have the format:
    00699   \code
    00700   bool on_array_ended(void* context);
    00701   \endcode
    00702   which would then be registered like so:
    00703   \code
    00704   JsonDecode_SetEndArrayCallback(on_array_ended);
    00705   \endcode
    00706   The \b context parameter will be set to whatever you originally passed to
    00707   JsonDecode_Init().  Since each JsonDecode_State can have a different context,
    00708   this makes it convenient to know in your callback which one you're currently parsing.
    00709
    00710   @param end_array_callback The function to be called back.
    00711 */
    00712 void JsonDecode_SetEndArrayCallback(bool(*end_array_callback)(void *ctx))
    00713 {
    00714   JsonDecode_Callbacks.end_array_callback = end_array_callback;
    00715 }
    00716
    00717 /**
    00718   Initialize or reset a JsonDecode_State variable.
    00719   Do this prior to making a call to JsonDecode().
    00720   @param state A pointer to the JsonDecode_State variable being used for this decode process.
    00721   @param context An optional paramter that your code can use to
    00722   pass around a known object within the callbacks.  Otherwise, just set it to 0
    00723 */
    00724 void JsonDecode_Init(JsonDecode_State* state, void* context)
    00725 {
    00726   state->depth = 0;
    00727   state->gotcomma = false;
    00728   state->context = context;
    00729   state->p = 0;
    00730   state->len = 0;
    00731 }
    00732
    00733 /**
    00734   Parse a JSON string.
    00735   The JSON parser is event based, meaning that you will receive any callbacks
    00736   you registered for as the elements are encountered in the JSON string.
    00737
    00738   @param state A pointer to the JsonDecode_State variable being used for this decode process.
    00739   @param text The JSON string to parse.
    00740   @param len The length of the JSON string.
    00741   @return True on a successful parse, false on failure.
    00742
    00743   \par Example
    00744   \code
    00745   // quotes are escaped since I'm writing it out manually
    00746   JsonDecode_State s;
    00747   char jsonstr[] = "[{\"label\":\"value\",\"label2\":{\"nested\":234}}]";
    00748   JsonDecode_Init(&s, 0);
    00749   JsonDecode(jsonstr, strlen(jsonstr), 0); // don't pass in any context
    00750   // now we expect to be called back on any callbacks we registered.
    00751   \endcode
    00752 */
    00753 bool JsonDecode(JsonDecode_State* state, char* text, int len)
    00754 {
    00755   JsonDecode_Token token;
    00756
    00757   // if these haven't been initialized, do it
    00758   if(!state->p)
    00759     state->p = text;
    00760   if(!state->len)
    00761     state->len = len;
    00762
    00763   while(state->len)
    00764   {
    00765     while(*state->p == ' ') // eat white space
    00766       state->p++;
    00767     token = JsonDecode_GetToken( state->p, state->len);
    00768     switch(token)
    00769     {
    00770       case token_true:
    00771         if(JsonDecode_Callbacks.bool_callback)
    00772         {
    00773           if(!JsonDecode_Callbacks.bool_callback(state->context, true))
    00774             return false;
    00775         }
    00776         state->p += 4;
    00777         state->len -= 4;
    00778         break;
    00779       case token_false:
    00780         if(JsonDecode_Callbacks.bool_callback)
    00781         {
    00782           if(!JsonDecode_Callbacks.bool_callback(state->context, false))
    00783             return false;
    00784         }
    00785         state->p += 5;
    00786         state->len -= 5;
    00787         break;
    00788       case token_null:
    00789         if(JsonDecode_Callbacks.null_callback)
    00790         {
    00791           if(!JsonDecode_Callbacks.null_callback(state->context))
    00792             return false;
    00793         }
    00794         state->p += 4;
    00795         state->len -= 4;
    00796         break;
    00797       case token_comma:
    00798         state->gotcomma = true;
    00799         // intentional fall-through
    00800       case token_colon: // just get the next one
    00801         state->p++;
    00802         state->len--;
    00803         break;
    00804       case token_left_bracket:
    00805         state->steps[++state->depth] = JSON_DECODE_OBJECT_START;
    00806         if(JsonDecode_Callbacks.start_obj_callback)
    00807         {
    00808           if(!JsonDecode_Callbacks.start_obj_callback(state->context))
    00809             return false;
    00810         }
    00811         state->p++;
    00812         state->len--;
    00813         break;
    00814       case token_right_bracket:
    00815         state->depth--;
    00816         if(JsonDecode_Callbacks.end_obj_callback)
    00817         {
    00818           if(!JsonDecode_Callbacks.end_obj_callback(state->context))
    00819             return false;
    00820         }
    00821         state->p++;
    00822         state->len--;
    00823         break;
    00824       case token_left_brace:
    00825         state->steps[++state->depth] = JSON_DECODE_IN_ARRAY;
    00826         if(JsonDecode_Callbacks.start_array_callback)
    00827         {
    00828           if(!JsonDecode_Callbacks.start_array_callback(state->context))
    00829             return false;
    00830         }
    00831         state->p++;
    00832         state->len--;
    00833         break;
    00834       case token_right_brace:
    00835         state->depth--;
    00836         if(JsonDecode_Callbacks.end_array_callback)
    00837         {
    00838           if(!JsonDecode_Callbacks.end_array_callback(state->context))
    00839             return false;
    00840         }
    00841         state->p++;
    00842         state->len--;
    00843         break;
    00844       case token_number:
    00845       {
    00846         const char* p = state->p;
    00847         bool keepgoing = true;
    00848         bool gotdecimal = false;
    00849         do
    00850         {
    00851           if(*p == '.')
    00852           {
    00853             if(gotdecimal) // we only expect to get one decimal place in a number
    00854               return false;
    00855             gotdecimal = true;
    00856             p++;
    00857           }
    00858           else if(!isdigit(*p))
    00859             keepgoing = false;
    00860           else
    00861             p++;
    00862         } while(keepgoing);
    00863         int size = p - state->p;
    00864         if(gotdecimal)
    00865         {
    00866           if(JsonDecode_Callbacks.float_callback)
    00867           {
    00868             if(!JsonDecode_Callbacks.float_callback(state->context, atof(state->p)))
    00869               return false;
    00870           }
    00871         }
    00872         else
    00873         {
    00874           if(JsonDecode_Callbacks.int_callback)
    00875           {
    00876             if(!JsonDecode_Callbacks.int_callback(state->context, atoi(state->p)))
    00877               return false;
    00878           }
    00879         }
    00880         state->p += size;
    00881         state->len -= size;
    00882         break;
    00883       }
    00884       case token_string:
    00885       {
    00886         char* p = ++state->p; // move past the opening "
    00887         state->len--;
    00888         bool keepgoing = true;
    00889         while(keepgoing)
    00890         {
    00891           if(*p == '\\') // we got an escape - skip the escape and the next character
    00892             p += 2;
    00893           else if(*p == '"') // we got the end of a string
    00894             keepgoing = false;
    00895           else
    00896             p++; // keep looking for the end of the string
    00897         }
    00898         int size = p - state->p;
    00899         *p = 0; // replace the trailing " with a null to make a string
    00900
    00901         // figure out if this is a key or a normal string
    00902         bool objkey = false;
    00903         if(state->steps[state->depth] == JSON_DECODE_OBJECT_START)
    00904         {
    00905           state->steps[state->depth] = JSON_DECODE_IN_OBJECT;
    00906           objkey = true;
    00907         }
    00908         if(state->gotcomma && state->steps[state->depth] == JSON_DECODE_IN_OBJECT)
    00909         {
    00910           state->gotcomma = false;
    00911           objkey = true;
    00912         }
    00913
    00914         if(objkey) // last one was a comma - next string has to be a key
    00915         {
    00916           if(JsonDecode_Callbacks.obj_key_callback)
    00917           {
    00918             if(!JsonDecode_Callbacks.obj_key_callback(state->context, state->p, size))
    00919               return false;
    00920           }
    00921         }
    00922         else // just a normal string
    00923         {
    00924           if(JsonDecode_Callbacks.string_callback)
    00925           {
    00926             if(!JsonDecode_Callbacks.string_callback(state->context, state->p, size))
    00927               return false;
    00928           }
    00929         }
    00930         state->p += (size+1); // account for the trailing "
    00931         state->len -= (size+1);
    00932         break;
    00933       }
    00934       case token_eof: // we don't expect to get this, since our len should run out before we get eof
    00935         return false;
    00936       default:
    00937         return false;
    00938     }
    00939   }
    00940   return true;
    00941 }
    00942
    00943 /** @}
    00944 */
    00945
    00946 // static
    00947 JsonDecode_Token JsonDecode_GetToken(char* text, int len)
    00948 {
    00949   char c = text[0];
    00950   switch(c)
    00951   {
    00952     case ':':
    00953       return token_colon;
    00954     case ',':
    00955       return token_comma;
    00956     case '{':
    00957       return token_left_bracket;
    00958     case '}':
    00959       return token_right_bracket;
    00960     case '[':
    00961       return token_left_brace;
    00962     case ']':
    00963       return token_right_brace;
    00964     case '"':
    00965       return token_string;
    00966     case '0': case '1': case '2': case '3': case '4':
    00967     case '5': case '6': case '7': case '8': case '9':
    00968       return token_number;
    00969     case '-':
    00970       return token_maybe_negative;
    00971     case 't':
    00972     {
    00973       if(len < 4) // not enough space;
    00974         return token_unknown;
    00975       if(!strncmp(text, "true", 4))
    00976         return token_true;
    00977       else
    00978         return token_unknown;
    00979     }
    00980     case 'f':
    00981     {
    00982       if(len < 5) // not enough space;
    00983         return token_unknown;
    00984       if(!strncmp(text, "false", 5))
    00985         return token_false;
    00986       else
    00987         return token_unknown;
    00988     }
    00989     case 'n':
    00990     {
    00991       if(len < 4) // not enough space;
    00992         return token_unknown;
    00993       if(!strncmp(text, "null", 4))
    00994         return token_null;
    00995       else
    00996         return token_unknown;
    00997     }
    00998     case '\0':
    00999       return token_eof;
    01000     default:
    01001       return token_unknown;
    01002   }
    01003 }
    01004
    01005
    01006
    01007
    01008

The Make Controller Kit is an open source project maintained by MakingThings.
MakingThings code is released under the Apache 2.0 license.
Bug tracker, development wiki and status can be found at http://dev.makingthings.com.
This document was last updated on 18 May 2009.