From f87021d8561f17dd05d9e2fd0239fcf7657ebbd8 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Tue, 30 Nov 2021 22:08:48 -0800 Subject: [PATCH] Expose JSON parse flag options Signed-off-by: Nicholas Van Sickle --- .../Backends/JSON/JsonSerializationUtils.cpp | 306 ++++++++---------- .../Backends/JSON/JsonSerializationUtils.h | 82 ++++- 2 files changed, 214 insertions(+), 174 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp index 743ef3df43..84f663f97c 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp @@ -304,183 +304,165 @@ namespace AZ::Dom::Json // // struct JsonReadHandler // - // Handler for a rapidjson::Reader that translates reads into an AZ::Dom::Visitor - struct JsonReadHandler + RapidJsonReadHandler::RapidJsonReadHandler(Visitor* visitor, Lifetime stringLifetime) + : m_visitor(visitor) + , m_stringLifetime(stringLifetime) + , m_outcome(AZ::Success()) { - public: - JsonReadHandler(Visitor* visitor, Lifetime stringLifetime) - : m_visitor(visitor) - , m_stringLifetime(stringLifetime) - , m_outcome(AZ::Success()) - { - } + } - bool Null() - { - return CheckResult(m_visitor->Null()); - } + bool RapidJsonReadHandler::Null() + { + return CheckResult(m_visitor->Null()); + } - bool Bool(bool b) - { - return CheckResult(m_visitor->Bool(b)); - } + bool RapidJsonReadHandler::Bool(bool b) + { + return CheckResult(m_visitor->Bool(b)); + } - bool Int(int i) - { - return CheckResult(m_visitor->Int64(static_cast(i))); - } + bool RapidJsonReadHandler::Int(int i) + { + return CheckResult(m_visitor->Int64(static_cast(i))); + } - bool Uint(unsigned i) - { - return CheckResult(m_visitor->Uint64(static_cast(i))); - } + bool RapidJsonReadHandler::Uint(unsigned i) + { + return CheckResult(m_visitor->Uint64(static_cast(i))); + } - bool Int64(int64_t i) - { - return CheckResult(m_visitor->Int64(i)); - } + bool RapidJsonReadHandler::Int64(int64_t i) + { + return CheckResult(m_visitor->Int64(i)); + } - bool Uint64(uint64_t i) - { - return CheckResult(m_visitor->Uint64(i)); - } + bool RapidJsonReadHandler::Uint64(uint64_t i) + { + return CheckResult(m_visitor->Uint64(i)); + } - bool Double(double d) - { - return CheckResult(m_visitor->Double(d)); - } + bool RapidJsonReadHandler::Double(double d) + { + return CheckResult(m_visitor->Double(d)); + } - bool RawNumber([[maybe_unused]] const char* str, [[maybe_unused]] rapidjson::SizeType length, [[maybe_unused]] bool copy) + bool RapidJsonReadHandler::RawNumber( + [[maybe_unused]] const char* str, [[maybe_unused]] rapidjson::SizeType length, [[maybe_unused]] bool copy) + { + AZ_Assert(false, "Raw numbers are unsupported in the rapidjson DOM backend"); + return false; + } + + bool RapidJsonReadHandler::String(const char* str, rapidjson::SizeType length, bool copy) + { + Lifetime lifetime = m_stringLifetime; + if (!copy) { - AZ_Assert(false, "Raw numbers are unsupported in the rapidjson DOM backend"); + lifetime = Lifetime::Temporary; + } + return CheckResult(m_visitor->String(AZStd::string_view(str, length), lifetime)); + } + + bool RapidJsonReadHandler::StartObject() + { + return CheckResult(m_visitor->StartObject()); + } + + bool RapidJsonReadHandler::Key(const char* str, rapidjson::SizeType length, [[maybe_unused]] bool copy) + { + AZStd::string_view key = AZStd::string_view(str, length); + if (!m_visitor->SupportsRawKeys()) + { + m_visitor->Key(AZ::Name(key)); + } + Lifetime lifetime = m_stringLifetime; + if (!copy) + { + lifetime = Lifetime::Temporary; + } + return CheckResult(m_visitor->RawKey(key, lifetime)); + } + + bool RapidJsonReadHandler::EndObject([[maybe_unused]] rapidjson::SizeType memberCount) + { + return CheckResult(m_visitor->EndObject(memberCount)); + } + + bool RapidJsonReadHandler::StartArray() + { + return CheckResult(m_visitor->StartArray()); + } + + bool RapidJsonReadHandler::EndArray([[maybe_unused]] rapidjson::SizeType elementCount) + { + return CheckResult(m_visitor->EndArray(elementCount)); + } + + Visitor::Result&& RapidJsonReadHandler::TakeOutcome() + { + return AZStd::move(m_outcome); + } + + bool RapidJsonReadHandler::CheckResult(Visitor::Result result) + { + if (!result.IsSuccess()) + { + m_outcome = AZStd::move(result); return false; } - - bool String(const char* str, rapidjson::SizeType length, bool copy) - { - Lifetime lifetime = m_stringLifetime; - if (!copy) - { - lifetime = Lifetime::Temporary; - } - return CheckResult(m_visitor->String(AZStd::string_view(str, length), lifetime)); - } - - bool StartObject() - { - return CheckResult(m_visitor->StartObject()); - } - - bool Key(const char* str, rapidjson::SizeType length, [[maybe_unused]] bool copy) - { - AZStd::string_view key = AZStd::string_view(str, length); - if (!m_visitor->SupportsRawKeys()) - { - m_visitor->Key(AZ::Name(key)); - } - Lifetime lifetime = m_stringLifetime; - if (!copy) - { - lifetime = Lifetime::Temporary; - } - return CheckResult(m_visitor->RawKey(key, lifetime)); - } - - bool EndObject([[maybe_unused]] rapidjson::SizeType memberCount) - { - return CheckResult(m_visitor->EndObject(memberCount)); - } - - bool StartArray() - { - return CheckResult(m_visitor->StartArray()); - } - - bool EndArray([[maybe_unused]] rapidjson::SizeType elementCount) - { - return CheckResult(m_visitor->EndArray(elementCount)); - } - - Visitor::Result&& TakeOutcome() - { - return AZStd::move(m_outcome); - } - - private: - bool CheckResult(Visitor::Result result) - { - if (!result.IsSuccess()) - { - m_outcome = AZStd::move(result); - return false; - } - return true; - } - - Visitor::Result m_outcome; - Visitor* m_visitor; - Lifetime m_stringLifetime; - }; + return true; + } // // struct AzStringStream // // rapidjson stream wrapper for AZStd::string suitable for in-situ parsing - struct AzStringStream + AzStringStream::AzStringStream(AZStd::string& buffer) { - using Ch = char; + m_cursor = buffer.data(); + m_begin = m_cursor; + } - AzStringStream(AZStd::string& buffer) - { - m_cursor = buffer.data(); - m_begin = m_cursor; - } + char AzStringStream::Peek() const + { + return *m_cursor; + } - char Peek() const - { - return *m_cursor; - } + char AzStringStream::Take() + { + return *m_cursor++; + } - char Take() - { - return *m_cursor++; - } + size_t AzStringStream::Tell() const + { + return static_cast(m_cursor - m_begin); + } - size_t Tell() const - { - return static_cast(m_cursor - m_begin); - } + char* AzStringStream::PutBegin() + { + m_write = m_cursor; + return m_cursor; + } - char* PutBegin() - { - m_write = m_cursor; - return m_cursor; - } + void AzStringStream::Put(char c) + { + (*m_write++) = c; + } - void Put(char c) - { - (*m_write++) = c; - } + void AzStringStream::Flush() + { + } - void Flush() - { - } + size_t AzStringStream::PutEnd(char* begin) + { + return m_write - begin; + } - size_t PutEnd(char* begin) - { - return m_write - begin; - } - - const char* Peek4() const - { - AZ_Assert(false, "Not implemented, encoding is hard-coded to UTF-8"); - return m_cursor; - } - - char* m_cursor; //!< Current read position. - char* m_write; //!< Current write position. - const char* m_begin; //!< Head of string. - }; + const char* AzStringStream::Peek4() const + { + AZ_Assert(false, "Not implemented, encoding is hard-coded to UTF-8"); + return m_cursor; + } // // Serialized JSON util functions @@ -499,28 +481,6 @@ namespace AZ::Dom::Json } } - Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) - { - rapidjson::Reader reader; - rapidjson::MemoryStream stream(buffer.data(), buffer.size()); - JsonReadHandler handler(&visitor, lifetime); - - constexpr int flags = rapidjson::kParseCommentsFlag; - reader.Parse(stream, handler); - return handler.TakeOutcome(); - } - - Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor& visitor) - { - rapidjson::Reader reader; - AzStringStream stream(buffer); - JsonReadHandler handler(&visitor, Lifetime::Persistent); - - constexpr int flags = rapidjson::kParseCommentsFlag | rapidjson::kParseInsituFlag; - reader.Parse(stream, handler); - return handler.TakeOutcome(); - } - // // In-memory rapidjson util functions // diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h index 007134227e..be055d7f5c 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h @@ -67,6 +67,56 @@ namespace AZ::Dom::Json AZStd::deque m_entryStack; }; + //! Handler for a rapidjson::Reader that translates reads into an AZ::Dom::Visitor + struct RapidJsonReadHandler + { + public: + RapidJsonReadHandler(Visitor* visitor, Lifetime stringLifetime); + + bool Null(); + bool Bool(bool b); + bool Int(int i); + bool Uint(unsigned i); + bool Int64(int64_t i); + bool Uint64(uint64_t i); + bool Double(double d); + bool RawNumber(const char* str, rapidjson::SizeType length, bool copy); + bool String(const char* str, rapidjson::SizeType length, bool copy); + bool StartObject(); + bool Key(const char* str, rapidjson::SizeType length, bool copy); + bool EndObject(rapidjson::SizeType memberCount); + bool StartArray(); + bool EndArray(rapidjson::SizeType elementCount); + Visitor::Result&& TakeOutcome(); + + private: + bool CheckResult(Visitor::Result result); + + Visitor::Result m_outcome; + Visitor* m_visitor; + Lifetime m_stringLifetime; + }; + + //! rapidjson stream wrapper for AZStd::string suitable for in-situ parsing + struct AzStringStream + { + using Ch = char; // Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor); //! Reads serialized JSON from a string in-place and applies it to a visitor. //! \param buffer The UTF-8 serialized JSON to read. This buffer will be modified as part of the deserialization process to @@ -86,6 +137,7 @@ namespace AZ::Dom::Json //! \param visitor The visitor to visit with the JSON buffer's contents. The strings provided to the visitor will only //! be valid for the lifetime of buffer. //! \return The aggregate result specifying whether the visitor operations were successful. + template Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor& visitor); //! Takes a visitor specified by a callback and produces a rapidjson::Document. @@ -106,4 +158,32 @@ namespace AZ::Dom::Json //! before the visitor is finished using these values, Lifetime::Temporary should be specified. //! \return The aggregate result specifying whether the visitor operations were successful. Visitor::Result VisitRapidJsonValue(const rapidjson::Value& value, Visitor& visitor, Lifetime lifetime); + + template + Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) + { + static_assert( + (ParseFlags & rapidjson::kParseInsituFlag) == 0, + "VisitSerializedJsonInPlace requires kParseInSituFlag not to be set, use VisitSerializedJsonInPlace to parse in-situ"); + + rapidjson::Reader reader; + rapidjson::MemoryStream stream(buffer.data(), buffer.size()); + RapidJsonReadHandler handler(&visitor, lifetime); + + reader.Parse(stream, handler); + return handler.TakeOutcome(); + } + + template + Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor& visitor) + { + static_assert((ParseFlags & rapidjson::kParseInsituFlag) != 0, "VisitSerializedJsonInPlace requires kParseInSituFlag to be set"); + + rapidjson::Reader reader; + AzStringStream stream(buffer); + RapidJsonReadHandler handler(&visitor, Lifetime::Persistent); + + reader.Parse(stream, handler); + return handler.TakeOutcome(); + } } // namespace AZ::Dom::Json