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

Dependents:   Solar_Powered_Smart_Camera

Fork of MbedJSONValue by Samuel Mokrani

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