json_utils.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #include "json_utils.h"
  2. #include <cctype>
  3. #include <sstream>
  4. #include <stdexcept>
  5. namespace reginfo {
  6. // Simple JSON string unescape: \" \\ \/ \b \f \n \r \t
  7. static std::string unescape(const std::string& s) {
  8. std::string result;
  9. result.reserve(s.size());
  10. for (size_t i = 0; i < s.size(); ++i) {
  11. if (s[i] == '\\' && i + 1 < s.size()) {
  12. switch (s[i + 1]) {
  13. case '"': result += '"'; ++i; break;
  14. case '\\': result += '\\'; ++i; break;
  15. case '/': result += '/'; ++i; break;
  16. case 'b': result += '\b'; ++i; break;
  17. case 'f': result += '\f'; ++i; break;
  18. case 'n': result += '\n'; ++i; break;
  19. case 'r': result += '\r'; ++i; break;
  20. case 't': result += '\t'; ++i; break;
  21. default: result += s[i]; break;
  22. }
  23. } else {
  24. result += s[i];
  25. }
  26. }
  27. return result;
  28. }
  29. // Simple JSON string escape
  30. static std::string escape(const std::string& s) {
  31. std::string result;
  32. result.reserve(s.size() + 2);
  33. for (char c : s) {
  34. switch (c) {
  35. case '"': result += "\\\""; break;
  36. case '\\': result += "\\\\"; break;
  37. case '\b': result += "\\b"; break;
  38. case '\f': result += "\\f"; break;
  39. case '\n': result += "\\n"; break;
  40. case '\r': result += "\\r"; break;
  41. case '\t': result += "\\t"; break;
  42. default: result += c; break;
  43. }
  44. }
  45. return result;
  46. }
  47. JsonObject JsonObject::parse(const std::string& json) {
  48. auto fail = [](const char* msg) { throw std::runtime_error(std::string("JSON parse error: ") + msg); };
  49. const char* p = json.c_str();
  50. const char* end = p + json.size();
  51. // Skip whitespace
  52. auto skipWs = [&]() {
  53. while (p < end && std::isspace(static_cast<unsigned char>(*p))) ++p;
  54. };
  55. skipWs();
  56. if (p >= end || *p != '{') fail("expected '{'");
  57. ++p;
  58. JsonObject obj;
  59. skipWs();
  60. if (p < end && *p == '}') { ++p; return obj; } // empty object
  61. while (true) {
  62. skipWs();
  63. if (p >= end || *p != '"') fail("expected string key");
  64. ++p; // skip opening quote
  65. // Read key
  66. std::string key;
  67. while (p < end && *p != '"') {
  68. if (*p == '\\' && p + 1 < end) {
  69. key += *p++;
  70. key += *p++;
  71. } else {
  72. key += *p++;
  73. }
  74. }
  75. if (p >= end) fail("unterminated key string");
  76. ++p; // skip closing quote
  77. key = unescape(key);
  78. skipWs();
  79. if (p >= end || *p != ':') fail("expected ':'");
  80. ++p;
  81. skipWs();
  82. if (p >= end || *p != '"') fail("expected string value");
  83. ++p;
  84. // Read value
  85. std::string val;
  86. while (p < end && *p != '"') {
  87. if (*p == '\\' && p + 1 < end) {
  88. val += *p++;
  89. val += *p++;
  90. } else {
  91. val += *p++;
  92. }
  93. }
  94. if (p >= end) fail("unterminated value string");
  95. ++p;
  96. val = unescape(val);
  97. obj.data_[key] = val;
  98. skipWs();
  99. if (p >= end) fail("unexpected end of object");
  100. if (*p == '}') { ++p; break; }
  101. if (*p != ',') fail("expected ',' or '}'");
  102. ++p;
  103. }
  104. return obj;
  105. }
  106. std::string JsonObject::dump(bool pretty) const {
  107. std::ostringstream oss;
  108. oss << '{';
  109. if (pretty) oss << '\n';
  110. size_t i = 0;
  111. for (const auto& kv : data_) {
  112. if (i > 0) {
  113. oss << ',';
  114. if (pretty) oss << '\n';
  115. }
  116. if (pretty) oss << " ";
  117. oss << '"' << escape(kv.first) << "\":\"" << escape(kv.second) << '"';
  118. ++i;
  119. }
  120. if (pretty) oss << '\n';
  121. oss << '}';
  122. return oss.str();
  123. }
  124. } // namespace reginfo