载入中...
搜索中...
未找到
Json.cpp
浏览该文件的文档.
1#include "common/Json.h"
2
3#include <cmath>
4#include <cstdlib>
5#include <limits>
6#include <sstream>
7#include <utility>
8
9namespace eve::json {
10
11// ---------------------------------------------------------------------------
12// Node
13// ---------------------------------------------------------------------------
14
15struct Node {
16 enum class Kind { Null, Bool, Number, String, Object, Array };
17
19 bool boolVal = false;
20 double numberVal = 0.0;
22 bool integral = false;
23 long long intVal = 0;
24 std::string stringVal;
25 std::vector<std::pair<std::string, Node>> members; // object, document order
26 std::vector<Node> elements; // array
27};
28
29namespace {
30
35class Parser {
36public:
37 explicit Parser(const std::string& text) : s_(text) {}
38
39 bool parse(Node& out, std::string* error) {
40 skipWs();
41 if (!parseValue(out)) {
42 if (error) *error = "invalid JSON near offset " + std::to_string(pos_);
43 return false;
44 }
45 skipWs();
46 if (pos_ != s_.size()) {
47 if (error) *error = "trailing data at offset " + std::to_string(pos_);
48 return false;
49 }
50 return true;
51 }
52
53private:
54 const std::string& s_;
55 size_t pos_ = 0;
56
57 void skipWs() {
58 while (pos_ < s_.size() &&
59 (s_[pos_] == ' ' || s_[pos_] == '\t' || s_[pos_] == '\n' || s_[pos_] == '\r'))
60 ++pos_;
61 }
62
63 bool peek(char c) const { return pos_ < s_.size() && s_[pos_] == c; }
64
65 bool parseValue(Node& out) {
66 if (pos_ >= s_.size()) return false;
67 switch (s_[pos_]) {
68 case '{': return parseObject(out);
69 case '[': return parseArray(out);
70 case '"':
71 if (!parseString(out.stringVal)) return false;
73 return true;
74 case 't': return parseLiteral("true", out, true);
75 case 'f': return parseLiteral("false", out, false);
76 case 'n': return parseNull(out);
77 default: return parseNumber(out);
78 }
79 }
80
81 bool parseLiteral(const char* lit, Node& out, bool value) {
82 const size_t n = std::char_traits<char>::length(lit);
83 if (s_.compare(pos_, n, lit) != 0) return false;
84 pos_ += n;
86 out.boolVal = value;
87 return true;
88 }
89
90 bool parseNull(Node& out) {
91 if (s_.compare(pos_, 4, "null") != 0) return false;
92 pos_ += 4;
94 return true;
95 }
96
97 bool parseNumber(Node& out) {
98 const size_t start = pos_;
99 if (pos_ < s_.size() && (s_[pos_] == '-' || s_[pos_] == '+')) ++pos_;
100 bool hasDigit = false;
101 while (pos_ < s_.size() && s_[pos_] >= '0' && s_[pos_] <= '9') {
102 ++pos_;
103 hasDigit = true;
104 }
105 bool integral = true;
106 if (pos_ < s_.size() && s_[pos_] == '.') {
107 integral = false;
108 ++pos_;
109 while (pos_ < s_.size() && s_[pos_] >= '0' && s_[pos_] <= '9') ++pos_;
110 }
111 if (pos_ < s_.size() && (s_[pos_] == 'e' || s_[pos_] == 'E')) {
112 integral = false;
113 ++pos_;
114 if (pos_ < s_.size() && (s_[pos_] == '-' || s_[pos_] == '+')) ++pos_;
115 while (pos_ < s_.size() && s_[pos_] >= '0' && s_[pos_] <= '9') ++pos_;
116 }
117 if (!hasDigit) return false;
118 const std::string num = s_.substr(start, pos_ - start);
119 try {
120 out.numberVal = std::stod(num);
121 if (integral) {
122 out.intVal = std::stoll(num);
123 out.integral = true;
124 }
125 } catch (...) {
126 // Out of long long range but still a valid double (or vice versa):
127 // keep whichever conversion succeeded.
128 if (!integral) return false;
129 try {
130 out.numberVal = std::stod(num);
131 out.integral = false;
132 } catch (...) {
133 return false;
134 }
135 }
137 return true;
138 }
139
140 bool parseString(std::string& out) {
141 if (!peek('"')) return false;
142 ++pos_;
143 out.clear();
144 while (pos_ < s_.size()) {
145 const char c = s_[pos_++];
146 if (c == '"') return true;
147 if (c != '\\') {
148 out += c;
149 continue;
150 }
151 if (pos_ >= s_.size()) return false;
152 const char esc = s_[pos_++];
153 switch (esc) {
154 case '"': out += '"'; break;
155 case '\\': out += '\\'; break;
156 case '/': out += '/'; break;
157 case 'b': out += '\b'; break;
158 case 'f': out += '\f'; break;
159 case 'n': out += '\n'; break;
160 case 'r': out += '\r'; break;
161 case 't': out += '\t'; break;
162 case 'u': {
163 if (pos_ + 4 > s_.size()) return false;
164 const char hex[5] = {s_[pos_], s_[pos_ + 1], s_[pos_ + 2], s_[pos_ + 3], '\0'};
165 pos_ += 4;
166 char* end = nullptr;
167 const unsigned cp = static_cast<unsigned>(std::strtoul(hex, &end, 16));
168 if (!end || *end != '\0') return false;
169 // A high surrogate followed by "\uXXXX" forms one code point.
170 if (cp >= 0xD800 && cp <= 0xDBFF && pos_ + 6 <= s_.size() && s_[pos_] == '\\' &&
171 s_[pos_ + 1] == 'u') {
172 const char lohex[5] = {s_[pos_ + 2], s_[pos_ + 3], s_[pos_ + 4],
173 s_[pos_ + 5], '\0'};
174 pos_ += 6;
175 char* loEnd = nullptr;
176 const unsigned lo = static_cast<unsigned>(std::strtoul(lohex, &loEnd, 16));
177 if (loEnd && *loEnd == '\0' && lo >= 0xDC00 && lo <= 0xDFFF)
178 appendUtf8(out, 0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00));
179 else
180 appendUtf8(out, cp);
181 } else {
182 appendUtf8(out, cp);
183 }
184 break;
185 }
186 default: return false;
187 }
188 }
189 return false; // unterminated
190 }
191
192 static void appendUtf8(std::string& out, unsigned cp) {
193 if (cp < 0x80) {
194 out += static_cast<char>(cp);
195 } else if (cp < 0x800) {
196 out += static_cast<char>(0xC0 | (cp >> 6));
197 out += static_cast<char>(0x80 | (cp & 0x3F));
198 } else if (cp < 0x10000) {
199 out += static_cast<char>(0xE0 | (cp >> 12));
200 out += static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
201 out += static_cast<char>(0x80 | (cp & 0x3F));
202 } else {
203 out += static_cast<char>(0xF0 | (cp >> 18));
204 out += static_cast<char>(0x80 | ((cp >> 12) & 0x3F));
205 out += static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
206 out += static_cast<char>(0x80 | (cp & 0x3F));
207 }
208 }
209
210 bool parseObject(Node& out) {
211 ++pos_; // '{'
212 skipWs();
213 if (peek('}')) {
214 ++pos_;
216 return true;
217 }
218 while (true) {
219 skipWs();
220 std::string key;
221 if (!parseString(key)) return false;
222 skipWs();
223 if (!peek(':')) return false;
224 ++pos_;
225 skipWs();
226 Node val;
227 if (!parseValue(val)) return false;
228 out.members.emplace_back(std::move(key), std::move(val));
229 skipWs();
230 if (peek('}')) {
231 ++pos_;
233 return true;
234 }
235 if (!peek(',')) return false;
236 ++pos_;
237 }
238 }
239
240 bool parseArray(Node& out) {
241 ++pos_; // '['
242 skipWs();
243 if (peek(']')) {
244 ++pos_;
246 return true;
247 }
248 while (true) {
249 skipWs();
250 Node val;
251 if (!parseValue(val)) return false;
252 out.elements.push_back(std::move(val));
253 skipWs();
254 if (peek(']')) {
255 ++pos_;
257 return true;
258 }
259 if (!peek(',')) return false;
260 ++pos_;
261 }
262 }
263};
264
266std::string numberToString(const Node& n) {
267 if (n.integral) return std::to_string(n.intVal);
268 std::ostringstream os;
269 os << n.numberVal;
270 return os.str();
271}
272
273bool stringToDouble(const std::string& s, double& out) {
274 try {
275 size_t used = 0;
276 const double v = std::stod(s, &used);
277 while (used < s.size() && (s[used] == ' ' || s[used] == '\t')) ++used;
278 if (used != s.size()) return false;
279 out = v;
280 return true;
281 } catch (...) {
282 return false;
283 }
284}
285
286} // namespace
287
288// ---------------------------------------------------------------------------
289// Value
290// ---------------------------------------------------------------------------
291
292bool Value::isNull() const { return !node_ || node_->kind == Node::Kind::Null; }
293bool Value::isBool() const { return node_ && node_->kind == Node::Kind::Bool; }
294bool Value::isNumber() const { return node_ && node_->kind == Node::Kind::Number; }
295bool Value::isString() const { return node_ && node_->kind == Node::Kind::String; }
296bool Value::isObject() const { return node_ && node_->kind == Node::Kind::Object; }
297bool Value::isArray() const { return node_ && node_->kind == Node::Kind::Array; }
298
299bool Value::has(const char* key) const { return static_cast<bool>(get(key)); }
300
301Value Value::get(const char* key) const {
302 if (!node_ || node_->kind != Node::Kind::Object || !key) return Value();
303 for (const auto& m : node_->members)
304 if (m.first == key) return Value(&m.second);
305 return Value();
306}
307
308std::vector<std::string> Value::keys() const {
309 std::vector<std::string> out;
310 if (!node_ || node_->kind != Node::Kind::Object) return out;
311 out.reserve(node_->members.size());
312 for (const auto& m : node_->members) out.push_back(m.first);
313 return out;
314}
315
316size_t Value::size() const {
317 if (!node_) return 0;
318 if (node_->kind == Node::Kind::Array) return node_->elements.size();
319 if (node_->kind == Node::Kind::Object) return node_->members.size();
320 return 0;
321}
322
323Value Value::at(size_t index) const {
324 if (!node_ || node_->kind != Node::Kind::Array || index >= node_->elements.size())
325 return Value();
326 return Value(&node_->elements[index]);
327}
328
329bool Value::asBool(bool fallback) const {
330 if (!node_) return fallback;
331 switch (node_->kind) {
332 case Node::Kind::Bool: return node_->boolVal;
333 case Node::Kind::Number: return node_->numberVal != 0.0;
335 if (node_->stringVal == "true") return true;
336 if (node_->stringVal == "false") return false;
337 return fallback;
338 default: return fallback;
339 }
340}
341
342double Value::asDouble(double fallback) const {
343 if (!node_) return fallback;
344 switch (node_->kind) {
345 case Node::Kind::Number: return node_->numberVal;
346 case Node::Kind::Bool: return node_->boolVal ? 1.0 : 0.0;
347 case Node::Kind::String: {
348 double v = 0.0;
349 return stringToDouble(node_->stringVal, v) ? v : fallback;
350 }
351 default: return fallback;
352 }
353}
354
355int Value::asInt(int fallback) const {
356 if (!node_) return fallback;
357 if (node_->kind == Node::Kind::Number && node_->integral) {
358 if (node_->intVal < std::numeric_limits<int>::min() ||
359 node_->intVal > std::numeric_limits<int>::max())
360 return fallback;
361 return static_cast<int>(node_->intVal);
362 }
363 const double d = asDouble(static_cast<double>(fallback));
364 if (!std::isfinite(d) || d < static_cast<double>(std::numeric_limits<int>::min()) ||
365 d > static_cast<double>(std::numeric_limits<int>::max()))
366 return fallback;
367 return static_cast<int>(d);
368}
369
370float Value::asFloat(float fallback) const {
371 return static_cast<float>(asDouble(static_cast<double>(fallback)));
372}
373
374std::string Value::asString(const std::string& fallback) const {
375 if (!node_) return fallback;
376 switch (node_->kind) {
377 case Node::Kind::String: return node_->stringVal;
378 case Node::Kind::Number: return numberToString(*node_);
379 case Node::Kind::Bool: return node_->boolVal ? "true" : "false";
380 default: return fallback;
381 }
382}
383
384bool Value::getBool(const char* key, bool fallback) const { return get(key).asBool(fallback); }
385int Value::getInt(const char* key, int fallback) const { return get(key).asInt(fallback); }
386float Value::getFloat(const char* key, float fallback) const { return get(key).asFloat(fallback); }
387double Value::getDouble(const char* key, double fallback) const {
388 return get(key).asDouble(fallback);
389}
390std::string Value::getString(const char* key, const std::string& fallback) const {
391 return get(key).asString(fallback);
392}
393
394std::vector<std::string> Value::toStringArray() const {
395 std::vector<std::string> out;
396 if (!node_ || node_->kind != Node::Kind::Array) return out;
397 out.reserve(node_->elements.size());
398 for (const auto& e : node_->elements) out.push_back(Value(&e).asString());
399 return out;
400}
401
402std::vector<std::string> Value::getStringArray(const char* key) const {
403 return get(key).toStringArray();
404}
405
406std::vector<int> Value::getIntArray(const char* key) const {
407 std::vector<int> out;
408 const Value arr = get(key);
409 const size_t n = arr.isArray() ? arr.size() : 0;
410 out.reserve(n);
411 for (size_t i = 0; i < n; ++i) out.push_back(arr.at(i).asInt(0));
412 return out;
413}
414
415std::vector<float> Value::getFloatArray(const char* key) const {
416 std::vector<float> out;
417 const Value arr = get(key);
418 const size_t n = arr.isArray() ? arr.size() : 0;
419 out.reserve(n);
420 for (size_t i = 0; i < n; ++i) out.push_back(arr.at(i).asFloat(0.f));
421 return out;
422}
423
424std::unordered_map<std::string, std::string> Value::getStringMap(const char* key) const {
425 std::unordered_map<std::string, std::string> out;
426 const Value obj = get(key);
427 if (!obj.isObject()) return out;
428 for (const auto& name : obj.keys()) out[name] = obj.getString(name.c_str());
429 return out;
430}
431
432std::unordered_map<std::string, int> Value::getIntMap(const char* key) const {
433 std::unordered_map<std::string, int> out;
434 const Value obj = get(key);
435 if (!obj.isObject()) return out;
436 for (const auto& name : obj.keys()) out[name] = obj.getInt(name.c_str(), 0);
437 return out;
438}
439
440// ---------------------------------------------------------------------------
441// Document
442// ---------------------------------------------------------------------------
443
444Document::Document() = default;
445Document::~Document() = default;
446Document::Document(Document&&) noexcept = default;
447Document& Document::operator=(Document&&) noexcept = default;
448
449Document Document::parse(const std::string& text, std::string* error) {
450 Document doc;
451 auto node = std::make_unique<Node>();
452 Parser parser(text);
453 if (!parser.parse(*node, error)) return doc;
454 doc.root_ = std::move(node);
455 return doc;
456}
457
458} // namespace eve::json
std::string value
glm::vec3 n
Definition Grass.cpp:64
std::string error
std::ostringstream & os
uint32_t c
const char * name
Definition RockMesh.cpp:21
int d
int v
float m[16]
uint32_t s
Definition Weather.cpp:28
float asFloat(float fallback=0.f) const
Definition Json.cpp:370
bool getBool(const char *key, bool fallback=false) const
Definition Json.cpp:384
bool isObject() const
Definition Json.cpp:296
bool has(const char *key) const
Definition Json.cpp:299
double asDouble(double fallback=0.0) const
Definition Json.cpp:342
Value get(const char *key) const
Definition Json.cpp:301
size_t size() const
Definition Json.cpp:316
bool isArray() const
Definition Json.cpp:297
Value at(size_t index) const
Definition Json.cpp:323
bool isString() const
Definition Json.cpp:295
float getFloat(const char *key, float fallback=0.f) const
Definition Json.cpp:386
int getInt(const char *key, int fallback=0) const
Definition Json.cpp:385
bool isNull() const
Definition Json.cpp:292
bool isNumber() const
Definition Json.cpp:294
std::string getString(const char *key, const std::string &fallback={}) const
Definition Json.cpp:390
int asInt(int fallback=0) const
Definition Json.cpp:355
std::vector< std::string > getStringArray(const char *key) const
Definition Json.cpp:402
bool asBool(bool fallback=false) const
Definition Json.cpp:329
double getDouble(const char *key, double fallback=0.0) const
Definition Json.cpp:387
bool isBool() const
Definition Json.cpp:293
std::vector< std::string > keys() const
Definition Json.cpp:308
std::string asString(const std::string &fallback={}) const
Definition Json.cpp:374
std::unordered_map< std::string, int > getIntMap(const char *key) const
Definition Json.cpp:432
std::unordered_map< std::string, std::string > getStringMap(const char *key) const
Definition Json.cpp:424
std::vector< int > getIntArray(const char *key) const
Definition Json.cpp:406
std::vector< std::string > toStringArray() const
Definition Json.cpp:394
std::vector< float > getFloatArray(const char *key) const
Definition Json.cpp:415
std::string stringVal
Definition Json.cpp:24
bool integral
Definition Json.cpp:22
long long intVal
Definition Json.cpp:23
std::vector< Node > elements
Definition Json.cpp:26
std::vector< std::pair< std::string, Node > > members
Definition Json.cpp:25
double numberVal
Definition Json.cpp:20