#include "JsonWriter.h" #include #include namespace RenderCadenceCompositor { namespace { constexpr int kMaxDepth = 32; void AppendHexEscape(std::ostringstream& stream, unsigned char value) { stream << "\\u" << std::hex << std::uppercase << std::setw(4) << std::setfill('0') << static_cast(value) << std::dec << std::nouppercase << std::setfill(' '); } } void JsonWriter::BeginObject() { BeginValue(); mStream << "{"; PushScope(ScopeKind::Object); } void JsonWriter::EndObject() { PopScope(ScopeKind::Object); mStream << "}"; } void JsonWriter::BeginArray() { BeginValue(); mStream << "["; PushScope(ScopeKind::Array); } void JsonWriter::EndArray() { PopScope(ScopeKind::Array); mStream << "]"; } void JsonWriter::Key(const std::string& name) { BeginKey(); mStream << "\"" << EscapeString(name) << "\":"; } void JsonWriter::String(const std::string& value) { BeginValue(); mStream << "\"" << EscapeString(value) << "\""; } void JsonWriter::Bool(bool value) { BeginValue(); mStream << (value ? "true" : "false"); } void JsonWriter::Null() { BeginValue(); mStream << "null"; } void JsonWriter::Int(int64_t value) { BeginValue(); mStream << value; } void JsonWriter::UInt(uint64_t value) { BeginValue(); mStream << value; } void JsonWriter::Double(double value) { BeginValue(); mStream << std::setprecision(15) << value; } void JsonWriter::KeyString(const std::string& name, const std::string& value) { Key(name); String(value); } void JsonWriter::KeyBool(const std::string& name, bool value) { Key(name); Bool(value); } void JsonWriter::KeyNull(const std::string& name) { Key(name); Null(); } void JsonWriter::KeyInt(const std::string& name, int64_t value) { Key(name); Int(value); } void JsonWriter::KeyUInt(const std::string& name, uint64_t value) { Key(name); UInt(value); } void JsonWriter::KeyDouble(const std::string& name, double value) { Key(name); Double(value); } std::string JsonWriter::StringValue() const { if (mScopeDepth != 0) throw std::logic_error("JSON document has unclosed scopes."); return mStream.str(); } void JsonWriter::Reset() { mStream.str(std::string()); mStream.clear(); mScopeDepth = 0; } std::string JsonWriter::EscapeString(const std::string& value) { std::ostringstream stream; for (unsigned char character : value) { switch (character) { case '"': stream << "\\\""; break; case '\\': stream << "\\\\"; break; case '\b': stream << "\\b"; break; case '\f': stream << "\\f"; break; case '\n': stream << "\\n"; break; case '\r': stream << "\\r"; break; case '\t': stream << "\\t"; break; default: if (character < 0x20) AppendHexEscape(stream, character); else stream << character; break; } } return stream.str(); } void JsonWriter::BeginValue() { if (mScopeDepth == 0) return; Scope& scope = mScopes[mScopeDepth - 1]; if (scope.kind == ScopeKind::Object) { if (!scope.expectingValue) throw std::logic_error("JSON object value must follow a key."); scope.expectingValue = false; return; } if (!scope.first) mStream << ","; scope.first = false; } void JsonWriter::BeginKey() { if (mScopeDepth == 0) throw std::logic_error("JSON key cannot be written outside an object."); Scope& scope = mScopes[mScopeDepth - 1]; if (scope.kind != ScopeKind::Object) throw std::logic_error("JSON key cannot be written inside an array."); if (scope.expectingValue) throw std::logic_error("JSON object key cannot be written before its previous value."); if (!scope.first) mStream << ","; scope.first = false; scope.expectingValue = true; } void JsonWriter::PushScope(ScopeKind kind) { if (mScopeDepth >= kMaxDepth) throw std::logic_error("JSON nesting is too deep."); mScopes[mScopeDepth++] = Scope{ kind, true, false }; } void JsonWriter::PopScope(ScopeKind kind) { if (mScopeDepth == 0) throw std::logic_error("JSON scope underflow."); Scope& scope = mScopes[mScopeDepth - 1]; if (scope.kind != kind) throw std::logic_error("JSON scope kind mismatch."); if (scope.expectingValue) throw std::logic_error("JSON object key is missing a value."); --mScopeDepth; } }