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

Dependents:   RPC_mbed_client WebSocket_test pseudo_comet RPC_Wifly_HelloWorld ... more

Committer:
samux
Date:
Thu Sep 22 10:57:37 2011 +0000
Revision:
4:10a99cdf7846
Parent:
3:f2ffae08b963

    

Who changed what in which revision?

UserRevisionLine numberNew contents of line
samux0:0cf0e27feaad 1/**
samux0:0cf0e27feaad 2* @author Samuel Mokrani
samux0:0cf0e27feaad 3*
samux0:0cf0e27feaad 4* @section LICENSE
samux0:0cf0e27feaad 5*
samux0:0cf0e27feaad 6* Copyright (c) 2011 mbed
samux0:0cf0e27feaad 7*
samux0:0cf0e27feaad 8* Permission is hereby granted, free of charge, to any person obtaining a copy
samux0:0cf0e27feaad 9* of this software and associated documentation files (the "Software"), to deal
samux0:0cf0e27feaad 10* in the Software without restriction, including without limitation the rights
samux0:0cf0e27feaad 11* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
samux0:0cf0e27feaad 12* copies of the Software, and to permit persons to whom the Software is
samux0:0cf0e27feaad 13* furnished to do so, subject to the following conditions:
samux0:0cf0e27feaad 14*
samux0:0cf0e27feaad 15* The above copyright notice and this permission notice shall be included in
samux0:0cf0e27feaad 16* all copies or substantial portions of the Software.
samux0:0cf0e27feaad 17*
samux0:0cf0e27feaad 18* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
samux0:0cf0e27feaad 19* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
samux0:0cf0e27feaad 20* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
samux0:0cf0e27feaad 21* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
samux0:0cf0e27feaad 22* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
samux0:0cf0e27feaad 23* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
samux0:0cf0e27feaad 24* THE SOFTWARE.
samux0:0cf0e27feaad 25*
samux0:0cf0e27feaad 26* @section DESCRIPTION
samux2:e39bfa3e917d 27* Types Abstraction. Minimalist JSON serializer and parser (inspired by picojson). Is used by MbedJSONRpc.
samux0:0cf0e27feaad 28*
samux0:0cf0e27feaad 29*/
samux0:0cf0e27feaad 30
samux0:0cf0e27feaad 31#ifndef _Mbed_RPC_VALUE_H_
samux0:0cf0e27feaad 32#define _Mbed_RPC_VALUE_H_
samux0:0cf0e27feaad 33
samux0:0cf0e27feaad 34#define NB_TOKEN 20
samux0:0cf0e27feaad 35/*!< Number maximum of MbedJSONValue in an array or an object */
samux0:0cf0e27feaad 36
samux0:0cf0e27feaad 37#include <string>
samux0:0cf0e27feaad 38#include <stdio.h>
samux0:0cf0e27feaad 39#include <stdlib.h>
samux0:0cf0e27feaad 40#include <string.h>
samux0:0cf0e27feaad 41
samux0:0cf0e27feaad 42/** MbedJSONValue class
samux0:0cf0e27feaad 43 *
samux0:0cf0e27feaad 44 * Example:
samux0:0cf0e27feaad 45 * - creation of an MbedJSONValue of type TypeObject containing two others MbedJSONValue:
samux0:0cf0e27feaad 46 * -one array of one string and one integer identified by "my_array"
samux0:0cf0e27feaad 47 * -a boolean identified by "my_boolean"
samux0:0cf0e27feaad 48 * - serialization in JSON format of this object
samux0:0cf0e27feaad 49 * @code
samux2:e39bfa3e917d 50 * #include "mbed.h"
samux2:e39bfa3e917d 51 * #include "MbedJSONValue.h"
samux2:e39bfa3e917d 52 * #include <string>
samux0:0cf0e27feaad 53 *
samux2:e39bfa3e917d 54 * int main() {
samux0:0cf0e27feaad 55 *
samux2:e39bfa3e917d 56 * MbedJSONValue demo;
samux2:e39bfa3e917d 57 * std::string s;
samux0:0cf0e27feaad 58 *
samux2:e39bfa3e917d 59 * //fill the object
samux2:e39bfa3e917d 60 * demo["my_array"][0] = "demo_string";
samux2:e39bfa3e917d 61 * demo["my_array"][1] = 10;
samux2:e39bfa3e917d 62 * demo["my_boolean"] = false;
samux2:e39bfa3e917d 63 *
samux2:e39bfa3e917d 64 * //serialize it into a JSON string
samux2:e39bfa3e917d 65 * s = demo.serialize();
samux2:e39bfa3e917d 66 * printf("json: %s\r\n", s.c_str());
samux2:e39bfa3e917d 67 * }
samux0:0cf0e27feaad 68 *
samux0:0cf0e27feaad 69 * @endcode
samux0:0cf0e27feaad 70 *
samux0:0cf0e27feaad 71 * Example:
samux0:0cf0e27feaad 72 * - creation of an MbedJSONValue from a JSON string
samux0:0cf0e27feaad 73 * - extraction of different values from this existing MbedJSONValue
samux0:0cf0e27feaad 74 * @code
samux2:e39bfa3e917d 75 * #include "mbed.h"
samux2:e39bfa3e917d 76 * #include "MbedJSONValue.h"
samux2:e39bfa3e917d 77 * #include <string>
samux0:0cf0e27feaad 78 *
samux2:e39bfa3e917d 79 * int main() {
samux2:e39bfa3e917d 80 * MbedJSONValue demo;
samux0:0cf0e27feaad 81 *
samux2:e39bfa3e917d 82 * const char * json = "{\"my_array\": [\"demo_string\", 10], \"my_boolean\": true}";
samux0:0cf0e27feaad 83 *
samux2:e39bfa3e917d 84 * //parse the previous string and fill the object demo
samux2:e39bfa3e917d 85 * parse(demo, json);
samux0:0cf0e27feaad 86 *
samux2:e39bfa3e917d 87 * std::string my_str;
samux2:e39bfa3e917d 88 * int my_int;
samux2:e39bfa3e917d 89 * bool my_bool;
samux0:0cf0e27feaad 90 *
samux2:e39bfa3e917d 91 * my_str = demo["my_array"][0].get<std::string>();
samux2:e39bfa3e917d 92 * my_int = demo["my_array"][1].get<int>();
samux2:e39bfa3e917d 93 * my_bool = demo["my_boolean"].get<bool>();
samux2:e39bfa3e917d 94 *
samux2:e39bfa3e917d 95 * printf("my_str: %s\r\n", my_str.c_str());
samux2:e39bfa3e917d 96 * printf("my_int: %d\r\n", my_int);
samux2:e39bfa3e917d 97 * printf("my_bool: %s\r\n", my_bool ? "true" : "false");
samux2:e39bfa3e917d 98 * }
samux0:0cf0e27feaad 99 * @endcode
samux0:0cf0e27feaad 100 */
samux0:0cf0e27feaad 101class MbedJSONValue {
samux0:0cf0e27feaad 102public:
samux0:0cf0e27feaad 103
samux0:0cf0e27feaad 104 /**
samux0:0cf0e27feaad 105 * \enum Type
samux0:0cf0e27feaad 106 * \brief All types which can be used
samux0:0cf0e27feaad 107 */
samux0:0cf0e27feaad 108 enum Type {
samux0:0cf0e27feaad 109 TypeNull, /*!< Null type */
samux0:0cf0e27feaad 110 TypeBoolean, /*!< Boolean */
samux0:0cf0e27feaad 111 TypeInt, /*!< Integer */
samux0:0cf0e27feaad 112 TypeDouble, /*!< Double */
samux0:0cf0e27feaad 113 TypeString, /*!< String */
samux4:10a99cdf7846 114 TypeArray, /*!< Array (contains MbedJSONValue) */
samux4:10a99cdf7846 115 TypeObject /*!< Object (contains MbedJSONValue identified by a name)*/
samux0:0cf0e27feaad 116 };
samux0:0cf0e27feaad 117
samux0:0cf0e27feaad 118 /**
samux0:0cf0e27feaad 119 * MbedJSONValue constructor of type TypeNull
samux0:0cf0e27feaad 120 */
samux0:0cf0e27feaad 121 MbedJSONValue() : _type(TypeNull), index_array(0), index_token(0) {}
samux0:0cf0e27feaad 122
samux0:0cf0e27feaad 123 /**
samux0:0cf0e27feaad 124 * MbedJSONValue constructor of type TypeBoolean
samux0:0cf0e27feaad 125 *
samux0:0cf0e27feaad 126 * @param value the object created will be initialized with this boolean
samux0:0cf0e27feaad 127 */
samux0:0cf0e27feaad 128 MbedJSONValue(bool value) : _type(TypeBoolean), index_array(0), index_token(0) {
samux0:0cf0e27feaad 129 _value.asBool = value;
samux0:0cf0e27feaad 130 }
samux0:0cf0e27feaad 131
samux0:0cf0e27feaad 132 /**
samux0:0cf0e27feaad 133 * MbedJSONValue constructor of type TypeInt
samux0:0cf0e27feaad 134 *
samux0:0cf0e27feaad 135 * @param value the object created will be initialized with this integer
samux0:0cf0e27feaad 136 */
samux0:0cf0e27feaad 137 MbedJSONValue(int value) : _type(TypeInt), index_array(0), index_token(0) {
samux0:0cf0e27feaad 138 _value.asInt = value;
samux0:0cf0e27feaad 139 }
samux0:0cf0e27feaad 140
samux0:0cf0e27feaad 141 /**
samux0:0cf0e27feaad 142 * MbedJSONValue constructor of type TypeDouble
samux0:0cf0e27feaad 143 *
samux0:0cf0e27feaad 144 * @param value the object created will be initialized with this double
samux0:0cf0e27feaad 145 */
samux0:0cf0e27feaad 146 MbedJSONValue(double value) : _type(TypeDouble), index_array(0), index_token(0) {
samux0:0cf0e27feaad 147 _value.asDouble = value;
samux0:0cf0e27feaad 148 }
samux0:0cf0e27feaad 149
samux0:0cf0e27feaad 150 /**
samux0:0cf0e27feaad 151 * MbedJSONValue constructor of type TypeString
samux0:0cf0e27feaad 152 *
samux0:0cf0e27feaad 153 * @param value the object created will be initialized with this string
samux0:0cf0e27feaad 154 */
samux0:0cf0e27feaad 155 MbedJSONValue(std::string const& value) : _type(TypeString), index_array(0), index_token(0) {
samux0:0cf0e27feaad 156 _value.asString = new std::string(value);
samux0:0cf0e27feaad 157 }
samux0:0cf0e27feaad 158
samux0:0cf0e27feaad 159 /**
samux0:0cf0e27feaad 160 * MbedJSONValue constructor of type TypeString
samux0:0cf0e27feaad 161 *
samux0:0cf0e27feaad 162 * @param value the object created will be initialized with this string
samux0:0cf0e27feaad 163 */
samux0:0cf0e27feaad 164 MbedJSONValue(const char* value) : _type(TypeString), index_array(0), index_token(0) {
samux0:0cf0e27feaad 165 _value.asString = new std::string(value);
samux0:0cf0e27feaad 166 }
samux0:0cf0e27feaad 167
samux0:0cf0e27feaad 168 /**
samux0:0cf0e27feaad 169 * Copy constructor
samux0:0cf0e27feaad 170 *
samux0:0cf0e27feaad 171 * @param rhs object which will be copied
samux0:0cf0e27feaad 172 */
samux0:0cf0e27feaad 173 MbedJSONValue(MbedJSONValue const& rhs) : _type(TypeNull) { *this = rhs; }
samux0:0cf0e27feaad 174
samux0:0cf0e27feaad 175 /**
samux0:0cf0e27feaad 176 * Destructor
samux0:0cf0e27feaad 177 */
samux0:0cf0e27feaad 178 ~MbedJSONValue() { clean(); }
samux0:0cf0e27feaad 179
samux0:0cf0e27feaad 180 /**
samux0:0cf0e27feaad 181 * = Operator overloading for an MbedJSONValue from an MbedJSONValue
samux0:0cf0e27feaad 182 *
samux0:0cf0e27feaad 183 * @param rhs object
samux0:0cf0e27feaad 184 * @return a reference on the MbedJSONValue affected
samux0:0cf0e27feaad 185 */
samux0:0cf0e27feaad 186 MbedJSONValue& operator=(MbedJSONValue const & rhs);
samux0:0cf0e27feaad 187
samux0:0cf0e27feaad 188 /**
samux0:0cf0e27feaad 189 * = Operator overloading for an MbedJSONValue from an int
samux0:0cf0e27feaad 190 *
samux0:0cf0e27feaad 191 * @param rhs integer
samux0:0cf0e27feaad 192 * @return a reference on the MbedJSONValue affected
samux0:0cf0e27feaad 193 */
samux0:0cf0e27feaad 194 MbedJSONValue& operator=(int const& rhs) { return operator=(MbedJSONValue(rhs)); }
samux0:0cf0e27feaad 195
samux0:0cf0e27feaad 196 /**
samux2:e39bfa3e917d 197 * = Operator overloading for an MbedJSONValue from a boolean
samux2:e39bfa3e917d 198 *
samux2:e39bfa3e917d 199 * @param rhs boolean
samux2:e39bfa3e917d 200 * @return a reference on the MbedJSONValue affected
samux2:e39bfa3e917d 201 */
samux2:e39bfa3e917d 202 MbedJSONValue& operator=(bool const& rhs) { return operator=(MbedJSONValue(rhs)); }
samux2:e39bfa3e917d 203
samux2:e39bfa3e917d 204 /**
samux0:0cf0e27feaad 205 * = Operator overloading for an MbedJSONValue from a double
samux0:0cf0e27feaad 206 *
samux0:0cf0e27feaad 207 * @param rhs double
samux0:0cf0e27feaad 208 * @return a reference on the MbedJSONValue affected
samux0:0cf0e27feaad 209 */
samux0:0cf0e27feaad 210 MbedJSONValue& operator=(double const& rhs) { return operator=(MbedJSONValue(rhs)); }
samux0:0cf0e27feaad 211
samux0:0cf0e27feaad 212 /**
samux0:0cf0e27feaad 213 * = Operator overloading for an MbedJSONValue from a string
samux0:0cf0e27feaad 214 *
samux0:0cf0e27feaad 215 * @param rhs string
samux0:0cf0e27feaad 216 * @return a reference on the MbedJSONValue affected
samux0:0cf0e27feaad 217 */
samux0:0cf0e27feaad 218 MbedJSONValue& operator=(const char* rhs) { return operator=(MbedJSONValue(std::string(rhs))); }
samux0:0cf0e27feaad 219
samux0:0cf0e27feaad 220
samux0:0cf0e27feaad 221 /**
samux0:0cf0e27feaad 222 * [] Operator overloading for an MbedJSONValue.
samux0:0cf0e27feaad 223 * Each TypeObject object can contain an array of NB_TOKEN MbedJSONValue.
samux0:0cf0e27feaad 224 * This operator is useful to create an array or to retrieve an MbedJSONValue of an existing array.
samux0:0cf0e27feaad 225 *
samux0:0cf0e27feaad 226 * @param i index of the array
samux0:0cf0e27feaad 227 * @return a reference on the MbedJSONValue created or retrieved
samux0:0cf0e27feaad 228 */
samux0:0cf0e27feaad 229 MbedJSONValue& operator[](int i);
samux0:0cf0e27feaad 230
samux0:0cf0e27feaad 231 /**
samux0:0cf0e27feaad 232 * [] Operator overloading for an MbedJSONValue.
samux0:0cf0e27feaad 233 * Each TypeObject MbedJSONValue can contain NB_TOKEN MbedJSONValue IDENTIFIED BY A NAME
samux0:0cf0e27feaad 234 * This operator is useful to create a TypeObject MbedJSONValue or to retrieve an MbedJSONValue of an existing TypeObject.
samux0:0cf0e27feaad 235 *
samux0:0cf0e27feaad 236 *
samux0:0cf0e27feaad 237 * @param str identifier of the sub MbedJSONValue
samux0:0cf0e27feaad 238 * @return a reference on the MbedJSONValue created or retrieved
samux0:0cf0e27feaad 239 */
samux0:0cf0e27feaad 240 MbedJSONValue& operator[](std::string str);
samux0:0cf0e27feaad 241
samux0:0cf0e27feaad 242 /**
samux0:0cf0e27feaad 243 * Retrieve the value of an MbedJSONValue object.
samux0:0cf0e27feaad 244 *
samux0:0cf0e27feaad 245 * Let's suppose that we have an MbedJSONValue of type TypeString.
samux0:0cf0e27feaad 246 * To retrieve this string, you have to do:
samux0:0cf0e27feaad 247 * my_obj.get<std::string>();
samux0:0cf0e27feaad 248 *
samux0:0cf0e27feaad 249 * @return A contant reference on the value of the object
samux0:0cf0e27feaad 250 */
samux0:0cf0e27feaad 251 template <typename T> const T& get() const;
samux0:0cf0e27feaad 252
samux0:0cf0e27feaad 253 /**
samux0:0cf0e27feaad 254 * Retrieve the value of an MbedJSONValue object.
samux0:0cf0e27feaad 255 *
samux0:0cf0e27feaad 256 * Let's suppose that we have an MbedJSONValue of type TypeInt.
samux0:0cf0e27feaad 257 * To retrieve this integer, you have to do:
samux0:0cf0e27feaad 258 * my_obj.get<int>();
samux0:0cf0e27feaad 259 *
samux0:0cf0e27feaad 260 * @return A reference on the value of the object
samux0:0cf0e27feaad 261 */
samux0:0cf0e27feaad 262 template <typename T> T& get();
samux0:0cf0e27feaad 263
samux0:0cf0e27feaad 264
samux0:0cf0e27feaad 265 /**
samux0:0cf0e27feaad 266 * Return the type of the MbedJSONValue object
samux0:0cf0e27feaad 267 *
samux0:0cf0e27feaad 268 * @return type of the MbedJSONValue object
samux0:0cf0e27feaad 269 */
samux0:0cf0e27feaad 270 Type const &getType() const {
samux0:0cf0e27feaad 271 return _type;
samux0:0cf0e27feaad 272 }
samux0:0cf0e27feaad 273
samux0:0cf0e27feaad 274 /**
samux0:0cf0e27feaad 275 * Return the size of an MbedJSONValue object (works for TypeString, TypeArray or TypeObject)
samux0:0cf0e27feaad 276 *
samux0:0cf0e27feaad 277 * @return size
samux0:0cf0e27feaad 278 */
samux0:0cf0e27feaad 279 int size() const;
samux0:0cf0e27feaad 280
samux0:0cf0e27feaad 281 /**
samux0:0cf0e27feaad 282 * Check for the existence in a TypeObject object of member identified by name
samux0:0cf0e27feaad 283 *
samux0:0cf0e27feaad 284 * @param name Identifier
samux0:0cf0e27feaad 285 * @return true if the object is of type TypeObject AND contains a member named "name", false otherwise
samux0:0cf0e27feaad 286 */
samux0:0cf0e27feaad 287 bool hasMember(char * name);
samux0:0cf0e27feaad 288
samux0:0cf0e27feaad 289 /**
samux0:0cf0e27feaad 290 * Convert an MbedJSONValue in a JSON frame
samux0:0cf0e27feaad 291 *
samux0:0cf0e27feaad 292 * @return JSON string
samux0:0cf0e27feaad 293 */
samux0:0cf0e27feaad 294 std::string serialize();
samux0:0cf0e27feaad 295
samux0:0cf0e27feaad 296protected:
samux0:0cf0e27feaad 297
samux0:0cf0e27feaad 298 // object type
samux0:0cf0e27feaad 299 Type _type;
samux0:0cf0e27feaad 300
samux0:0cf0e27feaad 301 //indexes of TypeObject and TypeArray
samux0:0cf0e27feaad 302 int index_array;
samux0:0cf0e27feaad 303 int index_token;
samux0:0cf0e27feaad 304
samux0:0cf0e27feaad 305 //an object can contain NB_TOKEN tokens. Each token have a name
samux0:0cf0e27feaad 306 MbedJSONValue * token[NB_TOKEN];
samux0:0cf0e27feaad 307 std::string * token_name[NB_TOKEN];
samux0:0cf0e27feaad 308
samux0:0cf0e27feaad 309 //an object can contain an array of NB_TOKEN elements
samux0:0cf0e27feaad 310 MbedJSONValue * array[NB_TOKEN];
samux0:0cf0e27feaad 311
samux0:0cf0e27feaad 312 // Clean up
samux0:0cf0e27feaad 313 void clean();
samux0:0cf0e27feaad 314
samux0:0cf0e27feaad 315 union {
samux0:0cf0e27feaad 316 bool asBool;
samux0:0cf0e27feaad 317 int asInt;
samux0:0cf0e27feaad 318 double asDouble;
samux0:0cf0e27feaad 319 std::string* asString;
samux0:0cf0e27feaad 320 } _value;
samux0:0cf0e27feaad 321
samux0:0cf0e27feaad 322
samux0:0cf0e27feaad 323 MbedJSONValue& operator[](int i) const { return *(array[i]); }
samux0:0cf0e27feaad 324 MbedJSONValue& operator[](std::string k) const;
samux0:0cf0e27feaad 325
samux0:0cf0e27feaad 326 std::string to_str();
samux0:0cf0e27feaad 327 void serialize(std::back_insert_iterator<std::string> os);
samux0:0cf0e27feaad 328
samux0:0cf0e27feaad 329};
samux0:0cf0e27feaad 330
samux0:0cf0e27feaad 331
samux0:0cf0e27feaad 332#define GET(ctype, var) \
samux0:0cf0e27feaad 333 template <> inline const ctype& MbedJSONValue::get<ctype>() const { \
samux0:0cf0e27feaad 334 return var; \
samux0:0cf0e27feaad 335 } \
samux0:0cf0e27feaad 336 template <> inline ctype& MbedJSONValue::get<ctype>() { \
samux0:0cf0e27feaad 337 return var; \
samux0:0cf0e27feaad 338 }
samux0:0cf0e27feaad 339GET(bool, _value.asBool)
samux0:0cf0e27feaad 340GET(double, _value.asDouble)
samux0:0cf0e27feaad 341GET(int, _value.asInt)
samux0:0cf0e27feaad 342GET(std::string, *_value.asString)
samux0:0cf0e27feaad 343#undef GET
samux0:0cf0e27feaad 344
samux0:0cf0e27feaad 345
samux0:0cf0e27feaad 346//Input class for JSON parser
samux0:0cf0e27feaad 347class input {
samux0:0cf0e27feaad 348protected:
samux0:0cf0e27feaad 349 const char * cur_;
samux0:0cf0e27feaad 350 const char * end_;
samux0:0cf0e27feaad 351 int last_ch_;
samux0:0cf0e27feaad 352 bool ungot_;
samux0:0cf0e27feaad 353 int line_;
samux0:0cf0e27feaad 354public:
samux0:0cf0e27feaad 355 input(const char * first, const char * last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {};
samux0:0cf0e27feaad 356
samux0:0cf0e27feaad 357 int getc() {
samux0:0cf0e27feaad 358 if (ungot_) {
samux0:0cf0e27feaad 359 ungot_ = false;
samux0:0cf0e27feaad 360 return last_ch_;
samux0:0cf0e27feaad 361 }
samux0:0cf0e27feaad 362 if (cur_ == end_) {
samux0:0cf0e27feaad 363 last_ch_ = -1;
samux0:0cf0e27feaad 364 return -1;
samux0:0cf0e27feaad 365 }
samux0:0cf0e27feaad 366 if (last_ch_ == '\n') {
samux0:0cf0e27feaad 367 line_++;
samux0:0cf0e27feaad 368 }
samux0:0cf0e27feaad 369 last_ch_ = *cur_++ & 0xff;
samux0:0cf0e27feaad 370 return last_ch_;
samux0:0cf0e27feaad 371 }
samux0:0cf0e27feaad 372
samux0:0cf0e27feaad 373 void ungetc() {
samux0:0cf0e27feaad 374 if (last_ch_ != -1) {
samux0:0cf0e27feaad 375 ungot_ = true;
samux0:0cf0e27feaad 376 }
samux0:0cf0e27feaad 377 }
samux0:0cf0e27feaad 378
samux0:0cf0e27feaad 379 const char * cur() const {
samux0:0cf0e27feaad 380 return cur_;
samux0:0cf0e27feaad 381 }
samux0:0cf0e27feaad 382 int line() const {
samux0:0cf0e27feaad 383 return line_;
samux0:0cf0e27feaad 384 }
samux0:0cf0e27feaad 385 void skip_ws() {
samux0:0cf0e27feaad 386 while (1) {
samux0:0cf0e27feaad 387 int ch = getc();
samux0:0cf0e27feaad 388 if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) {
samux0:0cf0e27feaad 389 ungetc();
samux0:0cf0e27feaad 390 break;
samux0:0cf0e27feaad 391 }
samux0:0cf0e27feaad 392 }
samux0:0cf0e27feaad 393 }
samux0:0cf0e27feaad 394 int expect(int expect) {
samux0:0cf0e27feaad 395 skip_ws();
samux0:0cf0e27feaad 396 if (getc() != expect) {
samux0:0cf0e27feaad 397 ungetc();
samux0:0cf0e27feaad 398 return false;
samux0:0cf0e27feaad 399 }
samux0:0cf0e27feaad 400 return true;
samux0:0cf0e27feaad 401 }
samux0:0cf0e27feaad 402 bool match(const std::string& pattern) {
samux0:0cf0e27feaad 403 for (std::string::const_iterator pi(pattern.begin());
samux0:0cf0e27feaad 404 pi != pattern.end();
samux0:0cf0e27feaad 405 ++pi) {
samux0:0cf0e27feaad 406 if (getc() != *pi) {
samux0:0cf0e27feaad 407 ungetc();
samux0:0cf0e27feaad 408 return false;
samux0:0cf0e27feaad 409 }
samux0:0cf0e27feaad 410 }
samux0:0cf0e27feaad 411 return true;
samux0:0cf0e27feaad 412 }
samux0:0cf0e27feaad 413};
samux0:0cf0e27feaad 414
samux0:0cf0e27feaad 415
samux0:0cf0e27feaad 416
samux0:0cf0e27feaad 417inline const char * parse(MbedJSONValue& out, const char * first, const char * last, std::string* err);
samux0:0cf0e27feaad 418
samux0:0cf0e27feaad 419/**
samux0:0cf0e27feaad 420* JSON string parser and creation of an MbedJSONValue
samux0:0cf0e27feaad 421*
samux0:0cf0e27feaad 422* @param out reference of an MbedJSONValue which will be filled according to the JSON string
samux0:0cf0e27feaad 423* @param str JSON string
samux0:0cf0e27feaad 424* @return A non empty string if there is a parsing error
samux0:0cf0e27feaad 425*
samux0:0cf0e27feaad 426*/
samux0:0cf0e27feaad 427
samux0:0cf0e27feaad 428inline std::string parse(MbedJSONValue& out, const char * str);
samux0:0cf0e27feaad 429inline bool _parse(MbedJSONValue& out, input& in);
samux0:0cf0e27feaad 430inline bool _parse_number(MbedJSONValue& out, input& in);
samux0:0cf0e27feaad 431inline bool _parse_string(MbedJSONValue& out, input& in);
samux0:0cf0e27feaad 432inline bool _parse_array(MbedJSONValue& out, input& in);
samux0:0cf0e27feaad 433inline bool _parse_object(MbedJSONValue& out, input& in);
samux0:0cf0e27feaad 434
samux0:0cf0e27feaad 435
samux0:0cf0e27feaad 436inline bool _parse_string(MbedJSONValue& out, input& in) {
samux0:0cf0e27feaad 437#ifdef DEBUG
samux0:0cf0e27feaad 438 printf("string detected\r\n");
samux0:0cf0e27feaad 439#endif
samux0:0cf0e27feaad 440 out = MbedJSONValue(std::string(""));
samux0:0cf0e27feaad 441 std::string& s = out.get<std::string>();
samux0:0cf0e27feaad 442 while (1) {
samux0:0cf0e27feaad 443 int ch = in.getc();
samux0:0cf0e27feaad 444 if (ch < ' ') {
samux0:0cf0e27feaad 445 in.ungetc();
samux0:0cf0e27feaad 446 return false;
samux0:0cf0e27feaad 447 } else if (ch == '"') {
samux0:0cf0e27feaad 448 return true;
samux0:0cf0e27feaad 449 } else if (ch == '\\') {
samux0:0cf0e27feaad 450 if ((ch = in.getc()) == -1) {
samux0:0cf0e27feaad 451 return false;
samux0:0cf0e27feaad 452 }
samux0:0cf0e27feaad 453 switch (ch) {
samux0:0cf0e27feaad 454#define MAP(sym, val) case sym: s.push_back(val); break
samux0:0cf0e27feaad 455 MAP('"', '\"');
samux0:0cf0e27feaad 456 MAP('\\', '\\');
samux0:0cf0e27feaad 457 MAP('/', '/');
samux0:0cf0e27feaad 458 MAP('b', '\b');
samux0:0cf0e27feaad 459 MAP('f', '\f');
samux0:0cf0e27feaad 460 MAP('n', '\n');
samux0:0cf0e27feaad 461 MAP('r', '\r');
samux0:0cf0e27feaad 462 MAP('t', '\t');
samux0:0cf0e27feaad 463#undef MAP
samux0:0cf0e27feaad 464 default:
samux0:0cf0e27feaad 465 return false;
samux0:0cf0e27feaad 466 }
samux0:0cf0e27feaad 467 } else {
samux0:0cf0e27feaad 468 s.push_back(ch);
samux0:0cf0e27feaad 469 }
samux0:0cf0e27feaad 470 }
samux0:0cf0e27feaad 471}
samux0:0cf0e27feaad 472
samux0:0cf0e27feaad 473inline bool _parse_array(MbedJSONValue& out, input& in) {
samux0:0cf0e27feaad 474#ifdef DEBUG
samux0:0cf0e27feaad 475 printf("array detected\r\n");
samux0:0cf0e27feaad 476#endif
samux0:0cf0e27feaad 477 int i = 0;
samux0:0cf0e27feaad 478 if (in.expect(']')) {
samux0:0cf0e27feaad 479 return true;
samux0:0cf0e27feaad 480 }
samux0:0cf0e27feaad 481 do {
samux0:0cf0e27feaad 482 if (! _parse(out[i], in)) {
samux0:0cf0e27feaad 483 return false;
samux0:0cf0e27feaad 484 }
samux0:0cf0e27feaad 485 i++;
samux0:0cf0e27feaad 486 } while (in.expect(','));
samux0:0cf0e27feaad 487 return in.expect(']');
samux0:0cf0e27feaad 488}
samux0:0cf0e27feaad 489
samux0:0cf0e27feaad 490inline bool _parse_object(MbedJSONValue& out, input& in) {
samux0:0cf0e27feaad 491#ifdef DEBUG
samux0:0cf0e27feaad 492 printf("object detected\r\n");
samux0:0cf0e27feaad 493#endif
samux0:0cf0e27feaad 494 if (in.expect('}')) {
samux0:0cf0e27feaad 495 return true;
samux0:0cf0e27feaad 496 }
samux0:0cf0e27feaad 497 do {
samux0:0cf0e27feaad 498 MbedJSONValue key, val;
samux0:0cf0e27feaad 499 if (in.expect('"') && _parse_string(key, in) && in.expect(':') && _parse(val, in)) {
samux0:0cf0e27feaad 500 out[key.get<std::string>().c_str()] = val;
samux0:0cf0e27feaad 501#ifdef DEBUG
samux0:0cf0e27feaad 502 printf("key: %s \r\n", key.get<std::string>().c_str());
samux0:0cf0e27feaad 503#endif
samux0:0cf0e27feaad 504 } else {
samux0:0cf0e27feaad 505 return false;
samux0:0cf0e27feaad 506 }
samux0:0cf0e27feaad 507 } while (in.expect(','));
samux0:0cf0e27feaad 508 return in.expect('}');
samux0:0cf0e27feaad 509}
samux0:0cf0e27feaad 510
samux0:0cf0e27feaad 511inline bool _parse_number(MbedJSONValue& out, input& in) {
samux0:0cf0e27feaad 512#ifdef DEBUG
samux0:0cf0e27feaad 513 printf("number detected\r\n");
samux0:0cf0e27feaad 514#endif
samux0:0cf0e27feaad 515 std::string num_str;
samux0:0cf0e27feaad 516 while (1) {
samux0:0cf0e27feaad 517 int ch = in.getc();
samux0:0cf0e27feaad 518 if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == '.'
samux0:0cf0e27feaad 519 || ch == 'e' || ch == 'E') {
samux0:0cf0e27feaad 520 num_str.push_back(ch);
samux0:0cf0e27feaad 521 } else {
samux0:0cf0e27feaad 522 in.ungetc();
samux0:0cf0e27feaad 523 break;
samux0:0cf0e27feaad 524 }
samux0:0cf0e27feaad 525 }
samux0:0cf0e27feaad 526 char* endp;
samux0:0cf0e27feaad 527 if (strchr(num_str.c_str(), '.') != NULL || strchr(num_str.c_str(), 'e') != NULL || strchr(num_str.c_str(), '+') != NULL)
samux0:0cf0e27feaad 528 out = MbedJSONValue(strtod(num_str.c_str(), &endp));
samux0:0cf0e27feaad 529 else
samux0:0cf0e27feaad 530 out = MbedJSONValue((int)strtod(num_str.c_str(), &endp));
samux0:0cf0e27feaad 531 return endp == num_str.c_str() + num_str.size();
samux0:0cf0e27feaad 532}
samux0:0cf0e27feaad 533
samux0:0cf0e27feaad 534inline bool _parse(MbedJSONValue& out, input& in) {
samux0:0cf0e27feaad 535 in.skip_ws();
samux0:0cf0e27feaad 536 int ch = in.getc();
samux0:0cf0e27feaad 537 switch (ch) {
samux0:0cf0e27feaad 538#define IS(ch, text, val) case ch: \
samux0:0cf0e27feaad 539 if (in.match(text)) { \
samux0:0cf0e27feaad 540 out = val; \
samux0:0cf0e27feaad 541 return true; \
samux0:0cf0e27feaad 542 } else { \
samux0:0cf0e27feaad 543 return false; \
samux0:0cf0e27feaad 544 }
samux0:0cf0e27feaad 545 IS('n', "ull", MbedJSONValue());
samux0:0cf0e27feaad 546 IS('f', "alse", MbedJSONValue(false));
samux0:0cf0e27feaad 547 IS('t', "rue", MbedJSONValue(true));
samux0:0cf0e27feaad 548#undef IS
samux0:0cf0e27feaad 549 case '"':
samux0:0cf0e27feaad 550 return _parse_string(out, in);
samux0:0cf0e27feaad 551 case '[':
samux0:0cf0e27feaad 552 return _parse_array(out, in);
samux0:0cf0e27feaad 553 case '{':
samux0:0cf0e27feaad 554 return _parse_object(out, in);
samux0:0cf0e27feaad 555 default:
samux0:0cf0e27feaad 556 if (('0' <= ch && ch <= '9') || ch == '-') {
samux0:0cf0e27feaad 557 in.ungetc();
samux0:0cf0e27feaad 558 return _parse_number(out, in);
samux0:0cf0e27feaad 559 }
samux0:0cf0e27feaad 560 break;
samux0:0cf0e27feaad 561 }
samux0:0cf0e27feaad 562 in.ungetc();
samux0:0cf0e27feaad 563 return false;
samux0:0cf0e27feaad 564}
samux0:0cf0e27feaad 565
samux0:0cf0e27feaad 566inline std::string parse(MbedJSONValue& out, const char * pos) {
samux0:0cf0e27feaad 567 const char * last = pos + strlen(pos);
samux0:0cf0e27feaad 568 std::string err;
samux0:0cf0e27feaad 569 pos = parse(out, pos, last, &err);
samux0:0cf0e27feaad 570 return err;
samux0:0cf0e27feaad 571}
samux0:0cf0e27feaad 572
samux0:0cf0e27feaad 573inline const char * parse(MbedJSONValue& out, const char * first, const char * last, std::string* err) {
samux0:0cf0e27feaad 574 input in = input(first, last);
samux0:0cf0e27feaad 575 if (! _parse(out, in) && err != NULL) {
samux0:0cf0e27feaad 576 char buf[64];
samux0:0cf0e27feaad 577 sprintf(buf, "syntax error at line %d near: ", in.line());
samux0:0cf0e27feaad 578 *err = buf;
samux0:0cf0e27feaad 579 while (1) {
samux0:0cf0e27feaad 580 int ch = in.getc();
samux0:0cf0e27feaad 581 if (ch == -1 || ch == '\n') {
samux0:0cf0e27feaad 582 break;
samux0:0cf0e27feaad 583 } else if (ch >= ' ') {
samux0:0cf0e27feaad 584 err->push_back(ch);
samux0:0cf0e27feaad 585 }
samux0:0cf0e27feaad 586 }
samux0:0cf0e27feaad 587 }
samux0:0cf0e27feaad 588 return in.cur();
samux0:0cf0e27feaad 589}
samux0:0cf0e27feaad 590
samux0:0cf0e27feaad 591#endif // _MbedMbedJSONValue_H_