1 /// Json-cpp amalgated 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 // //////////////////////////////////////////////////////////////////////
9 The JsonCpp library's source code, including accompanying documentation,
10 tests and demonstration applications, are licensed under the following
13 The author (Baptiste Lepilleur) explicitly disclaims 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 is
19 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
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
55 ========================================================================
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
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"
83 // //////////////////////////////////////////////////////////////////////
84 // Beginning of content of file: src/lib_json/json_tool.h
85 // //////////////////////////////////////////////////////////////////////
87 // Copyright 2007-2010 Baptiste Lepilleur
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
95 /* This header provides common string manipulation support, such as UTF-8,
96 * portable conversion from/to string...
98 * It is an internal header that must not be exposed.
103 /// Converts a unicode code-point to UTF-8.
104 static inline std::string codePointToUTF8(unsigned int cp) {
107 // based on description from http://en.wikipedia.org/wiki/UTF-8
111 result[0] = static_cast<char>(cp);
112 } else if (cp <= 0x7FF) {
114 result[1] = static_cast<char>(0x80 | (0x3f & cp));
115 result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
116 } else if (cp <= 0xFFFF) {
118 result[2] = static_cast<char>(0x80 | (0x3f & cp));
119 result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
120 result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
121 } else if (cp <= 0x10FFFF) {
123 result[3] = static_cast<char>(0x80 | (0x3f & cp));
124 result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
125 result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
126 result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
132 /// Returns true if ch is a control character (in range [1,31]).
133 static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
136 /// Constant that specify the size of the buffer that must be passed to
138 uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
141 // Defines a char buffer for use with uintToString().
142 typedef char UIntToStringBuffer[uintToStringBufferSize];
144 /** Converts an unsigned integer to string.
145 * @param value Unsigned interger to convert to string
146 * @param current Input/Output string buffer.
147 * Must have at least uintToStringBufferSize chars free.
149 static inline void uintToString(LargestUInt value, char*& current) {
152 *--current = static_cast<signed char>(value % 10U + static_cast<unsigned>('0'));
154 } while (value != 0);
157 /** Change ',' to '.' everywhere in buffer.
159 * We had a sophisticated way, but it did not work in WinCE.
160 * @see https://github.com/open-source-parsers/jsoncpp/pull/9
162 static inline void fixNumericLocale(char* begin, char* end) {
163 while (begin < end) {
171 } // namespace Json {
173 #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
175 // //////////////////////////////////////////////////////////////////////
176 // End of content of file: src/lib_json/json_tool.h
177 // //////////////////////////////////////////////////////////////////////
184 // //////////////////////////////////////////////////////////////////////
185 // Beginning of content of file: src/lib_json/json_reader.cpp
186 // //////////////////////////////////////////////////////////////////////
188 // Copyright 2007-2011 Baptiste Lepilleur
189 // Distributed under MIT license, or public domain if desired and
190 // recognized in your jurisdiction.
191 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
193 #if !defined(JSON_IS_AMALGAMATION)
194 #include <json/assertions.h>
195 #include <json/reader.h>
196 #include <json/value.h>
197 #include "json_tool.h"
198 #endif // if !defined(JSON_IS_AMALGAMATION)
209 #if defined(_MSC_VER)
210 #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
211 #define snprintf sprintf_s
212 #elif _MSC_VER >= 1900 // VC++ 14.0 and above
213 #define snprintf std::snprintf
215 #define snprintf _snprintf
217 #elif defined(__ANDROID__)
218 #define snprintf snprintf
219 #elif __cplusplus >= 201103L
220 #define snprintf std::snprintf
223 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
224 // Disable warning about strdup being deprecated.
225 #pragma warning(disable : 4996)
228 static int const stackLimit_g = 1000;
229 static int stackDepth_g = 0; // see readValue()
233 typedef std::auto_ptr<CharReader> CharReaderPtr;
235 // Implementation of class Features
236 // ////////////////////////////////
239 : allowComments_(true), strictRoot_(false)
241 Features Features::all() { return Features(); }
243 Features Features::strictMode() {
245 features.allowComments_ = false;
246 features.strictRoot_ = true;
250 // Implementation of class Reader
251 // ////////////////////////////////
253 static bool containsNewLine(Reader::Location begin, Reader::Location end) {
254 for (; begin < end; ++begin)
255 if (*begin == '\n' || *begin == '\r')
261 // //////////////////////////////////////////////////////////////////
264 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
265 lastValue_(), commentsBefore_(), features_(Features::all()),
266 collectComments_() {}
268 Reader::Reader(const Features& features)
269 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
270 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
274 Reader::parse(const std::string& document, Value& root, bool collectComments) {
275 document_ = document;
276 const char* begin = document_.c_str();
277 const char* end = begin + document_.length();
278 return parse(begin, end, root, collectComments);
281 bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
282 // std::istream_iterator<char> begin(sin);
283 // std::istream_iterator<char> end;
284 // Those would allow streamed input from a file, if parse() were a
285 // template function.
287 // Since std::string is reference-counted, this at least does not
288 // create an extra copy.
290 std::getline(sin, doc, (char)EOF);
291 return parse(doc, root, collectComments);
294 bool Reader::parse(const char* beginDoc,
297 bool collectComments) {
298 if (!features_.allowComments_) {
299 collectComments = false;
304 collectComments_ = collectComments;
308 commentsBefore_ = "";
310 while (!nodes_.empty())
314 stackDepth_g = 0; // Yes, this is bad coding, but options are limited.
315 bool successful = readValue();
317 skipCommentTokens(token);
318 if (collectComments_ && !commentsBefore_.empty())
319 root.setComment(commentsBefore_, commentAfter);
320 if (features_.strictRoot_) {
321 if (!root.isArray() && !root.isObject()) {
322 // Set error location to start of doc, ideally should be first token found
324 token.type_ = tokenError;
325 token.start_ = beginDoc;
328 "A valid JSON document must be either an array or an object value.",
336 bool Reader::readValue() {
337 // This is a non-reentrant way to support a stackLimit. Terrible!
338 // But this deprecated class has a security problem: Bad input can
339 // cause a seg-fault. This seems like a fair, binary-compatible way
340 // to prevent the problem.
341 if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
345 skipCommentTokens(token);
346 bool successful = true;
348 if (collectComments_ && !commentsBefore_.empty()) {
349 currentValue().setComment(commentsBefore_, commentBefore);
350 commentsBefore_ = "";
353 switch (token.type_) {
354 case tokenObjectBegin:
355 successful = readObject(token);
357 case tokenArrayBegin:
358 successful = readArray(token);
361 successful = decodeNumber(token);
364 successful = decodeString(token);
369 currentValue().swapPayload(v);
375 currentValue().swapPayload(v);
381 currentValue().swapPayload(v);
384 // Else, fall through...
386 return addError("Syntax error: value, object or array expected.", token);
389 if (collectComments_) {
390 lastValueEnd_ = current_;
391 lastValue_ = ¤tValue();
398 void Reader::skipCommentTokens(Token& token) {
399 if (features_.allowComments_) {
402 } while (token.type_ == tokenComment);
408 bool Reader::readToken(Token& token) {
410 token.start_ = current_;
411 Char c = getNextChar();
415 token.type_ = tokenObjectBegin;
418 token.type_ = tokenObjectEnd;
421 token.type_ = tokenArrayBegin;
424 token.type_ = tokenArrayEnd;
427 token.type_ = tokenString;
431 token.type_ = tokenComment;
445 token.type_ = tokenNumber;
449 token.type_ = tokenTrue;
450 ok = match("rue", 3);
453 token.type_ = tokenFalse;
454 ok = match("alse", 4);
457 token.type_ = tokenNull;
458 ok = match("ull", 3);
461 token.type_ = tokenArraySeparator;
464 token.type_ = tokenMemberSeparator;
467 token.type_ = tokenEndOfStream;
474 token.type_ = tokenError;
475 token.end_ = current_;
479 void Reader::skipSpaces() {
480 while (current_ != end_) {
482 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
489 bool Reader::match(Location pattern, int patternLength) {
490 if (end_ - current_ < patternLength)
492 int index = patternLength;
494 if (current_[index] != pattern[index])
496 current_ += patternLength;
500 bool Reader::readComment() {
501 Location commentBegin = current_ - 1;
502 Char c = getNextChar();
503 bool successful = false;
505 successful = readCStyleComment();
507 successful = readCppStyleComment();
511 if (collectComments_) {
512 CommentPlacement placement = commentBefore;
513 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
514 if (c != '*' || !containsNewLine(commentBegin, current_))
515 placement = commentAfterOnSameLine;
518 addComment(commentBegin, current_, placement);
523 static std::string normalizeEOL(Reader::Location begin, Reader::Location end) {
524 std::string normalized;
525 normalized.reserve(end - begin);
526 Reader::Location current = begin;
527 while (current != end) {
530 if (current != end && *current == '\n')
543 Reader::addComment(Location begin, Location end, CommentPlacement placement) {
544 assert(collectComments_);
545 const std::string& normalized = normalizeEOL(begin, end);
546 if (placement == commentAfterOnSameLine) {
547 assert(lastValue_ != 0);
548 lastValue_->setComment(normalized, placement);
550 commentsBefore_ += normalized;
554 bool Reader::readCStyleComment() {
555 while (current_ != end_) {
556 Char c = getNextChar();
557 if (c == '*' && *current_ == '/')
560 return getNextChar() == '/';
563 bool Reader::readCppStyleComment() {
564 while (current_ != end_) {
565 Char c = getNextChar();
569 // Consume DOS EOL. It will be normalized in addComment.
570 if (current_ != end_ && *current_ == '\n')
572 // Break on Moc OS 9 EOL.
579 void Reader::readNumber() {
580 const char *p = current_;
581 char c = '0'; // stopgap for already consumed character
583 while (c >= '0' && c <= '9')
584 c = (current_ = p) < end_ ? *p++ : 0;
587 c = (current_ = p) < end_ ? *p++ : 0;
588 while (c >= '0' && c <= '9')
589 c = (current_ = p) < end_ ? *p++ : 0;
592 if (c == 'e' || c == 'E') {
593 c = (current_ = p) < end_ ? *p++ : 0;
594 if (c == '+' || c == '-')
595 c = (current_ = p) < end_ ? *p++ : 0;
596 while (c >= '0' && c <= '9')
597 c = (current_ = p) < end_ ? *p++ : 0;
601 bool Reader::readString() {
603 while (current_ != end_) {
613 bool Reader::readObject(Token& /*tokenStart*/) {
616 Value init(objectValue);
617 currentValue().swapPayload(init);
618 while (readToken(tokenName)) {
619 bool initialTokenOk = true;
620 while (tokenName.type_ == tokenComment && initialTokenOk)
621 initialTokenOk = readToken(tokenName);
624 if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
627 if (tokenName.type_ == tokenString) {
628 if (!decodeString(tokenName, name))
629 return recoverFromError(tokenObjectEnd);
635 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
636 return addErrorAndRecover(
637 "Missing ':' after object member name", colon, tokenObjectEnd);
639 Value& value = currentValue()[name];
641 bool ok = readValue();
643 if (!ok) // error already set
644 return recoverFromError(tokenObjectEnd);
647 if (!readToken(comma) ||
648 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
649 comma.type_ != tokenComment)) {
650 return addErrorAndRecover(
651 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
653 bool finalizeTokenOk = true;
654 while (comma.type_ == tokenComment && finalizeTokenOk)
655 finalizeTokenOk = readToken(comma);
656 if (comma.type_ == tokenObjectEnd)
659 return addErrorAndRecover(
660 "Missing '}' or object member name", tokenName, tokenObjectEnd);
663 bool Reader::readArray(Token& /*tokenStart*/) {
664 Value init(arrayValue);
665 currentValue().swapPayload(init);
667 if (*current_ == ']') // empty array
675 Value& value = currentValue()[index++];
677 bool ok = readValue();
679 if (!ok) // error already set
680 return recoverFromError(tokenArrayEnd);
683 // Accept Comment after last item in the array.
684 ok = readToken(token);
685 while (token.type_ == tokenComment && ok) {
686 ok = readToken(token);
689 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
690 if (!ok || badTokenType) {
691 return addErrorAndRecover(
692 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
694 if (token.type_ == tokenArrayEnd)
700 bool Reader::decodeNumber(Token& token) {
702 if (!decodeNumber(token, decoded))
704 currentValue().swapPayload(decoded);
708 bool Reader::decodeNumber(Token& token, Value& decoded) {
709 // Attempts to parse the number as an integer. If the number is
710 // larger than the maximum supported value of an integer then
711 // we decode the number as a double.
712 Location current = token.start_;
713 bool isNegative = *current == '-';
716 // TODO: Help the compiler do the div and mod at compile time or get rid of them.
717 Value::LargestUInt maxIntegerValue =
718 isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
719 : Value::maxLargestUInt;
720 Value::LargestUInt threshold = maxIntegerValue / 10;
721 Value::LargestUInt value = 0;
722 while (current < token.end_) {
724 if (c < '0' || c > '9')
725 return decodeDouble(token, decoded);
726 Value::UInt digit(c - '0');
727 if (value >= threshold) {
728 // We've hit or exceeded the max value divided by 10 (rounded down). If
729 // a) we've only just touched the limit, b) this is the last digit, and
730 // c) it's small enough to fit in that rounding delta, we're okay.
731 // Otherwise treat this number as a double to avoid overflow.
732 if (value > threshold || current != token.end_ ||
733 digit > maxIntegerValue % 10) {
734 return decodeDouble(token, decoded);
737 value = value * 10 + digit;
739 if (isNegative && value == maxIntegerValue)
740 decoded = Value::minLargestInt;
742 decoded = -Value::LargestInt(value);
743 else if (value <= Value::LargestUInt(Value::maxInt))
744 decoded = Value::LargestInt(value);
750 bool Reader::decodeDouble(Token& token) {
752 if (!decodeDouble(token, decoded))
754 currentValue().swapPayload(decoded);
758 bool Reader::decodeDouble(Token& token, Value& decoded) {
760 std::string buffer(token.start_, token.end_);
761 std::istringstream is(buffer);
763 return addError("'" + std::string(token.start_, token.end_) +
764 "' is not a number.",
770 bool Reader::decodeString(Token& token) {
771 std::string decoded_string;
772 if (!decodeString(token, decoded_string))
774 Value decoded(decoded_string);
775 currentValue().swapPayload(decoded);
779 bool Reader::decodeString(Token& token, std::string& decoded) {
780 decoded.reserve(token.end_ - token.start_ - 2);
781 Location current = token.start_ + 1; // skip '"'
782 Location end = token.end_ - 1; // do not include '"'
783 while (current != end) {
787 else if (c == '\\') {
789 return addError("Empty escape sequence in string", token, current);
790 Char escape = *current++;
817 unsigned int unicode;
818 if (!decodeUnicodeCodePoint(token, current, end, unicode))
820 decoded += codePointToUTF8(unicode);
823 return addError("Bad escape sequence in string", token, current);
832 bool Reader::decodeUnicodeCodePoint(Token& token,
835 unsigned int& unicode) {
837 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
839 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
841 if (end - current < 6)
843 "additional six characters expected to parse unicode surrogate pair.",
846 unsigned int surrogatePair;
847 if (*(current++) == '\\' && *(current++) == 'u') {
848 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
849 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
853 return addError("expecting another \\u token to begin the second half of "
854 "a unicode surrogate pair",
861 bool Reader::decodeUnicodeEscapeSequence(Token& token,
864 unsigned int& unicode) {
865 if (end - current < 4)
867 "Bad unicode escape sequence in string: four digits expected.",
871 for (int index = 0; index < 4; ++index) {
874 if (c >= '0' && c <= '9')
876 else if (c >= 'a' && c <= 'f')
877 unicode += c - 'a' + 10;
878 else if (c >= 'A' && c <= 'F')
879 unicode += c - 'A' + 10;
882 "Bad unicode escape sequence in string: hexadecimal digit expected.",
890 Reader::addError(const std::string& message, Token& token, Location extra) {
893 info.message_ = message;
895 errors_.push_back(info);
899 bool Reader::recoverFromError(TokenType skipUntilToken) {
900 int errorCount = int(errors_.size());
903 if (!readToken(skip))
904 errors_.resize(errorCount); // discard errors caused by recovery
905 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
908 errors_.resize(errorCount);
912 bool Reader::addErrorAndRecover(const std::string& message,
914 TokenType skipUntilToken) {
915 addError(message, token);
916 return recoverFromError(skipUntilToken);
919 Value& Reader::currentValue() { return *(nodes_.top()); }
921 Reader::Char Reader::getNextChar() {
922 if (current_ == end_)
927 void Reader::getLocationLineAndColumn(Location location,
930 Location current = begin_;
931 Location lastLineStart = current;
933 while (current < location && current != end_) {
936 if (*current == '\n')
938 lastLineStart = current;
940 } else if (c == '\n') {
941 lastLineStart = current;
945 // column & line start at 1
946 column = int(location - lastLineStart) + 1;
950 std::string Reader::getLocationLineAndColumn(Location location) const {
952 getLocationLineAndColumn(location, line, column);
953 char buffer[18 + 16 + 16 + 1];
954 snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
958 // Deprecated. Preserved for backward compatibility
959 std::string Reader::getFormatedErrorMessages() const {
960 return getFormattedErrorMessages();
963 std::string Reader::getFormattedErrorMessages() const {
964 std::string formattedMessage;
965 for (Errors::const_iterator itError = errors_.begin();
966 itError != errors_.end();
968 const ErrorInfo& error = *itError;
970 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
971 formattedMessage += " " + error.message_ + "\n";
974 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
976 return formattedMessage;
980 /////////////////////////
982 // exact copy of Features
985 static OurFeatures all();
989 bool allowDroppedNullPlaceholders_;
990 bool allowNumericKeys_;
991 bool allowSingleQuotes_;
994 bool allowSpecialFloats_;
998 // exact copy of Implementation of class Features
999 // ////////////////////////////////
1001 OurFeatures::OurFeatures()
1002 : allowComments_(true), strictRoot_(false)
1003 , allowDroppedNullPlaceholders_(false), allowNumericKeys_(false)
1004 , allowSingleQuotes_(false)
1005 , failIfExtra_(false)
1006 , allowSpecialFloats_(false)
1010 OurFeatures OurFeatures::all() { return OurFeatures(); }
1012 // Implementation of class Reader
1013 // ////////////////////////////////
1015 // exact copy of Reader, renamed to OurReader
1019 typedef const Char* Location;
1020 struct StructuredError {
1021 size_t offset_start;
1022 size_t offset_limit;
1023 std::string message;
1026 OurReader(OurFeatures const& features);
1027 bool parse(const char* beginDoc,
1030 bool collectComments = true);
1031 std::string getFormattedErrorMessages() const;
1034 OurReader(OurReader const&); // no impl
1035 void operator=(OurReader const&); // no impl
1038 tokenEndOfStream = 0,
1051 tokenArraySeparator,
1052 tokenMemberSeparator,
1067 std::string message_;
1071 typedef std::deque<ErrorInfo> Errors;
1073 bool readToken(Token& token);
1075 bool match(Location pattern, int patternLength);
1077 bool readCStyleComment();
1078 bool readCppStyleComment();
1080 bool readStringSingleQuote();
1081 bool readNumber(bool checkInf);
1083 bool readObject(Token& token);
1084 bool readArray(Token& token);
1085 bool decodeNumber(Token& token);
1086 bool decodeNumber(Token& token, Value& decoded);
1087 bool decodeString(Token& token);
1088 bool decodeString(Token& token, std::string& decoded);
1089 bool decodeDouble(Token& token);
1090 bool decodeDouble(Token& token, Value& decoded);
1091 bool decodeUnicodeCodePoint(Token& token,
1094 unsigned int& unicode);
1095 bool decodeUnicodeEscapeSequence(Token& token,
1098 unsigned int& unicode);
1099 bool addError(const std::string& message, Token& token, Location extra = 0);
1100 bool recoverFromError(TokenType skipUntilToken);
1101 bool addErrorAndRecover(const std::string& message,
1103 TokenType skipUntilToken);
1104 void skipUntilSpace();
1105 Value& currentValue();
1108 getLocationLineAndColumn(Location location, int& line, int& column) const;
1109 std::string getLocationLineAndColumn(Location location) const;
1110 void addComment(Location begin, Location end, CommentPlacement placement);
1111 void skipCommentTokens(Token& token);
1113 typedef std::stack<Value*> Nodes;
1116 std::string document_;
1120 Location lastValueEnd_;
1122 std::string commentsBefore_;
1125 OurFeatures const features_;
1126 bool collectComments_;
1129 // complete copy of Read impl, for OurReader
1131 OurReader::OurReader(OurFeatures const& features)
1132 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
1133 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
1136 bool OurReader::parse(const char* beginDoc,
1139 bool collectComments) {
1140 if (!features_.allowComments_) {
1141 collectComments = false;
1146 collectComments_ = collectComments;
1150 commentsBefore_ = "";
1152 while (!nodes_.empty())
1157 bool successful = readValue();
1159 skipCommentTokens(token);
1160 if (features_.failIfExtra_) {
1161 if (token.type_ != tokenError && token.type_ != tokenEndOfStream) {
1162 addError("Extra non-whitespace after JSON value.", token);
1166 if (collectComments_ && !commentsBefore_.empty())
1167 root.setComment(commentsBefore_, commentAfter);
1168 if (features_.strictRoot_) {
1169 if (!root.isArray() && !root.isObject()) {
1170 // Set error location to start of doc, ideally should be first token found
1172 token.type_ = tokenError;
1173 token.start_ = beginDoc;
1174 token.end_ = endDoc;
1176 "A valid JSON document must be either an array or an object value.",
1184 bool OurReader::readValue() {
1185 if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
1188 skipCommentTokens(token);
1189 bool successful = true;
1191 if (collectComments_ && !commentsBefore_.empty()) {
1192 currentValue().setComment(commentsBefore_, commentBefore);
1193 commentsBefore_ = "";
1196 switch (token.type_) {
1197 case tokenObjectBegin:
1198 successful = readObject(token);
1200 case tokenArrayBegin:
1201 successful = readArray(token);
1204 successful = decodeNumber(token);
1207 successful = decodeString(token);
1212 currentValue().swapPayload(v);
1218 currentValue().swapPayload(v);
1224 currentValue().swapPayload(v);
1229 Value v(std::numeric_limits<double>::quiet_NaN());
1230 currentValue().swapPayload(v);
1235 Value v(std::numeric_limits<double>::infinity());
1236 currentValue().swapPayload(v);
1241 Value v(-std::numeric_limits<double>::infinity());
1242 currentValue().swapPayload(v);
1245 case tokenArraySeparator:
1246 case tokenObjectEnd:
1248 if (features_.allowDroppedNullPlaceholders_) {
1249 // "Un-read" the current token and mark the current value as a null
1253 currentValue().swapPayload(v);
1255 } // else, fall through ...
1257 return addError("Syntax error: value, object or array expected.", token);
1260 if (collectComments_) {
1261 lastValueEnd_ = current_;
1262 lastValue_ = ¤tValue();
1269 void OurReader::skipCommentTokens(Token& token) {
1270 if (features_.allowComments_) {
1273 } while (token.type_ == tokenComment);
1279 bool OurReader::readToken(Token& token) {
1281 token.start_ = current_;
1282 Char c = getNextChar();
1286 token.type_ = tokenObjectBegin;
1289 token.type_ = tokenObjectEnd;
1292 token.type_ = tokenArrayBegin;
1295 token.type_ = tokenArrayEnd;
1298 token.type_ = tokenString;
1302 if (features_.allowSingleQuotes_) {
1303 token.type_ = tokenString;
1304 ok = readStringSingleQuote();
1308 token.type_ = tokenComment;
1321 token.type_ = tokenNumber;
1325 if (readNumber(true)) {
1326 token.type_ = tokenNumber;
1328 token.type_ = tokenNegInf;
1329 ok = features_.allowSpecialFloats_ && match("nfinity", 7);
1333 token.type_ = tokenTrue;
1334 ok = match("rue", 3);
1337 token.type_ = tokenFalse;
1338 ok = match("alse", 4);
1341 token.type_ = tokenNull;
1342 ok = match("ull", 3);
1345 if (features_.allowSpecialFloats_) {
1346 token.type_ = tokenNaN;
1347 ok = match("aN", 2);
1353 if (features_.allowSpecialFloats_) {
1354 token.type_ = tokenPosInf;
1355 ok = match("nfinity", 7);
1361 token.type_ = tokenArraySeparator;
1364 token.type_ = tokenMemberSeparator;
1367 token.type_ = tokenEndOfStream;
1374 token.type_ = tokenError;
1375 token.end_ = current_;
1379 void OurReader::skipSpaces() {
1380 while (current_ != end_) {
1382 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
1389 bool OurReader::match(Location pattern, int patternLength) {
1390 if (end_ - current_ < patternLength)
1392 int index = patternLength;
1394 if (current_[index] != pattern[index])
1396 current_ += patternLength;
1400 bool OurReader::readComment() {
1401 Location commentBegin = current_ - 1;
1402 Char c = getNextChar();
1403 bool successful = false;
1405 successful = readCStyleComment();
1407 successful = readCppStyleComment();
1411 if (collectComments_) {
1412 CommentPlacement placement = commentBefore;
1413 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1414 if (c != '*' || !containsNewLine(commentBegin, current_))
1415 placement = commentAfterOnSameLine;
1418 addComment(commentBegin, current_, placement);
1424 OurReader::addComment(Location begin, Location end, CommentPlacement placement) {
1425 assert(collectComments_);
1426 const std::string& normalized = normalizeEOL(begin, end);
1427 if (placement == commentAfterOnSameLine) {
1428 assert(lastValue_ != 0);
1429 lastValue_->setComment(normalized, placement);
1431 commentsBefore_ += normalized;
1435 bool OurReader::readCStyleComment() {
1436 while (current_ != end_) {
1437 Char c = getNextChar();
1438 if (c == '*' && *current_ == '/')
1441 return getNextChar() == '/';
1444 bool OurReader::readCppStyleComment() {
1445 while (current_ != end_) {
1446 Char c = getNextChar();
1450 // Consume DOS EOL. It will be normalized in addComment.
1451 if (current_ != end_ && *current_ == '\n')
1453 // Break on Moc OS 9 EOL.
1460 bool OurReader::readNumber(bool checkInf) {
1461 const char *p = current_;
1462 if (checkInf && p != end_ && *p == 'I') {
1466 char c = '0'; // stopgap for already consumed character
1468 while (c >= '0' && c <= '9')
1469 c = (current_ = p) < end_ ? *p++ : 0;
1472 c = (current_ = p) < end_ ? *p++ : 0;
1473 while (c >= '0' && c <= '9')
1474 c = (current_ = p) < end_ ? *p++ : 0;
1477 if (c == 'e' || c == 'E') {
1478 c = (current_ = p) < end_ ? *p++ : 0;
1479 if (c == '+' || c == '-')
1480 c = (current_ = p) < end_ ? *p++ : 0;
1481 while (c >= '0' && c <= '9')
1482 c = (current_ = p) < end_ ? *p++ : 0;
1486 bool OurReader::readString() {
1488 while (current_ != end_) {
1499 bool OurReader::readStringSingleQuote() {
1501 while (current_ != end_) {
1511 bool OurReader::readObject(Token& /*tokenStart*/) {
1514 Value init(objectValue);
1515 currentValue().swapPayload(init);
1516 while (readToken(tokenName)) {
1517 bool initialTokenOk = true;
1518 while (tokenName.type_ == tokenComment && initialTokenOk)
1519 initialTokenOk = readToken(tokenName);
1520 if (!initialTokenOk)
1522 if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
1525 if (tokenName.type_ == tokenString) {
1526 if (!decodeString(tokenName, name))
1527 return recoverFromError(tokenObjectEnd);
1528 } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1530 if (!decodeNumber(tokenName, numberName))
1531 return recoverFromError(tokenObjectEnd);
1532 name = numberName.asString();
1538 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1539 return addErrorAndRecover(
1540 "Missing ':' after object member name", colon, tokenObjectEnd);
1542 if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
1543 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1544 std::string msg = "Duplicate key: '" + name + "'";
1545 return addErrorAndRecover(
1546 msg, tokenName, tokenObjectEnd);
1548 Value& value = currentValue()[name];
1549 nodes_.push(&value);
1550 bool ok = readValue();
1552 if (!ok) // error already set
1553 return recoverFromError(tokenObjectEnd);
1556 if (!readToken(comma) ||
1557 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1558 comma.type_ != tokenComment)) {
1559 return addErrorAndRecover(
1560 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
1562 bool finalizeTokenOk = true;
1563 while (comma.type_ == tokenComment && finalizeTokenOk)
1564 finalizeTokenOk = readToken(comma);
1565 if (comma.type_ == tokenObjectEnd)
1568 return addErrorAndRecover(
1569 "Missing '}' or object member name", tokenName, tokenObjectEnd);
1572 bool OurReader::readArray(Token& /*tokenStart*/) {
1573 Value init(arrayValue);
1574 currentValue().swapPayload(init);
1576 if (*current_ == ']') // empty array
1579 readToken(endArray);
1584 Value& value = currentValue()[index++];
1585 nodes_.push(&value);
1586 bool ok = readValue();
1588 if (!ok) // error already set
1589 return recoverFromError(tokenArrayEnd);
1592 // Accept Comment after last item in the array.
1593 ok = readToken(token);
1594 while (token.type_ == tokenComment && ok) {
1595 ok = readToken(token);
1598 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
1599 if (!ok || badTokenType) {
1600 return addErrorAndRecover(
1601 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
1603 if (token.type_ == tokenArrayEnd)
1609 bool OurReader::decodeNumber(Token& token) {
1611 if (!decodeNumber(token, decoded))
1613 currentValue().swapPayload(decoded);
1617 bool OurReader::decodeNumber(Token& token, Value& decoded) {
1618 // Attempts to parse the number as an integer. If the number is
1619 // larger than the maximum supported value of an integer then
1620 // we decode the number as a double.
1621 Location current = token.start_;
1622 bool isNegative = *current == '-';
1625 // TODO: Help the compiler do the div and mod at compile time or get rid of them.
1626 Value::LargestUInt maxIntegerValue =
1627 isNegative ? Value::LargestUInt(-Value::minLargestInt)
1628 : Value::maxLargestUInt;
1629 Value::LargestUInt threshold = maxIntegerValue / 10;
1630 Value::LargestUInt value = 0;
1631 while (current < token.end_) {
1632 Char c = *current++;
1633 if (c < '0' || c > '9')
1634 return decodeDouble(token, decoded);
1635 Value::UInt digit(c - '0');
1636 if (value >= threshold) {
1637 // We've hit or exceeded the max value divided by 10 (rounded down). If
1638 // a) we've only just touched the limit, b) this is the last digit, and
1639 // c) it's small enough to fit in that rounding delta, we're okay.
1640 // Otherwise treat this number as a double to avoid overflow.
1641 if (value > threshold || current != token.end_ ||
1642 digit > maxIntegerValue % 10) {
1643 return decodeDouble(token, decoded);
1646 value = value * 10 + digit;
1649 decoded = -Value::LargestInt(value);
1650 else if (value <= Value::LargestUInt(Value::maxInt))
1651 decoded = Value::LargestInt(value);
1657 bool OurReader::decodeDouble(Token& token) {
1659 if (!decodeDouble(token, decoded))
1661 currentValue().swapPayload(decoded);
1665 bool OurReader::decodeDouble(Token& token, Value& decoded) {
1667 std::string buffer( token.start_, token.end_ );
1668 std::istringstream is(buffer);
1670 return addError("'" + std::string(token.start_, token.end_) +
1671 "' is not a number.",
1677 bool OurReader::decodeString(Token& token) {
1678 std::string decoded_string;
1679 if (!decodeString(token, decoded_string))
1681 Value decoded(decoded_string);
1682 currentValue().swapPayload(decoded);
1686 bool OurReader::decodeString(Token& token, std::string& decoded) {
1687 decoded.reserve(token.end_ - token.start_ - 2);
1688 Location current = token.start_ + 1; // skip '"'
1689 Location end = token.end_ - 1; // do not include '"'
1690 while (current != end) {
1691 Char c = *current++;
1694 else if (c == '\\') {
1696 return addError("Empty escape sequence in string", token, current);
1697 Char escape = *current++;
1724 unsigned int unicode;
1725 if (!decodeUnicodeCodePoint(token, current, end, unicode))
1727 decoded += codePointToUTF8(unicode);
1730 return addError("Bad escape sequence in string", token, current);
1739 bool OurReader::decodeUnicodeCodePoint(Token& token,
1742 unsigned int& unicode) {
1744 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1746 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1748 if (end - current < 6)
1750 "additional six characters expected to parse unicode surrogate pair.",
1753 unsigned int surrogatePair;
1754 if (*(current++) == '\\' && *(current++) == 'u') {
1755 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1756 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1760 return addError("expecting another \\u token to begin the second half of "
1761 "a unicode surrogate pair",
1768 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
1771 unsigned int& unicode) {
1772 if (end - current < 4)
1774 "Bad unicode escape sequence in string: four digits expected.",
1778 for (int index = 0; index < 4; ++index) {
1779 Char c = *current++;
1781 if (c >= '0' && c <= '9')
1783 else if (c >= 'a' && c <= 'f')
1784 unicode += c - 'a' + 10;
1785 else if (c >= 'A' && c <= 'F')
1786 unicode += c - 'A' + 10;
1789 "Bad unicode escape sequence in string: hexadecimal digit expected.",
1797 OurReader::addError(const std::string& message, Token& token, Location extra) {
1799 info.token_ = token;
1800 info.message_ = message;
1801 info.extra_ = extra;
1802 errors_.push_back(info);
1806 bool OurReader::recoverFromError(TokenType skipUntilToken) {
1807 int errorCount = int(errors_.size());
1810 if (!readToken(skip))
1811 errors_.resize(errorCount); // discard errors caused by recovery
1812 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1815 errors_.resize(errorCount);
1819 bool OurReader::addErrorAndRecover(const std::string& message,
1821 TokenType skipUntilToken) {
1822 addError(message, token);
1823 return recoverFromError(skipUntilToken);
1826 Value& OurReader::currentValue() { return *(nodes_.top()); }
1828 OurReader::Char OurReader::getNextChar() {
1829 if (current_ == end_)
1834 void OurReader::getLocationLineAndColumn(Location location,
1836 int& column) const {
1837 Location current = begin_;
1838 Location lastLineStart = current;
1840 while (current < location && current != end_) {
1841 Char c = *current++;
1843 if (*current == '\n')
1845 lastLineStart = current;
1847 } else if (c == '\n') {
1848 lastLineStart = current;
1852 // column & line start at 1
1853 column = int(location - lastLineStart) + 1;
1857 std::string OurReader::getLocationLineAndColumn(Location location) const {
1859 getLocationLineAndColumn(location, line, column);
1860 char buffer[18 + 16 + 16 + 1];
1861 snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
1865 std::string OurReader::getFormattedErrorMessages() const {
1866 std::string formattedMessage;
1867 for (Errors::const_iterator itError = errors_.begin();
1868 itError != errors_.end();
1870 const ErrorInfo& error = *itError;
1872 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
1873 formattedMessage += " " + error.message_ + "\n";
1876 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
1878 return formattedMessage;
1882 class OurCharReader : public CharReader {
1883 bool const collectComments_;
1887 bool collectComments,
1888 OurFeatures const& features)
1889 : collectComments_(collectComments)
1893 char const* beginDoc, char const* endDoc,
1894 Value* root, std::string* errs) {
1895 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1897 *errs = reader_.getFormattedErrorMessages();
1903 CharReaderBuilder::CharReaderBuilder()
1905 setDefaults(&settings_);
1907 CharReaderBuilder::~CharReaderBuilder()
1909 CharReader* CharReaderBuilder::newCharReader() const
1911 bool collectComments = settings_["collectComments"].asBool();
1912 OurFeatures features = OurFeatures::all();
1913 features.allowComments_ = settings_["allowComments"].asBool();
1914 features.strictRoot_ = settings_["strictRoot"].asBool();
1915 features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
1916 features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
1917 features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
1918 features.stackLimit_ = settings_["stackLimit"].asInt();
1919 features.failIfExtra_ = settings_["failIfExtra"].asBool();
1920 features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
1921 features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
1922 return new OurCharReader(collectComments, features);
1924 static void getValidReaderKeys(std::set<std::string>* valid_keys)
1926 valid_keys->clear();
1927 valid_keys->insert("collectComments");
1928 valid_keys->insert("allowComments");
1929 valid_keys->insert("strictRoot");
1930 valid_keys->insert("allowDroppedNullPlaceholders");
1931 valid_keys->insert("allowNumericKeys");
1932 valid_keys->insert("allowSingleQuotes");
1933 valid_keys->insert("stackLimit");
1934 valid_keys->insert("failIfExtra");
1935 valid_keys->insert("rejectDupKeys");
1936 valid_keys->insert("allowSpecialFloats");
1938 bool CharReaderBuilder::validate(Json::Value* invalid) const
1940 Json::Value my_invalid;
1941 if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
1942 Json::Value& inv = *invalid;
1943 std::set<std::string> valid_keys;
1944 getValidReaderKeys(&valid_keys);
1945 Value::Members keys = settings_.getMemberNames();
1946 size_t n = keys.size();
1947 for (size_t i = 0; i < n; ++i) {
1948 std::string const& key = keys[i];
1949 if (valid_keys.find(key) == valid_keys.end()) {
1950 inv[key] = settings_[key];
1953 return 0u == inv.size();
1955 Value& CharReaderBuilder::operator[](std::string key)
1957 return settings_[key];
1960 void CharReaderBuilder::strictMode(Json::Value* settings)
1962 //! [CharReaderBuilderStrictMode]
1963 (*settings)["allowComments"] = false;
1964 (*settings)["strictRoot"] = true;
1965 (*settings)["allowDroppedNullPlaceholders"] = false;
1966 (*settings)["allowNumericKeys"] = false;
1967 (*settings)["allowSingleQuotes"] = false;
1968 (*settings)["failIfExtra"] = true;
1969 (*settings)["rejectDupKeys"] = true;
1970 (*settings)["allowSpecialFloats"] = false;
1971 //! [CharReaderBuilderStrictMode]
1974 void CharReaderBuilder::setDefaults(Json::Value* settings)
1976 //! [CharReaderBuilderDefaults]
1977 (*settings)["collectComments"] = true;
1978 (*settings)["allowComments"] = true;
1979 (*settings)["strictRoot"] = false;
1980 (*settings)["allowDroppedNullPlaceholders"] = false;
1981 (*settings)["allowNumericKeys"] = false;
1982 (*settings)["allowSingleQuotes"] = false;
1983 (*settings)["stackLimit"] = 1000;
1984 (*settings)["failIfExtra"] = false;
1985 (*settings)["rejectDupKeys"] = false;
1986 (*settings)["allowSpecialFloats"] = false;
1987 //! [CharReaderBuilderDefaults]
1990 //////////////////////////////////
1993 bool parseFromStream(
1994 CharReader::Factory const& fact, std::istream& sin,
1995 Value* root, std::string* errs)
1997 std::ostringstream ssin;
1998 ssin << sin.rdbuf();
1999 std::string doc = ssin.str();
2000 char const* begin = doc.data();
2001 char const* end = begin + doc.size();
2002 // Note that we do not actually need a null-terminator.
2003 CharReaderPtr const reader(fact.newCharReader());
2004 return reader->parse(begin, end, root, errs);
2007 std::istream& operator>>(std::istream& sin, Value& root) {
2008 CharReaderBuilder b;
2010 bool ok = parseFromStream(b, sin, &root, &errs);
2013 "Error from reader: %s",
2016 throwRuntimeError("reader error");
2023 // //////////////////////////////////////////////////////////////////////
2024 // End of content of file: src/lib_json/json_reader.cpp
2025 // //////////////////////////////////////////////////////////////////////
2032 // //////////////////////////////////////////////////////////////////////
2033 // Beginning of content of file: src/lib_json/json_valueiterator.inl
2034 // //////////////////////////////////////////////////////////////////////
2036 // Copyright 2007-2010 Baptiste Lepilleur
2037 // Distributed under MIT license, or public domain if desired and
2038 // recognized in your jurisdiction.
2039 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
2041 // included by json_value.cpp
2045 // //////////////////////////////////////////////////////////////////
2046 // //////////////////////////////////////////////////////////////////
2047 // //////////////////////////////////////////////////////////////////
2048 // class ValueIteratorBase
2049 // //////////////////////////////////////////////////////////////////
2050 // //////////////////////////////////////////////////////////////////
2051 // //////////////////////////////////////////////////////////////////
2053 ValueIteratorBase::ValueIteratorBase()
2054 : current_(), isNull_(true) {
2057 ValueIteratorBase::ValueIteratorBase(
2058 const Value::ObjectValues::iterator& current)
2059 : current_(current), isNull_(false) {}
2061 Value& ValueIteratorBase::deref() const {
2062 return current_->second;
2065 void ValueIteratorBase::increment() {
2069 void ValueIteratorBase::decrement() {
2073 ValueIteratorBase::difference_type
2074 ValueIteratorBase::computeDistance(const SelfType& other) const {
2075 #ifdef JSON_USE_CPPTL_SMALLMAP
2076 return other.current_ - current_;
2078 // Iterator for null value are initialized using the default
2079 // constructor, which initialize current_ to the default
2080 // std::map::iterator. As begin() and end() are two instance
2081 // of the default std::map::iterator, they can not be compared.
2082 // To allow this, we handle this comparison specifically.
2083 if (isNull_ && other.isNull_) {
2087 // Usage of std::distance is not portable (does not compile with Sun Studio 12
2089 // which is the one used by default).
2090 // Using a portable hand-made version for non random iterator instead:
2091 // return difference_type( std::distance( current_, other.current_ ) );
2092 difference_type myDistance = 0;
2093 for (Value::ObjectValues::iterator it = current_; it != other.current_;
2101 bool ValueIteratorBase::isEqual(const SelfType& other) const {
2103 return other.isNull_;
2105 return current_ == other.current_;
2108 void ValueIteratorBase::copy(const SelfType& other) {
2109 current_ = other.current_;
2110 isNull_ = other.isNull_;
2113 Value ValueIteratorBase::key() const {
2114 const Value::CZString czstring = (*current_).first;
2115 if (czstring.data()) {
2116 if (czstring.isStaticString())
2117 return Value(StaticString(czstring.data()));
2118 return Value(czstring.data(), czstring.data() + czstring.length());
2120 return Value(czstring.index());
2123 UInt ValueIteratorBase::index() const {
2124 const Value::CZString czstring = (*current_).first;
2125 if (!czstring.data())
2126 return czstring.index();
2127 return Value::UInt(-1);
2130 std::string ValueIteratorBase::name() const {
2133 keey = memberName(&end);
2134 if (!keey) return std::string();
2135 return std::string(keey, end);
2138 char const* ValueIteratorBase::memberName() const {
2139 const char* cname = (*current_).first.data();
2140 return cname ? cname : "";
2143 char const* ValueIteratorBase::memberName(char const** end) const {
2144 const char* cname = (*current_).first.data();
2149 *end = cname + (*current_).first.length();
2153 // //////////////////////////////////////////////////////////////////
2154 // //////////////////////////////////////////////////////////////////
2155 // //////////////////////////////////////////////////////////////////
2156 // class ValueConstIterator
2157 // //////////////////////////////////////////////////////////////////
2158 // //////////////////////////////////////////////////////////////////
2159 // //////////////////////////////////////////////////////////////////
2161 ValueConstIterator::ValueConstIterator() {}
2163 ValueConstIterator::ValueConstIterator(
2164 const Value::ObjectValues::iterator& current)
2165 : ValueIteratorBase(current) {}
2167 ValueConstIterator& ValueConstIterator::
2168 operator=(const ValueIteratorBase& other) {
2173 // //////////////////////////////////////////////////////////////////
2174 // //////////////////////////////////////////////////////////////////
2175 // //////////////////////////////////////////////////////////////////
2176 // class ValueIterator
2177 // //////////////////////////////////////////////////////////////////
2178 // //////////////////////////////////////////////////////////////////
2179 // //////////////////////////////////////////////////////////////////
2181 ValueIterator::ValueIterator() {}
2183 ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
2184 : ValueIteratorBase(current) {}
2186 ValueIterator::ValueIterator(const ValueConstIterator& other)
2187 : ValueIteratorBase(other) {}
2189 ValueIterator::ValueIterator(const ValueIterator& other)
2190 : ValueIteratorBase(other) {}
2192 ValueIterator& ValueIterator::operator=(const SelfType& other) {
2199 // //////////////////////////////////////////////////////////////////////
2200 // End of content of file: src/lib_json/json_valueiterator.inl
2201 // //////////////////////////////////////////////////////////////////////
2208 // //////////////////////////////////////////////////////////////////////
2209 // Beginning of content of file: src/lib_json/json_value.cpp
2210 // //////////////////////////////////////////////////////////////////////
2212 // Copyright 2011 Baptiste Lepilleur
2213 // Distributed under MIT license, or public domain if desired and
2214 // recognized in your jurisdiction.
2215 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
2217 #if !defined(JSON_IS_AMALGAMATION)
2218 #include <json/assertions.h>
2219 #include <json/value.h>
2220 #include <json/writer.h>
2221 #endif // if !defined(JSON_IS_AMALGAMATION)
2227 #ifdef JSON_USE_CPPTL
2228 #include <cpptl/conststring.h>
2230 #include <cstddef> // size_t
2231 #include <algorithm> // min()
2233 #define JSON_ASSERT_UNREACHABLE assert(false)
2237 // This is a walkaround to avoid the static initialization of Value::null.
2238 // kNull must be word-aligned to avoid crashing on ARM. We use an alignment of
2239 // 8 (instead of 4) as a bit of future-proofing.
2240 #if defined(__ARMEL__)
2241 #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
2243 // This exists for binary compatibility only. Use nullRef.
2244 const Value Value::null;
2245 #define ALIGNAS(byte_alignment)
2247 static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
2248 const unsigned char& kNullRef = kNull[0];
2249 const Value& Value::nullRef = reinterpret_cast<const Value&>(kNullRef);
2251 const Int Value::minInt = Int(~(UInt(-1) / 2));
2252 const Int Value::maxInt = Int(UInt(-1) / 2);
2253 const UInt Value::maxUInt = UInt(-1);
2254 #if defined(JSON_HAS_INT64)
2255 const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));
2256 const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);
2257 const UInt64 Value::maxUInt64 = UInt64(-1);
2258 // The constant is hard-coded because some compiler have trouble
2259 // converting Value::maxUInt64 to a double correctly (AIX/xlC).
2260 // Assumes that UInt64 is a 64 bits integer.
2261 static const double maxUInt64AsDouble = 18446744073709551615.0;
2262 #endif // defined(JSON_HAS_INT64)
2263 const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
2264 const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
2265 const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
2267 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2268 template <typename T, typename U>
2269 static inline bool InRange(double d, T min, U max) {
2270 return d >= min && d <= max;
2272 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2273 static inline double integerToDouble(Json::UInt64 value) {
2274 return static_cast<double>(Int64(value / 2)) * 2.0 + Int64(value & 1);
2277 template <typename T> static inline double integerToDouble(T value) {
2278 return static_cast<double>(value);
2281 template <typename T, typename U>
2282 static inline bool InRange(double d, T min, U max) {
2283 return d >= integerToDouble(min) && d <= integerToDouble(max);
2285 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2287 /** Duplicates the specified string value.
2288 * @param value Pointer to the string to duplicate. Must be zero-terminated if
2289 * length is "unknown".
2290 * @param length Length of the value. if equals to unknown, then it will be
2291 * computed using strlen(value).
2292 * @return Pointer on the duplicate instance of string.
2294 static inline char* duplicateStringValue(const char* value,
2296 // Avoid an integer overflow in the call to malloc below by limiting length
2298 if (length >= (size_t)Value::maxInt)
2299 length = Value::maxInt - 1;
2301 char* newString = static_cast<char*>(malloc(length + 1));
2302 if (newString == NULL) {
2304 "in Json::Value::duplicateStringValue(): "
2305 "Failed to allocate string value buffer");
2307 memcpy(newString, value, length);
2308 newString[length] = 0;
2312 /* Record the length as a prefix.
2314 static inline char* duplicateAndPrefixStringValue(
2316 unsigned int length)
2318 // Avoid an integer overflow in the call to malloc below by limiting length
2320 JSON_ASSERT_MESSAGE(length <= (unsigned)Value::maxInt - sizeof(unsigned) - 1U,
2321 "in Json::Value::duplicateAndPrefixStringValue(): "
2322 "length too big for prefixing");
2323 unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;
2324 char* newString = static_cast<char*>(malloc(actualLength));
2325 if (newString == 0) {
2327 "in Json::Value::duplicateAndPrefixStringValue(): "
2328 "Failed to allocate string value buffer");
2330 *reinterpret_cast<unsigned*>(newString) = length;
2331 memcpy(newString + sizeof(unsigned), value, length);
2332 newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
2335 inline static void decodePrefixedString(
2336 bool isPrefixed, char const* prefixed,
2337 unsigned* length, char const** value)
2340 *length = static_cast<unsigned>(strlen(prefixed));
2343 *length = *reinterpret_cast<unsigned const*>(prefixed);
2344 *value = prefixed + sizeof(unsigned);
2347 /** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue().
2349 static inline void releaseStringValue(char* value) { free(value); }
2353 // //////////////////////////////////////////////////////////////////
2354 // //////////////////////////////////////////////////////////////////
2355 // //////////////////////////////////////////////////////////////////
2356 // ValueInternals...
2357 // //////////////////////////////////////////////////////////////////
2358 // //////////////////////////////////////////////////////////////////
2359 // //////////////////////////////////////////////////////////////////
2360 #if !defined(JSON_IS_AMALGAMATION)
2362 #include "json_valueiterator.inl"
2363 #endif // if !defined(JSON_IS_AMALGAMATION)
2367 Exception::Exception(std::string const& msg)
2370 Exception::~Exception() throw()
2372 char const* Exception::what() const throw()
2374 return msg_.c_str();
2376 RuntimeError::RuntimeError(std::string const& msg)
2379 LogicError::LogicError(std::string const& msg)
2382 JSONCPP_NORETURN void throwRuntimeError(std::string const& msg)
2384 throw RuntimeError(msg);
2386 JSONCPP_NORETURN void throwLogicError(std::string const& msg)
2388 throw LogicError(msg);
2391 // //////////////////////////////////////////////////////////////////
2392 // //////////////////////////////////////////////////////////////////
2393 // //////////////////////////////////////////////////////////////////
2394 // class Value::CommentInfo
2395 // //////////////////////////////////////////////////////////////////
2396 // //////////////////////////////////////////////////////////////////
2397 // //////////////////////////////////////////////////////////////////
2399 Value::CommentInfo::CommentInfo() : comment_(0) {}
2401 Value::CommentInfo::~CommentInfo() {
2403 releaseStringValue(comment_);
2406 void Value::CommentInfo::setComment(const char* text, size_t len) {
2408 releaseStringValue(comment_);
2411 JSON_ASSERT(text != 0);
2412 JSON_ASSERT_MESSAGE(
2413 text[0] == '\0' || text[0] == '/',
2414 "in Json::Value::setComment(): Comments must start with /");
2415 // It seems that /**/ style comments are acceptable as well.
2416 comment_ = duplicateStringValue(text, len);
2419 // //////////////////////////////////////////////////////////////////
2420 // //////////////////////////////////////////////////////////////////
2421 // //////////////////////////////////////////////////////////////////
2422 // class Value::CZString
2423 // //////////////////////////////////////////////////////////////////
2424 // //////////////////////////////////////////////////////////////////
2425 // //////////////////////////////////////////////////////////////////
2427 // Notes: policy_ indicates if the string was allocated when
2428 // a string is stored.
2430 Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {}
2432 Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate)
2435 // allocate != duplicate
2436 storage_.policy_ = allocate & 0x3;
2437 storage_.length_ = ulength & 0x3FFFFFFF;
2440 Value::CZString::CZString(const CZString& other)
2441 : cstr_(other.storage_.policy_ != noDuplication && other.cstr_ != 0
2442 ? duplicateStringValue(other.cstr_, other.storage_.length_)
2445 storage_.policy_ = (other.cstr_
2446 ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication
2447 ? noDuplication : duplicate)
2448 : static_cast<DuplicationPolicy>(other.storage_.policy_));
2449 storage_.length_ = other.storage_.length_;
2452 Value::CZString::~CZString() {
2453 if (cstr_ && storage_.policy_ == duplicate)
2454 releaseStringValue(const_cast<char*>(cstr_));
2457 void Value::CZString::swap(CZString& other) {
2458 std::swap(cstr_, other.cstr_);
2459 std::swap(index_, other.index_);
2462 Value::CZString& Value::CZString::operator=(CZString other) {
2467 bool Value::CZString::operator<(const CZString& other) const {
2468 if (!cstr_) return index_ < other.index_;
2469 //return strcmp(cstr_, other.cstr_) < 0;
2470 // Assume both are strings.
2471 unsigned this_len = this->storage_.length_;
2472 unsigned other_len = other.storage_.length_;
2473 unsigned min_len = std::min(this_len, other_len);
2474 int comp = memcmp(this->cstr_, other.cstr_, min_len);
2475 if (comp < 0) return true;
2476 if (comp > 0) return false;
2477 return (this_len < other_len);
2480 bool Value::CZString::operator==(const CZString& other) const {
2481 if (!cstr_) return index_ == other.index_;
2482 //return strcmp(cstr_, other.cstr_) == 0;
2483 // Assume both are strings.
2484 unsigned this_len = this->storage_.length_;
2485 unsigned other_len = other.storage_.length_;
2486 if (this_len != other_len) return false;
2487 int comp = memcmp(this->cstr_, other.cstr_, this_len);
2491 ArrayIndex Value::CZString::index() const { return index_; }
2493 //const char* Value::CZString::c_str() const { return cstr_; }
2494 const char* Value::CZString::data() const { return cstr_; }
2495 unsigned Value::CZString::length() const { return storage_.length_; }
2496 bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; }
2498 // //////////////////////////////////////////////////////////////////
2499 // //////////////////////////////////////////////////////////////////
2500 // //////////////////////////////////////////////////////////////////
2501 // class Value::Value
2502 // //////////////////////////////////////////////////////////////////
2503 // //////////////////////////////////////////////////////////////////
2504 // //////////////////////////////////////////////////////////////////
2506 /*! \internal Default constructor initialization must be equivalent to:
2507 * memset( this, 0, sizeof(Value) )
2508 * This optimization is used in ValueInternalMap fast allocator.
2510 Value::Value(ValueType vtype) {
2527 value_.map_ = new ObjectValues();
2530 value_.bool_ = false;
2533 JSON_ASSERT_UNREACHABLE;
2537 Value::Value(Int value) {
2538 initBasic(intValue);
2539 value_.int_ = value;
2542 Value::Value(UInt value) {
2543 initBasic(uintValue);
2544 value_.uint_ = value;
2546 #if defined(JSON_HAS_INT64)
2547 Value::Value(Int64 value) {
2548 initBasic(intValue);
2549 value_.int_ = value;
2551 Value::Value(UInt64 value) {
2552 initBasic(uintValue);
2553 value_.uint_ = value;
2555 #endif // defined(JSON_HAS_INT64)
2557 Value::Value(double value) {
2558 initBasic(realValue);
2559 value_.real_ = value;
2562 Value::Value(const char* value) {
2563 initBasic(stringValue, true);
2564 value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value)));
2567 Value::Value(const char* beginValue, const char* endValue) {
2568 initBasic(stringValue, true);
2570 duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue));
2573 Value::Value(const std::string& value) {
2574 initBasic(stringValue, true);
2576 duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length()));
2579 Value::Value(const StaticString& value) {
2580 initBasic(stringValue);
2581 value_.string_ = const_cast<char*>(value.c_str());
2584 #ifdef JSON_USE_CPPTL
2585 Value::Value(const CppTL::ConstString& value) {
2586 initBasic(stringValue, true);
2587 value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length()));
2591 Value::Value(bool value) {
2592 initBasic(booleanValue);
2593 value_.bool_ = value;
2596 Value::Value(Value const& other)
2597 : type_(other.type_), allocated_(false)
2607 value_ = other.value_;
2610 if (other.value_.string_ && other.allocated_) {
2613 decodePrefixedString(other.allocated_, other.value_.string_,
2615 value_.string_ = duplicateAndPrefixStringValue(str, len);
2618 value_.string_ = other.value_.string_;
2624 value_.map_ = new ObjectValues(*other.value_.map_);
2627 JSON_ASSERT_UNREACHABLE;
2629 if (other.comments_) {
2630 comments_ = new CommentInfo[numberOfCommentPlacement];
2631 for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
2632 const CommentInfo& otherComment = other.comments_[comment];
2633 if (otherComment.comment_)
2634 comments_[comment].setComment(
2635 otherComment.comment_, strlen(otherComment.comment_));
2650 releaseStringValue(value_.string_);
2657 JSON_ASSERT_UNREACHABLE;
2664 Value &Value::operator=(const Value &other) {
2670 void Value::swapPayload(Value& other) {
2671 ValueType temp = type_;
2672 type_ = other.type_;
2674 std::swap(value_, other.value_);
2675 int temp2 = allocated_;
2676 allocated_ = other.allocated_;
2677 other.allocated_ = temp2 & 0x1;
2680 void Value::swap(Value& other) {
2682 std::swap(comments_, other.comments_);
2685 ValueType Value::type() const { return type_; }
2687 int Value::compare(const Value& other) const {
2695 bool Value::operator<(const Value& other) const {
2696 int typeDelta = type_ - other.type_;
2698 return typeDelta < 0 ? true : false;
2703 return value_.int_ < other.value_.int_;
2705 return value_.uint_ < other.value_.uint_;
2707 return value_.real_ < other.value_.real_;
2709 return value_.bool_ < other.value_.bool_;
2712 if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
2713 if (other.value_.string_) return true;
2718 char const* this_str;
2719 char const* other_str;
2720 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
2721 decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
2722 unsigned min_len = std::min(this_len, other_len);
2723 int comp = memcmp(this_str, other_str, min_len);
2724 if (comp < 0) return true;
2725 if (comp > 0) return false;
2726 return (this_len < other_len);
2730 int delta = int(value_.map_->size() - other.value_.map_->size());
2733 return (*value_.map_) < (*other.value_.map_);
2736 JSON_ASSERT_UNREACHABLE;
2738 return false; // unreachable
2741 bool Value::operator<=(const Value& other) const { return !(other < *this); }
2743 bool Value::operator>=(const Value& other) const { return !(*this < other); }
2745 bool Value::operator>(const Value& other) const { return other < *this; }
2747 bool Value::operator==(const Value& other) const {
2748 // if ( type_ != other.type_ )
2750 // attempt to take address of bit-field structure member `Json::Value::type_'
2751 // Beats me, but a temp solves the problem.
2752 int temp = other.type_;
2759 return value_.int_ == other.value_.int_;
2761 return value_.uint_ == other.value_.uint_;
2763 return value_.real_ == other.value_.real_;
2765 return value_.bool_ == other.value_.bool_;
2768 if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
2769 return (value_.string_ == other.value_.string_);
2773 char const* this_str;
2774 char const* other_str;
2775 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
2776 decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
2777 if (this_len != other_len) return false;
2778 int comp = memcmp(this_str, other_str, this_len);
2783 return value_.map_->size() == other.value_.map_->size() &&
2784 (*value_.map_) == (*other.value_.map_);
2786 JSON_ASSERT_UNREACHABLE;
2788 return false; // unreachable
2791 bool Value::operator!=(const Value& other) const { return !(*this == other); }
2793 const char* Value::asCString() const {
2794 JSON_ASSERT_MESSAGE(type_ == stringValue,
2795 "in Json::Value::asCString(): requires stringValue");
2796 if (value_.string_ == 0) return 0;
2798 char const* this_str;
2799 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
2803 bool Value::getString(char const** str, char const** cend) const {
2804 if (type_ != stringValue) return false;
2805 if (value_.string_ == 0) return false;
2807 decodePrefixedString(this->allocated_, this->value_.string_, &length, str);
2808 *cend = *str + length;
2812 std::string Value::asString() const {
2818 if (value_.string_ == 0) return "";
2820 char const* this_str;
2821 decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
2822 return std::string(this_str, this_len);
2825 return value_.bool_ ? "true" : "false";
2827 return valueToString(value_.int_);
2829 return valueToString(value_.uint_);
2831 return valueToString(value_.real_);
2833 JSON_FAIL_MESSAGE("Type is not convertible to string");
2837 #ifdef JSON_USE_CPPTL
2838 CppTL::ConstString Value::asConstString() const {
2841 decodePrefixedString(allocated_, value_.string_,
2843 return CppTL::ConstString(str, len);
2847 Value::Int Value::asInt() const {
2850 JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
2851 return Int(value_.int_);
2853 JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
2854 return Int(value_.uint_);
2856 JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
2857 "double out of Int range");
2858 return Int(value_.real_);
2862 return value_.bool_ ? 1 : 0;
2866 JSON_FAIL_MESSAGE("Value is not convertible to Int.");
2869 Value::UInt Value::asUInt() const {
2872 JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
2873 return UInt(value_.int_);
2875 JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
2876 return UInt(value_.uint_);
2878 JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
2879 "double out of UInt range");
2880 return UInt(value_.real_);
2884 return value_.bool_ ? 1 : 0;
2888 JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
2891 #if defined(JSON_HAS_INT64)
2893 Value::Int64 Value::asInt64() const {
2896 return Int64(value_.int_);
2898 JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
2899 return Int64(value_.uint_);
2901 JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
2902 "double out of Int64 range");
2903 return Int64(value_.real_);
2907 return value_.bool_ ? 1 : 0;
2911 JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
2914 Value::UInt64 Value::asUInt64() const {
2917 JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
2918 return UInt64(value_.int_);
2920 return UInt64(value_.uint_);
2922 JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
2923 "double out of UInt64 range");
2924 return UInt64(value_.real_);
2928 return value_.bool_ ? 1 : 0;
2932 JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
2934 #endif // if defined(JSON_HAS_INT64)
2936 LargestInt Value::asLargestInt() const {
2937 #if defined(JSON_NO_INT64)
2944 LargestUInt Value::asLargestUInt() const {
2945 #if defined(JSON_NO_INT64)
2952 double Value::asDouble() const {
2955 return static_cast<double>(value_.int_);
2957 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2958 return static_cast<double>(value_.uint_);
2959 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2960 return integerToDouble(value_.uint_);
2961 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2963 return value_.real_;
2967 return value_.bool_ ? 1.0 : 0.0;
2971 JSON_FAIL_MESSAGE("Value is not convertible to double.");
2974 float Value::asFloat() const {
2977 return static_cast<float>(value_.int_);
2979 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2980 return static_cast<float>(value_.uint_);
2981 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2982 return integerToDouble(value_.uint_);
2983 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2985 return static_cast<float>(value_.real_);
2989 return value_.bool_ ? 1.0f : 0.0f;
2993 JSON_FAIL_MESSAGE("Value is not convertible to float.");
2996 bool Value::asBool() const {
2999 return value_.bool_;
3003 return value_.int_ ? true : false;
3005 return value_.uint_ ? true : false;
3007 // This is kind of strange. Not recommended.
3008 return (value_.real_ != 0.0) ? true : false;
3012 JSON_FAIL_MESSAGE("Value is not convertible to bool.");
3015 bool Value::isConvertibleTo(ValueType other) const {
3018 return (isNumeric() && asDouble() == 0.0) ||
3019 (type_ == booleanValue && value_.bool_ == false) ||
3020 (type_ == stringValue && asString() == "") ||
3021 (type_ == arrayValue && value_.map_->size() == 0) ||
3022 (type_ == objectValue && value_.map_->size() == 0) ||
3026 (type_ == realValue && InRange(value_.real_, minInt, maxInt)) ||
3027 type_ == booleanValue || type_ == nullValue;
3030 (type_ == realValue && InRange(value_.real_, 0, maxUInt)) ||
3031 type_ == booleanValue || type_ == nullValue;
3033 return isNumeric() || type_ == booleanValue || type_ == nullValue;
3035 return isNumeric() || type_ == booleanValue || type_ == nullValue;
3037 return isNumeric() || type_ == booleanValue || type_ == stringValue ||
3040 return type_ == arrayValue || type_ == nullValue;
3042 return type_ == objectValue || type_ == nullValue;
3044 JSON_ASSERT_UNREACHABLE;
3048 /// Number of values in array or object
3049 ArrayIndex Value::size() const {
3058 case arrayValue: // size of the array is highest index + 1
3059 if (!value_.map_->empty()) {
3060 ObjectValues::const_iterator itLast = value_.map_->end();
3062 return (*itLast).first.index() + 1;
3066 return ArrayIndex(value_.map_->size());
3068 JSON_ASSERT_UNREACHABLE;
3069 return 0; // unreachable;
3072 bool Value::empty() const {
3073 if (isNull() || isArray() || isObject())
3074 return size() == 0u;
3079 bool Value::operator!() const { return isNull(); }
3081 void Value::clear() {
3082 JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
3083 type_ == objectValue,
3084 "in Json::Value::clear(): requires complex value");
3088 value_.map_->clear();
3095 void Value::resize(ArrayIndex newSize) {
3096 JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
3097 "in Json::Value::resize(): requires arrayValue");
3098 if (type_ == nullValue)
3099 *this = Value(arrayValue);
3100 ArrayIndex oldSize = size();
3103 else if (newSize > oldSize)
3104 (*this)[newSize - 1];
3106 for (ArrayIndex index = newSize; index < oldSize; ++index) {
3107 value_.map_->erase(index);
3109 assert(size() == newSize);
3113 Value& Value::operator[](ArrayIndex index) {
3114 JSON_ASSERT_MESSAGE(
3115 type_ == nullValue || type_ == arrayValue,
3116 "in Json::Value::operator[](ArrayIndex): requires arrayValue");
3117 if (type_ == nullValue)
3118 *this = Value(arrayValue);
3119 CZString key(index);
3120 ObjectValues::iterator it = value_.map_->lower_bound(key);
3121 if (it != value_.map_->end() && (*it).first == key)
3122 return (*it).second;
3124 ObjectValues::value_type defaultValue(key, nullRef);
3125 it = value_.map_->insert(it, defaultValue);
3126 return (*it).second;
3129 Value& Value::operator[](int index) {
3130 JSON_ASSERT_MESSAGE(
3132 "in Json::Value::operator[](int index): index cannot be negative");
3133 return (*this)[ArrayIndex(index)];
3136 const Value& Value::operator[](ArrayIndex index) const {
3137 JSON_ASSERT_MESSAGE(
3138 type_ == nullValue || type_ == arrayValue,
3139 "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
3140 if (type_ == nullValue)
3142 CZString key(index);
3143 ObjectValues::const_iterator it = value_.map_->find(key);
3144 if (it == value_.map_->end())
3146 return (*it).second;
3149 const Value& Value::operator[](int index) const {
3150 JSON_ASSERT_MESSAGE(
3152 "in Json::Value::operator[](int index) const: index cannot be negative");
3153 return (*this)[ArrayIndex(index)];
3156 void Value::initBasic(ValueType vtype, bool allocated) {
3158 allocated_ = allocated;
3162 // Access an object value by name, create a null member if it does not exist.
3163 // @pre Type of '*this' is object or null.
3164 // @param key is null-terminated.
3165 Value& Value::resolveReference(const char* key) {
3166 JSON_ASSERT_MESSAGE(
3167 type_ == nullValue || type_ == objectValue,
3168 "in Json::Value::resolveReference(): requires objectValue");
3169 if (type_ == nullValue)
3170 *this = Value(objectValue);
3172 key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE!
3173 ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
3174 if (it != value_.map_->end() && (*it).first == actualKey)
3175 return (*it).second;
3177 ObjectValues::value_type defaultValue(actualKey, nullRef);
3178 it = value_.map_->insert(it, defaultValue);
3179 Value& value = (*it).second;
3183 // @param key is not null-terminated.
3184 Value& Value::resolveReference(char const* key, char const* cend)
3186 JSON_ASSERT_MESSAGE(
3187 type_ == nullValue || type_ == objectValue,
3188 "in Json::Value::resolveReference(key, end): requires objectValue");
3189 if (type_ == nullValue)
3190 *this = Value(objectValue);
3192 key, static_cast<unsigned>(cend-key), CZString::duplicateOnCopy);
3193 ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
3194 if (it != value_.map_->end() && (*it).first == actualKey)
3195 return (*it).second;
3197 ObjectValues::value_type defaultValue(actualKey, nullRef);
3198 it = value_.map_->insert(it, defaultValue);
3199 Value& value = (*it).second;
3203 Value Value::get(ArrayIndex index, const Value& defaultValue) const {
3204 const Value* value = &((*this)[index]);
3205 return value == &nullRef ? defaultValue : *value;
3208 bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
3210 Value const* Value::find(char const* key, char const* cend) const
3212 JSON_ASSERT_MESSAGE(
3213 type_ == nullValue || type_ == objectValue,
3214 "in Json::Value::find(key, end, found): requires objectValue or nullValue");
3215 if (type_ == nullValue) return NULL;
3216 CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
3217 ObjectValues::const_iterator it = value_.map_->find(actualKey);
3218 if (it == value_.map_->end()) return NULL;
3219 return &(*it).second;
3221 const Value& Value::operator[](const char* key) const
3223 Value const* found = find(key, key + strlen(key));
3224 if (!found) return nullRef;
3227 Value const& Value::operator[](std::string const& key) const
3229 Value const* found = find(key.data(), key.data() + key.length());
3230 if (!found) return nullRef;
3234 Value& Value::operator[](const char* key) {
3235 return resolveReference(key, key + strlen(key));
3238 Value& Value::operator[](const std::string& key) {
3239 return resolveReference(key.data(), key.data() + key.length());
3242 Value& Value::operator[](const StaticString& key) {
3243 return resolveReference(key.c_str());
3246 #ifdef JSON_USE_CPPTL
3247 Value& Value::operator[](const CppTL::ConstString& key) {
3248 return resolveReference(key.c_str(), key.end_c_str());
3250 Value const& Value::operator[](CppTL::ConstString const& key) const
3252 Value const* found = find(key.c_str(), key.end_c_str());
3253 if (!found) return nullRef;
3258 Value& Value::append(const Value& value) { return (*this)[size()] = value; }
3260 Value Value::get(char const* key, char const* cend, Value const& defaultValue) const
3262 Value const* found = find(key, cend);
3263 return !found ? defaultValue : *found;
3265 Value Value::get(char const* key, Value const& defaultValue) const
3267 return get(key, key + strlen(key), defaultValue);
3269 Value Value::get(std::string const& key, Value const& defaultValue) const
3271 return get(key.data(), key.data() + key.length(), defaultValue);
3275 bool Value::removeMember(const char* key, const char* cend, Value* removed)
3277 if (type_ != objectValue) {
3280 CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
3281 ObjectValues::iterator it = value_.map_->find(actualKey);
3282 if (it == value_.map_->end())
3284 *removed = it->second;
3285 value_.map_->erase(it);
3288 bool Value::removeMember(const char* key, Value* removed)
3290 return removeMember(key, key + strlen(key), removed);
3292 bool Value::removeMember(std::string const& key, Value* removed)
3294 return removeMember(key.data(), key.data() + key.length(), removed);
3296 Value Value::removeMember(const char* key)
3298 JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
3299 "in Json::Value::removeMember(): requires objectValue");
3300 if (type_ == nullValue)
3303 Value removed; // null
3304 removeMember(key, key + strlen(key), &removed);
3305 return removed; // still null if removeMember() did nothing
3307 Value Value::removeMember(const std::string& key)
3309 return removeMember(key.c_str());
3312 bool Value::removeIndex(ArrayIndex index, Value* removed) {
3313 if (type_ != arrayValue) {
3316 CZString key(index);
3317 ObjectValues::iterator it = value_.map_->find(key);
3318 if (it == value_.map_->end()) {
3321 *removed = it->second;
3322 ArrayIndex oldSize = size();
3323 // shift left all items left, into the place of the "removed"
3324 for (ArrayIndex i = index; i < (oldSize - 1); ++i){
3326 (*value_.map_)[keey] = (*this)[i + 1];
3328 // erase the last one ("leftover")
3329 CZString keyLast(oldSize - 1);
3330 ObjectValues::iterator itLast = value_.map_->find(keyLast);
3331 value_.map_->erase(itLast);
3335 #ifdef JSON_USE_CPPTL
3336 Value Value::get(const CppTL::ConstString& key,
3337 const Value& defaultValue) const {
3338 return get(key.c_str(), key.end_c_str(), defaultValue);
3342 bool Value::isMember(char const* key, char const* cend) const
3344 Value const* value = find(key, cend);
3345 return NULL != value;
3347 bool Value::isMember(char const* key) const
3349 return isMember(key, key + strlen(key));
3351 bool Value::isMember(std::string const& key) const
3353 return isMember(key.data(), key.data() + key.length());
3356 #ifdef JSON_USE_CPPTL
3357 bool Value::isMember(const CppTL::ConstString& key) const {
3358 return isMember(key.c_str(), key.end_c_str());
3362 Value::Members Value::getMemberNames() const {
3363 JSON_ASSERT_MESSAGE(
3364 type_ == nullValue || type_ == objectValue,
3365 "in Json::Value::getMemberNames(), value must be objectValue");
3366 if (type_ == nullValue)
3367 return Value::Members();
3369 members.reserve(value_.map_->size());
3370 ObjectValues::const_iterator it = value_.map_->begin();
3371 ObjectValues::const_iterator itEnd = value_.map_->end();
3372 for (; it != itEnd; ++it) {
3373 members.push_back(std::string((*it).first.data(),
3374 (*it).first.length()));
3379 //# ifdef JSON_USE_CPPTL
3381 // Value::enumMemberNames() const
3383 // if ( type_ == objectValue )
3385 // return CppTL::Enum::any( CppTL::Enum::transform(
3386 // CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
3387 // MemberNamesTransform() ) );
3389 // return EnumMemberNames();
3394 // Value::enumValues() const
3396 // if ( type_ == objectValue || type_ == arrayValue )
3397 // return CppTL::Enum::anyValues( *(value_.map_),
3398 // CppTL::Type<const Value &>() );
3399 // return EnumValues();
3404 static bool IsIntegral(double d) {
3405 double integral_part;
3406 return modf(d, &integral_part) == 0.0;
3409 bool Value::isNull() const { return type_ == nullValue; }
3411 bool Value::isBool() const { return type_ == booleanValue; }
3413 bool Value::isInt() const {
3416 return value_.int_ >= minInt && value_.int_ <= maxInt;
3418 return value_.uint_ <= UInt(maxInt);
3420 return value_.real_ >= minInt && value_.real_ <= maxInt &&
3421 IsIntegral(value_.real_);
3428 bool Value::isUInt() const {
3431 return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
3433 return value_.uint_ <= maxUInt;
3435 return value_.real_ >= 0 && value_.real_ <= maxUInt &&
3436 IsIntegral(value_.real_);
3443 bool Value::isInt64() const {
3444 #if defined(JSON_HAS_INT64)
3449 return value_.uint_ <= UInt64(maxInt64);
3451 // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
3452 // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
3453 // require the value to be strictly less than the limit.
3454 return value_.real_ >= double(minInt64) &&
3455 value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
3459 #endif // JSON_HAS_INT64
3463 bool Value::isUInt64() const {
3464 #if defined(JSON_HAS_INT64)
3467 return value_.int_ >= 0;
3471 // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
3472 // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
3473 // require the value to be strictly less than the limit.
3474 return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
3475 IsIntegral(value_.real_);
3479 #endif // JSON_HAS_INT64
3483 bool Value::isIntegral() const {
3484 #if defined(JSON_HAS_INT64)
3485 return isInt64() || isUInt64();
3487 return isInt() || isUInt();
3491 bool Value::isDouble() const { return type_ == realValue || isIntegral(); }
3493 bool Value::isNumeric() const { return isIntegral() || isDouble(); }
3495 bool Value::isString() const { return type_ == stringValue; }
3497 bool Value::isArray() const { return type_ == arrayValue; }
3499 bool Value::isObject() const { return type_ == objectValue; }
3501 void Value::setComment(const char* comment, size_t len, CommentPlacement placement) {
3503 comments_ = new CommentInfo[numberOfCommentPlacement];
3504 if ((len > 0) && (comment[len-1] == '\n')) {
3505 // Always discard trailing newline, to aid indentation.
3508 comments_[placement].setComment(comment, len);
3511 void Value::setComment(const char* comment, CommentPlacement placement) {
3512 setComment(comment, strlen(comment), placement);
3515 void Value::setComment(const std::string& comment, CommentPlacement placement) {
3516 setComment(comment.c_str(), comment.length(), placement);
3519 bool Value::hasComment(CommentPlacement placement) const {
3520 return comments_ != 0 && comments_[placement].comment_ != 0;
3523 std::string Value::getComment(CommentPlacement placement) const {
3524 if (hasComment(placement))
3525 return comments_[placement].comment_;
3529 std::string Value::toStyledString() const {
3530 StyledWriter writer;
3531 return writer.write(*this);
3534 Value::const_iterator Value::begin() const {
3539 return const_iterator(value_.map_->begin());
3544 return const_iterator();
3547 Value::const_iterator Value::end() const {
3552 return const_iterator(value_.map_->end());
3557 return const_iterator();
3560 Value::iterator Value::begin() {
3565 return iterator(value_.map_->begin());
3573 Value::iterator Value::end() {
3578 return iterator(value_.map_->end());
3586 // class PathArgument
3587 // //////////////////////////////////////////////////////////////////
3589 PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {}
3591 PathArgument::PathArgument(ArrayIndex index)
3592 : key_(), index_(index), kind_(kindIndex) {}
3594 PathArgument::PathArgument(const char* key)
3595 : key_(key), index_(), kind_(kindKey) {}
3597 PathArgument::PathArgument(const std::string& key)
3598 : key_(key.c_str()), index_(), kind_(kindKey) {}
3601 // //////////////////////////////////////////////////////////////////
3603 Path::Path(const std::string& path,
3604 const PathArgument& a1,
3605 const PathArgument& a2,
3606 const PathArgument& a3,
3607 const PathArgument& a4,
3608 const PathArgument& a5) {
3618 void Path::makePath(const std::string& path, const InArgs& in) {
3619 const char* current = path.c_str();
3620 const char* end = current + path.length();
3621 InArgs::const_iterator itInArg = in.begin();
3622 while (current != end) {
3623 if (*current == '[') {
3625 if (*current == '%')
3626 addPathInArg(path, in, itInArg, PathArgument::kindIndex);
3628 ArrayIndex index = 0;
3629 for (; current != end && *current >= '0' && *current <= '9'; ++current)
3630 index = index * 10 + ArrayIndex(*current - '0');
3631 args_.push_back(index);
3633 if (current == end || *current++ != ']')
3634 invalidPath(path, int(current - path.c_str()));
3635 } else if (*current == '%') {
3636 addPathInArg(path, in, itInArg, PathArgument::kindKey);
3638 } else if (*current == '.') {
3641 const char* beginName = current;
3642 while (current != end && !strchr("[.", *current))
3644 args_.push_back(std::string(beginName, current));
3649 void Path::addPathInArg(const std::string& /*path*/,
3651 InArgs::const_iterator& itInArg,
3652 PathArgument::Kind kind) {
3653 if (itInArg == in.end()) {
3654 // Error: missing argument %d
3655 } else if ((*itInArg)->kind_ != kind) {
3656 // Error: bad argument type
3658 args_.push_back(**itInArg);
3662 void Path::invalidPath(const std::string& /*path*/, int /*location*/) {
3663 // Error: invalid path.
3666 const Value& Path::resolve(const Value& root) const {
3667 const Value* node = &root;
3668 for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
3669 const PathArgument& arg = *it;
3670 if (arg.kind_ == PathArgument::kindIndex) {
3671 if (!node->isArray() || !node->isValidIndex(arg.index_)) {
3672 // Error: unable to resolve path (array value expected at position...
3674 node = &((*node)[arg.index_]);
3675 } else if (arg.kind_ == PathArgument::kindKey) {
3676 if (!node->isObject()) {
3677 // Error: unable to resolve path (object value expected at position...)
3679 node = &((*node)[arg.key_]);
3680 if (node == &Value::nullRef) {
3681 // Error: unable to resolve path (object has no member named '' at
3689 Value Path::resolve(const Value& root, const Value& defaultValue) const {
3690 const Value* node = &root;
3691 for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
3692 const PathArgument& arg = *it;
3693 if (arg.kind_ == PathArgument::kindIndex) {
3694 if (!node->isArray() || !node->isValidIndex(arg.index_))
3695 return defaultValue;
3696 node = &((*node)[arg.index_]);
3697 } else if (arg.kind_ == PathArgument::kindKey) {
3698 if (!node->isObject())
3699 return defaultValue;
3700 node = &((*node)[arg.key_]);
3701 if (node == &Value::nullRef)
3702 return defaultValue;
3708 Value& Path::make(Value& root) const {
3709 Value* node = &root;
3710 for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
3711 const PathArgument& arg = *it;
3712 if (arg.kind_ == PathArgument::kindIndex) {
3713 if (!node->isArray()) {
3714 // Error: node is not an array at position ...
3716 node = &((*node)[arg.index_]);
3717 } else if (arg.kind_ == PathArgument::kindKey) {
3718 if (!node->isObject()) {
3719 // Error: node is not an object at position...
3721 node = &((*node)[arg.key_]);
3729 // //////////////////////////////////////////////////////////////////////
3730 // End of content of file: src/lib_json/json_value.cpp
3731 // //////////////////////////////////////////////////////////////////////
3738 // //////////////////////////////////////////////////////////////////////
3739 // Beginning of content of file: src/lib_json/json_writer.cpp
3740 // //////////////////////////////////////////////////////////////////////
3742 // Copyright 2011 Baptiste Lepilleur
3743 // Distributed under MIT license, or public domain if desired and
3744 // recognized in your jurisdiction.
3745 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
3747 #if !defined(JSON_IS_AMALGAMATION)
3748 #include <json/writer.h>
3749 #include "json_tool.h"
3750 #endif // if !defined(JSON_IS_AMALGAMATION)
3760 #if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0
3762 #define isfinite _finite
3763 #elif defined(__sun) && defined(__SVR4) //Solaris
3765 #define isfinite finite
3768 #define isfinite std::isfinite
3771 #if defined(_MSC_VER)
3772 #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
3773 #define snprintf sprintf_s
3774 #elif _MSC_VER >= 1900 // VC++ 14.0 and above
3775 #define snprintf std::snprintf
3777 #define snprintf _snprintf
3779 #elif defined(__ANDROID__)
3780 #define snprintf snprintf
3781 #elif __cplusplus >= 201103L
3782 #define snprintf std::snprintf
3785 #if defined(__BORLANDC__)
3787 #define isfinite _finite
3788 #define snprintf _snprintf
3791 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
3792 // Disable warning about strdup being deprecated.
3793 #pragma warning(disable : 4996)
3798 typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
3800 static bool containsControlCharacter(const char* str) {
3802 if (isControlCharacter(*(str++)))
3808 static bool containsControlCharacter0(const char* str, unsigned len) {
3809 char const* end = str + len;
3810 while (end != str) {
3811 if (isControlCharacter(*str) || 0==*str)
3818 std::string valueToString(LargestInt value) {
3819 UIntToStringBuffer buffer;
3820 char* current = buffer + sizeof(buffer);
3821 if (value == Value::minLargestInt) {
3822 uintToString(LargestUInt(Value::maxLargestInt) + 1, current);
3824 } else if (value < 0) {
3825 uintToString(LargestUInt(-value), current);
3828 uintToString(LargestUInt(value), current);
3830 assert(current >= buffer);
3834 std::string valueToString(LargestUInt value) {
3835 UIntToStringBuffer buffer;
3836 char* current = buffer + sizeof(buffer);
3837 uintToString(value, current);
3838 assert(current >= buffer);
3842 #if defined(JSON_HAS_INT64)
3844 std::string valueToString(Int value) {
3845 return valueToString(LargestInt(value));
3848 std::string valueToString(UInt value) {
3849 return valueToString(LargestUInt(value));
3852 #endif // # if defined(JSON_HAS_INT64)
3854 std::string valueToString(double value, bool useSpecialFloats, unsigned int precision) {
3855 // Allocate a buffer that is more than large enough to store the 16 digits of
3856 // precision requested below.
3860 char formatString[6];
3861 sprintf(formatString, "%%.%dg", precision);
3863 // Print into the buffer. We need not request the alternative representation
3864 // that always has a decimal point because JSON doesn't distingish the
3865 // concepts of reals and integers.
3866 if (isfinite(value)) {
3867 len = snprintf(buffer, sizeof(buffer), formatString, value);
3869 // IEEE standard states that NaN values will not compare to themselves
3870 if (value != value) {
3871 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");
3872 } else if (value < 0) {
3873 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");
3875 len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");
3877 // For those, we do not need to call fixNumLoc, but it is fast.
3880 fixNumericLocale(buffer, buffer + len);
3884 std::string valueToString(double value) { return valueToString(value, false, 17); }
3886 std::string valueToString(bool value) { return value ? "true" : "false"; }
3888 std::string valueToQuotedString(const char* value) {
3891 // Not sure how to handle unicode...
3892 if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL &&
3893 !containsControlCharacter(value))
3894 return std::string("\"") + value + "\"";
3895 // We have to walk value and escape any special characters.
3896 // Appending to std::string is not efficient, but this should be rare.
3897 // (Note: forward slashes are *not* rare, but I am not escaping them.)
3898 std::string::size_type maxsize =
3899 strlen(value) * 2 + 3; // allescaped+quotes+NULL
3901 result.reserve(maxsize); // to avoid lots of mallocs
3903 for (const char* c = value; *c != 0; ++c) {
3927 // Even though \/ is considered a legal escape in JSON, a bare
3928 // slash is also legal, so I see no reason to escape it.
3929 // (I hope I am not misunderstanding something.
3930 // blep notes: actually escaping \/ may be useful in javascript to avoid </
3932 // Should add a flag to allow this compatibility mode and prevent this
3933 // sequence from occurring.
3935 if (isControlCharacter(*c)) {
3936 std::ostringstream oss;
3937 oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
3938 << std::setw(4) << static_cast<int>(*c);
3939 result += oss.str();
3950 // https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp
3951 static char const* strnpbrk(char const* s, char const* accept, size_t n) {
3952 assert((s || !n) && accept);
3954 char const* const end = s + n;
3955 for (char const* cur = s; cur < end; ++cur) {
3957 for (char const* a = accept; *a; ++a) {
3965 static std::string valueToQuotedStringN(const char* value, unsigned length) {
3968 // Not sure how to handle unicode...
3969 if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL &&
3970 !containsControlCharacter0(value, length))
3971 return std::string("\"") + value + "\"";
3972 // We have to walk value and escape any special characters.
3973 // Appending to std::string is not efficient, but this should be rare.
3974 // (Note: forward slashes are *not* rare, but I am not escaping them.)
3975 std::string::size_type maxsize =
3976 length * 2 + 3; // allescaped+quotes+NULL
3978 result.reserve(maxsize); // to avoid lots of mallocs
3980 char const* end = value + length;
3981 for (const char* c = value; c != end; ++c) {
4005 // Even though \/ is considered a legal escape in JSON, a bare
4006 // slash is also legal, so I see no reason to escape it.
4007 // (I hope I am not misunderstanding something.)
4008 // blep notes: actually escaping \/ may be useful in javascript to avoid </
4010 // Should add a flag to allow this compatibility mode and prevent this
4011 // sequence from occurring.
4013 if ((isControlCharacter(*c)) || (*c == 0)) {
4014 std::ostringstream oss;
4015 oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
4016 << std::setw(4) << static_cast<int>(*c);
4017 result += oss.str();
4029 // //////////////////////////////////////////////////////////////////
4030 Writer::~Writer() {}
4033 // //////////////////////////////////////////////////////////////////
4035 FastWriter::FastWriter()
4036 : yamlCompatiblityEnabled_(false) {}
4038 void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
4040 std::string FastWriter::write(const Value& root) {
4047 void FastWriter::writeValue(const Value& value) {
4048 switch (value.type()) {
4050 document_ += "null";
4053 document_ += valueToString(value.asLargestInt());
4056 document_ += valueToString(value.asLargestUInt());
4059 document_ += valueToString(value.asDouble());
4063 // Is NULL possible for value.string_?
4066 bool ok = value.getString(&str, &end);
4067 if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str));
4071 document_ += valueToString(value.asBool());
4075 int size = value.size();
4076 for (int index = 0; index < size; ++index) {
4079 writeValue(value[index]);
4084 Value::Members members(value.getMemberNames());
4086 for (Value::Members::iterator it = members.begin(); it != members.end();
4088 const std::string& name = *it;
4089 if (it != members.begin())
4091 document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()));
4092 document_ += yamlCompatiblityEnabled_ ? ": " : ":";
4093 writeValue(value[name]);
4100 // Class StyledWriter
4101 // //////////////////////////////////////////////////////////////////
4103 StyledWriter::StyledWriter()
4104 : rightMargin_(74), indentSize_(3), addChildValues_() {}
4106 std::string StyledWriter::write(const Value& root) {
4108 addChildValues_ = false;
4110 writeCommentBeforeValue(root);
4112 writeCommentAfterValueOnSameLine(root);
4117 void StyledWriter::writeValue(const Value& value) {
4118 switch (value.type()) {
4123 pushValue(valueToString(value.asLargestInt()));
4126 pushValue(valueToString(value.asLargestUInt()));
4129 pushValue(valueToString(value.asDouble()));
4133 // Is NULL possible for value.string_?
4136 bool ok = value.getString(&str, &end);
4137 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
4142 pushValue(valueToString(value.asBool()));
4145 writeArrayValue(value);
4148 Value::Members members(value.getMemberNames());
4149 if (members.empty())
4152 writeWithIndent("{");
4154 Value::Members::iterator it = members.begin();
4156 const std::string& name = *it;
4157 const Value& childValue = value[name];
4158 writeCommentBeforeValue(childValue);
4159 writeWithIndent(valueToQuotedString(name.c_str()));
4161 writeValue(childValue);
4162 if (++it == members.end()) {
4163 writeCommentAfterValueOnSameLine(childValue);
4167 writeCommentAfterValueOnSameLine(childValue);
4170 writeWithIndent("}");
4176 void StyledWriter::writeArrayValue(const Value& value) {
4177 unsigned size = value.size();
4181 bool isArrayMultiLine = isMultineArray(value);
4182 if (isArrayMultiLine) {
4183 writeWithIndent("[");
4185 bool hasChildValue = !childValues_.empty();
4188 const Value& childValue = value[index];
4189 writeCommentBeforeValue(childValue);
4191 writeWithIndent(childValues_[index]);
4194 writeValue(childValue);
4196 if (++index == size) {
4197 writeCommentAfterValueOnSameLine(childValue);
4201 writeCommentAfterValueOnSameLine(childValue);
4204 writeWithIndent("]");
4205 } else // output on a single line
4207 assert(childValues_.size() == size);
4209 for (unsigned index = 0; index < size; ++index) {
4212 document_ += childValues_[index];
4219 bool StyledWriter::isMultineArray(const Value& value) {
4220 int size = value.size();
4221 bool isMultiLine = size * 3 >= rightMargin_;
4222 childValues_.clear();
4223 for (int index = 0; index < size && !isMultiLine; ++index) {
4224 const Value& childValue = value[index];
4226 isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
4227 childValue.size() > 0);
4229 if (!isMultiLine) // check if line length > max line length
4231 childValues_.reserve(size);
4232 addChildValues_ = true;
4233 int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
4234 for (int index = 0; index < size; ++index) {
4235 if (hasCommentForValue(value[index])) {
4238 writeValue(value[index]);
4239 lineLength += int(childValues_[index].length());
4241 addChildValues_ = false;
4242 isMultiLine = isMultiLine || lineLength >= rightMargin_;
4247 void StyledWriter::pushValue(const std::string& value) {
4248 if (addChildValues_)
4249 childValues_.push_back(value);
4254 void StyledWriter::writeIndent() {
4255 if (!document_.empty()) {
4256 char last = document_[document_.length() - 1];
4257 if (last == ' ') // already indented
4259 if (last != '\n') // Comments may add new-line
4262 document_ += indentString_;
4265 void StyledWriter::writeWithIndent(const std::string& value) {
4270 void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); }
4272 void StyledWriter::unindent() {
4273 assert(int(indentString_.size()) >= indentSize_);
4274 indentString_.resize(indentString_.size() - indentSize_);
4277 void StyledWriter::writeCommentBeforeValue(const Value& root) {
4278 if (!root.hasComment(commentBefore))
4283 const std::string& comment = root.getComment(commentBefore);
4284 std::string::const_iterator iter = comment.begin();
4285 while (iter != comment.end()) {
4287 if (*iter == '\n' &&
4288 (iter != comment.end() && *(iter + 1) == '/'))
4293 // Comments are stripped of trailing newlines, so add one here
4297 void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
4298 if (root.hasComment(commentAfterOnSameLine))
4299 document_ += " " + root.getComment(commentAfterOnSameLine);
4301 if (root.hasComment(commentAfter)) {
4303 document_ += root.getComment(commentAfter);
4308 bool StyledWriter::hasCommentForValue(const Value& value) {
4309 return value.hasComment(commentBefore) ||
4310 value.hasComment(commentAfterOnSameLine) ||
4311 value.hasComment(commentAfter);
4314 // Class StyledStreamWriter
4315 // //////////////////////////////////////////////////////////////////
4317 StyledStreamWriter::StyledStreamWriter(std::string indentation)
4318 : document_(NULL), rightMargin_(74), indentation_(indentation),
4319 addChildValues_() {}
4321 void StyledStreamWriter::write(std::ostream& out, const Value& root) {
4323 addChildValues_ = false;
4326 writeCommentBeforeValue(root);
4327 if (!indented_) writeIndent();
4330 writeCommentAfterValueOnSameLine(root);
4332 document_ = NULL; // Forget the stream, for safety.
4335 void StyledStreamWriter::writeValue(const Value& value) {
4336 switch (value.type()) {
4341 pushValue(valueToString(value.asLargestInt()));
4344 pushValue(valueToString(value.asLargestUInt()));
4347 pushValue(valueToString(value.asDouble()));
4351 // Is NULL possible for value.string_?
4354 bool ok = value.getString(&str, &end);
4355 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
4360 pushValue(valueToString(value.asBool()));
4363 writeArrayValue(value);
4366 Value::Members members(value.getMemberNames());
4367 if (members.empty())
4370 writeWithIndent("{");
4372 Value::Members::iterator it = members.begin();
4374 const std::string& name = *it;
4375 const Value& childValue = value[name];
4376 writeCommentBeforeValue(childValue);
4377 writeWithIndent(valueToQuotedString(name.c_str()));
4378 *document_ << " : ";
4379 writeValue(childValue);
4380 if (++it == members.end()) {
4381 writeCommentAfterValueOnSameLine(childValue);
4385 writeCommentAfterValueOnSameLine(childValue);
4388 writeWithIndent("}");
4394 void StyledStreamWriter::writeArrayValue(const Value& value) {
4395 unsigned size = value.size();
4399 bool isArrayMultiLine = isMultineArray(value);
4400 if (isArrayMultiLine) {
4401 writeWithIndent("[");
4403 bool hasChildValue = !childValues_.empty();
4406 const Value& childValue = value[index];
4407 writeCommentBeforeValue(childValue);
4409 writeWithIndent(childValues_[index]);
4411 if (!indented_) writeIndent();
4413 writeValue(childValue);
4416 if (++index == size) {
4417 writeCommentAfterValueOnSameLine(childValue);
4421 writeCommentAfterValueOnSameLine(childValue);
4424 writeWithIndent("]");
4425 } else // output on a single line
4427 assert(childValues_.size() == size);
4429 for (unsigned index = 0; index < size; ++index) {
4432 *document_ << childValues_[index];
4439 bool StyledStreamWriter::isMultineArray(const Value& value) {
4440 int size = value.size();
4441 bool isMultiLine = size * 3 >= rightMargin_;
4442 childValues_.clear();
4443 for (int index = 0; index < size && !isMultiLine; ++index) {
4444 const Value& childValue = value[index];
4446 isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
4447 childValue.size() > 0);
4449 if (!isMultiLine) // check if line length > max line length
4451 childValues_.reserve(size);
4452 addChildValues_ = true;
4453 int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
4454 for (int index = 0; index < size; ++index) {
4455 if (hasCommentForValue(value[index])) {
4458 writeValue(value[index]);
4459 lineLength += int(childValues_[index].length());
4461 addChildValues_ = false;
4462 isMultiLine = isMultiLine || lineLength >= rightMargin_;
4467 void StyledStreamWriter::pushValue(const std::string& value) {
4468 if (addChildValues_)
4469 childValues_.push_back(value);
4471 *document_ << value;
4474 void StyledStreamWriter::writeIndent() {
4475 // blep intended this to look at the so-far-written string
4476 // to determine whether we are already indented, but
4477 // with a stream we cannot do that. So we rely on some saved state.
4478 // The caller checks indented_.
4479 *document_ << '\n' << indentString_;
4482 void StyledStreamWriter::writeWithIndent(const std::string& value) {
4483 if (!indented_) writeIndent();
4484 *document_ << value;
4488 void StyledStreamWriter::indent() { indentString_ += indentation_; }
4490 void StyledStreamWriter::unindent() {
4491 assert(indentString_.size() >= indentation_.size());
4492 indentString_.resize(indentString_.size() - indentation_.size());
4495 void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
4496 if (!root.hasComment(commentBefore))
4499 if (!indented_) writeIndent();
4500 const std::string& comment = root.getComment(commentBefore);
4501 std::string::const_iterator iter = comment.begin();
4502 while (iter != comment.end()) {
4503 *document_ << *iter;
4504 if (*iter == '\n' &&
4505 (iter != comment.end() && *(iter + 1) == '/'))
4506 // writeIndent(); // would include newline
4507 *document_ << indentString_;
4513 void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
4514 if (root.hasComment(commentAfterOnSameLine))
4515 *document_ << ' ' << root.getComment(commentAfterOnSameLine);
4517 if (root.hasComment(commentAfter)) {
4519 *document_ << root.getComment(commentAfter);
4524 bool StyledStreamWriter::hasCommentForValue(const Value& value) {
4525 return value.hasComment(commentBefore) ||
4526 value.hasComment(commentAfterOnSameLine) ||
4527 value.hasComment(commentAfter);
4530 //////////////////////////
4531 // BuiltStyledStreamWriter
4533 /// Scoped enums are not available until C++11.
4534 struct CommentStyle {
4535 /// Decide whether to write comments.
4537 None, ///< Drop all comments.
4538 Most, ///< Recover odd behavior of previous versions (not implemented yet).
4539 All ///< Keep all comments.
4543 struct BuiltStyledStreamWriter : public StreamWriter
4545 BuiltStyledStreamWriter(
4546 std::string const& indentation,
4547 CommentStyle::Enum cs,
4548 std::string const& colonSymbol,
4549 std::string const& nullSymbol,
4550 std::string const& endingLineFeedSymbol,
4551 bool useSpecialFloats,
4552 unsigned int precision);
4553 virtual int write(Value const& root, std::ostream* sout);
4555 void writeValue(Value const& value);
4556 void writeArrayValue(Value const& value);
4557 bool isMultineArray(Value const& value);
4558 void pushValue(std::string const& value);
4560 void writeWithIndent(std::string const& value);
4563 void writeCommentBeforeValue(Value const& root);
4564 void writeCommentAfterValueOnSameLine(Value const& root);
4565 static bool hasCommentForValue(const Value& value);
4567 typedef std::vector<std::string> ChildValues;
4569 ChildValues childValues_;
4570 std::string indentString_;
4572 std::string indentation_;
4573 CommentStyle::Enum cs_;
4574 std::string colonSymbol_;
4575 std::string nullSymbol_;
4576 std::string endingLineFeedSymbol_;
4577 bool addChildValues_ : 1;
4579 bool useSpecialFloats_ : 1;
4580 unsigned int precision_;
4582 BuiltStyledStreamWriter::BuiltStyledStreamWriter(
4583 std::string const& indentation,
4584 CommentStyle::Enum cs,
4585 std::string const& colonSymbol,
4586 std::string const& nullSymbol,
4587 std::string const& endingLineFeedSymbol,
4588 bool useSpecialFloats,
4589 unsigned int precision)
4591 , indentation_(indentation)
4593 , colonSymbol_(colonSymbol)
4594 , nullSymbol_(nullSymbol)
4595 , endingLineFeedSymbol_(endingLineFeedSymbol)
4596 , addChildValues_(false)
4598 , useSpecialFloats_(useSpecialFloats)
4599 , precision_(precision)
4602 int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout)
4605 addChildValues_ = false;
4608 writeCommentBeforeValue(root);
4609 if (!indented_) writeIndent();
4612 writeCommentAfterValueOnSameLine(root);
4613 *sout_ << endingLineFeedSymbol_;
4617 void BuiltStyledStreamWriter::writeValue(Value const& value) {
4618 switch (value.type()) {
4620 pushValue(nullSymbol_);
4623 pushValue(valueToString(value.asLargestInt()));
4626 pushValue(valueToString(value.asLargestUInt()));
4629 pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
4633 // Is NULL is possible for value.string_?
4636 bool ok = value.getString(&str, &end);
4637 if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
4642 pushValue(valueToString(value.asBool()));
4645 writeArrayValue(value);
4648 Value::Members members(value.getMemberNames());
4649 if (members.empty())
4652 writeWithIndent("{");
4654 Value::Members::iterator it = members.begin();
4656 std::string const& name = *it;
4657 Value const& childValue = value[name];
4658 writeCommentBeforeValue(childValue);
4659 writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())));
4660 *sout_ << colonSymbol_;
4661 writeValue(childValue);
4662 if (++it == members.end()) {
4663 writeCommentAfterValueOnSameLine(childValue);
4667 writeCommentAfterValueOnSameLine(childValue);
4670 writeWithIndent("}");
4676 void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
4677 unsigned size = value.size();
4681 bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value);
4683 writeWithIndent("[");
4685 bool hasChildValue = !childValues_.empty();
4688 Value const& childValue = value[index];
4689 writeCommentBeforeValue(childValue);
4691 writeWithIndent(childValues_[index]);
4693 if (!indented_) writeIndent();
4695 writeValue(childValue);
4698 if (++index == size) {
4699 writeCommentAfterValueOnSameLine(childValue);
4703 writeCommentAfterValueOnSameLine(childValue);
4706 writeWithIndent("]");
4707 } else // output on a single line
4709 assert(childValues_.size() == size);
4711 if (!indentation_.empty()) *sout_ << " ";
4712 for (unsigned index = 0; index < size; ++index) {
4715 *sout_ << childValues_[index];
4717 if (!indentation_.empty()) *sout_ << " ";
4723 bool BuiltStyledStreamWriter::isMultineArray(Value const& value) {
4724 int size = value.size();
4725 bool isMultiLine = size * 3 >= rightMargin_;
4726 childValues_.clear();
4727 for (int index = 0; index < size && !isMultiLine; ++index) {
4728 Value const& childValue = value[index];
4730 isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
4731 childValue.size() > 0);
4733 if (!isMultiLine) // check if line length > max line length
4735 childValues_.reserve(size);
4736 addChildValues_ = true;
4737 int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
4738 for (int index = 0; index < size; ++index) {
4739 if (hasCommentForValue(value[index])) {
4742 writeValue(value[index]);
4743 lineLength += int(childValues_[index].length());
4745 addChildValues_ = false;
4746 isMultiLine = isMultiLine || lineLength >= rightMargin_;
4751 void BuiltStyledStreamWriter::pushValue(std::string const& value) {
4752 if (addChildValues_)
4753 childValues_.push_back(value);
4758 void BuiltStyledStreamWriter::writeIndent() {
4759 // blep intended this to look at the so-far-written string
4760 // to determine whether we are already indented, but
4761 // with a stream we cannot do that. So we rely on some saved state.
4762 // The caller checks indented_.
4764 if (!indentation_.empty()) {
4765 // In this case, drop newlines too.
4766 *sout_ << '\n' << indentString_;
4770 void BuiltStyledStreamWriter::writeWithIndent(std::string const& value) {
4771 if (!indented_) writeIndent();
4776 void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
4778 void BuiltStyledStreamWriter::unindent() {
4779 assert(indentString_.size() >= indentation_.size());
4780 indentString_.resize(indentString_.size() - indentation_.size());
4783 void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
4784 if (cs_ == CommentStyle::None) return;
4785 if (!root.hasComment(commentBefore))
4788 if (!indented_) writeIndent();
4789 const std::string& comment = root.getComment(commentBefore);
4790 std::string::const_iterator iter = comment.begin();
4791 while (iter != comment.end()) {
4793 if (*iter == '\n' &&
4794 (iter != comment.end() && *(iter + 1) == '/'))
4795 // writeIndent(); // would write extra newline
4796 *sout_ << indentString_;
4802 void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {
4803 if (cs_ == CommentStyle::None) return;
4804 if (root.hasComment(commentAfterOnSameLine))
4805 *sout_ << " " + root.getComment(commentAfterOnSameLine);
4807 if (root.hasComment(commentAfter)) {
4809 *sout_ << root.getComment(commentAfter);
4814 bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
4815 return value.hasComment(commentBefore) ||
4816 value.hasComment(commentAfterOnSameLine) ||
4817 value.hasComment(commentAfter);
4823 StreamWriter::StreamWriter()
4827 StreamWriter::~StreamWriter()
4830 StreamWriter::Factory::~Factory()
4832 StreamWriterBuilder::StreamWriterBuilder()
4834 setDefaults(&settings_);
4836 StreamWriterBuilder::~StreamWriterBuilder()
4838 StreamWriter* StreamWriterBuilder::newStreamWriter() const
4840 std::string indentation = settings_["indentation"].asString();
4841 std::string cs_str = settings_["commentStyle"].asString();
4842 bool eyc = settings_["enableYAMLCompatibility"].asBool();
4843 bool dnp = settings_["dropNullPlaceholders"].asBool();
4844 bool usf = settings_["useSpecialFloats"].asBool();
4845 unsigned int pre = settings_["precision"].asUInt();
4846 CommentStyle::Enum cs = CommentStyle::All;
4847 if (cs_str == "All") {
4848 cs = CommentStyle::All;
4849 } else if (cs_str == "None") {
4850 cs = CommentStyle::None;
4852 throwRuntimeError("commentStyle must be 'All' or 'None'");
4854 std::string colonSymbol = " : ";
4857 } else if (indentation.empty()) {
4860 std::string nullSymbol = "null";
4864 if (pre > 17) pre = 17;
4865 std::string endingLineFeedSymbol = "";
4866 return new BuiltStyledStreamWriter(
4868 colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
4870 static void getValidWriterKeys(std::set<std::string>* valid_keys)
4872 valid_keys->clear();
4873 valid_keys->insert("indentation");
4874 valid_keys->insert("commentStyle");
4875 valid_keys->insert("enableYAMLCompatibility");
4876 valid_keys->insert("dropNullPlaceholders");
4877 valid_keys->insert("useSpecialFloats");
4878 valid_keys->insert("precision");
4880 bool StreamWriterBuilder::validate(Json::Value* invalid) const
4882 Json::Value my_invalid;
4883 if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
4884 Json::Value& inv = *invalid;
4885 std::set<std::string> valid_keys;
4886 getValidWriterKeys(&valid_keys);
4887 Value::Members keys = settings_.getMemberNames();
4888 size_t n = keys.size();
4889 for (size_t i = 0; i < n; ++i) {
4890 std::string const& key = keys[i];
4891 if (valid_keys.find(key) == valid_keys.end()) {
4892 inv[key] = settings_[key];
4895 return 0u == inv.size();
4897 Value& StreamWriterBuilder::operator[](std::string key)
4899 return settings_[key];
4902 void StreamWriterBuilder::setDefaults(Json::Value* settings)
4904 //! [StreamWriterBuilderDefaults]
4905 (*settings)["commentStyle"] = "All";
4906 (*settings)["indentation"] = "\t";
4907 (*settings)["enableYAMLCompatibility"] = false;
4908 (*settings)["dropNullPlaceholders"] = false;
4909 (*settings)["useSpecialFloats"] = false;
4910 (*settings)["precision"] = 17;
4911 //! [StreamWriterBuilderDefaults]
4914 std::string writeString(StreamWriter::Factory const& builder, Value const& root) {
4915 std::ostringstream sout;
4916 StreamWriterPtr const writer(builder.newStreamWriter());
4917 writer->write(root, &sout);
4921 std::ostream& operator<<(std::ostream& sout, Value const& root) {
4922 StreamWriterBuilder builder;
4923 StreamWriterPtr const writer(builder.newStreamWriter());
4924 writer->write(root, &sout);
4930 // //////////////////////////////////////////////////////////////////////
4931 // End of content of file: src/lib_json/json_writer.cpp
4932 // //////////////////////////////////////////////////////////////////////