Expose JSON parse flag options

Signed-off-by: Nicholas Van Sickle <nvsickle@amazon.com>
This commit is contained in:
Nicholas Van Sickle
2021-11-30 22:08:48 -08:00
parent a9c05372d5
commit f87021d856
2 changed files with 214 additions and 174 deletions
@@ -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<AZ::s64>(i)));
}
bool RapidJsonReadHandler::Int(int i)
{
return CheckResult(m_visitor->Int64(static_cast<AZ::s64>(i)));
}
bool Uint(unsigned i)
{
return CheckResult(m_visitor->Uint64(static_cast<AZ::u64>(i)));
}
bool RapidJsonReadHandler::Uint(unsigned i)
{
return CheckResult(m_visitor->Uint64(static_cast<AZ::u64>(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<size_t>(m_cursor - m_begin);
}
size_t Tell() const
{
return static_cast<size_t>(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<flags>(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<flags>(stream, handler);
return handler.TakeOutcome();
}
//
// In-memory rapidjson util functions
//
@@ -67,6 +67,56 @@ namespace AZ::Dom::Json
AZStd::deque<ValueInfo> 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; //<! Denotes the string character storage type for rapidjson
AzStringStream(AZStd::string& buffer);
char Peek() const;
char Take();
size_t Tell() const;
char* PutBegin();
void Put(char c);
void Flush();
size_t PutEnd(char* begin);
const char* Peek4() const;
char* m_cursor; //!< Current read position.
char* m_write; //!< Current write position.
const char* m_begin; //!< Head of string.
};
//! Creates a Visitor that will write serialized JSON to the specified stream.
//! \param stream The stream the visitor will write to.
//! \param format The format to write in.
@@ -76,9 +126,10 @@ namespace AZ::Dom::Json
//! Reads serialized JSON from a string and applies it to a visitor.
//! \param buffer The UTF-8 serialized JSON to read.
//! \param lifetime Specifies the lifetime of the specified buffer. If the string specified by buffer might be deallocated,
//! ensure specify Lifetime::Temporary is specified.
//! ensure Lifetime::Temporary is specified.
//! \param visitor The visitor to visit with the JSON buffer's contents.
//! \return The aggregate result specifying whether the visitor operations were successful.
template<int ParseFlags = rapidjson::kParseCommentsFlag>
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<int ParseFlags = rapidjson::kParseCommentsFlag | rapidjson::kParseInsituFlag>
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<int ParseFlags>
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<ParseFlags>(stream, handler);
return handler.TakeOutcome();
}
template<int ParseFlags>
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<ParseFlags>(stream, handler);
return handler.TakeOutcome();
}
} // namespace AZ::Dom::Json