Add comment to analyzed call
[dueringa_WikiWalker.git] / lib / jsoncpp / jsoncpp.cpp
blob507a1c6ad35d8e3fce51efe14c4ef4e6e9ddc87d
1 /// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/).
2 /// It is intended to be used with #include "json/json.h"
4 // //////////////////////////////////////////////////////////////////////
5 // Beginning of content of file: LICENSE
6 // //////////////////////////////////////////////////////////////////////
8 /*
9 The JsonCpp library's source code, including accompanying documentation,
10 tests and demonstration applications, are licensed under the following
11 conditions...
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.
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).
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.
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:
29 http://en.wikipedia.org/wiki/MIT_License
31 The full text of the MIT License follows:
33 ========================================================================
34 Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
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:
44 The above copyright notice and this permission notice shall be
45 included in all copies or substantial portions of the Software.
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)
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.
67 // //////////////////////////////////////////////////////////////////////
68 // End of content of file: LICENSE
69 // //////////////////////////////////////////////////////////////////////
76 #include "json/json.h"
78 #ifndef JSON_IS_AMALGAMATION
79 #error "Compile with -I PATH_TO_JSON_DIRECTORY"
80 #endif
83 // //////////////////////////////////////////////////////////////////////
84 // Beginning of content of file: src/lib_json/json_tool.h
85 // //////////////////////////////////////////////////////////////////////
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
92 #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
93 #define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
96 // Also support old flag NO_LOCALE_SUPPORT
97 #ifdef NO_LOCALE_SUPPORT
98 #define JSONCPP_NO_LOCALE_SUPPORT
99 #endif
101 #ifndef JSONCPP_NO_LOCALE_SUPPORT
102 #include <clocale>
103 #endif
105 /* This header provides common string manipulation support, such as UTF-8,
106 * portable conversion from/to string...
108 * It is an internal header that must not be exposed.
111 namespace Json {
112 static char getDecimalPoint() {
113 #ifdef JSONCPP_NO_LOCALE_SUPPORT
114 return '\0';
115 #else
116 struct lconv* lc = localeconv();
117 return lc ? *(lc->decimal_point) : '\0';
118 #endif
121 /// Converts a unicode code-point to UTF-8.
122 static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) {
123 JSONCPP_STRING result;
125 // based on description from http://en.wikipedia.org/wiki/UTF-8
127 if (cp <= 0x7f) {
128 result.resize(1);
129 result[0] = static_cast<char>(cp);
130 } else if (cp <= 0x7FF) {
131 result.resize(2);
132 result[1] = static_cast<char>(0x80 | (0x3f & cp));
133 result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
134 } else if (cp <= 0xFFFF) {
135 result.resize(3);
136 result[2] = static_cast<char>(0x80 | (0x3f & cp));
137 result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
138 result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
139 } else if (cp <= 0x10FFFF) {
140 result.resize(4);
141 result[3] = static_cast<char>(0x80 | (0x3f & cp));
142 result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
143 result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
144 result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
147 return result;
150 enum {
151 /// Constant that specify the size of the buffer that must be passed to
152 /// uintToString.
153 uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
156 // Defines a char buffer for use with uintToString().
157 typedef char UIntToStringBuffer[uintToStringBufferSize];
159 /** Converts an unsigned integer to string.
160 * @param value Unsigned integer to convert to string
161 * @param current Input/Output string buffer.
162 * Must have at least uintToStringBufferSize chars free.
164 static inline void uintToString(LargestUInt value, char*& current) {
165 *--current = 0;
166 do {
167 *--current = static_cast<char>(value % 10U + static_cast<unsigned>('0'));
168 value /= 10;
169 } while (value != 0);
172 /** Change ',' to '.' everywhere in buffer.
174 * We had a sophisticated way, but it did not work in WinCE.
175 * @see https://github.com/open-source-parsers/jsoncpp/pull/9
177 static inline void fixNumericLocale(char* begin, char* end) {
178 while (begin < end) {
179 if (*begin == ',') {
180 *begin = '.';
182 ++begin;
186 static inline void fixNumericLocaleInput(char* begin, char* end) {
187 char decimalPoint = getDecimalPoint();
188 if (decimalPoint != '\0' && decimalPoint != '.') {
189 while (begin < end) {
190 if (*begin == '.') {
191 *begin = decimalPoint;
193 ++begin;
198 } // namespace Json {
200 #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
202 // //////////////////////////////////////////////////////////////////////
203 // End of content of file: src/lib_json/json_tool.h
204 // //////////////////////////////////////////////////////////////////////
211 // //////////////////////////////////////////////////////////////////////
212 // Beginning of content of file: src/lib_json/json_reader.cpp
213 // //////////////////////////////////////////////////////////////////////
215 // Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors
216 // Copyright (C) 2016 InfoTeCS JSC. All rights reserved.
217 // Distributed under MIT license, or public domain if desired and
218 // recognized in your jurisdiction.
219 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
221 #if !defined(JSON_IS_AMALGAMATION)
222 #include <json/assertions.h>
223 #include <json/reader.h>
224 #include <json/value.h>
225 #include "json_tool.h"
226 #endif // if !defined(JSON_IS_AMALGAMATION)
227 #include <utility>
228 #include <cstdio>
229 #include <cassert>
230 #include <cstring>
231 #include <istream>
232 #include <sstream>
233 #include <memory>
234 #include <set>
235 #include <limits>
237 #if defined(_MSC_VER)
238 #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
239 #define snprintf sprintf_s
240 #elif _MSC_VER >= 1900 // VC++ 14.0 and above
241 #define snprintf std::snprintf
242 #else
243 #define snprintf _snprintf
244 #endif
245 #elif defined(__ANDROID__) || defined(__QNXNTO__)
246 #define snprintf snprintf
247 #elif __cplusplus >= 201103L
248 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
249 #define snprintf std::snprintf
250 #endif
251 #endif
253 #if defined(__QNXNTO__)
254 #define sscanf std::sscanf
255 #endif
257 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
258 // Disable warning about strdup being deprecated.
259 #pragma warning(disable : 4996)
260 #endif
262 // Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile time to change the stack limit
263 #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
264 #define JSONCPP_DEPRECATED_STACK_LIMIT 1000
265 #endif
267 static size_t const stackLimit_g = JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
269 namespace Json {
271 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
272 typedef std::unique_ptr<CharReader> CharReaderPtr;
273 #else
274 typedef std::auto_ptr<CharReader> CharReaderPtr;
275 #endif
277 // Implementation of class Features
278 // ////////////////////////////////
280 Features::Features()
281 : allowComments_(true), strictRoot_(false),
282 allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
284 Features Features::all() { return Features(); }
286 Features Features::strictMode() {
287 Features features;
288 features.allowComments_ = false;
289 features.strictRoot_ = true;
290 features.allowDroppedNullPlaceholders_ = false;
291 features.allowNumericKeys_ = false;
292 return features;
295 // Implementation of class Reader
296 // ////////////////////////////////
298 bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
299 for (; begin < end; ++begin)
300 if (*begin == '\n' || *begin == '\r')
301 return true;
302 return false;
305 // Class Reader
306 // //////////////////////////////////////////////////////////////////
308 Reader::Reader()
309 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
310 lastValue_(), commentsBefore_(), features_(Features::all()),
311 collectComments_() {}
313 Reader::Reader(const Features& features)
314 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
315 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
318 bool
319 Reader::parse(const std::string& document, Value& root, bool collectComments) {
320 document_.assign(document.begin(), document.end());
321 const char* begin = document_.c_str();
322 const char* end = begin + document_.length();
323 return parse(begin, end, root, collectComments);
326 bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
327 // std::istream_iterator<char> begin(sin);
328 // std::istream_iterator<char> end;
329 // Those would allow streamed input from a file, if parse() were a
330 // template function.
332 // Since JSONCPP_STRING is reference-counted, this at least does not
333 // create an extra copy.
334 JSONCPP_STRING doc;
335 std::getline(sin, doc, (char)EOF);
336 return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
339 bool Reader::parse(const char* beginDoc,
340 const char* endDoc,
341 Value& root,
342 bool collectComments) {
343 if (!features_.allowComments_) {
344 collectComments = false;
347 begin_ = beginDoc;
348 end_ = endDoc;
349 collectComments_ = collectComments;
350 current_ = begin_;
351 lastValueEnd_ = 0;
352 lastValue_ = 0;
353 commentsBefore_.clear();
354 errors_.clear();
355 while (!nodes_.empty())
356 nodes_.pop();
357 nodes_.push(&root);
359 bool successful = readValue();
360 Token token;
361 skipCommentTokens(token);
362 if (collectComments_ && !commentsBefore_.empty())
363 root.setComment(commentsBefore_, commentAfter);
364 if (features_.strictRoot_) {
365 if (!root.isArray() && !root.isObject()) {
366 // Set error location to start of doc, ideally should be first token found
367 // in doc
368 token.type_ = tokenError;
369 token.start_ = beginDoc;
370 token.end_ = endDoc;
371 addError(
372 "A valid JSON document must be either an array or an object value.",
373 token);
374 return false;
377 return successful;
380 bool Reader::readValue() {
381 // readValue() may call itself only if it calls readObject() or ReadArray().
382 // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue().
383 // parse() executes one nodes_.push(), so > instead of >=.
384 if (nodes_.size() > stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
386 Token token;
387 skipCommentTokens(token);
388 bool successful = true;
390 if (collectComments_ && !commentsBefore_.empty()) {
391 currentValue().setComment(commentsBefore_, commentBefore);
392 commentsBefore_.clear();
395 switch (token.type_) {
396 case tokenObjectBegin:
397 successful = readObject(token);
398 currentValue().setOffsetLimit(current_ - begin_);
399 break;
400 case tokenArrayBegin:
401 successful = readArray(token);
402 currentValue().setOffsetLimit(current_ - begin_);
403 break;
404 case tokenNumber:
405 successful = decodeNumber(token);
406 break;
407 case tokenString:
408 successful = decodeString(token);
409 break;
410 case tokenTrue:
412 Value v(true);
413 currentValue().swapPayload(v);
414 currentValue().setOffsetStart(token.start_ - begin_);
415 currentValue().setOffsetLimit(token.end_ - begin_);
417 break;
418 case tokenFalse:
420 Value v(false);
421 currentValue().swapPayload(v);
422 currentValue().setOffsetStart(token.start_ - begin_);
423 currentValue().setOffsetLimit(token.end_ - begin_);
425 break;
426 case tokenNull:
428 Value v;
429 currentValue().swapPayload(v);
430 currentValue().setOffsetStart(token.start_ - begin_);
431 currentValue().setOffsetLimit(token.end_ - begin_);
433 break;
434 case tokenArraySeparator:
435 case tokenObjectEnd:
436 case tokenArrayEnd:
437 if (features_.allowDroppedNullPlaceholders_) {
438 // "Un-read" the current token and mark the current value as a null
439 // token.
440 current_--;
441 Value v;
442 currentValue().swapPayload(v);
443 currentValue().setOffsetStart(current_ - begin_ - 1);
444 currentValue().setOffsetLimit(current_ - begin_);
445 break;
446 } // Else, fall through...
447 default:
448 currentValue().setOffsetStart(token.start_ - begin_);
449 currentValue().setOffsetLimit(token.end_ - begin_);
450 return addError("Syntax error: value, object or array expected.", token);
453 if (collectComments_) {
454 lastValueEnd_ = current_;
455 lastValue_ = &currentValue();
458 return successful;
461 void Reader::skipCommentTokens(Token& token) {
462 if (features_.allowComments_) {
463 do {
464 readToken(token);
465 } while (token.type_ == tokenComment);
466 } else {
467 readToken(token);
471 bool Reader::readToken(Token& token) {
472 skipSpaces();
473 token.start_ = current_;
474 Char c = getNextChar();
475 bool ok = true;
476 switch (c) {
477 case '{':
478 token.type_ = tokenObjectBegin;
479 break;
480 case '}':
481 token.type_ = tokenObjectEnd;
482 break;
483 case '[':
484 token.type_ = tokenArrayBegin;
485 break;
486 case ']':
487 token.type_ = tokenArrayEnd;
488 break;
489 case '"':
490 token.type_ = tokenString;
491 ok = readString();
492 break;
493 case '/':
494 token.type_ = tokenComment;
495 ok = readComment();
496 break;
497 case '0':
498 case '1':
499 case '2':
500 case '3':
501 case '4':
502 case '5':
503 case '6':
504 case '7':
505 case '8':
506 case '9':
507 case '-':
508 token.type_ = tokenNumber;
509 readNumber();
510 break;
511 case 't':
512 token.type_ = tokenTrue;
513 ok = match("rue", 3);
514 break;
515 case 'f':
516 token.type_ = tokenFalse;
517 ok = match("alse", 4);
518 break;
519 case 'n':
520 token.type_ = tokenNull;
521 ok = match("ull", 3);
522 break;
523 case ',':
524 token.type_ = tokenArraySeparator;
525 break;
526 case ':':
527 token.type_ = tokenMemberSeparator;
528 break;
529 case 0:
530 token.type_ = tokenEndOfStream;
531 break;
532 default:
533 ok = false;
534 break;
536 if (!ok)
537 token.type_ = tokenError;
538 token.end_ = current_;
539 return true;
542 void Reader::skipSpaces() {
543 while (current_ != end_) {
544 Char c = *current_;
545 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
546 ++current_;
547 else
548 break;
552 bool Reader::match(Location pattern, int patternLength) {
553 if (end_ - current_ < patternLength)
554 return false;
555 int index = patternLength;
556 while (index--)
557 if (current_[index] != pattern[index])
558 return false;
559 current_ += patternLength;
560 return true;
563 bool Reader::readComment() {
564 Location commentBegin = current_ - 1;
565 Char c = getNextChar();
566 bool successful = false;
567 if (c == '*')
568 successful = readCStyleComment();
569 else if (c == '/')
570 successful = readCppStyleComment();
571 if (!successful)
572 return false;
574 if (collectComments_) {
575 CommentPlacement placement = commentBefore;
576 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
577 if (c != '*' || !containsNewLine(commentBegin, current_))
578 placement = commentAfterOnSameLine;
581 addComment(commentBegin, current_, placement);
583 return true;
586 JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {
587 JSONCPP_STRING normalized;
588 normalized.reserve(static_cast<size_t>(end - begin));
589 Reader::Location current = begin;
590 while (current != end) {
591 char c = *current++;
592 if (c == '\r') {
593 if (current != end && *current == '\n')
594 // convert dos EOL
595 ++current;
596 // convert Mac EOL
597 normalized += '\n';
598 } else {
599 normalized += c;
602 return normalized;
605 void
606 Reader::addComment(Location begin, Location end, CommentPlacement placement) {
607 assert(collectComments_);
608 const JSONCPP_STRING& normalized = normalizeEOL(begin, end);
609 if (placement == commentAfterOnSameLine) {
610 assert(lastValue_ != 0);
611 lastValue_->setComment(normalized, placement);
612 } else {
613 commentsBefore_ += normalized;
617 bool Reader::readCStyleComment() {
618 while ((current_ + 1) < end_) {
619 Char c = getNextChar();
620 if (c == '*' && *current_ == '/')
621 break;
623 return getNextChar() == '/';
626 bool Reader::readCppStyleComment() {
627 while (current_ != end_) {
628 Char c = getNextChar();
629 if (c == '\n')
630 break;
631 if (c == '\r') {
632 // Consume DOS EOL. It will be normalized in addComment.
633 if (current_ != end_ && *current_ == '\n')
634 getNextChar();
635 // Break on Moc OS 9 EOL.
636 break;
639 return true;
642 void Reader::readNumber() {
643 const char *p = current_;
644 char c = '0'; // stopgap for already consumed character
645 // integral part
646 while (c >= '0' && c <= '9')
647 c = (current_ = p) < end_ ? *p++ : '\0';
648 // fractional part
649 if (c == '.') {
650 c = (current_ = p) < end_ ? *p++ : '\0';
651 while (c >= '0' && c <= '9')
652 c = (current_ = p) < end_ ? *p++ : '\0';
654 // exponential part
655 if (c == 'e' || c == 'E') {
656 c = (current_ = p) < end_ ? *p++ : '\0';
657 if (c == '+' || c == '-')
658 c = (current_ = p) < end_ ? *p++ : '\0';
659 while (c >= '0' && c <= '9')
660 c = (current_ = p) < end_ ? *p++ : '\0';
664 bool Reader::readString() {
665 Char c = '\0';
666 while (current_ != end_) {
667 c = getNextChar();
668 if (c == '\\')
669 getNextChar();
670 else if (c == '"')
671 break;
673 return c == '"';
676 bool Reader::readObject(Token& tokenStart) {
677 Token tokenName;
678 JSONCPP_STRING name;
679 Value init(objectValue);
680 currentValue().swapPayload(init);
681 currentValue().setOffsetStart(tokenStart.start_ - begin_);
682 while (readToken(tokenName)) {
683 bool initialTokenOk = true;
684 while (tokenName.type_ == tokenComment && initialTokenOk)
685 initialTokenOk = readToken(tokenName);
686 if (!initialTokenOk)
687 break;
688 if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
689 return true;
690 name.clear();
691 if (tokenName.type_ == tokenString) {
692 if (!decodeString(tokenName, name))
693 return recoverFromError(tokenObjectEnd);
694 } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
695 Value numberName;
696 if (!decodeNumber(tokenName, numberName))
697 return recoverFromError(tokenObjectEnd);
698 name = JSONCPP_STRING(numberName.asCString());
699 } else {
700 break;
703 Token colon;
704 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
705 return addErrorAndRecover(
706 "Missing ':' after object member name", colon, tokenObjectEnd);
708 Value& value = currentValue()[name];
709 nodes_.push(&value);
710 bool ok = readValue();
711 nodes_.pop();
712 if (!ok) // error already set
713 return recoverFromError(tokenObjectEnd);
715 Token comma;
716 if (!readToken(comma) ||
717 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
718 comma.type_ != tokenComment)) {
719 return addErrorAndRecover(
720 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
722 bool finalizeTokenOk = true;
723 while (comma.type_ == tokenComment && finalizeTokenOk)
724 finalizeTokenOk = readToken(comma);
725 if (comma.type_ == tokenObjectEnd)
726 return true;
728 return addErrorAndRecover(
729 "Missing '}' or object member name", tokenName, tokenObjectEnd);
732 bool Reader::readArray(Token& tokenStart) {
733 Value init(arrayValue);
734 currentValue().swapPayload(init);
735 currentValue().setOffsetStart(tokenStart.start_ - begin_);
736 skipSpaces();
737 if (current_ != end_ && *current_ == ']') // empty array
739 Token endArray;
740 readToken(endArray);
741 return true;
743 int index = 0;
744 for (;;) {
745 Value& value = currentValue()[index++];
746 nodes_.push(&value);
747 bool ok = readValue();
748 nodes_.pop();
749 if (!ok) // error already set
750 return recoverFromError(tokenArrayEnd);
752 Token token;
753 // Accept Comment after last item in the array.
754 ok = readToken(token);
755 while (token.type_ == tokenComment && ok) {
756 ok = readToken(token);
758 bool badTokenType =
759 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
760 if (!ok || badTokenType) {
761 return addErrorAndRecover(
762 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
764 if (token.type_ == tokenArrayEnd)
765 break;
767 return true;
770 bool Reader::decodeNumber(Token& token) {
771 Value decoded;
772 if (!decodeNumber(token, decoded))
773 return false;
774 currentValue().swapPayload(decoded);
775 currentValue().setOffsetStart(token.start_ - begin_);
776 currentValue().setOffsetLimit(token.end_ - begin_);
777 return true;
780 bool Reader::decodeNumber(Token& token, Value& decoded) {
781 // Attempts to parse the number as an integer. If the number is
782 // larger than the maximum supported value of an integer then
783 // we decode the number as a double.
784 Location current = token.start_;
785 bool isNegative = *current == '-';
786 if (isNegative)
787 ++current;
788 // TODO: Help the compiler do the div and mod at compile time or get rid of them.
789 Value::LargestUInt maxIntegerValue =
790 isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
791 : Value::maxLargestUInt;
792 Value::LargestUInt threshold = maxIntegerValue / 10;
793 Value::LargestUInt value = 0;
794 while (current < token.end_) {
795 Char c = *current++;
796 if (c < '0' || c > '9')
797 return decodeDouble(token, decoded);
798 Value::UInt digit(static_cast<Value::UInt>(c - '0'));
799 if (value >= threshold) {
800 // We've hit or exceeded the max value divided by 10 (rounded down). If
801 // a) we've only just touched the limit, b) this is the last digit, and
802 // c) it's small enough to fit in that rounding delta, we're okay.
803 // Otherwise treat this number as a double to avoid overflow.
804 if (value > threshold || current != token.end_ ||
805 digit > maxIntegerValue % 10) {
806 return decodeDouble(token, decoded);
809 value = value * 10 + digit;
811 if (isNegative && value == maxIntegerValue)
812 decoded = Value::minLargestInt;
813 else if (isNegative)
814 decoded = -Value::LargestInt(value);
815 else if (value <= Value::LargestUInt(Value::maxInt))
816 decoded = Value::LargestInt(value);
817 else
818 decoded = value;
819 return true;
822 bool Reader::decodeDouble(Token& token) {
823 Value decoded;
824 if (!decodeDouble(token, decoded))
825 return false;
826 currentValue().swapPayload(decoded);
827 currentValue().setOffsetStart(token.start_ - begin_);
828 currentValue().setOffsetLimit(token.end_ - begin_);
829 return true;
832 bool Reader::decodeDouble(Token& token, Value& decoded) {
833 double value = 0;
834 JSONCPP_STRING buffer(token.start_, token.end_);
835 JSONCPP_ISTRINGSTREAM is(buffer);
836 if (!(is >> value))
837 return addError("'" + JSONCPP_STRING(token.start_, token.end_) +
838 "' is not a number.",
839 token);
840 decoded = value;
841 return true;
844 bool Reader::decodeString(Token& token) {
845 JSONCPP_STRING decoded_string;
846 if (!decodeString(token, decoded_string))
847 return false;
848 Value decoded(decoded_string);
849 currentValue().swapPayload(decoded);
850 currentValue().setOffsetStart(token.start_ - begin_);
851 currentValue().setOffsetLimit(token.end_ - begin_);
852 return true;
855 bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) {
856 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
857 Location current = token.start_ + 1; // skip '"'
858 Location end = token.end_ - 1; // do not include '"'
859 while (current != end) {
860 Char c = *current++;
861 if (c == '"')
862 break;
863 else if (c == '\\') {
864 if (current == end)
865 return addError("Empty escape sequence in string", token, current);
866 Char escape = *current++;
867 switch (escape) {
868 case '"':
869 decoded += '"';
870 break;
871 case '/':
872 decoded += '/';
873 break;
874 case '\\':
875 decoded += '\\';
876 break;
877 case 'b':
878 decoded += '\b';
879 break;
880 case 'f':
881 decoded += '\f';
882 break;
883 case 'n':
884 decoded += '\n';
885 break;
886 case 'r':
887 decoded += '\r';
888 break;
889 case 't':
890 decoded += '\t';
891 break;
892 case 'u': {
893 unsigned int unicode;
894 if (!decodeUnicodeCodePoint(token, current, end, unicode))
895 return false;
896 decoded += codePointToUTF8(unicode);
897 } break;
898 default:
899 return addError("Bad escape sequence in string", token, current);
901 } else {
902 decoded += c;
905 return true;
908 bool Reader::decodeUnicodeCodePoint(Token& token,
909 Location& current,
910 Location end,
911 unsigned int& unicode) {
913 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
914 return false;
915 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
916 // surrogate pairs
917 if (end - current < 6)
918 return addError(
919 "additional six characters expected to parse unicode surrogate pair.",
920 token,
921 current);
922 unsigned int surrogatePair;
923 if (*(current++) == '\\' && *(current++) == 'u') {
924 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
925 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
926 } else
927 return false;
928 } else
929 return addError("expecting another \\u token to begin the second half of "
930 "a unicode surrogate pair",
931 token,
932 current);
934 return true;
937 bool Reader::decodeUnicodeEscapeSequence(Token& token,
938 Location& current,
939 Location end,
940 unsigned int& ret_unicode) {
941 if (end - current < 4)
942 return addError(
943 "Bad unicode escape sequence in string: four digits expected.",
944 token,
945 current);
946 int unicode = 0;
947 for (int index = 0; index < 4; ++index) {
948 Char c = *current++;
949 unicode *= 16;
950 if (c >= '0' && c <= '9')
951 unicode += c - '0';
952 else if (c >= 'a' && c <= 'f')
953 unicode += c - 'a' + 10;
954 else if (c >= 'A' && c <= 'F')
955 unicode += c - 'A' + 10;
956 else
957 return addError(
958 "Bad unicode escape sequence in string: hexadecimal digit expected.",
959 token,
960 current);
962 ret_unicode = static_cast<unsigned int>(unicode);
963 return true;
966 bool
967 Reader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {
968 ErrorInfo info;
969 info.token_ = token;
970 info.message_ = message;
971 info.extra_ = extra;
972 errors_.push_back(info);
973 return false;
976 bool Reader::recoverFromError(TokenType skipUntilToken) {
977 size_t const errorCount = errors_.size();
978 Token skip;
979 for (;;) {
980 if (!readToken(skip))
981 errors_.resize(errorCount); // discard errors caused by recovery
982 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
983 break;
985 errors_.resize(errorCount);
986 return false;
989 bool Reader::addErrorAndRecover(const JSONCPP_STRING& message,
990 Token& token,
991 TokenType skipUntilToken) {
992 addError(message, token);
993 return recoverFromError(skipUntilToken);
996 Value& Reader::currentValue() { return *(nodes_.top()); }
998 Reader::Char Reader::getNextChar() {
999 if (current_ == end_)
1000 return 0;
1001 return *current_++;
1004 void Reader::getLocationLineAndColumn(Location location,
1005 int& line,
1006 int& column) const {
1007 Location current = begin_;
1008 Location lastLineStart = current;
1009 line = 0;
1010 while (current < location && current != end_) {
1011 Char c = *current++;
1012 if (c == '\r') {
1013 if (*current == '\n')
1014 ++current;
1015 lastLineStart = current;
1016 ++line;
1017 } else if (c == '\n') {
1018 lastLineStart = current;
1019 ++line;
1022 // column & line start at 1
1023 column = int(location - lastLineStart) + 1;
1024 ++line;
1027 JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const {
1028 int line, column;
1029 getLocationLineAndColumn(location, line, column);
1030 char buffer[18 + 16 + 16 + 1];
1031 snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
1032 return buffer;
1035 // Deprecated. Preserved for backward compatibility
1036 JSONCPP_STRING Reader::getFormatedErrorMessages() const {
1037 return getFormattedErrorMessages();
1040 JSONCPP_STRING Reader::getFormattedErrorMessages() const {
1041 JSONCPP_STRING formattedMessage;
1042 for (Errors::const_iterator itError = errors_.begin();
1043 itError != errors_.end();
1044 ++itError) {
1045 const ErrorInfo& error = *itError;
1046 formattedMessage +=
1047 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
1048 formattedMessage += " " + error.message_ + "\n";
1049 if (error.extra_)
1050 formattedMessage +=
1051 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
1053 return formattedMessage;
1056 std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
1057 std::vector<Reader::StructuredError> allErrors;
1058 for (Errors::const_iterator itError = errors_.begin();
1059 itError != errors_.end();
1060 ++itError) {
1061 const ErrorInfo& error = *itError;
1062 Reader::StructuredError structured;
1063 structured.offset_start = error.token_.start_ - begin_;
1064 structured.offset_limit = error.token_.end_ - begin_;
1065 structured.message = error.message_;
1066 allErrors.push_back(structured);
1068 return allErrors;
1071 bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) {
1072 ptrdiff_t const length = end_ - begin_;
1073 if(value.getOffsetStart() > length
1074 || value.getOffsetLimit() > length)
1075 return false;
1076 Token token;
1077 token.type_ = tokenError;
1078 token.start_ = begin_ + value.getOffsetStart();
1079 token.end_ = end_ + value.getOffsetLimit();
1080 ErrorInfo info;
1081 info.token_ = token;
1082 info.message_ = message;
1083 info.extra_ = 0;
1084 errors_.push_back(info);
1085 return true;
1088 bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {
1089 ptrdiff_t const length = end_ - begin_;
1090 if(value.getOffsetStart() > length
1091 || value.getOffsetLimit() > length
1092 || extra.getOffsetLimit() > length)
1093 return false;
1094 Token token;
1095 token.type_ = tokenError;
1096 token.start_ = begin_ + value.getOffsetStart();
1097 token.end_ = begin_ + value.getOffsetLimit();
1098 ErrorInfo info;
1099 info.token_ = token;
1100 info.message_ = message;
1101 info.extra_ = begin_ + extra.getOffsetStart();
1102 errors_.push_back(info);
1103 return true;
1106 bool Reader::good() const {
1107 return !errors_.size();
1110 // exact copy of Features
1111 class OurFeatures {
1112 public:
1113 static OurFeatures all();
1114 bool allowComments_;
1115 bool strictRoot_;
1116 bool allowDroppedNullPlaceholders_;
1117 bool allowNumericKeys_;
1118 bool allowSingleQuotes_;
1119 bool failIfExtra_;
1120 bool rejectDupKeys_;
1121 bool allowSpecialFloats_;
1122 int stackLimit_;
1123 }; // OurFeatures
1125 // exact copy of Implementation of class Features
1126 // ////////////////////////////////
1128 OurFeatures OurFeatures::all() { return OurFeatures(); }
1130 // Implementation of class Reader
1131 // ////////////////////////////////
1133 // exact copy of Reader, renamed to OurReader
1134 class OurReader {
1135 public:
1136 typedef char Char;
1137 typedef const Char* Location;
1138 struct StructuredError {
1139 ptrdiff_t offset_start;
1140 ptrdiff_t offset_limit;
1141 JSONCPP_STRING message;
1144 OurReader(OurFeatures const& features);
1145 bool parse(const char* beginDoc,
1146 const char* endDoc,
1147 Value& root,
1148 bool collectComments = true);
1149 JSONCPP_STRING getFormattedErrorMessages() const;
1150 std::vector<StructuredError> getStructuredErrors() const;
1151 bool pushError(const Value& value, const JSONCPP_STRING& message);
1152 bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra);
1153 bool good() const;
1155 private:
1156 OurReader(OurReader const&); // no impl
1157 void operator=(OurReader const&); // no impl
1159 enum TokenType {
1160 tokenEndOfStream = 0,
1161 tokenObjectBegin,
1162 tokenObjectEnd,
1163 tokenArrayBegin,
1164 tokenArrayEnd,
1165 tokenString,
1166 tokenNumber,
1167 tokenTrue,
1168 tokenFalse,
1169 tokenNull,
1170 tokenNaN,
1171 tokenPosInf,
1172 tokenNegInf,
1173 tokenArraySeparator,
1174 tokenMemberSeparator,
1175 tokenComment,
1176 tokenError
1179 class Token {
1180 public:
1181 TokenType type_;
1182 Location start_;
1183 Location end_;
1186 class ErrorInfo {
1187 public:
1188 Token token_;
1189 JSONCPP_STRING message_;
1190 Location extra_;
1193 typedef std::deque<ErrorInfo> Errors;
1195 bool readToken(Token& token);
1196 void skipSpaces();
1197 bool match(Location pattern, int patternLength);
1198 bool readComment();
1199 bool readCStyleComment();
1200 bool readCppStyleComment();
1201 bool readString();
1202 bool readStringSingleQuote();
1203 bool readNumber(bool checkInf);
1204 bool readValue();
1205 bool readObject(Token& token);
1206 bool readArray(Token& token);
1207 bool decodeNumber(Token& token);
1208 bool decodeNumber(Token& token, Value& decoded);
1209 bool decodeString(Token& token);
1210 bool decodeString(Token& token, JSONCPP_STRING& decoded);
1211 bool decodeDouble(Token& token);
1212 bool decodeDouble(Token& token, Value& decoded);
1213 bool decodeUnicodeCodePoint(Token& token,
1214 Location& current,
1215 Location end,
1216 unsigned int& unicode);
1217 bool decodeUnicodeEscapeSequence(Token& token,
1218 Location& current,
1219 Location end,
1220 unsigned int& unicode);
1221 bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0);
1222 bool recoverFromError(TokenType skipUntilToken);
1223 bool addErrorAndRecover(const JSONCPP_STRING& message,
1224 Token& token,
1225 TokenType skipUntilToken);
1226 void skipUntilSpace();
1227 Value& currentValue();
1228 Char getNextChar();
1229 void
1230 getLocationLineAndColumn(Location location, int& line, int& column) const;
1231 JSONCPP_STRING getLocationLineAndColumn(Location location) const;
1232 void addComment(Location begin, Location end, CommentPlacement placement);
1233 void skipCommentTokens(Token& token);
1235 static JSONCPP_STRING normalizeEOL(Location begin, Location end);
1236 static bool containsNewLine(Location begin, Location end);
1238 typedef std::stack<Value*> Nodes;
1239 Nodes nodes_;
1240 Errors errors_;
1241 JSONCPP_STRING document_;
1242 Location begin_;
1243 Location end_;
1244 Location current_;
1245 Location lastValueEnd_;
1246 Value* lastValue_;
1247 JSONCPP_STRING commentsBefore_;
1249 OurFeatures const features_;
1250 bool collectComments_;
1251 }; // OurReader
1253 // complete copy of Read impl, for OurReader
1255 bool OurReader::containsNewLine(OurReader::Location begin, OurReader::Location end) {
1256 for (; begin < end; ++begin)
1257 if (*begin == '\n' || *begin == '\r')
1258 return true;
1259 return false;
1262 OurReader::OurReader(OurFeatures const& features)
1263 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
1264 lastValue_(), commentsBefore_(),
1265 features_(features), collectComments_() {
1268 bool OurReader::parse(const char* beginDoc,
1269 const char* endDoc,
1270 Value& root,
1271 bool collectComments) {
1272 if (!features_.allowComments_) {
1273 collectComments = false;
1276 begin_ = beginDoc;
1277 end_ = endDoc;
1278 collectComments_ = collectComments;
1279 current_ = begin_;
1280 lastValueEnd_ = 0;
1281 lastValue_ = 0;
1282 commentsBefore_.clear();
1283 errors_.clear();
1284 while (!nodes_.empty())
1285 nodes_.pop();
1286 nodes_.push(&root);
1288 bool successful = readValue();
1289 Token token;
1290 skipCommentTokens(token);
1291 if (features_.failIfExtra_) {
1292 if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) {
1293 addError("Extra non-whitespace after JSON value.", token);
1294 return false;
1297 if (collectComments_ && !commentsBefore_.empty())
1298 root.setComment(commentsBefore_, commentAfter);
1299 if (features_.strictRoot_) {
1300 if (!root.isArray() && !root.isObject()) {
1301 // Set error location to start of doc, ideally should be first token found
1302 // in doc
1303 token.type_ = tokenError;
1304 token.start_ = beginDoc;
1305 token.end_ = endDoc;
1306 addError(
1307 "A valid JSON document must be either an array or an object value.",
1308 token);
1309 return false;
1312 return successful;
1315 bool OurReader::readValue() {
1316 // To preserve the old behaviour we cast size_t to int.
1317 if (static_cast<int>(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
1318 Token token;
1319 skipCommentTokens(token);
1320 bool successful = true;
1322 if (collectComments_ && !commentsBefore_.empty()) {
1323 currentValue().setComment(commentsBefore_, commentBefore);
1324 commentsBefore_.clear();
1327 switch (token.type_) {
1328 case tokenObjectBegin:
1329 successful = readObject(token);
1330 currentValue().setOffsetLimit(current_ - begin_);
1331 break;
1332 case tokenArrayBegin:
1333 successful = readArray(token);
1334 currentValue().setOffsetLimit(current_ - begin_);
1335 break;
1336 case tokenNumber:
1337 successful = decodeNumber(token);
1338 break;
1339 case tokenString:
1340 successful = decodeString(token);
1341 break;
1342 case tokenTrue:
1344 Value v(true);
1345 currentValue().swapPayload(v);
1346 currentValue().setOffsetStart(token.start_ - begin_);
1347 currentValue().setOffsetLimit(token.end_ - begin_);
1349 break;
1350 case tokenFalse:
1352 Value v(false);
1353 currentValue().swapPayload(v);
1354 currentValue().setOffsetStart(token.start_ - begin_);
1355 currentValue().setOffsetLimit(token.end_ - begin_);
1357 break;
1358 case tokenNull:
1360 Value v;
1361 currentValue().swapPayload(v);
1362 currentValue().setOffsetStart(token.start_ - begin_);
1363 currentValue().setOffsetLimit(token.end_ - begin_);
1365 break;
1366 case tokenNaN:
1368 Value v(std::numeric_limits<double>::quiet_NaN());
1369 currentValue().swapPayload(v);
1370 currentValue().setOffsetStart(token.start_ - begin_);
1371 currentValue().setOffsetLimit(token.end_ - begin_);
1373 break;
1374 case tokenPosInf:
1376 Value v(std::numeric_limits<double>::infinity());
1377 currentValue().swapPayload(v);
1378 currentValue().setOffsetStart(token.start_ - begin_);
1379 currentValue().setOffsetLimit(token.end_ - begin_);
1381 break;
1382 case tokenNegInf:
1384 Value v(-std::numeric_limits<double>::infinity());
1385 currentValue().swapPayload(v);
1386 currentValue().setOffsetStart(token.start_ - begin_);
1387 currentValue().setOffsetLimit(token.end_ - begin_);
1389 break;
1390 case tokenArraySeparator:
1391 case tokenObjectEnd:
1392 case tokenArrayEnd:
1393 if (features_.allowDroppedNullPlaceholders_) {
1394 // "Un-read" the current token and mark the current value as a null
1395 // token.
1396 current_--;
1397 Value v;
1398 currentValue().swapPayload(v);
1399 currentValue().setOffsetStart(current_ - begin_ - 1);
1400 currentValue().setOffsetLimit(current_ - begin_);
1401 break;
1402 } // else, fall through ...
1403 default:
1404 currentValue().setOffsetStart(token.start_ - begin_);
1405 currentValue().setOffsetLimit(token.end_ - begin_);
1406 return addError("Syntax error: value, object or array expected.", token);
1409 if (collectComments_) {
1410 lastValueEnd_ = current_;
1411 lastValue_ = &currentValue();
1414 return successful;
1417 void OurReader::skipCommentTokens(Token& token) {
1418 if (features_.allowComments_) {
1419 do {
1420 readToken(token);
1421 } while (token.type_ == tokenComment);
1422 } else {
1423 readToken(token);
1427 bool OurReader::readToken(Token& token) {
1428 skipSpaces();
1429 token.start_ = current_;
1430 Char c = getNextChar();
1431 bool ok = true;
1432 switch (c) {
1433 case '{':
1434 token.type_ = tokenObjectBegin;
1435 break;
1436 case '}':
1437 token.type_ = tokenObjectEnd;
1438 break;
1439 case '[':
1440 token.type_ = tokenArrayBegin;
1441 break;
1442 case ']':
1443 token.type_ = tokenArrayEnd;
1444 break;
1445 case '"':
1446 token.type_ = tokenString;
1447 ok = readString();
1448 break;
1449 case '\'':
1450 if (features_.allowSingleQuotes_) {
1451 token.type_ = tokenString;
1452 ok = readStringSingleQuote();
1453 break;
1454 } // else fall through
1455 case '/':
1456 token.type_ = tokenComment;
1457 ok = readComment();
1458 break;
1459 case '0':
1460 case '1':
1461 case '2':
1462 case '3':
1463 case '4':
1464 case '5':
1465 case '6':
1466 case '7':
1467 case '8':
1468 case '9':
1469 token.type_ = tokenNumber;
1470 readNumber(false);
1471 break;
1472 case '-':
1473 if (readNumber(true)) {
1474 token.type_ = tokenNumber;
1475 } else {
1476 token.type_ = tokenNegInf;
1477 ok = features_.allowSpecialFloats_ && match("nfinity", 7);
1479 break;
1480 case 't':
1481 token.type_ = tokenTrue;
1482 ok = match("rue", 3);
1483 break;
1484 case 'f':
1485 token.type_ = tokenFalse;
1486 ok = match("alse", 4);
1487 break;
1488 case 'n':
1489 token.type_ = tokenNull;
1490 ok = match("ull", 3);
1491 break;
1492 case 'N':
1493 if (features_.allowSpecialFloats_) {
1494 token.type_ = tokenNaN;
1495 ok = match("aN", 2);
1496 } else {
1497 ok = false;
1499 break;
1500 case 'I':
1501 if (features_.allowSpecialFloats_) {
1502 token.type_ = tokenPosInf;
1503 ok = match("nfinity", 7);
1504 } else {
1505 ok = false;
1507 break;
1508 case ',':
1509 token.type_ = tokenArraySeparator;
1510 break;
1511 case ':':
1512 token.type_ = tokenMemberSeparator;
1513 break;
1514 case 0:
1515 token.type_ = tokenEndOfStream;
1516 break;
1517 default:
1518 ok = false;
1519 break;
1521 if (!ok)
1522 token.type_ = tokenError;
1523 token.end_ = current_;
1524 return true;
1527 void OurReader::skipSpaces() {
1528 while (current_ != end_) {
1529 Char c = *current_;
1530 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
1531 ++current_;
1532 else
1533 break;
1537 bool OurReader::match(Location pattern, int patternLength) {
1538 if (end_ - current_ < patternLength)
1539 return false;
1540 int index = patternLength;
1541 while (index--)
1542 if (current_[index] != pattern[index])
1543 return false;
1544 current_ += patternLength;
1545 return true;
1548 bool OurReader::readComment() {
1549 Location commentBegin = current_ - 1;
1550 Char c = getNextChar();
1551 bool successful = false;
1552 if (c == '*')
1553 successful = readCStyleComment();
1554 else if (c == '/')
1555 successful = readCppStyleComment();
1556 if (!successful)
1557 return false;
1559 if (collectComments_) {
1560 CommentPlacement placement = commentBefore;
1561 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1562 if (c != '*' || !containsNewLine(commentBegin, current_))
1563 placement = commentAfterOnSameLine;
1566 addComment(commentBegin, current_, placement);
1568 return true;
1571 JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, OurReader::Location end) {
1572 JSONCPP_STRING normalized;
1573 normalized.reserve(static_cast<size_t>(end - begin));
1574 OurReader::Location current = begin;
1575 while (current != end) {
1576 char c = *current++;
1577 if (c == '\r') {
1578 if (current != end && *current == '\n')
1579 // convert dos EOL
1580 ++current;
1581 // convert Mac EOL
1582 normalized += '\n';
1583 } else {
1584 normalized += c;
1587 return normalized;
1590 void
1591 OurReader::addComment(Location begin, Location end, CommentPlacement placement) {
1592 assert(collectComments_);
1593 const JSONCPP_STRING& normalized = normalizeEOL(begin, end);
1594 if (placement == commentAfterOnSameLine) {
1595 assert(lastValue_ != 0);
1596 lastValue_->setComment(normalized, placement);
1597 } else {
1598 commentsBefore_ += normalized;
1602 bool OurReader::readCStyleComment() {
1603 while ((current_ + 1) < end_) {
1604 Char c = getNextChar();
1605 if (c == '*' && *current_ == '/')
1606 break;
1608 return getNextChar() == '/';
1611 bool OurReader::readCppStyleComment() {
1612 while (current_ != end_) {
1613 Char c = getNextChar();
1614 if (c == '\n')
1615 break;
1616 if (c == '\r') {
1617 // Consume DOS EOL. It will be normalized in addComment.
1618 if (current_ != end_ && *current_ == '\n')
1619 getNextChar();
1620 // Break on Moc OS 9 EOL.
1621 break;
1624 return true;
1627 bool OurReader::readNumber(bool checkInf) {
1628 const char *p = current_;
1629 if (checkInf && p != end_ && *p == 'I') {
1630 current_ = ++p;
1631 return false;
1633 char c = '0'; // stopgap for already consumed character
1634 // integral part
1635 while (c >= '0' && c <= '9')
1636 c = (current_ = p) < end_ ? *p++ : '\0';
1637 // fractional part
1638 if (c == '.') {
1639 c = (current_ = p) < end_ ? *p++ : '\0';
1640 while (c >= '0' && c <= '9')
1641 c = (current_ = p) < end_ ? *p++ : '\0';
1643 // exponential part
1644 if (c == 'e' || c == 'E') {
1645 c = (current_ = p) < end_ ? *p++ : '\0';
1646 if (c == '+' || c == '-')
1647 c = (current_ = p) < end_ ? *p++ : '\0';
1648 while (c >= '0' && c <= '9')
1649 c = (current_ = p) < end_ ? *p++ : '\0';
1651 return true;
1653 bool OurReader::readString() {
1654 Char c = 0;
1655 while (current_ != end_) {
1656 c = getNextChar();
1657 if (c == '\\')
1658 getNextChar();
1659 else if (c == '"')
1660 break;
1662 return c == '"';
1666 bool OurReader::readStringSingleQuote() {
1667 Char c = 0;
1668 while (current_ != end_) {
1669 c = getNextChar();
1670 if (c == '\\')
1671 getNextChar();
1672 else if (c == '\'')
1673 break;
1675 return c == '\'';
1678 bool OurReader::readObject(Token& tokenStart) {
1679 Token tokenName;
1680 JSONCPP_STRING name;
1681 Value init(objectValue);
1682 currentValue().swapPayload(init);
1683 currentValue().setOffsetStart(tokenStart.start_ - begin_);
1684 while (readToken(tokenName)) {
1685 bool initialTokenOk = true;
1686 while (tokenName.type_ == tokenComment && initialTokenOk)
1687 initialTokenOk = readToken(tokenName);
1688 if (!initialTokenOk)
1689 break;
1690 if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
1691 return true;
1692 name.clear();
1693 if (tokenName.type_ == tokenString) {
1694 if (!decodeString(tokenName, name))
1695 return recoverFromError(tokenObjectEnd);
1696 } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1697 Value numberName;
1698 if (!decodeNumber(tokenName, numberName))
1699 return recoverFromError(tokenObjectEnd);
1700 name = numberName.asString();
1701 } else {
1702 break;
1705 Token colon;
1706 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1707 return addErrorAndRecover(
1708 "Missing ':' after object member name", colon, tokenObjectEnd);
1710 if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
1711 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1712 JSONCPP_STRING msg = "Duplicate key: '" + name + "'";
1713 return addErrorAndRecover(
1714 msg, tokenName, tokenObjectEnd);
1716 Value& value = currentValue()[name];
1717 nodes_.push(&value);
1718 bool ok = readValue();
1719 nodes_.pop();
1720 if (!ok) // error already set
1721 return recoverFromError(tokenObjectEnd);
1723 Token comma;
1724 if (!readToken(comma) ||
1725 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1726 comma.type_ != tokenComment)) {
1727 return addErrorAndRecover(
1728 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
1730 bool finalizeTokenOk = true;
1731 while (comma.type_ == tokenComment && finalizeTokenOk)
1732 finalizeTokenOk = readToken(comma);
1733 if (comma.type_ == tokenObjectEnd)
1734 return true;
1736 return addErrorAndRecover(
1737 "Missing '}' or object member name", tokenName, tokenObjectEnd);
1740 bool OurReader::readArray(Token& tokenStart) {
1741 Value init(arrayValue);
1742 currentValue().swapPayload(init);
1743 currentValue().setOffsetStart(tokenStart.start_ - begin_);
1744 skipSpaces();
1745 if (current_ != end_ && *current_ == ']') // empty array
1747 Token endArray;
1748 readToken(endArray);
1749 return true;
1751 int index = 0;
1752 for (;;) {
1753 Value& value = currentValue()[index++];
1754 nodes_.push(&value);
1755 bool ok = readValue();
1756 nodes_.pop();
1757 if (!ok) // error already set
1758 return recoverFromError(tokenArrayEnd);
1760 Token token;
1761 // Accept Comment after last item in the array.
1762 ok = readToken(token);
1763 while (token.type_ == tokenComment && ok) {
1764 ok = readToken(token);
1766 bool badTokenType =
1767 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
1768 if (!ok || badTokenType) {
1769 return addErrorAndRecover(
1770 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
1772 if (token.type_ == tokenArrayEnd)
1773 break;
1775 return true;
1778 bool OurReader::decodeNumber(Token& token) {
1779 Value decoded;
1780 if (!decodeNumber(token, decoded))
1781 return false;
1782 currentValue().swapPayload(decoded);
1783 currentValue().setOffsetStart(token.start_ - begin_);
1784 currentValue().setOffsetLimit(token.end_ - begin_);
1785 return true;
1788 bool OurReader::decodeNumber(Token& token, Value& decoded) {
1789 // Attempts to parse the number as an integer. If the number is
1790 // larger than the maximum supported value of an integer then
1791 // we decode the number as a double.
1792 Location current = token.start_;
1793 bool isNegative = *current == '-';
1794 if (isNegative)
1795 ++current;
1796 // TODO: Help the compiler do the div and mod at compile time or get rid of them.
1797 Value::LargestUInt maxIntegerValue =
1798 isNegative ? Value::LargestUInt(-Value::minLargestInt)
1799 : Value::maxLargestUInt;
1800 Value::LargestUInt threshold = maxIntegerValue / 10;
1801 Value::LargestUInt value = 0;
1802 while (current < token.end_) {
1803 Char c = *current++;
1804 if (c < '0' || c > '9')
1805 return decodeDouble(token, decoded);
1806 Value::UInt digit(static_cast<Value::UInt>(c - '0'));
1807 if (value >= threshold) {
1808 // We've hit or exceeded the max value divided by 10 (rounded down). If
1809 // a) we've only just touched the limit, b) this is the last digit, and
1810 // c) it's small enough to fit in that rounding delta, we're okay.
1811 // Otherwise treat this number as a double to avoid overflow.
1812 if (value > threshold || current != token.end_ ||
1813 digit > maxIntegerValue % 10) {
1814 return decodeDouble(token, decoded);
1817 value = value * 10 + digit;
1819 if (isNegative)
1820 decoded = -Value::LargestInt(value);
1821 else if (value <= Value::LargestUInt(Value::maxInt))
1822 decoded = Value::LargestInt(value);
1823 else
1824 decoded = value;
1825 return true;
1828 bool OurReader::decodeDouble(Token& token) {
1829 Value decoded;
1830 if (!decodeDouble(token, decoded))
1831 return false;
1832 currentValue().swapPayload(decoded);
1833 currentValue().setOffsetStart(token.start_ - begin_);
1834 currentValue().setOffsetLimit(token.end_ - begin_);
1835 return true;
1838 bool OurReader::decodeDouble(Token& token, Value& decoded) {
1839 double value = 0;
1840 const int bufferSize = 32;
1841 int count;
1842 ptrdiff_t const length = token.end_ - token.start_;
1844 // Sanity check to avoid buffer overflow exploits.
1845 if (length < 0) {
1846 return addError("Unable to parse token length", token);
1848 size_t const ulength = static_cast<size_t>(length);
1850 // Avoid using a string constant for the format control string given to
1851 // sscanf, as this can cause hard to debug crashes on OS X. See here for more
1852 // info:
1854 // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
1855 char format[] = "%lf";
1857 if (length <= bufferSize) {
1858 Char buffer[bufferSize + 1];
1859 memcpy(buffer, token.start_, ulength);
1860 buffer[length] = 0;
1861 fixNumericLocaleInput(buffer, buffer + length);
1862 count = sscanf(buffer, format, &value);
1863 } else {
1864 JSONCPP_STRING buffer(token.start_, token.end_);
1865 count = sscanf(buffer.c_str(), format, &value);
1868 if (count != 1)
1869 return addError("'" + JSONCPP_STRING(token.start_, token.end_) +
1870 "' is not a number.",
1871 token);
1872 decoded = value;
1873 return true;
1876 bool OurReader::decodeString(Token& token) {
1877 JSONCPP_STRING decoded_string;
1878 if (!decodeString(token, decoded_string))
1879 return false;
1880 Value decoded(decoded_string);
1881 currentValue().swapPayload(decoded);
1882 currentValue().setOffsetStart(token.start_ - begin_);
1883 currentValue().setOffsetLimit(token.end_ - begin_);
1884 return true;
1887 bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) {
1888 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
1889 Location current = token.start_ + 1; // skip '"'
1890 Location end = token.end_ - 1; // do not include '"'
1891 while (current != end) {
1892 Char c = *current++;
1893 if (c == '"')
1894 break;
1895 else if (c == '\\') {
1896 if (current == end)
1897 return addError("Empty escape sequence in string", token, current);
1898 Char escape = *current++;
1899 switch (escape) {
1900 case '"':
1901 decoded += '"';
1902 break;
1903 case '/':
1904 decoded += '/';
1905 break;
1906 case '\\':
1907 decoded += '\\';
1908 break;
1909 case 'b':
1910 decoded += '\b';
1911 break;
1912 case 'f':
1913 decoded += '\f';
1914 break;
1915 case 'n':
1916 decoded += '\n';
1917 break;
1918 case 'r':
1919 decoded += '\r';
1920 break;
1921 case 't':
1922 decoded += '\t';
1923 break;
1924 case 'u': {
1925 unsigned int unicode;
1926 if (!decodeUnicodeCodePoint(token, current, end, unicode))
1927 return false;
1928 decoded += codePointToUTF8(unicode);
1929 } break;
1930 default:
1931 return addError("Bad escape sequence in string", token, current);
1933 } else {
1934 decoded += c;
1937 return true;
1940 bool OurReader::decodeUnicodeCodePoint(Token& token,
1941 Location& current,
1942 Location end,
1943 unsigned int& unicode) {
1945 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1946 return false;
1947 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1948 // surrogate pairs
1949 if (end - current < 6)
1950 return addError(
1951 "additional six characters expected to parse unicode surrogate pair.",
1952 token,
1953 current);
1954 unsigned int surrogatePair;
1955 if (*(current++) == '\\' && *(current++) == 'u') {
1956 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1957 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1958 } else
1959 return false;
1960 } else
1961 return addError("expecting another \\u token to begin the second half of "
1962 "a unicode surrogate pair",
1963 token,
1964 current);
1966 return true;
1969 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
1970 Location& current,
1971 Location end,
1972 unsigned int& ret_unicode) {
1973 if (end - current < 4)
1974 return addError(
1975 "Bad unicode escape sequence in string: four digits expected.",
1976 token,
1977 current);
1978 int unicode = 0;
1979 for (int index = 0; index < 4; ++index) {
1980 Char c = *current++;
1981 unicode *= 16;
1982 if (c >= '0' && c <= '9')
1983 unicode += c - '0';
1984 else if (c >= 'a' && c <= 'f')
1985 unicode += c - 'a' + 10;
1986 else if (c >= 'A' && c <= 'F')
1987 unicode += c - 'A' + 10;
1988 else
1989 return addError(
1990 "Bad unicode escape sequence in string: hexadecimal digit expected.",
1991 token,
1992 current);
1994 ret_unicode = static_cast<unsigned int>(unicode);
1995 return true;
1998 bool
1999 OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {
2000 ErrorInfo info;
2001 info.token_ = token;
2002 info.message_ = message;
2003 info.extra_ = extra;
2004 errors_.push_back(info);
2005 return false;
2008 bool OurReader::recoverFromError(TokenType skipUntilToken) {
2009 size_t errorCount = errors_.size();
2010 Token skip;
2011 for (;;) {
2012 if (!readToken(skip))
2013 errors_.resize(errorCount); // discard errors caused by recovery
2014 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
2015 break;
2017 errors_.resize(errorCount);
2018 return false;
2021 bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message,
2022 Token& token,
2023 TokenType skipUntilToken) {
2024 addError(message, token);
2025 return recoverFromError(skipUntilToken);
2028 Value& OurReader::currentValue() { return *(nodes_.top()); }
2030 OurReader::Char OurReader::getNextChar() {
2031 if (current_ == end_)
2032 return 0;
2033 return *current_++;
2036 void OurReader::getLocationLineAndColumn(Location location,
2037 int& line,
2038 int& column) const {
2039 Location current = begin_;
2040 Location lastLineStart = current;
2041 line = 0;
2042 while (current < location && current != end_) {
2043 Char c = *current++;
2044 if (c == '\r') {
2045 if (*current == '\n')
2046 ++current;
2047 lastLineStart = current;
2048 ++line;
2049 } else if (c == '\n') {
2050 lastLineStart = current;
2051 ++line;
2054 // column & line start at 1
2055 column = int(location - lastLineStart) + 1;
2056 ++line;
2059 JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const {
2060 int line, column;
2061 getLocationLineAndColumn(location, line, column);
2062 char buffer[18 + 16 + 16 + 1];
2063 snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
2064 return buffer;
2067 JSONCPP_STRING OurReader::getFormattedErrorMessages() const {
2068 JSONCPP_STRING formattedMessage;
2069 for (Errors::const_iterator itError = errors_.begin();
2070 itError != errors_.end();
2071 ++itError) {
2072 const ErrorInfo& error = *itError;
2073 formattedMessage +=
2074 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
2075 formattedMessage += " " + error.message_ + "\n";
2076 if (error.extra_)
2077 formattedMessage +=
2078 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
2080 return formattedMessage;
2083 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
2084 std::vector<OurReader::StructuredError> allErrors;
2085 for (Errors::const_iterator itError = errors_.begin();
2086 itError != errors_.end();
2087 ++itError) {
2088 const ErrorInfo& error = *itError;
2089 OurReader::StructuredError structured;
2090 structured.offset_start = error.token_.start_ - begin_;
2091 structured.offset_limit = error.token_.end_ - begin_;
2092 structured.message = error.message_;
2093 allErrors.push_back(structured);
2095 return allErrors;
2098 bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) {
2099 ptrdiff_t length = end_ - begin_;
2100 if(value.getOffsetStart() > length
2101 || value.getOffsetLimit() > length)
2102 return false;
2103 Token token;
2104 token.type_ = tokenError;
2105 token.start_ = begin_ + value.getOffsetStart();
2106 token.end_ = end_ + value.getOffsetLimit();
2107 ErrorInfo info;
2108 info.token_ = token;
2109 info.message_ = message;
2110 info.extra_ = 0;
2111 errors_.push_back(info);
2112 return true;
2115 bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {
2116 ptrdiff_t length = end_ - begin_;
2117 if(value.getOffsetStart() > length
2118 || value.getOffsetLimit() > length
2119 || extra.getOffsetLimit() > length)
2120 return false;
2121 Token token;
2122 token.type_ = tokenError;
2123 token.start_ = begin_ + value.getOffsetStart();
2124 token.end_ = begin_ + value.getOffsetLimit();
2125 ErrorInfo info;
2126 info.token_ = token;
2127 info.message_ = message;
2128 info.extra_ = begin_ + extra.getOffsetStart();
2129 errors_.push_back(info);
2130 return true;
2133 bool OurReader::good() const {
2134 return !errors_.size();
2138 class OurCharReader : public CharReader {
2139 bool const collectComments_;
2140 OurReader reader_;
2141 public:
2142 OurCharReader(
2143 bool collectComments,
2144 OurFeatures const& features)
2145 : collectComments_(collectComments)
2146 , reader_(features)
2148 bool parse(
2149 char const* beginDoc, char const* endDoc,
2150 Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE {
2151 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
2152 if (errs) {
2153 *errs = reader_.getFormattedErrorMessages();
2155 return ok;
2159 CharReaderBuilder::CharReaderBuilder()
2161 setDefaults(&settings_);
2163 CharReaderBuilder::~CharReaderBuilder()
2165 CharReader* CharReaderBuilder::newCharReader() const
2167 bool collectComments = settings_["collectComments"].asBool();
2168 OurFeatures features = OurFeatures::all();
2169 features.allowComments_ = settings_["allowComments"].asBool();
2170 features.strictRoot_ = settings_["strictRoot"].asBool();
2171 features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
2172 features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
2173 features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
2174 features.stackLimit_ = settings_["stackLimit"].asInt();
2175 features.failIfExtra_ = settings_["failIfExtra"].asBool();
2176 features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
2177 features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
2178 return new OurCharReader(collectComments, features);
2180 static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys)
2182 valid_keys->clear();
2183 valid_keys->insert("collectComments");
2184 valid_keys->insert("allowComments");
2185 valid_keys->insert("strictRoot");
2186 valid_keys->insert("allowDroppedNullPlaceholders");
2187 valid_keys->insert("allowNumericKeys");
2188 valid_keys->insert("allowSingleQuotes");
2189 valid_keys->insert("stackLimit");
2190 valid_keys->insert("failIfExtra");
2191 valid_keys->insert("rejectDupKeys");
2192 valid_keys->insert("allowSpecialFloats");
2194 bool CharReaderBuilder::validate(Json::Value* invalid) const
2196 Json::Value my_invalid;
2197 if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
2198 Json::Value& inv = *invalid;
2199 std::set<JSONCPP_STRING> valid_keys;
2200 getValidReaderKeys(&valid_keys);
2201 Value::Members keys = settings_.getMemberNames();
2202 size_t n = keys.size();
2203 for (size_t i = 0; i < n; ++i) {
2204 JSONCPP_STRING const& key = keys[i];
2205 if (valid_keys.find(key) == valid_keys.end()) {
2206 inv[key] = settings_[key];
2209 return 0u == inv.size();
2211 Value& CharReaderBuilder::operator[](JSONCPP_STRING key)
2213 return settings_[key];
2215 // static
2216 void CharReaderBuilder::strictMode(Json::Value* settings)
2218 //! [CharReaderBuilderStrictMode]
2219 (*settings)["allowComments"] = false;
2220 (*settings)["strictRoot"] = true;
2221 (*settings)["allowDroppedNullPlaceholders"] = false;
2222 (*settings)["allowNumericKeys"] = false;
2223 (*settings)["allowSingleQuotes"] = false;
2224 (*settings)["stackLimit"] = 1000;
2225 (*settings)["failIfExtra"] = true;
2226 (*settings)["rejectDupKeys"] = true;
2227 (*settings)["allowSpecialFloats"] = false;
2228 //! [CharReaderBuilderStrictMode]
2230 // static
2231 void CharReaderBuilder::setDefaults(Json::Value* settings)
2233 //! [CharReaderBuilderDefaults]
2234 (*settings)["collectComments"] = true;
2235 (*settings)["allowComments"] = true;
2236 (*settings)["strictRoot"] = false;
2237 (*settings)["allowDroppedNullPlaceholders"] = false;
2238 (*settings)["allowNumericKeys"] = false;
2239 (*settings)["allowSingleQuotes"] = false;
2240 (*settings)["stackLimit"] = 1000;
2241 (*settings)["failIfExtra"] = false;
2242 (*settings)["rejectDupKeys"] = false;
2243 (*settings)["allowSpecialFloats"] = false;
2244 //! [CharReaderBuilderDefaults]
2247 //////////////////////////////////
2248 // global functions
2250 bool parseFromStream(
2251 CharReader::Factory const& fact, JSONCPP_ISTREAM& sin,
2252 Value* root, JSONCPP_STRING* errs)
2254 JSONCPP_OSTRINGSTREAM ssin;
2255 ssin << sin.rdbuf();
2256 JSONCPP_STRING doc = ssin.str();
2257 char const* begin = doc.data();
2258 char const* end = begin + doc.size();
2259 // Note that we do not actually need a null-terminator.
2260 CharReaderPtr const reader(fact.newCharReader());
2261 return reader->parse(begin, end, root, errs);
2264 JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) {
2265 CharReaderBuilder b;
2266 JSONCPP_STRING errs;
2267 bool ok = parseFromStream(b, sin, &root, &errs);
2268 if (!ok) {
2269 throwRuntimeError(errs);
2271 return sin;
2274 } // namespace Json
2276 // //////////////////////////////////////////////////////////////////////
2277 // End of content of file: src/lib_json/json_reader.cpp
2278 // //////////////////////////////////////////////////////////////////////
2285 // //////////////////////////////////////////////////////////////////////
2286 // Beginning of content of file: src/lib_json/json_valueiterator.inl
2287 // //////////////////////////////////////////////////////////////////////
2289 // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
2290 // Distributed under MIT license, or public domain if desired and
2291 // recognized in your jurisdiction.
2292 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
2294 // included by json_value.cpp
2296 namespace Json {
2298 // //////////////////////////////////////////////////////////////////
2299 // //////////////////////////////////////////////////////////////////
2300 // //////////////////////////////////////////////////////////////////
2301 // class ValueIteratorBase
2302 // //////////////////////////////////////////////////////////////////
2303 // //////////////////////////////////////////////////////////////////
2304 // //////////////////////////////////////////////////////////////////
2306 ValueIteratorBase::ValueIteratorBase()
2307 : current_(), isNull_(true) {
2310 ValueIteratorBase::ValueIteratorBase(
2311 const Value::ObjectValues::iterator& current)
2312 : current_(current), isNull_(false) {}
2314 Value& ValueIteratorBase::deref() const {
2315 return current_->second;
2318 void ValueIteratorBase::increment() {
2319 ++current_;
2322 void ValueIteratorBase::decrement() {
2323 --current_;
2326 ValueIteratorBase::difference_type
2327 ValueIteratorBase::computeDistance(const SelfType& other) const {
2328 #ifdef JSON_USE_CPPTL_SMALLMAP
2329 return other.current_ - current_;
2330 #else
2331 // Iterator for null value are initialized using the default
2332 // constructor, which initialize current_ to the default
2333 // std::map::iterator. As begin() and end() are two instance
2334 // of the default std::map::iterator, they can not be compared.
2335 // To allow this, we handle this comparison specifically.
2336 if (isNull_ && other.isNull_) {
2337 return 0;
2340 // Usage of std::distance is not portable (does not compile with Sun Studio 12
2341 // RogueWave STL,
2342 // which is the one used by default).
2343 // Using a portable hand-made version for non random iterator instead:
2344 // return difference_type( std::distance( current_, other.current_ ) );
2345 difference_type myDistance = 0;
2346 for (Value::ObjectValues::iterator it = current_; it != other.current_;
2347 ++it) {
2348 ++myDistance;
2350 return myDistance;
2351 #endif
2354 bool ValueIteratorBase::isEqual(const SelfType& other) const {
2355 if (isNull_) {
2356 return other.isNull_;
2358 return current_ == other.current_;
2361 void ValueIteratorBase::copy(const SelfType& other) {
2362 current_ = other.current_;
2363 isNull_ = other.isNull_;
2366 Value ValueIteratorBase::key() const {
2367 const Value::CZString czstring = (*current_).first;
2368 if (czstring.data()) {
2369 if (czstring.isStaticString())
2370 return Value(StaticString(czstring.data()));
2371 return Value(czstring.data(), czstring.data() + czstring.length());
2373 return Value(czstring.index());
2376 UInt ValueIteratorBase::index() const {
2377 const Value::CZString czstring = (*current_).first;
2378 if (!czstring.data())
2379 return czstring.index();
2380 return Value::UInt(-1);
2383 JSONCPP_STRING ValueIteratorBase::name() const {
2384 char const* keey;
2385 char const* end;
2386 keey = memberName(&end);
2387 if (!keey) return JSONCPP_STRING();
2388 return JSONCPP_STRING(keey, end);
2391 char const* ValueIteratorBase::memberName() const {
2392 const char* cname = (*current_).first.data();
2393 return cname ? cname : "";
2396 char const* ValueIteratorBase::memberName(char const** end) const {
2397 const char* cname = (*current_).first.data();
2398 if (!cname) {
2399 *end = NULL;
2400 return NULL;
2402 *end = cname + (*current_).first.length();
2403 return cname;
2406 // //////////////////////////////////////////////////////////////////
2407 // //////////////////////////////////////////////////////////////////
2408 // //////////////////////////////////////////////////////////////////
2409 // class ValueConstIterator
2410 // //////////////////////////////////////////////////////////////////
2411 // //////////////////////////////////////////////////////////////////
2412 // //////////////////////////////////////////////////////////////////
2414 ValueConstIterator::ValueConstIterator() {}
2416 ValueConstIterator::ValueConstIterator(
2417 const Value::ObjectValues::iterator& current)
2418 : ValueIteratorBase(current) {}
2420 ValueConstIterator::ValueConstIterator(ValueIterator const& other)
2421 : ValueIteratorBase(other) {}
2423 ValueConstIterator& ValueConstIterator::
2424 operator=(const ValueIteratorBase& other) {
2425 copy(other);
2426 return *this;
2429 // //////////////////////////////////////////////////////////////////
2430 // //////////////////////////////////////////////////////////////////
2431 // //////////////////////////////////////////////////////////////////
2432 // class ValueIterator
2433 // //////////////////////////////////////////////////////////////////
2434 // //////////////////////////////////////////////////////////////////
2435 // //////////////////////////////////////////////////////////////////
2437 ValueIterator::ValueIterator() {}
2439 ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
2440 : ValueIteratorBase(current) {}
2442 ValueIterator::ValueIterator(const ValueConstIterator& other)
2443 : ValueIteratorBase(other) {
2444 throwRuntimeError("ConstIterator to Iterator should never be allowed.");
2447 ValueIterator::ValueIterator(const ValueIterator& other)
2448 : ValueIteratorBase(other) {}
2450 ValueIterator& ValueIterator::operator=(const SelfType& other) {
2451 copy(other);
2452 return *this;
2455 } // namespace Json
2457 // //////////////////////////////////////////////////////////////////////
2458 // End of content of file: src/lib_json/json_valueiterator.inl
2459 // //////////////////////////////////////////////////////////////////////
2466 // //////////////////////////////////////////////////////////////////////
2467 // Beginning of content of file: src/lib_json/json_value.cpp
2468 // //////////////////////////////////////////////////////////////////////
2470 // Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
2471 // Distributed under MIT license, or public domain if desired and
2472 // recognized in your jurisdiction.
2473 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
2475 #if !defined(JSON_IS_AMALGAMATION)
2476 #include <json/assertions.h>
2477 #include <json/value.h>
2478 #include <json/writer.h>
2479 #endif // if !defined(JSON_IS_AMALGAMATION)
2480 #include <math.h>
2481 #include <sstream>
2482 #include <utility>
2483 #include <cstring>
2484 #include <cassert>
2485 #ifdef JSON_USE_CPPTL
2486 #include <cpptl/conststring.h>
2487 #endif
2488 #include <cstddef> // size_t
2489 #include <algorithm> // min()
2491 #define JSON_ASSERT_UNREACHABLE assert(false)
2493 namespace Json {
2495 // This is a walkaround to avoid the static initialization of Value::null.
2496 // kNull must be word-aligned to avoid crashing on ARM. We use an alignment of
2497 // 8 (instead of 4) as a bit of future-proofing.
2498 #if defined(__ARMEL__)
2499 #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
2500 #else
2501 #define ALIGNAS(byte_alignment)
2502 #endif
2503 //static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
2504 //const unsigned char& kNullRef = kNull[0];
2505 //const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
2506 //const Value& Value::nullRef = null;
2508 // static
2509 Value const& Value::nullSingleton()
2511 static Value const nullStatic;
2512 return nullStatic;
2515 // for backwards compatibility, we'll leave these global references around, but DO NOT
2516 // use them in JSONCPP library code any more!
2517 Value const& Value::null = Value::nullSingleton();
2518 Value const& Value::nullRef = Value::nullSingleton();
2520 const Int Value::minInt = Int(~(UInt(-1) / 2));
2521 const Int Value::maxInt = Int(UInt(-1) / 2);
2522 const UInt Value::maxUInt = UInt(-1);
2523 #if defined(JSON_HAS_INT64)
2524 const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));
2525 const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);
2526 const UInt64 Value::maxUInt64 = UInt64(-1);
2527 // The constant is hard-coded because some compiler have trouble
2528 // converting Value::maxUInt64 to a double correctly (AIX/xlC).
2529 // Assumes that UInt64 is a 64 bits integer.
2530 static const double maxUInt64AsDouble = 18446744073709551615.0;
2531 #endif // defined(JSON_HAS_INT64)
2532 const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
2533 const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
2534 const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
2536 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2537 template <typename T, typename U>
2538 static inline bool InRange(double d, T min, U max) {
2539 // The casts can lose precision, but we are looking only for
2540 // an approximate range. Might fail on edge cases though. ~cdunn
2541 //return d >= static_cast<double>(min) && d <= static_cast<double>(max);
2542 return d >= min && d <= max;
2544 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2545 static inline double integerToDouble(Json::UInt64 value) {
2546 return static_cast<double>(Int64(value / 2)) * 2.0 + static_cast<double>(Int64(value & 1));
2549 template <typename T> static inline double integerToDouble(T value) {
2550 return static_cast<double>(value);
2553 template <typename T, typename U>
2554 static inline bool InRange(double d, T min, U max) {
2555 return d >= integerToDouble(min) && d <= integerToDouble(max);
2557 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2559 /** Duplicates the specified string value.
2560 * @param value Pointer to the string to duplicate. Must be zero-terminated if
2561 * length is "unknown".
2562 * @param length Length of the value. if equals to unknown, then it will be
2563 * computed using strlen(value).
2564 * @return Pointer on the duplicate instance of string.
2566 static inline char* duplicateStringValue(const char* value,
2567 size_t length)
2569 // Avoid an integer overflow in the call to malloc below by limiting length
2570 // to a sane value.
2571 if (length >= static_cast<size_t>(Value::maxInt))
2572 length = Value::maxInt - 1;
2574 char* newString = static_cast<char*>(malloc(length + 1));
2575 if (newString == NULL) {
2576 throwRuntimeError(
2577 "in Json::Value::duplicateStringValue(): "
2578 "Failed to allocate string value buffer");
2580 memcpy(newString, value, length);
2581 newString[length] = 0;
2582 return newString;
2585 /* Record the length as a prefix.
2587 static inline char* duplicateAndPrefixStringValue(
2588 const char* value,
2589 unsigned int length)
2591 // Avoid an integer overflow in the call to malloc below by limiting length
2592 // to a sane value.
2593 JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) - sizeof(unsigned) - 1U,
2594 "in Json::Value::duplicateAndPrefixStringValue(): "
2595 "length too big for prefixing");
2596 unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;
2597 char* newString = static_cast<char*>(malloc(actualLength));
2598 if (newString == 0) {
2599 throwRuntimeError(
2600 "in Json::Value::duplicateAndPrefixStringValue(): "
2601 "Failed to allocate string value buffer");
2603 *reinterpret_cast<unsigned*>(newString) = length;
2604 memcpy(newString + sizeof(unsigned), value, length);
2605 newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
2606 return newString;
2608 inline static void decodePrefixedString(
2609 bool isPrefixed, char const* prefixed,
2610 unsigned* length, char const** value)
2612 if (!isPrefixed) {
2613 *length = static_cast<unsigned>(strlen(prefixed));
2614 *value = prefixed;
2615 } else {
2616 *length = *reinterpret_cast<unsigned const*>(prefixed);
2617 *value = prefixed + sizeof(unsigned);
2620 /** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue().
2622 #if JSONCPP_USING_SECURE_MEMORY
2623 static inline void releasePrefixedStringValue(char* value) {
2624 unsigned length = 0;
2625 char const* valueDecoded;
2626 decodePrefixedString(true, value, &length, &valueDecoded);
2627 size_t const size = sizeof(unsigned) + length + 1U;
2628 memset(value, 0, size);
2629 free(value);
2631 static inline void releaseStringValue(char* value, unsigned length) {
2632 // length==0 => we allocated the strings memory
2633 size_t size = (length==0) ? strlen(value) : length;
2634 memset(value, 0, size);
2635 free(value);
2637 #else // !JSONCPP_USING_SECURE_MEMORY
2638 static inline void releasePrefixedStringValue(char* value) {
2639 free(value);
2641 static inline void releaseStringValue(char* value, unsigned) {
2642 free(value);
2644 #endif // JSONCPP_USING_SECURE_MEMORY
2646 } // namespace Json
2648 // //////////////////////////////////////////////////////////////////
2649 // //////////////////////////////////////////////////////////////////
2650 // //////////////////////////////////////////////////////////////////
2651 // ValueInternals...
2652 // //////////////////////////////////////////////////////////////////
2653 // //////////////////////////////////////////////////////////////////
2654 // //////////////////////////////////////////////////////////////////
2655 #if !defined(JSON_IS_AMALGAMATION)
2657 #include "json_valueiterator.inl"
2658 #endif // if !defined(JSON_IS_AMALGAMATION)
2660 namespace Json {
2662 Exception::Exception(JSONCPP_STRING const& msg)
2663 : msg_(msg)
2665 Exception::~Exception() JSONCPP_NOEXCEPT
2667 char const* Exception::what() const JSONCPP_NOEXCEPT
2669 return msg_.c_str();
2671 RuntimeError::RuntimeError(JSONCPP_STRING const& msg)
2672 : Exception(msg)
2674 LogicError::LogicError(JSONCPP_STRING const& msg)
2675 : Exception(msg)
2677 JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg)
2679 throw RuntimeError(msg);
2681 JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg)
2683 throw LogicError(msg);
2686 // //////////////////////////////////////////////////////////////////
2687 // //////////////////////////////////////////////////////////////////
2688 // //////////////////////////////////////////////////////////////////
2689 // class Value::CommentInfo
2690 // //////////////////////////////////////////////////////////////////
2691 // //////////////////////////////////////////////////////////////////
2692 // //////////////////////////////////////////////////////////////////
2694 Value::CommentInfo::CommentInfo() : comment_(0)
2697 Value::CommentInfo::~CommentInfo() {
2698 if (comment_)
2699 releaseStringValue(comment_, 0u);
2702 void Value::CommentInfo::setComment(const char* text, size_t len) {
2703 if (comment_) {
2704 releaseStringValue(comment_, 0u);
2705 comment_ = 0;
2707 JSON_ASSERT(text != 0);
2708 JSON_ASSERT_MESSAGE(
2709 text[0] == '\0' || text[0] == '/',
2710 "in Json::Value::setComment(): Comments must start with /");
2711 // It seems that /**/ style comments are acceptable as well.
2712 comment_ = duplicateStringValue(text, len);
2715 // //////////////////////////////////////////////////////////////////
2716 // //////////////////////////////////////////////////////////////////
2717 // //////////////////////////////////////////////////////////////////
2718 // class Value::CZString
2719 // //////////////////////////////////////////////////////////////////
2720 // //////////////////////////////////////////////////////////////////
2721 // //////////////////////////////////////////////////////////////////
2723 // Notes: policy_ indicates if the string was allocated when
2724 // a string is stored.
2726 Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {}
2728 Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate)
2729 : cstr_(str) {
2730 // allocate != duplicate
2731 storage_.policy_ = allocate & 0x3;
2732 storage_.length_ = ulength & 0x3FFFFFFF;
2735 Value::CZString::CZString(const CZString& other) {
2736 cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0
2737 ? duplicateStringValue(other.cstr_, other.storage_.length_)
2738 : other.cstr_);
2739 storage_.policy_ = static_cast<unsigned>(other.cstr_
2740 ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication
2741 ? noDuplication : duplicate)
2742 : static_cast<DuplicationPolicy>(other.storage_.policy_)) & 3U;
2743 storage_.length_ = other.storage_.length_;
2746 #if JSON_HAS_RVALUE_REFERENCES
2747 Value::CZString::CZString(CZString&& other)
2748 : cstr_(other.cstr_), index_(other.index_) {
2749 other.cstr_ = nullptr;
2751 #endif
2753 Value::CZString::~CZString() {
2754 if (cstr_ && storage_.policy_ == duplicate) {
2755 releaseStringValue(const_cast<char*>(cstr_), storage_.length_ + 1u); //+1 for null terminating character for sake of completeness but not actually necessary
2759 void Value::CZString::swap(CZString& other) {
2760 std::swap(cstr_, other.cstr_);
2761 std::swap(index_, other.index_);
2764 Value::CZString& Value::CZString::operator=(const CZString& other) {
2765 cstr_ = other.cstr_;
2766 index_ = other.index_;
2767 return *this;
2770 #if JSON_HAS_RVALUE_REFERENCES
2771 Value::CZString& Value::CZString::operator=(CZString&& other) {
2772 cstr_ = other.cstr_;
2773 index_ = other.index_;
2774 other.cstr_ = nullptr;
2775 return *this;
2777 #endif
2779 bool Value::CZString::operator<(const CZString& other) const {
2780 if (!cstr_) return index_ < other.index_;
2781 //return strcmp(cstr_, other.cstr_) < 0;
2782 // Assume both are strings.
2783 unsigned this_len = this->storage_.length_;
2784 unsigned other_len = other.storage_.length_;
2785 unsigned min_len = std::min<unsigned>(this_len, other_len);
2786 JSON_ASSERT(this->cstr_ && other.cstr_);
2787 int comp = memcmp(this->cstr_, other.cstr_, min_len);
2788 if (comp < 0) return true;
2789 if (comp > 0) return false;
2790 return (this_len < other_len);
2793 bool Value::CZString::operator==(const CZString& other) const {
2794 if (!cstr_) return index_ == other.index_;
2795 //return strcmp(cstr_, other.cstr_) == 0;
2796 // Assume both are strings.
2797 unsigned this_len = this->storage_.length_;
2798 unsigned other_len = other.storage_.length_;
2799 if (this_len != other_len) return false;
2800 JSON_ASSERT(this->cstr_ && other.cstr_);
2801 int comp = memcmp(this->cstr_, other.cstr_, this_len);
2802 return comp == 0;
2805 ArrayIndex Value::CZString::index() const { return index_; }
2807 //const char* Value::CZString::c_str() const { return cstr_; }
2808 const char* Value::CZString::data() const { return cstr_; }
2809 unsigned Value::CZString::length() const { return storage_.length_; }
2810 bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; }
2812 // //////////////////////////////////////////////////////////////////
2813 // //////////////////////////////////////////////////////////////////
2814 // //////////////////////////////////////////////////////////////////
2815 // class Value::Value
2816 // //////////////////////////////////////////////////////////////////
2817 // //////////////////////////////////////////////////////////////////
2818 // //////////////////////////////////////////////////////////////////
2820 /*! \internal Default constructor initialization must be equivalent to:
2821 * memset( this, 0, sizeof(Value) )
2822 * This optimization is used in ValueInternalMap fast allocator.
2824 Value::Value(ValueType vtype) {
2825 static char const emptyString[] = "";
2826 initBasic(vtype);
2827 switch (vtype) {
2828 case nullValue:
2829 break;
2830 case intValue:
2831 case uintValue:
2832 value_.int_ = 0;
2833 break;
2834 case realValue:
2835 value_.real_ = 0.0;
2836 break;
2837 case stringValue:
2838 // allocated_ == false, so this is safe.
2839 value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));
2840 break;
2841 case arrayValue:
2842 case objectValue:
2843 value_.map_ = new ObjectValues();
2844 break;
2845 case booleanValue:
2846 value_.bool_ = false;
2847 break;
2848 default:
2849 JSON_ASSERT_UNREACHABLE;
2853 Value::Value(Int value) {
2854 initBasic(intValue);
2855 value_.int_ = value;
2858 Value::Value(UInt value) {
2859 initBasic(uintValue);
2860 value_.uint_ = value;
2862 #if defined(JSON_HAS_INT64)
2863 Value::Value(Int64 value) {
2864 initBasic(intValue);
2865 value_.int_ = value;
2867 Value::Value(UInt64 value) {
2868 initBasic(uintValue);
2869 value_.uint_ = value;
2871 #endif // defined(JSON_HAS_INT64)
2873 Value::Value(double value) {
2874 initBasic(realValue);
2875 value_.real_ = value;
2878 Value::Value(const char* value) {
2879 initBasic(stringValue, true);
2880 JSON_ASSERT_MESSAGE(value != NULL, "Null Value Passed to Value Constructor");
2881 value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value)));
2884 Value::Value(const char* beginValue, const char* endValue) {
2885 initBasic(stringValue, true);
2886 value_.string_ =
2887 duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue));
2890 Value::Value(const JSONCPP_STRING& value) {
2891 initBasic(stringValue, true);
2892 value_.string_ =
2893 duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length()));
2896 Value::Value(const StaticString& value) {
2897 initBasic(stringValue);
2898 value_.string_ = const_cast<char*>(value.c_str());
2901 #ifdef JSON_USE_CPPTL
2902 Value::Value(const CppTL::ConstString& value) {
2903 initBasic(stringValue, true);
2904 value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length()));
2906 #endif
2908 Value::Value(bool value) {
2909 initBasic(booleanValue);
2910 value_.bool_ = value;
2913 Value::Value(Value const& other)
2914 : type_(other.type_), allocated_(false)
2916 comments_(0), start_(other.start_), limit_(other.limit_)
2918 switch (type_) {
2919 case nullValue:
2920 case intValue:
2921 case uintValue:
2922 case realValue:
2923 case booleanValue:
2924 value_ = other.value_;
2925 break;
2926 case stringValue:
2927 if (other.value_.string_ && other.allocated_) {
2928 unsigned len;
2929 char const* str;
2930 decodePrefixedString(other.allocated_, other.value_.string_,
2931 &len, &str);
2932 value_.string_ = duplicateAndPrefixStringValue(str, len);
2933 allocated_ = true;
2934 } else {
2935 value_.string_ = other.value_.string_;
2936 allocated_ = false;
2938 break;
2939 case arrayValue:
2940 case objectValue:
2941 value_.map_ = new ObjectValues(*other.value_.map_);
2942 break;
2943 default:
2944 JSON_ASSERT_UNREACHABLE;
2946 if (other.comments_) {
2947 comments_ = new CommentInfo[numberOfCommentPlacement];
2948 for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
2949 const CommentInfo& otherComment = other.comments_[comment];
2950 if (otherComment.comment_)
2951 comments_[comment].setComment(
2952 otherComment.comment_, strlen(otherComment.comment_));
2957 #if JSON_HAS_RVALUE_REFERENCES
2958 // Move constructor
2959 Value::Value(Value&& other) {
2960 initBasic(nullValue);
2961 swap(other);
2963 #endif
2965 Value::~Value() {
2966 switch (type_) {
2967 case nullValue:
2968 case intValue:
2969 case uintValue:
2970 case realValue:
2971 case booleanValue:
2972 break;
2973 case stringValue:
2974 if (allocated_)
2975 releasePrefixedStringValue(value_.string_);
2976 break;
2977 case arrayValue:
2978 case objectValue:
2979 delete value_.map_;
2980 break;
2981 default:
2982 JSON_ASSERT_UNREACHABLE;
2985 delete[] comments_;
2987 value_.uint_ = 0;
2990 Value& Value::operator=(Value other) {
2991 swap(other);
2992 return *this;
2995 void Value::swapPayload(Value& other) {
2996 ValueType temp = type_;
2997 type_ = other.type_;
2998 other.type_ = temp;
2999 std::swap(value_, other.value_);
3000 int temp2 = allocated_;
3001 allocated_ = other.allocated_;
3002 other.allocated_ = temp2 & 0x1;
3005 void Value::copyPayload(const Value& other) {
3006 type_ = other.type_;
3007 value_ = other.value_;
3008 allocated_ = other.allocated_;
3011 void Value::swap(Value& other) {
3012 swapPayload(other);
3013 std::swap(comments_, other.comments_);
3014 std::swap(start_, other.start_);
3015 std::swap(limit_, other.limit_);
3018 void Value::copy(const Value& other) {
3019 copyPayload(other);
3020 comments_ = other.comments_;
3021 start_ = other.start_;
3022 limit_ = other.limit_;
3025 ValueType Value::type() const { return type_; }
3027 int Value::compare(const Value& other) const {
3028 if (*this < other)
3029 return -1;
3030 if (*this > other)
3031 return 1;
3032 return 0;
3035 bool Value::operator<(const Value& other) const {
3036 int typeDelta = type_ - other.type_;
3037 if (typeDelta)
3038 return typeDelta < 0 ? true : false;
3039 switch (type_) {
3040 case nullValue:
3041 return false;
3042 case intValue:
3043 return value_.int_ < other.value_.int_;
3044 case uintValue:
3045 return value_.uint_ < other.value_.uint_;
3046 case realValue:
3047 return value_.real_ < other.value_.real_;
3048 case booleanValue:
3049 return value_.bool_ < other.value_.bool_;
3050 case stringValue:
3052 if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
3053 if (other.value_.string_) return true;
3054 else return false;
3056 unsigned this_len;
3057 unsigned other_len;
3058 char const* this_str;
3059 char const* other_str;
3060 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
3061 decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
3062 unsigned min_len = std::min<unsigned>(this_len, other_len);
3063 JSON_ASSERT(this_str && other_str);
3064 int comp = memcmp(this_str, other_str, min_len);
3065 if (comp < 0) return true;
3066 if (comp > 0) return false;
3067 return (this_len < other_len);
3069 case arrayValue:
3070 case objectValue: {
3071 int delta = int(value_.map_->size() - other.value_.map_->size());
3072 if (delta)
3073 return delta < 0;
3074 return (*value_.map_) < (*other.value_.map_);
3076 default:
3077 JSON_ASSERT_UNREACHABLE;
3079 return false; // unreachable
3082 bool Value::operator<=(const Value& other) const { return !(other < *this); }
3084 bool Value::operator>=(const Value& other) const { return !(*this < other); }
3086 bool Value::operator>(const Value& other) const { return other < *this; }
3088 bool Value::operator==(const Value& other) const {
3089 // if ( type_ != other.type_ )
3090 // GCC 2.95.3 says:
3091 // attempt to take address of bit-field structure member `Json::Value::type_'
3092 // Beats me, but a temp solves the problem.
3093 int temp = other.type_;
3094 if (type_ != temp)
3095 return false;
3096 switch (type_) {
3097 case nullValue:
3098 return true;
3099 case intValue:
3100 return value_.int_ == other.value_.int_;
3101 case uintValue:
3102 return value_.uint_ == other.value_.uint_;
3103 case realValue:
3104 return value_.real_ == other.value_.real_;
3105 case booleanValue:
3106 return value_.bool_ == other.value_.bool_;
3107 case stringValue:
3109 if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
3110 return (value_.string_ == other.value_.string_);
3112 unsigned this_len;
3113 unsigned other_len;
3114 char const* this_str;
3115 char const* other_str;
3116 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
3117 decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
3118 if (this_len != other_len) return false;
3119 JSON_ASSERT(this_str && other_str);
3120 int comp = memcmp(this_str, other_str, this_len);
3121 return comp == 0;
3123 case arrayValue:
3124 case objectValue:
3125 return value_.map_->size() == other.value_.map_->size() &&
3126 (*value_.map_) == (*other.value_.map_);
3127 default:
3128 JSON_ASSERT_UNREACHABLE;
3130 return false; // unreachable
3133 bool Value::operator!=(const Value& other) const { return !(*this == other); }
3135 const char* Value::asCString() const {
3136 JSON_ASSERT_MESSAGE(type_ == stringValue,
3137 "in Json::Value::asCString(): requires stringValue");
3138 if (value_.string_ == 0) return 0;
3139 unsigned this_len;
3140 char const* this_str;
3141 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
3142 return this_str;
3145 #if JSONCPP_USING_SECURE_MEMORY
3146 unsigned Value::getCStringLength() const {
3147 JSON_ASSERT_MESSAGE(type_ == stringValue,
3148 "in Json::Value::asCString(): requires stringValue");
3149 if (value_.string_ == 0) return 0;
3150 unsigned this_len;
3151 char const* this_str;
3152 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
3153 return this_len;
3155 #endif
3157 bool Value::getString(char const** str, char const** cend) const {
3158 if (type_ != stringValue) return false;
3159 if (value_.string_ == 0) return false;
3160 unsigned length;
3161 decodePrefixedString(this->allocated_, this->value_.string_, &length, str);
3162 *cend = *str + length;
3163 return true;
3166 JSONCPP_STRING Value::asString() const {
3167 switch (type_) {
3168 case nullValue:
3169 return "";
3170 case stringValue:
3172 if (value_.string_ == 0) return "";
3173 unsigned this_len;
3174 char const* this_str;
3175 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
3176 return JSONCPP_STRING(this_str, this_len);
3178 case booleanValue:
3179 return value_.bool_ ? "true" : "false";
3180 case intValue:
3181 return valueToString(value_.int_);
3182 case uintValue:
3183 return valueToString(value_.uint_);
3184 case realValue:
3185 return valueToString(value_.real_);
3186 default:
3187 JSON_FAIL_MESSAGE("Type is not convertible to string");
3191 #ifdef JSON_USE_CPPTL
3192 CppTL::ConstString Value::asConstString() const {
3193 unsigned len;
3194 char const* str;
3195 decodePrefixedString(allocated_, value_.string_,
3196 &len, &str);
3197 return CppTL::ConstString(str, len);
3199 #endif
3201 Value::Int Value::asInt() const {
3202 switch (type_) {
3203 case intValue:
3204 JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
3205 return Int(value_.int_);
3206 case uintValue:
3207 JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
3208 return Int(value_.uint_);
3209 case realValue:
3210 JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
3211 "double out of Int range");
3212 return Int(value_.real_);
3213 case nullValue:
3214 return 0;
3215 case booleanValue:
3216 return value_.bool_ ? 1 : 0;
3217 default:
3218 break;
3220 JSON_FAIL_MESSAGE("Value is not convertible to Int.");
3223 Value::UInt Value::asUInt() const {
3224 switch (type_) {
3225 case intValue:
3226 JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
3227 return UInt(value_.int_);
3228 case uintValue:
3229 JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
3230 return UInt(value_.uint_);
3231 case realValue:
3232 JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
3233 "double out of UInt range");
3234 return UInt(value_.real_);
3235 case nullValue:
3236 return 0;
3237 case booleanValue:
3238 return value_.bool_ ? 1 : 0;
3239 default:
3240 break;
3242 JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
3245 #if defined(JSON_HAS_INT64)
3247 Value::Int64 Value::asInt64() const {
3248 switch (type_) {
3249 case intValue:
3250 return Int64(value_.int_);
3251 case uintValue:
3252 JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
3253 return Int64(value_.uint_);
3254 case realValue:
3255 JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
3256 "double out of Int64 range");
3257 return Int64(value_.real_);
3258 case nullValue:
3259 return 0;
3260 case booleanValue:
3261 return value_.bool_ ? 1 : 0;
3262 default:
3263 break;
3265 JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
3268 Value::UInt64 Value::asUInt64() const {
3269 switch (type_) {
3270 case intValue:
3271 JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
3272 return UInt64(value_.int_);
3273 case uintValue:
3274 return UInt64(value_.uint_);
3275 case realValue:
3276 JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
3277 "double out of UInt64 range");
3278 return UInt64(value_.real_);
3279 case nullValue:
3280 return 0;
3281 case booleanValue:
3282 return value_.bool_ ? 1 : 0;
3283 default:
3284 break;
3286 JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
3288 #endif // if defined(JSON_HAS_INT64)
3290 LargestInt Value::asLargestInt() const {
3291 #if defined(JSON_NO_INT64)
3292 return asInt();
3293 #else
3294 return asInt64();
3295 #endif
3298 LargestUInt Value::asLargestUInt() const {
3299 #if defined(JSON_NO_INT64)
3300 return asUInt();
3301 #else
3302 return asUInt64();
3303 #endif
3306 double Value::asDouble() const {
3307 switch (type_) {
3308 case intValue:
3309 return static_cast<double>(value_.int_);
3310 case uintValue:
3311 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3312 return static_cast<double>(value_.uint_);
3313 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3314 return integerToDouble(value_.uint_);
3315 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3316 case realValue:
3317 return value_.real_;
3318 case nullValue:
3319 return 0.0;
3320 case booleanValue:
3321 return value_.bool_ ? 1.0 : 0.0;
3322 default:
3323 break;
3325 JSON_FAIL_MESSAGE("Value is not convertible to double.");
3328 float Value::asFloat() const {
3329 switch (type_) {
3330 case intValue:
3331 return static_cast<float>(value_.int_);
3332 case uintValue:
3333 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3334 return static_cast<float>(value_.uint_);
3335 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3336 // This can fail (silently?) if the value is bigger than MAX_FLOAT.
3337 return static_cast<float>(integerToDouble(value_.uint_));
3338 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3339 case realValue:
3340 return static_cast<float>(value_.real_);
3341 case nullValue:
3342 return 0.0;
3343 case booleanValue:
3344 return value_.bool_ ? 1.0f : 0.0f;
3345 default:
3346 break;
3348 JSON_FAIL_MESSAGE("Value is not convertible to float.");
3351 bool Value::asBool() const {
3352 switch (type_) {
3353 case booleanValue:
3354 return value_.bool_;
3355 case nullValue:
3356 return false;
3357 case intValue:
3358 return value_.int_ ? true : false;
3359 case uintValue:
3360 return value_.uint_ ? true : false;
3361 case realValue:
3362 // This is kind of strange. Not recommended.
3363 return (value_.real_ != 0.0) ? true : false;
3364 default:
3365 break;
3367 JSON_FAIL_MESSAGE("Value is not convertible to bool.");
3370 bool Value::isConvertibleTo(ValueType other) const {
3371 switch (other) {
3372 case nullValue:
3373 return (isNumeric() && asDouble() == 0.0) ||
3374 (type_ == booleanValue && value_.bool_ == false) ||
3375 (type_ == stringValue && asString().empty()) ||
3376 (type_ == arrayValue && value_.map_->size() == 0) ||
3377 (type_ == objectValue && value_.map_->size() == 0) ||
3378 type_ == nullValue;
3379 case intValue:
3380 return isInt() ||
3381 (type_ == realValue && InRange(value_.real_, minInt, maxInt)) ||
3382 type_ == booleanValue || type_ == nullValue;
3383 case uintValue:
3384 return isUInt() ||
3385 (type_ == realValue && InRange(value_.real_, 0, maxUInt)) ||
3386 type_ == booleanValue || type_ == nullValue;
3387 case realValue:
3388 return isNumeric() || type_ == booleanValue || type_ == nullValue;
3389 case booleanValue:
3390 return isNumeric() || type_ == booleanValue || type_ == nullValue;
3391 case stringValue:
3392 return isNumeric() || type_ == booleanValue || type_ == stringValue ||
3393 type_ == nullValue;
3394 case arrayValue:
3395 return type_ == arrayValue || type_ == nullValue;
3396 case objectValue:
3397 return type_ == objectValue || type_ == nullValue;
3399 JSON_ASSERT_UNREACHABLE;
3400 return false;
3403 /// Number of values in array or object
3404 ArrayIndex Value::size() const {
3405 switch (type_) {
3406 case nullValue:
3407 case intValue:
3408 case uintValue:
3409 case realValue:
3410 case booleanValue:
3411 case stringValue:
3412 return 0;
3413 case arrayValue: // size of the array is highest index + 1
3414 if (!value_.map_->empty()) {
3415 ObjectValues::const_iterator itLast = value_.map_->end();
3416 --itLast;
3417 return (*itLast).first.index() + 1;
3419 return 0;
3420 case objectValue:
3421 return ArrayIndex(value_.map_->size());
3423 JSON_ASSERT_UNREACHABLE;
3424 return 0; // unreachable;
3427 bool Value::empty() const {
3428 if (isNull() || isArray() || isObject())
3429 return size() == 0u;
3430 else
3431 return false;
3434 Value::operator bool() const { return ! isNull(); }
3436 void Value::clear() {
3437 JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
3438 type_ == objectValue,
3439 "in Json::Value::clear(): requires complex value");
3440 start_ = 0;
3441 limit_ = 0;
3442 switch (type_) {
3443 case arrayValue:
3444 case objectValue:
3445 value_.map_->clear();
3446 break;
3447 default:
3448 break;
3452 void Value::resize(ArrayIndex newSize) {
3453 JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
3454 "in Json::Value::resize(): requires arrayValue");
3455 if (type_ == nullValue)
3456 *this = Value(arrayValue);
3457 ArrayIndex oldSize = size();
3458 if (newSize == 0)
3459 clear();
3460 else if (newSize > oldSize)
3461 (*this)[newSize - 1];
3462 else {
3463 for (ArrayIndex index = newSize; index < oldSize; ++index) {
3464 value_.map_->erase(index);
3466 JSON_ASSERT(size() == newSize);
3470 Value& Value::operator[](ArrayIndex index) {
3471 JSON_ASSERT_MESSAGE(
3472 type_ == nullValue || type_ == arrayValue,
3473 "in Json::Value::operator[](ArrayIndex): requires arrayValue");
3474 if (type_ == nullValue)
3475 *this = Value(arrayValue);
3476 CZString key(index);
3477 ObjectValues::iterator it = value_.map_->lower_bound(key);
3478 if (it != value_.map_->end() && (*it).first == key)
3479 return (*it).second;
3481 ObjectValues::value_type defaultValue(key, nullSingleton());
3482 it = value_.map_->insert(it, defaultValue);
3483 return (*it).second;
3486 Value& Value::operator[](int index) {
3487 JSON_ASSERT_MESSAGE(
3488 index >= 0,
3489 "in Json::Value::operator[](int index): index cannot be negative");
3490 return (*this)[ArrayIndex(index)];
3493 const Value& Value::operator[](ArrayIndex index) const {
3494 JSON_ASSERT_MESSAGE(
3495 type_ == nullValue || type_ == arrayValue,
3496 "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
3497 if (type_ == nullValue)
3498 return nullSingleton();
3499 CZString key(index);
3500 ObjectValues::const_iterator it = value_.map_->find(key);
3501 if (it == value_.map_->end())
3502 return nullSingleton();
3503 return (*it).second;
3506 const Value& Value::operator[](int index) const {
3507 JSON_ASSERT_MESSAGE(
3508 index >= 0,
3509 "in Json::Value::operator[](int index) const: index cannot be negative");
3510 return (*this)[ArrayIndex(index)];
3513 void Value::initBasic(ValueType vtype, bool allocated) {
3514 type_ = vtype;
3515 allocated_ = allocated;
3516 comments_ = 0;
3517 start_ = 0;
3518 limit_ = 0;
3521 // Access an object value by name, create a null member if it does not exist.
3522 // @pre Type of '*this' is object or null.
3523 // @param key is null-terminated.
3524 Value& Value::resolveReference(const char* key) {
3525 JSON_ASSERT_MESSAGE(
3526 type_ == nullValue || type_ == objectValue,
3527 "in Json::Value::resolveReference(): requires objectValue");
3528 if (type_ == nullValue)
3529 *this = Value(objectValue);
3530 CZString actualKey(
3531 key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE!
3532 ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
3533 if (it != value_.map_->end() && (*it).first == actualKey)
3534 return (*it).second;
3536 ObjectValues::value_type defaultValue(actualKey, nullSingleton());
3537 it = value_.map_->insert(it, defaultValue);
3538 Value& value = (*it).second;
3539 return value;
3542 // @param key is not null-terminated.
3543 Value& Value::resolveReference(char const* key, char const* cend)
3545 JSON_ASSERT_MESSAGE(
3546 type_ == nullValue || type_ == objectValue,
3547 "in Json::Value::resolveReference(key, end): requires objectValue");
3548 if (type_ == nullValue)
3549 *this = Value(objectValue);
3550 CZString actualKey(
3551 key, static_cast<unsigned>(cend-key), CZString::duplicateOnCopy);
3552 ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
3553 if (it != value_.map_->end() && (*it).first == actualKey)
3554 return (*it).second;
3556 ObjectValues::value_type defaultValue(actualKey, nullSingleton());
3557 it = value_.map_->insert(it, defaultValue);
3558 Value& value = (*it).second;
3559 return value;
3562 Value Value::get(ArrayIndex index, const Value& defaultValue) const {
3563 const Value* value = &((*this)[index]);
3564 return value == &nullSingleton() ? defaultValue : *value;
3567 bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
3569 Value const* Value::find(char const* key, char const* cend) const
3571 JSON_ASSERT_MESSAGE(
3572 type_ == nullValue || type_ == objectValue,
3573 "in Json::Value::find(key, end, found): requires objectValue or nullValue");
3574 if (type_ == nullValue) return NULL;
3575 CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
3576 ObjectValues::const_iterator it = value_.map_->find(actualKey);
3577 if (it == value_.map_->end()) return NULL;
3578 return &(*it).second;
3580 const Value& Value::operator[](const char* key) const
3582 Value const* found = find(key, key + strlen(key));
3583 if (!found) return nullSingleton();
3584 return *found;
3586 Value const& Value::operator[](JSONCPP_STRING const& key) const
3588 Value const* found = find(key.data(), key.data() + key.length());
3589 if (!found) return nullSingleton();
3590 return *found;
3593 Value& Value::operator[](const char* key) {
3594 return resolveReference(key, key + strlen(key));
3597 Value& Value::operator[](const JSONCPP_STRING& key) {
3598 return resolveReference(key.data(), key.data() + key.length());
3601 Value& Value::operator[](const StaticString& key) {
3602 return resolveReference(key.c_str());
3605 #ifdef JSON_USE_CPPTL
3606 Value& Value::operator[](const CppTL::ConstString& key) {
3607 return resolveReference(key.c_str(), key.end_c_str());
3609 Value const& Value::operator[](CppTL::ConstString const& key) const
3611 Value const* found = find(key.c_str(), key.end_c_str());
3612 if (!found) return nullSingleton();
3613 return *found;
3615 #endif
3617 Value& Value::append(const Value& value) { return (*this)[size()] = value; }
3619 #if JSON_HAS_RVALUE_REFERENCES
3620 Value& Value::append(Value&& value) { return (*this)[size()] = std::move(value); }
3621 #endif
3623 Value Value::get(char const* key, char const* cend, Value const& defaultValue) const
3625 Value const* found = find(key, cend);
3626 return !found ? defaultValue : *found;
3628 Value Value::get(char const* key, Value const& defaultValue) const
3630 return get(key, key + strlen(key), defaultValue);
3632 Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const
3634 return get(key.data(), key.data() + key.length(), defaultValue);
3638 bool Value::removeMember(const char* key, const char* cend, Value* removed)
3640 if (type_ != objectValue) {
3641 return false;
3643 CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
3644 ObjectValues::iterator it = value_.map_->find(actualKey);
3645 if (it == value_.map_->end())
3646 return false;
3647 *removed = it->second;
3648 value_.map_->erase(it);
3649 return true;
3651 bool Value::removeMember(const char* key, Value* removed)
3653 return removeMember(key, key + strlen(key), removed);
3655 bool Value::removeMember(JSONCPP_STRING const& key, Value* removed)
3657 return removeMember(key.data(), key.data() + key.length(), removed);
3659 void Value::removeMember(const char* key)
3661 JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
3662 "in Json::Value::removeMember(): requires objectValue");
3663 if (type_ == nullValue)
3664 return;
3666 CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication);
3667 value_.map_->erase(actualKey);
3669 void Value::removeMember(const JSONCPP_STRING& key)
3671 removeMember(key.c_str());
3674 bool Value::removeIndex(ArrayIndex index, Value* removed) {
3675 if (type_ != arrayValue) {
3676 return false;
3678 CZString key(index);
3679 ObjectValues::iterator it = value_.map_->find(key);
3680 if (it == value_.map_->end()) {
3681 return false;
3683 *removed = it->second;
3684 ArrayIndex oldSize = size();
3685 // shift left all items left, into the place of the "removed"
3686 for (ArrayIndex i = index; i < (oldSize - 1); ++i){
3687 CZString keey(i);
3688 (*value_.map_)[keey] = (*this)[i + 1];
3690 // erase the last one ("leftover")
3691 CZString keyLast(oldSize - 1);
3692 ObjectValues::iterator itLast = value_.map_->find(keyLast);
3693 value_.map_->erase(itLast);
3694 return true;
3697 #ifdef JSON_USE_CPPTL
3698 Value Value::get(const CppTL::ConstString& key,
3699 const Value& defaultValue) const {
3700 return get(key.c_str(), key.end_c_str(), defaultValue);
3702 #endif
3704 bool Value::isMember(char const* key, char const* cend) const
3706 Value const* value = find(key, cend);
3707 return NULL != value;
3709 bool Value::isMember(char const* key) const
3711 return isMember(key, key + strlen(key));
3713 bool Value::isMember(JSONCPP_STRING const& key) const
3715 return isMember(key.data(), key.data() + key.length());
3718 #ifdef JSON_USE_CPPTL
3719 bool Value::isMember(const CppTL::ConstString& key) const {
3720 return isMember(key.c_str(), key.end_c_str());
3722 #endif
3724 Value::Members Value::getMemberNames() const {
3725 JSON_ASSERT_MESSAGE(
3726 type_ == nullValue || type_ == objectValue,
3727 "in Json::Value::getMemberNames(), value must be objectValue");
3728 if (type_ == nullValue)
3729 return Value::Members();
3730 Members members;
3731 members.reserve(value_.map_->size());
3732 ObjectValues::const_iterator it = value_.map_->begin();
3733 ObjectValues::const_iterator itEnd = value_.map_->end();
3734 for (; it != itEnd; ++it) {
3735 members.push_back(JSONCPP_STRING((*it).first.data(),
3736 (*it).first.length()));
3738 return members;
3741 //# ifdef JSON_USE_CPPTL
3742 // EnumMemberNames
3743 // Value::enumMemberNames() const
3745 // if ( type_ == objectValue )
3746 // {
3747 // return CppTL::Enum::any( CppTL::Enum::transform(
3748 // CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
3749 // MemberNamesTransform() ) );
3750 // }
3751 // return EnumMemberNames();
3755 // EnumValues
3756 // Value::enumValues() const
3758 // if ( type_ == objectValue || type_ == arrayValue )
3759 // return CppTL::Enum::anyValues( *(value_.map_),
3760 // CppTL::Type<const Value &>() );
3761 // return EnumValues();
3764 //# endif
3766 static bool IsIntegral(double d) {
3767 double integral_part;
3768 return modf(d, &integral_part) == 0.0;
3771 bool Value::isNull() const { return type_ == nullValue; }
3773 bool Value::isBool() const { return type_ == booleanValue; }
3775 bool Value::isInt() const {
3776 switch (type_) {
3777 case intValue:
3778 #if defined(JSON_HAS_INT64)
3779 return value_.int_ >= minInt && value_.int_ <= maxInt;
3780 #else
3781 return true;
3782 #endif
3783 case uintValue:
3784 return value_.uint_ <= UInt(maxInt);
3785 case realValue:
3786 return value_.real_ >= minInt && value_.real_ <= maxInt &&
3787 IsIntegral(value_.real_);
3788 default:
3789 break;
3791 return false;
3794 bool Value::isUInt() const {
3795 switch (type_) {
3796 case intValue:
3797 #if defined(JSON_HAS_INT64)
3798 return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
3799 #else
3800 return value_.int_ >= 0;
3801 #endif
3802 case uintValue:
3803 #if defined(JSON_HAS_INT64)
3804 return value_.uint_ <= maxUInt;
3805 #else
3806 return true;
3807 #endif
3808 case realValue:
3809 return value_.real_ >= 0 && value_.real_ <= maxUInt &&
3810 IsIntegral(value_.real_);
3811 default:
3812 break;
3814 return false;
3817 bool Value::isInt64() const {
3818 #if defined(JSON_HAS_INT64)
3819 switch (type_) {
3820 case intValue:
3821 return true;
3822 case uintValue:
3823 return value_.uint_ <= UInt64(maxInt64);
3824 case realValue:
3825 // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
3826 // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
3827 // require the value to be strictly less than the limit.
3828 return value_.real_ >= double(minInt64) &&
3829 value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
3830 default:
3831 break;
3833 #endif // JSON_HAS_INT64
3834 return false;
3837 bool Value::isUInt64() const {
3838 #if defined(JSON_HAS_INT64)
3839 switch (type_) {
3840 case intValue:
3841 return value_.int_ >= 0;
3842 case uintValue:
3843 return true;
3844 case realValue:
3845 // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
3846 // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
3847 // require the value to be strictly less than the limit.
3848 return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
3849 IsIntegral(value_.real_);
3850 default:
3851 break;
3853 #endif // JSON_HAS_INT64
3854 return false;
3857 bool Value::isIntegral() const {
3858 switch (type_) {
3859 case intValue:
3860 case uintValue:
3861 return true;
3862 case realValue:
3863 #if defined(JSON_HAS_INT64)
3864 // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
3865 // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
3866 // require the value to be strictly less than the limit.
3867 return value_.real_ >= double(minInt64) && value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
3868 #else
3869 return value_.real_ >= minInt && value_.real_ <= maxUInt && IsIntegral(value_.real_);
3870 #endif // JSON_HAS_INT64
3871 default:
3872 break;
3874 return false;
3877 bool Value::isDouble() const { return type_ == intValue || type_ == uintValue || type_ == realValue; }
3879 bool Value::isNumeric() const { return isDouble(); }
3881 bool Value::isString() const { return type_ == stringValue; }
3883 bool Value::isArray() const { return type_ == arrayValue; }
3885 bool Value::isObject() const { return type_ == objectValue; }
3887 void Value::setComment(const char* comment, size_t len, CommentPlacement placement) {
3888 if (!comments_)
3889 comments_ = new CommentInfo[numberOfCommentPlacement];
3890 if ((len > 0) && (comment[len-1] == '\n')) {
3891 // Always discard trailing newline, to aid indentation.
3892 len -= 1;
3894 comments_[placement].setComment(comment, len);
3897 void Value::setComment(const char* comment, CommentPlacement placement) {
3898 setComment(comment, strlen(comment), placement);
3901 void Value::setComment(const JSONCPP_STRING& comment, CommentPlacement placement) {
3902 setComment(comment.c_str(), comment.length(), placement);
3905 bool Value::hasComment(CommentPlacement placement) const {
3906 return comments_ != 0 && comments_[placement].comment_ != 0;
3909 JSONCPP_STRING Value::getComment(CommentPlacement placement) const {
3910 if (hasComment(placement))
3911 return comments_[placement].comment_;
3912 return "";
3915 void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }
3917 void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; }
3919 ptrdiff_t Value::getOffsetStart() const { return start_; }
3921 ptrdiff_t Value::getOffsetLimit() const { return limit_; }
3923 JSONCPP_STRING Value::toStyledString() const {
3924 StreamWriterBuilder builder;
3926 JSONCPP_STRING out = this->hasComment(commentBefore) ? "\n" : "";
3927 out += Json::writeString(builder, *this);
3928 out += "\n";
3930 return out;
3933 Value::const_iterator Value::begin() const {
3934 switch (type_) {
3935 case arrayValue:
3936 case objectValue:
3937 if (value_.map_)
3938 return const_iterator(value_.map_->begin());
3939 break;
3940 default:
3941 break;
3943 return const_iterator();
3946 Value::const_iterator Value::end() const {
3947 switch (type_) {
3948 case arrayValue:
3949 case objectValue:
3950 if (value_.map_)
3951 return const_iterator(value_.map_->end());
3952 break;
3953 default:
3954 break;
3956 return const_iterator();
3959 Value::iterator Value::begin() {
3960 switch (type_) {
3961 case arrayValue:
3962 case objectValue:
3963 if (value_.map_)
3964 return iterator(value_.map_->begin());
3965 break;
3966 default:
3967 break;
3969 return iterator();
3972 Value::iterator Value::end() {
3973 switch (type_) {
3974 case arrayValue:
3975 case objectValue:
3976 if (value_.map_)
3977 return iterator(value_.map_->end());
3978 break;
3979 default:
3980 break;
3982 return iterator();
3985 // class PathArgument
3986 // //////////////////////////////////////////////////////////////////
3988 PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {}
3990 PathArgument::PathArgument(ArrayIndex index)
3991 : key_(), index_(index), kind_(kindIndex) {}
3993 PathArgument::PathArgument(const char* key)
3994 : key_(key), index_(), kind_(kindKey) {}
3996 PathArgument::PathArgument(const JSONCPP_STRING& key)
3997 : key_(key.c_str()), index_(), kind_(kindKey) {}
3999 // class Path
4000 // //////////////////////////////////////////////////////////////////
4002 Path::Path(const JSONCPP_STRING& path,
4003 const PathArgument& a1,
4004 const PathArgument& a2,
4005 const PathArgument& a3,
4006 const PathArgument& a4,
4007 const PathArgument& a5) {
4008 InArgs in;
4009 in.reserve(5);
4010 in.push_back(&a1);
4011 in.push_back(&a2);
4012 in.push_back(&a3);
4013 in.push_back(&a4);
4014 in.push_back(&a5);
4015 makePath(path, in);
4018 void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) {
4019 const char* current = path.c_str();
4020 const char* end = current + path.length();
4021 InArgs::const_iterator itInArg = in.begin();
4022 while (current != end) {
4023 if (*current == '[') {
4024 ++current;
4025 if (*current == '%')
4026 addPathInArg(path, in, itInArg, PathArgument::kindIndex);
4027 else {
4028 ArrayIndex index = 0;
4029 for (; current != end && *current >= '0' && *current <= '9'; ++current)
4030 index = index * 10 + ArrayIndex(*current - '0');
4031 args_.push_back(index);
4033 if (current == end || *++current != ']')
4034 invalidPath(path, int(current - path.c_str()));
4035 } else if (*current == '%') {
4036 addPathInArg(path, in, itInArg, PathArgument::kindKey);
4037 ++current;
4038 } else if (*current == '.' || *current == ']') {
4039 ++current;
4040 } else {
4041 const char* beginName = current;
4042 while (current != end && !strchr("[.", *current))
4043 ++current;
4044 args_.push_back(JSONCPP_STRING(beginName, current));
4049 void Path::addPathInArg(const JSONCPP_STRING& /*path*/,
4050 const InArgs& in,
4051 InArgs::const_iterator& itInArg,
4052 PathArgument::Kind kind) {
4053 if (itInArg == in.end()) {
4054 // Error: missing argument %d
4055 } else if ((*itInArg)->kind_ != kind) {
4056 // Error: bad argument type
4057 } else {
4058 args_.push_back(**itInArg++);
4062 void Path::invalidPath(const JSONCPP_STRING& /*path*/, int /*location*/) {
4063 // Error: invalid path.
4066 const Value& Path::resolve(const Value& root) const {
4067 const Value* node = &root;
4068 for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
4069 const PathArgument& arg = *it;
4070 if (arg.kind_ == PathArgument::kindIndex) {
4071 if (!node->isArray() || !node->isValidIndex(arg.index_)) {
4072 // Error: unable to resolve path (array value expected at position...
4073 return Value::null;
4075 node = &((*node)[arg.index_]);
4076 } else if (arg.kind_ == PathArgument::kindKey) {
4077 if (!node->isObject()) {
4078 // Error: unable to resolve path (object value expected at position...)
4079 return Value::null;
4081 node = &((*node)[arg.key_]);
4082 if (node == &Value::nullSingleton()) {
4083 // Error: unable to resolve path (object has no member named '' at
4084 // position...)
4085 return Value::null;
4089 return *node;
4092 Value Path::resolve(const Value& root, const Value& defaultValue) const {
4093 const Value* node = &root;
4094 for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
4095 const PathArgument& arg = *it;
4096 if (arg.kind_ == PathArgument::kindIndex) {
4097 if (!node->isArray() || !node->isValidIndex(arg.index_))
4098 return defaultValue;
4099 node = &((*node)[arg.index_]);
4100 } else if (arg.kind_ == PathArgument::kindKey) {
4101 if (!node->isObject())
4102 return defaultValue;
4103 node = &((*node)[arg.key_]);
4104 if (node == &Value::nullSingleton())
4105 return defaultValue;
4108 return *node;
4111 Value& Path::make(Value& root) const {
4112 Value* node = &root;
4113 for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
4114 const PathArgument& arg = *it;
4115 if (arg.kind_ == PathArgument::kindIndex) {
4116 if (!node->isArray()) {
4117 // Error: node is not an array at position ...
4119 node = &((*node)[arg.index_]);
4120 } else if (arg.kind_ == PathArgument::kindKey) {
4121 if (!node->isObject()) {
4122 // Error: node is not an object at position...
4124 node = &((*node)[arg.key_]);
4127 return *node;
4130 } // namespace Json
4132 // //////////////////////////////////////////////////////////////////////
4133 // End of content of file: src/lib_json/json_value.cpp
4134 // //////////////////////////////////////////////////////////////////////
4141 // //////////////////////////////////////////////////////////////////////
4142 // Beginning of content of file: src/lib_json/json_writer.cpp
4143 // //////////////////////////////////////////////////////////////////////
4145 // Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
4146 // Distributed under MIT license, or public domain if desired and
4147 // recognized in your jurisdiction.
4148 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
4150 #if !defined(JSON_IS_AMALGAMATION)
4151 #include <json/writer.h>
4152 #include "json_tool.h"
4153 #endif // if !defined(JSON_IS_AMALGAMATION)
4154 #include <iomanip>
4155 #include <memory>
4156 #include <sstream>
4157 #include <utility>
4158 #include <set>
4159 #include <cassert>
4160 #include <cstring>
4161 #include <cstdio>
4163 #if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0
4164 #include <float.h>
4165 #define isfinite _finite
4166 #elif defined(__sun) && defined(__SVR4) //Solaris
4167 #if !defined(isfinite)
4168 #include <ieeefp.h>
4169 #define isfinite finite
4170 #endif
4171 #elif defined(_AIX)
4172 #if !defined(isfinite)
4173 #include <math.h>
4174 #define isfinite finite
4175 #endif
4176 #elif defined(__hpux)
4177 #if !defined(isfinite)
4178 #if defined(__ia64) && !defined(finite)
4179 #define isfinite(x) ((sizeof(x) == sizeof(float) ? \
4180 _Isfinitef(x) : _IsFinite(x)))
4181 #else
4182 #include <math.h>
4183 #define isfinite finite
4184 #endif
4185 #endif
4186 #else
4187 #include <cmath>
4188 #if !(defined(__QNXNTO__)) // QNX already defines isfinite
4189 #define isfinite std::isfinite
4190 #endif
4191 #endif
4193 #if defined(_MSC_VER)
4194 #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
4195 #define snprintf sprintf_s
4196 #elif _MSC_VER >= 1900 // VC++ 14.0 and above
4197 #define snprintf std::snprintf
4198 #else
4199 #define snprintf _snprintf
4200 #endif
4201 #elif defined(__ANDROID__) || defined(__QNXNTO__)
4202 #define snprintf snprintf
4203 #elif __cplusplus >= 201103L
4204 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
4205 #define snprintf std::snprintf
4206 #endif
4207 #endif
4209 #if defined(__BORLANDC__)
4210 #include <float.h>
4211 #define isfinite _finite
4212 #define snprintf _snprintf
4213 #endif
4215 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
4216 // Disable warning about strdup being deprecated.
4217 #pragma warning(disable : 4996)
4218 #endif
4220 namespace Json {
4222 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
4223 typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
4224 #else
4225 typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
4226 #endif
4228 JSONCPP_STRING valueToString(LargestInt value) {
4229 UIntToStringBuffer buffer;
4230 char* current = buffer + sizeof(buffer);
4231 if (value == Value::minLargestInt) {
4232 uintToString(LargestUInt(Value::maxLargestInt) + 1, current);
4233 *--current = '-';
4234 } else if (value < 0) {
4235 uintToString(LargestUInt(-value), current);
4236 *--current = '-';
4237 } else {
4238 uintToString(LargestUInt(value), current);
4240 assert(current >= buffer);
4241 return current;
4244 JSONCPP_STRING valueToString(LargestUInt value) {
4245 UIntToStringBuffer buffer;
4246 char* current = buffer + sizeof(buffer);
4247 uintToString(value, current);
4248 assert(current >= buffer);
4249 return current;
4252 #if defined(JSON_HAS_INT64)
4254 JSONCPP_STRING valueToString(Int value) {
4255 return valueToString(LargestInt(value));
4258 JSONCPP_STRING valueToString(UInt value) {
4259 return valueToString(LargestUInt(value));
4262 #endif // # if defined(JSON_HAS_INT64)
4264 namespace {
4265 JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) {
4266 // Allocate a buffer that is more than large enough to store the 16 digits of
4267 // precision requested below.
4268 char buffer[36];
4269 int len = -1;
4271 char formatString[15];
4272 snprintf(formatString, sizeof(formatString), "%%.%ug", precision);
4274 // Print into the buffer. We need not request the alternative representation
4275 // that always has a decimal point because JSON doesn't distinguish the
4276 // concepts of reals and integers.
4277 if (isfinite(value)) {
4278 len = snprintf(buffer, sizeof(buffer), formatString, value);
4279 fixNumericLocale(buffer, buffer + len);
4281 // try to ensure we preserve the fact that this was given to us as a double on input
4282 if (!strchr(buffer, '.') && !strchr(buffer, 'e')) {
4283 strcat(buffer, ".0");
4286 } else {
4287 // IEEE standard states that NaN values will not compare to themselves
4288 if (value != value) {
4289 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");
4290 } else if (value < 0) {
4291 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");
4292 } else {
4293 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");
4296 assert(len >= 0);
4297 return buffer;
4301 JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); }
4303 JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; }
4305 static bool isAnyCharRequiredQuoting(char const* s, size_t n) {
4306 assert(s || !n);
4308 char const* const end = s + n;
4309 for (char const* cur = s; cur < end; ++cur) {
4310 if (*cur == '\\' || *cur == '\"' || *cur < ' '
4311 || static_cast<unsigned char>(*cur) < 0x80)
4312 return true;
4314 return false;
4317 static unsigned int utf8ToCodepoint(const char*& s, const char* e) {
4318 const unsigned int REPLACEMENT_CHARACTER = 0xFFFD;
4320 unsigned int firstByte = static_cast<unsigned char>(*s);
4322 if (firstByte < 0x80)
4323 return firstByte;
4325 if (firstByte < 0xE0) {
4326 if (e - s < 2)
4327 return REPLACEMENT_CHARACTER;
4329 unsigned int calculated = ((firstByte & 0x1F) << 6)
4330 | (static_cast<unsigned int>(s[1]) & 0x3F);
4331 s += 1;
4332 // oversized encoded characters are invalid
4333 return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated;
4336 if (firstByte < 0xF0) {
4337 if (e - s < 3)
4338 return REPLACEMENT_CHARACTER;
4340 unsigned int calculated = ((firstByte & 0x0F) << 12)
4341 | ((static_cast<unsigned int>(s[1]) & 0x3F) << 6)
4342 | (static_cast<unsigned int>(s[2]) & 0x3F);
4343 s += 2;
4344 // surrogates aren't valid codepoints itself
4345 // shouldn't be UTF-8 encoded
4346 if (calculated >= 0xD800 && calculated <= 0xDFFF)
4347 return REPLACEMENT_CHARACTER;
4348 // oversized encoded characters are invalid
4349 return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated;
4352 if (firstByte < 0xF8) {
4353 if (e - s < 4)
4354 return REPLACEMENT_CHARACTER;
4356 unsigned int calculated = ((firstByte & 0x07) << 24)
4357 | ((static_cast<unsigned int>(s[1]) & 0x3F) << 12)
4358 | ((static_cast<unsigned int>(s[2]) & 0x3F) << 6)
4359 | (static_cast<unsigned int>(s[3]) & 0x3F);
4360 s += 3;
4361 // oversized encoded characters are invalid
4362 return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated;
4365 return REPLACEMENT_CHARACTER;
4368 static const char hex2[] =
4369 "000102030405060708090a0b0c0d0e0f"
4370 "101112131415161718191a1b1c1d1e1f"
4371 "202122232425262728292a2b2c2d2e2f"
4372 "303132333435363738393a3b3c3d3e3f"
4373 "404142434445464748494a4b4c4d4e4f"
4374 "505152535455565758595a5b5c5d5e5f"
4375 "606162636465666768696a6b6c6d6e6f"
4376 "707172737475767778797a7b7c7d7e7f"
4377 "808182838485868788898a8b8c8d8e8f"
4378 "909192939495969798999a9b9c9d9e9f"
4379 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
4380 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
4381 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
4382 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
4383 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
4384 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
4386 static JSONCPP_STRING toHex16Bit(unsigned int x) {
4387 const unsigned int hi = (x >> 8) & 0xff;
4388 const unsigned int lo = x & 0xff;
4389 JSONCPP_STRING result(4, ' ');
4390 result[0] = hex2[2 * hi];
4391 result[1] = hex2[2 * hi + 1];
4392 result[2] = hex2[2 * lo];
4393 result[3] = hex2[2 * lo + 1];
4394 return result;
4397 static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) {
4398 if (value == NULL)
4399 return "";
4401 if (!isAnyCharRequiredQuoting(value, length))
4402 return JSONCPP_STRING("\"") + value + "\"";
4403 // We have to walk value and escape any special characters.
4404 // Appending to JSONCPP_STRING is not efficient, but this should be rare.
4405 // (Note: forward slashes are *not* rare, but I am not escaping them.)
4406 JSONCPP_STRING::size_type maxsize =
4407 length * 2 + 3; // allescaped+quotes+NULL
4408 JSONCPP_STRING result;
4409 result.reserve(maxsize); // to avoid lots of mallocs
4410 result += "\"";
4411 char const* end = value + length;
4412 for (const char* c = value; c != end; ++c) {
4413 switch (*c) {
4414 case '\"':
4415 result += "\\\"";
4416 break;
4417 case '\\':
4418 result += "\\\\";
4419 break;
4420 case '\b':
4421 result += "\\b";
4422 break;
4423 case '\f':
4424 result += "\\f";
4425 break;
4426 case '\n':
4427 result += "\\n";
4428 break;
4429 case '\r':
4430 result += "\\r";
4431 break;
4432 case '\t':
4433 result += "\\t";
4434 break;
4435 // case '/':
4436 // Even though \/ is considered a legal escape in JSON, a bare
4437 // slash is also legal, so I see no reason to escape it.
4438 // (I hope I am not misunderstanding something.)
4439 // blep notes: actually escaping \/ may be useful in javascript to avoid </
4440 // sequence.
4441 // Should add a flag to allow this compatibility mode and prevent this
4442 // sequence from occurring.
4443 default: {
4444 unsigned int cp = utf8ToCodepoint(c, end);
4445 // don't escape non-control characters
4446 // (short escape sequence are applied above)
4447 if (cp < 0x80 && cp >= 0x20)
4448 result += static_cast<char>(cp);
4449 else if (cp < 0x10000) { // codepoint is in Basic Multilingual Plane
4450 result += "\\u";
4451 result += toHex16Bit(cp);
4453 else { // codepoint is not in Basic Multilingual Plane
4454 // convert to surrogate pair first
4455 cp -= 0x10000;
4456 result += "\\u";
4457 result += toHex16Bit((cp >> 10) + 0xD800);
4458 result += "\\u";
4459 result += toHex16Bit((cp & 0x3FF) + 0xDC00);
4462 break;
4465 result += "\"";
4466 return result;
4469 JSONCPP_STRING valueToQuotedString(const char* value) {
4470 return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));
4473 // Class Writer
4474 // //////////////////////////////////////////////////////////////////
4475 Writer::~Writer() {}
4477 // Class FastWriter
4478 // //////////////////////////////////////////////////////////////////
4480 FastWriter::FastWriter()
4481 : yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false),
4482 omitEndingLineFeed_(false) {}
4484 void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; }
4486 void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
4488 void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
4490 JSONCPP_STRING FastWriter::write(const Value& root) {
4491 document_.clear();
4492 writeValue(root);
4493 if (!omitEndingLineFeed_)
4494 document_ += "\n";
4495 return document_;
4498 void FastWriter::writeValue(const Value& value) {
4499 switch (value.type()) {
4500 case nullValue:
4501 if (!dropNullPlaceholders_)
4502 document_ += "null";
4503 break;
4504 case intValue:
4505 document_ += valueToString(value.asLargestInt());
4506 break;
4507 case uintValue:
4508 document_ += valueToString(value.asLargestUInt());
4509 break;
4510 case realValue:
4511 document_ += valueToString(value.asDouble());
4512 break;
4513 case stringValue:
4515 // Is NULL possible for value.string_? No.
4516 char const* str;
4517 char const* end;
4518 bool ok = value.getString(&str, &end);
4519 if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str));
4520 break;
4522 case booleanValue:
4523 document_ += valueToString(value.asBool());
4524 break;
4525 case arrayValue: {
4526 document_ += '[';
4527 ArrayIndex size = value.size();
4528 for (ArrayIndex index = 0; index < size; ++index) {
4529 if (index > 0)
4530 document_ += ',';
4531 writeValue(value[index]);
4533 document_ += ']';
4534 } break;
4535 case objectValue: {
4536 Value::Members members(value.getMemberNames());
4537 document_ += '{';
4538 for (Value::Members::iterator it = members.begin(); it != members.end();
4539 ++it) {
4540 const JSONCPP_STRING& name = *it;
4541 if (it != members.begin())
4542 document_ += ',';
4543 document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()));
4544 document_ += yamlCompatibilityEnabled_ ? ": " : ":";
4545 writeValue(value[name]);
4547 document_ += '}';
4548 } break;
4552 // Class StyledWriter
4553 // //////////////////////////////////////////////////////////////////
4555 StyledWriter::StyledWriter()
4556 : rightMargin_(74), indentSize_(3), addChildValues_() {}
4558 JSONCPP_STRING StyledWriter::write(const Value& root) {
4559 document_.clear();
4560 addChildValues_ = false;
4561 indentString_.clear();
4562 writeCommentBeforeValue(root);
4563 writeValue(root);
4564 writeCommentAfterValueOnSameLine(root);
4565 document_ += "\n";
4566 return document_;
4569 void StyledWriter::writeValue(const Value& value) {
4570 switch (value.type()) {
4571 case nullValue:
4572 pushValue("null");
4573 break;
4574 case intValue:
4575 pushValue(valueToString(value.asLargestInt()));
4576 break;
4577 case uintValue:
4578 pushValue(valueToString(value.asLargestUInt()));
4579 break;
4580 case realValue:
4581 pushValue(valueToString(value.asDouble()));
4582 break;
4583 case stringValue:
4585 // Is NULL possible for value.string_? No.
4586 char const* str;
4587 char const* end;
4588 bool ok = value.getString(&str, &end);
4589 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
4590 else pushValue("");
4591 break;
4593 case booleanValue:
4594 pushValue(valueToString(value.asBool()));
4595 break;
4596 case arrayValue:
4597 writeArrayValue(value);
4598 break;
4599 case objectValue: {
4600 Value::Members members(value.getMemberNames());
4601 if (members.empty())
4602 pushValue("{}");
4603 else {
4604 writeWithIndent("{");
4605 indent();
4606 Value::Members::iterator it = members.begin();
4607 for (;;) {
4608 const JSONCPP_STRING& name = *it;
4609 const Value& childValue = value[name];
4610 writeCommentBeforeValue(childValue);
4611 writeWithIndent(valueToQuotedString(name.c_str()));
4612 document_ += " : ";
4613 writeValue(childValue);
4614 if (++it == members.end()) {
4615 writeCommentAfterValueOnSameLine(childValue);
4616 break;
4618 document_ += ',';
4619 writeCommentAfterValueOnSameLine(childValue);
4621 unindent();
4622 writeWithIndent("}");
4624 } break;
4628 void StyledWriter::writeArrayValue(const Value& value) {
4629 unsigned size = value.size();
4630 if (size == 0)
4631 pushValue("[]");
4632 else {
4633 bool isArrayMultiLine = isMultilineArray(value);
4634 if (isArrayMultiLine) {
4635 writeWithIndent("[");
4636 indent();
4637 bool hasChildValue = !childValues_.empty();
4638 unsigned index = 0;
4639 for (;;) {
4640 const Value& childValue = value[index];
4641 writeCommentBeforeValue(childValue);
4642 if (hasChildValue)
4643 writeWithIndent(childValues_[index]);
4644 else {
4645 writeIndent();
4646 writeValue(childValue);
4648 if (++index == size) {
4649 writeCommentAfterValueOnSameLine(childValue);
4650 break;
4652 document_ += ',';
4653 writeCommentAfterValueOnSameLine(childValue);
4655 unindent();
4656 writeWithIndent("]");
4657 } else // output on a single line
4659 assert(childValues_.size() == size);
4660 document_ += "[ ";
4661 for (unsigned index = 0; index < size; ++index) {
4662 if (index > 0)
4663 document_ += ", ";
4664 document_ += childValues_[index];
4666 document_ += " ]";
4671 bool StyledWriter::isMultilineArray(const Value& value) {
4672 ArrayIndex const size = value.size();
4673 bool isMultiLine = size * 3 >= rightMargin_;
4674 childValues_.clear();
4675 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
4676 const Value& childValue = value[index];
4677 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
4678 childValue.size() > 0);
4680 if (!isMultiLine) // check if line length > max line length
4682 childValues_.reserve(size);
4683 addChildValues_ = true;
4684 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
4685 for (ArrayIndex index = 0; index < size; ++index) {
4686 if (hasCommentForValue(value[index])) {
4687 isMultiLine = true;
4689 writeValue(value[index]);
4690 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
4692 addChildValues_ = false;
4693 isMultiLine = isMultiLine || lineLength >= rightMargin_;
4695 return isMultiLine;
4698 void StyledWriter::pushValue(const JSONCPP_STRING& value) {
4699 if (addChildValues_)
4700 childValues_.push_back(value);
4701 else
4702 document_ += value;
4705 void StyledWriter::writeIndent() {
4706 if (!document_.empty()) {
4707 char last = document_[document_.length() - 1];
4708 if (last == ' ') // already indented
4709 return;
4710 if (last != '\n') // Comments may add new-line
4711 document_ += '\n';
4713 document_ += indentString_;
4716 void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) {
4717 writeIndent();
4718 document_ += value;
4721 void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); }
4723 void StyledWriter::unindent() {
4724 assert(indentString_.size() >= indentSize_);
4725 indentString_.resize(indentString_.size() - indentSize_);
4728 void StyledWriter::writeCommentBeforeValue(const Value& root) {
4729 if (!root.hasComment(commentBefore))
4730 return;
4732 document_ += "\n";
4733 writeIndent();
4734 const JSONCPP_STRING& comment = root.getComment(commentBefore);
4735 JSONCPP_STRING::const_iterator iter = comment.begin();
4736 while (iter != comment.end()) {
4737 document_ += *iter;
4738 if (*iter == '\n' &&
4739 ((iter+1) != comment.end() && *(iter + 1) == '/'))
4740 writeIndent();
4741 ++iter;
4744 // Comments are stripped of trailing newlines, so add one here
4745 document_ += "\n";
4748 void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
4749 if (root.hasComment(commentAfterOnSameLine))
4750 document_ += " " + root.getComment(commentAfterOnSameLine);
4752 if (root.hasComment(commentAfter)) {
4753 document_ += "\n";
4754 document_ += root.getComment(commentAfter);
4755 document_ += "\n";
4759 bool StyledWriter::hasCommentForValue(const Value& value) {
4760 return value.hasComment(commentBefore) ||
4761 value.hasComment(commentAfterOnSameLine) ||
4762 value.hasComment(commentAfter);
4765 // Class StyledStreamWriter
4766 // //////////////////////////////////////////////////////////////////
4768 StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation)
4769 : document_(NULL), rightMargin_(74), indentation_(indentation),
4770 addChildValues_() {}
4772 void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) {
4773 document_ = &out;
4774 addChildValues_ = false;
4775 indentString_.clear();
4776 indented_ = true;
4777 writeCommentBeforeValue(root);
4778 if (!indented_) writeIndent();
4779 indented_ = true;
4780 writeValue(root);
4781 writeCommentAfterValueOnSameLine(root);
4782 *document_ << "\n";
4783 document_ = NULL; // Forget the stream, for safety.
4786 void StyledStreamWriter::writeValue(const Value& value) {
4787 switch (value.type()) {
4788 case nullValue:
4789 pushValue("null");
4790 break;
4791 case intValue:
4792 pushValue(valueToString(value.asLargestInt()));
4793 break;
4794 case uintValue:
4795 pushValue(valueToString(value.asLargestUInt()));
4796 break;
4797 case realValue:
4798 pushValue(valueToString(value.asDouble()));
4799 break;
4800 case stringValue:
4802 // Is NULL possible for value.string_? No.
4803 char const* str;
4804 char const* end;
4805 bool ok = value.getString(&str, &end);
4806 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
4807 else pushValue("");
4808 break;
4810 case booleanValue:
4811 pushValue(valueToString(value.asBool()));
4812 break;
4813 case arrayValue:
4814 writeArrayValue(value);
4815 break;
4816 case objectValue: {
4817 Value::Members members(value.getMemberNames());
4818 if (members.empty())
4819 pushValue("{}");
4820 else {
4821 writeWithIndent("{");
4822 indent();
4823 Value::Members::iterator it = members.begin();
4824 for (;;) {
4825 const JSONCPP_STRING& name = *it;
4826 const Value& childValue = value[name];
4827 writeCommentBeforeValue(childValue);
4828 writeWithIndent(valueToQuotedString(name.c_str()));
4829 *document_ << " : ";
4830 writeValue(childValue);
4831 if (++it == members.end()) {
4832 writeCommentAfterValueOnSameLine(childValue);
4833 break;
4835 *document_ << ",";
4836 writeCommentAfterValueOnSameLine(childValue);
4838 unindent();
4839 writeWithIndent("}");
4841 } break;
4845 void StyledStreamWriter::writeArrayValue(const Value& value) {
4846 unsigned size = value.size();
4847 if (size == 0)
4848 pushValue("[]");
4849 else {
4850 bool isArrayMultiLine = isMultilineArray(value);
4851 if (isArrayMultiLine) {
4852 writeWithIndent("[");
4853 indent();
4854 bool hasChildValue = !childValues_.empty();
4855 unsigned index = 0;
4856 for (;;) {
4857 const Value& childValue = value[index];
4858 writeCommentBeforeValue(childValue);
4859 if (hasChildValue)
4860 writeWithIndent(childValues_[index]);
4861 else {
4862 if (!indented_) writeIndent();
4863 indented_ = true;
4864 writeValue(childValue);
4865 indented_ = false;
4867 if (++index == size) {
4868 writeCommentAfterValueOnSameLine(childValue);
4869 break;
4871 *document_ << ",";
4872 writeCommentAfterValueOnSameLine(childValue);
4874 unindent();
4875 writeWithIndent("]");
4876 } else // output on a single line
4878 assert(childValues_.size() == size);
4879 *document_ << "[ ";
4880 for (unsigned index = 0; index < size; ++index) {
4881 if (index > 0)
4882 *document_ << ", ";
4883 *document_ << childValues_[index];
4885 *document_ << " ]";
4890 bool StyledStreamWriter::isMultilineArray(const Value& value) {
4891 ArrayIndex const size = value.size();
4892 bool isMultiLine = size * 3 >= rightMargin_;
4893 childValues_.clear();
4894 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
4895 const Value& childValue = value[index];
4896 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
4897 childValue.size() > 0);
4899 if (!isMultiLine) // check if line length > max line length
4901 childValues_.reserve(size);
4902 addChildValues_ = true;
4903 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
4904 for (ArrayIndex index = 0; index < size; ++index) {
4905 if (hasCommentForValue(value[index])) {
4906 isMultiLine = true;
4908 writeValue(value[index]);
4909 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
4911 addChildValues_ = false;
4912 isMultiLine = isMultiLine || lineLength >= rightMargin_;
4914 return isMultiLine;
4917 void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) {
4918 if (addChildValues_)
4919 childValues_.push_back(value);
4920 else
4921 *document_ << value;
4924 void StyledStreamWriter::writeIndent() {
4925 // blep intended this to look at the so-far-written string
4926 // to determine whether we are already indented, but
4927 // with a stream we cannot do that. So we rely on some saved state.
4928 // The caller checks indented_.
4929 *document_ << '\n' << indentString_;
4932 void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) {
4933 if (!indented_) writeIndent();
4934 *document_ << value;
4935 indented_ = false;
4938 void StyledStreamWriter::indent() { indentString_ += indentation_; }
4940 void StyledStreamWriter::unindent() {
4941 assert(indentString_.size() >= indentation_.size());
4942 indentString_.resize(indentString_.size() - indentation_.size());
4945 void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
4946 if (!root.hasComment(commentBefore))
4947 return;
4949 if (!indented_) writeIndent();
4950 const JSONCPP_STRING& comment = root.getComment(commentBefore);
4951 JSONCPP_STRING::const_iterator iter = comment.begin();
4952 while (iter != comment.end()) {
4953 *document_ << *iter;
4954 if (*iter == '\n' &&
4955 ((iter+1) != comment.end() && *(iter + 1) == '/'))
4956 // writeIndent(); // would include newline
4957 *document_ << indentString_;
4958 ++iter;
4960 indented_ = false;
4963 void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
4964 if (root.hasComment(commentAfterOnSameLine))
4965 *document_ << ' ' << root.getComment(commentAfterOnSameLine);
4967 if (root.hasComment(commentAfter)) {
4968 writeIndent();
4969 *document_ << root.getComment(commentAfter);
4971 indented_ = false;
4974 bool StyledStreamWriter::hasCommentForValue(const Value& value) {
4975 return value.hasComment(commentBefore) ||
4976 value.hasComment(commentAfterOnSameLine) ||
4977 value.hasComment(commentAfter);
4980 //////////////////////////
4981 // BuiltStyledStreamWriter
4983 /// Scoped enums are not available until C++11.
4984 struct CommentStyle {
4985 /// Decide whether to write comments.
4986 enum Enum {
4987 None, ///< Drop all comments.
4988 Most, ///< Recover odd behavior of previous versions (not implemented yet).
4989 All ///< Keep all comments.
4993 struct BuiltStyledStreamWriter : public StreamWriter
4995 BuiltStyledStreamWriter(
4996 JSONCPP_STRING const& indentation,
4997 CommentStyle::Enum cs,
4998 JSONCPP_STRING const& colonSymbol,
4999 JSONCPP_STRING const& nullSymbol,
5000 JSONCPP_STRING const& endingLineFeedSymbol,
5001 bool useSpecialFloats,
5002 unsigned int precision);
5003 int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE;
5004 private:
5005 void writeValue(Value const& value);
5006 void writeArrayValue(Value const& value);
5007 bool isMultilineArray(Value const& value);
5008 void pushValue(JSONCPP_STRING const& value);
5009 void writeIndent();
5010 void writeWithIndent(JSONCPP_STRING const& value);
5011 void indent();
5012 void unindent();
5013 void writeCommentBeforeValue(Value const& root);
5014 void writeCommentAfterValueOnSameLine(Value const& root);
5015 static bool hasCommentForValue(const Value& value);
5017 typedef std::vector<JSONCPP_STRING> ChildValues;
5019 ChildValues childValues_;
5020 JSONCPP_STRING indentString_;
5021 unsigned int rightMargin_;
5022 JSONCPP_STRING indentation_;
5023 CommentStyle::Enum cs_;
5024 JSONCPP_STRING colonSymbol_;
5025 JSONCPP_STRING nullSymbol_;
5026 JSONCPP_STRING endingLineFeedSymbol_;
5027 bool addChildValues_ : 1;
5028 bool indented_ : 1;
5029 bool useSpecialFloats_ : 1;
5030 unsigned int precision_;
5032 BuiltStyledStreamWriter::BuiltStyledStreamWriter(
5033 JSONCPP_STRING const& indentation,
5034 CommentStyle::Enum cs,
5035 JSONCPP_STRING const& colonSymbol,
5036 JSONCPP_STRING const& nullSymbol,
5037 JSONCPP_STRING const& endingLineFeedSymbol,
5038 bool useSpecialFloats,
5039 unsigned int precision)
5040 : rightMargin_(74)
5041 , indentation_(indentation)
5042 , cs_(cs)
5043 , colonSymbol_(colonSymbol)
5044 , nullSymbol_(nullSymbol)
5045 , endingLineFeedSymbol_(endingLineFeedSymbol)
5046 , addChildValues_(false)
5047 , indented_(false)
5048 , useSpecialFloats_(useSpecialFloats)
5049 , precision_(precision)
5052 int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout)
5054 sout_ = sout;
5055 addChildValues_ = false;
5056 indented_ = true;
5057 indentString_.clear();
5058 writeCommentBeforeValue(root);
5059 if (!indented_) writeIndent();
5060 indented_ = true;
5061 writeValue(root);
5062 writeCommentAfterValueOnSameLine(root);
5063 *sout_ << endingLineFeedSymbol_;
5064 sout_ = NULL;
5065 return 0;
5067 void BuiltStyledStreamWriter::writeValue(Value const& value) {
5068 switch (value.type()) {
5069 case nullValue:
5070 pushValue(nullSymbol_);
5071 break;
5072 case intValue:
5073 pushValue(valueToString(value.asLargestInt()));
5074 break;
5075 case uintValue:
5076 pushValue(valueToString(value.asLargestUInt()));
5077 break;
5078 case realValue:
5079 pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
5080 break;
5081 case stringValue:
5083 // Is NULL is possible for value.string_? No.
5084 char const* str;
5085 char const* end;
5086 bool ok = value.getString(&str, &end);
5087 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
5088 else pushValue("");
5089 break;
5091 case booleanValue:
5092 pushValue(valueToString(value.asBool()));
5093 break;
5094 case arrayValue:
5095 writeArrayValue(value);
5096 break;
5097 case objectValue: {
5098 Value::Members members(value.getMemberNames());
5099 if (members.empty())
5100 pushValue("{}");
5101 else {
5102 writeWithIndent("{");
5103 indent();
5104 Value::Members::iterator it = members.begin();
5105 for (;;) {
5106 JSONCPP_STRING const& name = *it;
5107 Value const& childValue = value[name];
5108 writeCommentBeforeValue(childValue);
5109 writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())));
5110 *sout_ << colonSymbol_;
5111 writeValue(childValue);
5112 if (++it == members.end()) {
5113 writeCommentAfterValueOnSameLine(childValue);
5114 break;
5116 *sout_ << ",";
5117 writeCommentAfterValueOnSameLine(childValue);
5119 unindent();
5120 writeWithIndent("}");
5122 } break;
5126 void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
5127 unsigned size = value.size();
5128 if (size == 0)
5129 pushValue("[]");
5130 else {
5131 bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value);
5132 if (isMultiLine) {
5133 writeWithIndent("[");
5134 indent();
5135 bool hasChildValue = !childValues_.empty();
5136 unsigned index = 0;
5137 for (;;) {
5138 Value const& childValue = value[index];
5139 writeCommentBeforeValue(childValue);
5140 if (hasChildValue)
5141 writeWithIndent(childValues_[index]);
5142 else {
5143 if (!indented_) writeIndent();
5144 indented_ = true;
5145 writeValue(childValue);
5146 indented_ = false;
5148 if (++index == size) {
5149 writeCommentAfterValueOnSameLine(childValue);
5150 break;
5152 *sout_ << ",";
5153 writeCommentAfterValueOnSameLine(childValue);
5155 unindent();
5156 writeWithIndent("]");
5157 } else // output on a single line
5159 assert(childValues_.size() == size);
5160 *sout_ << "[";
5161 if (!indentation_.empty()) *sout_ << " ";
5162 for (unsigned index = 0; index < size; ++index) {
5163 if (index > 0)
5164 *sout_ << ((!indentation_.empty()) ? ", " : ",");
5165 *sout_ << childValues_[index];
5167 if (!indentation_.empty()) *sout_ << " ";
5168 *sout_ << "]";
5173 bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) {
5174 ArrayIndex const size = value.size();
5175 bool isMultiLine = size * 3 >= rightMargin_;
5176 childValues_.clear();
5177 for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
5178 Value const& childValue = value[index];
5179 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
5180 childValue.size() > 0);
5182 if (!isMultiLine) // check if line length > max line length
5184 childValues_.reserve(size);
5185 addChildValues_ = true;
5186 ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
5187 for (ArrayIndex index = 0; index < size; ++index) {
5188 if (hasCommentForValue(value[index])) {
5189 isMultiLine = true;
5191 writeValue(value[index]);
5192 lineLength += static_cast<ArrayIndex>(childValues_[index].length());
5194 addChildValues_ = false;
5195 isMultiLine = isMultiLine || lineLength >= rightMargin_;
5197 return isMultiLine;
5200 void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) {
5201 if (addChildValues_)
5202 childValues_.push_back(value);
5203 else
5204 *sout_ << value;
5207 void BuiltStyledStreamWriter::writeIndent() {
5208 // blep intended this to look at the so-far-written string
5209 // to determine whether we are already indented, but
5210 // with a stream we cannot do that. So we rely on some saved state.
5211 // The caller checks indented_.
5213 if (!indentation_.empty()) {
5214 // In this case, drop newlines too.
5215 *sout_ << '\n' << indentString_;
5219 void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) {
5220 if (!indented_) writeIndent();
5221 *sout_ << value;
5222 indented_ = false;
5225 void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
5227 void BuiltStyledStreamWriter::unindent() {
5228 assert(indentString_.size() >= indentation_.size());
5229 indentString_.resize(indentString_.size() - indentation_.size());
5232 void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
5233 if (cs_ == CommentStyle::None) return;
5234 if (!root.hasComment(commentBefore))
5235 return;
5237 if (!indented_) writeIndent();
5238 const JSONCPP_STRING& comment = root.getComment(commentBefore);
5239 JSONCPP_STRING::const_iterator iter = comment.begin();
5240 while (iter != comment.end()) {
5241 *sout_ << *iter;
5242 if (*iter == '\n' &&
5243 ((iter+1) != comment.end() && *(iter + 1) == '/'))
5244 // writeIndent(); // would write extra newline
5245 *sout_ << indentString_;
5246 ++iter;
5248 indented_ = false;
5251 void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {
5252 if (cs_ == CommentStyle::None) return;
5253 if (root.hasComment(commentAfterOnSameLine))
5254 *sout_ << " " + root.getComment(commentAfterOnSameLine);
5256 if (root.hasComment(commentAfter)) {
5257 writeIndent();
5258 *sout_ << root.getComment(commentAfter);
5262 // static
5263 bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
5264 return value.hasComment(commentBefore) ||
5265 value.hasComment(commentAfterOnSameLine) ||
5266 value.hasComment(commentAfter);
5269 ///////////////
5270 // StreamWriter
5272 StreamWriter::StreamWriter()
5273 : sout_(NULL)
5276 StreamWriter::~StreamWriter()
5279 StreamWriter::Factory::~Factory()
5281 StreamWriterBuilder::StreamWriterBuilder()
5283 setDefaults(&settings_);
5285 StreamWriterBuilder::~StreamWriterBuilder()
5287 StreamWriter* StreamWriterBuilder::newStreamWriter() const
5289 JSONCPP_STRING indentation = settings_["indentation"].asString();
5290 JSONCPP_STRING cs_str = settings_["commentStyle"].asString();
5291 bool eyc = settings_["enableYAMLCompatibility"].asBool();
5292 bool dnp = settings_["dropNullPlaceholders"].asBool();
5293 bool usf = settings_["useSpecialFloats"].asBool();
5294 unsigned int pre = settings_["precision"].asUInt();
5295 CommentStyle::Enum cs = CommentStyle::All;
5296 if (cs_str == "All") {
5297 cs = CommentStyle::All;
5298 } else if (cs_str == "None") {
5299 cs = CommentStyle::None;
5300 } else {
5301 throwRuntimeError("commentStyle must be 'All' or 'None'");
5303 JSONCPP_STRING colonSymbol = " : ";
5304 if (eyc) {
5305 colonSymbol = ": ";
5306 } else if (indentation.empty()) {
5307 colonSymbol = ":";
5309 JSONCPP_STRING nullSymbol = "null";
5310 if (dnp) {
5311 nullSymbol.clear();
5313 if (pre > 17) pre = 17;
5314 JSONCPP_STRING endingLineFeedSymbol;
5315 return new BuiltStyledStreamWriter(
5316 indentation, cs,
5317 colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
5319 static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys)
5321 valid_keys->clear();
5322 valid_keys->insert("indentation");
5323 valid_keys->insert("commentStyle");
5324 valid_keys->insert("enableYAMLCompatibility");
5325 valid_keys->insert("dropNullPlaceholders");
5326 valid_keys->insert("useSpecialFloats");
5327 valid_keys->insert("precision");
5329 bool StreamWriterBuilder::validate(Json::Value* invalid) const
5331 Json::Value my_invalid;
5332 if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
5333 Json::Value& inv = *invalid;
5334 std::set<JSONCPP_STRING> valid_keys;
5335 getValidWriterKeys(&valid_keys);
5336 Value::Members keys = settings_.getMemberNames();
5337 size_t n = keys.size();
5338 for (size_t i = 0; i < n; ++i) {
5339 JSONCPP_STRING const& key = keys[i];
5340 if (valid_keys.find(key) == valid_keys.end()) {
5341 inv[key] = settings_[key];
5344 return 0u == inv.size();
5346 Value& StreamWriterBuilder::operator[](JSONCPP_STRING key)
5348 return settings_[key];
5350 // static
5351 void StreamWriterBuilder::setDefaults(Json::Value* settings)
5353 //! [StreamWriterBuilderDefaults]
5354 (*settings)["commentStyle"] = "All";
5355 (*settings)["indentation"] = "\t";
5356 (*settings)["enableYAMLCompatibility"] = false;
5357 (*settings)["dropNullPlaceholders"] = false;
5358 (*settings)["useSpecialFloats"] = false;
5359 (*settings)["precision"] = 17;
5360 //! [StreamWriterBuilderDefaults]
5363 JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) {
5364 JSONCPP_OSTRINGSTREAM sout;
5365 StreamWriterPtr const writer(builder.newStreamWriter());
5366 writer->write(root, &sout);
5367 return sout.str();
5370 JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) {
5371 StreamWriterBuilder builder;
5372 StreamWriterPtr const writer(builder.newStreamWriter());
5373 writer->write(root, &sout);
5374 return sout;
5377 } // namespace Json
5379 // //////////////////////////////////////////////////////////////////////
5380 // End of content of file: src/lib_json/json_writer.cpp
5381 // //////////////////////////////////////////////////////////////////////