| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- #include "json_utils.h"
- #include <cctype>
- #include <sstream>
- #include <stdexcept>
- 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<unsigned char>(*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
|