499
|
1 /// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/).
|
|
2 /// It is intended to be used with #include "json/json.h"
|
|
3
|
|
4 // //////////////////////////////////////////////////////////////////////
|
|
5 // Beginning of content of file: LICENSE
|
|
6 // //////////////////////////////////////////////////////////////////////
|
|
7
|
|
8 /*
|
|
9 The JsonCpp library's source code, including accompanying documentation,
|
|
10 tests and demonstration applications, are licensed under the following
|
|
11 conditions...
|
|
12
|
|
13 Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
|
|
14 jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
|
15 this software is released into the Public Domain.
|
|
16
|
|
17 In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
|
|
18 2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
|
|
19 The JsonCpp Authors, and is released under the terms of the MIT License (see below).
|
|
20
|
|
21 In jurisdictions which recognize Public Domain property, the user of this
|
|
22 software may choose to accept it either as 1) Public Domain, 2) under the
|
|
23 conditions of the MIT License (see below), or 3) under the terms of dual
|
|
24 Public Domain/MIT License conditions described here, as they choose.
|
|
25
|
|
26 The MIT License is about as close to Public Domain as a license can get, and is
|
|
27 described in clear, concise terms at:
|
|
28
|
|
29 http://en.wikipedia.org/wiki/MIT_License
|
|
30
|
|
31 The full text of the MIT License follows:
|
|
32
|
|
33 ========================================================================
|
|
34 Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
|
35
|
|
36 Permission is hereby granted, free of charge, to any person
|
|
37 obtaining a copy of this software and associated documentation
|
|
38 files (the "Software"), to deal in the Software without
|
|
39 restriction, including without limitation the rights to use, copy,
|
|
40 modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
41 of the Software, and to permit persons to whom the Software is
|
|
42 furnished to do so, subject to the following conditions:
|
|
43
|
|
44 The above copyright notice and this permission notice shall be
|
|
45 included in all copies or substantial portions of the Software.
|
|
46
|
|
47 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
48 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
49 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
50 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
51 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
52 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
53 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
54 SOFTWARE.
|
|
55 ========================================================================
|
|
56 (END LICENSE TEXT)
|
|
57
|
|
58 The MIT license is compatible with both the GPL and commercial
|
|
59 software, affording one all of the rights of Public Domain with the
|
|
60 minor nuisance of being required to keep the above copyright notice
|
|
61 and license text in the source code. Note also that by accepting the
|
|
62 Public Domain "license" you can re-license your copy using whatever
|
|
63 license you like.
|
|
64
|
|
65 */
|
|
66
|
|
67 // //////////////////////////////////////////////////////////////////////
|
|
68 // End of content of file: LICENSE
|
|
69 // //////////////////////////////////////////////////////////////////////
|
|
70
|
|
71
|
|
72
|
|
73
|
|
74
|
|
75
|
|
76 #include "json/json.h"
|
|
77
|
|
78 #ifndef JSON_IS_AMALGAMATION
|
|
79 #error "Compile with -I PATH_TO_JSON_DIRECTORY"
|
|
80 #endif
|
|
81
|
|
82
|
|
83 // //////////////////////////////////////////////////////////////////////
|
|
84 // Beginning of content of file: src/lib_json/json_tool.h
|
|
85 // //////////////////////////////////////////////////////////////////////
|
|
86
|
|
87 // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
|
88 // Distributed under MIT license, or public domain if desired and
|
|
89 // recognized in your jurisdiction.
|
|
90 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
|
91
|
|
92 #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
|
93 #define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
|
94
|
|
95 #if !defined(JSON_IS_AMALGAMATION)
|
|
96 #include <json/config.h>
|
|
97 #endif
|
|
98
|
|
99 // Also support old flag NO_LOCALE_SUPPORT
|
|
100 #ifdef NO_LOCALE_SUPPORT
|
|
101 #define JSONCPP_NO_LOCALE_SUPPORT
|
|
102 #endif
|
|
103
|
|
104 #ifndef JSONCPP_NO_LOCALE_SUPPORT
|
|
105 #include <clocale>
|
|
106 #endif
|
|
107
|
|
108 /* This header provides common string manipulation support, such as UTF-8,
|
|
109 * portable conversion from/to string...
|
|
110 *
|
|
111 * It is an internal header that must not be exposed.
|
|
112 */
|
|
113
|
|
114 namespace Json {
|
|
115 static inline char getDecimalPoint() {
|
|
116 #ifdef JSONCPP_NO_LOCALE_SUPPORT
|
|
117 return '\0';
|
|
118 #else
|
|
119 struct lconv* lc = localeconv();
|
|
120 return lc ? *(lc->decimal_point) : '\0';
|
|
121 #endif
|
|
122 }
|
|
123
|
|
124 /// Converts a unicode code-point to UTF-8.
|
|
125 static inline String codePointToUTF8(unsigned int cp) {
|
|
126 String result;
|
|
127
|
|
128 // based on description from http://en.wikipedia.org/wiki/UTF-8
|
|
129
|
|
130 if (cp <= 0x7f) {
|
|
131 result.resize(1);
|
|
132 result[0] = static_cast<char>(cp);
|
|
133 } else if (cp <= 0x7FF) {
|
|
134 result.resize(2);
|
|
135 result[1] = static_cast<char>(0x80 | (0x3f & cp));
|
|
136 result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
|
|
137 } else if (cp <= 0xFFFF) {
|
|
138 result.resize(3);
|
|
139 result[2] = static_cast<char>(0x80 | (0x3f & cp));
|
|
140 result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
|
141 result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
|
|
142 } else if (cp <= 0x10FFFF) {
|
|
143 result.resize(4);
|
|
144 result[3] = static_cast<char>(0x80 | (0x3f & cp));
|
|
145 result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
|
146 result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
|
|
147 result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
|
|
148 }
|
|
149
|
|
150 return result;
|
|
151 }
|
|
152
|
|
153 enum {
|
|
154 /// Constant that specify the size of the buffer that must be passed to
|
|
155 /// uintToString.
|
|
156 uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
|
|
157 };
|
|
158
|
|
159 // Defines a char buffer for use with uintToString().
|
|
160 typedef char UIntToStringBuffer[uintToStringBufferSize];
|
|
161
|
|
162 /** Converts an unsigned integer to string.
|
|
163 * @param value Unsigned integer to convert to string
|
|
164 * @param current Input/Output string buffer.
|
|
165 * Must have at least uintToStringBufferSize chars free.
|
|
166 */
|
|
167 static inline void uintToString(LargestUInt value, char*& current) {
|
|
168 *--current = 0;
|
|
169 do {
|
|
170 *--current = static_cast<char>(value % 10U + static_cast<unsigned>('0'));
|
|
171 value /= 10;
|
|
172 } while (value != 0);
|
|
173 }
|
|
174
|
|
175 /** Change ',' to '.' everywhere in buffer.
|
|
176 *
|
|
177 * We had a sophisticated way, but it did not work in WinCE.
|
|
178 * @see https://github.com/open-source-parsers/jsoncpp/pull/9
|
|
179 */
|
|
180 template <typename Iter> Iter fixNumericLocale(Iter begin, Iter end) {
|
|
181 for (; begin != end; ++begin) {
|
|
182 if (*begin == ',') {
|
|
183 *begin = '.';
|
|
184 }
|
|
185 }
|
|
186 return begin;
|
|
187 }
|
|
188
|
|
189 template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) {
|
|
190 char decimalPoint = getDecimalPoint();
|
|
191 if (decimalPoint == '\0' || decimalPoint == '.') {
|
|
192 return;
|
|
193 }
|
|
194 for (; begin != end; ++begin) {
|
|
195 if (*begin == '.') {
|
|
196 *begin = decimalPoint;
|
|
197 }
|
|
198 }
|
|
199 }
|
|
200
|
|
201 /**
|
|
202 * Return iterator that would be the new end of the range [begin,end), if we
|
|
203 * were to delete zeros in the end of string, but not the last zero before '.'.
|
|
204 */
|
|
205 template <typename Iter> Iter fixZerosInTheEnd(Iter begin, Iter end) {
|
|
206 for (; begin != end; --end) {
|
|
207 if (*(end - 1) != '0') {
|
|
208 return end;
|
|
209 }
|
|
210 // Don't delete the last zero before the decimal point.
|
|
211 if (begin != (end - 1) && *(end - 2) == '.') {
|
|
212 return end;
|
|
213 }
|
|
214 }
|
|
215 return end;
|
|
216 }
|
|
217
|
|
218 } // namespace Json
|
|
219
|
|
220 #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
|
221
|
|
222 // //////////////////////////////////////////////////////////////////////
|
|
223 // End of content of file: src/lib_json/json_tool.h
|
|
224 // //////////////////////////////////////////////////////////////////////
|
|
225
|
|
226
|
|
227
|
|
228
|
|
229
|
|
230
|
|
231 // //////////////////////////////////////////////////////////////////////
|
|
232 // Beginning of content of file: src/lib_json/json_reader.cpp
|
|
233 // //////////////////////////////////////////////////////////////////////
|
|
234
|
|
235 // Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors
|
|
236 // Copyright (C) 2016 InfoTeCS JSC. All rights reserved.
|
|
237 // Distributed under MIT license, or public domain if desired and
|
|
238 // recognized in your jurisdiction.
|
|
239 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
|
240
|
|
241 #if !defined(JSON_IS_AMALGAMATION)
|
|
242 #include "json_tool.h"
|
|
243 #include <json/assertions.h>
|
|
244 #include <json/reader.h>
|
|
245 #include <json/value.h>
|
|
246 #endif // if !defined(JSON_IS_AMALGAMATION)
|
|
247 #include <cassert>
|
|
248 #include <cstring>
|
|
249 #include <istream>
|
|
250 #include <limits>
|
|
251 #include <memory>
|
|
252 #include <set>
|
|
253 #include <sstream>
|
|
254 #include <utility>
|
|
255
|
|
256 #include <cstdio>
|
|
257 #if __cplusplus >= 201103L
|
|
258
|
|
259 #if !defined(sscanf)
|
|
260 #define sscanf std::sscanf
|
|
261 #endif
|
|
262
|
|
263 #endif //__cplusplus
|
|
264
|
|
265 #if defined(_MSC_VER)
|
|
266 #if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
|
|
267 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
|
|
268 #endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
|
|
269 #endif //_MSC_VER
|
|
270
|
|
271 #if defined(_MSC_VER)
|
|
272 // Disable warning about strdup being deprecated.
|
|
273 #pragma warning(disable : 4996)
|
|
274 #endif
|
|
275
|
|
276 // Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile
|
|
277 // time to change the stack limit
|
|
278 #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
|
|
279 #define JSONCPP_DEPRECATED_STACK_LIMIT 1000
|
|
280 #endif
|
|
281
|
|
282 static size_t const stackLimit_g =
|
|
283 JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
|
|
284
|
|
285 namespace Json {
|
|
286
|
|
287 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
|
|
288 typedef std::unique_ptr<CharReader> CharReaderPtr;
|
|
289 #else
|
|
290 typedef std::auto_ptr<CharReader> CharReaderPtr;
|
|
291 #endif
|
|
292
|
|
293 // Implementation of class Features
|
|
294 // ////////////////////////////////
|
|
295
|
|
296 Features::Features() = default;
|
|
297
|
|
298 Features Features::all() { return {}; }
|
|
299
|
|
300 Features Features::strictMode() {
|
|
301 Features features;
|
|
302 features.allowComments_ = false;
|
|
303 features.strictRoot_ = true;
|
|
304 features.allowDroppedNullPlaceholders_ = false;
|
|
305 features.allowNumericKeys_ = false;
|
|
306 return features;
|
|
307 }
|
|
308
|
|
309 // Implementation of class Reader
|
|
310 // ////////////////////////////////
|
|
311
|
|
312 bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
|
|
313 for (; begin < end; ++begin)
|
|
314 if (*begin == '\n' || *begin == '\r')
|
|
315 return true;
|
|
316 return false;
|
|
317 }
|
|
318
|
|
319 // Class Reader
|
|
320 // //////////////////////////////////////////////////////////////////
|
|
321
|
|
322 Reader::Reader()
|
|
323 : errors_(), document_(), commentsBefore_(), features_(Features::all()) {}
|
|
324
|
|
325 Reader::Reader(const Features& features)
|
|
326 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
|
|
327 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
|
|
328 }
|
|
329
|
|
330 bool Reader::parse(const std::string& document,
|
|
331 Value& root,
|
|
332 bool collectComments) {
|
|
333 document_.assign(document.begin(), document.end());
|
|
334 const char* begin = document_.c_str();
|
|
335 const char* end = begin + document_.length();
|
|
336 return parse(begin, end, root, collectComments);
|
|
337 }
|
|
338
|
|
339 bool Reader::parse(std::istream& is, Value& root, bool collectComments) {
|
|
340 // std::istream_iterator<char> begin(is);
|
|
341 // std::istream_iterator<char> end;
|
|
342 // Those would allow streamed input from a file, if parse() were a
|
|
343 // template function.
|
|
344
|
|
345 // Since String is reference-counted, this at least does not
|
|
346 // create an extra copy.
|
|
347 String doc;
|
|
348 std::getline(is, doc, (char)EOF);
|
|
349 return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
|
|
350 }
|
|
351
|
|
352 bool Reader::parse(const char* beginDoc,
|
|
353 const char* endDoc,
|
|
354 Value& root,
|
|
355 bool collectComments) {
|
|
356 if (!features_.allowComments_) {
|
|
357 collectComments = false;
|
|
358 }
|
|
359
|
|
360 begin_ = beginDoc;
|
|
361 end_ = endDoc;
|
|
362 collectComments_ = collectComments;
|
|
363 current_ = begin_;
|
|
364 lastValueEnd_ = nullptr;
|
|
365 lastValue_ = nullptr;
|
|
366 commentsBefore_.clear();
|
|
367 errors_.clear();
|
|
368 while (!nodes_.empty())
|
|
369 nodes_.pop();
|
|
370 nodes_.push(&root);
|
|
371
|
|
372 bool successful = readValue();
|
|
373 Token token;
|
|
374 skipCommentTokens(token);
|
|
375 if (collectComments_ && !commentsBefore_.empty())
|
|
376 root.setComment(commentsBefore_, commentAfter);
|
|
377 if (features_.strictRoot_) {
|
|
378 if (!root.isArray() && !root.isObject()) {
|
|
379 // Set error location to start of doc, ideally should be first token found
|
|
380 // in doc
|
|
381 token.type_ = tokenError;
|
|
382 token.start_ = beginDoc;
|
|
383 token.end_ = endDoc;
|
|
384 addError(
|
|
385 "A valid JSON document must be either an array or an object value.",
|
|
386 token);
|
|
387 return false;
|
|
388 }
|
|
389 }
|
|
390 return successful;
|
|
391 }
|
|
392
|
|
393 bool Reader::readValue() {
|
|
394 // readValue() may call itself only if it calls readObject() or ReadArray().
|
|
395 // These methods execute nodes_.push() just before and nodes_.pop)() just
|
|
396 // after calling readValue(). parse() executes one nodes_.push(), so > instead
|
|
397 // of >=.
|
|
398 if (nodes_.size() > stackLimit_g)
|
|
399 throwRuntimeError("Exceeded stackLimit in readValue().");
|
|
400
|
|
401 Token token;
|
|
402 skipCommentTokens(token);
|
|
403 bool successful = true;
|
|
404
|
|
405 if (collectComments_ && !commentsBefore_.empty()) {
|
|
406 currentValue().setComment(commentsBefore_, commentBefore);
|
|
407 commentsBefore_.clear();
|
|
408 }
|
|
409
|
|
410 switch (token.type_) {
|
|
411 case tokenObjectBegin:
|
|
412 successful = readObject(token);
|
|
413 currentValue().setOffsetLimit(current_ - begin_);
|
|
414 break;
|
|
415 case tokenArrayBegin:
|
|
416 successful = readArray(token);
|
|
417 currentValue().setOffsetLimit(current_ - begin_);
|
|
418 break;
|
|
419 case tokenNumber:
|
|
420 successful = decodeNumber(token);
|
|
421 break;
|
|
422 case tokenString:
|
|
423 successful = decodeString(token);
|
|
424 break;
|
|
425 case tokenTrue: {
|
|
426 Value v(true);
|
|
427 currentValue().swapPayload(v);
|
|
428 currentValue().setOffsetStart(token.start_ - begin_);
|
|
429 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
430 } break;
|
|
431 case tokenFalse: {
|
|
432 Value v(false);
|
|
433 currentValue().swapPayload(v);
|
|
434 currentValue().setOffsetStart(token.start_ - begin_);
|
|
435 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
436 } break;
|
|
437 case tokenNull: {
|
|
438 Value v;
|
|
439 currentValue().swapPayload(v);
|
|
440 currentValue().setOffsetStart(token.start_ - begin_);
|
|
441 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
442 } break;
|
|
443 case tokenArraySeparator:
|
|
444 case tokenObjectEnd:
|
|
445 case tokenArrayEnd:
|
|
446 if (features_.allowDroppedNullPlaceholders_) {
|
|
447 // "Un-read" the current token and mark the current value as a null
|
|
448 // token.
|
|
449 current_--;
|
|
450 Value v;
|
|
451 currentValue().swapPayload(v);
|
|
452 currentValue().setOffsetStart(current_ - begin_ - 1);
|
|
453 currentValue().setOffsetLimit(current_ - begin_);
|
|
454 break;
|
|
455 } // Else, fall through...
|
|
456 default:
|
|
457 currentValue().setOffsetStart(token.start_ - begin_);
|
|
458 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
459 return addError("Syntax error: value, object or array expected.", token);
|
|
460 }
|
|
461
|
|
462 if (collectComments_) {
|
|
463 lastValueEnd_ = current_;
|
|
464 lastValue_ = ¤tValue();
|
|
465 }
|
|
466
|
|
467 return successful;
|
|
468 }
|
|
469
|
|
470 void Reader::skipCommentTokens(Token& token) {
|
|
471 if (features_.allowComments_) {
|
|
472 do {
|
|
473 readToken(token);
|
|
474 } while (token.type_ == tokenComment);
|
|
475 } else {
|
|
476 readToken(token);
|
|
477 }
|
|
478 }
|
|
479
|
|
480 bool Reader::readToken(Token& token) {
|
|
481 skipSpaces();
|
|
482 token.start_ = current_;
|
|
483 Char c = getNextChar();
|
|
484 bool ok = true;
|
|
485 switch (c) {
|
|
486 case '{':
|
|
487 token.type_ = tokenObjectBegin;
|
|
488 break;
|
|
489 case '}':
|
|
490 token.type_ = tokenObjectEnd;
|
|
491 break;
|
|
492 case '[':
|
|
493 token.type_ = tokenArrayBegin;
|
|
494 break;
|
|
495 case ']':
|
|
496 token.type_ = tokenArrayEnd;
|
|
497 break;
|
|
498 case '"':
|
|
499 token.type_ = tokenString;
|
|
500 ok = readString();
|
|
501 break;
|
|
502 case '/':
|
|
503 token.type_ = tokenComment;
|
|
504 ok = readComment();
|
|
505 break;
|
|
506 case '0':
|
|
507 case '1':
|
|
508 case '2':
|
|
509 case '3':
|
|
510 case '4':
|
|
511 case '5':
|
|
512 case '6':
|
|
513 case '7':
|
|
514 case '8':
|
|
515 case '9':
|
|
516 case '-':
|
|
517 token.type_ = tokenNumber;
|
|
518 readNumber();
|
|
519 break;
|
|
520 case 't':
|
|
521 token.type_ = tokenTrue;
|
|
522 ok = match("rue", 3);
|
|
523 break;
|
|
524 case 'f':
|
|
525 token.type_ = tokenFalse;
|
|
526 ok = match("alse", 4);
|
|
527 break;
|
|
528 case 'n':
|
|
529 token.type_ = tokenNull;
|
|
530 ok = match("ull", 3);
|
|
531 break;
|
|
532 case ',':
|
|
533 token.type_ = tokenArraySeparator;
|
|
534 break;
|
|
535 case ':':
|
|
536 token.type_ = tokenMemberSeparator;
|
|
537 break;
|
|
538 case 0:
|
|
539 token.type_ = tokenEndOfStream;
|
|
540 break;
|
|
541 default:
|
|
542 ok = false;
|
|
543 break;
|
|
544 }
|
|
545 if (!ok)
|
|
546 token.type_ = tokenError;
|
|
547 token.end_ = current_;
|
|
548 return true;
|
|
549 }
|
|
550
|
|
551 void Reader::skipSpaces() {
|
|
552 while (current_ != end_) {
|
|
553 Char c = *current_;
|
|
554 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
|
|
555 ++current_;
|
|
556 else
|
|
557 break;
|
|
558 }
|
|
559 }
|
|
560
|
|
561 bool Reader::match(Location pattern, int patternLength) {
|
|
562 if (end_ - current_ < patternLength)
|
|
563 return false;
|
|
564 int index = patternLength;
|
|
565 while (index--)
|
|
566 if (current_[index] != pattern[index])
|
|
567 return false;
|
|
568 current_ += patternLength;
|
|
569 return true;
|
|
570 }
|
|
571
|
|
572 bool Reader::readComment() {
|
|
573 Location commentBegin = current_ - 1;
|
|
574 Char c = getNextChar();
|
|
575 bool successful = false;
|
|
576 if (c == '*')
|
|
577 successful = readCStyleComment();
|
|
578 else if (c == '/')
|
|
579 successful = readCppStyleComment();
|
|
580 if (!successful)
|
|
581 return false;
|
|
582
|
|
583 if (collectComments_) {
|
|
584 CommentPlacement placement = commentBefore;
|
|
585 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
|
|
586 if (c != '*' || !containsNewLine(commentBegin, current_))
|
|
587 placement = commentAfterOnSameLine;
|
|
588 }
|
|
589
|
|
590 addComment(commentBegin, current_, placement);
|
|
591 }
|
|
592 return true;
|
|
593 }
|
|
594
|
|
595 String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {
|
|
596 String normalized;
|
|
597 normalized.reserve(static_cast<size_t>(end - begin));
|
|
598 Reader::Location current = begin;
|
|
599 while (current != end) {
|
|
600 char c = *current++;
|
|
601 if (c == '\r') {
|
|
602 if (current != end && *current == '\n')
|
|
603 // convert dos EOL
|
|
604 ++current;
|
|
605 // convert Mac EOL
|
|
606 normalized += '\n';
|
|
607 } else {
|
|
608 normalized += c;
|
|
609 }
|
|
610 }
|
|
611 return normalized;
|
|
612 }
|
|
613
|
|
614 void Reader::addComment(Location begin,
|
|
615 Location end,
|
|
616 CommentPlacement placement) {
|
|
617 assert(collectComments_);
|
|
618 const String& normalized = normalizeEOL(begin, end);
|
|
619 if (placement == commentAfterOnSameLine) {
|
|
620 assert(lastValue_ != nullptr);
|
|
621 lastValue_->setComment(normalized, placement);
|
|
622 } else {
|
|
623 commentsBefore_ += normalized;
|
|
624 }
|
|
625 }
|
|
626
|
|
627 bool Reader::readCStyleComment() {
|
|
628 while ((current_ + 1) < end_) {
|
|
629 Char c = getNextChar();
|
|
630 if (c == '*' && *current_ == '/')
|
|
631 break;
|
|
632 }
|
|
633 return getNextChar() == '/';
|
|
634 }
|
|
635
|
|
636 bool Reader::readCppStyleComment() {
|
|
637 while (current_ != end_) {
|
|
638 Char c = getNextChar();
|
|
639 if (c == '\n')
|
|
640 break;
|
|
641 if (c == '\r') {
|
|
642 // Consume DOS EOL. It will be normalized in addComment.
|
|
643 if (current_ != end_ && *current_ == '\n')
|
|
644 getNextChar();
|
|
645 // Break on Moc OS 9 EOL.
|
|
646 break;
|
|
647 }
|
|
648 }
|
|
649 return true;
|
|
650 }
|
|
651
|
|
652 void Reader::readNumber() {
|
|
653 const char* p = current_;
|
|
654 char c = '0'; // stopgap for already consumed character
|
|
655 // integral part
|
|
656 while (c >= '0' && c <= '9')
|
|
657 c = (current_ = p) < end_ ? *p++ : '\0';
|
|
658 // fractional part
|
|
659 if (c == '.') {
|
|
660 c = (current_ = p) < end_ ? *p++ : '\0';
|
|
661 while (c >= '0' && c <= '9')
|
|
662 c = (current_ = p) < end_ ? *p++ : '\0';
|
|
663 }
|
|
664 // exponential part
|
|
665 if (c == 'e' || c == 'E') {
|
|
666 c = (current_ = p) < end_ ? *p++ : '\0';
|
|
667 if (c == '+' || c == '-')
|
|
668 c = (current_ = p) < end_ ? *p++ : '\0';
|
|
669 while (c >= '0' && c <= '9')
|
|
670 c = (current_ = p) < end_ ? *p++ : '\0';
|
|
671 }
|
|
672 }
|
|
673
|
|
674 bool Reader::readString() {
|
|
675 Char c = '\0';
|
|
676 while (current_ != end_) {
|
|
677 c = getNextChar();
|
|
678 if (c == '\\')
|
|
679 getNextChar();
|
|
680 else if (c == '"')
|
|
681 break;
|
|
682 }
|
|
683 return c == '"';
|
|
684 }
|
|
685
|
|
686 bool Reader::readObject(Token& token) {
|
|
687 Token tokenName;
|
|
688 String name;
|
|
689 Value init(objectValue);
|
|
690 currentValue().swapPayload(init);
|
|
691 currentValue().setOffsetStart(token.start_ - begin_);
|
|
692 while (readToken(tokenName)) {
|
|
693 bool initialTokenOk = true;
|
|
694 while (tokenName.type_ == tokenComment && initialTokenOk)
|
|
695 initialTokenOk = readToken(tokenName);
|
|
696 if (!initialTokenOk)
|
|
697 break;
|
|
698 if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
|
|
699 return true;
|
|
700 name.clear();
|
|
701 if (tokenName.type_ == tokenString) {
|
|
702 if (!decodeString(tokenName, name))
|
|
703 return recoverFromError(tokenObjectEnd);
|
|
704 } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
|
|
705 Value numberName;
|
|
706 if (!decodeNumber(tokenName, numberName))
|
|
707 return recoverFromError(tokenObjectEnd);
|
|
708 name = String(numberName.asCString());
|
|
709 } else {
|
|
710 break;
|
|
711 }
|
|
712
|
|
713 Token colon;
|
|
714 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
|
|
715 return addErrorAndRecover("Missing ':' after object member name", colon,
|
|
716 tokenObjectEnd);
|
|
717 }
|
|
718 Value& value = currentValue()[name];
|
|
719 nodes_.push(&value);
|
|
720 bool ok = readValue();
|
|
721 nodes_.pop();
|
|
722 if (!ok) // error already set
|
|
723 return recoverFromError(tokenObjectEnd);
|
|
724
|
|
725 Token comma;
|
|
726 if (!readToken(comma) ||
|
|
727 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
|
|
728 comma.type_ != tokenComment)) {
|
|
729 return addErrorAndRecover("Missing ',' or '}' in object declaration",
|
|
730 comma, tokenObjectEnd);
|
|
731 }
|
|
732 bool finalizeTokenOk = true;
|
|
733 while (comma.type_ == tokenComment && finalizeTokenOk)
|
|
734 finalizeTokenOk = readToken(comma);
|
|
735 if (comma.type_ == tokenObjectEnd)
|
|
736 return true;
|
|
737 }
|
|
738 return addErrorAndRecover("Missing '}' or object member name", tokenName,
|
|
739 tokenObjectEnd);
|
|
740 }
|
|
741
|
|
742 bool Reader::readArray(Token& token) {
|
|
743 Value init(arrayValue);
|
|
744 currentValue().swapPayload(init);
|
|
745 currentValue().setOffsetStart(token.start_ - begin_);
|
|
746 skipSpaces();
|
|
747 if (current_ != end_ && *current_ == ']') // empty array
|
|
748 {
|
|
749 Token endArray;
|
|
750 readToken(endArray);
|
|
751 return true;
|
|
752 }
|
|
753 int index = 0;
|
|
754 for (;;) {
|
|
755 Value& value = currentValue()[index++];
|
|
756 nodes_.push(&value);
|
|
757 bool ok = readValue();
|
|
758 nodes_.pop();
|
|
759 if (!ok) // error already set
|
|
760 return recoverFromError(tokenArrayEnd);
|
|
761
|
|
762 Token currentToken;
|
|
763 // Accept Comment after last item in the array.
|
|
764 ok = readToken(currentToken);
|
|
765 while (currentToken.type_ == tokenComment && ok) {
|
|
766 ok = readToken(currentToken);
|
|
767 }
|
|
768 bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
|
|
769 currentToken.type_ != tokenArrayEnd);
|
|
770 if (!ok || badTokenType) {
|
|
771 return addErrorAndRecover("Missing ',' or ']' in array declaration",
|
|
772 currentToken, tokenArrayEnd);
|
|
773 }
|
|
774 if (currentToken.type_ == tokenArrayEnd)
|
|
775 break;
|
|
776 }
|
|
777 return true;
|
|
778 }
|
|
779
|
|
780 bool Reader::decodeNumber(Token& token) {
|
|
781 Value decoded;
|
|
782 if (!decodeNumber(token, decoded))
|
|
783 return false;
|
|
784 currentValue().swapPayload(decoded);
|
|
785 currentValue().setOffsetStart(token.start_ - begin_);
|
|
786 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
787 return true;
|
|
788 }
|
|
789
|
|
790 bool Reader::decodeNumber(Token& token, Value& decoded) {
|
|
791 // Attempts to parse the number as an integer. If the number is
|
|
792 // larger than the maximum supported value of an integer then
|
|
793 // we decode the number as a double.
|
|
794 Location current = token.start_;
|
|
795 bool isNegative = *current == '-';
|
|
796 if (isNegative)
|
|
797 ++current;
|
|
798 // TODO: Help the compiler do the div and mod at compile time or get rid of
|
|
799 // them.
|
|
800 Value::LargestUInt maxIntegerValue =
|
|
801 isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
|
|
802 : Value::maxLargestUInt;
|
|
803 Value::LargestUInt threshold = maxIntegerValue / 10;
|
|
804 Value::LargestUInt value = 0;
|
|
805 while (current < token.end_) {
|
|
806 Char c = *current++;
|
|
807 if (c < '0' || c > '9')
|
|
808 return decodeDouble(token, decoded);
|
|
809 auto digit(static_cast<Value::UInt>(c - '0'));
|
|
810 if (value >= threshold) {
|
|
811 // We've hit or exceeded the max value divided by 10 (rounded down). If
|
|
812 // a) we've only just touched the limit, b) this is the last digit, and
|
|
813 // c) it's small enough to fit in that rounding delta, we're okay.
|
|
814 // Otherwise treat this number as a double to avoid overflow.
|
|
815 if (value > threshold || current != token.end_ ||
|
|
816 digit > maxIntegerValue % 10) {
|
|
817 return decodeDouble(token, decoded);
|
|
818 }
|
|
819 }
|
|
820 value = value * 10 + digit;
|
|
821 }
|
|
822 if (isNegative && value == maxIntegerValue)
|
|
823 decoded = Value::minLargestInt;
|
|
824 else if (isNegative)
|
|
825 decoded = -Value::LargestInt(value);
|
|
826 else if (value <= Value::LargestUInt(Value::maxInt))
|
|
827 decoded = Value::LargestInt(value);
|
|
828 else
|
|
829 decoded = value;
|
|
830 return true;
|
|
831 }
|
|
832
|
|
833 bool Reader::decodeDouble(Token& token) {
|
|
834 Value decoded;
|
|
835 if (!decodeDouble(token, decoded))
|
|
836 return false;
|
|
837 currentValue().swapPayload(decoded);
|
|
838 currentValue().setOffsetStart(token.start_ - begin_);
|
|
839 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
840 return true;
|
|
841 }
|
|
842
|
|
843 bool Reader::decodeDouble(Token& token, Value& decoded) {
|
|
844 double value = 0;
|
|
845 String buffer(token.start_, token.end_);
|
|
846 IStringStream is(buffer);
|
|
847 if (!(is >> value))
|
|
848 return addError(
|
|
849 "'" + String(token.start_, token.end_) + "' is not a number.", token);
|
|
850 decoded = value;
|
|
851 return true;
|
|
852 }
|
|
853
|
|
854 bool Reader::decodeString(Token& token) {
|
|
855 String decoded_string;
|
|
856 if (!decodeString(token, decoded_string))
|
|
857 return false;
|
|
858 Value decoded(decoded_string);
|
|
859 currentValue().swapPayload(decoded);
|
|
860 currentValue().setOffsetStart(token.start_ - begin_);
|
|
861 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
862 return true;
|
|
863 }
|
|
864
|
|
865 bool Reader::decodeString(Token& token, String& decoded) {
|
|
866 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
|
|
867 Location current = token.start_ + 1; // skip '"'
|
|
868 Location end = token.end_ - 1; // do not include '"'
|
|
869 while (current != end) {
|
|
870 Char c = *current++;
|
|
871 if (c == '"')
|
|
872 break;
|
|
873 else if (c == '\\') {
|
|
874 if (current == end)
|
|
875 return addError("Empty escape sequence in string", token, current);
|
|
876 Char escape = *current++;
|
|
877 switch (escape) {
|
|
878 case '"':
|
|
879 decoded += '"';
|
|
880 break;
|
|
881 case '/':
|
|
882 decoded += '/';
|
|
883 break;
|
|
884 case '\\':
|
|
885 decoded += '\\';
|
|
886 break;
|
|
887 case 'b':
|
|
888 decoded += '\b';
|
|
889 break;
|
|
890 case 'f':
|
|
891 decoded += '\f';
|
|
892 break;
|
|
893 case 'n':
|
|
894 decoded += '\n';
|
|
895 break;
|
|
896 case 'r':
|
|
897 decoded += '\r';
|
|
898 break;
|
|
899 case 't':
|
|
900 decoded += '\t';
|
|
901 break;
|
|
902 case 'u': {
|
|
903 unsigned int unicode;
|
|
904 if (!decodeUnicodeCodePoint(token, current, end, unicode))
|
|
905 return false;
|
|
906 decoded += codePointToUTF8(unicode);
|
|
907 } break;
|
|
908 default:
|
|
909 return addError("Bad escape sequence in string", token, current);
|
|
910 }
|
|
911 } else {
|
|
912 decoded += c;
|
|
913 }
|
|
914 }
|
|
915 return true;
|
|
916 }
|
|
917
|
|
918 bool Reader::decodeUnicodeCodePoint(Token& token,
|
|
919 Location& current,
|
|
920 Location end,
|
|
921 unsigned int& unicode) {
|
|
922
|
|
923 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
|
|
924 return false;
|
|
925 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
|
|
926 // surrogate pairs
|
|
927 if (end - current < 6)
|
|
928 return addError(
|
|
929 "additional six characters expected to parse unicode surrogate pair.",
|
|
930 token, current);
|
|
931 if (*(current++) == '\\' && *(current++) == 'u') {
|
|
932 unsigned int surrogatePair;
|
|
933 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
|
|
934 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
|
|
935 } else
|
|
936 return false;
|
|
937 } else
|
|
938 return addError("expecting another \\u token to begin the second half of "
|
|
939 "a unicode surrogate pair",
|
|
940 token, current);
|
|
941 }
|
|
942 return true;
|
|
943 }
|
|
944
|
|
945 bool Reader::decodeUnicodeEscapeSequence(Token& token,
|
|
946 Location& current,
|
|
947 Location end,
|
|
948 unsigned int& ret_unicode) {
|
|
949 if (end - current < 4)
|
|
950 return addError(
|
|
951 "Bad unicode escape sequence in string: four digits expected.", token,
|
|
952 current);
|
|
953 int unicode = 0;
|
|
954 for (int index = 0; index < 4; ++index) {
|
|
955 Char c = *current++;
|
|
956 unicode *= 16;
|
|
957 if (c >= '0' && c <= '9')
|
|
958 unicode += c - '0';
|
|
959 else if (c >= 'a' && c <= 'f')
|
|
960 unicode += c - 'a' + 10;
|
|
961 else if (c >= 'A' && c <= 'F')
|
|
962 unicode += c - 'A' + 10;
|
|
963 else
|
|
964 return addError(
|
|
965 "Bad unicode escape sequence in string: hexadecimal digit expected.",
|
|
966 token, current);
|
|
967 }
|
|
968 ret_unicode = static_cast<unsigned int>(unicode);
|
|
969 return true;
|
|
970 }
|
|
971
|
|
972 bool Reader::addError(const String& message, Token& token, Location extra) {
|
|
973 ErrorInfo info;
|
|
974 info.token_ = token;
|
|
975 info.message_ = message;
|
|
976 info.extra_ = extra;
|
|
977 errors_.push_back(info);
|
|
978 return false;
|
|
979 }
|
|
980
|
|
981 bool Reader::recoverFromError(TokenType skipUntilToken) {
|
|
982 size_t const errorCount = errors_.size();
|
|
983 Token skip;
|
|
984 for (;;) {
|
|
985 if (!readToken(skip))
|
|
986 errors_.resize(errorCount); // discard errors caused by recovery
|
|
987 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
|
|
988 break;
|
|
989 }
|
|
990 errors_.resize(errorCount);
|
|
991 return false;
|
|
992 }
|
|
993
|
|
994 bool Reader::addErrorAndRecover(const String& message,
|
|
995 Token& token,
|
|
996 TokenType skipUntilToken) {
|
|
997 addError(message, token);
|
|
998 return recoverFromError(skipUntilToken);
|
|
999 }
|
|
1000
|
|
1001 Value& Reader::currentValue() { return *(nodes_.top()); }
|
|
1002
|
|
1003 Reader::Char Reader::getNextChar() {
|
|
1004 if (current_ == end_)
|
|
1005 return 0;
|
|
1006 return *current_++;
|
|
1007 }
|
|
1008
|
|
1009 void Reader::getLocationLineAndColumn(Location location,
|
|
1010 int& line,
|
|
1011 int& column) const {
|
|
1012 Location current = begin_;
|
|
1013 Location lastLineStart = current;
|
|
1014 line = 0;
|
|
1015 while (current < location && current != end_) {
|
|
1016 Char c = *current++;
|
|
1017 if (c == '\r') {
|
|
1018 if (*current == '\n')
|
|
1019 ++current;
|
|
1020 lastLineStart = current;
|
|
1021 ++line;
|
|
1022 } else if (c == '\n') {
|
|
1023 lastLineStart = current;
|
|
1024 ++line;
|
|
1025 }
|
|
1026 }
|
|
1027 // column & line start at 1
|
|
1028 column = int(location - lastLineStart) + 1;
|
|
1029 ++line;
|
|
1030 }
|
|
1031
|
|
1032 String Reader::getLocationLineAndColumn(Location location) const {
|
|
1033 int line, column;
|
|
1034 getLocationLineAndColumn(location, line, column);
|
|
1035 char buffer[18 + 16 + 16 + 1];
|
|
1036 jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
|
|
1037 return buffer;
|
|
1038 }
|
|
1039
|
|
1040 // Deprecated. Preserved for backward compatibility
|
|
1041 String Reader::getFormatedErrorMessages() const {
|
|
1042 return getFormattedErrorMessages();
|
|
1043 }
|
|
1044
|
|
1045 String Reader::getFormattedErrorMessages() const {
|
|
1046 String formattedMessage;
|
|
1047 for (const auto& error : errors_) {
|
|
1048 formattedMessage +=
|
|
1049 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
|
|
1050 formattedMessage += " " + error.message_ + "\n";
|
|
1051 if (error.extra_)
|
|
1052 formattedMessage +=
|
|
1053 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
|
|
1054 }
|
|
1055 return formattedMessage;
|
|
1056 }
|
|
1057
|
|
1058 std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
|
|
1059 std::vector<Reader::StructuredError> allErrors;
|
|
1060 for (const auto& error : errors_) {
|
|
1061 Reader::StructuredError structured;
|
|
1062 structured.offset_start = error.token_.start_ - begin_;
|
|
1063 structured.offset_limit = error.token_.end_ - begin_;
|
|
1064 structured.message = error.message_;
|
|
1065 allErrors.push_back(structured);
|
|
1066 }
|
|
1067 return allErrors;
|
|
1068 }
|
|
1069
|
|
1070 bool Reader::pushError(const Value& value, const String& message) {
|
|
1071 ptrdiff_t const length = end_ - begin_;
|
|
1072 if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
|
|
1073 return false;
|
|
1074 Token token;
|
|
1075 token.type_ = tokenError;
|
|
1076 token.start_ = begin_ + value.getOffsetStart();
|
|
1077 token.end_ = end_ + value.getOffsetLimit();
|
|
1078 ErrorInfo info;
|
|
1079 info.token_ = token;
|
|
1080 info.message_ = message;
|
|
1081 info.extra_ = nullptr;
|
|
1082 errors_.push_back(info);
|
|
1083 return true;
|
|
1084 }
|
|
1085
|
|
1086 bool Reader::pushError(const Value& value,
|
|
1087 const String& message,
|
|
1088 const Value& extra) {
|
|
1089 ptrdiff_t const length = end_ - begin_;
|
|
1090 if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
|
|
1091 extra.getOffsetLimit() > length)
|
|
1092 return false;
|
|
1093 Token token;
|
|
1094 token.type_ = tokenError;
|
|
1095 token.start_ = begin_ + value.getOffsetStart();
|
|
1096 token.end_ = begin_ + value.getOffsetLimit();
|
|
1097 ErrorInfo info;
|
|
1098 info.token_ = token;
|
|
1099 info.message_ = message;
|
|
1100 info.extra_ = begin_ + extra.getOffsetStart();
|
|
1101 errors_.push_back(info);
|
|
1102 return true;
|
|
1103 }
|
|
1104
|
|
1105 bool Reader::good() const { return errors_.empty(); }
|
|
1106
|
|
1107 // exact copy of Features
|
|
1108 class OurFeatures {
|
|
1109 public:
|
|
1110 static OurFeatures all();
|
|
1111 bool allowComments_;
|
|
1112 bool strictRoot_;
|
|
1113 bool allowDroppedNullPlaceholders_;
|
|
1114 bool allowNumericKeys_;
|
|
1115 bool allowSingleQuotes_;
|
|
1116 bool failIfExtra_;
|
|
1117 bool rejectDupKeys_;
|
|
1118 bool allowSpecialFloats_;
|
|
1119 size_t stackLimit_;
|
|
1120 }; // OurFeatures
|
|
1121
|
|
1122 // exact copy of Implementation of class Features
|
|
1123 // ////////////////////////////////
|
|
1124
|
|
1125 OurFeatures OurFeatures::all() { return {}; }
|
|
1126
|
|
1127 // Implementation of class Reader
|
|
1128 // ////////////////////////////////
|
|
1129
|
|
1130 // exact copy of Reader, renamed to OurReader
|
|
1131 class OurReader {
|
|
1132 public:
|
|
1133 typedef char Char;
|
|
1134 typedef const Char* Location;
|
|
1135 struct StructuredError {
|
|
1136 ptrdiff_t offset_start;
|
|
1137 ptrdiff_t offset_limit;
|
|
1138 String message;
|
|
1139 };
|
|
1140
|
|
1141 OurReader(OurFeatures const& features);
|
|
1142 bool parse(const char* beginDoc,
|
|
1143 const char* endDoc,
|
|
1144 Value& root,
|
|
1145 bool collectComments = true);
|
|
1146 String getFormattedErrorMessages() const;
|
|
1147 std::vector<StructuredError> getStructuredErrors() const;
|
|
1148 bool pushError(const Value& value, const String& message);
|
|
1149 bool pushError(const Value& value, const String& message, const Value& extra);
|
|
1150 bool good() const;
|
|
1151
|
|
1152 private:
|
|
1153 OurReader(OurReader const&); // no impl
|
|
1154 void operator=(OurReader const&); // no impl
|
|
1155
|
|
1156 enum TokenType {
|
|
1157 tokenEndOfStream = 0,
|
|
1158 tokenObjectBegin,
|
|
1159 tokenObjectEnd,
|
|
1160 tokenArrayBegin,
|
|
1161 tokenArrayEnd,
|
|
1162 tokenString,
|
|
1163 tokenNumber,
|
|
1164 tokenTrue,
|
|
1165 tokenFalse,
|
|
1166 tokenNull,
|
|
1167 tokenNaN,
|
|
1168 tokenPosInf,
|
|
1169 tokenNegInf,
|
|
1170 tokenArraySeparator,
|
|
1171 tokenMemberSeparator,
|
|
1172 tokenComment,
|
|
1173 tokenError
|
|
1174 };
|
|
1175
|
|
1176 class Token {
|
|
1177 public:
|
|
1178 TokenType type_;
|
|
1179 Location start_;
|
|
1180 Location end_;
|
|
1181 };
|
|
1182
|
|
1183 class ErrorInfo {
|
|
1184 public:
|
|
1185 Token token_;
|
|
1186 String message_;
|
|
1187 Location extra_;
|
|
1188 };
|
|
1189
|
|
1190 typedef std::deque<ErrorInfo> Errors;
|
|
1191
|
|
1192 bool readToken(Token& token);
|
|
1193 void skipSpaces();
|
|
1194 bool match(Location pattern, int patternLength);
|
|
1195 bool readComment();
|
|
1196 bool readCStyleComment();
|
|
1197 bool readCppStyleComment();
|
|
1198 bool readString();
|
|
1199 bool readStringSingleQuote();
|
|
1200 bool readNumber(bool checkInf);
|
|
1201 bool readValue();
|
|
1202 bool readObject(Token& token);
|
|
1203 bool readArray(Token& token);
|
|
1204 bool decodeNumber(Token& token);
|
|
1205 bool decodeNumber(Token& token, Value& decoded);
|
|
1206 bool decodeString(Token& token);
|
|
1207 bool decodeString(Token& token, String& decoded);
|
|
1208 bool decodeDouble(Token& token);
|
|
1209 bool decodeDouble(Token& token, Value& decoded);
|
|
1210 bool decodeUnicodeCodePoint(Token& token,
|
|
1211 Location& current,
|
|
1212 Location end,
|
|
1213 unsigned int& unicode);
|
|
1214 bool decodeUnicodeEscapeSequence(Token& token,
|
|
1215 Location& current,
|
|
1216 Location end,
|
|
1217 unsigned int& unicode);
|
|
1218 bool addError(const String& message, Token& token, Location extra = nullptr);
|
|
1219 bool recoverFromError(TokenType skipUntilToken);
|
|
1220 bool addErrorAndRecover(const String& message,
|
|
1221 Token& token,
|
|
1222 TokenType skipUntilToken);
|
|
1223 void skipUntilSpace();
|
|
1224 Value& currentValue();
|
|
1225 Char getNextChar();
|
|
1226 void
|
|
1227 getLocationLineAndColumn(Location location, int& line, int& column) const;
|
|
1228 String getLocationLineAndColumn(Location location) const;
|
|
1229 void addComment(Location begin, Location end, CommentPlacement placement);
|
|
1230 void skipCommentTokens(Token& token);
|
|
1231
|
|
1232 static String normalizeEOL(Location begin, Location end);
|
|
1233 static bool containsNewLine(Location begin, Location end);
|
|
1234
|
|
1235 typedef std::stack<Value*> Nodes;
|
|
1236 Nodes nodes_;
|
|
1237 Errors errors_;
|
|
1238 String document_;
|
|
1239 Location begin_;
|
|
1240 Location end_;
|
|
1241 Location current_;
|
|
1242 Location lastValueEnd_;
|
|
1243 Value* lastValue_;
|
|
1244 String commentsBefore_;
|
|
1245
|
|
1246 OurFeatures const features_;
|
|
1247 bool collectComments_;
|
|
1248 }; // OurReader
|
|
1249
|
|
1250 // complete copy of Read impl, for OurReader
|
|
1251
|
|
1252 bool OurReader::containsNewLine(OurReader::Location begin,
|
|
1253 OurReader::Location end) {
|
|
1254 for (; begin < end; ++begin)
|
|
1255 if (*begin == '\n' || *begin == '\r')
|
|
1256 return true;
|
|
1257 return false;
|
|
1258 }
|
|
1259
|
|
1260 OurReader::OurReader(OurFeatures const& features)
|
|
1261 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
|
|
1262 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
|
|
1263 }
|
|
1264
|
|
1265 bool OurReader::parse(const char* beginDoc,
|
|
1266 const char* endDoc,
|
|
1267 Value& root,
|
|
1268 bool collectComments) {
|
|
1269 if (!features_.allowComments_) {
|
|
1270 collectComments = false;
|
|
1271 }
|
|
1272
|
|
1273 begin_ = beginDoc;
|
|
1274 end_ = endDoc;
|
|
1275 collectComments_ = collectComments;
|
|
1276 current_ = begin_;
|
|
1277 lastValueEnd_ = nullptr;
|
|
1278 lastValue_ = nullptr;
|
|
1279 commentsBefore_.clear();
|
|
1280 errors_.clear();
|
|
1281 while (!nodes_.empty())
|
|
1282 nodes_.pop();
|
|
1283 nodes_.push(&root);
|
|
1284
|
|
1285 bool successful = readValue();
|
|
1286 Token token;
|
|
1287 skipCommentTokens(token);
|
|
1288 if (features_.failIfExtra_) {
|
|
1289 if ((features_.strictRoot_ || token.type_ != tokenError) &&
|
|
1290 token.type_ != tokenEndOfStream) {
|
|
1291 addError("Extra non-whitespace after JSON value.", token);
|
|
1292 return false;
|
|
1293 }
|
|
1294 }
|
|
1295 if (collectComments_ && !commentsBefore_.empty())
|
|
1296 root.setComment(commentsBefore_, commentAfter);
|
|
1297 if (features_.strictRoot_) {
|
|
1298 if (!root.isArray() && !root.isObject()) {
|
|
1299 // Set error location to start of doc, ideally should be first token found
|
|
1300 // in doc
|
|
1301 token.type_ = tokenError;
|
|
1302 token.start_ = beginDoc;
|
|
1303 token.end_ = endDoc;
|
|
1304 addError(
|
|
1305 "A valid JSON document must be either an array or an object value.",
|
|
1306 token);
|
|
1307 return false;
|
|
1308 }
|
|
1309 }
|
|
1310 return successful;
|
|
1311 }
|
|
1312
|
|
1313 bool OurReader::readValue() {
|
|
1314 // To preserve the old behaviour we cast size_t to int.
|
|
1315 if (nodes_.size() > features_.stackLimit_)
|
|
1316 throwRuntimeError("Exceeded stackLimit in readValue().");
|
|
1317 Token token;
|
|
1318 skipCommentTokens(token);
|
|
1319 bool successful = true;
|
|
1320
|
|
1321 if (collectComments_ && !commentsBefore_.empty()) {
|
|
1322 currentValue().setComment(commentsBefore_, commentBefore);
|
|
1323 commentsBefore_.clear();
|
|
1324 }
|
|
1325
|
|
1326 switch (token.type_) {
|
|
1327 case tokenObjectBegin:
|
|
1328 successful = readObject(token);
|
|
1329 currentValue().setOffsetLimit(current_ - begin_);
|
|
1330 break;
|
|
1331 case tokenArrayBegin:
|
|
1332 successful = readArray(token);
|
|
1333 currentValue().setOffsetLimit(current_ - begin_);
|
|
1334 break;
|
|
1335 case tokenNumber:
|
|
1336 successful = decodeNumber(token);
|
|
1337 break;
|
|
1338 case tokenString:
|
|
1339 successful = decodeString(token);
|
|
1340 break;
|
|
1341 case tokenTrue: {
|
|
1342 Value v(true);
|
|
1343 currentValue().swapPayload(v);
|
|
1344 currentValue().setOffsetStart(token.start_ - begin_);
|
|
1345 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
1346 } break;
|
|
1347 case tokenFalse: {
|
|
1348 Value v(false);
|
|
1349 currentValue().swapPayload(v);
|
|
1350 currentValue().setOffsetStart(token.start_ - begin_);
|
|
1351 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
1352 } break;
|
|
1353 case tokenNull: {
|
|
1354 Value v;
|
|
1355 currentValue().swapPayload(v);
|
|
1356 currentValue().setOffsetStart(token.start_ - begin_);
|
|
1357 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
1358 } break;
|
|
1359 case tokenNaN: {
|
|
1360 Value v(std::numeric_limits<double>::quiet_NaN());
|
|
1361 currentValue().swapPayload(v);
|
|
1362 currentValue().setOffsetStart(token.start_ - begin_);
|
|
1363 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
1364 } break;
|
|
1365 case tokenPosInf: {
|
|
1366 Value v(std::numeric_limits<double>::infinity());
|
|
1367 currentValue().swapPayload(v);
|
|
1368 currentValue().setOffsetStart(token.start_ - begin_);
|
|
1369 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
1370 } break;
|
|
1371 case tokenNegInf: {
|
|
1372 Value v(-std::numeric_limits<double>::infinity());
|
|
1373 currentValue().swapPayload(v);
|
|
1374 currentValue().setOffsetStart(token.start_ - begin_);
|
|
1375 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
1376 } break;
|
|
1377 case tokenArraySeparator:
|
|
1378 case tokenObjectEnd:
|
|
1379 case tokenArrayEnd:
|
|
1380 if (features_.allowDroppedNullPlaceholders_) {
|
|
1381 // "Un-read" the current token and mark the current value as a null
|
|
1382 // token.
|
|
1383 current_--;
|
|
1384 Value v;
|
|
1385 currentValue().swapPayload(v);
|
|
1386 currentValue().setOffsetStart(current_ - begin_ - 1);
|
|
1387 currentValue().setOffsetLimit(current_ - begin_);
|
|
1388 break;
|
|
1389 } // else, fall through ...
|
|
1390 default:
|
|
1391 currentValue().setOffsetStart(token.start_ - begin_);
|
|
1392 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
1393 return addError("Syntax error: value, object or array expected.", token);
|
|
1394 }
|
|
1395
|
|
1396 if (collectComments_) {
|
|
1397 lastValueEnd_ = current_;
|
|
1398 lastValue_ = ¤tValue();
|
|
1399 }
|
|
1400
|
|
1401 return successful;
|
|
1402 }
|
|
1403
|
|
1404 void OurReader::skipCommentTokens(Token& token) {
|
|
1405 if (features_.allowComments_) {
|
|
1406 do {
|
|
1407 readToken(token);
|
|
1408 } while (token.type_ == tokenComment);
|
|
1409 } else {
|
|
1410 readToken(token);
|
|
1411 }
|
|
1412 }
|
|
1413
|
|
1414 bool OurReader::readToken(Token& token) {
|
|
1415 skipSpaces();
|
|
1416 token.start_ = current_;
|
|
1417 Char c = getNextChar();
|
|
1418 bool ok = true;
|
|
1419 switch (c) {
|
|
1420 case '{':
|
|
1421 token.type_ = tokenObjectBegin;
|
|
1422 break;
|
|
1423 case '}':
|
|
1424 token.type_ = tokenObjectEnd;
|
|
1425 break;
|
|
1426 case '[':
|
|
1427 token.type_ = tokenArrayBegin;
|
|
1428 break;
|
|
1429 case ']':
|
|
1430 token.type_ = tokenArrayEnd;
|
|
1431 break;
|
|
1432 case '"':
|
|
1433 token.type_ = tokenString;
|
|
1434 ok = readString();
|
|
1435 break;
|
|
1436 case '\'':
|
|
1437 if (features_.allowSingleQuotes_) {
|
|
1438 token.type_ = tokenString;
|
|
1439 ok = readStringSingleQuote();
|
|
1440 break;
|
|
1441 } // else fall through
|
|
1442 case '/':
|
|
1443 token.type_ = tokenComment;
|
|
1444 ok = readComment();
|
|
1445 break;
|
|
1446 case '0':
|
|
1447 case '1':
|
|
1448 case '2':
|
|
1449 case '3':
|
|
1450 case '4':
|
|
1451 case '5':
|
|
1452 case '6':
|
|
1453 case '7':
|
|
1454 case '8':
|
|
1455 case '9':
|
|
1456 token.type_ = tokenNumber;
|
|
1457 readNumber(false);
|
|
1458 break;
|
|
1459 case '-':
|
|
1460 if (readNumber(true)) {
|
|
1461 token.type_ = tokenNumber;
|
|
1462 } else {
|
|
1463 token.type_ = tokenNegInf;
|
|
1464 ok = features_.allowSpecialFloats_ && match("nfinity", 7);
|
|
1465 }
|
|
1466 break;
|
|
1467 case 't':
|
|
1468 token.type_ = tokenTrue;
|
|
1469 ok = match("rue", 3);
|
|
1470 break;
|
|
1471 case 'f':
|
|
1472 token.type_ = tokenFalse;
|
|
1473 ok = match("alse", 4);
|
|
1474 break;
|
|
1475 case 'n':
|
|
1476 token.type_ = tokenNull;
|
|
1477 ok = match("ull", 3);
|
|
1478 break;
|
|
1479 case 'N':
|
|
1480 if (features_.allowSpecialFloats_) {
|
|
1481 token.type_ = tokenNaN;
|
|
1482 ok = match("aN", 2);
|
|
1483 } else {
|
|
1484 ok = false;
|
|
1485 }
|
|
1486 break;
|
|
1487 case 'I':
|
|
1488 if (features_.allowSpecialFloats_) {
|
|
1489 token.type_ = tokenPosInf;
|
|
1490 ok = match("nfinity", 7);
|
|
1491 } else {
|
|
1492 ok = false;
|
|
1493 }
|
|
1494 break;
|
|
1495 case ',':
|
|
1496 token.type_ = tokenArraySeparator;
|
|
1497 break;
|
|
1498 case ':':
|
|
1499 token.type_ = tokenMemberSeparator;
|
|
1500 break;
|
|
1501 case 0:
|
|
1502 token.type_ = tokenEndOfStream;
|
|
1503 break;
|
|
1504 default:
|
|
1505 ok = false;
|
|
1506 break;
|
|
1507 }
|
|
1508 if (!ok)
|
|
1509 token.type_ = tokenError;
|
|
1510 token.end_ = current_;
|
|
1511 return true;
|
|
1512 }
|
|
1513
|
|
1514 void OurReader::skipSpaces() {
|
|
1515 while (current_ != end_) {
|
|
1516 Char c = *current_;
|
|
1517 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
|
|
1518 ++current_;
|
|
1519 else
|
|
1520 break;
|
|
1521 }
|
|
1522 }
|
|
1523
|
|
1524 bool OurReader::match(Location pattern, int patternLength) {
|
|
1525 if (end_ - current_ < patternLength)
|
|
1526 return false;
|
|
1527 int index = patternLength;
|
|
1528 while (index--)
|
|
1529 if (current_[index] != pattern[index])
|
|
1530 return false;
|
|
1531 current_ += patternLength;
|
|
1532 return true;
|
|
1533 }
|
|
1534
|
|
1535 bool OurReader::readComment() {
|
|
1536 Location commentBegin = current_ - 1;
|
|
1537 Char c = getNextChar();
|
|
1538 bool successful = false;
|
|
1539 if (c == '*')
|
|
1540 successful = readCStyleComment();
|
|
1541 else if (c == '/')
|
|
1542 successful = readCppStyleComment();
|
|
1543 if (!successful)
|
|
1544 return false;
|
|
1545
|
|
1546 if (collectComments_) {
|
|
1547 CommentPlacement placement = commentBefore;
|
|
1548 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
|
|
1549 if (c != '*' || !containsNewLine(commentBegin, current_))
|
|
1550 placement = commentAfterOnSameLine;
|
|
1551 }
|
|
1552
|
|
1553 addComment(commentBegin, current_, placement);
|
|
1554 }
|
|
1555 return true;
|
|
1556 }
|
|
1557
|
|
1558 String OurReader::normalizeEOL(OurReader::Location begin,
|
|
1559 OurReader::Location end) {
|
|
1560 String normalized;
|
|
1561 normalized.reserve(static_cast<size_t>(end - begin));
|
|
1562 OurReader::Location current = begin;
|
|
1563 while (current != end) {
|
|
1564 char c = *current++;
|
|
1565 if (c == '\r') {
|
|
1566 if (current != end && *current == '\n')
|
|
1567 // convert dos EOL
|
|
1568 ++current;
|
|
1569 // convert Mac EOL
|
|
1570 normalized += '\n';
|
|
1571 } else {
|
|
1572 normalized += c;
|
|
1573 }
|
|
1574 }
|
|
1575 return normalized;
|
|
1576 }
|
|
1577
|
|
1578 void OurReader::addComment(Location begin,
|
|
1579 Location end,
|
|
1580 CommentPlacement placement) {
|
|
1581 assert(collectComments_);
|
|
1582 const String& normalized = normalizeEOL(begin, end);
|
|
1583 if (placement == commentAfterOnSameLine) {
|
|
1584 assert(lastValue_ != nullptr);
|
|
1585 lastValue_->setComment(normalized, placement);
|
|
1586 } else {
|
|
1587 commentsBefore_ += normalized;
|
|
1588 }
|
|
1589 }
|
|
1590
|
|
1591 bool OurReader::readCStyleComment() {
|
|
1592 while ((current_ + 1) < end_) {
|
|
1593 Char c = getNextChar();
|
|
1594 if (c == '*' && *current_ == '/')
|
|
1595 break;
|
|
1596 }
|
|
1597 return getNextChar() == '/';
|
|
1598 }
|
|
1599
|
|
1600 bool OurReader::readCppStyleComment() {
|
|
1601 while (current_ != end_) {
|
|
1602 Char c = getNextChar();
|
|
1603 if (c == '\n')
|
|
1604 break;
|
|
1605 if (c == '\r') {
|
|
1606 // Consume DOS EOL. It will be normalized in addComment.
|
|
1607 if (current_ != end_ && *current_ == '\n')
|
|
1608 getNextChar();
|
|
1609 // Break on Moc OS 9 EOL.
|
|
1610 break;
|
|
1611 }
|
|
1612 }
|
|
1613 return true;
|
|
1614 }
|
|
1615
|
|
1616 bool OurReader::readNumber(bool checkInf) {
|
|
1617 const char* p = current_;
|
|
1618 if (checkInf && p != end_ && *p == 'I') {
|
|
1619 current_ = ++p;
|
|
1620 return false;
|
|
1621 }
|
|
1622 char c = '0'; // stopgap for already consumed character
|
|
1623 // integral part
|
|
1624 while (c >= '0' && c <= '9')
|
|
1625 c = (current_ = p) < end_ ? *p++ : '\0';
|
|
1626 // fractional part
|
|
1627 if (c == '.') {
|
|
1628 c = (current_ = p) < end_ ? *p++ : '\0';
|
|
1629 while (c >= '0' && c <= '9')
|
|
1630 c = (current_ = p) < end_ ? *p++ : '\0';
|
|
1631 }
|
|
1632 // exponential part
|
|
1633 if (c == 'e' || c == 'E') {
|
|
1634 c = (current_ = p) < end_ ? *p++ : '\0';
|
|
1635 if (c == '+' || c == '-')
|
|
1636 c = (current_ = p) < end_ ? *p++ : '\0';
|
|
1637 while (c >= '0' && c <= '9')
|
|
1638 c = (current_ = p) < end_ ? *p++ : '\0';
|
|
1639 }
|
|
1640 return true;
|
|
1641 }
|
|
1642 bool OurReader::readString() {
|
|
1643 Char c = 0;
|
|
1644 while (current_ != end_) {
|
|
1645 c = getNextChar();
|
|
1646 if (c == '\\')
|
|
1647 getNextChar();
|
|
1648 else if (c == '"')
|
|
1649 break;
|
|
1650 }
|
|
1651 return c == '"';
|
|
1652 }
|
|
1653
|
|
1654 bool OurReader::readStringSingleQuote() {
|
|
1655 Char c = 0;
|
|
1656 while (current_ != end_) {
|
|
1657 c = getNextChar();
|
|
1658 if (c == '\\')
|
|
1659 getNextChar();
|
|
1660 else if (c == '\'')
|
|
1661 break;
|
|
1662 }
|
|
1663 return c == '\'';
|
|
1664 }
|
|
1665
|
|
1666 bool OurReader::readObject(Token& token) {
|
|
1667 Token tokenName;
|
|
1668 String name;
|
|
1669 Value init(objectValue);
|
|
1670 currentValue().swapPayload(init);
|
|
1671 currentValue().setOffsetStart(token.start_ - begin_);
|
|
1672 while (readToken(tokenName)) {
|
|
1673 bool initialTokenOk = true;
|
|
1674 while (tokenName.type_ == tokenComment && initialTokenOk)
|
|
1675 initialTokenOk = readToken(tokenName);
|
|
1676 if (!initialTokenOk)
|
|
1677 break;
|
|
1678 if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
|
|
1679 return true;
|
|
1680 name.clear();
|
|
1681 if (tokenName.type_ == tokenString) {
|
|
1682 if (!decodeString(tokenName, name))
|
|
1683 return recoverFromError(tokenObjectEnd);
|
|
1684 } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
|
|
1685 Value numberName;
|
|
1686 if (!decodeNumber(tokenName, numberName))
|
|
1687 return recoverFromError(tokenObjectEnd);
|
|
1688 name = numberName.asString();
|
|
1689 } else {
|
|
1690 break;
|
|
1691 }
|
|
1692
|
|
1693 Token colon;
|
|
1694 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
|
|
1695 return addErrorAndRecover("Missing ':' after object member name", colon,
|
|
1696 tokenObjectEnd);
|
|
1697 }
|
|
1698 if (name.length() >= (1U << 30))
|
|
1699 throwRuntimeError("keylength >= 2^30");
|
|
1700 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
|
|
1701 String msg = "Duplicate key: '" + name + "'";
|
|
1702 return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
|
|
1703 }
|
|
1704 Value& value = currentValue()[name];
|
|
1705 nodes_.push(&value);
|
|
1706 bool ok = readValue();
|
|
1707 nodes_.pop();
|
|
1708 if (!ok) // error already set
|
|
1709 return recoverFromError(tokenObjectEnd);
|
|
1710
|
|
1711 Token comma;
|
|
1712 if (!readToken(comma) ||
|
|
1713 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
|
|
1714 comma.type_ != tokenComment)) {
|
|
1715 return addErrorAndRecover("Missing ',' or '}' in object declaration",
|
|
1716 comma, tokenObjectEnd);
|
|
1717 }
|
|
1718 bool finalizeTokenOk = true;
|
|
1719 while (comma.type_ == tokenComment && finalizeTokenOk)
|
|
1720 finalizeTokenOk = readToken(comma);
|
|
1721 if (comma.type_ == tokenObjectEnd)
|
|
1722 return true;
|
|
1723 }
|
|
1724 return addErrorAndRecover("Missing '}' or object member name", tokenName,
|
|
1725 tokenObjectEnd);
|
|
1726 }
|
|
1727
|
|
1728 bool OurReader::readArray(Token& token) {
|
|
1729 Value init(arrayValue);
|
|
1730 currentValue().swapPayload(init);
|
|
1731 currentValue().setOffsetStart(token.start_ - begin_);
|
|
1732 skipSpaces();
|
|
1733 if (current_ != end_ && *current_ == ']') // empty array
|
|
1734 {
|
|
1735 Token endArray;
|
|
1736 readToken(endArray);
|
|
1737 return true;
|
|
1738 }
|
|
1739 int index = 0;
|
|
1740 for (;;) {
|
|
1741 Value& value = currentValue()[index++];
|
|
1742 nodes_.push(&value);
|
|
1743 bool ok = readValue();
|
|
1744 nodes_.pop();
|
|
1745 if (!ok) // error already set
|
|
1746 return recoverFromError(tokenArrayEnd);
|
|
1747
|
|
1748 Token currentToken;
|
|
1749 // Accept Comment after last item in the array.
|
|
1750 ok = readToken(currentToken);
|
|
1751 while (currentToken.type_ == tokenComment && ok) {
|
|
1752 ok = readToken(currentToken);
|
|
1753 }
|
|
1754 bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
|
|
1755 currentToken.type_ != tokenArrayEnd);
|
|
1756 if (!ok || badTokenType) {
|
|
1757 return addErrorAndRecover("Missing ',' or ']' in array declaration",
|
|
1758 currentToken, tokenArrayEnd);
|
|
1759 }
|
|
1760 if (currentToken.type_ == tokenArrayEnd)
|
|
1761 break;
|
|
1762 }
|
|
1763 return true;
|
|
1764 }
|
|
1765
|
|
1766 bool OurReader::decodeNumber(Token& token) {
|
|
1767 Value decoded;
|
|
1768 if (!decodeNumber(token, decoded))
|
|
1769 return false;
|
|
1770 currentValue().swapPayload(decoded);
|
|
1771 currentValue().setOffsetStart(token.start_ - begin_);
|
|
1772 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
1773 return true;
|
|
1774 }
|
|
1775
|
|
1776 bool OurReader::decodeNumber(Token& token, Value& decoded) {
|
|
1777 // Attempts to parse the number as an integer. If the number is
|
|
1778 // larger than the maximum supported value of an integer then
|
|
1779 // we decode the number as a double.
|
|
1780 Location current = token.start_;
|
|
1781 bool isNegative = *current == '-';
|
|
1782 if (isNegative)
|
|
1783 ++current;
|
|
1784 // TODO: Help the compiler do the div and mod at compile time or get rid of
|
|
1785 // them.
|
|
1786 Value::LargestUInt maxIntegerValue =
|
|
1787 isNegative ? Value::LargestUInt(Value::minLargestInt)
|
|
1788 : Value::maxLargestUInt;
|
|
1789 Value::LargestUInt threshold = maxIntegerValue / 10;
|
|
1790 Value::LargestUInt value = 0;
|
|
1791 while (current < token.end_) {
|
|
1792 Char c = *current++;
|
|
1793 if (c < '0' || c > '9')
|
|
1794 return decodeDouble(token, decoded);
|
|
1795 auto digit(static_cast<Value::UInt>(c - '0'));
|
|
1796 if (value >= threshold) {
|
|
1797 // We've hit or exceeded the max value divided by 10 (rounded down). If
|
|
1798 // a) we've only just touched the limit, b) this is the last digit, and
|
|
1799 // c) it's small enough to fit in that rounding delta, we're okay.
|
|
1800 // Otherwise treat this number as a double to avoid overflow.
|
|
1801 if (value > threshold || current != token.end_ ||
|
|
1802 digit > maxIntegerValue % 10) {
|
|
1803 return decodeDouble(token, decoded);
|
|
1804 }
|
|
1805 }
|
|
1806 value = value * 10 + digit;
|
|
1807 }
|
|
1808 if (isNegative)
|
|
1809 decoded = -Value::LargestInt(value);
|
|
1810 else if (value <= Value::LargestUInt(Value::maxInt))
|
|
1811 decoded = Value::LargestInt(value);
|
|
1812 else
|
|
1813 decoded = value;
|
|
1814 return true;
|
|
1815 }
|
|
1816
|
|
1817 bool OurReader::decodeDouble(Token& token) {
|
|
1818 Value decoded;
|
|
1819 if (!decodeDouble(token, decoded))
|
|
1820 return false;
|
|
1821 currentValue().swapPayload(decoded);
|
|
1822 currentValue().setOffsetStart(token.start_ - begin_);
|
|
1823 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
1824 return true;
|
|
1825 }
|
|
1826
|
|
1827 bool OurReader::decodeDouble(Token& token, Value& decoded) {
|
|
1828 double value = 0;
|
|
1829 const int bufferSize = 32;
|
|
1830 int count;
|
|
1831 ptrdiff_t const length = token.end_ - token.start_;
|
|
1832
|
|
1833 // Sanity check to avoid buffer overflow exploits.
|
|
1834 if (length < 0) {
|
|
1835 return addError("Unable to parse token length", token);
|
|
1836 }
|
|
1837 auto const ulength = static_cast<size_t>(length);
|
|
1838
|
|
1839 // Avoid using a string constant for the format control string given to
|
|
1840 // sscanf, as this can cause hard to debug crashes on OS X. See here for more
|
|
1841 // info:
|
|
1842 //
|
|
1843 // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
|
|
1844 char format[] = "%lf";
|
|
1845
|
|
1846 if (length <= bufferSize) {
|
|
1847 Char buffer[bufferSize + 1];
|
|
1848 memcpy(buffer, token.start_, ulength);
|
|
1849 buffer[length] = 0;
|
|
1850 fixNumericLocaleInput(buffer, buffer + length);
|
|
1851 count = sscanf(buffer, format, &value);
|
|
1852 } else {
|
|
1853 String buffer(token.start_, token.end_);
|
|
1854 count = sscanf(buffer.c_str(), format, &value);
|
|
1855 }
|
|
1856
|
|
1857 if (count != 1)
|
|
1858 return addError(
|
|
1859 "'" + String(token.start_, token.end_) + "' is not a number.", token);
|
|
1860 decoded = value;
|
|
1861 return true;
|
|
1862 }
|
|
1863
|
|
1864 bool OurReader::decodeString(Token& token) {
|
|
1865 String decoded_string;
|
|
1866 if (!decodeString(token, decoded_string))
|
|
1867 return false;
|
|
1868 Value decoded(decoded_string);
|
|
1869 currentValue().swapPayload(decoded);
|
|
1870 currentValue().setOffsetStart(token.start_ - begin_);
|
|
1871 currentValue().setOffsetLimit(token.end_ - begin_);
|
|
1872 return true;
|
|
1873 }
|
|
1874
|
|
1875 bool OurReader::decodeString(Token& token, String& decoded) {
|
|
1876 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
|
|
1877 Location current = token.start_ + 1; // skip '"'
|
|
1878 Location end = token.end_ - 1; // do not include '"'
|
|
1879 while (current != end) {
|
|
1880 Char c = *current++;
|
|
1881 if (c == '"')
|
|
1882 break;
|
|
1883 else if (c == '\\') {
|
|
1884 if (current == end)
|
|
1885 return addError("Empty escape sequence in string", token, current);
|
|
1886 Char escape = *current++;
|
|
1887 switch (escape) {
|
|
1888 case '"':
|
|
1889 decoded += '"';
|
|
1890 break;
|
|
1891 case '/':
|
|
1892 decoded += '/';
|
|
1893 break;
|
|
1894 case '\\':
|
|
1895 decoded += '\\';
|
|
1896 break;
|
|
1897 case 'b':
|
|
1898 decoded += '\b';
|
|
1899 break;
|
|
1900 case 'f':
|
|
1901 decoded += '\f';
|
|
1902 break;
|
|
1903 case 'n':
|
|
1904 decoded += '\n';
|
|
1905 break;
|
|
1906 case 'r':
|
|
1907 decoded += '\r';
|
|
1908 break;
|
|
1909 case 't':
|
|
1910 decoded += '\t';
|
|
1911 break;
|
|
1912 case 'u': {
|
|
1913 unsigned int unicode;
|
|
1914 if (!decodeUnicodeCodePoint(token, current, end, unicode))
|
|
1915 return false;
|
|
1916 decoded += codePointToUTF8(unicode);
|
|
1917 } break;
|
|
1918 default:
|
|
1919 return addError("Bad escape sequence in string", token, current);
|
|
1920 }
|
|
1921 } else {
|
|
1922 decoded += c;
|
|
1923 }
|
|
1924 }
|
|
1925 return true;
|
|
1926 }
|
|
1927
|
|
1928 bool OurReader::decodeUnicodeCodePoint(Token& token,
|
|
1929 Location& current,
|
|
1930 Location end,
|
|
1931 unsigned int& unicode) {
|
|
1932
|
|
1933 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
|
|
1934 return false;
|
|
1935 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
|
|
1936 // surrogate pairs
|
|
1937 if (end - current < 6)
|
|
1938 return addError(
|
|
1939 "additional six characters expected to parse unicode surrogate pair.",
|
|
1940 token, current);
|
|
1941 if (*(current++) == '\\' && *(current++) == 'u') {
|
|
1942 unsigned int surrogatePair;
|
|
1943 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
|
|
1944 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
|
|
1945 } else
|
|
1946 return false;
|
|
1947 } else
|
|
1948 return addError("expecting another \\u token to begin the second half of "
|
|
1949 "a unicode surrogate pair",
|
|
1950 token, current);
|
|
1951 }
|
|
1952 return true;
|
|
1953 }
|
|
1954
|
|
1955 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
|
|
1956 Location& current,
|
|
1957 Location end,
|
|
1958 unsigned int& ret_unicode) {
|
|
1959 if (end - current < 4)
|
|
1960 return addError(
|
|
1961 "Bad unicode escape sequence in string: four digits expected.", token,
|
|
1962 current);
|
|
1963 int unicode = 0;
|
|
1964 for (int index = 0; index < 4; ++index) {
|
|
1965 Char c = *current++;
|
|
1966 unicode *= 16;
|
|
1967 if (c >= '0' && c <= '9')
|
|
1968 unicode += c - '0';
|
|
1969 else if (c >= 'a' && c <= 'f')
|
|
1970 unicode += c - 'a' + 10;
|
|
1971 else if (c >= 'A' && c <= 'F')
|
|
1972 unicode += c - 'A' + 10;
|
|
1973 else
|
|
1974 return addError(
|
|
1975 "Bad unicode escape sequence in string: hexadecimal digit expected.",
|
|
1976 token, current);
|
|
1977 }
|
|
1978 ret_unicode = static_cast<unsigned int>(unicode);
|
|
1979 return true;
|
|
1980 }
|
|
1981
|
|
1982 bool OurReader::addError(const String& message, Token& token, Location extra) {
|
|
1983 ErrorInfo info;
|
|
1984 info.token_ = token;
|
|
1985 info.message_ = message;
|
|
1986 info.extra_ = extra;
|
|
1987 errors_.push_back(info);
|
|
1988 return false;
|
|
1989 }
|
|
1990
|
|
1991 bool OurReader::recoverFromError(TokenType skipUntilToken) {
|
|
1992 size_t errorCount = errors_.size();
|
|
1993 Token skip;
|
|
1994 for (;;) {
|
|
1995 if (!readToken(skip))
|
|
1996 errors_.resize(errorCount); // discard errors caused by recovery
|
|
1997 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
|
|
1998 break;
|
|
1999 }
|
|
2000 errors_.resize(errorCount);
|
|
2001 return false;
|
|
2002 }
|
|
2003
|
|
2004 bool OurReader::addErrorAndRecover(const String& message,
|
|
2005 Token& token,
|
|
2006 TokenType skipUntilToken) {
|
|
2007 addError(message, token);
|
|
2008 return recoverFromError(skipUntilToken);
|
|
2009 }
|
|
2010
|
|
2011 Value& OurReader::currentValue() { return *(nodes_.top()); }
|
|
2012
|
|
2013 OurReader::Char OurReader::getNextChar() {
|
|
2014 if (current_ == end_)
|
|
2015 return 0;
|
|
2016 return *current_++;
|
|
2017 }
|
|
2018
|
|
2019 void OurReader::getLocationLineAndColumn(Location location,
|
|
2020 int& line,
|
|
2021 int& column) const {
|
|
2022 Location current = begin_;
|
|
2023 Location lastLineStart = current;
|
|
2024 line = 0;
|
|
2025 while (current < location && current != end_) {
|
|
2026 Char c = *current++;
|
|
2027 if (c == '\r') {
|
|
2028 if (*current == '\n')
|
|
2029 ++current;
|
|
2030 lastLineStart = current;
|
|
2031 ++line;
|
|
2032 } else if (c == '\n') {
|
|
2033 lastLineStart = current;
|
|
2034 ++line;
|
|
2035 }
|
|
2036 }
|
|
2037 // column & line start at 1
|
|
2038 column = int(location - lastLineStart) + 1;
|
|
2039 ++line;
|
|
2040 }
|
|
2041
|
|
2042 String OurReader::getLocationLineAndColumn(Location location) const {
|
|
2043 int line, column;
|
|
2044 getLocationLineAndColumn(location, line, column);
|
|
2045 char buffer[18 + 16 + 16 + 1];
|
|
2046 jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
|
|
2047 return buffer;
|
|
2048 }
|
|
2049
|
|
2050 String OurReader::getFormattedErrorMessages() const {
|
|
2051 String formattedMessage;
|
|
2052 for (const auto& error : errors_) {
|
|
2053 formattedMessage +=
|
|
2054 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
|
|
2055 formattedMessage += " " + error.message_ + "\n";
|
|
2056 if (error.extra_)
|
|
2057 formattedMessage +=
|
|
2058 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
|
|
2059 }
|
|
2060 return formattedMessage;
|
|
2061 }
|
|
2062
|
|
2063 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
|
|
2064 std::vector<OurReader::StructuredError> allErrors;
|
|
2065 for (const auto& error : errors_) {
|
|
2066 OurReader::StructuredError structured;
|
|
2067 structured.offset_start = error.token_.start_ - begin_;
|
|
2068 structured.offset_limit = error.token_.end_ - begin_;
|
|
2069 structured.message = error.message_;
|
|
2070 allErrors.push_back(structured);
|
|
2071 }
|
|
2072 return allErrors;
|
|
2073 }
|
|
2074
|
|
2075 bool OurReader::pushError(const Value& value, const String& message) {
|
|
2076 ptrdiff_t length = end_ - begin_;
|
|
2077 if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
|
|
2078 return false;
|
|
2079 Token token;
|
|
2080 token.type_ = tokenError;
|
|
2081 token.start_ = begin_ + value.getOffsetStart();
|
|
2082 token.end_ = end_ + value.getOffsetLimit();
|
|
2083 ErrorInfo info;
|
|
2084 info.token_ = token;
|
|
2085 info.message_ = message;
|
|
2086 info.extra_ = nullptr;
|
|
2087 errors_.push_back(info);
|
|
2088 return true;
|
|
2089 }
|
|
2090
|
|
2091 bool OurReader::pushError(const Value& value,
|
|
2092 const String& message,
|
|
2093 const Value& extra) {
|
|
2094 ptrdiff_t length = end_ - begin_;
|
|
2095 if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
|
|
2096 extra.getOffsetLimit() > length)
|
|
2097 return false;
|
|
2098 Token token;
|
|
2099 token.type_ = tokenError;
|
|
2100 token.start_ = begin_ + value.getOffsetStart();
|
|
2101 token.end_ = begin_ + value.getOffsetLimit();
|
|
2102 ErrorInfo info;
|
|
2103 info.token_ = token;
|
|
2104 info.message_ = message;
|
|
2105 info.extra_ = begin_ + extra.getOffsetStart();
|
|
2106 errors_.push_back(info);
|
|
2107 return true;
|
|
2108 }
|
|
2109
|
|
2110 bool OurReader::good() const { return errors_.empty(); }
|
|
2111
|
|
2112 class OurCharReader : public CharReader {
|
|
2113 bool const collectComments_;
|
|
2114 OurReader reader_;
|
|
2115
|
|
2116 public:
|
|
2117 OurCharReader(bool collectComments, OurFeatures const& features)
|
|
2118 : collectComments_(collectComments), reader_(features) {}
|
|
2119 bool parse(char const* beginDoc,
|
|
2120 char const* endDoc,
|
|
2121 Value* root,
|
|
2122 String* errs) override {
|
|
2123 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
|
|
2124 if (errs) {
|
|
2125 *errs = reader_.getFormattedErrorMessages();
|
|
2126 }
|
|
2127 return ok;
|
|
2128 }
|
|
2129 };
|
|
2130
|
|
2131 CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
|
|
2132 CharReaderBuilder::~CharReaderBuilder() = default;
|
|
2133 CharReader* CharReaderBuilder::newCharReader() const {
|
|
2134 bool collectComments = settings_["collectComments"].asBool();
|
|
2135 OurFeatures features = OurFeatures::all();
|
|
2136 features.allowComments_ = settings_["allowComments"].asBool();
|
|
2137 features.strictRoot_ = settings_["strictRoot"].asBool();
|
|
2138 features.allowDroppedNullPlaceholders_ =
|
|
2139 settings_["allowDroppedNullPlaceholders"].asBool();
|
|
2140 features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
|
|
2141 features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
|
|
2142 #if defined(JSON_HAS_INT64)
|
|
2143 features.stackLimit_ = settings_["stackLimit"].asUInt64();
|
|
2144 #else
|
|
2145 features.stackLimit_ = settings_["stackLimit"].asUInt();
|
|
2146 #endif
|
|
2147 features.failIfExtra_ = settings_["failIfExtra"].asBool();
|
|
2148 features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
|
|
2149 features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
|
|
2150 return new OurCharReader(collectComments, features);
|
|
2151 }
|
|
2152 static void getValidReaderKeys(std::set<String>* valid_keys) {
|
|
2153 valid_keys->clear();
|
|
2154 valid_keys->insert("collectComments");
|
|
2155 valid_keys->insert("allowComments");
|
|
2156 valid_keys->insert("strictRoot");
|
|
2157 valid_keys->insert("allowDroppedNullPlaceholders");
|
|
2158 valid_keys->insert("allowNumericKeys");
|
|
2159 valid_keys->insert("allowSingleQuotes");
|
|
2160 valid_keys->insert("stackLimit");
|
|
2161 valid_keys->insert("failIfExtra");
|
|
2162 valid_keys->insert("rejectDupKeys");
|
|
2163 valid_keys->insert("allowSpecialFloats");
|
|
2164 }
|
|
2165 bool CharReaderBuilder::validate(Json::Value* invalid) const {
|
|
2166 Json::Value my_invalid;
|
|
2167 if (!invalid)
|
|
2168 invalid = &my_invalid; // so we do not need to test for NULL
|
|
2169 Json::Value& inv = *invalid;
|
|
2170 std::set<String> valid_keys;
|
|
2171 getValidReaderKeys(&valid_keys);
|
|
2172 Value::Members keys = settings_.getMemberNames();
|
|
2173 size_t n = keys.size();
|
|
2174 for (size_t i = 0; i < n; ++i) {
|
|
2175 String const& key = keys[i];
|
|
2176 if (valid_keys.find(key) == valid_keys.end()) {
|
|
2177 inv[key] = settings_[key];
|
|
2178 }
|
|
2179 }
|
|
2180 return inv.empty();
|
|
2181 }
|
|
2182 Value& CharReaderBuilder::operator[](const String& key) {
|
|
2183 return settings_[key];
|
|
2184 }
|
|
2185 // static
|
|
2186 void CharReaderBuilder::strictMode(Json::Value* settings) {
|
|
2187 //! [CharReaderBuilderStrictMode]
|
|
2188 (*settings)["allowComments"] = false;
|
|
2189 (*settings)["strictRoot"] = true;
|
|
2190 (*settings)["allowDroppedNullPlaceholders"] = false;
|
|
2191 (*settings)["allowNumericKeys"] = false;
|
|
2192 (*settings)["allowSingleQuotes"] = false;
|
|
2193 (*settings)["stackLimit"] = 1000;
|
|
2194 (*settings)["failIfExtra"] = true;
|
|
2195 (*settings)["rejectDupKeys"] = true;
|
|
2196 (*settings)["allowSpecialFloats"] = false;
|
|
2197 //! [CharReaderBuilderStrictMode]
|
|
2198 }
|
|
2199 // static
|
|
2200 void CharReaderBuilder::setDefaults(Json::Value* settings) {
|
|
2201 //! [CharReaderBuilderDefaults]
|
|
2202 (*settings)["collectComments"] = true;
|
|
2203 (*settings)["allowComments"] = true;
|
|
2204 (*settings)["strictRoot"] = false;
|
|
2205 (*settings)["allowDroppedNullPlaceholders"] = false;
|
|
2206 (*settings)["allowNumericKeys"] = false;
|
|
2207 (*settings)["allowSingleQuotes"] = false;
|
|
2208 (*settings)["stackLimit"] = 1000;
|
|
2209 (*settings)["failIfExtra"] = false;
|
|
2210 (*settings)["rejectDupKeys"] = false;
|
|
2211 (*settings)["allowSpecialFloats"] = false;
|
|
2212 //! [CharReaderBuilderDefaults]
|
|
2213 }
|
|
2214
|
|
2215 //////////////////////////////////
|
|
2216 // global functions
|
|
2217
|
|
2218 bool parseFromStream(CharReader::Factory const& fact,
|
|
2219 IStream& sin,
|
|
2220 Value* root,
|
|
2221 String* errs) {
|
|
2222 OStringStream ssin;
|
|
2223 ssin << sin.rdbuf();
|
|
2224 String doc = ssin.str();
|
|
2225 char const* begin = doc.data();
|
|
2226 char const* end = begin + doc.size();
|
|
2227 // Note that we do not actually need a null-terminator.
|
|
2228 CharReaderPtr const reader(fact.newCharReader());
|
|
2229 return reader->parse(begin, end, root, errs);
|
|
2230 }
|
|
2231
|
|
2232 IStream& operator>>(IStream& sin, Value& root) {
|
|
2233 CharReaderBuilder b;
|
|
2234 String errs;
|
|
2235 bool ok = parseFromStream(b, sin, &root, &errs);
|
|
2236 if (!ok) {
|
|
2237 throwRuntimeError(errs);
|
|
2238 }
|
|
2239 return sin;
|
|
2240 }
|
|
2241
|
|
2242 } // namespace Json
|
|
2243
|
|
2244 // //////////////////////////////////////////////////////////////////////
|
|
2245 // End of content of file: src/lib_json/json_reader.cpp
|
|
2246 // //////////////////////////////////////////////////////////////////////
|
|
2247
|
|
2248
|
|
2249
|
|
2250
|
|
2251
|
|
2252
|
|
2253 // //////////////////////////////////////////////////////////////////////
|
|
2254 // Beginning of content of file: src/lib_json/json_valueiterator.inl
|
|
2255 // //////////////////////////////////////////////////////////////////////
|
|
2256
|
|
2257 // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
|
2258 // Distributed under MIT license, or public domain if desired and
|
|
2259 // recognized in your jurisdiction.
|
|
2260 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
|
2261
|
|
2262 // included by json_value.cpp
|
|
2263
|
|
2264 namespace Json {
|
|
2265
|
|
2266 // //////////////////////////////////////////////////////////////////
|
|
2267 // //////////////////////////////////////////////////////////////////
|
|
2268 // //////////////////////////////////////////////////////////////////
|
|
2269 // class ValueIteratorBase
|
|
2270 // //////////////////////////////////////////////////////////////////
|
|
2271 // //////////////////////////////////////////////////////////////////
|
|
2272 // //////////////////////////////////////////////////////////////////
|
|
2273
|
|
2274 ValueIteratorBase::ValueIteratorBase() : current_() {}
|
|
2275
|
|
2276 ValueIteratorBase::ValueIteratorBase(
|
|
2277 const Value::ObjectValues::iterator& current)
|
|
2278 : current_(current), isNull_(false) {}
|
|
2279
|
|
2280 Value& ValueIteratorBase::deref() const { return current_->second; }
|
|
2281
|
|
2282 void ValueIteratorBase::increment() { ++current_; }
|
|
2283
|
|
2284 void ValueIteratorBase::decrement() { --current_; }
|
|
2285
|
|
2286 ValueIteratorBase::difference_type
|
|
2287 ValueIteratorBase::computeDistance(const SelfType& other) const {
|
|
2288 #ifdef JSON_USE_CPPTL_SMALLMAP
|
|
2289 return other.current_ - current_;
|
|
2290 #else
|
|
2291 // Iterator for null value are initialized using the default
|
|
2292 // constructor, which initialize current_ to the default
|
|
2293 // std::map::iterator. As begin() and end() are two instance
|
|
2294 // of the default std::map::iterator, they can not be compared.
|
|
2295 // To allow this, we handle this comparison specifically.
|
|
2296 if (isNull_ && other.isNull_) {
|
|
2297 return 0;
|
|
2298 }
|
|
2299
|
|
2300 // Usage of std::distance is not portable (does not compile with Sun Studio 12
|
|
2301 // RogueWave STL,
|
|
2302 // which is the one used by default).
|
|
2303 // Using a portable hand-made version for non random iterator instead:
|
|
2304 // return difference_type( std::distance( current_, other.current_ ) );
|
|
2305 difference_type myDistance = 0;
|
|
2306 for (Value::ObjectValues::iterator it = current_; it != other.current_;
|
|
2307 ++it) {
|
|
2308 ++myDistance;
|
|
2309 }
|
|
2310 return myDistance;
|
|
2311 #endif
|
|
2312 }
|
|
2313
|
|
2314 bool ValueIteratorBase::isEqual(const SelfType& other) const {
|
|
2315 if (isNull_) {
|
|
2316 return other.isNull_;
|
|
2317 }
|
|
2318 return current_ == other.current_;
|
|
2319 }
|
|
2320
|
|
2321 void ValueIteratorBase::copy(const SelfType& other) {
|
|
2322 current_ = other.current_;
|
|
2323 isNull_ = other.isNull_;
|
|
2324 }
|
|
2325
|
|
2326 Value ValueIteratorBase::key() const {
|
|
2327 const Value::CZString czstring = (*current_).first;
|
|
2328 if (czstring.data()) {
|
|
2329 if (czstring.isStaticString())
|
|
2330 return Value(StaticString(czstring.data()));
|
|
2331 return Value(czstring.data(), czstring.data() + czstring.length());
|
|
2332 }
|
|
2333 return Value(czstring.index());
|
|
2334 }
|
|
2335
|
|
2336 UInt ValueIteratorBase::index() const {
|
|
2337 const Value::CZString czstring = (*current_).first;
|
|
2338 if (!czstring.data())
|
|
2339 return czstring.index();
|
|
2340 return Value::UInt(-1);
|
|
2341 }
|
|
2342
|
|
2343 String ValueIteratorBase::name() const {
|
|
2344 char const* keey;
|
|
2345 char const* end;
|
|
2346 keey = memberName(&end);
|
|
2347 if (!keey)
|
|
2348 return String();
|
|
2349 return String(keey, end);
|
|
2350 }
|
|
2351
|
|
2352 char const* ValueIteratorBase::memberName() const {
|
|
2353 const char* cname = (*current_).first.data();
|
|
2354 return cname ? cname : "";
|
|
2355 }
|
|
2356
|
|
2357 char const* ValueIteratorBase::memberName(char const** end) const {
|
|
2358 const char* cname = (*current_).first.data();
|
|
2359 if (!cname) {
|
|
2360 *end = nullptr;
|
|
2361 return nullptr;
|
|
2362 }
|
|
2363 *end = cname + (*current_).first.length();
|
|
2364 return cname;
|
|
2365 }
|
|
2366
|
|
2367 // //////////////////////////////////////////////////////////////////
|
|
2368 // //////////////////////////////////////////////////////////////////
|
|
2369 // //////////////////////////////////////////////////////////////////
|
|
2370 // class ValueConstIterator
|
|
2371 // //////////////////////////////////////////////////////////////////
|
|
2372 // //////////////////////////////////////////////////////////////////
|
|
2373 // //////////////////////////////////////////////////////////////////
|
|
2374
|
|
2375 ValueConstIterator::ValueConstIterator() = default;
|
|
2376
|
|
2377 ValueConstIterator::ValueConstIterator(
|
|
2378 const Value::ObjectValues::iterator& current)
|
|
2379 : ValueIteratorBase(current) {}
|
|
2380
|
|
2381 ValueConstIterator::ValueConstIterator(ValueIterator const& other)
|
|
2382 : ValueIteratorBase(other) {}
|
|
2383
|
|
2384 ValueConstIterator& ValueConstIterator::
|
|
2385 operator=(const ValueIteratorBase& other) {
|
|
2386 copy(other);
|
|
2387 return *this;
|
|
2388 }
|
|
2389
|
|
2390 // //////////////////////////////////////////////////////////////////
|
|
2391 // //////////////////////////////////////////////////////////////////
|
|
2392 // //////////////////////////////////////////////////////////////////
|
|
2393 // class ValueIterator
|
|
2394 // //////////////////////////////////////////////////////////////////
|
|
2395 // //////////////////////////////////////////////////////////////////
|
|
2396 // //////////////////////////////////////////////////////////////////
|
|
2397
|
|
2398 ValueIterator::ValueIterator() = default;
|
|
2399
|
|
2400 ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
|
|
2401 : ValueIteratorBase(current) {}
|
|
2402
|
|
2403 ValueIterator::ValueIterator(const ValueConstIterator& other)
|
|
2404 : ValueIteratorBase(other) {
|
|
2405 throwRuntimeError("ConstIterator to Iterator should never be allowed.");
|
|
2406 }
|
|
2407
|
|
2408 ValueIterator::ValueIterator(const ValueIterator& other) = default;
|
|
2409
|
|
2410 ValueIterator& ValueIterator::operator=(const SelfType& other) {
|
|
2411 copy(other);
|
|
2412 return *this;
|
|
2413 }
|
|
2414
|
|
2415 } // namespace Json
|
|
2416
|
|
2417 // //////////////////////////////////////////////////////////////////////
|
|
2418 // End of content of file: src/lib_json/json_valueiterator.inl
|
|
2419 // //////////////////////////////////////////////////////////////////////
|
|
2420
|
|
2421
|
|
2422
|
|
2423
|
|
2424
|
|
2425
|
|
2426 // //////////////////////////////////////////////////////////////////////
|
|
2427 // Beginning of content of file: src/lib_json/json_value.cpp
|
|
2428 // //////////////////////////////////////////////////////////////////////
|
|
2429
|
|
2430 // Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
|
|
2431 // Distributed under MIT license, or public domain if desired and
|
|
2432 // recognized in your jurisdiction.
|
|
2433 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
|
2434
|
|
2435 #if !defined(JSON_IS_AMALGAMATION)
|
|
2436 #include <json/assertions.h>
|
|
2437 #include <json/value.h>
|
|
2438 #include <json/writer.h>
|
|
2439 #endif // if !defined(JSON_IS_AMALGAMATION)
|
|
2440 #include <cassert>
|
|
2441 #include <cmath>
|
|
2442 #include <cstring>
|
|
2443 #include <sstream>
|
|
2444 #include <utility>
|
|
2445 #ifdef JSON_USE_CPPTL
|
|
2446 #include <cpptl/conststring.h>
|
|
2447 #endif
|
|
2448 #include <algorithm> // min()
|
|
2449 #include <cstddef> // size_t
|
|
2450
|
|
2451 // Provide implementation equivalent of std::snprintf for older _MSC compilers
|
|
2452 #if defined(_MSC_VER) && _MSC_VER < 1900
|
|
2453 #include <stdarg.h>
|
|
2454 static int msvc_pre1900_c99_vsnprintf(char* outBuf,
|
|
2455 size_t size,
|
|
2456 const char* format,
|
|
2457 va_list ap) {
|
|
2458 int count = -1;
|
|
2459 if (size != 0)
|
|
2460 count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
|
|
2461 if (count == -1)
|
|
2462 count = _vscprintf(format, ap);
|
|
2463 return count;
|
|
2464 }
|
|
2465
|
|
2466 int JSON_API msvc_pre1900_c99_snprintf(char* outBuf,
|
|
2467 size_t size,
|
|
2468 const char* format,
|
|
2469 ...) {
|
|
2470 va_list ap;
|
|
2471 va_start(ap, format);
|
|
2472 const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap);
|
|
2473 va_end(ap);
|
|
2474 return count;
|
|
2475 }
|
|
2476 #endif
|
|
2477
|
|
2478 // Disable warning C4702 : unreachable code
|
|
2479 #if defined(_MSC_VER)
|
|
2480 #pragma warning(disable : 4702)
|
|
2481 #endif
|
|
2482
|
|
2483 #define JSON_ASSERT_UNREACHABLE assert(false)
|
|
2484
|
|
2485 namespace Json {
|
|
2486
|
|
2487 // This is a walkaround to avoid the static initialization of Value::null.
|
|
2488 // kNull must be word-aligned to avoid crashing on ARM. We use an alignment of
|
|
2489 // 8 (instead of 4) as a bit of future-proofing.
|
|
2490 #if defined(__ARMEL__)
|
|
2491 #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
|
|
2492 #else
|
|
2493 #define ALIGNAS(byte_alignment)
|
|
2494 #endif
|
|
2495 // static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
|
|
2496 // const unsigned char& kNullRef = kNull[0];
|
|
2497 // const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
|
|
2498 // const Value& Value::nullRef = null;
|
|
2499
|
|
2500 // static
|
|
2501 Value const& Value::nullSingleton() {
|
|
2502 static Value const nullStatic;
|
|
2503 return nullStatic;
|
|
2504 }
|
|
2505
|
|
2506 // for backwards compatibility, we'll leave these global references around, but
|
|
2507 // DO NOT use them in JSONCPP library code any more!
|
|
2508 Value const& Value::null = Value::nullSingleton();
|
|
2509 Value const& Value::nullRef = Value::nullSingleton();
|
|
2510
|
|
2511 const Int Value::minInt = Int(~(UInt(-1) / 2));
|
|
2512 const Int Value::maxInt = Int(UInt(-1) / 2);
|
|
2513 const UInt Value::maxUInt = UInt(-1);
|
|
2514 #if defined(JSON_HAS_INT64)
|
|
2515 const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));
|
|
2516 const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);
|
|
2517 const UInt64 Value::maxUInt64 = UInt64(-1);
|
|
2518 // The constant is hard-coded because some compiler have trouble
|
|
2519 // converting Value::maxUInt64 to a double correctly (AIX/xlC).
|
|
2520 // Assumes that UInt64 is a 64 bits integer.
|
|
2521 static const double maxUInt64AsDouble = 18446744073709551615.0;
|
|
2522 #endif // defined(JSON_HAS_INT64)
|
|
2523 const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
|
|
2524 const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
|
|
2525 const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
|
|
2526
|
|
2527 const UInt Value::defaultRealPrecision = 17;
|
|
2528
|
|
2529 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
|
2530 template <typename T, typename U>
|
|
2531 static inline bool InRange(double d, T min, U max) {
|
|
2532 // The casts can lose precision, but we are looking only for
|
|
2533 // an approximate range. Might fail on edge cases though. ~cdunn
|
|
2534 // return d >= static_cast<double>(min) && d <= static_cast<double>(max);
|
|
2535 return d >= min && d <= max;
|
|
2536 }
|
|
2537 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
|
2538 static inline double integerToDouble(Json::UInt64 value) {
|
|
2539 return static_cast<double>(Int64(value / 2)) * 2.0 +
|
|
2540 static_cast<double>(Int64(value & 1));
|
|
2541 }
|
|
2542
|
|
2543 template <typename T> static inline double integerToDouble(T value) {
|
|
2544 return static_cast<double>(value);
|
|
2545 }
|
|
2546
|
|
2547 template <typename T, typename U>
|
|
2548 static inline bool InRange(double d, T min, U max) {
|
|
2549 return d >= integerToDouble(min) && d <= integerToDouble(max);
|
|
2550 }
|
|
2551 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
|
2552
|
|
2553 /** Duplicates the specified string value.
|
|
2554 * @param value Pointer to the string to duplicate. Must be zero-terminated if
|
|
2555 * length is "unknown".
|
|
2556 * @param length Length of the value. if equals to unknown, then it will be
|
|
2557 * computed using strlen(value).
|
|
2558 * @return Pointer on the duplicate instance of string.
|
|
2559 */
|
|
2560 static inline char* duplicateStringValue(const char* value, size_t length) {
|
|
2561 // Avoid an integer overflow in the call to malloc below by limiting length
|
|
2562 // to a sane value.
|
|
2563 if (length >= static_cast<size_t>(Value::maxInt))
|
|
2564 length = Value::maxInt - 1;
|
|
2565
|
|
2566 char* newString = static_cast<char*>(malloc(length + 1));
|
|
2567 if (newString == nullptr) {
|
|
2568 throwRuntimeError("in Json::Value::duplicateStringValue(): "
|
|
2569 "Failed to allocate string value buffer");
|
|
2570 }
|
|
2571 memcpy(newString, value, length);
|
|
2572 newString[length] = 0;
|
|
2573 return newString;
|
|
2574 }
|
|
2575
|
|
2576 /* Record the length as a prefix.
|
|
2577 */
|
|
2578 static inline char* duplicateAndPrefixStringValue(const char* value,
|
|
2579 unsigned int length) {
|
|
2580 // Avoid an integer overflow in the call to malloc below by limiting length
|
|
2581 // to a sane value.
|
|
2582 JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) -
|
|
2583 sizeof(unsigned) - 1U,
|
|
2584 "in Json::Value::duplicateAndPrefixStringValue(): "
|
|
2585 "length too big for prefixing");
|
|
2586 unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;
|
|
2587 char* newString = static_cast<char*>(malloc(actualLength));
|
|
2588 if (newString == nullptr) {
|
|
2589 throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
|
|
2590 "Failed to allocate string value buffer");
|
|
2591 }
|
|
2592 *reinterpret_cast<unsigned*>(newString) = length;
|
|
2593 memcpy(newString + sizeof(unsigned), value, length);
|
|
2594 newString[actualLength - 1U] =
|
|
2595 0; // to avoid buffer over-run accidents by users later
|
|
2596 return newString;
|
|
2597 }
|
|
2598 inline static void decodePrefixedString(bool isPrefixed,
|
|
2599 char const* prefixed,
|
|
2600 unsigned* length,
|
|
2601 char const** value) {
|
|
2602 if (!isPrefixed) {
|
|
2603 *length = static_cast<unsigned>(strlen(prefixed));
|
|
2604 *value = prefixed;
|
|
2605 } else {
|
|
2606 *length = *reinterpret_cast<unsigned const*>(prefixed);
|
|
2607 *value = prefixed + sizeof(unsigned);
|
|
2608 }
|
|
2609 }
|
|
2610 /** Free the string duplicated by
|
|
2611 * duplicateStringValue()/duplicateAndPrefixStringValue().
|
|
2612 */
|
|
2613 #if JSONCPP_USING_SECURE_MEMORY
|
|
2614 static inline void releasePrefixedStringValue(char* value) {
|
|
2615 unsigned length = 0;
|
|
2616 char const* valueDecoded;
|
|
2617 decodePrefixedString(true, value, &length, &valueDecoded);
|
|
2618 size_t const size = sizeof(unsigned) + length + 1U;
|
|
2619 memset(value, 0, size);
|
|
2620 free(value);
|
|
2621 }
|
|
2622 static inline void releaseStringValue(char* value, unsigned length) {
|
|
2623 // length==0 => we allocated the strings memory
|
|
2624 size_t size = (length == 0) ? strlen(value) : length;
|
|
2625 memset(value, 0, size);
|
|
2626 free(value);
|
|
2627 }
|
|
2628 #else // !JSONCPP_USING_SECURE_MEMORY
|
|
2629 static inline void releasePrefixedStringValue(char* value) { free(value); }
|
|
2630 static inline void releaseStringValue(char* value, unsigned) { free(value); }
|
|
2631 #endif // JSONCPP_USING_SECURE_MEMORY
|
|
2632
|
|
2633 } // namespace Json
|
|
2634
|
|
2635 // //////////////////////////////////////////////////////////////////
|
|
2636 // //////////////////////////////////////////////////////////////////
|
|
2637 // //////////////////////////////////////////////////////////////////
|
|
2638 // ValueInternals...
|
|
2639 // //////////////////////////////////////////////////////////////////
|
|
2640 // //////////////////////////////////////////////////////////////////
|
|
2641 // //////////////////////////////////////////////////////////////////
|
|
2642 #if !defined(JSON_IS_AMALGAMATION)
|
|
2643
|
|
2644 #include "json_valueiterator.inl"
|
|
2645 #endif // if !defined(JSON_IS_AMALGAMATION)
|
|
2646
|
|
2647 namespace Json {
|
|
2648
|
|
2649 Exception::Exception(String msg) : msg_(std::move(msg)) {}
|
|
2650 Exception::~Exception() JSONCPP_NOEXCEPT {}
|
|
2651 char const* Exception::what() const JSONCPP_NOEXCEPT { return msg_.c_str(); }
|
|
2652 RuntimeError::RuntimeError(String const& msg) : Exception(msg) {}
|
|
2653 LogicError::LogicError(String const& msg) : Exception(msg) {}
|
|
2654 JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
|
|
2655 throw RuntimeError(msg);
|
|
2656 }
|
|
2657 JSONCPP_NORETURN void throwLogicError(String const& msg) {
|
|
2658 throw LogicError(msg);
|
|
2659 }
|
|
2660
|
|
2661 // //////////////////////////////////////////////////////////////////
|
|
2662 // //////////////////////////////////////////////////////////////////
|
|
2663 // //////////////////////////////////////////////////////////////////
|
|
2664 // class Value::CommentInfo
|
|
2665 // //////////////////////////////////////////////////////////////////
|
|
2666 // //////////////////////////////////////////////////////////////////
|
|
2667 // //////////////////////////////////////////////////////////////////
|
|
2668
|
|
2669 Value::CommentInfo::CommentInfo() = default;
|
|
2670
|
|
2671 Value::CommentInfo::~CommentInfo() {
|
|
2672 if (comment_)
|
|
2673 releaseStringValue(comment_, 0u);
|
|
2674 }
|
|
2675
|
|
2676 void Value::CommentInfo::setComment(const char* text, size_t len) {
|
|
2677 if (comment_) {
|
|
2678 releaseStringValue(comment_, 0u);
|
|
2679 comment_ = nullptr;
|
|
2680 }
|
|
2681 JSON_ASSERT(text != nullptr);
|
|
2682 JSON_ASSERT_MESSAGE(
|
|
2683 text[0] == '\0' || text[0] == '/',
|
|
2684 "in Json::Value::setComment(): Comments must start with /");
|
|
2685 // It seems that /**/ style comments are acceptable as well.
|
|
2686 comment_ = duplicateStringValue(text, len);
|
|
2687 }
|
|
2688
|
|
2689 // //////////////////////////////////////////////////////////////////
|
|
2690 // //////////////////////////////////////////////////////////////////
|
|
2691 // //////////////////////////////////////////////////////////////////
|
|
2692 // class Value::CZString
|
|
2693 // //////////////////////////////////////////////////////////////////
|
|
2694 // //////////////////////////////////////////////////////////////////
|
|
2695 // //////////////////////////////////////////////////////////////////
|
|
2696
|
|
2697 // Notes: policy_ indicates if the string was allocated when
|
|
2698 // a string is stored.
|
|
2699
|
|
2700 Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {}
|
|
2701
|
|
2702 Value::CZString::CZString(char const* str,
|
|
2703 unsigned length,
|
|
2704 DuplicationPolicy allocate)
|
|
2705 : cstr_(str) {
|
|
2706 // allocate != duplicate
|
|
2707 storage_.policy_ = allocate & 0x3;
|
|
2708 storage_.length_ = length & 0x3FFFFFFF;
|
|
2709 }
|
|
2710
|
|
2711 Value::CZString::CZString(const CZString& other) {
|
|
2712 cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr
|
|
2713 ? duplicateStringValue(other.cstr_, other.storage_.length_)
|
|
2714 : other.cstr_);
|
|
2715 storage_.policy_ =
|
|
2716 static_cast<unsigned>(
|
|
2717 other.cstr_
|
|
2718 ? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==
|
|
2719 noDuplication
|
|
2720 ? noDuplication
|
|
2721 : duplicate)
|
|
2722 : static_cast<DuplicationPolicy>(other.storage_.policy_)) &
|
|
2723 3U;
|
|
2724 storage_.length_ = other.storage_.length_;
|
|
2725 }
|
|
2726
|
|
2727 #if JSON_HAS_RVALUE_REFERENCES
|
|
2728 Value::CZString::CZString(CZString&& other)
|
|
2729 : cstr_(other.cstr_), index_(other.index_) {
|
|
2730 other.cstr_ = nullptr;
|
|
2731 }
|
|
2732 #endif
|
|
2733
|
|
2734 Value::CZString::~CZString() {
|
|
2735 if (cstr_ && storage_.policy_ == duplicate) {
|
|
2736 releaseStringValue(const_cast<char*>(cstr_),
|
|
2737 storage_.length_ + 1u); // +1 for null terminating
|
|
2738 // character for sake of
|
|
2739 // completeness but not actually
|
|
2740 // necessary
|
|
2741 }
|
|
2742 }
|
|
2743
|
|
2744 void Value::CZString::swap(CZString& other) {
|
|
2745 std::swap(cstr_, other.cstr_);
|
|
2746 std::swap(index_, other.index_);
|
|
2747 }
|
|
2748
|
|
2749 Value::CZString& Value::CZString::operator=(const CZString& other) {
|
|
2750 cstr_ = other.cstr_;
|
|
2751 index_ = other.index_;
|
|
2752 return *this;
|
|
2753 }
|
|
2754
|
|
2755 #if JSON_HAS_RVALUE_REFERENCES
|
|
2756 Value::CZString& Value::CZString::operator=(CZString&& other) {
|
|
2757 cstr_ = other.cstr_;
|
|
2758 index_ = other.index_;
|
|
2759 other.cstr_ = nullptr;
|
|
2760 return *this;
|
|
2761 }
|
|
2762 #endif
|
|
2763
|
|
2764 bool Value::CZString::operator<(const CZString& other) const {
|
|
2765 if (!cstr_)
|
|
2766 return index_ < other.index_;
|
|
2767 // return strcmp(cstr_, other.cstr_) < 0;
|
|
2768 // Assume both are strings.
|
|
2769 unsigned this_len = this->storage_.length_;
|
|
2770 unsigned other_len = other.storage_.length_;
|
|
2771 unsigned min_len = std::min<unsigned>(this_len, other_len);
|
|
2772 JSON_ASSERT(this->cstr_ && other.cstr_);
|
|
2773 int comp = memcmp(this->cstr_, other.cstr_, min_len);
|
|
2774 if (comp < 0)
|
|
2775 return true;
|
|
2776 if (comp > 0)
|
|
2777 return false;
|
|
2778 return (this_len < other_len);
|
|
2779 }
|
|
2780
|
|
2781 bool Value::CZString::operator==(const CZString& other) const {
|
|
2782 if (!cstr_)
|
|
2783 return index_ == other.index_;
|
|
2784 // return strcmp(cstr_, other.cstr_) == 0;
|
|
2785 // Assume both are strings.
|
|
2786 unsigned this_len = this->storage_.length_;
|
|
2787 unsigned other_len = other.storage_.length_;
|
|
2788 if (this_len != other_len)
|
|
2789 return false;
|
|
2790 JSON_ASSERT(this->cstr_ && other.cstr_);
|
|
2791 int comp = memcmp(this->cstr_, other.cstr_, this_len);
|
|
2792 return comp == 0;
|
|
2793 }
|
|
2794
|
|
2795 ArrayIndex Value::CZString::index() const { return index_; }
|
|
2796
|
|
2797 // const char* Value::CZString::c_str() const { return cstr_; }
|
|
2798 const char* Value::CZString::data() const { return cstr_; }
|
|
2799 unsigned Value::CZString::length() const { return storage_.length_; }
|
|
2800 bool Value::CZString::isStaticString() const {
|
|
2801 return storage_.policy_ == noDuplication;
|
|
2802 }
|
|
2803
|
|
2804 // //////////////////////////////////////////////////////////////////
|
|
2805 // //////////////////////////////////////////////////////////////////
|
|
2806 // //////////////////////////////////////////////////////////////////
|
|
2807 // class Value::Value
|
|
2808 // //////////////////////////////////////////////////////////////////
|
|
2809 // //////////////////////////////////////////////////////////////////
|
|
2810 // //////////////////////////////////////////////////////////////////
|
|
2811
|
|
2812 /*! \internal Default constructor initialization must be equivalent to:
|
|
2813 * memset( this, 0, sizeof(Value) )
|
|
2814 * This optimization is used in ValueInternalMap fast allocator.
|
|
2815 */
|
|
2816 Value::Value(ValueType type) {
|
|
2817 static char const emptyString[] = "";
|
|
2818 initBasic(type);
|
|
2819 switch (type) {
|
|
2820 case nullValue:
|
|
2821 break;
|
|
2822 case intValue:
|
|
2823 case uintValue:
|
|
2824 value_.int_ = 0;
|
|
2825 break;
|
|
2826 case realValue:
|
|
2827 value_.real_ = 0.0;
|
|
2828 break;
|
|
2829 case stringValue:
|
|
2830 // allocated_ == false, so this is safe.
|
|
2831 value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));
|
|
2832 break;
|
|
2833 case arrayValue:
|
|
2834 case objectValue:
|
|
2835 value_.map_ = new ObjectValues();
|
|
2836 break;
|
|
2837 case booleanValue:
|
|
2838 value_.bool_ = false;
|
|
2839 break;
|
|
2840 default:
|
|
2841 JSON_ASSERT_UNREACHABLE;
|
|
2842 }
|
|
2843 }
|
|
2844
|
|
2845 Value::Value(Int value) {
|
|
2846 initBasic(intValue);
|
|
2847 value_.int_ = value;
|
|
2848 }
|
|
2849
|
|
2850 Value::Value(UInt value) {
|
|
2851 initBasic(uintValue);
|
|
2852 value_.uint_ = value;
|
|
2853 }
|
|
2854 #if defined(JSON_HAS_INT64)
|
|
2855 Value::Value(Int64 value) {
|
|
2856 initBasic(intValue);
|
|
2857 value_.int_ = value;
|
|
2858 }
|
|
2859 Value::Value(UInt64 value) {
|
|
2860 initBasic(uintValue);
|
|
2861 value_.uint_ = value;
|
|
2862 }
|
|
2863 #endif // defined(JSON_HAS_INT64)
|
|
2864
|
|
2865 Value::Value(double value) {
|
|
2866 initBasic(realValue);
|
|
2867 value_.real_ = value;
|
|
2868 }
|
|
2869
|
|
2870 Value::Value(const char* value) {
|
|
2871 initBasic(stringValue, true);
|
|
2872 JSON_ASSERT_MESSAGE(value != nullptr,
|
|
2873 "Null Value Passed to Value Constructor");
|
|
2874 value_.string_ = duplicateAndPrefixStringValue(
|
|
2875 value, static_cast<unsigned>(strlen(value)));
|
|
2876 }
|
|
2877
|
|
2878 Value::Value(const char* begin, const char* end) {
|
|
2879 initBasic(stringValue, true);
|
|
2880 value_.string_ =
|
|
2881 duplicateAndPrefixStringValue(begin, static_cast<unsigned>(end - begin));
|
|
2882 }
|
|
2883
|
|
2884 Value::Value(const String& value) {
|
|
2885 initBasic(stringValue, true);
|
|
2886 value_.string_ = duplicateAndPrefixStringValue(
|
|
2887 value.data(), static_cast<unsigned>(value.length()));
|
|
2888 }
|
|
2889
|
|
2890 Value::Value(const StaticString& value) {
|
|
2891 initBasic(stringValue);
|
|
2892 value_.string_ = const_cast<char*>(value.c_str());
|
|
2893 }
|
|
2894
|
|
2895 #ifdef JSON_USE_CPPTL
|
|
2896 Value::Value(const CppTL::ConstString& value) {
|
|
2897 initBasic(stringValue, true);
|
|
2898 value_.string_ = duplicateAndPrefixStringValue(
|
|
2899 value, static_cast<unsigned>(value.length()));
|
|
2900 }
|
|
2901 #endif
|
|
2902
|
|
2903 Value::Value(bool value) {
|
|
2904 initBasic(booleanValue);
|
|
2905 value_.bool_ = value;
|
|
2906 }
|
|
2907
|
|
2908 Value::Value(const Value& other) {
|
|
2909 dupPayload(other);
|
|
2910 dupMeta(other);
|
|
2911 }
|
|
2912
|
|
2913 Value::Value(Value&& other) {
|
|
2914 initBasic(nullValue);
|
|
2915 swap(other);
|
|
2916 }
|
|
2917
|
|
2918 Value::~Value() {
|
|
2919 releasePayload();
|
|
2920 delete[] comments_;
|
|
2921 value_.uint_ = 0;
|
|
2922 }
|
|
2923
|
|
2924 Value& Value::operator=(const Value& other) {
|
|
2925 Value(other).swap(*this);
|
|
2926 return *this;
|
|
2927 }
|
|
2928
|
|
2929 Value& Value::operator=(Value&& other) {
|
|
2930 other.swap(*this);
|
|
2931 return *this;
|
|
2932 }
|
|
2933
|
|
2934 void Value::swapPayload(Value& other) {
|
|
2935 std::swap(bits_, other.bits_);
|
|
2936 std::swap(value_, other.value_);
|
|
2937 }
|
|
2938
|
|
2939 void Value::copyPayload(const Value& other) {
|
|
2940 releasePayload();
|
|
2941 dupPayload(other);
|
|
2942 }
|
|
2943
|
|
2944 void Value::swap(Value& other) {
|
|
2945 swapPayload(other);
|
|
2946 std::swap(comments_, other.comments_);
|
|
2947 std::swap(start_, other.start_);
|
|
2948 std::swap(limit_, other.limit_);
|
|
2949 }
|
|
2950
|
|
2951 void Value::copy(const Value& other) {
|
|
2952 copyPayload(other);
|
|
2953 delete[] comments_;
|
|
2954 dupMeta(other);
|
|
2955 }
|
|
2956
|
|
2957 ValueType Value::type() const {
|
|
2958 return static_cast<ValueType>(bits_.value_type_);
|
|
2959 }
|
|
2960
|
|
2961 int Value::compare(const Value& other) const {
|
|
2962 if (*this < other)
|
|
2963 return -1;
|
|
2964 if (*this > other)
|
|
2965 return 1;
|
|
2966 return 0;
|
|
2967 }
|
|
2968
|
|
2969 bool Value::operator<(const Value& other) const {
|
|
2970 int typeDelta = type() - other.type();
|
|
2971 if (typeDelta)
|
|
2972 return typeDelta < 0 ? true : false;
|
|
2973 switch (type()) {
|
|
2974 case nullValue:
|
|
2975 return false;
|
|
2976 case intValue:
|
|
2977 return value_.int_ < other.value_.int_;
|
|
2978 case uintValue:
|
|
2979 return value_.uint_ < other.value_.uint_;
|
|
2980 case realValue:
|
|
2981 return value_.real_ < other.value_.real_;
|
|
2982 case booleanValue:
|
|
2983 return value_.bool_ < other.value_.bool_;
|
|
2984 case stringValue: {
|
|
2985 if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
|
|
2986 if (other.value_.string_)
|
|
2987 return true;
|
|
2988 else
|
|
2989 return false;
|
|
2990 }
|
|
2991 unsigned this_len;
|
|
2992 unsigned other_len;
|
|
2993 char const* this_str;
|
|
2994 char const* other_str;
|
|
2995 decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
|
|
2996 &this_str);
|
|
2997 decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
|
|
2998 &other_str);
|
|
2999 unsigned min_len = std::min<unsigned>(this_len, other_len);
|
|
3000 JSON_ASSERT(this_str && other_str);
|
|
3001 int comp = memcmp(this_str, other_str, min_len);
|
|
3002 if (comp < 0)
|
|
3003 return true;
|
|
3004 if (comp > 0)
|
|
3005 return false;
|
|
3006 return (this_len < other_len);
|
|
3007 }
|
|
3008 case arrayValue:
|
|
3009 case objectValue: {
|
|
3010 int delta = int(value_.map_->size() - other.value_.map_->size());
|
|
3011 if (delta)
|
|
3012 return delta < 0;
|
|
3013 return (*value_.map_) < (*other.value_.map_);
|
|
3014 }
|
|
3015 default:
|
|
3016 JSON_ASSERT_UNREACHABLE;
|
|
3017 }
|
|
3018 return false; // unreachable
|
|
3019 }
|
|
3020
|
|
3021 bool Value::operator<=(const Value& other) const { return !(other < *this); }
|
|
3022
|
|
3023 bool Value::operator>=(const Value& other) const { return !(*this < other); }
|
|
3024
|
|
3025 bool Value::operator>(const Value& other) const { return other < *this; }
|
|
3026
|
|
3027 bool Value::operator==(const Value& other) const {
|
|
3028 if (type() != other.type())
|
|
3029 return false;
|
|
3030 switch (type()) {
|
|
3031 case nullValue:
|
|
3032 return true;
|
|
3033 case intValue:
|
|
3034 return value_.int_ == other.value_.int_;
|
|
3035 case uintValue:
|
|
3036 return value_.uint_ == other.value_.uint_;
|
|
3037 case realValue:
|
|
3038 return value_.real_ == other.value_.real_;
|
|
3039 case booleanValue:
|
|
3040 return value_.bool_ == other.value_.bool_;
|
|
3041 case stringValue: {
|
|
3042 if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
|
|
3043 return (value_.string_ == other.value_.string_);
|
|
3044 }
|
|
3045 unsigned this_len;
|
|
3046 unsigned other_len;
|
|
3047 char const* this_str;
|
|
3048 char const* other_str;
|
|
3049 decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
|
|
3050 &this_str);
|
|
3051 decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
|
|
3052 &other_str);
|
|
3053 if (this_len != other_len)
|
|
3054 return false;
|
|
3055 JSON_ASSERT(this_str && other_str);
|
|
3056 int comp = memcmp(this_str, other_str, this_len);
|
|
3057 return comp == 0;
|
|
3058 }
|
|
3059 case arrayValue:
|
|
3060 case objectValue:
|
|
3061 return value_.map_->size() == other.value_.map_->size() &&
|
|
3062 (*value_.map_) == (*other.value_.map_);
|
|
3063 default:
|
|
3064 JSON_ASSERT_UNREACHABLE;
|
|
3065 }
|
|
3066 return false; // unreachable
|
|
3067 }
|
|
3068
|
|
3069 bool Value::operator!=(const Value& other) const { return !(*this == other); }
|
|
3070
|
|
3071 const char* Value::asCString() const {
|
|
3072 JSON_ASSERT_MESSAGE(type() == stringValue,
|
|
3073 "in Json::Value::asCString(): requires stringValue");
|
|
3074 if (value_.string_ == nullptr)
|
|
3075 return nullptr;
|
|
3076 unsigned this_len;
|
|
3077 char const* this_str;
|
|
3078 decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
|
|
3079 &this_str);
|
|
3080 return this_str;
|
|
3081 }
|
|
3082
|
|
3083 #if JSONCPP_USING_SECURE_MEMORY
|
|
3084 unsigned Value::getCStringLength() const {
|
|
3085 JSON_ASSERT_MESSAGE(type() == stringValue,
|
|
3086 "in Json::Value::asCString(): requires stringValue");
|
|
3087 if (value_.string_ == 0)
|
|
3088 return 0;
|
|
3089 unsigned this_len;
|
|
3090 char const* this_str;
|
|
3091 decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
|
|
3092 &this_str);
|
|
3093 return this_len;
|
|
3094 }
|
|
3095 #endif
|
|
3096
|
|
3097 bool Value::getString(char const** begin, char const** end) const {
|
|
3098 if (type() != stringValue)
|
|
3099 return false;
|
|
3100 if (value_.string_ == nullptr)
|
|
3101 return false;
|
|
3102 unsigned length;
|
|
3103 decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
|
|
3104 begin);
|
|
3105 *end = *begin + length;
|
|
3106 return true;
|
|
3107 }
|
|
3108
|
|
3109 String Value::asString() const {
|
|
3110 switch (type()) {
|
|
3111 case nullValue:
|
|
3112 return "";
|
|
3113 case stringValue: {
|
|
3114 if (value_.string_ == nullptr)
|
|
3115 return "";
|
|
3116 unsigned this_len;
|
|
3117 char const* this_str;
|
|
3118 decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
|
|
3119 &this_str);
|
|
3120 return String(this_str, this_len);
|
|
3121 }
|
|
3122 case booleanValue:
|
|
3123 return value_.bool_ ? "true" : "false";
|
|
3124 case intValue:
|
|
3125 return valueToString(value_.int_);
|
|
3126 case uintValue:
|
|
3127 return valueToString(value_.uint_);
|
|
3128 case realValue:
|
|
3129 return valueToString(value_.real_);
|
|
3130 default:
|
|
3131 JSON_FAIL_MESSAGE("Type is not convertible to string");
|
|
3132 }
|
|
3133 }
|
|
3134
|
|
3135 #ifdef JSON_USE_CPPTL
|
|
3136 CppTL::ConstString Value::asConstString() const {
|
|
3137 unsigned len;
|
|
3138 char const* str;
|
|
3139 decodePrefixedString(isAllocated(), value_.string_, &len, &str);
|
|
3140 return CppTL::ConstString(str, len);
|
|
3141 }
|
|
3142 #endif
|
|
3143
|
|
3144 Value::Int Value::asInt() const {
|
|
3145 switch (type()) {
|
|
3146 case intValue:
|
|
3147 JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
|
|
3148 return Int(value_.int_);
|
|
3149 case uintValue:
|
|
3150 JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
|
|
3151 return Int(value_.uint_);
|
|
3152 case realValue:
|
|
3153 JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
|
|
3154 "double out of Int range");
|
|
3155 return Int(value_.real_);
|
|
3156 case nullValue:
|
|
3157 return 0;
|
|
3158 case booleanValue:
|
|
3159 return value_.bool_ ? 1 : 0;
|
|
3160 default:
|
|
3161 break;
|
|
3162 }
|
|
3163 JSON_FAIL_MESSAGE("Value is not convertible to Int.");
|
|
3164 }
|
|
3165
|
|
3166 Value::UInt Value::asUInt() const {
|
|
3167 switch (type()) {
|
|
3168 case intValue:
|
|
3169 JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
|
|
3170 return UInt(value_.int_);
|
|
3171 case uintValue:
|
|
3172 JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
|
|
3173 return UInt(value_.uint_);
|
|
3174 case realValue:
|
|
3175 JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
|
|
3176 "double out of UInt range");
|
|
3177 return UInt(value_.real_);
|
|
3178 case nullValue:
|
|
3179 return 0;
|
|
3180 case booleanValue:
|
|
3181 return value_.bool_ ? 1 : 0;
|
|
3182 default:
|
|
3183 break;
|
|
3184 }
|
|
3185 JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
|
|
3186 }
|
|
3187
|
|
3188 #if defined(JSON_HAS_INT64)
|
|
3189
|
|
3190 Value::Int64 Value::asInt64() const {
|
|
3191 switch (type()) {
|
|
3192 case intValue:
|
|
3193 return Int64(value_.int_);
|
|
3194 case uintValue:
|
|
3195 JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
|
|
3196 return Int64(value_.uint_);
|
|
3197 case realValue:
|
|
3198 JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
|
|
3199 "double out of Int64 range");
|
|
3200 return Int64(value_.real_);
|
|
3201 case nullValue:
|
|
3202 return 0;
|
|
3203 case booleanValue:
|
|
3204 return value_.bool_ ? 1 : 0;
|
|
3205 default:
|
|
3206 break;
|
|
3207 }
|
|
3208 JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
|
|
3209 }
|
|
3210
|
|
3211 Value::UInt64 Value::asUInt64() const {
|
|
3212 switch (type()) {
|
|
3213 case intValue:
|
|
3214 JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
|
|
3215 return UInt64(value_.int_);
|
|
3216 case uintValue:
|
|
3217 return UInt64(value_.uint_);
|
|
3218 case realValue:
|
|
3219 JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
|
|
3220 "double out of UInt64 range");
|
|
3221 return UInt64(value_.real_);
|
|
3222 case nullValue:
|
|
3223 return 0;
|
|
3224 case booleanValue:
|
|
3225 return value_.bool_ ? 1 : 0;
|
|
3226 default:
|
|
3227 break;
|
|
3228 }
|
|
3229 JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
|
|
3230 }
|
|
3231 #endif // if defined(JSON_HAS_INT64)
|
|
3232
|
|
3233 LargestInt Value::asLargestInt() const {
|
|
3234 #if defined(JSON_NO_INT64)
|
|
3235 return asInt();
|
|
3236 #else
|
|
3237 return asInt64();
|
|
3238 #endif
|
|
3239 }
|
|
3240
|
|
3241 LargestUInt Value::asLargestUInt() const {
|
|
3242 #if defined(JSON_NO_INT64)
|
|
3243 return asUInt();
|
|
3244 #else
|
|
3245 return asUInt64();
|
|
3246 #endif
|
|
3247 }
|
|
3248
|
|
3249 double Value::asDouble() const {
|
|
3250 switch (type()) {
|
|
3251 case intValue:
|
|
3252 return static_cast<double>(value_.int_);
|
|
3253 case uintValue:
|
|
3254 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
|
3255 return static_cast<double>(value_.uint_);
|
|
3256 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
|
3257 return integerToDouble(value_.uint_);
|
|
3258 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
|
3259 case realValue:
|
|
3260 return value_.real_;
|
|
3261 case nullValue:
|
|
3262 return 0.0;
|
|
3263 case booleanValue:
|
|
3264 return value_.bool_ ? 1.0 : 0.0;
|
|
3265 default:
|
|
3266 break;
|
|
3267 }
|
|
3268 JSON_FAIL_MESSAGE("Value is not convertible to double.");
|
|
3269 }
|
|
3270
|
|
3271 float Value::asFloat() const {
|
|
3272 switch (type()) {
|
|
3273 case intValue:
|
|
3274 return static_cast<float>(value_.int_);
|
|
3275 case uintValue:
|
|
3276 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
|
3277 return static_cast<float>(value_.uint_);
|
|
3278 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
|
3279 // This can fail (silently?) if the value is bigger than MAX_FLOAT.
|
|
3280 return static_cast<float>(integerToDouble(value_.uint_));
|
|
3281 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
|
3282 case realValue:
|
|
3283 return static_cast<float>(value_.real_);
|
|
3284 case nullValue:
|
|
3285 return 0.0;
|
|
3286 case booleanValue:
|
|
3287 return value_.bool_ ? 1.0f : 0.0f;
|
|
3288 default:
|
|
3289 break;
|
|
3290 }
|
|
3291 JSON_FAIL_MESSAGE("Value is not convertible to float.");
|
|
3292 }
|
|
3293
|
|
3294 bool Value::asBool() const {
|
|
3295 switch (type()) {
|
|
3296 case booleanValue:
|
|
3297 return value_.bool_;
|
|
3298 case nullValue:
|
|
3299 return false;
|
|
3300 case intValue:
|
|
3301 return value_.int_ ? true : false;
|
|
3302 case uintValue:
|
|
3303 return value_.uint_ ? true : false;
|
|
3304 case realValue:
|
|
3305 // This is kind of strange. Not recommended.
|
|
3306 return (value_.real_ != 0.0) ? true : false;
|
|
3307 default:
|
|
3308 break;
|
|
3309 }
|
|
3310 JSON_FAIL_MESSAGE("Value is not convertible to bool.");
|
|
3311 }
|
|
3312
|
|
3313 bool Value::isConvertibleTo(ValueType other) const {
|
|
3314 switch (other) {
|
|
3315 case nullValue:
|
|
3316 return (isNumeric() && asDouble() == 0.0) ||
|
|
3317 (type() == booleanValue && value_.bool_ == false) ||
|
|
3318 (type() == stringValue && asString().empty()) ||
|
|
3319 (type() == arrayValue && value_.map_->empty()) ||
|
|
3320 (type() == objectValue && value_.map_->empty()) ||
|
|
3321 type() == nullValue;
|
|
3322 case intValue:
|
|
3323 return isInt() ||
|
|
3324 (type() == realValue && InRange(value_.real_, minInt, maxInt)) ||
|
|
3325 type() == booleanValue || type() == nullValue;
|
|
3326 case uintValue:
|
|
3327 return isUInt() ||
|
|
3328 (type() == realValue && InRange(value_.real_, 0, maxUInt)) ||
|
|
3329 type() == booleanValue || type() == nullValue;
|
|
3330 case realValue:
|
|
3331 return isNumeric() || type() == booleanValue || type() == nullValue;
|
|
3332 case booleanValue:
|
|
3333 return isNumeric() || type() == booleanValue || type() == nullValue;
|
|
3334 case stringValue:
|
|
3335 return isNumeric() || type() == booleanValue || type() == stringValue ||
|
|
3336 type() == nullValue;
|
|
3337 case arrayValue:
|
|
3338 return type() == arrayValue || type() == nullValue;
|
|
3339 case objectValue:
|
|
3340 return type() == objectValue || type() == nullValue;
|
|
3341 }
|
|
3342 JSON_ASSERT_UNREACHABLE;
|
|
3343 return false;
|
|
3344 }
|
|
3345
|
|
3346 /// Number of values in array or object
|
|
3347 ArrayIndex Value::size() const {
|
|
3348 switch (type()) {
|
|
3349 case nullValue:
|
|
3350 case intValue:
|
|
3351 case uintValue:
|
|
3352 case realValue:
|
|
3353 case booleanValue:
|
|
3354 case stringValue:
|
|
3355 return 0;
|
|
3356 case arrayValue: // size of the array is highest index + 1
|
|
3357 if (!value_.map_->empty()) {
|
|
3358 ObjectValues::const_iterator itLast = value_.map_->end();
|
|
3359 --itLast;
|
|
3360 return (*itLast).first.index() + 1;
|
|
3361 }
|
|
3362 return 0;
|
|
3363 case objectValue:
|
|
3364 return ArrayIndex(value_.map_->size());
|
|
3365 }
|
|
3366 JSON_ASSERT_UNREACHABLE;
|
|
3367 return 0; // unreachable;
|
|
3368 }
|
|
3369
|
|
3370 bool Value::empty() const {
|
|
3371 if (isNull() || isArray() || isObject())
|
|
3372 return size() == 0u;
|
|
3373 else
|
|
3374 return false;
|
|
3375 }
|
|
3376
|
|
3377 Value::operator bool() const { return !isNull(); }
|
|
3378
|
|
3379 void Value::clear() {
|
|
3380 JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue ||
|
|
3381 type() == objectValue,
|
|
3382 "in Json::Value::clear(): requires complex value");
|
|
3383 start_ = 0;
|
|
3384 limit_ = 0;
|
|
3385 switch (type()) {
|
|
3386 case arrayValue:
|
|
3387 case objectValue:
|
|
3388 value_.map_->clear();
|
|
3389 break;
|
|
3390 default:
|
|
3391 break;
|
|
3392 }
|
|
3393 }
|
|
3394
|
|
3395 void Value::resize(ArrayIndex newSize) {
|
|
3396 JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
|
|
3397 "in Json::Value::resize(): requires arrayValue");
|
|
3398 if (type() == nullValue)
|
|
3399 *this = Value(arrayValue);
|
|
3400 ArrayIndex oldSize = size();
|
|
3401 if (newSize == 0)
|
|
3402 clear();
|
|
3403 else if (newSize > oldSize)
|
|
3404 this->operator[](newSize - 1);
|
|
3405 else {
|
|
3406 for (ArrayIndex index = newSize; index < oldSize; ++index) {
|
|
3407 value_.map_->erase(index);
|
|
3408 }
|
|
3409 JSON_ASSERT(size() == newSize);
|
|
3410 }
|
|
3411 }
|
|
3412
|
|
3413 Value& Value::operator[](ArrayIndex index) {
|
|
3414 JSON_ASSERT_MESSAGE(
|
|
3415 type() == nullValue || type() == arrayValue,
|
|
3416 "in Json::Value::operator[](ArrayIndex): requires arrayValue");
|
|
3417 if (type() == nullValue)
|
|
3418 *this = Value(arrayValue);
|
|
3419 CZString key(index);
|
|
3420 auto it = value_.map_->lower_bound(key);
|
|
3421 if (it != value_.map_->end() && (*it).first == key)
|
|
3422 return (*it).second;
|
|
3423
|
|
3424 ObjectValues::value_type defaultValue(key, nullSingleton());
|
|
3425 it = value_.map_->insert(it, defaultValue);
|
|
3426 return (*it).second;
|
|
3427 }
|
|
3428
|
|
3429 Value& Value::operator[](int index) {
|
|
3430 JSON_ASSERT_MESSAGE(
|
|
3431 index >= 0,
|
|
3432 "in Json::Value::operator[](int index): index cannot be negative");
|
|
3433 return (*this)[ArrayIndex(index)];
|
|
3434 }
|
|
3435
|
|
3436 const Value& Value::operator[](ArrayIndex index) const {
|
|
3437 JSON_ASSERT_MESSAGE(
|
|
3438 type() == nullValue || type() == arrayValue,
|
|
3439 "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
|
|
3440 if (type() == nullValue)
|
|
3441 return nullSingleton();
|
|
3442 CZString key(index);
|
|
3443 ObjectValues::const_iterator it = value_.map_->find(key);
|
|
3444 if (it == value_.map_->end())
|
|
3445 return nullSingleton();
|
|
3446 return (*it).second;
|
|
3447 }
|
|
3448
|
|
3449 const Value& Value::operator[](int index) const {
|
|
3450 JSON_ASSERT_MESSAGE(
|
|
3451 index >= 0,
|
|
3452 "in Json::Value::operator[](int index) const: index cannot be negative");
|
|
3453 return (*this)[ArrayIndex(index)];
|
|
3454 }
|
|
3455
|
|
3456 void Value::initBasic(ValueType type, bool allocated) {
|
|
3457 setType(type);
|
|
3458 setIsAllocated(allocated);
|
|
3459 comments_ = nullptr;
|
|
3460 start_ = 0;
|
|
3461 limit_ = 0;
|
|
3462 }
|
|
3463
|
|
3464 void Value::dupPayload(const Value& other) {
|
|
3465 setType(other.type());
|
|
3466 setIsAllocated(false);
|
|
3467 switch (type()) {
|
|
3468 case nullValue:
|
|
3469 case intValue:
|
|
3470 case uintValue:
|
|
3471 case realValue:
|
|
3472 case booleanValue:
|
|
3473 value_ = other.value_;
|
|
3474 break;
|
|
3475 case stringValue:
|
|
3476 if (other.value_.string_ && other.isAllocated()) {
|
|
3477 unsigned len;
|
|
3478 char const* str;
|
|
3479 decodePrefixedString(other.isAllocated(), other.value_.string_, &len,
|
|
3480 &str);
|
|
3481 value_.string_ = duplicateAndPrefixStringValue(str, len);
|
|
3482 setIsAllocated(true);
|
|
3483 } else {
|
|
3484 value_.string_ = other.value_.string_;
|
|
3485 }
|
|
3486 break;
|
|
3487 case arrayValue:
|
|
3488 case objectValue:
|
|
3489 value_.map_ = new ObjectValues(*other.value_.map_);
|
|
3490 break;
|
|
3491 default:
|
|
3492 JSON_ASSERT_UNREACHABLE;
|
|
3493 }
|
|
3494 }
|
|
3495
|
|
3496 void Value::releasePayload() {
|
|
3497 switch (type()) {
|
|
3498 case nullValue:
|
|
3499 case intValue:
|
|
3500 case uintValue:
|
|
3501 case realValue:
|
|
3502 case booleanValue:
|
|
3503 break;
|
|
3504 case stringValue:
|
|
3505 if (isAllocated())
|
|
3506 releasePrefixedStringValue(value_.string_);
|
|
3507 break;
|
|
3508 case arrayValue:
|
|
3509 case objectValue:
|
|
3510 delete value_.map_;
|
|
3511 break;
|
|
3512 default:
|
|
3513 JSON_ASSERT_UNREACHABLE;
|
|
3514 }
|
|
3515 }
|
|
3516
|
|
3517 void Value::dupMeta(const Value& other) {
|
|
3518 if (other.comments_) {
|
|
3519 comments_ = new CommentInfo[numberOfCommentPlacement];
|
|
3520 for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
|
|
3521 const CommentInfo& otherComment = other.comments_[comment];
|
|
3522 if (otherComment.comment_)
|
|
3523 comments_[comment].setComment(otherComment.comment_,
|
|
3524 strlen(otherComment.comment_));
|
|
3525 }
|
|
3526 } else {
|
|
3527 comments_ = nullptr;
|
|
3528 }
|
|
3529 start_ = other.start_;
|
|
3530 limit_ = other.limit_;
|
|
3531 }
|
|
3532
|
|
3533 // Access an object value by name, create a null member if it does not exist.
|
|
3534 // @pre Type of '*this' is object or null.
|
|
3535 // @param key is null-terminated.
|
|
3536 Value& Value::resolveReference(const char* key) {
|
|
3537 JSON_ASSERT_MESSAGE(
|
|
3538 type() == nullValue || type() == objectValue,
|
|
3539 "in Json::Value::resolveReference(): requires objectValue");
|
|
3540 if (type() == nullValue)
|
|
3541 *this = Value(objectValue);
|
|
3542 CZString actualKey(key, static_cast<unsigned>(strlen(key)),
|
|
3543 CZString::noDuplication); // NOTE!
|
|
3544 auto it = value_.map_->lower_bound(actualKey);
|
|
3545 if (it != value_.map_->end() && (*it).first == actualKey)
|
|
3546 return (*it).second;
|
|
3547
|
|
3548 ObjectValues::value_type defaultValue(actualKey, nullSingleton());
|
|
3549 it = value_.map_->insert(it, defaultValue);
|
|
3550 Value& value = (*it).second;
|
|
3551 return value;
|
|
3552 }
|
|
3553
|
|
3554 // @param key is not null-terminated.
|
|
3555 Value& Value::resolveReference(char const* key, char const* end) {
|
|
3556 JSON_ASSERT_MESSAGE(
|
|
3557 type() == nullValue || type() == objectValue,
|
|
3558 "in Json::Value::resolveReference(key, end): requires objectValue");
|
|
3559 if (type() == nullValue)
|
|
3560 *this = Value(objectValue);
|
|
3561 CZString actualKey(key, static_cast<unsigned>(end - key),
|
|
3562 CZString::duplicateOnCopy);
|
|
3563 auto it = value_.map_->lower_bound(actualKey);
|
|
3564 if (it != value_.map_->end() && (*it).first == actualKey)
|
|
3565 return (*it).second;
|
|
3566
|
|
3567 ObjectValues::value_type defaultValue(actualKey, nullSingleton());
|
|
3568 it = value_.map_->insert(it, defaultValue);
|
|
3569 Value& value = (*it).second;
|
|
3570 return value;
|
|
3571 }
|
|
3572
|
|
3573 Value Value::get(ArrayIndex index, const Value& defaultValue) const {
|
|
3574 const Value* value = &((*this)[index]);
|
|
3575 return value == &nullSingleton() ? defaultValue : *value;
|
|
3576 }
|
|
3577
|
|
3578 bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
|
|
3579
|
|
3580 Value const* Value::find(char const* begin, char const* end) const {
|
|
3581 JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
|
|
3582 "in Json::Value::find(key, end, found): requires "
|
|
3583 "objectValue or nullValue");
|
|
3584 if (type() == nullValue)
|
|
3585 return nullptr;
|
|
3586 CZString actualKey(begin, static_cast<unsigned>(end - begin),
|
|
3587 CZString::noDuplication);
|
|
3588 ObjectValues::const_iterator it = value_.map_->find(actualKey);
|
|
3589 if (it == value_.map_->end())
|
|
3590 return nullptr;
|
|
3591 return &(*it).second;
|
|
3592 }
|
|
3593 const Value& Value::operator[](const char* key) const {
|
|
3594 Value const* found = find(key, key + strlen(key));
|
|
3595 if (!found)
|
|
3596 return nullSingleton();
|
|
3597 return *found;
|
|
3598 }
|
|
3599 Value const& Value::operator[](const String& key) const {
|
|
3600 Value const* found = find(key.data(), key.data() + key.length());
|
|
3601 if (!found)
|
|
3602 return nullSingleton();
|
|
3603 return *found;
|
|
3604 }
|
|
3605
|
|
3606 Value& Value::operator[](const char* key) {
|
|
3607 return resolveReference(key, key + strlen(key));
|
|
3608 }
|
|
3609
|
|
3610 Value& Value::operator[](const String& key) {
|
|
3611 return resolveReference(key.data(), key.data() + key.length());
|
|
3612 }
|
|
3613
|
|
3614 Value& Value::operator[](const StaticString& key) {
|
|
3615 return resolveReference(key.c_str());
|
|
3616 }
|
|
3617
|
|
3618 #ifdef JSON_USE_CPPTL
|
|
3619 Value& Value::operator[](const CppTL::ConstString& key) {
|
|
3620 return resolveReference(key.c_str(), key.end_c_str());
|
|
3621 }
|
|
3622 Value const& Value::operator[](CppTL::ConstString const& key) const {
|
|
3623 Value const* found = find(key.c_str(), key.end_c_str());
|
|
3624 if (!found)
|
|
3625 return nullSingleton();
|
|
3626 return *found;
|
|
3627 }
|
|
3628 #endif
|
|
3629
|
|
3630 Value& Value::append(const Value& value) { return (*this)[size()] = value; }
|
|
3631
|
|
3632 #if JSON_HAS_RVALUE_REFERENCES
|
|
3633 Value& Value::append(Value&& value) {
|
|
3634 return (*this)[size()] = std::move(value);
|
|
3635 }
|
|
3636 #endif
|
|
3637
|
|
3638 Value Value::get(char const* begin,
|
|
3639 char const* end,
|
|
3640 Value const& defaultValue) const {
|
|
3641 Value const* found = find(begin, end);
|
|
3642 return !found ? defaultValue : *found;
|
|
3643 }
|
|
3644 Value Value::get(char const* key, Value const& defaultValue) const {
|
|
3645 return get(key, key + strlen(key), defaultValue);
|
|
3646 }
|
|
3647 Value Value::get(String const& key, Value const& defaultValue) const {
|
|
3648 return get(key.data(), key.data() + key.length(), defaultValue);
|
|
3649 }
|
|
3650
|
|
3651 bool Value::removeMember(const char* begin, const char* end, Value* removed) {
|
|
3652 if (type() != objectValue) {
|
|
3653 return false;
|
|
3654 }
|
|
3655 CZString actualKey(begin, static_cast<unsigned>(end - begin),
|
|
3656 CZString::noDuplication);
|
|
3657 auto it = value_.map_->find(actualKey);
|
|
3658 if (it == value_.map_->end())
|
|
3659 return false;
|
|
3660 if (removed)
|
|
3661 #if JSON_HAS_RVALUE_REFERENCES
|
|
3662 *removed = std::move(it->second);
|
|
3663 #else
|
|
3664 *removed = it->second;
|
|
3665 #endif
|
|
3666 value_.map_->erase(it);
|
|
3667 return true;
|
|
3668 }
|
|
3669 bool Value::removeMember(const char* key, Value* removed) {
|
|
3670 return removeMember(key, key + strlen(key), removed);
|
|
3671 }
|
|
3672 bool Value::removeMember(String const& key, Value* removed) {
|
|
3673 return removeMember(key.data(), key.data() + key.length(), removed);
|
|
3674 }
|
|
3675 void Value::removeMember(const char* key) {
|
|
3676 JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
|
|
3677 "in Json::Value::removeMember(): requires objectValue");
|
|
3678 if (type() == nullValue)
|
|
3679 return;
|
|
3680
|
|
3681 CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication);
|
|
3682 value_.map_->erase(actualKey);
|
|
3683 }
|
|
3684 void Value::removeMember(const String& key) { removeMember(key.c_str()); }
|
|
3685
|
|
3686 bool Value::removeIndex(ArrayIndex index, Value* removed) {
|
|
3687 if (type() != arrayValue) {
|
|
3688 return false;
|
|
3689 }
|
|
3690 CZString key(index);
|
|
3691 auto it = value_.map_->find(key);
|
|
3692 if (it == value_.map_->end()) {
|
|
3693 return false;
|
|
3694 }
|
|
3695 if (removed)
|
|
3696 *removed = it->second;
|
|
3697 ArrayIndex oldSize = size();
|
|
3698 // shift left all items left, into the place of the "removed"
|
|
3699 for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
|
|
3700 CZString keey(i);
|
|
3701 (*value_.map_)[keey] = (*this)[i + 1];
|
|
3702 }
|
|
3703 // erase the last one ("leftover")
|
|
3704 CZString keyLast(oldSize - 1);
|
|
3705 auto itLast = value_.map_->find(keyLast);
|
|
3706 value_.map_->erase(itLast);
|
|
3707 return true;
|
|
3708 }
|
|
3709
|
|
3710 #ifdef JSON_USE_CPPTL
|
|
3711 Value Value::get(const CppTL::ConstString& key,
|
|
3712 const Value& defaultValue) const {
|
|
3713 return get(key.c_str(), key.end_c_str(), defaultValue);
|
|
3714 }
|
|
3715 #endif
|
|
3716
|
|
3717 bool Value::isMember(char const* begin, char const* end) const {
|
|
3718 Value const* value = find(begin, end);
|
|
3719 return nullptr != value;
|
|
3720 }
|
|
3721 bool Value::isMember(char const* key) const {
|
|
3722 return isMember(key, key + strlen(key));
|
|
3723 }
|
|
3724 bool Value::isMember(String const& key) const {
|
|
3725 return isMember(key.data(), key.data() + key.length());
|
|
3726 }
|
|
3727
|
|
3728 #ifdef JSON_USE_CPPTL
|
|
3729 bool Value::isMember(const CppTL::ConstString& key) const {
|
|
3730 return isMember(key.c_str(), key.end_c_str());
|
|
3731 }
|
|
3732 #endif
|
|
3733
|
|
3734 Value::Members Value::getMemberNames() const {
|
|
3735 JSON_ASSERT_MESSAGE(
|
|
3736 type() == nullValue || type() == objectValue,
|
|
3737 "in Json::Value::getMemberNames(), value must be objectValue");
|
|
3738 if (type() == nullValue)
|
|
3739 return Value::Members();
|
|
3740 Members members;
|
|
3741 members.reserve(value_.map_->size());
|
|
3742 ObjectValues::const_iterator it = value_.map_->begin();
|
|
3743 ObjectValues::const_iterator itEnd = value_.map_->end();
|
|
3744 for (; it != itEnd; ++it) {
|
|
3745 members.push_back(String((*it).first.data(), (*it).first.length()));
|
|
3746 }
|
|
3747 return members;
|
|
3748 }
|
|
3749 //
|
|
3750 //# ifdef JSON_USE_CPPTL
|
|
3751 // EnumMemberNames
|
|
3752 // Value::enumMemberNames() const
|
|
3753 //{
|
|
3754 // if ( type() == objectValue )
|
|
3755 // {
|
|
3756 // return CppTL::Enum::any( CppTL::Enum::transform(
|
|
3757 // CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
|
|
3758 // MemberNamesTransform() ) );
|
|
3759 // }
|
|
3760 // return EnumMemberNames();
|
|
3761 //}
|
|
3762 //
|
|
3763 //
|
|
3764 // EnumValues
|
|
3765 // Value::enumValues() const
|
|
3766 //{
|
|
3767 // if ( type() == objectValue || type() == arrayValue )
|
|
3768 // return CppTL::Enum::anyValues( *(value_.map_),
|
|
3769 // CppTL::Type<const Value &>() );
|
|
3770 // return EnumValues();
|
|
3771 //}
|
|
3772 //
|
|
3773 //# endif
|
|
3774
|
|
3775 static bool IsIntegral(double d) {
|
|
3776 double integral_part;
|
|
3777 return modf(d, &integral_part) == 0.0;
|
|
3778 }
|
|
3779
|
|
3780 bool Value::isNull() const { return type() == nullValue; }
|
|
3781
|
|
3782 bool Value::isBool() const { return type() == booleanValue; }
|
|
3783
|
|
3784 bool Value::isInt() const {
|
|
3785 switch (type()) {
|
|
3786 case intValue:
|
|
3787 #if defined(JSON_HAS_INT64)
|
|
3788 return value_.int_ >= minInt && value_.int_ <= maxInt;
|
|
3789 #else
|
|
3790 return true;
|
|
3791 #endif
|
|
3792 case uintValue:
|
|
3793 return value_.uint_ <= UInt(maxInt);
|
|
3794 case realValue:
|
|
3795 return value_.real_ >= minInt && value_.real_ <= maxInt &&
|
|
3796 IsIntegral(value_.real_);
|
|
3797 default:
|
|
3798 break;
|
|
3799 }
|
|
3800 return false;
|
|
3801 }
|
|
3802
|
|
3803 bool Value::isUInt() const {
|
|
3804 switch (type()) {
|
|
3805 case intValue:
|
|
3806 #if defined(JSON_HAS_INT64)
|
|
3807 return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
|
|
3808 #else
|
|
3809 return value_.int_ >= 0;
|
|
3810 #endif
|
|
3811 case uintValue:
|
|
3812 #if defined(JSON_HAS_INT64)
|
|
3813 return value_.uint_ <= maxUInt;
|
|
3814 #else
|
|
3815 return true;
|
|
3816 #endif
|
|
3817 case realValue:
|
|
3818 return value_.real_ >= 0 && value_.real_ <= maxUInt &&
|
|
3819 IsIntegral(value_.real_);
|
|
3820 default:
|
|
3821 break;
|
|
3822 }
|
|
3823 return false;
|
|
3824 }
|
|
3825
|
|
3826 bool Value::isInt64() const {
|
|
3827 #if defined(JSON_HAS_INT64)
|
|
3828 switch (type()) {
|
|
3829 case intValue:
|
|
3830 return true;
|
|
3831 case uintValue:
|
|
3832 return value_.uint_ <= UInt64(maxInt64);
|
|
3833 case realValue:
|
|
3834 // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
|
|
3835 // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
|
|
3836 // require the value to be strictly less than the limit.
|
|
3837 return value_.real_ >= double(minInt64) &&
|
|
3838 value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
|
|
3839 default:
|
|
3840 break;
|
|
3841 }
|
|
3842 #endif // JSON_HAS_INT64
|
|
3843 return false;
|
|
3844 }
|
|
3845
|
|
3846 bool Value::isUInt64() const {
|
|
3847 #if defined(JSON_HAS_INT64)
|
|
3848 switch (type()) {
|
|
3849 case intValue:
|
|
3850 return value_.int_ >= 0;
|
|
3851 case uintValue:
|
|
3852 return true;
|
|
3853 case realValue:
|
|
3854 // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
|
|
3855 // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
|
|
3856 // require the value to be strictly less than the limit.
|
|
3857 return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
|
|
3858 IsIntegral(value_.real_);
|
|
3859 default:
|
|
3860 break;
|
|
3861 }
|
|
3862 #endif // JSON_HAS_INT64
|
|
3863 return false;
|
|
3864 }
|
|
3865
|
|
3866 bool Value::isIntegral() const {
|
|
3867 switch (type()) {
|
|
3868 case intValue:
|
|
3869 case uintValue:
|
|
3870 return true;
|
|
3871 case realValue:
|
|
3872 #if defined(JSON_HAS_INT64)
|
|
3873 // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
|
|
3874 // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
|
|
3875 // require the value to be strictly less than the limit.
|
|
3876 return value_.real_ >= double(minInt64) &&
|
|
3877 value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
|
|
3878 #else
|
|
3879 return value_.real_ >= minInt && value_.real_ <= maxUInt &&
|
|
3880 IsIntegral(value_.real_);
|
|
3881 #endif // JSON_HAS_INT64
|
|
3882 default:
|
|
3883 break;
|
|
3884 }
|
|
3885 return false;
|
|
3886 }
|
|
3887
|
|
3888 bool Value::isDouble() const {
|
|
3889 return type() == intValue || type() == uintValue || type() == realValue;
|
|
3890 }
|
|
3891
|
|
3892 bool Value::isNumeric() const { return isDouble(); }
|
|
3893
|
|
3894 bool Value::isString() const { return type() == stringValue; }
|
|
3895
|
|
3896 bool Value::isArray() const { return type() == arrayValue; }
|
|
3897
|
|
3898 bool Value::isObject() const { return type() == objectValue; }
|
|
3899
|
|
3900 void Value::setComment(const char* comment,
|
|
3901 size_t len,
|
|
3902 CommentPlacement placement) {
|
|
3903 if (!comments_)
|
|
3904 comments_ = new CommentInfo[numberOfCommentPlacement];
|
|
3905 if ((len > 0) && (comment[len - 1] == '\n')) {
|
|
3906 // Always discard trailing newline, to aid indentation.
|
|
3907 len -= 1;
|
|
3908 }
|
|
3909 comments_[placement].setComment(comment, len);
|
|
3910 }
|
|
3911
|
|
3912 void Value::setComment(const char* comment, CommentPlacement placement) {
|
|
3913 setComment(comment, strlen(comment), placement);
|
|
3914 }
|
|
3915
|
|
3916 void Value::setComment(const String& comment, CommentPlacement placement) {
|
|
3917 setComment(comment.c_str(), comment.length(), placement);
|
|
3918 }
|
|
3919
|
|
3920 bool Value::hasComment(CommentPlacement placement) const {
|
|
3921 return comments_ != nullptr && comments_[placement].comment_ != nullptr;
|
|
3922 }
|
|
3923
|
|
3924 String Value::getComment(CommentPlacement placement) const {
|
|
3925 if (hasComment(placement))
|
|
3926 return comments_[placement].comment_;
|
|
3927 return "";
|
|
3928 }
|
|
3929
|
|
3930 void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }
|
|
3931
|
|
3932 void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; }
|
|
3933
|
|
3934 ptrdiff_t Value::getOffsetStart() const { return start_; }
|
|
3935
|
|
3936 ptrdiff_t Value::getOffsetLimit() const { return limit_; }
|
|
3937
|
|
3938 String Value::toStyledString() const {
|
|
3939 StreamWriterBuilder builder;
|
|
3940
|
|
3941 String out = this->hasComment(commentBefore) ? "\n" : "";
|
|
3942 out += Json::writeString(builder, *this);
|
|
3943 out += '\n';
|
|
3944
|
|
3945 return out;
|
|
3946 }
|
|
3947
|
|
3948 Value::const_iterator Value::begin() const {
|
|
3949 switch (type()) {
|
|
3950 case arrayValue:
|
|
3951 case objectValue:
|
|
3952 if (value_.map_)
|
|
3953 return const_iterator(value_.map_->begin());
|
|
3954 break;
|
|
3955 default:
|
|
3956 break;
|
|
3957 }
|
|
3958 return {};
|
|
3959 }
|
|
3960
|
|
3961 Value::const_iterator Value::end() const {
|
|
3962 switch (type()) {
|
|
3963 case arrayValue:
|
|
3964 case objectValue:
|
|
3965 if (value_.map_)
|
|
3966 return const_iterator(value_.map_->end());
|
|
3967 break;
|
|
3968 default:
|
|
3969 break;
|
|
3970 }
|
|
3971 return {};
|
|
3972 }
|
|
3973
|
|
3974 Value::iterator Value::begin() {
|
|
3975 switch (type()) {
|
|
3976 case arrayValue:
|
|
3977 case objectValue:
|
|
3978 if (value_.map_)
|
|
3979 return iterator(value_.map_->begin());
|
|
3980 break;
|
|
3981 default:
|
|
3982 break;
|
|
3983 }
|
|
3984 return iterator();
|
|
3985 }
|
|
3986
|
|
3987 Value::iterator Value::end() {
|
|
3988 switch (type()) {
|
|
3989 case arrayValue:
|
|
3990 case objectValue:
|
|
3991 if (value_.map_)
|
|
3992 return iterator(value_.map_->end());
|
|
3993 break;
|
|
3994 default:
|
|
3995 break;
|
|
3996 }
|
|
3997 return iterator();
|
|
3998 }
|
|
3999
|
|
4000 // class PathArgument
|
|
4001 // //////////////////////////////////////////////////////////////////
|
|
4002
|
|
4003 PathArgument::PathArgument() : key_() {}
|
|
4004
|
|
4005 PathArgument::PathArgument(ArrayIndex index)
|
|
4006 : key_(), index_(index), kind_(kindIndex) {}
|
|
4007
|
|
4008 PathArgument::PathArgument(const char* key)
|
|
4009 : key_(key), index_(), kind_(kindKey) {}
|
|
4010
|
|
4011 PathArgument::PathArgument(const String& key)
|
|
4012 : key_(key.c_str()), index_(), kind_(kindKey) {}
|
|
4013
|
|
4014 // class Path
|
|
4015 // //////////////////////////////////////////////////////////////////
|
|
4016
|
|
4017 Path::Path(const String& path,
|
|
4018 const PathArgument& a1,
|
|
4019 const PathArgument& a2,
|
|
4020 const PathArgument& a3,
|
|
4021 const PathArgument& a4,
|
|
4022 const PathArgument& a5) {
|
|
4023 InArgs in;
|
|
4024 in.reserve(5);
|
|
4025 in.push_back(&a1);
|
|
4026 in.push_back(&a2);
|
|
4027 in.push_back(&a3);
|
|
4028 in.push_back(&a4);
|
|
4029 in.push_back(&a5);
|
|
4030 makePath(path, in);
|
|
4031 }
|
|
4032
|
|
4033 void Path::makePath(const String& path, const InArgs& in) {
|
|
4034 const char* current = path.c_str();
|
|
4035 const char* end = current + path.length();
|
|
4036 auto itInArg = in.begin();
|
|
4037 while (current != end) {
|
|
4038 if (*current == '[') {
|
|
4039 ++current;
|
|
4040 if (*current == '%')
|
|
4041 addPathInArg(path, in, itInArg, PathArgument::kindIndex);
|
|
4042 else {
|
|
4043 ArrayIndex index = 0;
|
|
4044 for (; current != end && *current >= '0' && *current <= '9'; ++current)
|
|
4045 index = index * 10 + ArrayIndex(*current - '0');
|
|
4046 args_.push_back(index);
|
|
4047 }
|
|
4048 if (current == end || *++current != ']')
|
|
4049 invalidPath(path, int(current - path.c_str()));
|
|
4050 } else if (*current == '%') {
|
|
4051 addPathInArg(path, in, itInArg, PathArgument::kindKey);
|
|
4052 ++current;
|
|
4053 } else if (*current == '.' || *current == ']') {
|
|
4054 ++current;
|
|
4055 } else {
|
|
4056 const char* beginName = current;
|
|
4057 while (current != end && !strchr("[.", *current))
|
|
4058 ++current;
|
|
4059 args_.push_back(String(beginName, current));
|
|
4060 }
|
|
4061 }
|
|
4062 }
|
|
4063
|
|
4064 void Path::addPathInArg(const String& /*path*/,
|
|
4065 const InArgs& in,
|
|
4066 InArgs::const_iterator& itInArg,
|
|
4067 PathArgument::Kind kind) {
|
|
4068 if (itInArg == in.end()) {
|
|
4069 // Error: missing argument %d
|
|
4070 } else if ((*itInArg)->kind_ != kind) {
|
|
4071 // Error: bad argument type
|
|
4072 } else {
|
|
4073 args_.push_back(**itInArg++);
|
|
4074 }
|
|
4075 }
|
|
4076
|
|
4077 void Path::invalidPath(const String& /*path*/, int /*location*/) {
|
|
4078 // Error: invalid path.
|
|
4079 }
|
|
4080
|
|
4081 const Value& Path::resolve(const Value& root) const {
|
|
4082 const Value* node = &root;
|
|
4083 for (const auto& arg : args_) {
|
|
4084 if (arg.kind_ == PathArgument::kindIndex) {
|
|
4085 if (!node->isArray() || !node->isValidIndex(arg.index_)) {
|
|
4086 // Error: unable to resolve path (array value expected at position...
|
|
4087 return Value::null;
|
|
4088 }
|
|
4089 node = &((*node)[arg.index_]);
|
|
4090 } else if (arg.kind_ == PathArgument::kindKey) {
|
|
4091 if (!node->isObject()) {
|
|
4092 // Error: unable to resolve path (object value expected at position...)
|
|
4093 return Value::null;
|
|
4094 }
|
|
4095 node = &((*node)[arg.key_]);
|
|
4096 if (node == &Value::nullSingleton()) {
|
|
4097 // Error: unable to resolve path (object has no member named '' at
|
|
4098 // position...)
|
|
4099 return Value::null;
|
|
4100 }
|
|
4101 }
|
|
4102 }
|
|
4103 return *node;
|
|
4104 }
|
|
4105
|
|
4106 Value Path::resolve(const Value& root, const Value& defaultValue) const {
|
|
4107 const Value* node = &root;
|
|
4108 for (const auto& arg : args_) {
|
|
4109 if (arg.kind_ == PathArgument::kindIndex) {
|
|
4110 if (!node->isArray() || !node->isValidIndex(arg.index_))
|
|
4111 return defaultValue;
|
|
4112 node = &((*node)[arg.index_]);
|
|
4113 } else if (arg.kind_ == PathArgument::kindKey) {
|
|
4114 if (!node->isObject())
|
|
4115 return defaultValue;
|
|
4116 node = &((*node)[arg.key_]);
|
|
4117 if (node == &Value::nullSingleton())
|
|
4118 return defaultValue;
|
|
4119 }
|
|
4120 }
|
|
4121 return *node;
|
|
4122 }
|
|
4123
|
|
4124 Value& Path::make(Value& root) const {
|
|
4125 Value* node = &root;
|
|
4126 for (const auto& arg : args_) {
|
|
4127 if (arg.kind_ == PathArgument::kindIndex) {
|
|
4128 if (!node->isArray()) {
|
|
4129 // Error: node is not an array at position ...
|
|
4130 }
|
|
4131 node = &((*node)[arg.index_]);
|
|
4132 } else if (arg.kind_ == PathArgument::kindKey) {
|
|
4133 if (!node->isObject()) {
|
|
4134 // Error: node is not an object at position...
|
|
4135 }
|
|
4136 node = &((*node)[arg.key_]);
|
|
4137 }
|
|
4138 }
|
|
4139 return *node;
|
|
4140 }
|
|
4141
|
|
4142 } // namespace Json
|
|
4143
|
|
4144 // //////////////////////////////////////////////////////////////////////
|
|
4145 // End of content of file: src/lib_json/json_value.cpp
|
|
4146 // //////////////////////////////////////////////////////////////////////
|
|
4147
|
|
4148
|
|
4149
|
|
4150
|
|
4151
|
|
4152
|
|
4153 // //////////////////////////////////////////////////////////////////////
|
|
4154 // Beginning of content of file: src/lib_json/json_writer.cpp
|
|
4155 // //////////////////////////////////////////////////////////////////////
|
|
4156
|
|
4157 // Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
|
|
4158 // Distributed under MIT license, or public domain if desired and
|
|
4159 // recognized in your jurisdiction.
|
|
4160 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
|
4161
|
|
4162 #if !defined(JSON_IS_AMALGAMATION)
|
|
4163 #include "json_tool.h"
|
|
4164 #include <json/writer.h>
|
|
4165 #endif // if !defined(JSON_IS_AMALGAMATION)
|
|
4166 #include <cassert>
|
|
4167 #include <cstring>
|
|
4168 #include <iomanip>
|
|
4169 #include <memory>
|
|
4170 #include <set>
|
|
4171 #include <sstream>
|
|
4172 #include <utility>
|
|
4173
|
|
4174 #if __cplusplus >= 201103L
|
|
4175 #include <cmath>
|
|
4176 #include <cstdio>
|
|
4177
|
|
4178 #if !defined(isnan)
|
|
4179 #define isnan std::isnan
|
|
4180 #endif
|
|
4181
|
|
4182 #if !defined(isfinite)
|
|
4183 #define isfinite std::isfinite
|
|
4184 #endif
|
|
4185
|
|
4186 #else
|
|
4187 #include <cmath>
|
|
4188 #include <cstdio>
|
|
4189
|
|
4190 #if defined(_MSC_VER)
|
|
4191 #if !defined(isnan)
|
|
4192 #include <float.h>
|
|
4193 #define isnan _isnan
|
|
4194 #endif
|
|
4195
|
|
4196 #if !defined(isfinite)
|
|
4197 #include <float.h>
|
|
4198 #define isfinite _finite
|
|
4199 #endif
|
|
4200
|
|
4201 #if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
|
|
4202 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
|
|
4203 #endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
|
|
4204
|
|
4205 #endif //_MSC_VER
|
|
4206
|
|
4207 #if defined(__sun) && defined(__SVR4) // Solaris
|
|
4208 #if !defined(isfinite)
|
|
4209 #include <ieeefp.h>
|
|
4210 #define isfinite finite
|
|
4211 #endif
|
|
4212 #endif
|
|
4213
|
|
4214 #if defined(__hpux)
|
|
4215 #if !defined(isfinite)
|
|
4216 #if defined(__ia64) && !defined(finite)
|
|
4217 #define isfinite(x) \
|
|
4218 ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x)))
|
|
4219 #endif
|
|
4220 #endif
|
|
4221 #endif
|
|
4222
|
|
4223 #if !defined(isnan)
|
|
4224 // IEEE standard states that NaN values will not compare to themselves
|
|
4225 #define isnan(x) (x != x)
|
|
4226 #endif
|
|
4227
|
|
4228 #if !defined(__APPLE__)
|
|
4229 #if !defined(isfinite)
|
|
4230 #define isfinite finite
|
|
4231 #endif
|
|
4232 #endif
|
|
4233 #endif
|
|
4234
|
|
4235 #if defined(_MSC_VER)
|
|
4236 // Disable warning about strdup being deprecated.
|
|
4237 #pragma warning(disable : 4996)
|
|
4238 #endif
|
|
4239
|
|
4240 namespace Json {
|
|
4241
|
|
4242 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
|
|
4243 typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
|
|
4244 #else
|
|
4245 typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
|
|
4246 #endif
|
|
4247
|
|
4248 String valueToString(LargestInt value) {
|
|
4249 UIntToStringBuffer buffer;
|
|
4250 char* current = buffer + sizeof(buffer);
|
|
4251 if (value == Value::minLargestInt) {
|
|
4252 uintToString(LargestUInt(Value::maxLargestInt) + 1, current);
|
|
4253 *--current = '-';
|
|
4254 } else if (value < 0) {
|
|
4255 uintToString(LargestUInt(-value), current);
|
|
4256 *--current = '-';
|
|
4257 } else {
|
|
4258 uintToString(LargestUInt(value), current);
|
|
4259 }
|
|
4260 assert(current >= buffer);
|
|
4261 return current;
|
|
4262 }
|
|
4263
|
|
4264 String valueToString(LargestUInt value) {
|
|
4265 UIntToStringBuffer buffer;
|
|
4266 char* current = buffer + sizeof(buffer);
|
|
4267 uintToString(value, current);
|
|
4268 assert(current >= buffer);
|
|
4269 return current;
|
|
4270 }
|
|
4271
|
|
4272 #if defined(JSON_HAS_INT64)
|
|
4273
|
|
4274 String valueToString(Int value) { return valueToString(LargestInt(value)); }
|
|
4275
|
|
4276 String valueToString(UInt value) { return valueToString(LargestUInt(value)); }
|
|
4277
|
|
4278 #endif // # if defined(JSON_HAS_INT64)
|
|
4279
|
|
4280 namespace {
|
|
4281 String valueToString(double value,
|
|
4282 bool useSpecialFloats,
|
|
4283 unsigned int precision,
|
|
4284 PrecisionType precisionType) {
|
|
4285 // Print into the buffer. We need not request the alternative representation
|
|
4286 // that always has a decimal point because JSON doesn't distinguish the
|
|
4287 // concepts of reals and integers.
|
|
4288 if (!isfinite(value)) {
|
|
4289 static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"},
|
|
4290 {"null", "-1e+9999", "1e+9999"}};
|
|
4291 return reps[useSpecialFloats ? 0 : 1]
|
|
4292 [isnan(value) ? 0 : (value < 0) ? 1 : 2];
|
|
4293 }
|
|
4294
|
|
4295 String buffer(size_t(36), '\0');
|
|
4296 while (true) {
|
|
4297 int len = jsoncpp_snprintf(
|
|
4298 &*buffer.begin(), buffer.size(),
|
|
4299 (precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f",
|
|
4300 precision, value);
|
|
4301 assert(len >= 0);
|
|
4302 auto wouldPrint = static_cast<size_t>(len);
|
|
4303 if (wouldPrint >= buffer.size()) {
|
|
4304 buffer.resize(wouldPrint + 1);
|
|
4305 continue;
|
|
4306 }
|
|
4307 buffer.resize(wouldPrint);
|
|
4308 break;
|
|
4309 }
|
|
4310
|
|
4311 buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end());
|
|
4312
|
|
4313 // strip the zero padding from the right
|
|
4314 if (precisionType == PrecisionType::decimalPlaces) {
|
|
4315 buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end());
|
|
4316 }
|
|
4317
|
|
4318 // try to ensure we preserve the fact that this was given to us as a double on
|
|
4319 // input
|
|
4320 if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) {
|
|
4321 buffer += ".0";
|
|
4322 }
|
|
4323 return buffer;
|
|
4324 }
|
|
4325 } // namespace
|
|
4326
|
|
4327 String valueToString(double value,
|
|
4328 unsigned int precision,
|
|
4329 PrecisionType precisionType) {
|
|
4330 return valueToString(value, false, precision, precisionType);
|
|
4331 }
|
|
4332
|
|
4333 String valueToString(bool value) { return value ? "true" : "false"; }
|
|
4334
|
|
4335 static bool isAnyCharRequiredQuoting(char const* s, size_t n) {
|
|
4336 assert(s || !n);
|
|
4337
|
|
4338 char const* const end = s + n;
|
|
4339 for (char const* cur = s; cur < end; ++cur) {
|
|
4340 if (*cur == '\\' || *cur == '\"' || *cur < ' ' ||
|
|
4341 static_cast<unsigned char>(*cur) < 0x80)
|
|
4342 return true;
|
|
4343 }
|
|
4344 return false;
|
|
4345 }
|
|
4346
|
|
4347 static unsigned int utf8ToCodepoint(const char*& s, const char* e) {
|
|
4348 const unsigned int REPLACEMENT_CHARACTER = 0xFFFD;
|
|
4349
|
|
4350 unsigned int firstByte = static_cast<unsigned char>(*s);
|
|
4351
|
|
4352 if (firstByte < 0x80)
|
|
4353 return firstByte;
|
|
4354
|
|
4355 if (firstByte < 0xE0) {
|
|
4356 if (e - s < 2)
|
|
4357 return REPLACEMENT_CHARACTER;
|
|
4358
|
|
4359 unsigned int calculated =
|
|
4360 ((firstByte & 0x1F) << 6) | (static_cast<unsigned int>(s[1]) & 0x3F);
|
|
4361 s += 1;
|
|
4362 // oversized encoded characters are invalid
|
|
4363 return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated;
|
|
4364 }
|
|
4365
|
|
4366 if (firstByte < 0xF0) {
|
|
4367 if (e - s < 3)
|
|
4368 return REPLACEMENT_CHARACTER;
|
|
4369
|
|
4370 unsigned int calculated = ((firstByte & 0x0F) << 12) |
|
|
4371 ((static_cast<unsigned int>(s[1]) & 0x3F) << 6) |
|
|
4372 (static_cast<unsigned int>(s[2]) & 0x3F);
|
|
4373 s += 2;
|
|
4374 // surrogates aren't valid codepoints itself
|
|
4375 // shouldn't be UTF-8 encoded
|
|
4376 if (calculated >= 0xD800 && calculated <= 0xDFFF)
|
|
4377 return REPLACEMENT_CHARACTER;
|
|
4378 // oversized encoded characters are invalid
|
|
4379 return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated;
|
|
4380 }
|
|
4381
|
|
4382 if (firstByte < 0xF8) {
|
|
4383 if (e - s < 4)
|
|
4384 return REPLACEMENT_CHARACTER;
|
|
4385
|
|
4386 unsigned int calculated = ((firstByte & 0x07) << 18) |
|
|
4387 ((static_cast<unsigned int>(s[1]) & 0x3F) << 12) |
|
|
4388 ((static_cast<unsigned int>(s[2]) & 0x3F) << 6) |
|
|
4389 (static_cast<unsigned int>(s[3]) & 0x3F);
|
|
4390 s += 3;
|
|
4391 // oversized encoded characters are invalid
|
|
4392 return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated;
|
|
4393 }
|
|
4394
|
|
4395 return REPLACEMENT_CHARACTER;
|
|
4396 }
|
|
4397
|
|
4398 static const char hex2[] = "000102030405060708090a0b0c0d0e0f"
|
|
4399 "101112131415161718191a1b1c1d1e1f"
|
|
4400 "202122232425262728292a2b2c2d2e2f"
|
|
4401 "303132333435363738393a3b3c3d3e3f"
|
|
4402 "404142434445464748494a4b4c4d4e4f"
|
|
4403 "505152535455565758595a5b5c5d5e5f"
|
|
4404 "606162636465666768696a6b6c6d6e6f"
|
|
4405 "707172737475767778797a7b7c7d7e7f"
|
|
4406 "808182838485868788898a8b8c8d8e8f"
|
|
4407 "909192939495969798999a9b9c9d9e9f"
|
|
4408 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
|
|
4409 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
|
|
4410 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
|
|
4411 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
|
|
4412 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
|
|
4413 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
|
|
4414
|
|
4415 static String toHex16Bit(unsigned int x) {
|
|
4416 const unsigned int hi = (x >> 8) & 0xff;
|
|
4417 const unsigned int lo = x & 0xff;
|
|
4418 String result(4, ' ');
|
|
4419 result[0] = hex2[2 * hi];
|
|
4420 result[1] = hex2[2 * hi + 1];
|
|
4421 result[2] = hex2[2 * lo];
|
|
4422 result[3] = hex2[2 * lo + 1];
|
|
4423 return result;
|
|
4424 }
|
|
4425
|
|
4426 static String valueToQuotedStringN(const char* value, unsigned length) {
|
|
4427 if (value == nullptr)
|
|
4428 return "";
|
|
4429
|
|
4430 if (!isAnyCharRequiredQuoting(value, length))
|
|
4431 return String("\"") + value + "\"";
|
|
4432 // We have to walk value and escape any special characters.
|
|
4433 // Appending to String is not efficient, but this should be rare.
|
|
4434 // (Note: forward slashes are *not* rare, but I am not escaping them.)
|
|
4435 String::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL
|
|
4436 String result;
|
|
4437 result.reserve(maxsize); // to avoid lots of mallocs
|
|
4438 result += "\"";
|
|
4439 char const* end = value + length;
|
|
4440 for (const char* c = value; c != end; ++c) {
|
|
4441 switch (*c) {
|
|
4442 case '\"':
|
|
4443 result += "\\\"";
|
|
4444 break;
|
|
4445 case '\\':
|
|
4446 result += "\\\\";
|
|
4447 break;
|
|
4448 case '\b':
|
|
4449 result += "\\b";
|
|
4450 break;
|
|
4451 case '\f':
|
|
4452 result += "\\f";
|
|
4453 break;
|
|
4454 case '\n':
|
|
4455 result += "\\n";
|
|
4456 break;
|
|
4457 case '\r':
|
|
4458 result += "\\r";
|
|
4459 break;
|
|
4460 case '\t':
|
|
4461 result += "\\t";
|
|
4462 break;
|
|
4463 // case '/':
|
|
4464 // Even though \/ is considered a legal escape in JSON, a bare
|
|
4465 // slash is also legal, so I see no reason to escape it.
|
|
4466 // (I hope I am not misunderstanding something.)
|
|
4467 // blep notes: actually escaping \/ may be useful in javascript to avoid </
|
|
4468 // sequence.
|
|
4469 // Should add a flag to allow this compatibility mode and prevent this
|
|
4470 // sequence from occurring.
|
|
4471 default: {
|
|
4472 unsigned int cp = utf8ToCodepoint(c, end);
|
|
4473 // don't escape non-control characters
|
|
4474 // (short escape sequence are applied above)
|
|
4475 if (cp < 0x80 && cp >= 0x20)
|
|
4476 result += static_cast<char>(cp);
|
|
4477 else if (cp < 0x10000) { // codepoint is in Basic Multilingual Plane
|
|
4478 result += "\\u";
|
|
4479 result += toHex16Bit(cp);
|
|
4480 } else { // codepoint is not in Basic Multilingual Plane
|
|
4481 // convert to surrogate pair first
|
|
4482 cp -= 0x10000;
|
|
4483 result += "\\u";
|
|
4484 result += toHex16Bit((cp >> 10) + 0xD800);
|
|
4485 result += "\\u";
|
|
4486 result += toHex16Bit((cp & 0x3FF) + 0xDC00);
|
|
4487 }
|
|
4488 } break;
|
|
4489 }
|
|
4490 }
|
|
4491 result += "\"";
|
|
4492 return result;
|
|
4493 }
|
|
4494
|
|
4495 String valueToQuotedString(const char* value) {
|
|
4496 return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));
|
|
4497 }
|
|
4498
|
|
4499 // Class Writer
|
|
4500 // //////////////////////////////////////////////////////////////////
|
|
4501 Writer::~Writer() = default;
|
|
4502
|
|
4503 // Class FastWriter
|
|
4504 // //////////////////////////////////////////////////////////////////
|
|
4505
|
|
4506 FastWriter::FastWriter()
|
|
4507
|
|
4508 = default;
|
|
4509
|
|
4510 void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; }
|
|
4511
|
|
4512 void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
|
|
4513
|
|
4514 void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
|
|
4515
|
|
4516 String FastWriter::write(const Value& root) {
|
|
4517 document_.clear();
|
|
4518 writeValue(root);
|
|
4519 if (!omitEndingLineFeed_)
|
|
4520 document_ += '\n';
|
|
4521 return document_;
|
|
4522 }
|
|
4523
|
|
4524 void FastWriter::writeValue(const Value& value) {
|
|
4525 switch (value.type()) {
|
|
4526 case nullValue:
|
|
4527 if (!dropNullPlaceholders_)
|
|
4528 document_ += "null";
|
|
4529 break;
|
|
4530 case intValue:
|
|
4531 document_ += valueToString(value.asLargestInt());
|
|
4532 break;
|
|
4533 case uintValue:
|
|
4534 document_ += valueToString(value.asLargestUInt());
|
|
4535 break;
|
|
4536 case realValue:
|
|
4537 document_ += valueToString(value.asDouble());
|
|
4538 break;
|
|
4539 case stringValue: {
|
|
4540 // Is NULL possible for value.string_? No.
|
|
4541 char const* str;
|
|
4542 char const* end;
|
|
4543 bool ok = value.getString(&str, &end);
|
|
4544 if (ok)
|
|
4545 document_ += valueToQuotedStringN(str, static_cast<unsigned>(end - str));
|
|
4546 break;
|
|
4547 }
|
|
4548 case booleanValue:
|
|
4549 document_ += valueToString(value.asBool());
|
|
4550 break;
|
|
4551 case arrayValue: {
|
|
4552 document_ += '[';
|
|
4553 ArrayIndex size = value.size();
|
|
4554 for (ArrayIndex index = 0; index < size; ++index) {
|
|
4555 if (index > 0)
|
|
4556 document_ += ',';
|
|
4557 writeValue(value[index]);
|
|
4558 }
|
|
4559 document_ += ']';
|
|
4560 } break;
|
|
4561 case objectValue: {
|
|
4562 Value::Members members(value.getMemberNames());
|
|
4563 document_ += '{';
|
|
4564 for (auto it = members.begin(); it != members.end(); ++it) {
|
|
4565 const String& name = *it;
|
|
4566 if (it != members.begin())
|
|
4567 document_ += ',';
|
|
4568 document_ += valueToQuotedStringN(name.data(),
|
|
4569 static_cast<unsigned>(name.length()));
|
|
4570 document_ += yamlCompatibilityEnabled_ ? ": " : ":";
|
|
4571 writeValue(value[name]);
|
|
4572 }
|
|
4573 document_ += '}';
|
|
4574 } break;
|
|
4575 }
|
|
4576 }
|
|
4577
|
|
4578 // Class StyledWriter
|
|
4579 // //////////////////////////////////////////////////////////////////
|
|
4580
|
|
4581 StyledWriter::StyledWriter() = default;
|
|
4582
|
|
4583 String StyledWriter::write(const Value& root) {
|
|
4584 document_.clear();
|
|
4585 addChildValues_ = false;
|
|
4586 indentString_.clear();
|
|
4587 writeCommentBeforeValue(root);
|
|
4588 writeValue(root);
|
|
4589 writeCommentAfterValueOnSameLine(root);
|
|
4590 document_ += '\n';
|
|
4591 return document_;
|
|
4592 }
|
|
4593
|
|
4594 void StyledWriter::writeValue(const Value& value) {
|
|
4595 switch (value.type()) {
|
|
4596 case nullValue:
|
|
4597 pushValue("null");
|
|
4598 break;
|
|
4599 case intValue:
|
|
4600 pushValue(valueToString(value.asLargestInt()));
|
|
4601 break;
|
|
4602 case uintValue:
|
|
4603 pushValue(valueToString(value.asLargestUInt()));
|
|
4604 break;
|
|
4605 case realValue:
|
|
4606 pushValue(valueToString(value.asDouble()));
|
|
4607 break;
|
|
4608 case stringValue: {
|
|
4609 // Is NULL possible for value.string_? No.
|
|
4610 char const* str;
|
|
4611 char const* end;
|
|
4612 bool ok = value.getString(&str, &end);
|
|
4613 if (ok)
|
|
4614 pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
|
|
4615 else
|
|
4616 pushValue("");
|
|
4617 break;
|
|
4618 }
|
|
4619 case booleanValue:
|
|
4620 pushValue(valueToString(value.asBool()));
|
|
4621 break;
|
|
4622 case arrayValue:
|
|
4623 writeArrayValue(value);
|
|
4624 break;
|
|
4625 case objectValue: {
|
|
4626 Value::Members members(value.getMemberNames());
|
|
4627 if (members.empty())
|
|
4628 pushValue("{}");
|
|
4629 else {
|
|
4630 writeWithIndent("{");
|
|
4631 indent();
|
|
4632 auto it = members.begin();
|
|
4633 for (;;) {
|
|
4634 const String& name = *it;
|
|
4635 const Value& childValue = value[name];
|
|
4636 writeCommentBeforeValue(childValue);
|
|
4637 writeWithIndent(valueToQuotedString(name.c_str()));
|
|
4638 document_ += " : ";
|
|
4639 writeValue(childValue);
|
|
4640 if (++it == members.end()) {
|
|
4641 writeCommentAfterValueOnSameLine(childValue);
|
|
4642 break;
|
|
4643 }
|
|
4644 document_ += ',';
|
|
4645 writeCommentAfterValueOnSameLine(childValue);
|
|
4646 }
|
|
4647 unindent();
|
|
4648 writeWithIndent("}");
|
|
4649 }
|
|
4650 } break;
|
|
4651 }
|
|
4652 }
|
|
4653
|
|
4654 void StyledWriter::writeArrayValue(const Value& value) {
|
|
4655 unsigned size = value.size();
|
|
4656 if (size == 0)
|
|
4657 pushValue("[]");
|
|
4658 else {
|
|
4659 bool isArrayMultiLine = isMultilineArray(value);
|
|
4660 if (isArrayMultiLine) {
|
|
4661 writeWithIndent("[");
|
|
4662 indent();
|
|
4663 bool hasChildValue = !childValues_.empty();
|
|
4664 unsigned index = 0;
|
|
4665 for (;;) {
|
|
4666 const Value& childValue = value[index];
|
|
4667 writeCommentBeforeValue(childValue);
|
|
4668 if (hasChildValue)
|
|
4669 writeWithIndent(childValues_[index]);
|
|
4670 else {
|
|
4671 writeIndent();
|
|
4672 writeValue(childValue);
|
|
4673 }
|
|
4674 if (++index == size) {
|
|
4675 writeCommentAfterValueOnSameLine(childValue);
|
|
4676 break;
|
|
4677 }
|
|
4678 document_ += ',';
|
|
4679 writeCommentAfterValueOnSameLine(childValue);
|
|
4680 }
|
|
4681 unindent();
|
|
4682 writeWithIndent("]");
|
|
4683 } else // output on a single line
|
|
4684 {
|
|
4685 assert(childValues_.size() == size);
|
|
4686 document_ += "[ ";
|
|
4687 for (unsigned index = 0; index < size; ++index) {
|
|
4688 if (index > 0)
|
|
4689 document_ += ", ";
|
|
4690 document_ += childValues_[index];
|
|
4691 }
|
|
4692 document_ += " ]";
|
|
4693 }
|
|
4694 }
|
|
4695 }
|
|
4696
|
|
4697 bool StyledWriter::isMultilineArray(const Value& value) {
|
|
4698 ArrayIndex const size = value.size();
|
|
4699 bool isMultiLine = size * 3 >= rightMargin_;
|
|
4700 childValues_.clear();
|
|
4701 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
|
|
4702 const Value& childValue = value[index];
|
|
4703 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
|
|
4704 !childValue.empty());
|
|
4705 }
|
|
4706 if (!isMultiLine) // check if line length > max line length
|
|
4707 {
|
|
4708 childValues_.reserve(size);
|
|
4709 addChildValues_ = true;
|
|
4710 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
|
|
4711 for (ArrayIndex index = 0; index < size; ++index) {
|
|
4712 if (hasCommentForValue(value[index])) {
|
|
4713 isMultiLine = true;
|
|
4714 }
|
|
4715 writeValue(value[index]);
|
|
4716 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
|
|
4717 }
|
|
4718 addChildValues_ = false;
|
|
4719 isMultiLine = isMultiLine || lineLength >= rightMargin_;
|
|
4720 }
|
|
4721 return isMultiLine;
|
|
4722 }
|
|
4723
|
|
4724 void StyledWriter::pushValue(const String& value) {
|
|
4725 if (addChildValues_)
|
|
4726 childValues_.push_back(value);
|
|
4727 else
|
|
4728 document_ += value;
|
|
4729 }
|
|
4730
|
|
4731 void StyledWriter::writeIndent() {
|
|
4732 if (!document_.empty()) {
|
|
4733 char last = document_[document_.length() - 1];
|
|
4734 if (last == ' ') // already indented
|
|
4735 return;
|
|
4736 if (last != '\n') // Comments may add new-line
|
|
4737 document_ += '\n';
|
|
4738 }
|
|
4739 document_ += indentString_;
|
|
4740 }
|
|
4741
|
|
4742 void StyledWriter::writeWithIndent(const String& value) {
|
|
4743 writeIndent();
|
|
4744 document_ += value;
|
|
4745 }
|
|
4746
|
|
4747 void StyledWriter::indent() { indentString_ += String(indentSize_, ' '); }
|
|
4748
|
|
4749 void StyledWriter::unindent() {
|
|
4750 assert(indentString_.size() >= indentSize_);
|
|
4751 indentString_.resize(indentString_.size() - indentSize_);
|
|
4752 }
|
|
4753
|
|
4754 void StyledWriter::writeCommentBeforeValue(const Value& root) {
|
|
4755 if (!root.hasComment(commentBefore))
|
|
4756 return;
|
|
4757
|
|
4758 document_ += '\n';
|
|
4759 writeIndent();
|
|
4760 const String& comment = root.getComment(commentBefore);
|
|
4761 String::const_iterator iter = comment.begin();
|
|
4762 while (iter != comment.end()) {
|
|
4763 document_ += *iter;
|
|
4764 if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))
|
|
4765 writeIndent();
|
|
4766 ++iter;
|
|
4767 }
|
|
4768
|
|
4769 // Comments are stripped of trailing newlines, so add one here
|
|
4770 document_ += '\n';
|
|
4771 }
|
|
4772
|
|
4773 void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
|
|
4774 if (root.hasComment(commentAfterOnSameLine))
|
|
4775 document_ += " " + root.getComment(commentAfterOnSameLine);
|
|
4776
|
|
4777 if (root.hasComment(commentAfter)) {
|
|
4778 document_ += '\n';
|
|
4779 document_ += root.getComment(commentAfter);
|
|
4780 document_ += '\n';
|
|
4781 }
|
|
4782 }
|
|
4783
|
|
4784 bool StyledWriter::hasCommentForValue(const Value& value) {
|
|
4785 return value.hasComment(commentBefore) ||
|
|
4786 value.hasComment(commentAfterOnSameLine) ||
|
|
4787 value.hasComment(commentAfter);
|
|
4788 }
|
|
4789
|
|
4790 // Class StyledStreamWriter
|
|
4791 // //////////////////////////////////////////////////////////////////
|
|
4792
|
|
4793 StyledStreamWriter::StyledStreamWriter(String indentation)
|
|
4794 : document_(nullptr), indentation_(std::move(indentation)),
|
|
4795 addChildValues_(), indented_(false) {}
|
|
4796
|
|
4797 void StyledStreamWriter::write(OStream& out, const Value& root) {
|
|
4798 document_ = &out;
|
|
4799 addChildValues_ = false;
|
|
4800 indentString_.clear();
|
|
4801 indented_ = true;
|
|
4802 writeCommentBeforeValue(root);
|
|
4803 if (!indented_)
|
|
4804 writeIndent();
|
|
4805 indented_ = true;
|
|
4806 writeValue(root);
|
|
4807 writeCommentAfterValueOnSameLine(root);
|
|
4808 *document_ << "\n";
|
|
4809 document_ = nullptr; // Forget the stream, for safety.
|
|
4810 }
|
|
4811
|
|
4812 void StyledStreamWriter::writeValue(const Value& value) {
|
|
4813 switch (value.type()) {
|
|
4814 case nullValue:
|
|
4815 pushValue("null");
|
|
4816 break;
|
|
4817 case intValue:
|
|
4818 pushValue(valueToString(value.asLargestInt()));
|
|
4819 break;
|
|
4820 case uintValue:
|
|
4821 pushValue(valueToString(value.asLargestUInt()));
|
|
4822 break;
|
|
4823 case realValue:
|
|
4824 pushValue(valueToString(value.asDouble()));
|
|
4825 break;
|
|
4826 case stringValue: {
|
|
4827 // Is NULL possible for value.string_? No.
|
|
4828 char const* str;
|
|
4829 char const* end;
|
|
4830 bool ok = value.getString(&str, &end);
|
|
4831 if (ok)
|
|
4832 pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
|
|
4833 else
|
|
4834 pushValue("");
|
|
4835 break;
|
|
4836 }
|
|
4837 case booleanValue:
|
|
4838 pushValue(valueToString(value.asBool()));
|
|
4839 break;
|
|
4840 case arrayValue:
|
|
4841 writeArrayValue(value);
|
|
4842 break;
|
|
4843 case objectValue: {
|
|
4844 Value::Members members(value.getMemberNames());
|
|
4845 if (members.empty())
|
|
4846 pushValue("{}");
|
|
4847 else {
|
|
4848 writeWithIndent("{");
|
|
4849 indent();
|
|
4850 auto it = members.begin();
|
|
4851 for (;;) {
|
|
4852 const String& name = *it;
|
|
4853 const Value& childValue = value[name];
|
|
4854 writeCommentBeforeValue(childValue);
|
|
4855 writeWithIndent(valueToQuotedString(name.c_str()));
|
|
4856 *document_ << " : ";
|
|
4857 writeValue(childValue);
|
|
4858 if (++it == members.end()) {
|
|
4859 writeCommentAfterValueOnSameLine(childValue);
|
|
4860 break;
|
|
4861 }
|
|
4862 *document_ << ",";
|
|
4863 writeCommentAfterValueOnSameLine(childValue);
|
|
4864 }
|
|
4865 unindent();
|
|
4866 writeWithIndent("}");
|
|
4867 }
|
|
4868 } break;
|
|
4869 }
|
|
4870 }
|
|
4871
|
|
4872 void StyledStreamWriter::writeArrayValue(const Value& value) {
|
|
4873 unsigned size = value.size();
|
|
4874 if (size == 0)
|
|
4875 pushValue("[]");
|
|
4876 else {
|
|
4877 bool isArrayMultiLine = isMultilineArray(value);
|
|
4878 if (isArrayMultiLine) {
|
|
4879 writeWithIndent("[");
|
|
4880 indent();
|
|
4881 bool hasChildValue = !childValues_.empty();
|
|
4882 unsigned index = 0;
|
|
4883 for (;;) {
|
|
4884 const Value& childValue = value[index];
|
|
4885 writeCommentBeforeValue(childValue);
|
|
4886 if (hasChildValue)
|
|
4887 writeWithIndent(childValues_[index]);
|
|
4888 else {
|
|
4889 if (!indented_)
|
|
4890 writeIndent();
|
|
4891 indented_ = true;
|
|
4892 writeValue(childValue);
|
|
4893 indented_ = false;
|
|
4894 }
|
|
4895 if (++index == size) {
|
|
4896 writeCommentAfterValueOnSameLine(childValue);
|
|
4897 break;
|
|
4898 }
|
|
4899 *document_ << ",";
|
|
4900 writeCommentAfterValueOnSameLine(childValue);
|
|
4901 }
|
|
4902 unindent();
|
|
4903 writeWithIndent("]");
|
|
4904 } else // output on a single line
|
|
4905 {
|
|
4906 assert(childValues_.size() == size);
|
|
4907 *document_ << "[ ";
|
|
4908 for (unsigned index = 0; index < size; ++index) {
|
|
4909 if (index > 0)
|
|
4910 *document_ << ", ";
|
|
4911 *document_ << childValues_[index];
|
|
4912 }
|
|
4913 *document_ << " ]";
|
|
4914 }
|
|
4915 }
|
|
4916 }
|
|
4917
|
|
4918 bool StyledStreamWriter::isMultilineArray(const Value& value) {
|
|
4919 ArrayIndex const size = value.size();
|
|
4920 bool isMultiLine = size * 3 >= rightMargin_;
|
|
4921 childValues_.clear();
|
|
4922 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
|
|
4923 const Value& childValue = value[index];
|
|
4924 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
|
|
4925 !childValue.empty());
|
|
4926 }
|
|
4927 if (!isMultiLine) // check if line length > max line length
|
|
4928 {
|
|
4929 childValues_.reserve(size);
|
|
4930 addChildValues_ = true;
|
|
4931 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
|
|
4932 for (ArrayIndex index = 0; index < size; ++index) {
|
|
4933 if (hasCommentForValue(value[index])) {
|
|
4934 isMultiLine = true;
|
|
4935 }
|
|
4936 writeValue(value[index]);
|
|
4937 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
|
|
4938 }
|
|
4939 addChildValues_ = false;
|
|
4940 isMultiLine = isMultiLine || lineLength >= rightMargin_;
|
|
4941 }
|
|
4942 return isMultiLine;
|
|
4943 }
|
|
4944
|
|
4945 void StyledStreamWriter::pushValue(const String& value) {
|
|
4946 if (addChildValues_)
|
|
4947 childValues_.push_back(value);
|
|
4948 else
|
|
4949 *document_ << value;
|
|
4950 }
|
|
4951
|
|
4952 void StyledStreamWriter::writeIndent() {
|
|
4953 // blep intended this to look at the so-far-written string
|
|
4954 // to determine whether we are already indented, but
|
|
4955 // with a stream we cannot do that. So we rely on some saved state.
|
|
4956 // The caller checks indented_.
|
|
4957 *document_ << '\n' << indentString_;
|
|
4958 }
|
|
4959
|
|
4960 void StyledStreamWriter::writeWithIndent(const String& value) {
|
|
4961 if (!indented_)
|
|
4962 writeIndent();
|
|
4963 *document_ << value;
|
|
4964 indented_ = false;
|
|
4965 }
|
|
4966
|
|
4967 void StyledStreamWriter::indent() { indentString_ += indentation_; }
|
|
4968
|
|
4969 void StyledStreamWriter::unindent() {
|
|
4970 assert(indentString_.size() >= indentation_.size());
|
|
4971 indentString_.resize(indentString_.size() - indentation_.size());
|
|
4972 }
|
|
4973
|
|
4974 void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
|
|
4975 if (!root.hasComment(commentBefore))
|
|
4976 return;
|
|
4977
|
|
4978 if (!indented_)
|
|
4979 writeIndent();
|
|
4980 const String& comment = root.getComment(commentBefore);
|
|
4981 String::const_iterator iter = comment.begin();
|
|
4982 while (iter != comment.end()) {
|
|
4983 *document_ << *iter;
|
|
4984 if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))
|
|
4985 // writeIndent(); // would include newline
|
|
4986 *document_ << indentString_;
|
|
4987 ++iter;
|
|
4988 }
|
|
4989 indented_ = false;
|
|
4990 }
|
|
4991
|
|
4992 void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
|
|
4993 if (root.hasComment(commentAfterOnSameLine))
|
|
4994 *document_ << ' ' << root.getComment(commentAfterOnSameLine);
|
|
4995
|
|
4996 if (root.hasComment(commentAfter)) {
|
|
4997 writeIndent();
|
|
4998 *document_ << root.getComment(commentAfter);
|
|
4999 }
|
|
5000 indented_ = false;
|
|
5001 }
|
|
5002
|
|
5003 bool StyledStreamWriter::hasCommentForValue(const Value& value) {
|
|
5004 return value.hasComment(commentBefore) ||
|
|
5005 value.hasComment(commentAfterOnSameLine) ||
|
|
5006 value.hasComment(commentAfter);
|
|
5007 }
|
|
5008
|
|
5009 //////////////////////////
|
|
5010 // BuiltStyledStreamWriter
|
|
5011
|
|
5012 /// Scoped enums are not available until C++11.
|
|
5013 struct CommentStyle {
|
|
5014 /// Decide whether to write comments.
|
|
5015 enum Enum {
|
|
5016 None, ///< Drop all comments.
|
|
5017 Most, ///< Recover odd behavior of previous versions (not implemented yet).
|
|
5018 All ///< Keep all comments.
|
|
5019 };
|
|
5020 };
|
|
5021
|
|
5022 struct BuiltStyledStreamWriter : public StreamWriter {
|
|
5023 BuiltStyledStreamWriter(String indentation,
|
|
5024 CommentStyle::Enum cs,
|
|
5025 String colonSymbol,
|
|
5026 String nullSymbol,
|
|
5027 String endingLineFeedSymbol,
|
|
5028 bool useSpecialFloats,
|
|
5029 unsigned int precision,
|
|
5030 PrecisionType precisionType);
|
|
5031 int write(Value const& root, OStream* sout) override;
|
|
5032
|
|
5033 private:
|
|
5034 void writeValue(Value const& value);
|
|
5035 void writeArrayValue(Value const& value);
|
|
5036 bool isMultilineArray(Value const& value);
|
|
5037 void pushValue(String const& value);
|
|
5038 void writeIndent();
|
|
5039 void writeWithIndent(String const& value);
|
|
5040 void indent();
|
|
5041 void unindent();
|
|
5042 void writeCommentBeforeValue(Value const& root);
|
|
5043 void writeCommentAfterValueOnSameLine(Value const& root);
|
|
5044 static bool hasCommentForValue(const Value& value);
|
|
5045
|
|
5046 typedef std::vector<String> ChildValues;
|
|
5047
|
|
5048 ChildValues childValues_;
|
|
5049 String indentString_;
|
|
5050 unsigned int rightMargin_;
|
|
5051 String indentation_;
|
|
5052 CommentStyle::Enum cs_;
|
|
5053 String colonSymbol_;
|
|
5054 String nullSymbol_;
|
|
5055 String endingLineFeedSymbol_;
|
|
5056 bool addChildValues_ : 1;
|
|
5057 bool indented_ : 1;
|
|
5058 bool useSpecialFloats_ : 1;
|
|
5059 unsigned int precision_;
|
|
5060 PrecisionType precisionType_;
|
|
5061 };
|
|
5062 BuiltStyledStreamWriter::BuiltStyledStreamWriter(String indentation,
|
|
5063 CommentStyle::Enum cs,
|
|
5064 String colonSymbol,
|
|
5065 String nullSymbol,
|
|
5066 String endingLineFeedSymbol,
|
|
5067 bool useSpecialFloats,
|
|
5068 unsigned int precision,
|
|
5069 PrecisionType precisionType)
|
|
5070 : rightMargin_(74), indentation_(std::move(indentation)), cs_(cs),
|
|
5071 colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)),
|
|
5072 endingLineFeedSymbol_(std::move(endingLineFeedSymbol)),
|
|
5073 addChildValues_(false), indented_(false),
|
|
5074 useSpecialFloats_(useSpecialFloats), precision_(precision),
|
|
5075 precisionType_(precisionType) {}
|
|
5076 int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) {
|
|
5077 sout_ = sout;
|
|
5078 addChildValues_ = false;
|
|
5079 indented_ = true;
|
|
5080 indentString_.clear();
|
|
5081 writeCommentBeforeValue(root);
|
|
5082 if (!indented_)
|
|
5083 writeIndent();
|
|
5084 indented_ = true;
|
|
5085 writeValue(root);
|
|
5086 writeCommentAfterValueOnSameLine(root);
|
|
5087 *sout_ << endingLineFeedSymbol_;
|
|
5088 sout_ = nullptr;
|
|
5089 return 0;
|
|
5090 }
|
|
5091 void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
|
5092 switch (value.type()) {
|
|
5093 case nullValue:
|
|
5094 pushValue(nullSymbol_);
|
|
5095 break;
|
|
5096 case intValue:
|
|
5097 pushValue(valueToString(value.asLargestInt()));
|
|
5098 break;
|
|
5099 case uintValue:
|
|
5100 pushValue(valueToString(value.asLargestUInt()));
|
|
5101 break;
|
|
5102 case realValue:
|
|
5103 pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_,
|
|
5104 precisionType_));
|
|
5105 break;
|
|
5106 case stringValue: {
|
|
5107 // Is NULL is possible for value.string_? No.
|
|
5108 char const* str;
|
|
5109 char const* end;
|
|
5110 bool ok = value.getString(&str, &end);
|
|
5111 if (ok)
|
|
5112 pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
|
|
5113 else
|
|
5114 pushValue("");
|
|
5115 break;
|
|
5116 }
|
|
5117 case booleanValue:
|
|
5118 pushValue(valueToString(value.asBool()));
|
|
5119 break;
|
|
5120 case arrayValue:
|
|
5121 writeArrayValue(value);
|
|
5122 break;
|
|
5123 case objectValue: {
|
|
5124 Value::Members members(value.getMemberNames());
|
|
5125 if (members.empty())
|
|
5126 pushValue("{}");
|
|
5127 else {
|
|
5128 writeWithIndent("{");
|
|
5129 indent();
|
|
5130 auto it = members.begin();
|
|
5131 for (;;) {
|
|
5132 String const& name = *it;
|
|
5133 Value const& childValue = value[name];
|
|
5134 writeCommentBeforeValue(childValue);
|
|
5135 writeWithIndent(valueToQuotedStringN(
|
|
5136 name.data(), static_cast<unsigned>(name.length())));
|
|
5137 *sout_ << colonSymbol_;
|
|
5138 writeValue(childValue);
|
|
5139 if (++it == members.end()) {
|
|
5140 writeCommentAfterValueOnSameLine(childValue);
|
|
5141 break;
|
|
5142 }
|
|
5143 *sout_ << ",";
|
|
5144 writeCommentAfterValueOnSameLine(childValue);
|
|
5145 }
|
|
5146 unindent();
|
|
5147 writeWithIndent("}");
|
|
5148 }
|
|
5149 } break;
|
|
5150 }
|
|
5151 }
|
|
5152
|
|
5153 void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
|
|
5154 unsigned size = value.size();
|
|
5155 if (size == 0)
|
|
5156 pushValue("[]");
|
|
5157 else {
|
|
5158 bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value);
|
|
5159 if (isMultiLine) {
|
|
5160 writeWithIndent("[");
|
|
5161 indent();
|
|
5162 bool hasChildValue = !childValues_.empty();
|
|
5163 unsigned index = 0;
|
|
5164 for (;;) {
|
|
5165 Value const& childValue = value[index];
|
|
5166 writeCommentBeforeValue(childValue);
|
|
5167 if (hasChildValue)
|
|
5168 writeWithIndent(childValues_[index]);
|
|
5169 else {
|
|
5170 if (!indented_)
|
|
5171 writeIndent();
|
|
5172 indented_ = true;
|
|
5173 writeValue(childValue);
|
|
5174 indented_ = false;
|
|
5175 }
|
|
5176 if (++index == size) {
|
|
5177 writeCommentAfterValueOnSameLine(childValue);
|
|
5178 break;
|
|
5179 }
|
|
5180 *sout_ << ",";
|
|
5181 writeCommentAfterValueOnSameLine(childValue);
|
|
5182 }
|
|
5183 unindent();
|
|
5184 writeWithIndent("]");
|
|
5185 } else // output on a single line
|
|
5186 {
|
|
5187 assert(childValues_.size() == size);
|
|
5188 *sout_ << "[";
|
|
5189 if (!indentation_.empty())
|
|
5190 *sout_ << " ";
|
|
5191 for (unsigned index = 0; index < size; ++index) {
|
|
5192 if (index > 0)
|
|
5193 *sout_ << ((!indentation_.empty()) ? ", " : ",");
|
|
5194 *sout_ << childValues_[index];
|
|
5195 }
|
|
5196 if (!indentation_.empty())
|
|
5197 *sout_ << " ";
|
|
5198 *sout_ << "]";
|
|
5199 }
|
|
5200 }
|
|
5201 }
|
|
5202
|
|
5203 bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) {
|
|
5204 ArrayIndex const size = value.size();
|
|
5205 bool isMultiLine = size * 3 >= rightMargin_;
|
|
5206 childValues_.clear();
|
|
5207 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
|
|
5208 Value const& childValue = value[index];
|
|
5209 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
|
|
5210 !childValue.empty());
|
|
5211 }
|
|
5212 if (!isMultiLine) // check if line length > max line length
|
|
5213 {
|
|
5214 childValues_.reserve(size);
|
|
5215 addChildValues_ = true;
|
|
5216 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
|
|
5217 for (ArrayIndex index = 0; index < size; ++index) {
|
|
5218 if (hasCommentForValue(value[index])) {
|
|
5219 isMultiLine = true;
|
|
5220 }
|
|
5221 writeValue(value[index]);
|
|
5222 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
|
|
5223 }
|
|
5224 addChildValues_ = false;
|
|
5225 isMultiLine = isMultiLine || lineLength >= rightMargin_;
|
|
5226 }
|
|
5227 return isMultiLine;
|
|
5228 }
|
|
5229
|
|
5230 void BuiltStyledStreamWriter::pushValue(String const& value) {
|
|
5231 if (addChildValues_)
|
|
5232 childValues_.push_back(value);
|
|
5233 else
|
|
5234 *sout_ << value;
|
|
5235 }
|
|
5236
|
|
5237 void BuiltStyledStreamWriter::writeIndent() {
|
|
5238 // blep intended this to look at the so-far-written string
|
|
5239 // to determine whether we are already indented, but
|
|
5240 // with a stream we cannot do that. So we rely on some saved state.
|
|
5241 // The caller checks indented_.
|
|
5242
|
|
5243 if (!indentation_.empty()) {
|
|
5244 // In this case, drop newlines too.
|
|
5245 *sout_ << '\n' << indentString_;
|
|
5246 }
|
|
5247 }
|
|
5248
|
|
5249 void BuiltStyledStreamWriter::writeWithIndent(String const& value) {
|
|
5250 if (!indented_)
|
|
5251 writeIndent();
|
|
5252 *sout_ << value;
|
|
5253 indented_ = false;
|
|
5254 }
|
|
5255
|
|
5256 void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
|
|
5257
|
|
5258 void BuiltStyledStreamWriter::unindent() {
|
|
5259 assert(indentString_.size() >= indentation_.size());
|
|
5260 indentString_.resize(indentString_.size() - indentation_.size());
|
|
5261 }
|
|
5262
|
|
5263 void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
|
|
5264 if (cs_ == CommentStyle::None)
|
|
5265 return;
|
|
5266 if (!root.hasComment(commentBefore))
|
|
5267 return;
|
|
5268
|
|
5269 if (!indented_)
|
|
5270 writeIndent();
|
|
5271 const String& comment = root.getComment(commentBefore);
|
|
5272 String::const_iterator iter = comment.begin();
|
|
5273 while (iter != comment.end()) {
|
|
5274 *sout_ << *iter;
|
|
5275 if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))
|
|
5276 // writeIndent(); // would write extra newline
|
|
5277 *sout_ << indentString_;
|
|
5278 ++iter;
|
|
5279 }
|
|
5280 indented_ = false;
|
|
5281 }
|
|
5282
|
|
5283 void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(
|
|
5284 Value const& root) {
|
|
5285 if (cs_ == CommentStyle::None)
|
|
5286 return;
|
|
5287 if (root.hasComment(commentAfterOnSameLine))
|
|
5288 *sout_ << " " + root.getComment(commentAfterOnSameLine);
|
|
5289
|
|
5290 if (root.hasComment(commentAfter)) {
|
|
5291 writeIndent();
|
|
5292 *sout_ << root.getComment(commentAfter);
|
|
5293 }
|
|
5294 }
|
|
5295
|
|
5296 // static
|
|
5297 bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
|
|
5298 return value.hasComment(commentBefore) ||
|
|
5299 value.hasComment(commentAfterOnSameLine) ||
|
|
5300 value.hasComment(commentAfter);
|
|
5301 }
|
|
5302
|
|
5303 ///////////////
|
|
5304 // StreamWriter
|
|
5305
|
|
5306 StreamWriter::StreamWriter() : sout_(nullptr) {}
|
|
5307 StreamWriter::~StreamWriter() = default;
|
|
5308 StreamWriter::Factory::~Factory() = default;
|
|
5309 StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); }
|
|
5310 StreamWriterBuilder::~StreamWriterBuilder() = default;
|
|
5311 StreamWriter* StreamWriterBuilder::newStreamWriter() const {
|
|
5312 String indentation = settings_["indentation"].asString();
|
|
5313 String cs_str = settings_["commentStyle"].asString();
|
|
5314 String pt_str = settings_["precisionType"].asString();
|
|
5315 bool eyc = settings_["enableYAMLCompatibility"].asBool();
|
|
5316 bool dnp = settings_["dropNullPlaceholders"].asBool();
|
|
5317 bool usf = settings_["useSpecialFloats"].asBool();
|
|
5318 unsigned int pre = settings_["precision"].asUInt();
|
|
5319 CommentStyle::Enum cs = CommentStyle::All;
|
|
5320 if (cs_str == "All") {
|
|
5321 cs = CommentStyle::All;
|
|
5322 } else if (cs_str == "None") {
|
|
5323 cs = CommentStyle::None;
|
|
5324 } else {
|
|
5325 throwRuntimeError("commentStyle must be 'All' or 'None'");
|
|
5326 }
|
|
5327 PrecisionType precisionType(significantDigits);
|
|
5328 if (pt_str == "significant") {
|
|
5329 precisionType = PrecisionType::significantDigits;
|
|
5330 } else if (pt_str == "decimal") {
|
|
5331 precisionType = PrecisionType::decimalPlaces;
|
|
5332 } else {
|
|
5333 throwRuntimeError("precisionType must be 'significant' or 'decimal'");
|
|
5334 }
|
|
5335 String colonSymbol = " : ";
|
|
5336 if (eyc) {
|
|
5337 colonSymbol = ": ";
|
|
5338 } else if (indentation.empty()) {
|
|
5339 colonSymbol = ":";
|
|
5340 }
|
|
5341 String nullSymbol = "null";
|
|
5342 if (dnp) {
|
|
5343 nullSymbol.clear();
|
|
5344 }
|
|
5345 if (pre > 17)
|
|
5346 pre = 17;
|
|
5347 String endingLineFeedSymbol;
|
|
5348 return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol,
|
|
5349 endingLineFeedSymbol, usf, pre,
|
|
5350 precisionType);
|
|
5351 }
|
|
5352 static void getValidWriterKeys(std::set<String>* valid_keys) {
|
|
5353 valid_keys->clear();
|
|
5354 valid_keys->insert("indentation");
|
|
5355 valid_keys->insert("commentStyle");
|
|
5356 valid_keys->insert("enableYAMLCompatibility");
|
|
5357 valid_keys->insert("dropNullPlaceholders");
|
|
5358 valid_keys->insert("useSpecialFloats");
|
|
5359 valid_keys->insert("precision");
|
|
5360 valid_keys->insert("precisionType");
|
|
5361 }
|
|
5362 bool StreamWriterBuilder::validate(Json::Value* invalid) const {
|
|
5363 Json::Value my_invalid;
|
|
5364 if (!invalid)
|
|
5365 invalid = &my_invalid; // so we do not need to test for NULL
|
|
5366 Json::Value& inv = *invalid;
|
|
5367 std::set<String> valid_keys;
|
|
5368 getValidWriterKeys(&valid_keys);
|
|
5369 Value::Members keys = settings_.getMemberNames();
|
|
5370 size_t n = keys.size();
|
|
5371 for (size_t i = 0; i < n; ++i) {
|
|
5372 String const& key = keys[i];
|
|
5373 if (valid_keys.find(key) == valid_keys.end()) {
|
|
5374 inv[key] = settings_[key];
|
|
5375 }
|
|
5376 }
|
|
5377 return inv.empty();
|
|
5378 }
|
|
5379 Value& StreamWriterBuilder::operator[](const String& key) {
|
|
5380 return settings_[key];
|
|
5381 }
|
|
5382 // static
|
|
5383 void StreamWriterBuilder::setDefaults(Json::Value* settings) {
|
|
5384 //! [StreamWriterBuilderDefaults]
|
|
5385 (*settings)["commentStyle"] = "All";
|
|
5386 (*settings)["indentation"] = "\t";
|
|
5387 (*settings)["enableYAMLCompatibility"] = false;
|
|
5388 (*settings)["dropNullPlaceholders"] = false;
|
|
5389 (*settings)["useSpecialFloats"] = false;
|
|
5390 (*settings)["precision"] = 17;
|
|
5391 (*settings)["precisionType"] = "significant";
|
|
5392 //! [StreamWriterBuilderDefaults]
|
|
5393 }
|
|
5394
|
|
5395 String writeString(StreamWriter::Factory const& factory, Value const& root) {
|
|
5396 OStringStream sout;
|
|
5397 StreamWriterPtr const writer(factory.newStreamWriter());
|
|
5398 writer->write(root, &sout);
|
|
5399 return sout.str();
|
|
5400 }
|
|
5401
|
|
5402 OStream& operator<<(OStream& sout, Value const& root) {
|
|
5403 StreamWriterBuilder builder;
|
|
5404 StreamWriterPtr const writer(builder.newStreamWriter());
|
|
5405 writer->write(root, &sout);
|
|
5406 return sout;
|
|
5407 }
|
|
5408
|
|
5409 } // namespace Json
|
|
5410
|
|
5411 // //////////////////////////////////////////////////////////////////////
|
|
5412 // End of content of file: src/lib_json/json_writer.cpp
|
|
5413 // //////////////////////////////////////////////////////////////////////
|
|
5414
|
|
5415
|
|
5416
|
|
5417
|
|
5418
|