1 | #include "json.h"
|
---|
2 | #include <stdlib.h>
|
---|
3 | #include <string>
|
---|
4 | #include <algorithm>
|
---|
5 | #include <cstdlib>
|
---|
6 | #include <cstdio>
|
---|
7 | #include <climits>
|
---|
8 | #include <string.h>
|
---|
9 | #include <functional>
|
---|
10 | #include <cctype>
|
---|
11 | #include <stack>
|
---|
12 | #include <cerrno>
|
---|
13 |
|
---|
14 | #ifndef WIN32
|
---|
15 | #define _stricmp strcasecmp
|
---|
16 | #endif
|
---|
17 |
|
---|
18 | #ifdef _MSC_VER
|
---|
19 | #define snprintf sprintf_s
|
---|
20 | #endif
|
---|
21 |
|
---|
22 | #define nullptr NULL
|
---|
23 |
|
---|
24 | using namespace json;
|
---|
25 |
|
---|
26 | namespace json
|
---|
27 | {
|
---|
28 | enum StackDepthType
|
---|
29 | {
|
---|
30 | InObject,
|
---|
31 | InArray
|
---|
32 | };
|
---|
33 | }
|
---|
34 |
|
---|
35 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
36 | // Helper functions
|
---|
37 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
38 | static std::string Trim(const std::string& str)
|
---|
39 | {
|
---|
40 | std::string s = str;
|
---|
41 |
|
---|
42 | // remove white space in front
|
---|
43 | s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
|
---|
44 |
|
---|
45 | // remove trailing white space
|
---|
46 | s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
|
---|
47 |
|
---|
48 | return s;
|
---|
49 | }
|
---|
50 |
|
---|
51 | // Finds the position of the first " character that is NOT preceeded immediately by a \ character.
|
---|
52 | // In JSON, \" is valid and has a different meaning than the escaped " character.
|
---|
53 | static size_t GetQuotePos(const std::string& str, size_t start_pos = 0)
|
---|
54 | {
|
---|
55 | bool found_slash = false;
|
---|
56 | for (size_t i = start_pos; i < str.length(); i++)
|
---|
57 | {
|
---|
58 | char c = str[i];
|
---|
59 | if ((c == '\\') && !found_slash)
|
---|
60 | {
|
---|
61 | found_slash = true;
|
---|
62 | continue;
|
---|
63 | }
|
---|
64 | else if ((c == '\"') && !found_slash)
|
---|
65 | return i;
|
---|
66 |
|
---|
67 | found_slash = false;
|
---|
68 | }
|
---|
69 |
|
---|
70 | return std::string::npos;
|
---|
71 | }
|
---|
72 |
|
---|
73 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
74 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
75 | Value::Value(const Value& v) : mValueType(v.mValueType)
|
---|
76 | {
|
---|
77 | switch (mValueType)
|
---|
78 | {
|
---|
79 | case StringVal : mStringVal = v.mStringVal; break;
|
---|
80 | case IntVal : mIntVal = v.mIntVal; mFloatVal = (float)v.mIntVal; mDoubleVal = (double)v.mIntVal; break;
|
---|
81 | case FloatVal : mFloatVal = v.mFloatVal; mIntVal = (int)v.mFloatVal; mDoubleVal = (double)v.mDoubleVal; break;
|
---|
82 | case DoubleVal : mDoubleVal = v.mDoubleVal; mIntVal = (int)v.mDoubleVal; mFloatVal = (float)v.mDoubleVal; break;
|
---|
83 | case BoolVal : mBoolVal = v.mBoolVal; break;
|
---|
84 | case ObjectVal : mObjectVal = v.mObjectVal; break;
|
---|
85 | case ArrayVal : mArrayVal = v.mArrayVal; break;
|
---|
86 | default : break;
|
---|
87 | }
|
---|
88 | }
|
---|
89 |
|
---|
90 | Value& Value::operator =(const Value& v)
|
---|
91 | {
|
---|
92 | if (&v == this)
|
---|
93 | return *this;
|
---|
94 |
|
---|
95 | mValueType = v.mValueType;
|
---|
96 |
|
---|
97 | switch (mValueType)
|
---|
98 | {
|
---|
99 | case StringVal : mStringVal = v.mStringVal; break;
|
---|
100 | case IntVal : mIntVal = v.mIntVal; mFloatVal = (float)v.mIntVal; mDoubleVal = (double)v.mIntVal; break;
|
---|
101 | case FloatVal : mFloatVal = v.mFloatVal; mIntVal = (int)v.mFloatVal; mDoubleVal = (double)v.mDoubleVal; break;
|
---|
102 | case DoubleVal : mDoubleVal = v.mDoubleVal; mIntVal = (int)v.mDoubleVal; mFloatVal = (float)v.mDoubleVal; break;
|
---|
103 | case BoolVal : mBoolVal = v.mBoolVal; break;
|
---|
104 | case ObjectVal : mObjectVal = v.mObjectVal; break;
|
---|
105 | case ArrayVal : mArrayVal = v.mArrayVal; break;
|
---|
106 | default : break;
|
---|
107 | }
|
---|
108 |
|
---|
109 | return *this;
|
---|
110 | }
|
---|
111 |
|
---|
112 | Value& Value::operator [](size_t idx)
|
---|
113 | {
|
---|
114 | if (mValueType != ArrayVal)
|
---|
115 | throw std::runtime_error("json mValueType==ArrayVal required");
|
---|
116 |
|
---|
117 | return mArrayVal[idx];
|
---|
118 | }
|
---|
119 |
|
---|
120 | const Value& Value::operator [](size_t idx) const
|
---|
121 | {
|
---|
122 | if (mValueType != ArrayVal)
|
---|
123 | throw std::runtime_error("json mValueType==ArrayVal required");
|
---|
124 |
|
---|
125 | return mArrayVal[idx];
|
---|
126 | }
|
---|
127 |
|
---|
128 | Value& Value::operator [](const std::string& key)
|
---|
129 | {
|
---|
130 | if (mValueType != ObjectVal)
|
---|
131 | throw std::runtime_error("json mValueType==ObjectVal required");
|
---|
132 |
|
---|
133 | return mObjectVal[key];
|
---|
134 | }
|
---|
135 |
|
---|
136 | Value& Value::operator [](const char* key)
|
---|
137 | {
|
---|
138 | if (mValueType != ObjectVal)
|
---|
139 | throw std::runtime_error("json mValueType==ObjectVal required");
|
---|
140 |
|
---|
141 | return mObjectVal[key];
|
---|
142 | }
|
---|
143 |
|
---|
144 | const Value& Value::operator [](const char* key) const
|
---|
145 | {
|
---|
146 | if (mValueType != ObjectVal)
|
---|
147 | throw std::runtime_error("json mValueType==ObjectVal required");
|
---|
148 |
|
---|
149 | return mObjectVal[key];
|
---|
150 | }
|
---|
151 |
|
---|
152 | const Value& Value::operator [](const std::string& key) const
|
---|
153 | {
|
---|
154 | if (mValueType != ObjectVal)
|
---|
155 | throw std::runtime_error("json mValueType==ObjectVal required");
|
---|
156 |
|
---|
157 | return mObjectVal[key];
|
---|
158 | }
|
---|
159 |
|
---|
160 | void Value::Clear()
|
---|
161 | {
|
---|
162 | mValueType = NULLVal;
|
---|
163 | }
|
---|
164 |
|
---|
165 | size_t Value::size() const
|
---|
166 | {
|
---|
167 | if ((mValueType != ObjectVal) && (mValueType != ArrayVal))
|
---|
168 | return 1;
|
---|
169 |
|
---|
170 | return mValueType == ObjectVal ? mObjectVal.size() : mArrayVal.size();
|
---|
171 | }
|
---|
172 |
|
---|
173 | bool Value::HasKey(const std::string &key) const
|
---|
174 | {
|
---|
175 | if (mValueType != ObjectVal)
|
---|
176 | throw std::runtime_error("json mValueType==ObjectVal required");
|
---|
177 |
|
---|
178 | return mObjectVal.HasKey(key);
|
---|
179 | }
|
---|
180 |
|
---|
181 | int Value::HasKeys(const std::vector<std::string> &keys) const
|
---|
182 | {
|
---|
183 | if (mValueType != ObjectVal)
|
---|
184 | throw std::runtime_error("json mValueType==ObjectVal required");
|
---|
185 |
|
---|
186 | return mObjectVal.HasKeys(keys);
|
---|
187 | }
|
---|
188 |
|
---|
189 | int Value::HasKeys(const char **keys, int key_count) const
|
---|
190 | {
|
---|
191 | if (mValueType != ObjectVal)
|
---|
192 | throw std::runtime_error("json mValueType==ObjectVal required");
|
---|
193 |
|
---|
194 | return mObjectVal.HasKeys(keys, key_count);
|
---|
195 | }
|
---|
196 |
|
---|
197 | int Value::ToInt() const
|
---|
198 | {
|
---|
199 | if (!IsNumeric())
|
---|
200 | throw std::runtime_error("json mValueType==IsNumeric() required");
|
---|
201 |
|
---|
202 | return mIntVal;
|
---|
203 | }
|
---|
204 |
|
---|
205 | float Value::ToFloat() const
|
---|
206 | {
|
---|
207 | if (!IsNumeric())
|
---|
208 | throw std::runtime_error("json mValueType==IsNumeric() required");
|
---|
209 |
|
---|
210 | return mFloatVal;
|
---|
211 | }
|
---|
212 |
|
---|
213 | double Value::ToDouble() const
|
---|
214 | {
|
---|
215 | if (!IsNumeric())
|
---|
216 | throw std::runtime_error("json mValueType==IsNumeric() required");
|
---|
217 |
|
---|
218 | return mDoubleVal;
|
---|
219 | }
|
---|
220 |
|
---|
221 | bool Value::ToBool() const
|
---|
222 | {
|
---|
223 | if (mValueType != BoolVal)
|
---|
224 | throw std::runtime_error("json mValueType==BoolVal required");
|
---|
225 |
|
---|
226 | return mBoolVal;
|
---|
227 | }
|
---|
228 |
|
---|
229 | const std::string& Value::ToString() const
|
---|
230 | {
|
---|
231 | if (mValueType != StringVal)
|
---|
232 | throw std::runtime_error("json mValueType==StringVal required");
|
---|
233 |
|
---|
234 | return mStringVal;
|
---|
235 | }
|
---|
236 |
|
---|
237 | Object Value::ToObject() const
|
---|
238 | {
|
---|
239 | if (mValueType != ObjectVal)
|
---|
240 | throw std::runtime_error("json mValueType==ObjectVal required");
|
---|
241 |
|
---|
242 | return mObjectVal;
|
---|
243 | }
|
---|
244 |
|
---|
245 | Array Value::ToArray() const
|
---|
246 | {
|
---|
247 | if (mValueType != ArrayVal)
|
---|
248 | throw std::runtime_error("json mValueType==ArrayVal required");
|
---|
249 |
|
---|
250 | return mArrayVal;
|
---|
251 | }
|
---|
252 |
|
---|
253 | Value::operator int() const
|
---|
254 | {
|
---|
255 | if (!IsNumeric())
|
---|
256 | throw std::runtime_error("json mValueType==IsNumeric() required");
|
---|
257 |
|
---|
258 | return mIntVal;
|
---|
259 | }
|
---|
260 |
|
---|
261 | Value::operator float() const
|
---|
262 | {
|
---|
263 | if (!IsNumeric())
|
---|
264 | throw std::runtime_error("json mValueType==IsNumeric() required");
|
---|
265 |
|
---|
266 | return mFloatVal;
|
---|
267 | }
|
---|
268 |
|
---|
269 | Value::operator double() const
|
---|
270 | {
|
---|
271 | if (!IsNumeric())
|
---|
272 | throw std::runtime_error("json mValueType==IsNumeric() required");
|
---|
273 |
|
---|
274 | return mDoubleVal;
|
---|
275 | }
|
---|
276 |
|
---|
277 | Value::operator bool() const
|
---|
278 | {
|
---|
279 | if (mValueType != BoolVal)
|
---|
280 | throw std::runtime_error("json mValueType==BoolVal required");
|
---|
281 |
|
---|
282 | return mBoolVal;
|
---|
283 | }
|
---|
284 |
|
---|
285 | Value::operator std::string() const
|
---|
286 | {
|
---|
287 | if (mValueType != StringVal)
|
---|
288 | throw std::runtime_error("json mValueType==StringVal required");
|
---|
289 |
|
---|
290 | return mStringVal;
|
---|
291 | }
|
---|
292 |
|
---|
293 | Value::operator Object() const
|
---|
294 | {
|
---|
295 | if (mValueType != ObjectVal)
|
---|
296 | throw std::runtime_error("json mValueType==ObjectVal required");
|
---|
297 |
|
---|
298 | return mObjectVal;
|
---|
299 | }
|
---|
300 |
|
---|
301 | Value::operator Array() const
|
---|
302 | {
|
---|
303 | if (mValueType != ArrayVal)
|
---|
304 | throw std::runtime_error("json mValueType==ArrayVal required");
|
---|
305 |
|
---|
306 | return mArrayVal;
|
---|
307 | }
|
---|
308 |
|
---|
309 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
310 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
311 | Array::Array()
|
---|
312 | {
|
---|
313 | }
|
---|
314 |
|
---|
315 | Array::Array(const Array& a) : mValues(a.mValues)
|
---|
316 | {
|
---|
317 | }
|
---|
318 |
|
---|
319 | Array& Array::operator =(const Array& a)
|
---|
320 | {
|
---|
321 | if (&a == this)
|
---|
322 | return *this;
|
---|
323 |
|
---|
324 | Clear();
|
---|
325 | mValues = a.mValues;
|
---|
326 |
|
---|
327 | return *this;
|
---|
328 | }
|
---|
329 |
|
---|
330 | Value& Array::operator [](size_t i)
|
---|
331 | {
|
---|
332 | return mValues[i];
|
---|
333 | }
|
---|
334 |
|
---|
335 | const Value& Array::operator [](size_t i) const
|
---|
336 | {
|
---|
337 | return mValues[i];
|
---|
338 | }
|
---|
339 |
|
---|
340 |
|
---|
341 | Array::ValueVector::const_iterator Array::begin() const
|
---|
342 | {
|
---|
343 | return mValues.begin();
|
---|
344 | }
|
---|
345 |
|
---|
346 | Array::ValueVector::const_iterator Array::end() const
|
---|
347 | {
|
---|
348 | return mValues.end();
|
---|
349 | }
|
---|
350 |
|
---|
351 | Array::ValueVector::iterator Array::begin()
|
---|
352 | {
|
---|
353 | return mValues.begin();
|
---|
354 | }
|
---|
355 |
|
---|
356 | Array::ValueVector::iterator Array::end()
|
---|
357 | {
|
---|
358 | return mValues.end();
|
---|
359 | }
|
---|
360 |
|
---|
361 | void Array::push_back(const Value& v)
|
---|
362 | {
|
---|
363 | mValues.push_back(v);
|
---|
364 | }
|
---|
365 |
|
---|
366 | void Array::insert(size_t index, const Value& v)
|
---|
367 | {
|
---|
368 | mValues.insert(mValues.begin() + index, v);
|
---|
369 | }
|
---|
370 |
|
---|
371 | size_t Array::size() const
|
---|
372 | {
|
---|
373 | return mValues.size();
|
---|
374 | }
|
---|
375 |
|
---|
376 | void Array::Clear()
|
---|
377 | {
|
---|
378 | mValues.clear();
|
---|
379 | }
|
---|
380 |
|
---|
381 | Array::ValueVector::iterator Array::find(const Value& v)
|
---|
382 | {
|
---|
383 | return std::find(mValues.begin(), mValues.end(), v);
|
---|
384 | }
|
---|
385 |
|
---|
386 | Array::ValueVector::const_iterator Array::find(const Value& v) const
|
---|
387 | {
|
---|
388 | return std::find(mValues.begin(), mValues.end(), v);
|
---|
389 | }
|
---|
390 |
|
---|
391 | bool Array::HasValue(const Value& v) const
|
---|
392 | {
|
---|
393 | return find(v) != end();
|
---|
394 | }
|
---|
395 |
|
---|
396 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
397 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
398 | Object::Object()
|
---|
399 | {
|
---|
400 | }
|
---|
401 |
|
---|
402 | Object::Object(const Object& obj) : mValues(obj.mValues)
|
---|
403 | {
|
---|
404 |
|
---|
405 | }
|
---|
406 |
|
---|
407 | Object& Object::operator =(const Object& obj)
|
---|
408 | {
|
---|
409 | if (&obj == this)
|
---|
410 | return *this;
|
---|
411 |
|
---|
412 | Clear();
|
---|
413 | mValues = obj.mValues;
|
---|
414 |
|
---|
415 | return *this;
|
---|
416 | }
|
---|
417 |
|
---|
418 | Value& Object::operator [](const std::string& key)
|
---|
419 | {
|
---|
420 | return mValues[key];
|
---|
421 | }
|
---|
422 |
|
---|
423 | const Value& Object::operator [](const std::string& key) const
|
---|
424 | {
|
---|
425 | ValueMap::const_iterator it = mValues.find(key);
|
---|
426 | return it->second;
|
---|
427 | }
|
---|
428 |
|
---|
429 | Value& Object::operator [](const char* key)
|
---|
430 | {
|
---|
431 | return mValues[key];
|
---|
432 | }
|
---|
433 |
|
---|
434 | const Value& Object::operator [](const char* key) const
|
---|
435 | {
|
---|
436 | ValueMap::const_iterator it = mValues.find(key);
|
---|
437 | return it->second;
|
---|
438 | }
|
---|
439 |
|
---|
440 | Object::ValueMap::const_iterator Object::begin() const
|
---|
441 | {
|
---|
442 | return mValues.begin();
|
---|
443 | }
|
---|
444 |
|
---|
445 | Object::ValueMap::const_iterator Object::end() const
|
---|
446 | {
|
---|
447 | return mValues.end();
|
---|
448 | }
|
---|
449 |
|
---|
450 | Object::ValueMap::iterator Object::begin()
|
---|
451 | {
|
---|
452 | return mValues.begin();
|
---|
453 | }
|
---|
454 |
|
---|
455 | Object::ValueMap::iterator Object::end()
|
---|
456 | {
|
---|
457 | return mValues.end();
|
---|
458 | }
|
---|
459 |
|
---|
460 | Object::ValueMap::iterator Object::find(const std::string& key)
|
---|
461 | {
|
---|
462 | return mValues.find(key);
|
---|
463 | }
|
---|
464 |
|
---|
465 | Object::ValueMap::const_iterator Object::find(const std::string& key) const
|
---|
466 | {
|
---|
467 | return mValues.find(key);
|
---|
468 | }
|
---|
469 |
|
---|
470 | bool Object::HasKey(const std::string& key) const
|
---|
471 | {
|
---|
472 | return find(key) != end();
|
---|
473 | }
|
---|
474 |
|
---|
475 | int Object::HasKeys(const std::vector<std::string>& keys) const
|
---|
476 | {
|
---|
477 | for (size_t i = 0; i < keys.size(); i++)
|
---|
478 | {
|
---|
479 | if (!HasKey(keys[i]))
|
---|
480 | return (int)i;
|
---|
481 | }
|
---|
482 |
|
---|
483 | return -1;
|
---|
484 | }
|
---|
485 |
|
---|
486 | int Object::HasKeys(const char** keys, int key_count) const
|
---|
487 | {
|
---|
488 | for (int i = 0; i < key_count; i++)
|
---|
489 | if (!HasKey(keys[i]))
|
---|
490 | return i;
|
---|
491 |
|
---|
492 | return -1;
|
---|
493 | }
|
---|
494 |
|
---|
495 | void Object::Clear()
|
---|
496 | {
|
---|
497 | mValues.clear();
|
---|
498 | }
|
---|
499 |
|
---|
500 |
|
---|
501 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
502 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
503 | std::string SerializeArray(const Array& a);
|
---|
504 |
|
---|
505 | std::string SerializeValue(const Value& v)
|
---|
506 | {
|
---|
507 | std::string str;
|
---|
508 |
|
---|
509 | static const int BUFF_SZ = 500;
|
---|
510 | char buff[BUFF_SZ];
|
---|
511 | switch (v.GetType())
|
---|
512 | {
|
---|
513 | case IntVal : snprintf(buff, BUFF_SZ, "%d", (int)v); str = buff; break;
|
---|
514 | case FloatVal : snprintf(buff, BUFF_SZ, "%f", (float)v); str = buff; break;
|
---|
515 | case DoubleVal : snprintf(buff, BUFF_SZ, "%f", (double)v); str = buff; break;
|
---|
516 | case BoolVal : str = v ? "true" : "false"; break;
|
---|
517 | case NULLVal : str = "null"; break;
|
---|
518 | case ObjectVal : str = Serialize(v); break;
|
---|
519 | case ArrayVal : str = SerializeArray(v); break;
|
---|
520 | case StringVal : str = std::string("\"") + (std::string)v + std::string("\""); break;
|
---|
521 | }
|
---|
522 |
|
---|
523 | return str;
|
---|
524 | }
|
---|
525 |
|
---|
526 | std::string SerializeArray(const Array& a)
|
---|
527 | {
|
---|
528 | std::string str = "[";
|
---|
529 |
|
---|
530 | bool first = true;
|
---|
531 | for (size_t i = 0; i < a.size(); i++)
|
---|
532 | {
|
---|
533 | const Value& v = a[i];
|
---|
534 | if (!first)
|
---|
535 | str += std::string(",");
|
---|
536 |
|
---|
537 | str += SerializeValue(v);
|
---|
538 |
|
---|
539 | first = false;
|
---|
540 | }
|
---|
541 |
|
---|
542 | str += "]";
|
---|
543 | return str;
|
---|
544 | }
|
---|
545 |
|
---|
546 | std::string json::Serialize(const Value& v)
|
---|
547 | {
|
---|
548 | std::string str;
|
---|
549 |
|
---|
550 | bool first = true;
|
---|
551 |
|
---|
552 | if (v.GetType() == ObjectVal)
|
---|
553 | {
|
---|
554 | str = "{";
|
---|
555 | Object obj = v.ToObject();
|
---|
556 | for (Object::ValueMap::const_iterator it = obj.begin(); it != obj.end(); ++it)
|
---|
557 | {
|
---|
558 | if (!first)
|
---|
559 | str += std::string(",");
|
---|
560 |
|
---|
561 | str += std::string("\"") + it->first + std::string("\":") + SerializeValue(it->second);
|
---|
562 | first = false;
|
---|
563 | }
|
---|
564 |
|
---|
565 | str += "}";
|
---|
566 | }
|
---|
567 | else if (v.GetType() == ArrayVal)
|
---|
568 | {
|
---|
569 | str = "[";
|
---|
570 | Array a = v.ToArray();
|
---|
571 | for (Array::ValueVector::const_iterator it = a.begin(); it != a.end(); ++it)
|
---|
572 | {
|
---|
573 | if (!first)
|
---|
574 | str += std::string(",");
|
---|
575 |
|
---|
576 | str += SerializeValue(*it);
|
---|
577 | first = false;
|
---|
578 | }
|
---|
579 |
|
---|
580 | str += "]";
|
---|
581 |
|
---|
582 | }
|
---|
583 | // else it's not valid JSON, as a JSON data structure must be an array or an object. We'll return an empty string.
|
---|
584 |
|
---|
585 |
|
---|
586 | return str;
|
---|
587 | }
|
---|
588 |
|
---|
589 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
590 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
591 | static Value DeserializeArray(std::string& str, std::stack<StackDepthType>& depth_stack);
|
---|
592 | static Value DeserializeObj(const std::string& _str, std::stack<StackDepthType>& depth_stack);
|
---|
593 |
|
---|
594 | static Value DeserializeInternal(const std::string& _str, std::stack<StackDepthType>& depth_stack)
|
---|
595 | {
|
---|
596 | Value v;
|
---|
597 |
|
---|
598 | std::string str = Trim(_str);
|
---|
599 | if (str[0] == '{')
|
---|
600 | {
|
---|
601 | // Error: Began with a { but doesn't end with one
|
---|
602 | if (str[str.length() - 1] != '}')
|
---|
603 | return Value();
|
---|
604 |
|
---|
605 | depth_stack.push(InObject);
|
---|
606 | v = DeserializeObj(str, depth_stack);
|
---|
607 | if ((v.GetType() == NULLVal) || (depth_stack.top() != InObject))
|
---|
608 | return v;
|
---|
609 |
|
---|
610 | depth_stack.pop();
|
---|
611 | }
|
---|
612 | else if (str[0] == '[')
|
---|
613 | {
|
---|
614 | // Error: Began with a [ but doesn't end with one
|
---|
615 | if (str[str.length() - 1] != ']')
|
---|
616 | return Value();
|
---|
617 |
|
---|
618 | depth_stack.push(InArray);
|
---|
619 | v = DeserializeArray(str, depth_stack);
|
---|
620 | if ((v.GetType() == NULLVal) || (depth_stack.top() != InArray))
|
---|
621 | return v;
|
---|
622 |
|
---|
623 | depth_stack.pop();
|
---|
624 | }
|
---|
625 | else
|
---|
626 | {
|
---|
627 | // Will never get here unless _str is not valid JSON
|
---|
628 | return Value();
|
---|
629 | }
|
---|
630 |
|
---|
631 | return v;
|
---|
632 | }
|
---|
633 |
|
---|
634 | static size_t GetEndOfArrayOrObj(const std::string& str, std::stack<StackDepthType>& depth_stack)
|
---|
635 | {
|
---|
636 | size_t i = 1;
|
---|
637 | bool in_quote = false;
|
---|
638 | size_t original_count = depth_stack.size();
|
---|
639 |
|
---|
640 | for (; i < str.length(); i++)
|
---|
641 | {
|
---|
642 | if (str[i] == '\"')
|
---|
643 | {
|
---|
644 | if (str[i - 1] != '\\')
|
---|
645 | in_quote = !in_quote;
|
---|
646 | }
|
---|
647 | else if (!in_quote)
|
---|
648 | {
|
---|
649 | if (str[i] == '[')
|
---|
650 | depth_stack.push(InArray);
|
---|
651 | else if (str[i] == '{')
|
---|
652 | depth_stack.push(InObject);
|
---|
653 | else if (str[i] == ']')
|
---|
654 | {
|
---|
655 | StackDepthType t = depth_stack.top();
|
---|
656 | if (t != InArray)
|
---|
657 | {
|
---|
658 | // expected to be closing an array but instead we're inside an object block.
|
---|
659 | // Example problem: {]}
|
---|
660 | return std::string::npos;
|
---|
661 | }
|
---|
662 |
|
---|
663 | size_t count = depth_stack.size();
|
---|
664 | depth_stack.pop();
|
---|
665 | if (count == original_count)
|
---|
666 | break;
|
---|
667 | }
|
---|
668 | else if (str[i] == '}')
|
---|
669 | {
|
---|
670 | StackDepthType t = depth_stack.top();
|
---|
671 | if (t != InObject)
|
---|
672 | {
|
---|
673 | // expected to be closing an object but instead we're inside an array.
|
---|
674 | // Example problem: [}]
|
---|
675 | return std::string::npos;
|
---|
676 | }
|
---|
677 |
|
---|
678 | size_t count = depth_stack.size();
|
---|
679 | depth_stack.pop();
|
---|
680 | if (count == original_count)
|
---|
681 | break;
|
---|
682 | }
|
---|
683 | }
|
---|
684 | }
|
---|
685 |
|
---|
686 | return i;
|
---|
687 | }
|
---|
688 |
|
---|
689 | static std::string UnescapeJSONString(const std::string& str)
|
---|
690 | {
|
---|
691 | std::string s = "";
|
---|
692 |
|
---|
693 | for (std::string::size_type i = 0; i < str.length(); i++)
|
---|
694 | {
|
---|
695 | char c = str[i];
|
---|
696 | if ((c == '\\') && (i + 1 < str.length()))
|
---|
697 | {
|
---|
698 | int skip_ahead = 1;
|
---|
699 | unsigned int hex;
|
---|
700 | std::string hex_str;
|
---|
701 |
|
---|
702 | switch (str[i+1])
|
---|
703 | {
|
---|
704 | case '"' : s.push_back('\"'); break;
|
---|
705 | case '\\': s.push_back('\\'); break;
|
---|
706 | case '/' : s.push_back('/'); break;
|
---|
707 | case 't' : s.push_back('\t'); break;
|
---|
708 | case 'n' : s.push_back('\n'); break;
|
---|
709 | case 'r' : s.push_back('\r'); break;
|
---|
710 | case 'b' : s.push_back('\b'); break;
|
---|
711 | case 'f' : s.push_back('\f'); break;
|
---|
712 | case 'u' : skip_ahead = 5;
|
---|
713 | hex_str = str.substr(i + 4, 2);
|
---|
714 | hex = (unsigned int)std::strtoul(hex_str.c_str(), nullptr, 16);
|
---|
715 | s.push_back((char)hex);
|
---|
716 | break;
|
---|
717 |
|
---|
718 | default: break;
|
---|
719 | }
|
---|
720 |
|
---|
721 | i += skip_ahead;
|
---|
722 | }
|
---|
723 | else
|
---|
724 | s.push_back(c);
|
---|
725 | }
|
---|
726 |
|
---|
727 | return Trim(s);
|
---|
728 | }
|
---|
729 |
|
---|
730 | static Value DeserializeValue(std::string& str, bool* had_error, std::stack<StackDepthType>& depth_stack)
|
---|
731 | {
|
---|
732 | Value v;
|
---|
733 |
|
---|
734 | *had_error = false;
|
---|
735 | str = Trim(str);
|
---|
736 |
|
---|
737 | if (str.length() == 0)
|
---|
738 | return v;
|
---|
739 |
|
---|
740 | if (str[0] == '[')
|
---|
741 | {
|
---|
742 | // This value is an array, determine the end of it and then deserialize the array
|
---|
743 | depth_stack.push(InArray);
|
---|
744 | size_t i = GetEndOfArrayOrObj(str, depth_stack);
|
---|
745 | if (i == std::string::npos)
|
---|
746 | {
|
---|
747 | *had_error = true;
|
---|
748 | return Value();
|
---|
749 | }
|
---|
750 |
|
---|
751 | std::string array_str = str.substr(0, i + 1);
|
---|
752 | v = Value(DeserializeArray(array_str, depth_stack));
|
---|
753 | str = str.substr(i + 1, str.length());
|
---|
754 | }
|
---|
755 | else if (str[0] == '{')
|
---|
756 | {
|
---|
757 | // This value is an object, determine the end of it and then deserialize the object
|
---|
758 | depth_stack.push(InObject);
|
---|
759 | size_t i = GetEndOfArrayOrObj(str, depth_stack);
|
---|
760 |
|
---|
761 | if (i == std::string::npos)
|
---|
762 | {
|
---|
763 | *had_error = true;
|
---|
764 | return Value();
|
---|
765 | }
|
---|
766 |
|
---|
767 | std::string obj_str = str.substr(0, i + 1);
|
---|
768 | v = Value(DeserializeInternal(obj_str, depth_stack));
|
---|
769 | str = str.substr(i + 1, str.length());
|
---|
770 | }
|
---|
771 | else if (str[0] == '\"')
|
---|
772 | {
|
---|
773 | // This value is a string
|
---|
774 | size_t end_quote = GetQuotePos(str, 1);
|
---|
775 | if (end_quote == std::string::npos)
|
---|
776 | {
|
---|
777 | *had_error = true;
|
---|
778 | return Value();
|
---|
779 | }
|
---|
780 |
|
---|
781 | v = Value(UnescapeJSONString(str.substr(1, end_quote - 1)));
|
---|
782 | str = str.substr(end_quote + 1, str.length());
|
---|
783 | }
|
---|
784 | else
|
---|
785 | {
|
---|
786 | // it's not an object, string, or array so it's either a boolean or a number or null.
|
---|
787 | // Numbers can contain an exponent indicator ('e') or a decimal point.
|
---|
788 | bool has_dot = false;
|
---|
789 | bool has_e = false;
|
---|
790 | std::string temp_val;
|
---|
791 | size_t i = 0;
|
---|
792 | bool found_digit = false;
|
---|
793 | bool found_first_valid_char = false;
|
---|
794 |
|
---|
795 | for (; i < str.length(); i++)
|
---|
796 | {
|
---|
797 | if (str[i] == '.')
|
---|
798 | {
|
---|
799 | if (!found_digit)
|
---|
800 | {
|
---|
801 | // As per JSON standards, there must be a digit preceding a decimal point
|
---|
802 | *had_error = true;
|
---|
803 | return Value();
|
---|
804 | }
|
---|
805 |
|
---|
806 | has_dot = true;
|
---|
807 | }
|
---|
808 | else if ((str[i] == 'e') || (str[i] == 'E'))
|
---|
809 | {
|
---|
810 | if ((_stricmp(temp_val.c_str(), "fals") != 0) && (_stricmp(temp_val.c_str(), "tru") != 0))
|
---|
811 | {
|
---|
812 | // it's not a boolean, check for scientific notation validity. This will also trap booleans with extra 'e' characters like falsee/truee
|
---|
813 | if (!found_digit)
|
---|
814 | {
|
---|
815 | // As per JSON standards, a digit must precede the 'e' notation
|
---|
816 | *had_error = true;
|
---|
817 | return Value();
|
---|
818 | }
|
---|
819 | else if (has_e)
|
---|
820 | {
|
---|
821 | // multiple 'e' characters not allowed
|
---|
822 | *had_error = true;
|
---|
823 | return Value();
|
---|
824 | }
|
---|
825 |
|
---|
826 | has_e = true;
|
---|
827 | }
|
---|
828 | }
|
---|
829 | else if (str[i] == ']')
|
---|
830 | {
|
---|
831 | if (depth_stack.empty() || (depth_stack.top() != InArray))
|
---|
832 | {
|
---|
833 | *had_error = true;
|
---|
834 | return Value();
|
---|
835 | }
|
---|
836 |
|
---|
837 | depth_stack.pop();
|
---|
838 | }
|
---|
839 | else if (str[i] == '}')
|
---|
840 | {
|
---|
841 | if (depth_stack.empty() || (depth_stack.top() != InObject))
|
---|
842 | {
|
---|
843 | *had_error = true;
|
---|
844 | return Value();
|
---|
845 | }
|
---|
846 |
|
---|
847 | depth_stack.pop();
|
---|
848 | }
|
---|
849 | else if (str[i] == ',')
|
---|
850 | break;
|
---|
851 | else if ((str[i] == '[') || (str[i] == '{'))
|
---|
852 | {
|
---|
853 | // error, we're supposed to be processing things besides arrays/objects in here
|
---|
854 | *had_error = true;
|
---|
855 | return Value();
|
---|
856 | }
|
---|
857 |
|
---|
858 | if (!std::isspace(str[i]))
|
---|
859 | {
|
---|
860 | if (std::isdigit(str[i]))
|
---|
861 | found_digit = true;
|
---|
862 |
|
---|
863 | found_first_valid_char = true;
|
---|
864 | temp_val += str[i];
|
---|
865 | }
|
---|
866 | }
|
---|
867 |
|
---|
868 | // store all floating point as doubles. This will also set the float and int values as well.
|
---|
869 | if (_stricmp(temp_val.c_str(), "true") == 0)
|
---|
870 | v = Value(true);
|
---|
871 | else if (_stricmp(temp_val.c_str(), "false") == 0)
|
---|
872 | v = Value(false);
|
---|
873 | else if (has_e || has_dot)
|
---|
874 | {
|
---|
875 | char* end_char;
|
---|
876 | errno = 0;
|
---|
877 | double d = strtod(temp_val.c_str(), &end_char);
|
---|
878 | if ((errno != 0) || (*end_char != '\0'))
|
---|
879 | {
|
---|
880 | // invalid conversion or out of range
|
---|
881 | *had_error = true;
|
---|
882 | return Value();
|
---|
883 | }
|
---|
884 |
|
---|
885 | v = Value(d);
|
---|
886 | }
|
---|
887 | else if (_stricmp(temp_val.c_str(), "null") == 0)
|
---|
888 | v = Value();
|
---|
889 | else
|
---|
890 | {
|
---|
891 | // Check if the value is beyond the size of an int and if so, store it as a double
|
---|
892 | char* end_char;
|
---|
893 | errno = 0;
|
---|
894 | long int ival = strtol(temp_val.c_str(), &end_char, 10);
|
---|
895 | if (*end_char != '\0')
|
---|
896 | {
|
---|
897 | // invalid character sequence, not a number
|
---|
898 | *had_error = true;
|
---|
899 | return Value();
|
---|
900 | }
|
---|
901 | else if ((errno == ERANGE) && ((ival == LONG_MAX) || (ival == LONG_MIN)))
|
---|
902 | {
|
---|
903 | // value is out of range for a long int, should be a double then. See if we can convert it correctly.
|
---|
904 | errno = 0;
|
---|
905 | double dval = strtod(temp_val.c_str(), &end_char);
|
---|
906 | if ((errno != 0) || (*end_char != '\0'))
|
---|
907 | {
|
---|
908 | // error in conversion or it's too big for a double
|
---|
909 | *had_error = true;
|
---|
910 | return Value();
|
---|
911 | }
|
---|
912 |
|
---|
913 | v = Value(dval);
|
---|
914 | }
|
---|
915 | else if ((ival >= INT_MIN) && (ival <= INT_MAX))
|
---|
916 | {
|
---|
917 | // valid integer range
|
---|
918 | v = Value((int)ival);
|
---|
919 | }
|
---|
920 | else
|
---|
921 | {
|
---|
922 | // probably running on a very old OS since this block implies that long isn't the same size as int.
|
---|
923 | // int is guaranteed to be at least 16 bits and long 32 bits...however nowadays they're almost
|
---|
924 | // always the same 32 bit size. But it's possible someone is running this on a very old architecture
|
---|
925 | // so for correctness, we'll error out here
|
---|
926 | *had_error = true;
|
---|
927 | return Value();
|
---|
928 | }
|
---|
929 | }
|
---|
930 |
|
---|
931 | str = str.substr(i, str.length());
|
---|
932 | }
|
---|
933 |
|
---|
934 | return v;
|
---|
935 | }
|
---|
936 |
|
---|
937 | static Value DeserializeArray(std::string& str, std::stack<StackDepthType>& depth_stack)
|
---|
938 | {
|
---|
939 | Array a;
|
---|
940 | bool had_error = false;
|
---|
941 |
|
---|
942 | str = Trim(str);
|
---|
943 |
|
---|
944 | // Arrays begin and end with [], so if we don't find one, it's an error
|
---|
945 | if ((str[0] == '[') && (str[str.length() - 1] == ']'))
|
---|
946 | str = str.substr(1, str.length() - 2);
|
---|
947 | else
|
---|
948 | return Value();
|
---|
949 |
|
---|
950 | // extract out all values from the array (remember, a value can also be an array or an object)
|
---|
951 | while (str.length() > 0)
|
---|
952 | {
|
---|
953 | std::string tmp;
|
---|
954 |
|
---|
955 | size_t i = 0;
|
---|
956 | for (; i < str.length(); i++)
|
---|
957 | {
|
---|
958 | // If we get to an object or array, parse it:
|
---|
959 | if ((str[i] == '{') || (str[i] == '['))
|
---|
960 | {
|
---|
961 | Value v = DeserializeValue(str, &had_error, depth_stack);
|
---|
962 | if (had_error)
|
---|
963 | return Value();
|
---|
964 |
|
---|
965 | if (v.GetType() != NULLVal)
|
---|
966 | a.push_back(v);
|
---|
967 |
|
---|
968 | break;
|
---|
969 | }
|
---|
970 |
|
---|
971 | bool terminate_parsing = false;
|
---|
972 |
|
---|
973 | if ((str[i] == ',') || (str[i] == ']'))
|
---|
974 | terminate_parsing = true; // hit the end of a value, parse it in the next block
|
---|
975 | else
|
---|
976 | {
|
---|
977 | // keep grabbing chars to build up the value
|
---|
978 | tmp += str[i];
|
---|
979 | if (i == str.length() - 1)
|
---|
980 | terminate_parsing = true; // end of string, finish parsing
|
---|
981 | }
|
---|
982 |
|
---|
983 | if (terminate_parsing)
|
---|
984 | {
|
---|
985 | Value v = DeserializeValue(tmp, &had_error, depth_stack);
|
---|
986 | if (had_error)
|
---|
987 | return Value();
|
---|
988 |
|
---|
989 | if (v.GetType() != NULLVal)
|
---|
990 | a.push_back(v);
|
---|
991 |
|
---|
992 | str = str.substr(i + 1, str.length());
|
---|
993 | break;
|
---|
994 | }
|
---|
995 | }
|
---|
996 | }
|
---|
997 |
|
---|
998 | return a;
|
---|
999 | }
|
---|
1000 |
|
---|
1001 | static Value DeserializeObj(const std::string& _str, std::stack<StackDepthType>& depth_stack)
|
---|
1002 | {
|
---|
1003 | Object obj;
|
---|
1004 |
|
---|
1005 | std::string str = Trim(_str);
|
---|
1006 |
|
---|
1007 | // Objects begin and end with {} so if we don't find a pair, it's an error
|
---|
1008 | if ((str[0] != '{') && (str[str.length() - 1] != '}'))
|
---|
1009 | return Value();
|
---|
1010 | else
|
---|
1011 | str = str.substr(1, str.length() - 2);
|
---|
1012 |
|
---|
1013 | // Get all key/value pairs in this object...
|
---|
1014 | while (str.length() > 0)
|
---|
1015 | {
|
---|
1016 | // Get the key name
|
---|
1017 | size_t start_quote_idx = GetQuotePos(str);
|
---|
1018 | size_t end_quote_idx = GetQuotePos(str, start_quote_idx + 1);
|
---|
1019 | size_t colon_idx = str.find(':', end_quote_idx);
|
---|
1020 |
|
---|
1021 | if ((start_quote_idx == std::string::npos) || (end_quote_idx == std::string::npos) || (colon_idx == std::string::npos))
|
---|
1022 | return Value(); // can't find key name
|
---|
1023 |
|
---|
1024 | std::string key = str.substr(start_quote_idx + 1, end_quote_idx - start_quote_idx - 1);
|
---|
1025 | if (key.length() == 0)
|
---|
1026 | return Value();
|
---|
1027 |
|
---|
1028 | bool had_error = false;
|
---|
1029 | str = str.substr(colon_idx + 1, str.length());
|
---|
1030 |
|
---|
1031 | // We have the key, now extract the value from the string
|
---|
1032 | obj[key] = DeserializeValue(str, &had_error, depth_stack);
|
---|
1033 | if (had_error)
|
---|
1034 | return Value();
|
---|
1035 | }
|
---|
1036 |
|
---|
1037 | return obj;
|
---|
1038 | }
|
---|
1039 |
|
---|
1040 | Value json::Deserialize(const std::string &str)
|
---|
1041 | {
|
---|
1042 | std::stack<StackDepthType> depth_stack;
|
---|
1043 | return DeserializeInternal(str, depth_stack);
|
---|
1044 | }
|
---|
1045 |
|
---|