feat: add parseJson to Json
This commit is contained in:
1 parent
9be045c7da
commit
bd549ca34f
1 file changed
+160
@@ -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<unsigned char>(value[at]);
|
||||
if (c == '"' || c == '\\') {
|
||||
out.push_back('\\');
|
||||
out.push_back(static_cast<char>(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<std::size_t>(indentWidth * (depth + 1)), ' ')
|
||||
: std::string();
|
||||
const std::string outer = pretty ? std::string(static_cast<std::size_t>(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);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user