From bd549ca34fc0330c7148a557772fc0073ea813da Mon Sep 17 00:00:00 2001 From: DualFroz Date: Tue, 8 Sep 2026 13:16:58 +0200 Subject: [PATCH] feat: add parseJson to Json --- core/src/Json.cpp | 160 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/core/src/Json.cpp b/core/src/Json.cpp index 1553af0..924e1e1 100644 --- a/core/src/Json.cpp +++ b/core/src/Json.cpp @@ -628,3 +628,163 @@ std::string JsonValue::stringOr(const std::string& key, const std::string& fallb return member ? member->stringOr(fallback) : fallback; } +bool JsonValue::operator==(const JsonValue& other) const { + if (type != other.type) return false; + switch (type) { + case JsonType::Null: return true; + case JsonType::Bool: return boolPayload == other.boolPayload; + case JsonType::Number: return numberValue() == other.numberValue(); + case JsonType::String: return stringPayload == other.stringPayload; + case JsonType::Array: return arrayPayload == other.arrayPayload; + case JsonType::Object: return objectPayload == other.objectPayload; + } + return false; +} + +std::string JsonParseError::text() const { + if (!present()) return "no error"; + return std::to_string(line) + ":" + std::to_string(column) + ": " + message; +} + +JsonParseResult parseJson(const std::string& text, int maxDepth) { + Parser parser(text, maxDepth < 1 ? 1 : maxDepth); + return parser.run(); +} + +void JsonWriter::writeString(const std::string& value, std::string& out) const { + static const char* hexDigits = "0123456789abcdef"; + out.push_back('"'); + std::size_t at = 0u; + while (at < value.size()) { + unsigned char c = static_cast(value[at]); + if (c == '"' || c == '\\') { + out.push_back('\\'); + out.push_back(static_cast(c)); + ++at; + continue; + } + if (c == '\b') { out += "\\b"; ++at; continue; } + if (c == '\f') { out += "\\f"; ++at; continue; } + if (c == '\n') { out += "\\n"; ++at; continue; } + if (c == '\r') { out += "\\r"; ++at; continue; } + if (c == '\t') { out += "\\t"; ++at; continue; } + if (c < 0x20u) { + out += "\\u00"; + out.push_back(hexDigits[(c >> 4) & 0xFu]); + out.push_back(hexDigits[c & 0xFu]); + ++at; + continue; + } + if (c < 0x80u || !escapeNonAscii) { + out.push_back(value[at]); + ++at; + continue; + } + uint32_t codePoint = 0u; + std::size_t length = decodeUtf8(value, at, codePoint); + if (length == 0u) { + // Only reachable for a hand built string that never went through the + // parser; the byte is kept so nothing is silently rewritten. + out.push_back(value[at]); + ++at; + continue; + } + if (codePoint >= 0x10000u) { + uint32_t rest = codePoint - 0x10000u; + uint32_t high = 0xD800u + (rest >> 10); + uint32_t low = 0xDC00u + (rest & 0x3FFu); + for (uint32_t unit : {high, low}) { + out += "\\u"; + for (int shift = 12; shift >= 0; shift -= 4) + out.push_back(hexDigits[(unit >> shift) & 0xFu]); + } + } else { + out += "\\u"; + for (int shift = 12; shift >= 0; shift -= 4) + out.push_back(hexDigits[(codePoint >> shift) & 0xFu]); + } + at += length; + } + out.push_back('"'); +} + +void JsonWriter::writeValue(const JsonValue& value, int depth, std::string& out) const { + const bool pretty = indentWidth > 0; + const std::string inner = pretty ? std::string(static_cast(indentWidth * (depth + 1)), ' ') + : std::string(); + const std::string outer = pretty ? std::string(static_cast(indentWidth * depth), ' ') + : std::string(); + switch (value.kind()) { + case JsonType::Null: out += "null"; return; + case JsonType::Bool: out += value.boolValue() ? "true" : "false"; return; + case JsonType::Number: out += formatNumber(value); return; + case JsonType::String: writeString(value.stringValue(), out); return; + case JsonType::Array: { + if (value.elements().empty()) { + out += "[]"; + return; + } + out.push_back('['); + bool first = true; + for (const JsonValue& element : value.elements()) { + if (!first) out.push_back(','); + first = false; + if (pretty) { + out.push_back('\n'); + out += inner; + } + writeValue(element, depth + 1, out); + } + if (pretty) { + out.push_back('\n'); + out += outer; + } + out.push_back(']'); + return; + } + case JsonType::Object: { + if (value.members().empty()) { + out += "{}"; + return; + } + out.push_back('{'); + bool first = true; + for (const JsonValue::Member& member : value.members()) { + if (!first) out.push_back(','); + first = false; + if (pretty) { + out.push_back('\n'); + out += inner; + } + writeString(member.first, out); + out.push_back(':'); + if (pretty) out.push_back(' '); + writeValue(member.second, depth + 1, out); + } + if (pretty) { + out.push_back('\n'); + out += outer; + } + out.push_back('}'); + return; + } + } +} + +std::string JsonWriter::write(const JsonValue& value) const { + std::string out; + writeValue(value, 0, out); + return out; +} + +std::string JsonWriter::compact(const JsonValue& value) { + JsonWriter writer; + return writer.write(value); +} + +std::string JsonWriter::indented(const JsonValue& value, int indentWidth) { + JsonWriter writer; + writer.indentWidth = indentWidth; + return writer.write(value); +} +