CreoPluging9.0/JsonLite.cpp
2026-01-15 16:23:23 +08:00

252 lines
5.6 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "pch.h"
#include "JsonLite.h"
#include <cstring>
#include <sstream>
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<unsigned char>(*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<unsigned char>(*p))) {
any = true;
++p;
}
if (p < end && *p == '.') {
++p;
while (p < end && std::isdigit(static_cast<unsigned char>(*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<unsigned char>(*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<size_t>(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<unsigned char>(c) < 0x20) {
// 控制字符:最小处理,替换为空格
out += ' ';
} else {
out += c;
}
break;
}
}
return out;
}
} // namespace jsonlite