Minimalist JSON parser and serializer (inspired by picojson). Used by MbedJSONRpc.

Dependents:   RPC_mbed_client WebSocket_test pseudo_comet RPC_Wifly_HelloWorld ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MbedJSONValue.h Source File

MbedJSONValue.h

00001 /**
00002 * @author Samuel Mokrani
00003 *
00004 * @section LICENSE
00005 *
00006 * Copyright (c) 2011 mbed
00007 *
00008 * Permission is hereby granted, free of charge, to any person obtaining a copy
00009 * of this software and associated documentation files (the "Software"), to deal
00010 * in the Software without restriction, including without limitation the rights
00011 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00012 * copies of the Software, and to permit persons to whom the Software is
00013 * furnished to do so, subject to the following conditions:
00014 *
00015 * The above copyright notice and this permission notice shall be included in
00016 * all copies or substantial portions of the Software.
00017 *
00018 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00019 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00020 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00021 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00022 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00023 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00024 * THE SOFTWARE.
00025 *
00026 * @section DESCRIPTION
00027 *    Types Abstraction. Minimalist JSON serializer and parser (inspired by picojson). Is used by MbedJSONRpc.
00028 *
00029 */
00030 
00031 #ifndef _Mbed_RPC_VALUE_H_
00032 #define _Mbed_RPC_VALUE_H_
00033 
00034 #define NB_TOKEN 20
00035 /*!< Number maximum of MbedJSONValue in an array or an object */
00036 
00037 #include <string>
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <string.h>
00041 
00042 /** MbedJSONValue class
00043  *
00044  * Example:
00045  *    - creation of an MbedJSONValue of type TypeObject containing two others MbedJSONValue: 
00046  *         -one array of one string and one integer identified by "my_array"
00047  *         -a boolean identified by "my_boolean"
00048  *    - serialization in JSON format of this object
00049  * @code
00050  * #include "mbed.h"
00051  * #include "MbedJSONValue.h"
00052  * #include <string>
00053  *
00054  * int main() {          
00055  *
00056  *   MbedJSONValue demo;
00057  *   std::string s;
00058  *
00059  *   //fill the object
00060  *   demo["my_array"][0] = "demo_string";
00061  *   demo["my_array"][1] = 10;
00062  *   demo["my_boolean"] = false;
00063  *
00064  *   //serialize it into a JSON string
00065  *   s = demo.serialize();
00066  *   printf("json: %s\r\n", s.c_str());
00067  * }
00068  *  
00069  * @endcode
00070  *
00071  * Example:
00072  *     - creation of an MbedJSONValue from a JSON string
00073  *     - extraction of different values from this existing MbedJSONValue
00074  * @code
00075  * #include "mbed.h"
00076  * #include "MbedJSONValue.h"
00077  * #include <string>
00078  *
00079  * int main() {     
00080  *    MbedJSONValue demo;
00081  *
00082  *   const  char * json = "{\"my_array\": [\"demo_string\", 10], \"my_boolean\": true}";
00083  *
00084  *   //parse the previous string and fill the object demo
00085  *   parse(demo, json);
00086  *
00087  *   std::string my_str;
00088  *   int my_int;
00089  *   bool my_bool;
00090  *
00091  *   my_str = demo["my_array"][0].get<std::string>();
00092  *   my_int = demo["my_array"][1].get<int>();
00093  *   my_bool = demo["my_boolean"].get<bool>();
00094  *   
00095  *    printf("my_str: %s\r\n", my_str.c_str());
00096  *    printf("my_int: %d\r\n", my_int);
00097  *    printf("my_bool: %s\r\n", my_bool ? "true" : "false");
00098  * }
00099  * @endcode
00100  */
00101 class MbedJSONValue {
00102 public:
00103 
00104     /**
00105     * \enum Type
00106     * \brief All types which can be used
00107     */
00108     enum Type {
00109         TypeNull ,     /*!< Null type */
00110         TypeBoolean ,  /*!< Boolean */
00111         TypeInt ,      /*!< Integer */
00112         TypeDouble ,   /*!< Double */
00113         TypeString ,   /*!< String */
00114         TypeArray ,    /*!< Array (contains MbedJSONValue) */
00115         TypeObject     /*!< Object (contains MbedJSONValue identified by a name)*/
00116     };
00117 
00118     /**
00119     * MbedJSONValue constructor of type TypeNull
00120     */
00121     MbedJSONValue() : _type(TypeNull ), index_array(0), index_token(0) {}
00122     
00123     /**
00124     * MbedJSONValue constructor of type TypeBoolean
00125     *
00126     * @param value the object created will be initialized with this boolean
00127     */
00128     MbedJSONValue(bool value) : _type(TypeBoolean ), index_array(0), index_token(0) {
00129         _value.asBool = value;
00130     }
00131     
00132     /**
00133     * MbedJSONValue constructor of type TypeInt
00134     *
00135     * @param value the object created will be initialized with this integer
00136     */
00137     MbedJSONValue(int value)  : _type(TypeInt ), index_array(0), index_token(0) {
00138         _value.asInt = value;
00139     }
00140     
00141     /**
00142     * MbedJSONValue constructor of type TypeDouble
00143     *
00144     * @param value the object created will be initialized with this double
00145     */
00146     MbedJSONValue(double value)  : _type(TypeDouble ), index_array(0), index_token(0) {
00147         _value.asDouble = value;
00148     }
00149 
00150     /**
00151     * MbedJSONValue constructor of type TypeString
00152     *
00153     * @param value the object created will be initialized with this string
00154     */
00155     MbedJSONValue(std::string const& value) : _type(TypeString ), index_array(0), index_token(0) {
00156         _value.asString = new std::string(value);
00157     }
00158 
00159     /**
00160     * MbedJSONValue constructor of type TypeString
00161     *
00162     * @param value the object created will be initialized with this string
00163     */
00164     MbedJSONValue(const char* value)  : _type(TypeString ), index_array(0), index_token(0) {
00165         _value.asString = new std::string(value);
00166     }
00167 
00168     /**
00169     * Copy constructor
00170     *
00171     * @param rhs object which will be copied
00172     */
00173     MbedJSONValue(MbedJSONValue const& rhs) : _type(TypeNull ) {  *this = rhs;  }
00174 
00175     /**
00176     * Destructor
00177     */
00178     ~MbedJSONValue() {  clean();  }
00179 
00180     /**
00181     * = Operator overloading for an MbedJSONValue from an MbedJSONValue
00182     *
00183     * @param rhs object
00184     * @return a reference on the MbedJSONValue affected
00185     */
00186     MbedJSONValue& operator=(MbedJSONValue const & rhs);
00187     
00188     /**
00189     * = Operator overloading for an MbedJSONValue from an int
00190     *
00191     * @param rhs integer
00192     * @return a reference on the MbedJSONValue affected
00193     */
00194     MbedJSONValue& operator=(int const& rhs) { return operator=(MbedJSONValue(rhs));  }
00195     
00196     /**
00197     * = Operator overloading for an MbedJSONValue from a boolean
00198     *
00199     * @param rhs boolean
00200     * @return a reference on the MbedJSONValue affected
00201     */
00202     MbedJSONValue& operator=(bool const& rhs) { return operator=(MbedJSONValue(rhs));  }
00203     
00204     /**
00205     * = Operator overloading for an MbedJSONValue from a double
00206     *
00207     * @param rhs double
00208     * @return a reference on the MbedJSONValue affected
00209     */
00210     MbedJSONValue& operator=(double const& rhs) {  return operator=(MbedJSONValue(rhs));  }
00211     
00212     /**
00213     * = Operator overloading for an MbedJSONValue from a string
00214     *
00215     * @param rhs string
00216     * @return a reference on the MbedJSONValue affected
00217     */
00218     MbedJSONValue& operator=(const char* rhs) {  return operator=(MbedJSONValue(std::string(rhs))); }
00219     
00220     
00221     /**
00222     * [] Operator overloading for an MbedJSONValue.
00223     * Each TypeObject object can contain an array of NB_TOKEN MbedJSONValue. 
00224     * This operator is useful to create an array or to retrieve an MbedJSONValue of an existing array.
00225     *
00226     * @param i index of the array
00227     * @return a reference on the MbedJSONValue created or retrieved
00228     */
00229     MbedJSONValue& operator[](int i);
00230     
00231     /**
00232     * [] Operator overloading for an MbedJSONValue.
00233     * Each TypeObject MbedJSONValue can contain NB_TOKEN MbedJSONValue IDENTIFIED BY A NAME 
00234     * This operator is useful to create a TypeObject MbedJSONValue or to retrieve an MbedJSONValue of an existing TypeObject.
00235     *
00236     *
00237     * @param str identifier of the sub MbedJSONValue
00238     * @return a reference on the MbedJSONValue created or retrieved
00239     */
00240     MbedJSONValue& operator[](std::string str);
00241 
00242     /**
00243     * Retrieve the value of an MbedJSONValue object.
00244     *
00245     * Let's suppose that we have an MbedJSONValue of type TypeString.
00246     * To retrieve this string, you have to do:
00247     *   my_obj.get<std::string>();
00248     *
00249     * @return A contant reference on the value of the object
00250     */
00251     template <typename T> const T& get() const;
00252     
00253     /**
00254     * Retrieve the value of an MbedJSONValue object.
00255     *
00256     * Let's suppose that we have an MbedJSONValue of type TypeInt.
00257     * To retrieve this integer, you have to do:
00258     *   my_obj.get<int>();
00259     *
00260     * @return A reference on the value of the object
00261     */
00262     template <typename T> T& get();
00263 
00264 
00265     /**
00266     * Return the type of the MbedJSONValue object
00267     *
00268     * @return type of the MbedJSONValue object
00269     */
00270     Type const &getType() const {
00271         return _type;
00272     }
00273 
00274     /**
00275     * Return the size of an MbedJSONValue object (works for TypeString, TypeArray or TypeObject) 
00276     *
00277     * @return size
00278     */
00279     int size() const;
00280 
00281     /**
00282     * Check for the existence in a TypeObject object of member identified by name
00283     *
00284     * @param name Identifier
00285     * @return true if the object is of type TypeObject AND contains a member named "name", false otherwise
00286     */
00287     bool hasMember(char * name);
00288 
00289     /**
00290     * Convert an MbedJSONValue in a JSON frame
00291     *
00292     * @return JSON string
00293     */
00294     std::string serialize();
00295 
00296 protected:
00297 
00298     // object type
00299     Type _type;
00300     
00301     //indexes of TypeObject and TypeArray
00302     int index_array;
00303     int index_token;
00304 
00305     //an object can contain NB_TOKEN tokens. Each token have a name
00306     MbedJSONValue * token[NB_TOKEN];
00307     std::string * token_name[NB_TOKEN];
00308 
00309     //an object can contain an array of NB_TOKEN elements
00310     MbedJSONValue * array[NB_TOKEN];
00311 
00312     // Clean up
00313     void clean();
00314 
00315     union {
00316         bool          asBool;
00317         int           asInt;
00318         double        asDouble;
00319         std::string*  asString;
00320     } _value;
00321 
00322 
00323     MbedJSONValue& operator[](int i) const { return *(array[i]); }
00324     MbedJSONValue& operator[](std::string k) const;
00325     
00326     std::string to_str();
00327     void serialize(std::back_insert_iterator<std::string> os);
00328 
00329 };
00330 
00331 
00332 #define GET(ctype, var)                          \
00333   template <> inline const ctype& MbedJSONValue::get<ctype>() const { \
00334     return var;                              \
00335   }                                  \
00336   template <> inline ctype& MbedJSONValue::get<ctype>() {          \
00337     return var;                              \
00338   }
00339 GET(bool, _value.asBool)
00340 GET(double, _value.asDouble)
00341 GET(int, _value.asInt)
00342 GET(std::string, *_value.asString)
00343 #undef GET
00344 
00345 
00346 //Input class for JSON parser
00347 class input {
00348 protected:
00349     const char * cur_;
00350     const char * end_;
00351     int last_ch_;
00352     bool ungot_;
00353     int line_;
00354 public:
00355     input(const char * first, const char * last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {};
00356 
00357     int getc() {
00358         if (ungot_) {
00359             ungot_ = false;
00360             return last_ch_;
00361         }
00362         if (cur_ == end_) {
00363             last_ch_ = -1;
00364             return -1;
00365         }
00366         if (last_ch_ == '\n') {
00367             line_++;
00368         }
00369         last_ch_ = *cur_++ & 0xff;
00370         return last_ch_;
00371     }
00372 
00373     void ungetc() {
00374         if (last_ch_ != -1) {
00375             ungot_ = true;
00376         }
00377     }
00378 
00379     const char * cur() const {
00380         return cur_;
00381     }
00382     int line() const {
00383         return line_;
00384     }
00385     void skip_ws() {
00386         while (1) {
00387             int ch = getc();
00388             if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) {
00389                 ungetc();
00390                 break;
00391             }
00392         }
00393     }
00394     int expect(int expect) {
00395         skip_ws();
00396         if (getc() != expect) {
00397             ungetc();
00398             return false;
00399         }
00400         return true;
00401     }
00402     bool match(const std::string& pattern) {
00403         for (std::string::const_iterator pi(pattern.begin());
00404                 pi != pattern.end();
00405                 ++pi) {
00406             if (getc() != *pi) {
00407                 ungetc();
00408                 return false;
00409             }
00410         }
00411         return true;
00412     }
00413 };
00414 
00415 
00416 
00417 inline const char * parse(MbedJSONValue& out, const char * first, const char * last, std::string* err);
00418 
00419 /**
00420 * JSON string parser and creation of an MbedJSONValue
00421 *
00422 * @param out reference of an MbedJSONValue which will be filled according to the JSON string
00423 * @param str JSON string
00424 * @return A non empty string if there is a parsing error
00425 *
00426 */
00427 
00428 inline std::string parse(MbedJSONValue& out, const char * str);
00429 inline bool _parse(MbedJSONValue& out, input& in);
00430 inline bool _parse_number(MbedJSONValue& out, input& in);
00431 inline bool _parse_string(MbedJSONValue& out, input& in);
00432 inline bool _parse_array(MbedJSONValue& out, input& in);
00433 inline bool _parse_object(MbedJSONValue& out, input& in);
00434 
00435 
00436 inline bool _parse_string(MbedJSONValue& out, input& in) {
00437 #ifdef DEBUG
00438     printf("string detected\r\n");
00439 #endif
00440     out = MbedJSONValue(std::string(""));
00441     std::string& s = out.get<std::string>();
00442     while (1) {
00443         int ch = in.getc();
00444         if (ch < ' ') {
00445             in.ungetc();
00446             return false;
00447         } else if (ch == '"') {
00448             return true;
00449         } else if (ch == '\\') {
00450             if ((ch = in.getc()) == -1) {
00451                 return false;
00452             }
00453             switch (ch) {
00454 #define MAP(sym, val) case sym: s.push_back(val); break
00455                     MAP('"', '\"');
00456                     MAP('\\', '\\');
00457                     MAP('/', '/');
00458                     MAP('b', '\b');
00459                     MAP('f', '\f');
00460                     MAP('n', '\n');
00461                     MAP('r', '\r');
00462                     MAP('t', '\t');
00463 #undef MAP
00464                 default:
00465                     return false;
00466             }
00467         } else {
00468             s.push_back(ch);
00469         }
00470     }
00471 }
00472 
00473 inline bool _parse_array(MbedJSONValue& out, input& in) {
00474 #ifdef DEBUG
00475     printf("array detected\r\n");
00476 #endif
00477     int i = 0;
00478     if (in.expect(']')) {
00479         return true;
00480     }
00481     do {
00482         if (! _parse(out[i], in)) {
00483             return false;
00484         }
00485         i++;
00486     } while (in.expect(','));
00487     return in.expect(']');
00488 }
00489 
00490 inline bool _parse_object(MbedJSONValue& out, input& in) {
00491 #ifdef DEBUG
00492     printf("object detected\r\n");
00493 #endif
00494     if (in.expect('}')) {
00495         return true;
00496     }
00497     do {
00498         MbedJSONValue key, val;
00499         if (in.expect('"') && _parse_string(key, in) && in.expect(':') && _parse(val, in)) {
00500             out[key.get<std::string>().c_str()] = val;
00501 #ifdef DEBUG
00502             printf("key: %s \r\n", key.get<std::string>().c_str());
00503 #endif
00504         } else {
00505             return false;
00506         }
00507     } while (in.expect(','));
00508     return in.expect('}');
00509 }
00510 
00511 inline bool _parse_number(MbedJSONValue& out, input& in) {
00512 #ifdef DEBUG
00513     printf("number detected\r\n");
00514 #endif
00515     std::string num_str;
00516     while (1) {
00517         int ch = in.getc();
00518         if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == '.'
00519                 || ch == 'e' || ch == 'E') {
00520             num_str.push_back(ch);
00521         } else {
00522             in.ungetc();
00523             break;
00524         }
00525     }
00526     char* endp;
00527     if (strchr(num_str.c_str(), '.') != NULL || strchr(num_str.c_str(), 'e') != NULL || strchr(num_str.c_str(), '+') != NULL)
00528         out = MbedJSONValue(strtod(num_str.c_str(), &endp));
00529     else
00530         out = MbedJSONValue((int)strtod(num_str.c_str(), &endp));
00531     return endp == num_str.c_str() + num_str.size();
00532 }
00533 
00534 inline bool _parse(MbedJSONValue& out, input& in) {
00535     in.skip_ws();
00536     int ch = in.getc();
00537     switch (ch) {
00538 #define IS(ch, text, val) case ch: \
00539       if (in.match(text)) { \
00540     out = val; \
00541     return true; \
00542       } else { \
00543     return false; \
00544       }
00545             IS('n', "ull", MbedJSONValue());
00546             IS('f', "alse", MbedJSONValue(false));
00547             IS('t', "rue", MbedJSONValue(true));
00548 #undef IS
00549         case '"':
00550             return _parse_string(out, in);
00551         case '[':
00552             return _parse_array(out, in);
00553         case '{':
00554             return _parse_object(out, in);
00555         default:
00556             if (('0' <= ch && ch <= '9') || ch == '-') {
00557                 in.ungetc();
00558                 return _parse_number(out, in);
00559             }
00560             break;
00561     }
00562     in.ungetc();
00563     return false;
00564 }
00565 
00566 inline std::string parse(MbedJSONValue& out, const char * pos) {
00567     const char * last = pos + strlen(pos);
00568     std::string err;
00569     pos = parse(out, pos, last, &err);
00570     return err;
00571 }
00572 
00573 inline const char * parse(MbedJSONValue& out, const char * first, const char * last, std::string* err) {
00574     input in = input(first, last);
00575     if (! _parse(out, in) && err != NULL) {
00576         char buf[64];
00577         sprintf(buf, "syntax error at line %d near: ", in.line());
00578         *err = buf;
00579         while (1) {
00580             int ch = in.getc();
00581             if (ch == -1 || ch == '\n') {
00582                 break;
00583             } else if (ch >= ' ') {
00584                 err->push_back(ch);
00585             }
00586         }
00587     }
00588     return in.cur();
00589 }
00590 
00591 #endif // _MbedMbedJSONValue_H_