#include "json_utils.h" #include #include #include namespace reginfo { // Simple JSON string unescape: \" \\ \/ \b \f \n \r \t static std::string unescape(const std::string& s) { std::string result; result.reserve(s.size()); for (size_t i = 0; i < s.size(); ++i) { if (s[i] == '\\' && i + 1 < s.size()) { switch (s[i + 1]) { case '"': result += '"'; ++i; break; case '\\': result += '\\'; ++i; break; case '/': result += '/'; ++i; break; case 'b': result += '\b'; ++i; break; case 'f': result += '\f'; ++i; break; case 'n': result += '\n'; ++i; break; case 'r': result += '\r'; ++i; break; case 't': result += '\t'; ++i; break; default: result += s[i]; break; } } else { result += s[i]; } } return result; } // Simple JSON string escape static std::string escape(const std::string& s) { std::string result; result.reserve(s.size() + 2); for (char c : s) { switch (c) { case '"': result += "\\\""; break; case '\\': result += "\\\\"; break; case '\b': result += "\\b"; break; case '\f': result += "\\f"; break; case '\n': result += "\\n"; break; case '\r': result += "\\r"; break; case '\t': result += "\\t"; break; default: result += c; break; } } return result; } JsonObject JsonObject::parse(const std::string& json) { auto fail = [](const char* msg) { throw std::runtime_error(std::string("JSON parse error: ") + msg); }; const char* p = json.c_str(); const char* end = p + json.size(); // Skip whitespace auto skipWs = [&]() { while (p < end && std::isspace(static_cast(*p))) ++p; }; skipWs(); if (p >= end || *p != '{') fail("expected '{'"); ++p; JsonObject obj; skipWs(); if (p < end && *p == '}') { ++p; return obj; } // empty object while (true) { skipWs(); if (p >= end || *p != '"') fail("expected string key"); ++p; // skip opening quote // Read key std::string key; while (p < end && *p != '"') { if (*p == '\\' && p + 1 < end) { key += *p++; key += *p++; } else { key += *p++; } } if (p >= end) fail("unterminated key string"); ++p; // skip closing quote key = unescape(key); skipWs(); if (p >= end || *p != ':') fail("expected ':'"); ++p; skipWs(); if (p >= end || *p != '"') fail("expected string value"); ++p; // Read value std::string val; while (p < end && *p != '"') { if (*p == '\\' && p + 1 < end) { val += *p++; val += *p++; } else { val += *p++; } } if (p >= end) fail("unterminated value string"); ++p; val = unescape(val); obj.data_[key] = val; skipWs(); if (p >= end) fail("unexpected end of object"); if (*p == '}') { ++p; break; } if (*p != ',') fail("expected ',' or '}'"); ++p; } return obj; } std::string JsonObject::dump(bool pretty) const { std::ostringstream oss; oss << '{'; if (pretty) oss << '\n'; size_t i = 0; for (const auto& kv : data_) { if (i > 0) { oss << ','; if (pretty) oss << '\n'; } if (pretty) oss << " "; oss << '"' << escape(kv.first) << "\":\"" << escape(kv.second) << '"'; ++i; } if (pretty) oss << '\n'; oss << '}'; return oss.str(); } } // namespace reginfo