Minimalist JSON parser and serializer (inspired by picojson). Used by MbedJSONRpc.
Dependents: RPC_mbed_client WebSocket_test pseudo_comet RPC_Wifly_HelloWorld ... more
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_
Generated on Tue Jul 12 2022 18:09:13 by 1.7.2