iot_water_monitor_v2

Dependencies:   easy-connect-v16 Watchdog FP MQTTPacket RecordType-v-16 watersenor_and_temp_code

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Json.h Source File

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