Mercurial > hg > orthanc-stone
annotate Resources/CodeGeneration/testWasmIntegrated/jsoncpp-1.8.4/jsoncpp.cpp @ 1313:f30905f5d246 broker
Added support for OnGenericSdlEvent to GuiAdapter.
This makes it possible to piggyback app-specific logic
to special events (here, to support the Viewport refresh
events)
author | Benjamin Golinvaux <bgo@osimis.io> |
---|---|
date | Mon, 16 Mar 2020 11:12:39 +0100 |
parents | 8a0a62189f46 |
children |
rev | line source |
---|---|
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 | |
1298
8a0a62189f46
replacing std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
499
diff
changeset
|
290 typedef std::unique_ptr<CharReader> CharReaderPtr; |
499 | 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 | |
1298
8a0a62189f46
replacing std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
499
diff
changeset
|
4245 typedef std::unique_ptr<StreamWriter> StreamWriterPtr; |
499 | 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 |