/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include "CloudGemFramework_precompiled.h" #include #include #include namespace CloudGemFramework { class JsonReaderHandler : public JsonReader { public: using Ch = char; using SizeType = rapidjson::SizeType; bool StartObject() { if (!CallArrayHandler()) { return false; } if (m_expecting != Expecting::OBJECT) { return UnexpectedContent(Expecting::OBJECT); } else { m_jsonKeyHandlerStack.push_back(m_targetKeyHandler); m_jsonArrayHandlerStack.push_back(nullptr); return true; } } bool EndObject(rapidjson::SizeType memberCount) { m_jsonKeyHandlerStack.pop_back(); m_jsonArrayHandlerStack.pop_back(); return true; } bool StartArray() { if (!CallArrayHandler()) { return false; } if (m_expecting != Expecting::ARRAY) { return UnexpectedContent(Expecting::ARRAY); } else { m_jsonArrayHandlerStack.push_back(m_targetArrayHandler); m_jsonKeyHandlerStack.push_back(nullptr); return true; } } bool EndArray(rapidjson::SizeType elementCount) { m_jsonKeyHandlerStack.pop_back(); m_jsonArrayHandlerStack.pop_back(); return true; } bool Key(const Ch* str, rapidjson::SizeType length, bool copy) { if (m_jsonKeyHandlerStack.empty() || !m_jsonKeyHandlerStack.back()) { return UnexpectedContent("key"); } else { m_expecting = Expecting::NOTHING; // default to ignoring bool ok = m_jsonKeyHandlerStack.back()(str, *this); if (!ok) { return UnexpectedObjectKey(str); } return true; } } inline bool CallArrayHandler() { if (!m_jsonArrayHandlerStack.empty() && m_jsonArrayHandlerStack.back()) { bool ok = m_jsonArrayHandlerStack.back()(*this); if (!ok) { return UnexpectedArrayElement(); } } return true; } bool String(const Ch* str, rapidjson::SizeType length, bool copy) { if (!CallArrayHandler()) { return false; } if (m_expecting != Expecting::STRING) { return UnexpectedContent(Expecting::STRING); } else { // Doesn't support embedded \0, which rapidjson allows. *m_targetString = AZStd::string::format("%.*s", aznumeric_cast(length), str); return true; } } bool RawNumber(const Ch* str, rapidjson::SizeType length, bool copy) { return String(str, length, copy); } bool Null() { if (!CallArrayHandler()) { return false; } return UnexpectedContent("null"); } bool Bool(bool b) { if (!CallArrayHandler()) { return false; } if (m_expecting != Expecting::BOOL) { return UnexpectedContent(Expecting::BOOL); } else { *m_targetBool = b; return true; } } bool Int(int i) { if (!CallArrayHandler()) { return false; } if (m_expecting == Expecting::INT) { *m_targetInt = i; return true; } if (m_expecting == Expecting::INT64) { *m_targetInt64 = i; return true; } if (m_expecting == Expecting::DOUBLE) { *m_targetDouble = i; return true; } return UnexpectedContent(Expecting::INT); } bool Uint(unsigned i) { if (!CallArrayHandler()) { return false; } if (m_expecting == Expecting::INT && i <= INT_MAX) { *m_targetInt = i; return true; } if (m_expecting == Expecting::UINT) { *m_targetUInt = i; return true; } if (m_expecting == Expecting::INT64) { *m_targetInt64 = i; return true; } if (m_expecting == Expecting::UINT64) { *m_targetUInt64 = i; return true; } if (m_expecting == Expecting::DOUBLE) { *m_targetDouble = i; return true; } return UnexpectedContent("unsigned"); } bool Int64(int64_t i) { if (!CallArrayHandler()) { return false; } if (m_expecting == Expecting::INT64) { *m_targetInt64 = i; return true; } if (m_expecting == Expecting::DOUBLE) { *m_targetDouble = aznumeric_caster(i); return true; } return UnexpectedContent(Expecting::INT64); } bool Uint64(uint64_t i) { if (!CallArrayHandler()) { return false; } if (m_expecting == Expecting::INT64 && i < INT64_MAX) { *m_targetInt64 = i; return true; } if (m_expecting == Expecting::UINT64) { *m_targetUInt64 = i; return true; } if (m_expecting == Expecting::DOUBLE) { *m_targetDouble = aznumeric_caster(i); return true; } return UnexpectedContent(Expecting::UINT64); } bool Double(double d) { if (!CallArrayHandler()) { return false; } if (m_expecting == Expecting::DOUBLE) { *m_targetDouble = d; return true; } return UnexpectedContent(Expecting::DOUBLE); } bool Ignore() override { m_expecting = JsonReaderHandler::Expecting::NOTHING; return true; } /// Tell the JsonReaderHandler that a boolean value is expected and provide /// a location where the value can be stored. bool Accept(bool& target) override { m_targetBool = ⌖ m_expecting = JsonReaderHandler::Expecting::BOOL; return true; } /// Tell the JsonReaderHandler that a string value is expected and provide /// a location where the value can be stored. bool Accept(AZStd::string& target) override { m_targetString = ⌖ m_expecting = JsonReaderHandler::Expecting::STRING; return true; } /// Tell the JsonReaderHandler that an int value is expected and provide /// a location where the value can be stored. bool Accept(int& target) override { m_targetInt = ⌖ m_expecting = JsonReaderHandler::Expecting::INT; return true; } /// Tell the JsonReaderHandler that an unsigned value is expected and provide /// a location where the value can be stored. bool Accept(unsigned& target) override { m_targetUInt = ⌖ m_expecting = JsonReaderHandler::Expecting::UINT; return true; } /// Tell the JsonReaderHandler that a int64_t value is expected and provide /// a location where the value can be stored. bool Accept(int64_t& target) override { m_targetInt64 = ⌖ m_expecting = JsonReaderHandler::Expecting::INT64; return true; } /// Tell the JsonReaderHandler that a uint64_t value is expected and provide /// a location where the value can be stored. bool Accept(uint64_t& target) override { m_targetUInt64 = ⌖ m_expecting = JsonReaderHandler::Expecting::UINT64; return true; } /// Tell the JsonReaderHandler that a double value is expected and provide /// a location where the value can be stored. bool Accept(double& target) override { m_targetDouble = ⌖ m_expecting = JsonReaderHandler::Expecting::DOUBLE; return true; } /// Tell the JsonReaderHandler that an object is expected and provide /// a JsonKeyHandler function for that object. bool Accept(JsonKeyHandler keyHandler) override { m_targetKeyHandler = keyHandler; m_expecting = JsonReaderHandler::Expecting::OBJECT; return true; } bool Accept(JsonArrayHandler arrayHandler) override { m_expecting = JsonReaderHandler::Expecting::ARRAY; m_targetArrayHandler = arrayHandler; return true; } AZStd::string GetParseErrorMessage(const rapidjson::ParseResult& result, JsonInputStream& stream) { AZStd::string msg; switch (result.Code()) { case rapidjson::kParseErrorNone: msg = "No error"; break; case rapidjson::kParseErrorDocumentEmpty: msg = "The document is empty"; break; case rapidjson::kParseErrorDocumentRootNotSingular: msg = "The document root must not follow by other values"; break; case rapidjson::kParseErrorValueInvalid: msg = "Invalid value"; break; case rapidjson::kParseErrorObjectMissName: msg = "Missing a name for object member"; break; case rapidjson::kParseErrorObjectMissColon: msg = "Missing a colon after a name of object member"; break; case rapidjson::kParseErrorObjectMissCommaOrCurlyBracket: msg = "Missing a comma or '}' after an object member"; break; case rapidjson::kParseErrorArrayMissCommaOrSquareBracket: msg = "Missing a comma or ']' after an array element"; break; case rapidjson::kParseErrorStringUnicodeEscapeInvalidHex: msg = "Incorrect hex digit after \\u escape in string"; break; case rapidjson::kParseErrorStringUnicodeSurrogateInvalid: msg = "The surrogate pair in string is invalid"; break; case rapidjson::kParseErrorStringEscapeInvalid: msg = "Invalid escape character in string"; break; case rapidjson::kParseErrorStringMissQuotationMark: msg = "Missing a closing quotation mark in string"; break; case rapidjson::kParseErrorStringInvalidEncoding: msg = "Invalid encoding in string"; break; case rapidjson::kParseErrorNumberTooBig: msg = "Number too big to be stored in double"; break; case rapidjson::kParseErrorNumberMissFraction: msg = "Miss fraction part in number"; break; case rapidjson::kParseErrorNumberMissExponent: msg = "Miss exponent in number"; break; case rapidjson::kParseErrorTermination: if (m_errorMessage.empty()) { msg = "Parsing terminated"; } else { msg = m_errorMessage; } break; case rapidjson::kParseErrorUnspecificSyntaxError: msg = "Unspecific syntax error"; break; default: msg = AZStd::string::format("Unexpected error code %i", result.Code()); break; } msg += AZStd::string::format(" at character %zu: ", result.Offset()); const int snippet_size = 40; int start = result.Offset() - snippet_size / 2; int length = snippet_size; int offset = snippet_size / 2; if(start < 0) { length -= -start; offset -= -start; start = 0; } AZStd::string snippet = stream.GetContent().substr(start, length); if (offset >= 0 && offset <= snippet.size()) { snippet.insert(offset, " <--- "); } msg += snippet; return msg; } protected: friend class JsonReader; enum class Expecting { ARRAY, BOOL, DOUBLE, INT, INT64, NOTHING, OBJECT, STRING, UINT, UINT64 }; Expecting m_expecting{Expecting::NOTHING}; bool* m_targetBool{nullptr}; AZStd::string* m_targetString{nullptr}; int* m_targetInt{nullptr}; unsigned* m_targetUInt{nullptr}; int64_t* m_targetInt64{nullptr}; uint64_t* m_targetUInt64{nullptr}; double* m_targetDouble{nullptr}; JsonKeyHandler m_targetKeyHandler{}; JsonArrayHandler m_targetArrayHandler{}; AZStd::vector m_jsonKeyHandlerStack; AZStd::vector m_jsonArrayHandlerStack; AZStd::string m_errorMessage; bool UnexpectedObjectKey(const char* key) { m_errorMessage = AZStd::string::format("Found unexpected object key %s", key ); return false; } bool UnexpectedArrayElement() { m_errorMessage = "Found unexpected array element"; return false; } bool UnexpectedContent(Expecting actual) { return UnexpectedContent(ExpectingToString(actual)); } bool UnexpectedContent(const char* actual) { bool result = false; if (m_expecting == Expecting::NOTHING) { result = true; } else if (m_expecting == Expecting::STRING && !strcmp(actual, "null")) { // We are allowing null values to parse as empty strings as a workaround for optional fields not always being handled correctly. result = true; } else { m_errorMessage = AZStd::string::format("Found %s when expecting %s", actual, ExpectingToString(m_expecting) ); } return result; } static const char* ExpectingToString(Expecting expecting) { switch (expecting) { case Expecting::ARRAY: return "an array"; case Expecting::BOOL: return "a boolean"; case Expecting::DOUBLE: return "a double"; case Expecting::INT: return "an int"; case Expecting::INT64: return "an int64"; case Expecting::NOTHING: return "nothing"; case Expecting::OBJECT: return "an object"; case Expecting::STRING: return "a string"; case Expecting::UINT: return "an unsigned"; case Expecting::UINT64: return "an uint64"; default: return "unknown"; } } }; bool JsonReader::ReadObject(JsonInputStream& stream, JsonKeyHandler keyHandler, AZStd::string& errorMessage) { JsonReaderHandler handler; handler.Accept(keyHandler); rapidjson::Reader reader; rapidjson::ParseResult result = reader.Parse(stream, handler); if(result.IsError()) { errorMessage = handler.GetParseErrorMessage(result, stream); return false; } else { return true; } } }