#include "json.hpp" #include #include #include #include #include #include namespace connector { namespace { void append_utf8(std::string& out, unsigned codepoint) { if (codepoint <= 0x7f) { out.push_back(static_cast(codepoint)); } else if (codepoint <= 0x7ff) { out.push_back(static_cast(0xc0 | (codepoint >> 6))); out.push_back(static_cast(0x80 | (codepoint & 0x3f))); } else if (codepoint <= 0xffff) { out.push_back(static_cast(0xe0 | (codepoint >> 12))); out.push_back(static_cast(0x80 | ((codepoint >> 6) & 0x3f))); out.push_back(static_cast(0x80 | (codepoint & 0x3f))); } else { out.push_back(static_cast(0xf0 | (codepoint >> 18))); out.push_back(static_cast(0x80 | ((codepoint >> 12) & 0x3f))); out.push_back(static_cast(0x80 | ((codepoint >> 6) & 0x3f))); out.push_back(static_cast(0x80 | (codepoint & 0x3f))); } } class Parser { public: explicit Parser(const std::string& text) : text_(text) {} Json parse() { skip_space(); Json result = value(); skip_space(); if (position_ != text_.size()) fail("JSON 末尾存在多余内容"); return result; } private: const std::string& text_; std::size_t position_ = 0; [[noreturn]] void fail(const std::string& message) const { throw std::runtime_error(message + "(位置 " + std::to_string(position_) + ")"); } void skip_space() { while (position_ < text_.size()) { const char c = text_[position_]; if (c != ' ' && c != '\t' && c != '\r' && c != '\n') break; ++position_; } } bool consume(char expected) { skip_space(); if (position_ >= text_.size() || text_[position_] != expected) return false; ++position_; return true; } void literal(const char* expected) { while (*expected) { if (position_ >= text_.size() || text_[position_++] != *expected++) fail("JSON 字面量无效"); } } unsigned hex4() { unsigned value = 0; for (int index = 0; index < 4; ++index) { if (position_ >= text_.size()) fail("JSON Unicode 转义不完整"); const char c = text_[position_++]; value <<= 4; if (c >= '0' && c <= '9') value |= static_cast(c - '0'); else if (c >= 'a' && c <= 'f') value |= static_cast(c - 'a' + 10); else if (c >= 'A' && c <= 'F') value |= static_cast(c - 'A' + 10); else fail("JSON Unicode 转义无效"); } return value; } std::string string_value() { if (!consume('"')) fail("JSON 字符串缺少引号"); std::string out; while (position_ < text_.size()) { const char c = text_[position_++]; if (c == '"') return out; if (static_cast(c) < 0x20) fail("JSON 字符串包含控制字符"); if (c != '\\') { out.push_back(c); continue; } if (position_ >= text_.size()) fail("JSON 转义不完整"); switch (text_[position_++]) { case '"': out.push_back('"'); break; case '\\': out.push_back('\\'); break; case '/': out.push_back('/'); break; case 'b': out.push_back('\b'); break; case 'f': out.push_back('\f'); break; case 'n': out.push_back('\n'); break; case 'r': out.push_back('\r'); break; case 't': out.push_back('\t'); break; case 'u': { unsigned codepoint = hex4(); if (codepoint >= 0xd800 && codepoint <= 0xdbff) { if (position_ + 2 > text_.size() || text_[position_++] != '\\' || text_[position_++] != 'u') { fail("JSON Unicode 代理对无效"); } const unsigned low = hex4(); if (low < 0xdc00 || low > 0xdfff) fail("JSON Unicode 代理对无效"); codepoint = 0x10000 + ((codepoint - 0xd800) << 10) + (low - 0xdc00); } append_utf8(out, codepoint); break; } default: fail("JSON 转义字符无效"); } } fail("JSON 字符串未结束"); } Json number_value() { const std::size_t start = position_; if (position_ < text_.size() && text_[position_] == '-') ++position_; if (position_ >= text_.size()) fail("JSON 数字无效"); if (text_[position_] == '0') { ++position_; } else { if (text_[position_] < '1' || text_[position_] > '9') fail("JSON 数字无效"); while (position_ < text_.size() && text_[position_] >= '0' && text_[position_] <= '9') ++position_; } if (position_ < text_.size() && text_[position_] == '.') { ++position_; if (position_ >= text_.size() || text_[position_] < '0' || text_[position_] > '9') fail("JSON 小数无效"); while (position_ < text_.size() && text_[position_] >= '0' && text_[position_] <= '9') ++position_; } if (position_ < text_.size() && (text_[position_] == 'e' || text_[position_] == 'E')) { ++position_; if (position_ < text_.size() && (text_[position_] == '+' || text_[position_] == '-')) ++position_; if (position_ >= text_.size() || text_[position_] < '0' || text_[position_] > '9') fail("JSON 指数无效"); while (position_ < text_.size() && text_[position_] >= '0' && text_[position_] <= '9') ++position_; } const std::string token = text_.substr(start, position_ - start); char* end = nullptr; const double parsed = std::strtod(token.c_str(), &end); if (!end || *end || !std::isfinite(parsed)) fail("JSON 数字超出范围"); return Json(parsed); } Json array_value() { consume('['); Json::Array values; if (consume(']')) return Json(std::move(values)); while (true) { values.push_back(value()); if (consume(']')) break; if (!consume(',')) fail("JSON 数组缺少逗号"); } return Json(std::move(values)); } Json object_value() { consume('{'); Json::Object values; if (consume('}')) return Json(std::move(values)); while (true) { skip_space(); if (position_ >= text_.size() || text_[position_] != '"') fail("JSON 对象键名无效"); const std::string key = string_value(); if (!consume(':')) fail("JSON 对象缺少冒号"); values[key] = value(); if (consume('}')) break; if (!consume(',')) fail("JSON 对象缺少逗号"); } return Json(std::move(values)); } Json value() { skip_space(); if (position_ >= text_.size()) fail("JSON 内容不完整"); switch (text_[position_]) { case 'n': literal("null"); return Json(); case 't': literal("true"); return Json(true); case 'f': literal("false"); return Json(false); case '"': return Json(string_value()); case '[': return array_value(); case '{': return object_value(); default: return number_value(); } } }; std::string indent_text(int indent, int depth) { return indent > 0 ? std::string(static_cast(indent * depth), ' ') : std::string(); } void dump_string(std::ostringstream& out, const std::string& value) { out << '"'; for (const unsigned char c : value) { switch (c) { case '"': out << "\\\""; break; case '\\': out << "\\\\"; break; case '\b': out << "\\b"; break; case '\f': out << "\\f"; break; case '\n': out << "\\n"; break; case '\r': out << "\\r"; break; case '\t': out << "\\t"; break; default: if (c < 0x20) { out << "\\u" << std::hex << std::setw(4) << std::setfill('0') << static_cast(c) << std::dec << std::setfill(' '); } else { out << static_cast(c); } } } out << '"'; } void dump_value(std::ostringstream& out, const Json& value, int indent, int depth) { if (value.is_null()) { out << "null"; } else if (value.is_bool()) { out << (value.boolean() ? "true" : "false"); } else if (value.is_number()) { out << std::setprecision(std::numeric_limits::max_digits10) << value.number(); } else if (value.is_string()) { dump_string(out, value.string()); } else if (value.is_array()) { out << '['; const auto& values = value.array(); for (std::size_t index = 0; index < values.size(); ++index) { if (index) out << ','; if (indent > 0) out << '\n' << indent_text(indent, depth + 1); dump_value(out, values[index], indent, depth + 1); } if (indent > 0 && !values.empty()) out << '\n' << indent_text(indent, depth); out << ']'; } else { out << '{'; const auto& values = value.object(); std::size_t index = 0; for (const auto& [key, child] : values) { if (index++) out << ','; if (indent > 0) out << '\n' << indent_text(indent, depth + 1); dump_string(out, key); out << (indent > 0 ? ": " : ":"); dump_value(out, child, indent, depth + 1); } if (indent > 0 && !values.empty()) out << '\n' << indent_text(indent, depth); out << '}'; } } } // namespace Json::Json() : value_(nullptr) {} Json::Json(std::nullptr_t) : value_(nullptr) {} Json::Json(bool value) : value_(value) {} Json::Json(double value) : value_(value) {} Json::Json(const char* value) : value_(std::string(value ? value : "")) {} Json::Json(std::string value) : value_(std::move(value)) {} Json::Json(Array value) : value_(std::move(value)) {} Json::Json(Object value) : value_(std::move(value)) {} Json Json::parse(const std::string& text) { return Parser(text).parse(); } std::string Json::dump(int indent) const { std::ostringstream out; dump_value(out, *this, indent, 0); return out.str(); } bool Json::is_null() const { return std::holds_alternative(value_); } bool Json::is_bool() const { return std::holds_alternative(value_); } bool Json::is_number() const { return std::holds_alternative(value_); } bool Json::is_string() const { return std::holds_alternative(value_); } bool Json::is_array() const { return std::holds_alternative(value_); } bool Json::is_object() const { return std::holds_alternative(value_); } bool Json::boolean(bool fallback) const { return is_bool() ? std::get(value_) : fallback; } double Json::number(double fallback) const { return is_number() ? std::get(value_) : fallback; } const std::string& Json::string() const { static const std::string empty; return is_string() ? std::get(value_) : empty; } const Json::Array& Json::array() const { static const Array empty; return is_array() ? std::get(value_) : empty; } Json::Array& Json::array() { if (!is_array()) value_ = Array{}; return std::get(value_); } const Json::Object& Json::object() const { static const Object empty; return is_object() ? std::get(value_) : empty; } Json::Object& Json::object() { if (!is_object()) value_ = Object{}; return std::get(value_); } const Json* Json::find(const std::string& key) const { if (!is_object()) return nullptr; const auto found = object().find(key); return found == object().end() ? nullptr : &found->second; } Json* Json::find(const std::string& key) { if (!is_object()) return nullptr; const auto found = object().find(key); return found == object().end() ? nullptr : &found->second; } Json& Json::operator[](const std::string& key) { return object()[key]; } } // namespace connector