diff --git a/JsonParser/JsonArray.cpp b/JsonParser/JsonArray.cpp index 2e7bbe35..1d3629df 100644 --- a/JsonParser/JsonArray.cpp +++ b/JsonParser/JsonArray.cpp @@ -7,8 +7,31 @@ #include "JsonHashTable.h" using namespace ArduinoJson::Parser; +using namespace ArduinoJson::Internal; DEPRECATED JsonHashTable JsonArray::getHashTable(int index) { return (JsonHashTable) (*this)[index]; } + +/* +* Returns the token for the value at the specified index +*/ +JsonValue JsonArray::operator[](int index) +{ + // sanity check + if (index < 0 || !token.isArray() || index >= token.size()) + return JsonValue::null(); + + // skip first token, it's the whole object + JsonToken currentToken = token + 1; + + // skip all tokens before the specified index + for (int i = 0; i < index; i++) + { + // move forward: current + nested tokens + currentToken += 1 + currentToken.nestedTokenCount(); + } + + return JsonValue(json, currentToken); +} \ No newline at end of file diff --git a/JsonParser/JsonArray.h b/JsonParser/JsonArray.h index 0fe50e69..d1f336c5 100644 --- a/JsonParser/JsonArray.h +++ b/JsonParser/JsonArray.h @@ -7,6 +7,7 @@ #include "JsonValue.h" #include "JsonArrayIterator.h" +#include "JsonToken.h" namespace ArduinoJson { @@ -15,40 +16,41 @@ namespace ArduinoJson class JsonHashTable; class JsonArray - { + { public: - JsonArray() {} + JsonArray() + : token(0) + { - JsonArray(JsonValue& value) - : value(value) + } + + JsonArray(char* json, Internal::JsonToken token) + : json(json), token(token) { } bool success() { - return value.success(); + return token.isArray(); } int size() { - return value.size(); + return success() ? token.size() : 0; } - JsonValue operator[](int index) - { - return value[index]; - } + JsonValue operator[](int index); JsonArrayIterator begin() { - return JsonArrayIterator(value); + return JsonArrayIterator(json, token); } JsonArrayIterator end() { - return JsonArrayIterator(); + return JsonArrayIterator(json, token + token.nestedTokenCount()); } DEPRECATED int getLength() @@ -83,9 +85,15 @@ namespace ArduinoJson return (char*) (*this)[index]; } + static JsonArray null() + { + return JsonArray(); + } + private: - JsonValue value; + char* json; + Internal::JsonToken token; }; } } \ No newline at end of file diff --git a/JsonParser/JsonArrayIterator.h b/JsonParser/JsonArrayIterator.h index db755512..5b4d9a2d 100644 --- a/JsonParser/JsonArrayIterator.h +++ b/JsonParser/JsonArrayIterator.h @@ -6,6 +6,7 @@ #pragma once #include "JsonValue.h" +#include "JsonToken.h" namespace ArduinoJson { @@ -21,33 +22,34 @@ namespace ArduinoJson JsonArrayIterator operator++() { - tokens++; - return *this; + JsonArrayIterator prev = *this; + token += 1; + return prev; } JsonValue operator*() { - return JsonValue(json, tokens); + return JsonValue(json, token); } bool operator !=(const JsonArrayIterator& other) { - return tokens != other.tokens || json != other.json; + return token != other.token || json != other.json; } private: char* json; - jsmntok_t* tokens; + Internal::JsonToken token; JsonArrayIterator() - : json(0), tokens(0) + : json(0), token(0) { } - JsonArrayIterator(JsonValue& value) - : json(value.json), tokens(value.tokens) + JsonArrayIterator(char* json, Internal::JsonToken& token) + : json(json), token(token) { } diff --git a/JsonParser/JsonHashTable.cpp b/JsonParser/JsonHashTable.cpp index e3bc59e4..627c2548 100644 --- a/JsonParser/JsonHashTable.cpp +++ b/JsonParser/JsonHashTable.cpp @@ -3,13 +3,51 @@ * Benoit Blanchon 2014 - MIT License */ +#include // for strcmp() #include "JsonHashTable.h" #include "JsonArray.h" #include "JsonValue.h" using namespace ArduinoJson::Parser; +using namespace ArduinoJson::Internal; DEPRECATED JsonArray JsonHashTable::getArray(const char* key) { - return (JsonArray) (*this)[key]; + return (*this)[key]; +} + +/* +* Returns the token for the value associated with the specified key +*/ +JsonValue JsonHashTable::getValue(const char* desiredKey) +{ + // sanity check + if (desiredKey == 0 || !token.isObject()) + return JsonValue::null(); + + // skip first token, it's the whole object + JsonToken runningToken = token + 1; + + // scan each keys + for (int i = 0; i < token.size() / 2; i++) + { + // get 'key' token string + char* key = runningToken.getText(json); + + // move to the 'value' token + runningToken += 1; + + // compare with desired name + if (strcmp(desiredKey, key) == 0) + { + // return the value token that follows the key token + return JsonValue(json, runningToken); + } + + // skip nested tokens + runningToken += 1 + runningToken.nestedTokenCount(); + } + + // nothing found, return NULL + return JsonValue::null(); } \ No newline at end of file diff --git a/JsonParser/JsonHashTable.h b/JsonParser/JsonHashTable.h index 30092784..9d285304 100644 --- a/JsonParser/JsonHashTable.h +++ b/JsonParser/JsonHashTable.h @@ -19,59 +19,70 @@ namespace ArduinoJson public: - JsonHashTable() {} + JsonHashTable() + : token(Internal::JsonToken::null()) + { + } bool success() { - return value.success(); + return token.isObject(); } JsonValue operator[](const char* key) { - return value[key]; + return getValue(key); } bool containsKey(const char* key) { - return value[key]; + return getValue(key).success(); } DEPRECATED JsonArray getArray(const char* key); DEPRECATED bool getBool(const char* key) { - return value[key]; + return getValue(key); } DEPRECATED double getDouble(const char* key) { - return value[key]; + return getValue(key); } DEPRECATED JsonHashTable getHashTable(const char* key) { - return value[key]; + return getValue(key); } DEPRECATED long getLong(const char* key) { - return value[key]; + return getValue(key); } DEPRECATED char* getString(const char* key) { - return value[key]; + return getValue(key); + } + + static JsonHashTable null() + { + return JsonHashTable(); } private: - JsonHashTable(JsonValue& value) - : value(value) + JsonHashTable(char* json, Internal::JsonToken token) + : json(json), token(token) { } - JsonValue value; + char* json; + Internal::JsonToken token; + + JsonValue getValue(const char* key); }; } } \ No newline at end of file diff --git a/JsonParser/JsonParserBase.cpp b/JsonParser/JsonParserBase.cpp index 0d2d274c..2d0767ab 100644 --- a/JsonParser/JsonParserBase.cpp +++ b/JsonParser/JsonParserBase.cpp @@ -4,8 +4,10 @@ */ #include "JsonParserBase.h" +#include "JsonToken.h" using namespace ArduinoJson::Parser; +using namespace ArduinoJson::Internal; JsonValue JsonParserBase::parse(char* json) { @@ -13,7 +15,7 @@ JsonValue JsonParserBase::parse(char* json) jsmn_init(&parser); if (JSMN_SUCCESS != jsmn_parse(&parser, json, tokens, maxTokens)) - return JsonValue(); + return JsonValue::null(); - return JsonValue(json, tokens); + return JsonValue(json, JsonToken(tokens)); } diff --git a/JsonParser/JsonToken.cpp b/JsonParser/JsonToken.cpp new file mode 100644 index 00000000..502917f6 --- /dev/null +++ b/JsonParser/JsonToken.cpp @@ -0,0 +1,21 @@ + +#include "JsonToken.h" + +using namespace ArduinoJson::Internal; + +int JsonToken::nestedTokenCount() const +{ + jsmntok_t* t = token; + int yetToVisit = t->size; + int count = 0; + + while (yetToVisit) + { + count++; + t++; + yetToVisit--; + yetToVisit += t->size; + } + + return count; +} \ No newline at end of file diff --git a/JsonParser/JsonToken.h b/JsonParser/JsonToken.h new file mode 100644 index 00000000..f29b5095 --- /dev/null +++ b/JsonParser/JsonToken.h @@ -0,0 +1,87 @@ +/* +* Arduino JSON library +* Benoit Blanchon 2014 - MIT License +*/ + +#pragma once + +#include "jsmn.h" + +namespace ArduinoJson +{ + namespace Internal + { + class JsonToken + { + public: + + JsonToken(jsmntok_t* token) + :token(token) + { + + } + + char* getText(char* json) + { + json[token->end] = 0; + return json + token->start; + } + + JsonToken operator+ (int n) + { + return JsonToken(token + n); + } + + void operator+= (int n) + { + token += n; + } + + bool operator!= (const JsonToken& other) + { + return token != other.token; + } + + int size() + { + return token->size; + } + + bool isValid() + { + return token != 0; + } + + bool isObject() + { + return token != 0 && token->type == JSMN_OBJECT; + } + + bool isArray() + { + return token != 0 && token->type == JSMN_ARRAY; + } + + bool isPrimitive() + { + return token != 0 && token->type == JSMN_PRIMITIVE; + } + + bool isString() + { + return token != 0 && token->type == JSMN_STRING; + } + + static JsonToken null() + { + return JsonToken(0); + } + + int nestedTokenCount() const; + + private: + jsmntok_t* token; + }; + } +} + diff --git a/JsonParser/JsonValue.cpp b/JsonParser/JsonValue.cpp index bbb5157e..98fd3cfb 100644 --- a/JsonParser/JsonValue.cpp +++ b/JsonParser/JsonValue.cpp @@ -4,141 +4,57 @@ */ #include // for strtol, strtod -#include // for strcmp() #include "JsonArray.h" #include "JsonHashTable.h" #include "JsonValue.h" using namespace ArduinoJson::Parser; +using namespace ArduinoJson::Internal; JsonValue::operator bool() { - if (tokens == 0 || tokens->type != JSMN_PRIMITIVE) return 0; + if (!token.isPrimitive()) return 0; + + char *text = token.getText(json); // "true" - if (json[tokens->start] == 't') return true; + if (text[0] == 't') return true; // "false" - if (json[tokens->start] == 'f') return false; + if (text[0] == 'f') return false; // "null" - if (json[tokens->start] == 'n') return false; + if (text[0] == 'n') return false; // number - return strtol(json + tokens->start, 0, 0) != 0; + return strtol(text, 0, 0) != 0; } JsonValue::operator double() { - if (tokens == 0 || tokens->type != JSMN_PRIMITIVE) return 0; - - return strtod(json + tokens->start, 0); + return token.isPrimitive() ? strtod(token.getText(json), 0) : 0; } JsonValue::operator long() { - if (tokens == 0 || tokens->type != JSMN_PRIMITIVE) return 0; - - return strtol(json + tokens->start, 0, 0); + return token.isPrimitive() ? strtol(token.getText(json), 0, 0) : 0; } JsonValue::operator char*() { - if (tokens == 0 || tokens->type != JSMN_PRIMITIVE && tokens->type != JSMN_STRING) - return 0; - - // add null terminator to the string - json[tokens->end] = 0; - - return json + tokens->start; + return token.isString() || token.isPrimitive() ? token.getText(json) : 0; } JsonValue::operator JsonArray() { - return tokens != 0 && tokens->type == JSMN_ARRAY - ? JsonArray(*this) - : JsonArray(); + return token.isArray() + ? JsonArray(json, token) + : JsonArray::null(); } JsonValue::operator JsonHashTable() { - return tokens != 0 && tokens->type == JSMN_OBJECT - ? JsonHashTable(*this) - : JsonHashTable(); -} - -int JsonValue::size() -{ - return tokens != 0 && tokens->type == JSMN_ARRAY ? tokens->size : 0; -} - -/* -* Returns the token for the value associated with the specified key -*/ -JsonValue JsonValue::operator [](const char* desiredKey) -{ - // sanity check - if (json == 0 || desiredKey == 0 || tokens->type != JSMN_OBJECT) - return JsonValue(); - - // skip first token, it's the whole object - jsmntok_t* currentToken = tokens + 1; - - // scan each keys - for (int i = 0; i < tokens[0].size / 2; i++) - { - // get key token string - char* key = JsonValue(json, currentToken); - - // compare with desired name - if (strcmp(desiredKey, key) == 0) - { - // return the value token that follows the key token - return JsonValue(json, currentToken + 1); - } - - // move forward: key + value + nested tokens - currentToken += 2 + getNestedTokenCount(currentToken + 1); - } - - // nothing found, return NULL - return JsonValue(); -} - -/* -* Returns the token for the value at the specified index -*/ -JsonValue JsonValue::operator[](int index) -{ - // sanity check - if (index < 0 || index >= size()) - return JsonValue(); - - // skip first token, it's the whole object - jsmntok_t* currentToken = tokens + 1; - - // skip all tokens before the specified index - for (int i = 0; i < index; i++) - { - // move forward: current + nested tokens - currentToken += 1 + getNestedTokenCount(currentToken); - } - - return JsonValue(json, currentToken); -} - -int JsonValue::getNestedTokenCount(jsmntok_t* token) -{ - int tokensToVisit = token->size; - int count = 0; - - while (tokensToVisit) - { - count++; - token++; - tokensToVisit--; - tokensToVisit += token->size; - } - - return count; + return token.isObject() + ? JsonHashTable(json, token) + : JsonHashTable::null(); } \ No newline at end of file diff --git a/JsonParser/JsonValue.h b/JsonParser/JsonValue.h index 7cb0bbc1..900b5dbc 100644 --- a/JsonParser/JsonValue.h +++ b/JsonParser/JsonValue.h @@ -5,7 +5,7 @@ #pragma once -#include "jsmn.h" +#include "JsonToken.h" #ifndef ARDUINO_JSON_NO_DEPRECATED_WARNING #ifdef __GNUC__ @@ -26,44 +26,37 @@ namespace ArduinoJson class JsonValue { - friend class JsonArrayIterator; - - public: - JsonValue() - : json(0), tokens(0) - { - - } + public: - JsonValue(char* json, jsmntok_t* tokens) - : json(json), tokens(tokens) + JsonValue(char* json, Internal::JsonToken token) + : json(json), token(token) { } bool success() { - return json != 0 && tokens != 0; - } - + return token.isValid(); + } + operator bool(); operator double(); operator long(); operator char*(); operator JsonArray(); operator JsonHashTable(); + JsonValue operator[](int index); + JsonValue operator[](const char*key); - JsonValue operator[](const char*); - JsonValue operator[](int); - - int size(); + static JsonValue null() + { + return JsonValue(0, Internal::JsonToken(0)); + } private: char* json; - jsmntok_t* tokens; - - static int getNestedTokenCount(jsmntok_t* token); + Internal::JsonToken token; }; } } \ No newline at end of file diff --git a/JsonParserTests/JsonArrayIteratorTests.cpp b/JsonParserTests/JsonArrayIteratorTests.cpp index 9f46dd36..99ca5cb5 100644 --- a/JsonParserTests/JsonArrayIteratorTests.cpp +++ b/JsonParserTests/JsonArrayIteratorTests.cpp @@ -11,7 +11,7 @@ namespace JsonParserTests { public: - TEST_METHOD(TestMethod1) + TEST_METHOD(SimpleIteraton) { char json [] = "[1,2,3]"; JsonParser<4> parser; diff --git a/JsonParserTests/JsonParserTests.vcxproj b/JsonParserTests/JsonParserTests.vcxproj index fb05706c..156cfd01 100644 --- a/JsonParserTests/JsonParserTests.vcxproj +++ b/JsonParserTests/JsonParserTests.vcxproj @@ -89,6 +89,7 @@ + @@ -102,6 +103,7 @@ + diff --git a/JsonParserTests/JsonParserTests.vcxproj.filters b/JsonParserTests/JsonParserTests.vcxproj.filters index f632b7b6..a88b7cb2 100644 --- a/JsonParserTests/JsonParserTests.vcxproj.filters +++ b/JsonParserTests/JsonParserTests.vcxproj.filters @@ -42,6 +42,9 @@ Source Files + + Source Files + @@ -65,5 +68,8 @@ Header Files + + Header Files + \ No newline at end of file