Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: Json.h
- Revision:
- 0:c1cd8e6ecdc9
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Json.h Thu May 25 15:14:50 2017 +0545
@@ -0,0 +1,474 @@
+/* Json.h */
+/* Original Author: Faheem Inayat
+ * Created by "Night Crue" Team @ TechShop San Jose, CA
+ *
+ * MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __JSON_LIB_CLASS_H_
+#define __JSON_LIB_CLASS_H_
+
+#include "jsmn.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+/**
+ * C++ JSON wrapper over JSMN lib (https://github.com/zserge/jsmn).
+ *
+ * This C++ Class is a set of common tools/procedures as a C++ wrapper over JSMN
+ * JSON parser library. It is intended to provide the boiler-plate code, with
+ * intentions to reduce code clutter, in more of C++ fashion.
+ *
+ * In contrast to original library, Json is intended to work strictly with valid
+ * JSON structures. Non-standard JSON structures should result in an error.
+ *
+ * This class works explicitly on the indices returned by underlying JSMN
+ * library. In the scope of this class, its function parameters, return types,
+ * and documentation, the term 'index' will always mean the index of JSMN
+ * tokens, parsed by the Json constructor, unless and until explicitly mentioned
+ * otherwise.
+ */
+
+ /*
+ Example:
+
+ Let's say we have to parse the samle JSON:
+
+ {
+ "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
+ }
+ ]
+ }
+
+ 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}]}
+
+ Anyways, this class doesn't care about the formatting of JSON, however, it
+ DOES care about the validity of JSON. So here's a sample code to parse and
+ extract values from this JSON structure.
+
+ @code
+
+ void main ()
+ {
+ const char *jsonSource = "{\"team\":\"Night Crue\",\"company\":\"TechShop\",\"city\":\"San Jose\",\"info\":{\"name\":\"Amod\",\"age\":23}}";
+
+ Json json(jsonSource, strlen(jsonSource));
+ const char * a = json.JsonParse(jsonSource, "info");
+ logInfo("Information is %s",a);
+ const char * b = json.JsonParse(a, "name");
+ logInfo("Name is %s",b);
+ const char * c = json.JsonParse(a, "age");
+ logInfo("Age is %s",c);
+
+ // More on this example to come, later.
+ }
+
+ @endcode
+ */
+
+class Json
+{
+
+
+ private:
+ const unsigned int maxTokenCount;
+ const char * source;
+ const size_t sourceLength;
+ jsmntok_t * tokens;
+ int tokenCount;
+
+ // Copy COntructor is intentionally kept private to enforce the caller
+ // to use pointers/reference, and never pass-by-value
+ Json ( const Json & );
+
+
+ public:
+ /** The only constructor allowed.
+ As JSON object will create/allocate memory for its working, in favor of
+ small memory footprints, it is not allowed to be passed-by-value. So
+ there is no copy- or default-constructor
+
+ @param jsonString char string containing JSON data
+ @param length length of the jsonString
+ @param maxTokens optional maximum count of Tokens. Default is 32.
+ */
+ // Json ();
+ Json ( const char * jsonString, size_t length, unsigned int maxTokens = 32 );
+
+ // Json();
+
+
+ /** Although there is no virtual function to this class, destructor is
+ still made virtual, for just-in-case use. Destructor will delete the
+ 'tokens' array, created in constructor.
+ */
+ virtual ~Json ();
+
+
+ /** findKeyIndex will find and return the token index representing the
+ 'Key' in underlying JSON object. It is a strictly a linear key search
+ and will return the first occurrence, without the JSON node structure
+ semantics. For search in a specific node, refer to #findKeyIndex
+
+ @param key a char string to find as a 'Key' in JSON structure.
+ @param startingAt the starting token-index for 'key' search. The
+ search will NOT include this index, but instead will use the
+ next one as the starting point. In case, a negative value is
+ passed, search will start from '0'. It's caller's
+ responsibility to make sure what values they're passing.
+ Default value is set to '0', as the zero-th token index in any
+ valid JSON object should always be starting object brace '{'.
+ So default behavior is to always find the very first occurrence
+ of key as represented by 'key' parameter.
+
+ @return a non-zero positive integer, if a key is found in the source
+ JSON. If no key is found, -1 will be returned. There should be
+ no '0' value returned in any valid case.
+ */
+ int findKeyIndex ( const char * key, const int &startingAt = 0 ) const;
+
+
+ /** findKeyIndexIn will find and return the token index representing the
+ 'Key' in underlying JSON object node. It is strictly a single-level
+ key search function, and will NOT look for the key in any child JSON
+ nodes (JSON Object/Array).
+
+ @param key a char string to find as a 'Key' in JSON structure.
+ @param parentIndex the starting token-index for 'key' search. The
+ search will look for the key, only under the JSON node
+ represented by this parentIndex. Default value is '0', making
+ the default behavior to look for only root-level keys. The
+ valid value range is 0 to [parsedTokenCount()-1] both inclusive.
+
+ @return a non-zero positive integer, if a key is found in the source
+ JSON. If no key is found, -1 will be returned. There should be
+ no '0' value returned in any valid case.
+ */
+ int findKeyIndexIn ( const char * key, const int &parentIndex = 0 ) const;
+
+
+ /** findChildIndexOf will find and return the token index representing
+ first child a JSON node represented by parentIndex (that is either a
+ Key, an Object, or an Array), and exists after the startingAt value.
+ This function is particularly handy in iterating over Array Objects, or
+ getting the index for JSON 'Value' of a JSON 'Key'.
+
+ @param parentIndex token index representing the parent node in JSON
+ source. The valid value range is 0 to [parsedTokenCount()-1]
+ both inclusive.
+ @param startingAt describes the starting index of the nodes to search.
+ In other words, if caller wants to skip some nodes, they can
+ provide this value. Default value is 0, which means search for
+ all nodes in the parent.
+
+ @return a non-zero positive integer, if the child node is found in
+ source JSON. If no child is found, -1 will be returned. There
+ should be no '0' value returned in any valid case.
+ */
+ int findChildIndexOf ( const int &parentIndex, const int &startingAt = 0 ) const;
+
+
+ /** matches will tell if the token data (either key or value) matches
+ with the value provided. This function is particularly handy in
+ iterating over the keys, and finding a specific key, in an object. The
+ comparison is case-sensitive. i.e. 'Apple' will NOT match with 'apple'.
+
+ @param tokenIndex representing the token to compare. The valid value
+ range is 0 to [parsedTokenCount()-1] both inclusive.
+ @param value to compare the token data with.
+
+ @return true if the token data matches with value. false will be
+ returned either the value doesn't match OR the tokenIndex is
+ not valid.
+ */
+ bool matches ( const int & tokenIndex, const char * value ) const;
+
+
+ /** parsedTokenCount will tell how many tokens have been parsed by JSMN
+ parser. It is a utility function, for token validity.
+
+ @return non-negative integer number of tokens parsed by JSMN library.
+ Negative value may be returned in case of error, but this
+ behavior is not tested, yet.
+ */
+ inline int parsedTokenCount () const;
+
+
+ /** isValidJson will tell the caller if the parsed JSON was valid,
+ parsed, and accepted to further work on.
+
+ @return true if the JSON is valid, false otherwise.
+ */
+ inline bool isValidJson () const;
+
+
+ /** isValidToken will tell the caller if the tokenIndex is in valid
+ range. The valid value range is 0 to [parsedTokenCount()-1] both
+ inclusive.
+
+ @param tokenIndex representing the token in the JSON source
+
+ @return true if the JSON is valid, false otherwise.
+ */
+ inline bool isValidToken ( const int tokenIndex ) const;
+
+
+ /** type will return the JSMN type represented by the tokenIndex.
+
+ @param tokenIndex representing the token in the JSON source. The valid
+ value range is 0 to [parsedTokenCount()-1] both inclusive.
+
+ @return the type represented by tokenIndex. In case of invalid
+ tokenIndex, JSMN_UNDEFINED is returned.
+ */
+ inline jsmntype_t type ( const int tokenIndex ) const;
+
+
+ /** parent is a utility function to get the parent index of the
+ tokenIndex passed.
+
+ @param tokenIndex representing the token in the JSON source. The valid
+ value range is 0 to [parsedTokenCount()-1] both inclusive.
+
+ @return the parentIndex if the node has a parent, and tokenIndex is a
+ valid index. In case of no parent, or invalid tokenIndex, -1
+ is returned.
+ */
+ inline int parent ( const int tokenIndex ) const;
+
+
+ /** childCount returns the number of children sharing the same parent.
+ This utility function is handy for iterating over Arrays or Objects.
+
+ @param tokenIndex representing the token in the JSON source. The valid
+ value range is 0 to [parsedTokenCount()-1] both inclusive.
+
+ @return non-negative integer representing the number of children
+ tokenIndex node has. 0 is a valid number, in case the node has
+ no child nodes. -1 will be returned if the tokenIndex is not
+ valid.
+ */
+ inline int childCount ( const int tokenIndex ) const;
+
+
+ /** tokenLength returns the number of characters a node takes up in JSON
+ source string.
+
+ @param tokenIndex representing the token in the JSON source. The valid
+ value range is 0 to [parsedTokenCount()-1] both inclusive.
+
+ @return positive integer value representing the length of the token
+ sub-string in the source JSON. The 0 value is an invalid state
+ and should never occur. -1 will be returned in case of invalid
+ tokenIndex.
+ */
+ inline int tokenLength ( const int tokenIndex ) const;
+
+
+ /** tokenAddress returns the pointer that marks as the start of token
+ in JSON source string. This is a utility function for character/string
+ manipulation by the caller.
+
+ @param tokenIndex representing the token in the JSON source. The valid
+ value range is 0 to [parsedTokenCount()-1] both inclusive.
+
+ @return a non-NULL pointer will be returned if tokenIndex is valid, -1
+ otherwise.
+ */
+ inline const char * tokenAddress ( const int tokenIndex ) const;
+
+
+ /** tokenInterValue will convert the value as int represented by the
+ tokenIndex. A typical use is that caller has found the Key-index, and
+ then has retrieved the Value-index (by using findChildIndexOf function)
+ , and now they want to read the value of Value-index, as integer value.
+
+ @param tokenIndex representing the "value" in the JSON source. The
+ valid value range is 0 to [parsedTokenCount()-1] both inclusive.
+
+ @param returnValue is a return-parameter passed by reference to hold up
+ the integer value parsed by this function. If the converted
+ value would be out of the range of representable values by an
+ int, it causes undefined behavior. It is caller's
+ responsibility to check for these cases.
+
+ @return 0 if the operation is successful. -1 if tokenIndex is invalid.
+ */
+ int tokenIntegerValue ( const int tokenIndex, int &returnValue ) const;
+
+
+ /** tokenNumberValue will convert the value as float represented by the
+ tokenIndex. A typical use is that caller has found the Key-index, and
+ then has retrieved the Value-index (by using findChildIndexOf function)
+ , and now they want to read the value of Value-index, as floating-point
+ value.
+
+ @param tokenIndex representing the "value" in the JSON source. The
+ valid value range is 0 to [parsedTokenCount()-1] both inclusive.
+
+ @param returnValue is a return-parameter passed by reference to hold up
+ the floating-point value parsed by this function. If the
+ converted value would be out of the range of representable
+ values by a float, it causes undefined behavior. It is caller's
+ responsibility to check for these cases.
+
+ @return 0 if the operation is successful. -1 if tokenIndex is invalid.
+ */
+ int tokenNumberValue ( const int tokenIndex, float &returnValue ) const;
+
+
+ /** tokenBooleanValue will convert the value as bool represented by
+ the tokenIndex. A typical use is that caller has found the Key-index,
+ and then has retrieved the Value-index (by using findChildIndexOf
+ function), and now they want to read the value of Value-index, as
+ boolean value.
+
+ @param tokenIndex representing the "value" in the JSON source. The
+ valid value range is 0 to [parsedTokenCount()-1] both inclusive.
+
+ @param returnValue is a return-parameter passed by reference to hold up
+ the bool value parsed by this function.
+
+ @return 0 if the operation is successful. -1 if tokenIndex is invalid.
+ */
+ int tokenBooleanValue ( const int tokenIndex, bool &returnValue ) const;
+
+
+ /** unescape is a utility function to unescape a JSON string. This
+ function does not change any state of Json object, and is a pure
+ static utility function. This function is in-pace unescaping, and WILL
+ modify the source parameter.
+
+ @param jsonString representing an escaped JSON string. This parameter
+ is also the return parameter as well. All modifications will be
+ reflected in this parameter.
+
+ @return pointer to unescaped JSON string. This is exactly the same
+ pointer as jsonString parameter.
+ */
+
+ const char * JsonParse(const char * jsonString, const char * key);
+
+ static char * unescape ( char * jsonString );
+};
+
+inline int Json::parsedTokenCount () const
+{
+ return tokenCount;
+}
+
+inline bool Json::isValidJson () const
+{
+ return ( tokenCount >= 1 );
+}
+
+inline bool Json::isValidToken ( const int tokenIndex ) const
+{
+ return ( tokenIndex >= 0 && tokenIndex < tokenCount );
+}
+
+inline jsmntype_t Json::type ( const int tokenIndex ) const
+{
+ jsmntype_t retVal = JSMN_UNDEFINED;
+
+ if ( isValidToken ( tokenIndex ) )
+ {
+ retVal = tokens [ tokenIndex ].type;
+ }
+
+ return retVal;
+}
+
+inline int Json::parent ( const int tokenIndex ) const
+{
+ int retVal = -1;
+
+ if ( isValidToken ( tokenIndex ) )
+ {
+ retVal = tokens [ tokenIndex ].parent;
+ }
+
+ return retVal;
+}
+
+inline int Json::childCount ( const int tokenIndex ) const
+{
+ int retVal = -1;
+
+ if ( isValidToken ( tokenIndex ) )
+ {
+ retVal = tokens [ tokenIndex ].childCount;
+ }
+
+ return retVal;
+}
+
+inline int Json::tokenLength ( const int tokenIndex ) const
+{
+ int retVal = -1;
+
+ if ( isValidToken ( tokenIndex ) )
+ {
+ retVal = tokens [ tokenIndex ].end - tokens [ tokenIndex ].start;
+ }
+
+ return retVal;
+}
+
+inline const char * Json::tokenAddress ( const int tokenIndex ) const
+{
+ char * retVal = NULL;
+
+ if ( isValidToken ( tokenIndex ) )
+ {
+ retVal = (char *) source + tokens [ tokenIndex ].start;
+ }
+
+ return retVal;
+}
+
+#endif
+