#include "pch.h" #include "JsonLite.h" #include #include namespace jsonlite { namespace { struct Parser { const char* p; const char* end; std::string err; explicit Parser(const std::string& s) : p(s.data()), end(s.data() + s.size()) {} void SkipWs() { while (p < end && std::isspace(static_cast(*p))) { ++p; } } bool Consume(char c) { SkipWs(); if (p < end && *p == c) { ++p; return true; } return false; } bool Expect(char c) { if (Consume(c)) return true; std::ostringstream oss; oss << "expected '" << c << "'"; err = oss.str(); return false; } bool ParseString(std::string& out) { SkipWs(); if (p >= end || *p != '"') { err = "expected string"; return false; } ++p; std::string s; while (p < end) { char c = *p++; if (c == '"') { out = std::move(s); return true; } if (c == '\\') { if (p >= end) { err = "unterminated escape"; return false; } char e = *p++; switch (e) { case '"': s.push_back('"'); break; case '\\': s.push_back('\\'); break; case '/': s.push_back('/'); break; case 'b': s.push_back('\b'); break; case 'f': s.push_back('\f'); break; case 'n': s.push_back('\n'); break; case 'r': s.push_back('\r'); break; case 't': s.push_back('\t'); break; case 'u': // 仅实现最小兼容:不解析 \uXXXX,原样丢弃并报错 err = "\\uXXXX escape not supported"; return false; default: err = "invalid escape"; return false; } continue; } s.push_back(c); } err = "unterminated string"; return false; } bool ParseNumber(double& out) { SkipWs(); const char* start = p; if (p < end && (*p == '-' || *p == '+')) ++p; bool any = false; while (p < end && std::isdigit(static_cast(*p))) { any = true; ++p; } if (p < end && *p == '.') { ++p; while (p < end && std::isdigit(static_cast(*p))) { any = true; ++p; } } if (p < end && (*p == 'e' || *p == 'E')) { ++p; if (p < end && (*p == '-' || *p == '+')) ++p; bool anyExp = false; while (p < end && std::isdigit(static_cast(*p))) { anyExp = true; ++p; } if (!anyExp) { err = "invalid number exponent"; return false; } } if (!any) { err = "invalid number"; return false; } std::string token(start, p); char* last = nullptr; out = std::strtod(token.c_str(), &last); if (!last || *last != '\0') { err = "invalid number"; return false; } return true; } bool ParseLiteral(const char* lit) { SkipWs(); size_t n = std::strlen(lit); if (static_cast(end - p) < n) return false; if (std::strncmp(p, lit, n) != 0) return false; p += n; return true; } bool ParseValue(Value& v) { SkipWs(); if (p >= end) { err = "unexpected end"; return false; } if (*p == '"') { std::string s; if (!ParseString(s)) return false; v = Value::String(std::move(s)); return true; } if (*p == '{') { err = "nested objects not supported"; return false; } if (*p == '[') { err = "arrays not supported"; return false; } if (*p == 't') { if (!ParseLiteral("true")) { err = "invalid literal"; return false; } v = Value::Bool(true); return true; } if (*p == 'f') { if (!ParseLiteral("false")) { err = "invalid literal"; return false; } v = Value::Bool(false); return true; } if (*p == 'n') { if (!ParseLiteral("null")) { err = "invalid literal"; return false; } v = Value::Null(); return true; } double n = 0.0; if (!ParseNumber(n)) return false; v = Value::Number(n); return true; } bool ParseObject(Object& out) { out.clear(); if (!Expect('{')) return false; SkipWs(); if (Consume('}')) return true; while (true) { std::string key; if (!ParseString(key)) return false; if (!Expect(':')) return false; Value v; if (!ParseValue(v)) return false; out[std::move(key)] = std::move(v); SkipWs(); if (Consume('}')) return true; if (!Expect(',')) return false; } } }; } // namespace bool ParseObject(const std::string& input, Object& out, std::string& err) { Parser parser(input); if (!parser.ParseObject(out)) { err = parser.err.empty() ? "parse error" : parser.err; return false; } parser.SkipWs(); if (parser.p != parser.end) { err = "trailing characters"; return false; } return true; } std::string EscapeString(const std::string& s) { std::string out; out.reserve(s.size() + 8); for (char c : s) { 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 (static_cast(c) < 0x20) { // 控制字符:最小处理,替换为空格 out += ' '; } else { out += c; } break; } } return out; } } // namespace jsonlite