iot_water_monitor_v2
Dependencies: easy-connect-v16 Watchdog FP MQTTPacket RecordType-v-16 watersenor_and_temp_code
Json.h
00001 /* Json.h */ 00002 /* Original Author: Faheem Inayat 00003 * Created by "Night Crue" Team @ TechShop San Jose, CA 00004 * 00005 * MIT License 00006 * 00007 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00008 * and associated documentation files (the "Software"), to deal in the Software without restriction, 00009 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 00010 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 00011 * furnished to do so, subject to the following conditions: 00012 * 00013 * The above copyright notice and this permission notice shall be included in all copies or 00014 * substantial portions of the Software. 00015 * 00016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00017 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00018 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00019 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00020 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00021 */ 00022 00023 #ifndef __JSON_LIB_CLASS_H_ 00024 #define __JSON_LIB_CLASS_H_ 00025 00026 #include "jsmn.h" 00027 #include <stdlib.h> 00028 #include <string.h> 00029 00030 /** 00031 * C++ JSON wrapper over JSMN lib (https://github.com/zserge/jsmn). 00032 * 00033 * This C++ Class is a set of common tools/procedures as a C++ wrapper over JSMN 00034 * JSON parser library. It is intended to provide the boiler-plate code, with 00035 * intentions to reduce code clutter, in more of C++ fashion. 00036 * 00037 * In contrast to original library, Json is intended to work strictly with valid 00038 * JSON structures. Non-standard JSON structures should result in an error. 00039 * 00040 * This class works explicitly on the indices returned by underlying JSMN 00041 * library. In the scope of this class, its function parameters, return types, 00042 * and documentation, the term 'index' will always mean the index of JSMN 00043 * tokens, parsed by the Json constructor, unless and until explicitly mentioned 00044 * otherwise. 00045 */ 00046 00047 /* 00048 Example: 00049 00050 Let's say we have to parse the samle JSON: 00051 00052 { 00053 "team": "Night Crue", 00054 "company": "TechShop", 00055 "city": "San Jose", 00056 "state": "California", 00057 "country": "USA", 00058 "zip": 95113, 00059 "active": true, 00060 "members": 00061 [ 00062 { 00063 "firstName": "John", 00064 "lastName": "Smith", 00065 "active": false, 00066 "hours": 18.5, 00067 "age": 21 00068 }, 00069 { 00070 "firstName": "Foo", 00071 "lastName": "Bar", 00072 "active": true, 00073 "hours": 25, 00074 "age": 21 00075 }, 00076 { 00077 "firstName": "Peter", 00078 "lastName": "Jones", 00079 "active": false 00080 } 00081 ] 00082 } 00083 00084 which without the "white spaces" will look like: {"team":"Night Crue","company":"TechShop","city":"San Jose","state":"California","country":"USA","zip":95113,"active":true,"members":[{"firstName":"John","lastName":"Smith","active":false,"hours":18.5,"age":21},{"firstName":"Foo","lastName":"Bar","active":true,"hours":25,"age":21},{"firstName":"Peter","lastName":"Jones","active":false}]} 00085 00086 Anyways, this class doesn't care about the formatting of JSON, however, it 00087 DOES care about the validity of JSON. So here's a sample code to parse and 00088 extract values from this JSON structure. 00089 00090 @code 00091 00092 void main () 00093 { 00094 // Note that the JSON object is 'escaped'. One doesn't get escaped JSON 00095 // directly from the webservice, if the response type is APPLICATION/JSON 00096 // Just a little thing to keep in mind. 00097 const char * jsonSource = "{\"team\":\"Night Crue\",\"company\":\"TechShop\",\"city\":\"San Jose\",\"state\":\"California\",\"country\":\"USA\",\"zip\":95113,\"active\":true,\"members\":[{\"firstName\":\"John\",\"lastName\":\"Smith\",\"active\":false,\"hours\":18.5,\"age\":21},{\"firstName\":\"Foo\",\"lastName\":\"Bar\",\"active\":true,\"hours\":25,\"age\":21},{\"firstName\":\"Peter\",\"lastName\":\"Jones\",\"active\":false}]}"; 00098 00099 Json json ( jsonSource, strlen ( jsonSource ) ); 00100 00101 if ( !json.isValidJson () ) 00102 { 00103 logError ( "Invalid JSON: %s", jsonSource ); 00104 return; 00105 } 00106 00107 if ( json.type (0) != JSMN_OBJECT ) 00108 { 00109 logError ( "Invalid JSON. ROOT element is not Object: %s", jsonSource ); 00110 return; 00111 } 00112 00113 // Let's get the value of key "city" in ROOT object, and copy into 00114 // cityValue 00115 char cityValue [ 32 ]; 00116 00117 logInfo ( "Finding \"city\" Key ... " ); 00118 // ROOT object should have '0' tokenIndex, and -1 parentIndex 00119 int cityKeyIndex = json.findKeyIndexIn ( "city", 0 ); 00120 if ( cityKeyIndex == -1 ) 00121 { 00122 // Error handling part ... 00123 logError ( "\"city\" does not exist ... do something!!" ); 00124 } 00125 else 00126 { 00127 // Find the first child index of key-node "city" 00128 int cityValueIndex = json.findChildIndexOf ( cityKeyIndex, -1 ); 00129 if ( cityValueIndex > 0 ) 00130 { 00131 const char * valueStart = json.tokenAddress ( cityValueIndex ); 00132 int valueLength = json.tokenLength ( cityValueIndex ); 00133 strncpy ( cityValue, valueStart, valueLength ); 00134 cityValue [ valueLength ] = 0; // NULL-terminate the string 00135 00136 //let's print the value. It should be "San Jose" 00137 logInfo ( "city: %s", cityValue ); 00138 } 00139 } 00140 00141 // More on this example to come, later. 00142 } 00143 00144 @endcode 00145 */ 00146 00147 class Json 00148 { 00149 private: 00150 const unsigned int maxTokenCount; 00151 const char * source; 00152 const size_t sourceLength; 00153 jsmntok_t * tokens; 00154 int tokenCount; 00155 00156 // Copy COntructor is intentionally kept private to enforce the caller 00157 // to use pointers/reference, and never pass-by-value 00158 Json ( const Json & ); 00159 00160 public: 00161 /** The only constructor allowed. 00162 As JSON object will create/allocate memory for its working, in favor of 00163 small memory footprints, it is not allowed to be passed-by-value. So 00164 there is no copy- or default-constructor 00165 00166 @param jsonString char string containing JSON data 00167 @param length length of the jsonString 00168 @param maxTokens optional maximum count of Tokens. Default is 32. 00169 */ 00170 Json ( const char * jsonString, size_t length, unsigned int maxTokens = 32 ); 00171 00172 00173 /** Although there is no virtual function to this class, destructor is 00174 still made virtual, for just-in-case use. Destructor will delete the 00175 'tokens' array, created in constructor. 00176 */ 00177 virtual ~Json (); 00178 00179 00180 /** findKeyIndex will find and return the token index representing the 00181 'Key' in underlying JSON object. It is a strictly a linear key search 00182 and will return the first occurrence, without the JSON node structure 00183 semantics. For search in a specific node, refer to #findKeyIndex 00184 00185 @param key a char string to find as a 'Key' in JSON structure. 00186 @param startingAt the starting token-index for 'key' search. The 00187 search will NOT include this index, but instead will use the 00188 next one as the starting point. In case, a negative value is 00189 passed, search will start from '0'. It's caller's 00190 responsibility to make sure what values they're passing. 00191 Default value is set to '0', as the zero-th token index in any 00192 valid JSON object should always be starting object brace '{'. 00193 So default behavior is to always find the very first occurrence 00194 of key as represented by 'key' parameter. 00195 00196 @return a non-zero positive integer, if a key is found in the source 00197 JSON. If no key is found, -1 will be returned. There should be 00198 no '0' value returned in any valid case. 00199 */ 00200 int findKeyIndex ( const char * key, const int &startingAt = 0 ) const; 00201 00202 00203 /** findKeyIndexIn will find and return the token index representing the 00204 'Key' in underlying JSON object node. It is strictly a single-level 00205 key search function, and will NOT look for the key in any child JSON 00206 nodes (JSON Object/Array). 00207 00208 @param key a char string to find as a 'Key' in JSON structure. 00209 @param parentIndex the starting token-index for 'key' search. The 00210 search will look for the key, only under the JSON node 00211 represented by this parentIndex. Default value is '0', making 00212 the default behavior to look for only root-level keys. The 00213 valid value range is 0 to [parsedTokenCount()-1] both inclusive. 00214 00215 @return a non-zero positive integer, if a key is found in the source 00216 JSON. If no key is found, -1 will be returned. There should be 00217 no '0' value returned in any valid case. 00218 */ 00219 int findKeyIndexIn ( const char * key, const int &parentIndex = 0 ) const; 00220 00221 00222 /** findChildIndexOf will find and return the token index representing 00223 first child a JSON node represented by parentIndex (that is either a 00224 Key, an Object, or an Array), and exists after the startingAt value. 00225 This function is particularly handy in iterating over Array Objects, or 00226 getting the index for JSON 'Value' of a JSON 'Key'. 00227 00228 @param parentIndex token index representing the parent node in JSON 00229 source. The valid value range is 0 to [parsedTokenCount()-1] 00230 both inclusive. 00231 @param startingAt describes the starting index of the nodes to search. 00232 In other words, if caller wants to skip some nodes, they can 00233 provide this value. Default value is 0, which means search for 00234 all nodes in the parent. 00235 00236 @return a non-zero positive integer, if the child node is found in 00237 source JSON. If no child is found, -1 will be returned. There 00238 should be no '0' value returned in any valid case. 00239 */ 00240 int findChildIndexOf ( const int &parentIndex, const int &startingAt = 0 ) const; 00241 00242 00243 /** matches will tell if the token data (either key or value) matches 00244 with the value provided. This function is particularly handy in 00245 iterating over the keys, and finding a specific key, in an object. The 00246 comparison is case-sensitive. i.e. 'Apple' will NOT match with 'apple'. 00247 00248 @param tokenIndex representing the token to compare. The valid value 00249 range is 0 to [parsedTokenCount()-1] both inclusive. 00250 @param value to compare the token data with. 00251 00252 @return true if the token data matches with value. false will be 00253 returned either the value doesn't match OR the tokenIndex is 00254 not valid. 00255 */ 00256 bool matches ( const int & tokenIndex, const char * value ) const; 00257 00258 00259 /** parsedTokenCount will tell how many tokens have been parsed by JSMN 00260 parser. It is a utility function, for token validity. 00261 00262 @return non-negative integer number of tokens parsed by JSMN library. 00263 Negative value may be returned in case of error, but this 00264 behavior is not tested, yet. 00265 */ 00266 inline int parsedTokenCount () const; 00267 00268 00269 /** isValidJson will tell the caller if the parsed JSON was valid, 00270 parsed, and accepted to further work on. 00271 00272 @return true if the JSON is valid, false otherwise. 00273 */ 00274 inline bool isValidJson () const; 00275 00276 00277 /** isValidToken will tell the caller if the tokenIndex is in valid 00278 range. The valid value range is 0 to [parsedTokenCount()-1] both 00279 inclusive. 00280 00281 @param tokenIndex representing the token in the JSON source 00282 00283 @return true if the JSON is valid, false otherwise. 00284 */ 00285 inline bool isValidToken ( const int tokenIndex ) const; 00286 00287 00288 /** type will return the JSMN type represented by the tokenIndex. 00289 00290 @param tokenIndex representing the token in the JSON source. The valid 00291 value range is 0 to [parsedTokenCount()-1] both inclusive. 00292 00293 @return the type represented by tokenIndex. In case of invalid 00294 tokenIndex, JSMN_UNDEFINED is returned. 00295 */ 00296 inline jsmntype_t type ( const int tokenIndex ) const; 00297 00298 00299 /** parent is a utility function to get the parent index of the 00300 tokenIndex passed. 00301 00302 @param tokenIndex representing the token in the JSON source. The valid 00303 value range is 0 to [parsedTokenCount()-1] both inclusive. 00304 00305 @return the parentIndex if the node has a parent, and tokenIndex is a 00306 valid index. In case of no parent, or invalid tokenIndex, -1 00307 is returned. 00308 */ 00309 inline int parent ( const int tokenIndex ) const; 00310 00311 00312 /** childCount returns the number of children sharing the same parent. 00313 This utility function is handy for iterating over Arrays or Objects. 00314 00315 @param tokenIndex representing the token in the JSON source. The valid 00316 value range is 0 to [parsedTokenCount()-1] both inclusive. 00317 00318 @return non-negative integer representing the number of children 00319 tokenIndex node has. 0 is a valid number, in case the node has 00320 no child nodes. -1 will be returned if the tokenIndex is not 00321 valid. 00322 */ 00323 inline int childCount ( const int tokenIndex ) const; 00324 00325 00326 /** tokenLength returns the number of characters a node takes up in JSON 00327 source string. 00328 00329 @param tokenIndex representing the token in the JSON source. The valid 00330 value range is 0 to [parsedTokenCount()-1] both inclusive. 00331 00332 @return positive integer value representing the length of the token 00333 sub-string in the source JSON. The 0 value is an invalid state 00334 and should never occur. -1 will be returned in case of invalid 00335 tokenIndex. 00336 */ 00337 inline int tokenLength ( const int tokenIndex ) const; 00338 00339 00340 /** tokenAddress returns the pointer that marks as the start of token 00341 in JSON source string. This is a utility function for character/string 00342 manipulation by the caller. 00343 00344 @param tokenIndex representing the token in the JSON source. The valid 00345 value range is 0 to [parsedTokenCount()-1] both inclusive. 00346 00347 @return a non-NULL pointer will be returned if tokenIndex is valid, -1 00348 otherwise. 00349 */ 00350 inline const char * tokenAddress ( const int tokenIndex ) const; 00351 00352 00353 /** tokenInterValue will convert the value as int represented by the 00354 tokenIndex. A typical use is that caller has found the Key-index, and 00355 then has retrieved the Value-index (by using findChildIndexOf function) 00356 , and now they want to read the value of Value-index, as integer value. 00357 00358 @param tokenIndex representing the "value" in the JSON source. The 00359 valid value range is 0 to [parsedTokenCount()-1] both inclusive. 00360 00361 @param returnValue is a return-parameter passed by reference to hold up 00362 the integer value parsed by this function. If the converted 00363 value would be out of the range of representable values by an 00364 int, it causes undefined behavior. It is caller's 00365 responsibility to check for these cases. 00366 00367 @return 0 if the operation is successful. -1 if tokenIndex is invalid. 00368 */ 00369 int tokenIntegerValue ( const int tokenIndex, int &returnValue ) const; 00370 00371 00372 /** tokenNumberValue will convert the value as float represented by the 00373 tokenIndex. A typical use is that caller has found the Key-index, and 00374 then has retrieved the Value-index (by using findChildIndexOf function) 00375 , and now they want to read the value of Value-index, as floating-point 00376 value. 00377 00378 @param tokenIndex representing the "value" in the JSON source. The 00379 valid value range is 0 to [parsedTokenCount()-1] both inclusive. 00380 00381 @param returnValue is a return-parameter passed by reference to hold up 00382 the floating-point value parsed by this function. If the 00383 converted value would be out of the range of representable 00384 values by a float, it causes undefined behavior. It is caller's 00385 responsibility to check for these cases. 00386 00387 @return 0 if the operation is successful. -1 if tokenIndex is invalid. 00388 */ 00389 int tokenNumberValue ( const int tokenIndex, float &returnValue ) const; 00390 00391 00392 /** tokenBooleanValue will convert the value as bool represented by 00393 the tokenIndex. A typical use is that caller has found the Key-index, 00394 and then has retrieved the Value-index (by using findChildIndexOf 00395 function), and now they want to read the value of Value-index, as 00396 boolean value. 00397 00398 @param tokenIndex representing the "value" in the JSON source. The 00399 valid value range is 0 to [parsedTokenCount()-1] both inclusive. 00400 00401 @param returnValue is a return-parameter passed by reference to hold up 00402 the bool value parsed by this function. 00403 00404 @return 0 if the operation is successful. -1 if tokenIndex is invalid. 00405 */ 00406 int tokenBooleanValue ( const int tokenIndex, bool &returnValue ) const; 00407 00408 00409 /** unescape is a utility function to unescape a JSON string. This 00410 function does not change any state of Json object, and is a pure 00411 static utility function. This function is in-pace unescaping, and WILL 00412 modify the source parameter. 00413 00414 @param jsonString representing an escaped JSON string. This parameter 00415 is also the return parameter as well. All modifications will be 00416 reflected in this parameter. 00417 00418 @return pointer to unescaped JSON string. This is exactly the same 00419 pointer as jsonString parameter. 00420 */ 00421 static char * unescape ( char * jsonString ); 00422 }; 00423 00424 inline int Json::parsedTokenCount () const 00425 { 00426 return tokenCount; 00427 } 00428 00429 inline bool Json::isValidJson () const 00430 { 00431 return ( tokenCount >= 1 ); 00432 } 00433 00434 inline bool Json::isValidToken ( const int tokenIndex ) const 00435 { 00436 return ( tokenIndex >= 0 && tokenIndex < tokenCount ); 00437 } 00438 00439 inline jsmntype_t Json::type ( const int tokenIndex ) const 00440 { 00441 jsmntype_t retVal = JSMN_UNDEFINED; 00442 00443 if ( isValidToken ( tokenIndex ) ) 00444 { 00445 retVal = tokens [ tokenIndex ].type; 00446 } 00447 00448 return retVal; 00449 } 00450 00451 inline int Json::parent ( const int tokenIndex ) const 00452 { 00453 int retVal = -1; 00454 00455 if ( isValidToken ( tokenIndex ) ) 00456 { 00457 retVal = tokens [ tokenIndex ].parent; 00458 } 00459 00460 return retVal; 00461 } 00462 00463 inline int Json::childCount ( const int tokenIndex ) const 00464 { 00465 int retVal = -1; 00466 00467 if ( isValidToken ( tokenIndex ) ) 00468 { 00469 retVal = tokens [ tokenIndex ].childCount; 00470 } 00471 00472 return retVal; 00473 } 00474 00475 inline int Json::tokenLength ( const int tokenIndex ) const 00476 { 00477 int retVal = -1; 00478 00479 if ( isValidToken ( tokenIndex ) ) 00480 { 00481 retVal = tokens [ tokenIndex ].end - tokens [ tokenIndex ].start; 00482 } 00483 00484 return retVal; 00485 } 00486 00487 inline const char * Json::tokenAddress ( const int tokenIndex ) const 00488 { 00489 char * retVal = NULL; 00490 00491 if ( isValidToken ( tokenIndex ) ) 00492 { 00493 retVal = (char *) source + tokens [ tokenIndex ].start; 00494 } 00495 00496 return retVal; 00497 } 00498 00499 #endif 00500
Generated on Tue Jul 12 2022 20:06:04 by 1.7.2