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.
Revision 0:c1cd8e6ecdc9, committed 2017-05-25
- Comitter:
- Amod Amatya amodamatya@gmail.com
- Date:
- Thu May 25 15:14:50 2017 +0545
- Commit message:
- ini
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Json.cpp Thu May 25 15:14:50 2017 +0545
@@ -0,0 +1,308 @@
+/* Json.cpp */
+/* 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.
+ */
+
+#include "Json.h"
+#include <stdio.h>
+
+
+// Json::Json() : maxTokenCount ( 0 ), sourceLength ( 0 )
+// {
+
+// }
+// Json::Json() :maxTokenCount ( 0 ), source ( NULL ), sourceLength ( 0 )
+// {
+// tokenCount = 0;
+// tokens = NULL;
+// }
+
+Json::Json ( const char * jsonString, size_t length, unsigned int maxTokens )
+ : maxTokenCount ( maxTokens ), source ( jsonString ), sourceLength ( length )
+{
+ jsmn_parser parser;
+ tokens = new jsmntok_t [ maxTokenCount ];
+
+ jsmn_init ( &parser );
+ tokenCount = jsmn_parse ( &parser, jsonString, length, tokens, maxTokenCount );
+}
+
+Json::Json ( const Json & )
+ : maxTokenCount ( 0 ), source ( NULL ), sourceLength ( 0 )
+{
+ tokenCount = 0;
+ tokens = NULL;
+}
+
+Json::~Json ()
+{
+ delete [] tokens;
+}
+
+int Json::findKeyIndex ( const char * key, const int &startingAt ) const
+{
+ int retVal = -1;
+
+ int i = startingAt + 1;
+ if ( i < 0 ) {
+ i = 0;
+ }
+
+ for ( ; i < tokenCount; i++ )
+ {
+ jsmntok_t t = tokens [ i ];
+
+ if ( t.type == JSMN_KEY )
+ {
+ size_t keyLength = (size_t) ( t.end - t.start );
+ if ( ( strlen ( key ) == keyLength ) && ( strncmp ( source + t.start, key, keyLength ) == 0 ) )
+ {
+ retVal = i;
+ break;
+ }
+ }
+ }
+
+ return retVal;
+}
+
+int Json::findKeyIndexIn ( const char * key, const int &parentIndex ) const
+{
+ int retVal = -1;
+
+ if ( isValidToken ( parentIndex ) )
+ {
+ for ( int i = parentIndex + 1; i < tokenCount; i++ )
+ {
+ jsmntok_t t = tokens [ i ];
+
+ if ( t.end >= tokens [ parentIndex ].end )
+ {
+ break;
+ }
+
+ if ( ( t.type == JSMN_KEY ) && ( t.parent == parentIndex ) )
+ {
+ size_t keyLength = (size_t) ( t.end - t.start );
+ if ( ( strlen ( key ) == keyLength ) && ( strncmp ( source + t.start, key, keyLength ) == 0 ) )
+ {
+ retVal = i;
+ break;
+ }
+ }
+ }
+ }
+
+ return retVal;
+}
+
+int Json::findChildIndexOf ( const int &parentIndex, const int &startingAt ) const
+{
+ int retVal = -1;
+
+ if ( isValidToken ( parentIndex ) )
+ {
+
+ jsmntype_t type = tokens [ parentIndex ].type;
+ if ( ( type == JSMN_KEY ) || ( type == JSMN_OBJECT ) || ( type == JSMN_ARRAY ) )
+ {
+ int i = startingAt + 1;
+ if ( startingAt < 0 )
+ {
+ i = 0;
+ }
+
+ for ( i += parentIndex; i < tokenCount; i++ )
+ {
+ if ( tokens [ i ].parent == parentIndex )
+ {
+ retVal = i;
+ break;
+ }
+ }
+ }
+ }
+
+ return retVal;
+}
+
+bool Json::matches ( const int & tokenIndex, const char * value ) const
+{
+ bool retVal = false;
+
+ if ( isValidToken ( tokenIndex ) )
+ {
+ jsmntok_t token = tokens [ tokenIndex ];
+ retVal = ( strncmp ( source + token.start, value, ( token.end - token.start ) ) == 0 );
+ }
+
+ return retVal;
+}
+
+int Json::tokenIntegerValue ( const int tokenIndex, int &returnValue ) const
+{
+ int retVal = -1;
+
+ if ( type ( tokenIndex ) == JSMN_PRIMITIVE )
+ {
+ int len = tokenLength ( tokenIndex );
+ char * tok = new char [ len + 1 ];
+ strncpy ( tok, tokenAddress ( tokenIndex ), len );
+ tok [ len ] = 0;
+ returnValue = atoi ( tok );
+ delete [] tok;
+ retVal = 0;
+ }
+ return retVal;
+}
+
+int Json::tokenNumberValue ( const int tokenIndex, float &returnValue ) const
+{
+ int retVal = -1;
+
+ if ( type ( tokenIndex ) == JSMN_PRIMITIVE )
+ {
+ int len = tokenLength ( tokenIndex );
+ char * tok = new char [ len + 1 ];
+ strncpy ( tok, tokenAddress ( tokenIndex ), len );
+ tok [ len ] = 0;
+ returnValue = atof ( tok );
+ delete [] tok;
+ retVal = 0;
+ }
+
+ return retVal;
+}
+
+int Json::tokenBooleanValue ( const int tokenIndex, bool &returnValue ) const
+{
+ int retVal = -1;
+
+ if ( type ( tokenIndex ) == JSMN_PRIMITIVE )
+ {
+ returnValue = matches ( tokenIndex, "true" );
+ retVal = 0;
+ }
+
+ return retVal;
+}
+
+char * Json::unescape ( char * jsonString )
+{
+ if ( jsonString != NULL )
+ {
+ int stringIndex = 0;
+ int indentLevel = 0;
+ int quoteCount = 0;
+ for ( int i = 0; jsonString [ i ] != 0; i ++ )
+ {
+ switch ( jsonString [ i ] )
+ {
+ case '{':
+ indentLevel ++;
+ break;
+
+ case '}':
+ indentLevel --;
+ if ( indentLevel == 0 ) {
+ // Just close and return the first valid JSON object. No need to handle complex cases.
+ jsonString [ stringIndex ++ ] = '}';
+ jsonString [ stringIndex ] = 0;
+ return jsonString;
+ }
+ break;
+
+ case '\\':
+ i ++;
+ break;
+
+ case '"':
+ quoteCount ++;
+ break;
+ }
+
+ if ( indentLevel > 0 )
+ {
+ if ( quoteCount == 0 ) {
+ return jsonString; //No need to unescape. JsonString needs to be already escaped
+ }
+ jsonString [ stringIndex ++ ] = jsonString [ i ];
+ }
+ }
+ jsonString [ stringIndex ] = 0;
+ }
+
+ return jsonString;
+}
+
+const char * Json::JsonParse(const char * jsonString, const char * key)
+{
+
+ Json json ( jsonString, strlen ( jsonString));
+
+ if ( !json.isValidJson () )
+ {
+ printf( "Invalid JSON: %s", jsonString );
+ }
+
+ if ( json.type (0) != JSMN_OBJECT )
+ {
+ printf ( "Invalid JSON. ROOT element is not Object: %s", jsonString );
+ }
+
+ char *info1 = new char[32];
+
+ // ROOT object should have '0' tokenIndex, and -1 parentIndex
+ int KeyIndex = json.findKeyIndexIn(key,0);
+
+ if (KeyIndex == -1)
+ {
+ // Error handling part ...
+ printf ( "Key does not exist");
+ }
+ else
+ {
+ // Find the first child index of key-node "info"
+ int ValueIndex = json.findChildIndexOf (KeyIndex, -1 );
+ if (ValueIndex > 0 )
+ {
+ const char * valueStart = json.tokenAddress (ValueIndex );
+ int valueLength = json.tokenLength (ValueIndex );
+ strncpy ( info1, valueStart, valueLength );
+ // info[valueLength] = 0; // NULL-terminate the string
+ // strcpy(info1, info);
+ //let's print the value. It should be "San Jose"
+ // printf( "info: %s", info);
+ }
+ }
+ return info1;
+}
+// plublic:
+// const char* getBar() const {
+// char * str = new char[_sBar.length()+1];
+// strcpy(str, _sBar.c_str());
+// return str;}
+// In main:
+
+// foo object;
+// ///some code
+// const char* bar = object.getBar();
+// ///some code
+// delete [] bar;
\ No newline at end of file
--- /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
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jsmn.c Thu May 25 15:14:50 2017 +0545
@@ -0,0 +1,340 @@
+/* Author: Faheem Inayat
+ * Created by "Night Crue" Team @ TechShop San Jose, CA
+ *
+ * --- DISCLAIMER ---
+ * This code is a modified version of original JSMN lirary, written by
+ * *** Serge A. Zaitsev ***
+ * and hosted at https://github.com/zserge/jsmn
+ * Any modification to the original source is not guaranteed to be included
+ * in this version. As of writing of this file, the original source is
+ * licensed under MIT License
+ * (http://www.opensource.org/licenses/mit-license.php).
+ */
+
+#include "jsmn.h"
+
+/**
+ * Allocates a fresh unused token from the token pull.
+ */
+static jsmntok_t *jsmn_alloc_token ( jsmn_parser *parser, jsmntok_t *tokens, size_t num_tokens )
+{
+ jsmntok_t *tok;
+ if ( parser->toknext >= num_tokens )
+ {
+ return NULL ;
+ }
+ tok = &tokens [ parser->toknext++ ];
+ tok->start = tok->end = -1;
+ tok->childCount = 0;
+ tok->parent = -1;
+ return tok;
+}
+
+/**
+ * Fills token type and boundaries.
+ */
+static void jsmn_fill_token ( jsmntok_t *token, jsmntype_t type, int start, int end )
+{
+ token->type = type;
+ token->start = start;
+ token->end = end;
+ token->childCount = 0;
+}
+
+/**
+ * Fills next available token with JSON primitive.
+ */
+static int jsmn_parse_primitive ( jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens )
+{
+ jsmntok_t *token;
+ int start;
+
+ start = parser->pos;
+
+ for ( ; parser->pos < len && js [ parser->pos ] != '\0'; parser->pos++ )
+ {
+ switch ( js [ parser->pos ] )
+ {
+ case '\t':
+ case '\r':
+ case '\n':
+ case ' ':
+ case ',':
+ case ']':
+ case '}':
+ goto found;
+ }
+ if ( js [ parser->pos ] < 32 || js [ parser->pos ] >= 127 )
+ {
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ }
+ /* primitive must be followed by a comma/object/array */
+ parser->pos = start;
+ return JSMN_ERROR_PART;
+
+ found: if ( tokens == NULL )
+ {
+ parser->pos--;
+ return 0;
+ }
+ token = jsmn_alloc_token ( parser, tokens, num_tokens );
+ if ( token == NULL )
+ {
+ parser->pos = start;
+ return JSMN_ERROR_NOMEM;
+ }
+ jsmn_fill_token ( token, JSMN_PRIMITIVE, start, parser->pos );
+ token->parent = parser->toksuper;
+ parser->pos--;
+ return 0;
+}
+
+/**
+ * Fills next token with JSON string.
+ */
+static int jsmn_parse_string ( jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens, unsigned char isKey )
+{
+ jsmntok_t *token;
+
+ int start = parser->pos;
+
+ parser->pos++;
+
+ /* Skip starting quote */
+ for ( ; parser->pos < len && js [ parser->pos ] != '\0'; parser->pos++ )
+ {
+ char c = js [ parser->pos ];
+
+ /* Quote: end of string */
+ if ( c == '\"' )
+ {
+ if ( tokens == NULL )
+ {
+ return 0;
+ }
+ token = jsmn_alloc_token ( parser, tokens, num_tokens );
+ if ( token == NULL )
+ {
+ parser->pos = start;
+ return JSMN_ERROR_NOMEM;
+ }
+ if ( isKey == 1 )
+ {
+ jsmn_fill_token ( token, JSMN_KEY, start + 1, parser->pos );
+ }
+ else
+ {
+ jsmn_fill_token ( token, JSMN_STRING, start + 1, parser->pos );
+ }
+ token->parent = parser->toksuper;
+ return 0;
+ }
+
+ /* Backslash: Quoted symbol expected */
+ if ( c == '\\' && parser->pos + 1 < len )
+ {
+ int i;
+ parser->pos++;
+ switch ( js [ parser->pos ] )
+ {
+ /* Allowed escaped symbols */
+ case '\"':
+ case '/':
+ case '\\':
+ case 'b':
+ case 'f':
+ case 'r':
+ case 'n':
+ case 't':
+ break;
+ /* Allows escaped symbol \uXXXX */
+ case 'u':
+ parser->pos++;
+ for ( i = 0; i < 4 && parser->pos < len && js [ parser->pos ] != '\0'; i++ )
+ {
+ /* If it isn't a hex character we have an error */
+ if ( ! ( ( js [ parser->pos ] >= 48 && js [ parser->pos ] <= 57 ) || /* 0-9 */
+ ( js [ parser->pos ] >= 65 && js [ parser->pos ] <= 70 )
+ || /* A-F */
+ ( js [ parser->pos ] >= 97 && js [ parser->pos ] <= 102 ) ) )
+ { /* a-f */
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ parser->pos++;
+ }
+ parser->pos--;
+ break;
+ /* Unexpected symbol */
+ default:
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ }
+ }
+ parser->pos = start;
+ return JSMN_ERROR_PART;
+}
+
+/**
+ * Parse JSON string and fill tokens.
+ */
+int jsmn_parse ( jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens )
+{
+ int r;
+ int i;
+ jsmntok_t *token;
+ int count = parser->toknext;
+
+ unsigned char isKey = 1;
+
+ for ( ; parser->pos < len && js [ parser->pos ] != '\0'; parser->pos++ )
+ {
+ char c;
+ jsmntype_t type;
+
+ c = js [ parser->pos ];
+ switch ( c )
+ {
+ case '{':
+ case '[':
+ count++;
+ if ( tokens == NULL )
+ {
+ break;
+ }
+ token = jsmn_alloc_token ( parser, tokens, num_tokens );
+ if ( token == NULL )
+ return JSMN_ERROR_NOMEM;
+ if ( parser->toksuper != -1 )
+ {
+ tokens [ parser->toksuper ].childCount++;
+ token->parent = parser->toksuper;
+ }
+ token->type = ( c == '{' ? JSMN_OBJECT : JSMN_ARRAY );
+ token->start = parser->pos;
+ parser->toksuper = parser->toknext - 1;
+ if ( token->type == JSMN_OBJECT )
+ {
+ isKey = 1;
+ }
+ break;
+ case '}':
+ case ']':
+ if ( tokens == NULL )
+ break;
+ type = ( c == '}' ? JSMN_OBJECT : JSMN_ARRAY );
+ if ( parser->toknext < 1 )
+ {
+ return JSMN_ERROR_INVAL;
+ }
+ token = &tokens [ parser->toknext - 1 ];
+ for ( ;; )
+ {
+ if ( token->start != -1 && token->end == -1 )
+ {
+ if ( token->type != type )
+ {
+ return JSMN_ERROR_INVAL;
+ }
+ token->end = parser->pos + 1;
+ parser->toksuper = token->parent;
+ break;
+ }
+ if ( token->parent == -1 )
+ {
+ break;
+ }
+ token = &tokens [ token->parent ];
+ }
+ break;
+ case '\"':
+ r = jsmn_parse_string ( parser, js, len, tokens, num_tokens, isKey );
+ if ( r < 0 )
+ return r;
+ count++;
+ if ( parser->toksuper != -1 && tokens != NULL )
+ tokens [ parser->toksuper ].childCount++;
+ break;
+ case '\t':
+ case '\r':
+ case '\n':
+ case ' ':
+ break;
+ case ':':
+ isKey = 0;
+ parser->toksuper = parser->toknext - 1;
+ break;
+ case ',':
+ if ( tokens != NULL && parser->toksuper != -1 && tokens [ parser->toksuper ].type != JSMN_ARRAY && tokens [ parser->toksuper ].type != JSMN_OBJECT )
+ {
+ parser->toksuper = tokens [ parser->toksuper ].parent;
+ }
+ isKey = 1;
+ break;
+ /* In strict mode primitives are: numbers and booleans */
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 't':
+ case 'f':
+ case 'n':
+ /* And they must not be keys of the object */
+ if ( tokens != NULL && parser->toksuper != -1 )
+ {
+ jsmntok_t *t = &tokens [ parser->toksuper ];
+ if ( t->type == JSMN_OBJECT || ( t->type == JSMN_STRING && t->childCount != 0 ) )
+ {
+ return JSMN_ERROR_INVAL;
+ }
+ }
+ r = jsmn_parse_primitive ( parser, js, len, tokens, num_tokens );
+ if ( r < 0 )
+ return r;
+ count++;
+ if ( parser->toksuper != -1 && tokens != NULL )
+ tokens [ parser->toksuper ].childCount++;
+ break;
+
+ /* Unexpected char in strict mode */
+ default:
+ return JSMN_ERROR_INVAL;
+ }
+ }
+
+ if ( tokens != NULL )
+ {
+ for ( i = parser->toknext - 1; i >= 0; i-- )
+ {
+ /* Unmatched opened object or array */
+ if ( tokens [ i ].start != -1 && tokens [ i ].end == -1 )
+ {
+ return JSMN_ERROR_PART;
+ }
+ }
+ }
+
+ return count;
+}
+
+/**
+ * Creates a new parser based over a given buffer with an array of tokens
+ * available.
+ */
+void jsmn_init ( jsmn_parser *parser )
+{
+ parser->pos = 0;
+ parser->toknext = 0;
+ parser->toksuper = -1;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jsmn.h Thu May 25 15:14:50 2017 +0545
@@ -0,0 +1,96 @@
+/* Author: Faheem Inayat
+ * Created by "Night Crue" Team @ TechShop San Jose, CA
+ *
+ * --- DISCLAIMER ---
+ * This code is a modified version of original JSMN lirary, written by
+ * *** Serge A. Zaitsev ***
+ * and hosted at https://github.com/zserge/jsmn
+ * Any modification to the original source is not guaranteed to be included
+ * in this version. As of writing of this file, the original source is
+ * licensed under MIT License
+ * (http://www.opensource.org/licenses/mit-license.php).
+ */
+
+#ifndef __JSMN_H_
+#define __JSMN_H_
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/*
+ Modified version of original jsmn lib ... added a type "JSMN_KEY" and enabled
+ parent-pointers and strict JSON check.
+*/
+ /**
+ * JSON type identifier. Basic types are:
+ * o Object
+ * o Array
+ * o String
+ * o Other primitive: number, boolean (true/false) or null
+ */
+ typedef enum
+ {
+ JSMN_UNDEFINED = 0,
+ JSMN_OBJECT = 1,
+ JSMN_ARRAY = 2,
+ JSMN_STRING = 3,
+ JSMN_PRIMITIVE = 4,
+ JSMN_KEY = 5
+ } jsmntype_t;
+
+ enum jsmnerr
+ {
+ /* Not enough tokens were provided */
+ JSMN_ERROR_NOMEM = -1,
+ /* Invalid character inside JSON string */
+ JSMN_ERROR_INVAL = -2,
+ /* The string is not a full JSON packet, more bytes expected */
+ JSMN_ERROR_PART = -3
+ };
+
+ /**
+ * JSON token description.
+ * @param type type (object, array, string etc.)
+ * @param start start position in JSON data string
+ * @param end end position in JSON data string
+ */
+ typedef struct
+ {
+ jsmntype_t type;
+ int start;
+ int end;
+ int parent;
+ int childCount;
+ } jsmntok_t;
+
+ /**
+ * JSON parser. Contains an array of token blocks available. Also stores
+ * the string being parsed now and current position in that string
+ */
+ typedef struct
+ {
+ unsigned int pos; /* offset in the JSON string */
+ unsigned int toknext; /* next token to allocate */
+ int toksuper; /* superior token node, e.g parent object or array */
+ } jsmn_parser;
+
+ /**
+ * Create JSON parser over an array of tokens
+ */
+ void jsmn_init ( jsmn_parser *parser );
+
+ /**
+ * Run JSON parser. It parses a JSON data string into and array of tokens, each describing
+ * a single JSON object.
+ */
+ int jsmn_parse ( jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __JSMN_H_ */
+