1 /// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/).
2 /// It is intended to be used with #include "json/json.h"
4 // //////////////////////////////////////////////////////////////////////
5 // Beginning of content of file: LICENSE
6 // //////////////////////////////////////////////////////////////////////
9 The JsonCpp library's source code, including accompanying documentation,
10 tests and demonstration applications, are licensed under the following
13 Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
14 jurisdictions which recognize such a disclaimer. In such jurisdictions,
15 this software is released into the Public Domain.
17 In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
18 2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
19 The JsonCpp Authors, and is released under the terms of the MIT License (see below).
21 In jurisdictions which recognize Public Domain property, the user of this
22 software may choose to accept it either as 1) Public Domain, 2) under the
23 conditions of the MIT License (see below), or 3) under the terms of dual
24 Public Domain/MIT License conditions described here, as they choose.
26 The MIT License is about as close to Public Domain as a license can get, and is
27 described in clear, concise terms at:
29 http://en.wikipedia.org/wiki/MIT_License
31 The full text of the MIT License follows:
33 ========================================================================
34 Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
36 Permission is hereby granted, free of charge, to any person
37 obtaining a copy of this software and associated documentation
38 files (the "Software"), to deal in the Software without
39 restriction, including without limitation the rights to use, copy,
40 modify, merge, publish, distribute, sublicense, and/or sell copies
41 of the Software, and to permit persons to whom the Software is
42 furnished to do so, subject to the following conditions:
44 The above copyright notice and this permission notice shall be
45 included in all copies or substantial portions of the Software.
47 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
48 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
49 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
50 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
51 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
52 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
53 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
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 and The JsonCpp Authors
88 // Distributed under MIT license, or public domain if desired and
89 // recognized in your jurisdiction.
90 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
92 #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
93 #define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
96 // Also support old flag NO_LOCALE_SUPPORT
97 #ifdef NO_LOCALE_SUPPORT
98 #define JSONCPP_NO_LOCALE_SUPPORT
101 #ifndef JSONCPP_NO_LOCALE_SUPPORT
105 /* This header provides common string manipulation support, such as UTF-8,
106 * portable conversion from/to string...
108 * It is an internal header that must not be exposed.
112 static char getDecimalPoint() {
113 #ifdef JSONCPP_NO_LOCALE_SUPPORT
116 struct lconv
* lc
= localeconv();
117 return lc
? *(lc
->decimal_point
) : '\0';
121 /// Converts a unicode code-point to UTF-8.
122 static inline JSONCPP_STRING
codePointToUTF8(unsigned int cp
) {
123 JSONCPP_STRING result
;
125 // based on description from http://en.wikipedia.org/wiki/UTF-8
129 result
[0] = static_cast<char>(cp
);
130 } else if (cp
<= 0x7FF) {
132 result
[1] = static_cast<char>(0x80 | (0x3f & cp
));
133 result
[0] = static_cast<char>(0xC0 | (0x1f & (cp
>> 6)));
134 } else if (cp
<= 0xFFFF) {
136 result
[2] = static_cast<char>(0x80 | (0x3f & cp
));
137 result
[1] = static_cast<char>(0x80 | (0x3f & (cp
>> 6)));
138 result
[0] = static_cast<char>(0xE0 | (0xf & (cp
>> 12)));
139 } else if (cp
<= 0x10FFFF) {
141 result
[3] = static_cast<char>(0x80 | (0x3f & cp
));
142 result
[2] = static_cast<char>(0x80 | (0x3f & (cp
>> 6)));
143 result
[1] = static_cast<char>(0x80 | (0x3f & (cp
>> 12)));
144 result
[0] = static_cast<char>(0xF0 | (0x7 & (cp
>> 18)));
151 /// Constant that specify the size of the buffer that must be passed to
153 uintToStringBufferSize
= 3 * sizeof(LargestUInt
) + 1
156 // Defines a char buffer for use with uintToString().
157 typedef char UIntToStringBuffer
[uintToStringBufferSize
];
159 /** Converts an unsigned integer to string.
160 * @param value Unsigned integer to convert to string
161 * @param current Input/Output string buffer.
162 * Must have at least uintToStringBufferSize chars free.
164 static inline void uintToString(LargestUInt value
, char*& current
) {
167 *--current
= static_cast<char>(value
% 10U + static_cast<unsigned>('0'));
169 } while (value
!= 0);
172 /** Change ',' to '.' everywhere in buffer.
174 * We had a sophisticated way, but it did not work in WinCE.
175 * @see https://github.com/open-source-parsers/jsoncpp/pull/9
177 static inline void fixNumericLocale(char* begin
, char* end
) {
178 while (begin
< end
) {
186 static inline void fixNumericLocaleInput(char* begin
, char* end
) {
187 char decimalPoint
= getDecimalPoint();
188 if (decimalPoint
!= '\0' && decimalPoint
!= '.') {
189 while (begin
< end
) {
191 *begin
= decimalPoint
;
198 } // namespace Json {
200 #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
202 // //////////////////////////////////////////////////////////////////////
203 // End of content of file: src/lib_json/json_tool.h
204 // //////////////////////////////////////////////////////////////////////
211 // //////////////////////////////////////////////////////////////////////
212 // Beginning of content of file: src/lib_json/json_reader.cpp
213 // //////////////////////////////////////////////////////////////////////
215 // Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors
216 // Copyright (C) 2016 InfoTeCS JSC. All rights reserved.
217 // Distributed under MIT license, or public domain if desired and
218 // recognized in your jurisdiction.
219 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
221 #if !defined(JSON_IS_AMALGAMATION)
222 #include <json/assertions.h>
223 #include <json/reader.h>
224 #include <json/value.h>
225 #include "json_tool.h"
226 #endif // if !defined(JSON_IS_AMALGAMATION)
237 #if defined(_MSC_VER)
238 #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
239 #define snprintf sprintf_s
240 #elif _MSC_VER >= 1900 // VC++ 14.0 and above
241 #define snprintf std::snprintf
243 #define snprintf _snprintf
245 #elif defined(__ANDROID__) || defined(__QNXNTO__)
246 #define snprintf snprintf
247 #elif __cplusplus >= 201103L
248 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
249 #define snprintf std::snprintf
253 #if defined(__QNXNTO__)
254 #define sscanf std::sscanf
257 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
258 // Disable warning about strdup being deprecated.
259 #pragma warning(disable : 4996)
262 // Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile time to change the stack limit
263 #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
264 #define JSONCPP_DEPRECATED_STACK_LIMIT 1000
267 static size_t const stackLimit_g
= JSONCPP_DEPRECATED_STACK_LIMIT
; // see readValue()
271 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
272 typedef std::unique_ptr
<CharReader
> CharReaderPtr
;
274 typedef std::auto_ptr
<CharReader
> CharReaderPtr
;
277 // Implementation of class Features
278 // ////////////////////////////////
281 : allowComments_(true), strictRoot_(false),
282 allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
284 Features
Features::all() { return Features(); }
286 Features
Features::strictMode() {
288 features
.allowComments_
= false;
289 features
.strictRoot_
= true;
290 features
.allowDroppedNullPlaceholders_
= false;
291 features
.allowNumericKeys_
= false;
295 // Implementation of class Reader
296 // ////////////////////////////////
298 bool Reader::containsNewLine(Reader::Location begin
, Reader::Location end
) {
299 for (; begin
< end
; ++begin
)
300 if (*begin
== '\n' || *begin
== '\r')
306 // //////////////////////////////////////////////////////////////////
309 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
310 lastValue_(), commentsBefore_(), features_(Features::all()),
311 collectComments_() {}
313 Reader::Reader(const Features
& features
)
314 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
315 lastValue_(), commentsBefore_(), features_(features
), collectComments_() {
319 Reader::parse(const std::string
& document
, Value
& root
, bool collectComments
) {
320 document_
.assign(document
.begin(), document
.end());
321 const char* begin
= document_
.c_str();
322 const char* end
= begin
+ document_
.length();
323 return parse(begin
, end
, root
, collectComments
);
326 bool Reader::parse(std::istream
& sin
, Value
& root
, bool collectComments
) {
327 // std::istream_iterator<char> begin(sin);
328 // std::istream_iterator<char> end;
329 // Those would allow streamed input from a file, if parse() were a
330 // template function.
332 // Since JSONCPP_STRING is reference-counted, this at least does not
333 // create an extra copy.
335 std::getline(sin
, doc
, (char)EOF
);
336 return parse(doc
.data(), doc
.data() + doc
.size(), root
, collectComments
);
339 bool Reader::parse(const char* beginDoc
,
342 bool collectComments
) {
343 if (!features_
.allowComments_
) {
344 collectComments
= false;
349 collectComments_
= collectComments
;
353 commentsBefore_
.clear();
355 while (!nodes_
.empty())
359 bool successful
= readValue();
361 skipCommentTokens(token
);
362 if (collectComments_
&& !commentsBefore_
.empty())
363 root
.setComment(commentsBefore_
, commentAfter
);
364 if (features_
.strictRoot_
) {
365 if (!root
.isArray() && !root
.isObject()) {
366 // Set error location to start of doc, ideally should be first token found
368 token
.type_
= tokenError
;
369 token
.start_
= beginDoc
;
372 "A valid JSON document must be either an array or an object value.",
380 bool Reader::readValue() {
381 // readValue() may call itself only if it calls readObject() or ReadArray().
382 // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue().
383 // parse() executes one nodes_.push(), so > instead of >=.
384 if (nodes_
.size() > stackLimit_g
) throwRuntimeError("Exceeded stackLimit in readValue().");
387 skipCommentTokens(token
);
388 bool successful
= true;
390 if (collectComments_
&& !commentsBefore_
.empty()) {
391 currentValue().setComment(commentsBefore_
, commentBefore
);
392 commentsBefore_
.clear();
395 switch (token
.type_
) {
396 case tokenObjectBegin
:
397 successful
= readObject(token
);
398 currentValue().setOffsetLimit(current_
- begin_
);
400 case tokenArrayBegin
:
401 successful
= readArray(token
);
402 currentValue().setOffsetLimit(current_
- begin_
);
405 successful
= decodeNumber(token
);
408 successful
= decodeString(token
);
413 currentValue().swapPayload(v
);
414 currentValue().setOffsetStart(token
.start_
- begin_
);
415 currentValue().setOffsetLimit(token
.end_
- begin_
);
421 currentValue().swapPayload(v
);
422 currentValue().setOffsetStart(token
.start_
- begin_
);
423 currentValue().setOffsetLimit(token
.end_
- begin_
);
429 currentValue().swapPayload(v
);
430 currentValue().setOffsetStart(token
.start_
- begin_
);
431 currentValue().setOffsetLimit(token
.end_
- begin_
);
434 case tokenArraySeparator
:
437 if (features_
.allowDroppedNullPlaceholders_
) {
438 // "Un-read" the current token and mark the current value as a null
442 currentValue().swapPayload(v
);
443 currentValue().setOffsetStart(current_
- begin_
- 1);
444 currentValue().setOffsetLimit(current_
- begin_
);
446 } // Else, fall through...
448 currentValue().setOffsetStart(token
.start_
- begin_
);
449 currentValue().setOffsetLimit(token
.end_
- begin_
);
450 return addError("Syntax error: value, object or array expected.", token
);
453 if (collectComments_
) {
454 lastValueEnd_
= current_
;
455 lastValue_
= ¤tValue();
461 void Reader::skipCommentTokens(Token
& token
) {
462 if (features_
.allowComments_
) {
465 } while (token
.type_
== tokenComment
);
471 bool Reader::readToken(Token
& token
) {
473 token
.start_
= current_
;
474 Char c
= getNextChar();
478 token
.type_
= tokenObjectBegin
;
481 token
.type_
= tokenObjectEnd
;
484 token
.type_
= tokenArrayBegin
;
487 token
.type_
= tokenArrayEnd
;
490 token
.type_
= tokenString
;
494 token
.type_
= tokenComment
;
508 token
.type_
= tokenNumber
;
512 token
.type_
= tokenTrue
;
513 ok
= match("rue", 3);
516 token
.type_
= tokenFalse
;
517 ok
= match("alse", 4);
520 token
.type_
= tokenNull
;
521 ok
= match("ull", 3);
524 token
.type_
= tokenArraySeparator
;
527 token
.type_
= tokenMemberSeparator
;
530 token
.type_
= tokenEndOfStream
;
537 token
.type_
= tokenError
;
538 token
.end_
= current_
;
542 void Reader::skipSpaces() {
543 while (current_
!= end_
) {
545 if (c
== ' ' || c
== '\t' || c
== '\r' || c
== '\n')
552 bool Reader::match(Location pattern
, int patternLength
) {
553 if (end_
- current_
< patternLength
)
555 int index
= patternLength
;
557 if (current_
[index
] != pattern
[index
])
559 current_
+= patternLength
;
563 bool Reader::readComment() {
564 Location commentBegin
= current_
- 1;
565 Char c
= getNextChar();
566 bool successful
= false;
568 successful
= readCStyleComment();
570 successful
= readCppStyleComment();
574 if (collectComments_
) {
575 CommentPlacement placement
= commentBefore
;
576 if (lastValueEnd_
&& !containsNewLine(lastValueEnd_
, commentBegin
)) {
577 if (c
!= '*' || !containsNewLine(commentBegin
, current_
))
578 placement
= commentAfterOnSameLine
;
581 addComment(commentBegin
, current_
, placement
);
586 JSONCPP_STRING
Reader::normalizeEOL(Reader::Location begin
, Reader::Location end
) {
587 JSONCPP_STRING normalized
;
588 normalized
.reserve(static_cast<size_t>(end
- begin
));
589 Reader::Location current
= begin
;
590 while (current
!= end
) {
593 if (current
!= end
&& *current
== '\n')
606 Reader::addComment(Location begin
, Location end
, CommentPlacement placement
) {
607 assert(collectComments_
);
608 const JSONCPP_STRING
& normalized
= normalizeEOL(begin
, end
);
609 if (placement
== commentAfterOnSameLine
) {
610 assert(lastValue_
!= 0);
611 lastValue_
->setComment(normalized
, placement
);
613 commentsBefore_
+= normalized
;
617 bool Reader::readCStyleComment() {
618 while ((current_
+ 1) < end_
) {
619 Char c
= getNextChar();
620 if (c
== '*' && *current_
== '/')
623 return getNextChar() == '/';
626 bool Reader::readCppStyleComment() {
627 while (current_
!= end_
) {
628 Char c
= getNextChar();
632 // Consume DOS EOL. It will be normalized in addComment.
633 if (current_
!= end_
&& *current_
== '\n')
635 // Break on Moc OS 9 EOL.
642 void Reader::readNumber() {
643 const char *p
= current_
;
644 char c
= '0'; // stopgap for already consumed character
646 while (c
>= '0' && c
<= '9')
647 c
= (current_
= p
) < end_
? *p
++ : '\0';
650 c
= (current_
= p
) < end_
? *p
++ : '\0';
651 while (c
>= '0' && c
<= '9')
652 c
= (current_
= p
) < end_
? *p
++ : '\0';
655 if (c
== 'e' || c
== 'E') {
656 c
= (current_
= p
) < end_
? *p
++ : '\0';
657 if (c
== '+' || c
== '-')
658 c
= (current_
= p
) < end_
? *p
++ : '\0';
659 while (c
>= '0' && c
<= '9')
660 c
= (current_
= p
) < end_
? *p
++ : '\0';
664 bool Reader::readString() {
666 while (current_
!= end_
) {
676 bool Reader::readObject(Token
& tokenStart
) {
679 Value
init(objectValue
);
680 currentValue().swapPayload(init
);
681 currentValue().setOffsetStart(tokenStart
.start_
- begin_
);
682 while (readToken(tokenName
)) {
683 bool initialTokenOk
= true;
684 while (tokenName
.type_
== tokenComment
&& initialTokenOk
)
685 initialTokenOk
= readToken(tokenName
);
688 if (tokenName
.type_
== tokenObjectEnd
&& name
.empty()) // empty object
691 if (tokenName
.type_
== tokenString
) {
692 if (!decodeString(tokenName
, name
))
693 return recoverFromError(tokenObjectEnd
);
694 } else if (tokenName
.type_
== tokenNumber
&& features_
.allowNumericKeys_
) {
696 if (!decodeNumber(tokenName
, numberName
))
697 return recoverFromError(tokenObjectEnd
);
698 name
= JSONCPP_STRING(numberName
.asCString());
704 if (!readToken(colon
) || colon
.type_
!= tokenMemberSeparator
) {
705 return addErrorAndRecover(
706 "Missing ':' after object member name", colon
, tokenObjectEnd
);
708 Value
& value
= currentValue()[name
];
710 bool ok
= readValue();
712 if (!ok
) // error already set
713 return recoverFromError(tokenObjectEnd
);
716 if (!readToken(comma
) ||
717 (comma
.type_
!= tokenObjectEnd
&& comma
.type_
!= tokenArraySeparator
&&
718 comma
.type_
!= tokenComment
)) {
719 return addErrorAndRecover(
720 "Missing ',' or '}' in object declaration", comma
, tokenObjectEnd
);
722 bool finalizeTokenOk
= true;
723 while (comma
.type_
== tokenComment
&& finalizeTokenOk
)
724 finalizeTokenOk
= readToken(comma
);
725 if (comma
.type_
== tokenObjectEnd
)
728 return addErrorAndRecover(
729 "Missing '}' or object member name", tokenName
, tokenObjectEnd
);
732 bool Reader::readArray(Token
& tokenStart
) {
733 Value
init(arrayValue
);
734 currentValue().swapPayload(init
);
735 currentValue().setOffsetStart(tokenStart
.start_
- begin_
);
737 if (current_
!= end_
&& *current_
== ']') // empty array
745 Value
& value
= currentValue()[index
++];
747 bool ok
= readValue();
749 if (!ok
) // error already set
750 return recoverFromError(tokenArrayEnd
);
753 // Accept Comment after last item in the array.
754 ok
= readToken(token
);
755 while (token
.type_
== tokenComment
&& ok
) {
756 ok
= readToken(token
);
759 (token
.type_
!= tokenArraySeparator
&& token
.type_
!= tokenArrayEnd
);
760 if (!ok
|| badTokenType
) {
761 return addErrorAndRecover(
762 "Missing ',' or ']' in array declaration", token
, tokenArrayEnd
);
764 if (token
.type_
== tokenArrayEnd
)
770 bool Reader::decodeNumber(Token
& token
) {
772 if (!decodeNumber(token
, decoded
))
774 currentValue().swapPayload(decoded
);
775 currentValue().setOffsetStart(token
.start_
- begin_
);
776 currentValue().setOffsetLimit(token
.end_
- begin_
);
780 bool Reader::decodeNumber(Token
& token
, Value
& decoded
) {
781 // Attempts to parse the number as an integer. If the number is
782 // larger than the maximum supported value of an integer then
783 // we decode the number as a double.
784 Location current
= token
.start_
;
785 bool isNegative
= *current
== '-';
788 // TODO: Help the compiler do the div and mod at compile time or get rid of them.
789 Value::LargestUInt maxIntegerValue
=
790 isNegative
? Value::LargestUInt(Value::maxLargestInt
) + 1
791 : Value::maxLargestUInt
;
792 Value::LargestUInt threshold
= maxIntegerValue
/ 10;
793 Value::LargestUInt value
= 0;
794 while (current
< token
.end_
) {
796 if (c
< '0' || c
> '9')
797 return decodeDouble(token
, decoded
);
798 Value::UInt
digit(static_cast<Value::UInt
>(c
- '0'));
799 if (value
>= threshold
) {
800 // We've hit or exceeded the max value divided by 10 (rounded down). If
801 // a) we've only just touched the limit, b) this is the last digit, and
802 // c) it's small enough to fit in that rounding delta, we're okay.
803 // Otherwise treat this number as a double to avoid overflow.
804 if (value
> threshold
|| current
!= token
.end_
||
805 digit
> maxIntegerValue
% 10) {
806 return decodeDouble(token
, decoded
);
809 value
= value
* 10 + digit
;
811 if (isNegative
&& value
== maxIntegerValue
)
812 decoded
= Value::minLargestInt
;
814 decoded
= -Value::LargestInt(value
);
815 else if (value
<= Value::LargestUInt(Value::maxInt
))
816 decoded
= Value::LargestInt(value
);
822 bool Reader::decodeDouble(Token
& token
) {
824 if (!decodeDouble(token
, decoded
))
826 currentValue().swapPayload(decoded
);
827 currentValue().setOffsetStart(token
.start_
- begin_
);
828 currentValue().setOffsetLimit(token
.end_
- begin_
);
832 bool Reader::decodeDouble(Token
& token
, Value
& decoded
) {
834 JSONCPP_STRING
buffer(token
.start_
, token
.end_
);
835 JSONCPP_ISTRINGSTREAM
is(buffer
);
837 return addError("'" + JSONCPP_STRING(token
.start_
, token
.end_
) +
838 "' is not a number.",
844 bool Reader::decodeString(Token
& token
) {
845 JSONCPP_STRING decoded_string
;
846 if (!decodeString(token
, decoded_string
))
848 Value
decoded(decoded_string
);
849 currentValue().swapPayload(decoded
);
850 currentValue().setOffsetStart(token
.start_
- begin_
);
851 currentValue().setOffsetLimit(token
.end_
- begin_
);
855 bool Reader::decodeString(Token
& token
, JSONCPP_STRING
& decoded
) {
856 decoded
.reserve(static_cast<size_t>(token
.end_
- token
.start_
- 2));
857 Location current
= token
.start_
+ 1; // skip '"'
858 Location end
= token
.end_
- 1; // do not include '"'
859 while (current
!= end
) {
863 else if (c
== '\\') {
865 return addError("Empty escape sequence in string", token
, current
);
866 Char escape
= *current
++;
893 unsigned int unicode
;
894 if (!decodeUnicodeCodePoint(token
, current
, end
, unicode
))
896 decoded
+= codePointToUTF8(unicode
);
899 return addError("Bad escape sequence in string", token
, current
);
908 bool Reader::decodeUnicodeCodePoint(Token
& token
,
911 unsigned int& unicode
) {
913 if (!decodeUnicodeEscapeSequence(token
, current
, end
, unicode
))
915 if (unicode
>= 0xD800 && unicode
<= 0xDBFF) {
917 if (end
- current
< 6)
919 "additional six characters expected to parse unicode surrogate pair.",
922 unsigned int surrogatePair
;
923 if (*(current
++) == '\\' && *(current
++) == 'u') {
924 if (decodeUnicodeEscapeSequence(token
, current
, end
, surrogatePair
)) {
925 unicode
= 0x10000 + ((unicode
& 0x3FF) << 10) + (surrogatePair
& 0x3FF);
929 return addError("expecting another \\u token to begin the second half of "
930 "a unicode surrogate pair",
937 bool Reader::decodeUnicodeEscapeSequence(Token
& token
,
940 unsigned int& ret_unicode
) {
941 if (end
- current
< 4)
943 "Bad unicode escape sequence in string: four digits expected.",
947 for (int index
= 0; index
< 4; ++index
) {
950 if (c
>= '0' && c
<= '9')
952 else if (c
>= 'a' && c
<= 'f')
953 unicode
+= c
- 'a' + 10;
954 else if (c
>= 'A' && c
<= 'F')
955 unicode
+= c
- 'A' + 10;
958 "Bad unicode escape sequence in string: hexadecimal digit expected.",
962 ret_unicode
= static_cast<unsigned int>(unicode
);
967 Reader::addError(const JSONCPP_STRING
& message
, Token
& token
, Location extra
) {
970 info
.message_
= message
;
972 errors_
.push_back(info
);
976 bool Reader::recoverFromError(TokenType skipUntilToken
) {
977 size_t const errorCount
= errors_
.size();
980 if (!readToken(skip
))
981 errors_
.resize(errorCount
); // discard errors caused by recovery
982 if (skip
.type_
== skipUntilToken
|| skip
.type_
== tokenEndOfStream
)
985 errors_
.resize(errorCount
);
989 bool Reader::addErrorAndRecover(const JSONCPP_STRING
& message
,
991 TokenType skipUntilToken
) {
992 addError(message
, token
);
993 return recoverFromError(skipUntilToken
);
996 Value
& Reader::currentValue() { return *(nodes_
.top()); }
998 Reader::Char
Reader::getNextChar() {
999 if (current_
== end_
)
1004 void Reader::getLocationLineAndColumn(Location location
,
1006 int& column
) const {
1007 Location current
= begin_
;
1008 Location lastLineStart
= current
;
1010 while (current
< location
&& current
!= end_
) {
1011 Char c
= *current
++;
1013 if (*current
== '\n')
1015 lastLineStart
= current
;
1017 } else if (c
== '\n') {
1018 lastLineStart
= current
;
1022 // column & line start at 1
1023 column
= int(location
- lastLineStart
) + 1;
1027 JSONCPP_STRING
Reader::getLocationLineAndColumn(Location location
) const {
1029 getLocationLineAndColumn(location
, line
, column
);
1030 char buffer
[18 + 16 + 16 + 1];
1031 snprintf(buffer
, sizeof(buffer
), "Line %d, Column %d", line
, column
);
1035 // Deprecated. Preserved for backward compatibility
1036 JSONCPP_STRING
Reader::getFormatedErrorMessages() const {
1037 return getFormattedErrorMessages();
1040 JSONCPP_STRING
Reader::getFormattedErrorMessages() const {
1041 JSONCPP_STRING formattedMessage
;
1042 for (Errors::const_iterator itError
= errors_
.begin();
1043 itError
!= errors_
.end();
1045 const ErrorInfo
& error
= *itError
;
1047 "* " + getLocationLineAndColumn(error
.token_
.start_
) + "\n";
1048 formattedMessage
+= " " + error
.message_
+ "\n";
1051 "See " + getLocationLineAndColumn(error
.extra_
) + " for detail.\n";
1053 return formattedMessage
;
1056 std::vector
<Reader::StructuredError
> Reader::getStructuredErrors() const {
1057 std::vector
<Reader::StructuredError
> allErrors
;
1058 for (Errors::const_iterator itError
= errors_
.begin();
1059 itError
!= errors_
.end();
1061 const ErrorInfo
& error
= *itError
;
1062 Reader::StructuredError structured
;
1063 structured
.offset_start
= error
.token_
.start_
- begin_
;
1064 structured
.offset_limit
= error
.token_
.end_
- begin_
;
1065 structured
.message
= error
.message_
;
1066 allErrors
.push_back(structured
);
1071 bool Reader::pushError(const Value
& value
, const JSONCPP_STRING
& message
) {
1072 ptrdiff_t const length
= end_
- begin_
;
1073 if(value
.getOffsetStart() > length
1074 || value
.getOffsetLimit() > length
)
1077 token
.type_
= tokenError
;
1078 token
.start_
= begin_
+ value
.getOffsetStart();
1079 token
.end_
= end_
+ value
.getOffsetLimit();
1081 info
.token_
= token
;
1082 info
.message_
= message
;
1084 errors_
.push_back(info
);
1088 bool Reader::pushError(const Value
& value
, const JSONCPP_STRING
& message
, const Value
& extra
) {
1089 ptrdiff_t const length
= end_
- begin_
;
1090 if(value
.getOffsetStart() > length
1091 || value
.getOffsetLimit() > length
1092 || extra
.getOffsetLimit() > length
)
1095 token
.type_
= tokenError
;
1096 token
.start_
= begin_
+ value
.getOffsetStart();
1097 token
.end_
= begin_
+ value
.getOffsetLimit();
1099 info
.token_
= token
;
1100 info
.message_
= message
;
1101 info
.extra_
= begin_
+ extra
.getOffsetStart();
1102 errors_
.push_back(info
);
1106 bool Reader::good() const {
1107 return !errors_
.size();
1110 // exact copy of Features
1113 static OurFeatures
all();
1114 bool allowComments_
;
1116 bool allowDroppedNullPlaceholders_
;
1117 bool allowNumericKeys_
;
1118 bool allowSingleQuotes_
;
1120 bool rejectDupKeys_
;
1121 bool allowSpecialFloats_
;
1125 // exact copy of Implementation of class Features
1126 // ////////////////////////////////
1128 OurFeatures
OurFeatures::all() { return OurFeatures(); }
1130 // Implementation of class Reader
1131 // ////////////////////////////////
1133 // exact copy of Reader, renamed to OurReader
1137 typedef const Char
* Location
;
1138 struct StructuredError
{
1139 ptrdiff_t offset_start
;
1140 ptrdiff_t offset_limit
;
1141 JSONCPP_STRING message
;
1144 OurReader(OurFeatures
const& features
);
1145 bool parse(const char* beginDoc
,
1148 bool collectComments
= true);
1149 JSONCPP_STRING
getFormattedErrorMessages() const;
1150 std::vector
<StructuredError
> getStructuredErrors() const;
1151 bool pushError(const Value
& value
, const JSONCPP_STRING
& message
);
1152 bool pushError(const Value
& value
, const JSONCPP_STRING
& message
, const Value
& extra
);
1156 OurReader(OurReader
const&); // no impl
1157 void operator=(OurReader
const&); // no impl
1160 tokenEndOfStream
= 0,
1173 tokenArraySeparator
,
1174 tokenMemberSeparator
,
1189 JSONCPP_STRING message_
;
1193 typedef std::deque
<ErrorInfo
> Errors
;
1195 bool readToken(Token
& token
);
1197 bool match(Location pattern
, int patternLength
);
1199 bool readCStyleComment();
1200 bool readCppStyleComment();
1202 bool readStringSingleQuote();
1203 bool readNumber(bool checkInf
);
1205 bool readObject(Token
& token
);
1206 bool readArray(Token
& token
);
1207 bool decodeNumber(Token
& token
);
1208 bool decodeNumber(Token
& token
, Value
& decoded
);
1209 bool decodeString(Token
& token
);
1210 bool decodeString(Token
& token
, JSONCPP_STRING
& decoded
);
1211 bool decodeDouble(Token
& token
);
1212 bool decodeDouble(Token
& token
, Value
& decoded
);
1213 bool decodeUnicodeCodePoint(Token
& token
,
1216 unsigned int& unicode
);
1217 bool decodeUnicodeEscapeSequence(Token
& token
,
1220 unsigned int& unicode
);
1221 bool addError(const JSONCPP_STRING
& message
, Token
& token
, Location extra
= 0);
1222 bool recoverFromError(TokenType skipUntilToken
);
1223 bool addErrorAndRecover(const JSONCPP_STRING
& message
,
1225 TokenType skipUntilToken
);
1226 void skipUntilSpace();
1227 Value
& currentValue();
1230 getLocationLineAndColumn(Location location
, int& line
, int& column
) const;
1231 JSONCPP_STRING
getLocationLineAndColumn(Location location
) const;
1232 void addComment(Location begin
, Location end
, CommentPlacement placement
);
1233 void skipCommentTokens(Token
& token
);
1235 static JSONCPP_STRING
normalizeEOL(Location begin
, Location end
);
1236 static bool containsNewLine(Location begin
, Location end
);
1238 typedef std::stack
<Value
*> Nodes
;
1241 JSONCPP_STRING document_
;
1245 Location lastValueEnd_
;
1247 JSONCPP_STRING commentsBefore_
;
1249 OurFeatures
const features_
;
1250 bool collectComments_
;
1253 // complete copy of Read impl, for OurReader
1255 bool OurReader::containsNewLine(OurReader::Location begin
, OurReader::Location end
) {
1256 for (; begin
< end
; ++begin
)
1257 if (*begin
== '\n' || *begin
== '\r')
1262 OurReader::OurReader(OurFeatures
const& features
)
1263 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
1264 lastValue_(), commentsBefore_(),
1265 features_(features
), collectComments_() {
1268 bool OurReader::parse(const char* beginDoc
,
1271 bool collectComments
) {
1272 if (!features_
.allowComments_
) {
1273 collectComments
= false;
1278 collectComments_
= collectComments
;
1282 commentsBefore_
.clear();
1284 while (!nodes_
.empty())
1288 bool successful
= readValue();
1290 skipCommentTokens(token
);
1291 if (features_
.failIfExtra_
) {
1292 if ((features_
.strictRoot_
|| token
.type_
!= tokenError
) && token
.type_
!= tokenEndOfStream
) {
1293 addError("Extra non-whitespace after JSON value.", token
);
1297 if (collectComments_
&& !commentsBefore_
.empty())
1298 root
.setComment(commentsBefore_
, commentAfter
);
1299 if (features_
.strictRoot_
) {
1300 if (!root
.isArray() && !root
.isObject()) {
1301 // Set error location to start of doc, ideally should be first token found
1303 token
.type_
= tokenError
;
1304 token
.start_
= beginDoc
;
1305 token
.end_
= endDoc
;
1307 "A valid JSON document must be either an array or an object value.",
1315 bool OurReader::readValue() {
1316 // To preserve the old behaviour we cast size_t to int.
1317 if (static_cast<int>(nodes_
.size()) > features_
.stackLimit_
) throwRuntimeError("Exceeded stackLimit in readValue().");
1319 skipCommentTokens(token
);
1320 bool successful
= true;
1322 if (collectComments_
&& !commentsBefore_
.empty()) {
1323 currentValue().setComment(commentsBefore_
, commentBefore
);
1324 commentsBefore_
.clear();
1327 switch (token
.type_
) {
1328 case tokenObjectBegin
:
1329 successful
= readObject(token
);
1330 currentValue().setOffsetLimit(current_
- begin_
);
1332 case tokenArrayBegin
:
1333 successful
= readArray(token
);
1334 currentValue().setOffsetLimit(current_
- begin_
);
1337 successful
= decodeNumber(token
);
1340 successful
= decodeString(token
);
1345 currentValue().swapPayload(v
);
1346 currentValue().setOffsetStart(token
.start_
- begin_
);
1347 currentValue().setOffsetLimit(token
.end_
- begin_
);
1353 currentValue().swapPayload(v
);
1354 currentValue().setOffsetStart(token
.start_
- begin_
);
1355 currentValue().setOffsetLimit(token
.end_
- begin_
);
1361 currentValue().swapPayload(v
);
1362 currentValue().setOffsetStart(token
.start_
- begin_
);
1363 currentValue().setOffsetLimit(token
.end_
- begin_
);
1368 Value
v(std::numeric_limits
<double>::quiet_NaN());
1369 currentValue().swapPayload(v
);
1370 currentValue().setOffsetStart(token
.start_
- begin_
);
1371 currentValue().setOffsetLimit(token
.end_
- begin_
);
1376 Value
v(std::numeric_limits
<double>::infinity());
1377 currentValue().swapPayload(v
);
1378 currentValue().setOffsetStart(token
.start_
- begin_
);
1379 currentValue().setOffsetLimit(token
.end_
- begin_
);
1384 Value
v(-std::numeric_limits
<double>::infinity());
1385 currentValue().swapPayload(v
);
1386 currentValue().setOffsetStart(token
.start_
- begin_
);
1387 currentValue().setOffsetLimit(token
.end_
- begin_
);
1390 case tokenArraySeparator
:
1391 case tokenObjectEnd
:
1393 if (features_
.allowDroppedNullPlaceholders_
) {
1394 // "Un-read" the current token and mark the current value as a null
1398 currentValue().swapPayload(v
);
1399 currentValue().setOffsetStart(current_
- begin_
- 1);
1400 currentValue().setOffsetLimit(current_
- begin_
);
1402 } // else, fall through ...
1404 currentValue().setOffsetStart(token
.start_
- begin_
);
1405 currentValue().setOffsetLimit(token
.end_
- begin_
);
1406 return addError("Syntax error: value, object or array expected.", token
);
1409 if (collectComments_
) {
1410 lastValueEnd_
= current_
;
1411 lastValue_
= ¤tValue();
1417 void OurReader::skipCommentTokens(Token
& token
) {
1418 if (features_
.allowComments_
) {
1421 } while (token
.type_
== tokenComment
);
1427 bool OurReader::readToken(Token
& token
) {
1429 token
.start_
= current_
;
1430 Char c
= getNextChar();
1434 token
.type_
= tokenObjectBegin
;
1437 token
.type_
= tokenObjectEnd
;
1440 token
.type_
= tokenArrayBegin
;
1443 token
.type_
= tokenArrayEnd
;
1446 token
.type_
= tokenString
;
1450 if (features_
.allowSingleQuotes_
) {
1451 token
.type_
= tokenString
;
1452 ok
= readStringSingleQuote();
1454 } // else fall through
1456 token
.type_
= tokenComment
;
1469 token
.type_
= tokenNumber
;
1473 if (readNumber(true)) {
1474 token
.type_
= tokenNumber
;
1476 token
.type_
= tokenNegInf
;
1477 ok
= features_
.allowSpecialFloats_
&& match("nfinity", 7);
1481 token
.type_
= tokenTrue
;
1482 ok
= match("rue", 3);
1485 token
.type_
= tokenFalse
;
1486 ok
= match("alse", 4);
1489 token
.type_
= tokenNull
;
1490 ok
= match("ull", 3);
1493 if (features_
.allowSpecialFloats_
) {
1494 token
.type_
= tokenNaN
;
1495 ok
= match("aN", 2);
1501 if (features_
.allowSpecialFloats_
) {
1502 token
.type_
= tokenPosInf
;
1503 ok
= match("nfinity", 7);
1509 token
.type_
= tokenArraySeparator
;
1512 token
.type_
= tokenMemberSeparator
;
1515 token
.type_
= tokenEndOfStream
;
1522 token
.type_
= tokenError
;
1523 token
.end_
= current_
;
1527 void OurReader::skipSpaces() {
1528 while (current_
!= end_
) {
1530 if (c
== ' ' || c
== '\t' || c
== '\r' || c
== '\n')
1537 bool OurReader::match(Location pattern
, int patternLength
) {
1538 if (end_
- current_
< patternLength
)
1540 int index
= patternLength
;
1542 if (current_
[index
] != pattern
[index
])
1544 current_
+= patternLength
;
1548 bool OurReader::readComment() {
1549 Location commentBegin
= current_
- 1;
1550 Char c
= getNextChar();
1551 bool successful
= false;
1553 successful
= readCStyleComment();
1555 successful
= readCppStyleComment();
1559 if (collectComments_
) {
1560 CommentPlacement placement
= commentBefore
;
1561 if (lastValueEnd_
&& !containsNewLine(lastValueEnd_
, commentBegin
)) {
1562 if (c
!= '*' || !containsNewLine(commentBegin
, current_
))
1563 placement
= commentAfterOnSameLine
;
1566 addComment(commentBegin
, current_
, placement
);
1571 JSONCPP_STRING
OurReader::normalizeEOL(OurReader::Location begin
, OurReader::Location end
) {
1572 JSONCPP_STRING normalized
;
1573 normalized
.reserve(static_cast<size_t>(end
- begin
));
1574 OurReader::Location current
= begin
;
1575 while (current
!= end
) {
1576 char c
= *current
++;
1578 if (current
!= end
&& *current
== '\n')
1591 OurReader::addComment(Location begin
, Location end
, CommentPlacement placement
) {
1592 assert(collectComments_
);
1593 const JSONCPP_STRING
& normalized
= normalizeEOL(begin
, end
);
1594 if (placement
== commentAfterOnSameLine
) {
1595 assert(lastValue_
!= 0);
1596 lastValue_
->setComment(normalized
, placement
);
1598 commentsBefore_
+= normalized
;
1602 bool OurReader::readCStyleComment() {
1603 while ((current_
+ 1) < end_
) {
1604 Char c
= getNextChar();
1605 if (c
== '*' && *current_
== '/')
1608 return getNextChar() == '/';
1611 bool OurReader::readCppStyleComment() {
1612 while (current_
!= end_
) {
1613 Char c
= getNextChar();
1617 // Consume DOS EOL. It will be normalized in addComment.
1618 if (current_
!= end_
&& *current_
== '\n')
1620 // Break on Moc OS 9 EOL.
1627 bool OurReader::readNumber(bool checkInf
) {
1628 const char *p
= current_
;
1629 if (checkInf
&& p
!= end_
&& *p
== 'I') {
1633 char c
= '0'; // stopgap for already consumed character
1635 while (c
>= '0' && c
<= '9')
1636 c
= (current_
= p
) < end_
? *p
++ : '\0';
1639 c
= (current_
= p
) < end_
? *p
++ : '\0';
1640 while (c
>= '0' && c
<= '9')
1641 c
= (current_
= p
) < end_
? *p
++ : '\0';
1644 if (c
== 'e' || c
== 'E') {
1645 c
= (current_
= p
) < end_
? *p
++ : '\0';
1646 if (c
== '+' || c
== '-')
1647 c
= (current_
= p
) < end_
? *p
++ : '\0';
1648 while (c
>= '0' && c
<= '9')
1649 c
= (current_
= p
) < end_
? *p
++ : '\0';
1653 bool OurReader::readString() {
1655 while (current_
!= end_
) {
1666 bool OurReader::readStringSingleQuote() {
1668 while (current_
!= end_
) {
1678 bool OurReader::readObject(Token
& tokenStart
) {
1680 JSONCPP_STRING name
;
1681 Value
init(objectValue
);
1682 currentValue().swapPayload(init
);
1683 currentValue().setOffsetStart(tokenStart
.start_
- begin_
);
1684 while (readToken(tokenName
)) {
1685 bool initialTokenOk
= true;
1686 while (tokenName
.type_
== tokenComment
&& initialTokenOk
)
1687 initialTokenOk
= readToken(tokenName
);
1688 if (!initialTokenOk
)
1690 if (tokenName
.type_
== tokenObjectEnd
&& name
.empty()) // empty object
1693 if (tokenName
.type_
== tokenString
) {
1694 if (!decodeString(tokenName
, name
))
1695 return recoverFromError(tokenObjectEnd
);
1696 } else if (tokenName
.type_
== tokenNumber
&& features_
.allowNumericKeys_
) {
1698 if (!decodeNumber(tokenName
, numberName
))
1699 return recoverFromError(tokenObjectEnd
);
1700 name
= numberName
.asString();
1706 if (!readToken(colon
) || colon
.type_
!= tokenMemberSeparator
) {
1707 return addErrorAndRecover(
1708 "Missing ':' after object member name", colon
, tokenObjectEnd
);
1710 if (name
.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
1711 if (features_
.rejectDupKeys_
&& currentValue().isMember(name
)) {
1712 JSONCPP_STRING msg
= "Duplicate key: '" + name
+ "'";
1713 return addErrorAndRecover(
1714 msg
, tokenName
, tokenObjectEnd
);
1716 Value
& value
= currentValue()[name
];
1717 nodes_
.push(&value
);
1718 bool ok
= readValue();
1720 if (!ok
) // error already set
1721 return recoverFromError(tokenObjectEnd
);
1724 if (!readToken(comma
) ||
1725 (comma
.type_
!= tokenObjectEnd
&& comma
.type_
!= tokenArraySeparator
&&
1726 comma
.type_
!= tokenComment
)) {
1727 return addErrorAndRecover(
1728 "Missing ',' or '}' in object declaration", comma
, tokenObjectEnd
);
1730 bool finalizeTokenOk
= true;
1731 while (comma
.type_
== tokenComment
&& finalizeTokenOk
)
1732 finalizeTokenOk
= readToken(comma
);
1733 if (comma
.type_
== tokenObjectEnd
)
1736 return addErrorAndRecover(
1737 "Missing '}' or object member name", tokenName
, tokenObjectEnd
);
1740 bool OurReader::readArray(Token
& tokenStart
) {
1741 Value
init(arrayValue
);
1742 currentValue().swapPayload(init
);
1743 currentValue().setOffsetStart(tokenStart
.start_
- begin_
);
1745 if (current_
!= end_
&& *current_
== ']') // empty array
1748 readToken(endArray
);
1753 Value
& value
= currentValue()[index
++];
1754 nodes_
.push(&value
);
1755 bool ok
= readValue();
1757 if (!ok
) // error already set
1758 return recoverFromError(tokenArrayEnd
);
1761 // Accept Comment after last item in the array.
1762 ok
= readToken(token
);
1763 while (token
.type_
== tokenComment
&& ok
) {
1764 ok
= readToken(token
);
1767 (token
.type_
!= tokenArraySeparator
&& token
.type_
!= tokenArrayEnd
);
1768 if (!ok
|| badTokenType
) {
1769 return addErrorAndRecover(
1770 "Missing ',' or ']' in array declaration", token
, tokenArrayEnd
);
1772 if (token
.type_
== tokenArrayEnd
)
1778 bool OurReader::decodeNumber(Token
& token
) {
1780 if (!decodeNumber(token
, decoded
))
1782 currentValue().swapPayload(decoded
);
1783 currentValue().setOffsetStart(token
.start_
- begin_
);
1784 currentValue().setOffsetLimit(token
.end_
- begin_
);
1788 bool OurReader::decodeNumber(Token
& token
, Value
& decoded
) {
1789 // Attempts to parse the number as an integer. If the number is
1790 // larger than the maximum supported value of an integer then
1791 // we decode the number as a double.
1792 Location current
= token
.start_
;
1793 bool isNegative
= *current
== '-';
1796 // TODO: Help the compiler do the div and mod at compile time or get rid of them.
1797 Value::LargestUInt maxIntegerValue
=
1798 isNegative
? Value::LargestUInt(-Value::minLargestInt
)
1799 : Value::maxLargestUInt
;
1800 Value::LargestUInt threshold
= maxIntegerValue
/ 10;
1801 Value::LargestUInt value
= 0;
1802 while (current
< token
.end_
) {
1803 Char c
= *current
++;
1804 if (c
< '0' || c
> '9')
1805 return decodeDouble(token
, decoded
);
1806 Value::UInt
digit(static_cast<Value::UInt
>(c
- '0'));
1807 if (value
>= threshold
) {
1808 // We've hit or exceeded the max value divided by 10 (rounded down). If
1809 // a) we've only just touched the limit, b) this is the last digit, and
1810 // c) it's small enough to fit in that rounding delta, we're okay.
1811 // Otherwise treat this number as a double to avoid overflow.
1812 if (value
> threshold
|| current
!= token
.end_
||
1813 digit
> maxIntegerValue
% 10) {
1814 return decodeDouble(token
, decoded
);
1817 value
= value
* 10 + digit
;
1820 decoded
= -Value::LargestInt(value
);
1821 else if (value
<= Value::LargestUInt(Value::maxInt
))
1822 decoded
= Value::LargestInt(value
);
1828 bool OurReader::decodeDouble(Token
& token
) {
1830 if (!decodeDouble(token
, decoded
))
1832 currentValue().swapPayload(decoded
);
1833 currentValue().setOffsetStart(token
.start_
- begin_
);
1834 currentValue().setOffsetLimit(token
.end_
- begin_
);
1838 bool OurReader::decodeDouble(Token
& token
, Value
& decoded
) {
1840 const int bufferSize
= 32;
1842 ptrdiff_t const length
= token
.end_
- token
.start_
;
1844 // Sanity check to avoid buffer overflow exploits.
1846 return addError("Unable to parse token length", token
);
1848 size_t const ulength
= static_cast<size_t>(length
);
1850 // Avoid using a string constant for the format control string given to
1851 // sscanf, as this can cause hard to debug crashes on OS X. See here for more
1854 // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
1855 char format
[] = "%lf";
1857 if (length
<= bufferSize
) {
1858 Char buffer
[bufferSize
+ 1];
1859 memcpy(buffer
, token
.start_
, ulength
);
1861 fixNumericLocaleInput(buffer
, buffer
+ length
);
1862 count
= sscanf(buffer
, format
, &value
);
1864 JSONCPP_STRING
buffer(token
.start_
, token
.end_
);
1865 count
= sscanf(buffer
.c_str(), format
, &value
);
1869 return addError("'" + JSONCPP_STRING(token
.start_
, token
.end_
) +
1870 "' is not a number.",
1876 bool OurReader::decodeString(Token
& token
) {
1877 JSONCPP_STRING decoded_string
;
1878 if (!decodeString(token
, decoded_string
))
1880 Value
decoded(decoded_string
);
1881 currentValue().swapPayload(decoded
);
1882 currentValue().setOffsetStart(token
.start_
- begin_
);
1883 currentValue().setOffsetLimit(token
.end_
- begin_
);
1887 bool OurReader::decodeString(Token
& token
, JSONCPP_STRING
& decoded
) {
1888 decoded
.reserve(static_cast<size_t>(token
.end_
- token
.start_
- 2));
1889 Location current
= token
.start_
+ 1; // skip '"'
1890 Location end
= token
.end_
- 1; // do not include '"'
1891 while (current
!= end
) {
1892 Char c
= *current
++;
1895 else if (c
== '\\') {
1897 return addError("Empty escape sequence in string", token
, current
);
1898 Char escape
= *current
++;
1925 unsigned int unicode
;
1926 if (!decodeUnicodeCodePoint(token
, current
, end
, unicode
))
1928 decoded
+= codePointToUTF8(unicode
);
1931 return addError("Bad escape sequence in string", token
, current
);
1940 bool OurReader::decodeUnicodeCodePoint(Token
& token
,
1943 unsigned int& unicode
) {
1945 if (!decodeUnicodeEscapeSequence(token
, current
, end
, unicode
))
1947 if (unicode
>= 0xD800 && unicode
<= 0xDBFF) {
1949 if (end
- current
< 6)
1951 "additional six characters expected to parse unicode surrogate pair.",
1954 unsigned int surrogatePair
;
1955 if (*(current
++) == '\\' && *(current
++) == 'u') {
1956 if (decodeUnicodeEscapeSequence(token
, current
, end
, surrogatePair
)) {
1957 unicode
= 0x10000 + ((unicode
& 0x3FF) << 10) + (surrogatePair
& 0x3FF);
1961 return addError("expecting another \\u token to begin the second half of "
1962 "a unicode surrogate pair",
1969 bool OurReader::decodeUnicodeEscapeSequence(Token
& token
,
1972 unsigned int& ret_unicode
) {
1973 if (end
- current
< 4)
1975 "Bad unicode escape sequence in string: four digits expected.",
1979 for (int index
= 0; index
< 4; ++index
) {
1980 Char c
= *current
++;
1982 if (c
>= '0' && c
<= '9')
1984 else if (c
>= 'a' && c
<= 'f')
1985 unicode
+= c
- 'a' + 10;
1986 else if (c
>= 'A' && c
<= 'F')
1987 unicode
+= c
- 'A' + 10;
1990 "Bad unicode escape sequence in string: hexadecimal digit expected.",
1994 ret_unicode
= static_cast<unsigned int>(unicode
);
1999 OurReader::addError(const JSONCPP_STRING
& message
, Token
& token
, Location extra
) {
2001 info
.token_
= token
;
2002 info
.message_
= message
;
2003 info
.extra_
= extra
;
2004 errors_
.push_back(info
);
2008 bool OurReader::recoverFromError(TokenType skipUntilToken
) {
2009 size_t errorCount
= errors_
.size();
2012 if (!readToken(skip
))
2013 errors_
.resize(errorCount
); // discard errors caused by recovery
2014 if (skip
.type_
== skipUntilToken
|| skip
.type_
== tokenEndOfStream
)
2017 errors_
.resize(errorCount
);
2021 bool OurReader::addErrorAndRecover(const JSONCPP_STRING
& message
,
2023 TokenType skipUntilToken
) {
2024 addError(message
, token
);
2025 return recoverFromError(skipUntilToken
);
2028 Value
& OurReader::currentValue() { return *(nodes_
.top()); }
2030 OurReader::Char
OurReader::getNextChar() {
2031 if (current_
== end_
)
2036 void OurReader::getLocationLineAndColumn(Location location
,
2038 int& column
) const {
2039 Location current
= begin_
;
2040 Location lastLineStart
= current
;
2042 while (current
< location
&& current
!= end_
) {
2043 Char c
= *current
++;
2045 if (*current
== '\n')
2047 lastLineStart
= current
;
2049 } else if (c
== '\n') {
2050 lastLineStart
= current
;
2054 // column & line start at 1
2055 column
= int(location
- lastLineStart
) + 1;
2059 JSONCPP_STRING
OurReader::getLocationLineAndColumn(Location location
) const {
2061 getLocationLineAndColumn(location
, line
, column
);
2062 char buffer
[18 + 16 + 16 + 1];
2063 snprintf(buffer
, sizeof(buffer
), "Line %d, Column %d", line
, column
);
2067 JSONCPP_STRING
OurReader::getFormattedErrorMessages() const {
2068 JSONCPP_STRING formattedMessage
;
2069 for (Errors::const_iterator itError
= errors_
.begin();
2070 itError
!= errors_
.end();
2072 const ErrorInfo
& error
= *itError
;
2074 "* " + getLocationLineAndColumn(error
.token_
.start_
) + "\n";
2075 formattedMessage
+= " " + error
.message_
+ "\n";
2078 "See " + getLocationLineAndColumn(error
.extra_
) + " for detail.\n";
2080 return formattedMessage
;
2083 std::vector
<OurReader::StructuredError
> OurReader::getStructuredErrors() const {
2084 std::vector
<OurReader::StructuredError
> allErrors
;
2085 for (Errors::const_iterator itError
= errors_
.begin();
2086 itError
!= errors_
.end();
2088 const ErrorInfo
& error
= *itError
;
2089 OurReader::StructuredError structured
;
2090 structured
.offset_start
= error
.token_
.start_
- begin_
;
2091 structured
.offset_limit
= error
.token_
.end_
- begin_
;
2092 structured
.message
= error
.message_
;
2093 allErrors
.push_back(structured
);
2098 bool OurReader::pushError(const Value
& value
, const JSONCPP_STRING
& message
) {
2099 ptrdiff_t length
= end_
- begin_
;
2100 if(value
.getOffsetStart() > length
2101 || value
.getOffsetLimit() > length
)
2104 token
.type_
= tokenError
;
2105 token
.start_
= begin_
+ value
.getOffsetStart();
2106 token
.end_
= end_
+ value
.getOffsetLimit();
2108 info
.token_
= token
;
2109 info
.message_
= message
;
2111 errors_
.push_back(info
);
2115 bool OurReader::pushError(const Value
& value
, const JSONCPP_STRING
& message
, const Value
& extra
) {
2116 ptrdiff_t length
= end_
- begin_
;
2117 if(value
.getOffsetStart() > length
2118 || value
.getOffsetLimit() > length
2119 || extra
.getOffsetLimit() > length
)
2122 token
.type_
= tokenError
;
2123 token
.start_
= begin_
+ value
.getOffsetStart();
2124 token
.end_
= begin_
+ value
.getOffsetLimit();
2126 info
.token_
= token
;
2127 info
.message_
= message
;
2128 info
.extra_
= begin_
+ extra
.getOffsetStart();
2129 errors_
.push_back(info
);
2133 bool OurReader::good() const {
2134 return !errors_
.size();
2138 class OurCharReader
: public CharReader
{
2139 bool const collectComments_
;
2143 bool collectComments
,
2144 OurFeatures
const& features
)
2145 : collectComments_(collectComments
)
2149 char const* beginDoc
, char const* endDoc
,
2150 Value
* root
, JSONCPP_STRING
* errs
) JSONCPP_OVERRIDE
{
2151 bool ok
= reader_
.parse(beginDoc
, endDoc
, *root
, collectComments_
);
2153 *errs
= reader_
.getFormattedErrorMessages();
2159 CharReaderBuilder::CharReaderBuilder()
2161 setDefaults(&settings_
);
2163 CharReaderBuilder::~CharReaderBuilder()
2165 CharReader
* CharReaderBuilder::newCharReader() const
2167 bool collectComments
= settings_
["collectComments"].asBool();
2168 OurFeatures features
= OurFeatures::all();
2169 features
.allowComments_
= settings_
["allowComments"].asBool();
2170 features
.strictRoot_
= settings_
["strictRoot"].asBool();
2171 features
.allowDroppedNullPlaceholders_
= settings_
["allowDroppedNullPlaceholders"].asBool();
2172 features
.allowNumericKeys_
= settings_
["allowNumericKeys"].asBool();
2173 features
.allowSingleQuotes_
= settings_
["allowSingleQuotes"].asBool();
2174 features
.stackLimit_
= settings_
["stackLimit"].asInt();
2175 features
.failIfExtra_
= settings_
["failIfExtra"].asBool();
2176 features
.rejectDupKeys_
= settings_
["rejectDupKeys"].asBool();
2177 features
.allowSpecialFloats_
= settings_
["allowSpecialFloats"].asBool();
2178 return new OurCharReader(collectComments
, features
);
2180 static void getValidReaderKeys(std::set
<JSONCPP_STRING
>* valid_keys
)
2182 valid_keys
->clear();
2183 valid_keys
->insert("collectComments");
2184 valid_keys
->insert("allowComments");
2185 valid_keys
->insert("strictRoot");
2186 valid_keys
->insert("allowDroppedNullPlaceholders");
2187 valid_keys
->insert("allowNumericKeys");
2188 valid_keys
->insert("allowSingleQuotes");
2189 valid_keys
->insert("stackLimit");
2190 valid_keys
->insert("failIfExtra");
2191 valid_keys
->insert("rejectDupKeys");
2192 valid_keys
->insert("allowSpecialFloats");
2194 bool CharReaderBuilder::validate(Json::Value
* invalid
) const
2196 Json::Value my_invalid
;
2197 if (!invalid
) invalid
= &my_invalid
; // so we do not need to test for NULL
2198 Json::Value
& inv
= *invalid
;
2199 std::set
<JSONCPP_STRING
> valid_keys
;
2200 getValidReaderKeys(&valid_keys
);
2201 Value::Members keys
= settings_
.getMemberNames();
2202 size_t n
= keys
.size();
2203 for (size_t i
= 0; i
< n
; ++i
) {
2204 JSONCPP_STRING
const& key
= keys
[i
];
2205 if (valid_keys
.find(key
) == valid_keys
.end()) {
2206 inv
[key
] = settings_
[key
];
2209 return 0u == inv
.size();
2211 Value
& CharReaderBuilder::operator[](JSONCPP_STRING key
)
2213 return settings_
[key
];
2216 void CharReaderBuilder::strictMode(Json::Value
* settings
)
2218 //! [CharReaderBuilderStrictMode]
2219 (*settings
)["allowComments"] = false;
2220 (*settings
)["strictRoot"] = true;
2221 (*settings
)["allowDroppedNullPlaceholders"] = false;
2222 (*settings
)["allowNumericKeys"] = false;
2223 (*settings
)["allowSingleQuotes"] = false;
2224 (*settings
)["stackLimit"] = 1000;
2225 (*settings
)["failIfExtra"] = true;
2226 (*settings
)["rejectDupKeys"] = true;
2227 (*settings
)["allowSpecialFloats"] = false;
2228 //! [CharReaderBuilderStrictMode]
2231 void CharReaderBuilder::setDefaults(Json::Value
* settings
)
2233 //! [CharReaderBuilderDefaults]
2234 (*settings
)["collectComments"] = true;
2235 (*settings
)["allowComments"] = true;
2236 (*settings
)["strictRoot"] = false;
2237 (*settings
)["allowDroppedNullPlaceholders"] = false;
2238 (*settings
)["allowNumericKeys"] = false;
2239 (*settings
)["allowSingleQuotes"] = false;
2240 (*settings
)["stackLimit"] = 1000;
2241 (*settings
)["failIfExtra"] = false;
2242 (*settings
)["rejectDupKeys"] = false;
2243 (*settings
)["allowSpecialFloats"] = false;
2244 //! [CharReaderBuilderDefaults]
2247 //////////////////////////////////
2250 bool parseFromStream(
2251 CharReader::Factory
const& fact
, JSONCPP_ISTREAM
& sin
,
2252 Value
* root
, JSONCPP_STRING
* errs
)
2254 JSONCPP_OSTRINGSTREAM ssin
;
2255 ssin
<< sin
.rdbuf();
2256 JSONCPP_STRING doc
= ssin
.str();
2257 char const* begin
= doc
.data();
2258 char const* end
= begin
+ doc
.size();
2259 // Note that we do not actually need a null-terminator.
2260 CharReaderPtr
const reader(fact
.newCharReader());
2261 return reader
->parse(begin
, end
, root
, errs
);
2264 JSONCPP_ISTREAM
& operator>>(JSONCPP_ISTREAM
& sin
, Value
& root
) {
2265 CharReaderBuilder b
;
2266 JSONCPP_STRING errs
;
2267 bool ok
= parseFromStream(b
, sin
, &root
, &errs
);
2269 throwRuntimeError(errs
);
2276 // //////////////////////////////////////////////////////////////////////
2277 // End of content of file: src/lib_json/json_reader.cpp
2278 // //////////////////////////////////////////////////////////////////////
2285 // //////////////////////////////////////////////////////////////////////
2286 // Beginning of content of file: src/lib_json/json_valueiterator.inl
2287 // //////////////////////////////////////////////////////////////////////
2289 // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
2290 // Distributed under MIT license, or public domain if desired and
2291 // recognized in your jurisdiction.
2292 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
2294 // included by json_value.cpp
2298 // //////////////////////////////////////////////////////////////////
2299 // //////////////////////////////////////////////////////////////////
2300 // //////////////////////////////////////////////////////////////////
2301 // class ValueIteratorBase
2302 // //////////////////////////////////////////////////////////////////
2303 // //////////////////////////////////////////////////////////////////
2304 // //////////////////////////////////////////////////////////////////
2306 ValueIteratorBase::ValueIteratorBase()
2307 : current_(), isNull_(true) {
2310 ValueIteratorBase::ValueIteratorBase(
2311 const Value::ObjectValues::iterator
& current
)
2312 : current_(current
), isNull_(false) {}
2314 Value
& ValueIteratorBase::deref() const {
2315 return current_
->second
;
2318 void ValueIteratorBase::increment() {
2322 void ValueIteratorBase::decrement() {
2326 ValueIteratorBase::difference_type
2327 ValueIteratorBase::computeDistance(const SelfType
& other
) const {
2328 #ifdef JSON_USE_CPPTL_SMALLMAP
2329 return other
.current_
- current_
;
2331 // Iterator for null value are initialized using the default
2332 // constructor, which initialize current_ to the default
2333 // std::map::iterator. As begin() and end() are two instance
2334 // of the default std::map::iterator, they can not be compared.
2335 // To allow this, we handle this comparison specifically.
2336 if (isNull_
&& other
.isNull_
) {
2340 // Usage of std::distance is not portable (does not compile with Sun Studio 12
2342 // which is the one used by default).
2343 // Using a portable hand-made version for non random iterator instead:
2344 // return difference_type( std::distance( current_, other.current_ ) );
2345 difference_type myDistance
= 0;
2346 for (Value::ObjectValues::iterator it
= current_
; it
!= other
.current_
;
2354 bool ValueIteratorBase::isEqual(const SelfType
& other
) const {
2356 return other
.isNull_
;
2358 return current_
== other
.current_
;
2361 void ValueIteratorBase::copy(const SelfType
& other
) {
2362 current_
= other
.current_
;
2363 isNull_
= other
.isNull_
;
2366 Value
ValueIteratorBase::key() const {
2367 const Value::CZString czstring
= (*current_
).first
;
2368 if (czstring
.data()) {
2369 if (czstring
.isStaticString())
2370 return Value(StaticString(czstring
.data()));
2371 return Value(czstring
.data(), czstring
.data() + czstring
.length());
2373 return Value(czstring
.index());
2376 UInt
ValueIteratorBase::index() const {
2377 const Value::CZString czstring
= (*current_
).first
;
2378 if (!czstring
.data())
2379 return czstring
.index();
2380 return Value::UInt(-1);
2383 JSONCPP_STRING
ValueIteratorBase::name() const {
2386 keey
= memberName(&end
);
2387 if (!keey
) return JSONCPP_STRING();
2388 return JSONCPP_STRING(keey
, end
);
2391 char const* ValueIteratorBase::memberName() const {
2392 const char* cname
= (*current_
).first
.data();
2393 return cname
? cname
: "";
2396 char const* ValueIteratorBase::memberName(char const** end
) const {
2397 const char* cname
= (*current_
).first
.data();
2402 *end
= cname
+ (*current_
).first
.length();
2406 // //////////////////////////////////////////////////////////////////
2407 // //////////////////////////////////////////////////////////////////
2408 // //////////////////////////////////////////////////////////////////
2409 // class ValueConstIterator
2410 // //////////////////////////////////////////////////////////////////
2411 // //////////////////////////////////////////////////////////////////
2412 // //////////////////////////////////////////////////////////////////
2414 ValueConstIterator::ValueConstIterator() {}
2416 ValueConstIterator::ValueConstIterator(
2417 const Value::ObjectValues::iterator
& current
)
2418 : ValueIteratorBase(current
) {}
2420 ValueConstIterator::ValueConstIterator(ValueIterator
const& other
)
2421 : ValueIteratorBase(other
) {}
2423 ValueConstIterator
& ValueConstIterator::
2424 operator=(const ValueIteratorBase
& other
) {
2429 // //////////////////////////////////////////////////////////////////
2430 // //////////////////////////////////////////////////////////////////
2431 // //////////////////////////////////////////////////////////////////
2432 // class ValueIterator
2433 // //////////////////////////////////////////////////////////////////
2434 // //////////////////////////////////////////////////////////////////
2435 // //////////////////////////////////////////////////////////////////
2437 ValueIterator::ValueIterator() {}
2439 ValueIterator::ValueIterator(const Value::ObjectValues::iterator
& current
)
2440 : ValueIteratorBase(current
) {}
2442 ValueIterator::ValueIterator(const ValueConstIterator
& other
)
2443 : ValueIteratorBase(other
) {
2444 throwRuntimeError("ConstIterator to Iterator should never be allowed.");
2447 ValueIterator::ValueIterator(const ValueIterator
& other
)
2448 : ValueIteratorBase(other
) {}
2450 ValueIterator
& ValueIterator::operator=(const SelfType
& other
) {
2457 // //////////////////////////////////////////////////////////////////////
2458 // End of content of file: src/lib_json/json_valueiterator.inl
2459 // //////////////////////////////////////////////////////////////////////
2466 // //////////////////////////////////////////////////////////////////////
2467 // Beginning of content of file: src/lib_json/json_value.cpp
2468 // //////////////////////////////////////////////////////////////////////
2470 // Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
2471 // Distributed under MIT license, or public domain if desired and
2472 // recognized in your jurisdiction.
2473 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
2475 #if !defined(JSON_IS_AMALGAMATION)
2476 #include <json/assertions.h>
2477 #include <json/value.h>
2478 #include <json/writer.h>
2479 #endif // if !defined(JSON_IS_AMALGAMATION)
2485 #ifdef JSON_USE_CPPTL
2486 #include <cpptl/conststring.h>
2488 #include <cstddef> // size_t
2489 #include <algorithm> // min()
2491 #define JSON_ASSERT_UNREACHABLE assert(false)
2495 // This is a walkaround to avoid the static initialization of Value::null.
2496 // kNull must be word-aligned to avoid crashing on ARM. We use an alignment of
2497 // 8 (instead of 4) as a bit of future-proofing.
2498 #if defined(__ARMEL__)
2499 #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
2501 #define ALIGNAS(byte_alignment)
2503 //static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
2504 //const unsigned char& kNullRef = kNull[0];
2505 //const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
2506 //const Value& Value::nullRef = null;
2509 Value
const& Value::nullSingleton()
2511 static Value
const nullStatic
;
2515 // for backwards compatibility, we'll leave these global references around, but DO NOT
2516 // use them in JSONCPP library code any more!
2517 Value
const& Value::null
= Value::nullSingleton();
2518 Value
const& Value::nullRef
= Value::nullSingleton();
2520 const Int
Value::minInt
= Int(~(UInt(-1) / 2));
2521 const Int
Value::maxInt
= Int(UInt(-1) / 2);
2522 const UInt
Value::maxUInt
= UInt(-1);
2523 #if defined(JSON_HAS_INT64)
2524 const Int64
Value::minInt64
= Int64(~(UInt64(-1) / 2));
2525 const Int64
Value::maxInt64
= Int64(UInt64(-1) / 2);
2526 const UInt64
Value::maxUInt64
= UInt64(-1);
2527 // The constant is hard-coded because some compiler have trouble
2528 // converting Value::maxUInt64 to a double correctly (AIX/xlC).
2529 // Assumes that UInt64 is a 64 bits integer.
2530 static const double maxUInt64AsDouble
= 18446744073709551615.0;
2531 #endif // defined(JSON_HAS_INT64)
2532 const LargestInt
Value::minLargestInt
= LargestInt(~(LargestUInt(-1) / 2));
2533 const LargestInt
Value::maxLargestInt
= LargestInt(LargestUInt(-1) / 2);
2534 const LargestUInt
Value::maxLargestUInt
= LargestUInt(-1);
2536 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2537 template <typename T
, typename U
>
2538 static inline bool InRange(double d
, T min
, U max
) {
2539 // The casts can lose precision, but we are looking only for
2540 // an approximate range. Might fail on edge cases though. ~cdunn
2541 //return d >= static_cast<double>(min) && d <= static_cast<double>(max);
2542 return d
>= min
&& d
<= max
;
2544 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2545 static inline double integerToDouble(Json::UInt64 value
) {
2546 return static_cast<double>(Int64(value
/ 2)) * 2.0 + static_cast<double>(Int64(value
& 1));
2549 template <typename T
> static inline double integerToDouble(T value
) {
2550 return static_cast<double>(value
);
2553 template <typename T
, typename U
>
2554 static inline bool InRange(double d
, T min
, U max
) {
2555 return d
>= integerToDouble(min
) && d
<= integerToDouble(max
);
2557 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2559 /** Duplicates the specified string value.
2560 * @param value Pointer to the string to duplicate. Must be zero-terminated if
2561 * length is "unknown".
2562 * @param length Length of the value. if equals to unknown, then it will be
2563 * computed using strlen(value).
2564 * @return Pointer on the duplicate instance of string.
2566 static inline char* duplicateStringValue(const char* value
,
2569 // Avoid an integer overflow in the call to malloc below by limiting length
2571 if (length
>= static_cast<size_t>(Value::maxInt
))
2572 length
= Value::maxInt
- 1;
2574 char* newString
= static_cast<char*>(malloc(length
+ 1));
2575 if (newString
== NULL
) {
2577 "in Json::Value::duplicateStringValue(): "
2578 "Failed to allocate string value buffer");
2580 memcpy(newString
, value
, length
);
2581 newString
[length
] = 0;
2585 /* Record the length as a prefix.
2587 static inline char* duplicateAndPrefixStringValue(
2589 unsigned int length
)
2591 // Avoid an integer overflow in the call to malloc below by limiting length
2593 JSON_ASSERT_MESSAGE(length
<= static_cast<unsigned>(Value::maxInt
) - sizeof(unsigned) - 1U,
2594 "in Json::Value::duplicateAndPrefixStringValue(): "
2595 "length too big for prefixing");
2596 unsigned actualLength
= length
+ static_cast<unsigned>(sizeof(unsigned)) + 1U;
2597 char* newString
= static_cast<char*>(malloc(actualLength
));
2598 if (newString
== 0) {
2600 "in Json::Value::duplicateAndPrefixStringValue(): "
2601 "Failed to allocate string value buffer");
2603 *reinterpret_cast<unsigned*>(newString
) = length
;
2604 memcpy(newString
+ sizeof(unsigned), value
, length
);
2605 newString
[actualLength
- 1U] = 0; // to avoid buffer over-run accidents by users later
2608 inline static void decodePrefixedString(
2609 bool isPrefixed
, char const* prefixed
,
2610 unsigned* length
, char const** value
)
2613 *length
= static_cast<unsigned>(strlen(prefixed
));
2616 *length
= *reinterpret_cast<unsigned const*>(prefixed
);
2617 *value
= prefixed
+ sizeof(unsigned);
2620 /** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue().
2622 #if JSONCPP_USING_SECURE_MEMORY
2623 static inline void releasePrefixedStringValue(char* value
) {
2624 unsigned length
= 0;
2625 char const* valueDecoded
;
2626 decodePrefixedString(true, value
, &length
, &valueDecoded
);
2627 size_t const size
= sizeof(unsigned) + length
+ 1U;
2628 memset(value
, 0, size
);
2631 static inline void releaseStringValue(char* value
, unsigned length
) {
2632 // length==0 => we allocated the strings memory
2633 size_t size
= (length
==0) ? strlen(value
) : length
;
2634 memset(value
, 0, size
);
2637 #else // !JSONCPP_USING_SECURE_MEMORY
2638 static inline void releasePrefixedStringValue(char* value
) {
2641 static inline void releaseStringValue(char* value
, unsigned) {
2644 #endif // JSONCPP_USING_SECURE_MEMORY
2648 // //////////////////////////////////////////////////////////////////
2649 // //////////////////////////////////////////////////////////////////
2650 // //////////////////////////////////////////////////////////////////
2651 // ValueInternals...
2652 // //////////////////////////////////////////////////////////////////
2653 // //////////////////////////////////////////////////////////////////
2654 // //////////////////////////////////////////////////////////////////
2655 #if !defined(JSON_IS_AMALGAMATION)
2657 #include "json_valueiterator.inl"
2658 #endif // if !defined(JSON_IS_AMALGAMATION)
2662 Exception::Exception(JSONCPP_STRING
const& msg
)
2665 Exception::~Exception() JSONCPP_NOEXCEPT
2667 char const* Exception::what() const JSONCPP_NOEXCEPT
2669 return msg_
.c_str();
2671 RuntimeError::RuntimeError(JSONCPP_STRING
const& msg
)
2674 LogicError::LogicError(JSONCPP_STRING
const& msg
)
2677 JSONCPP_NORETURN
void throwRuntimeError(JSONCPP_STRING
const& msg
)
2679 throw RuntimeError(msg
);
2681 JSONCPP_NORETURN
void throwLogicError(JSONCPP_STRING
const& msg
)
2683 throw LogicError(msg
);
2686 // //////////////////////////////////////////////////////////////////
2687 // //////////////////////////////////////////////////////////////////
2688 // //////////////////////////////////////////////////////////////////
2689 // class Value::CommentInfo
2690 // //////////////////////////////////////////////////////////////////
2691 // //////////////////////////////////////////////////////////////////
2692 // //////////////////////////////////////////////////////////////////
2694 Value::CommentInfo::CommentInfo() : comment_(0)
2697 Value::CommentInfo::~CommentInfo() {
2699 releaseStringValue(comment_
, 0u);
2702 void Value::CommentInfo::setComment(const char* text
, size_t len
) {
2704 releaseStringValue(comment_
, 0u);
2707 JSON_ASSERT(text
!= 0);
2708 JSON_ASSERT_MESSAGE(
2709 text
[0] == '\0' || text
[0] == '/',
2710 "in Json::Value::setComment(): Comments must start with /");
2711 // It seems that /**/ style comments are acceptable as well.
2712 comment_
= duplicateStringValue(text
, len
);
2715 // //////////////////////////////////////////////////////////////////
2716 // //////////////////////////////////////////////////////////////////
2717 // //////////////////////////////////////////////////////////////////
2718 // class Value::CZString
2719 // //////////////////////////////////////////////////////////////////
2720 // //////////////////////////////////////////////////////////////////
2721 // //////////////////////////////////////////////////////////////////
2723 // Notes: policy_ indicates if the string was allocated when
2724 // a string is stored.
2726 Value::CZString::CZString(ArrayIndex aindex
) : cstr_(0), index_(aindex
) {}
2728 Value::CZString::CZString(char const* str
, unsigned ulength
, DuplicationPolicy allocate
)
2730 // allocate != duplicate
2731 storage_
.policy_
= allocate
& 0x3;
2732 storage_
.length_
= ulength
& 0x3FFFFFFF;
2735 Value::CZString::CZString(const CZString
& other
) {
2736 cstr_
= (other
.storage_
.policy_
!= noDuplication
&& other
.cstr_
!= 0
2737 ? duplicateStringValue(other
.cstr_
, other
.storage_
.length_
)
2739 storage_
.policy_
= static_cast<unsigned>(other
.cstr_
2740 ? (static_cast<DuplicationPolicy
>(other
.storage_
.policy_
) == noDuplication
2741 ? noDuplication
: duplicate
)
2742 : static_cast<DuplicationPolicy
>(other
.storage_
.policy_
)) & 3U;
2743 storage_
.length_
= other
.storage_
.length_
;
2746 #if JSON_HAS_RVALUE_REFERENCES
2747 Value::CZString::CZString(CZString
&& other
)
2748 : cstr_(other
.cstr_
), index_(other
.index_
) {
2749 other
.cstr_
= nullptr;
2753 Value::CZString::~CZString() {
2754 if (cstr_
&& storage_
.policy_
== duplicate
) {
2755 releaseStringValue(const_cast<char*>(cstr_
), storage_
.length_
+ 1u); //+1 for null terminating character for sake of completeness but not actually necessary
2759 void Value::CZString::swap(CZString
& other
) {
2760 std::swap(cstr_
, other
.cstr_
);
2761 std::swap(index_
, other
.index_
);
2764 Value::CZString
& Value::CZString::operator=(const CZString
& other
) {
2765 cstr_
= other
.cstr_
;
2766 index_
= other
.index_
;
2770 #if JSON_HAS_RVALUE_REFERENCES
2771 Value::CZString
& Value::CZString::operator=(CZString
&& other
) {
2772 cstr_
= other
.cstr_
;
2773 index_
= other
.index_
;
2774 other
.cstr_
= nullptr;
2779 bool Value::CZString::operator<(const CZString
& other
) const {
2780 if (!cstr_
) return index_
< other
.index_
;
2781 //return strcmp(cstr_, other.cstr_) < 0;
2782 // Assume both are strings.
2783 unsigned this_len
= this->storage_
.length_
;
2784 unsigned other_len
= other
.storage_
.length_
;
2785 unsigned min_len
= std::min
<unsigned>(this_len
, other_len
);
2786 JSON_ASSERT(this->cstr_
&& other
.cstr_
);
2787 int comp
= memcmp(this->cstr_
, other
.cstr_
, min_len
);
2788 if (comp
< 0) return true;
2789 if (comp
> 0) return false;
2790 return (this_len
< other_len
);
2793 bool Value::CZString::operator==(const CZString
& other
) const {
2794 if (!cstr_
) return index_
== other
.index_
;
2795 //return strcmp(cstr_, other.cstr_) == 0;
2796 // Assume both are strings.
2797 unsigned this_len
= this->storage_
.length_
;
2798 unsigned other_len
= other
.storage_
.length_
;
2799 if (this_len
!= other_len
) return false;
2800 JSON_ASSERT(this->cstr_
&& other
.cstr_
);
2801 int comp
= memcmp(this->cstr_
, other
.cstr_
, this_len
);
2805 ArrayIndex
Value::CZString::index() const { return index_
; }
2807 //const char* Value::CZString::c_str() const { return cstr_; }
2808 const char* Value::CZString::data() const { return cstr_
; }
2809 unsigned Value::CZString::length() const { return storage_
.length_
; }
2810 bool Value::CZString::isStaticString() const { return storage_
.policy_
== noDuplication
; }
2812 // //////////////////////////////////////////////////////////////////
2813 // //////////////////////////////////////////////////////////////////
2814 // //////////////////////////////////////////////////////////////////
2815 // class Value::Value
2816 // //////////////////////////////////////////////////////////////////
2817 // //////////////////////////////////////////////////////////////////
2818 // //////////////////////////////////////////////////////////////////
2820 /*! \internal Default constructor initialization must be equivalent to:
2821 * memset( this, 0, sizeof(Value) )
2822 * This optimization is used in ValueInternalMap fast allocator.
2824 Value::Value(ValueType vtype
) {
2825 static char const emptyString
[] = "";
2838 // allocated_ == false, so this is safe.
2839 value_
.string_
= const_cast<char*>(static_cast<char const*>(emptyString
));
2843 value_
.map_
= new ObjectValues();
2846 value_
.bool_
= false;
2849 JSON_ASSERT_UNREACHABLE
;
2853 Value::Value(Int value
) {
2854 initBasic(intValue
);
2855 value_
.int_
= value
;
2858 Value::Value(UInt value
) {
2859 initBasic(uintValue
);
2860 value_
.uint_
= value
;
2862 #if defined(JSON_HAS_INT64)
2863 Value::Value(Int64 value
) {
2864 initBasic(intValue
);
2865 value_
.int_
= value
;
2867 Value::Value(UInt64 value
) {
2868 initBasic(uintValue
);
2869 value_
.uint_
= value
;
2871 #endif // defined(JSON_HAS_INT64)
2873 Value::Value(double value
) {
2874 initBasic(realValue
);
2875 value_
.real_
= value
;
2878 Value::Value(const char* value
) {
2879 initBasic(stringValue
, true);
2880 JSON_ASSERT_MESSAGE(value
!= NULL
, "Null Value Passed to Value Constructor");
2881 value_
.string_
= duplicateAndPrefixStringValue(value
, static_cast<unsigned>(strlen(value
)));
2884 Value::Value(const char* beginValue
, const char* endValue
) {
2885 initBasic(stringValue
, true);
2887 duplicateAndPrefixStringValue(beginValue
, static_cast<unsigned>(endValue
- beginValue
));
2890 Value::Value(const JSONCPP_STRING
& value
) {
2891 initBasic(stringValue
, true);
2893 duplicateAndPrefixStringValue(value
.data(), static_cast<unsigned>(value
.length()));
2896 Value::Value(const StaticString
& value
) {
2897 initBasic(stringValue
);
2898 value_
.string_
= const_cast<char*>(value
.c_str());
2901 #ifdef JSON_USE_CPPTL
2902 Value::Value(const CppTL::ConstString
& value
) {
2903 initBasic(stringValue
, true);
2904 value_
.string_
= duplicateAndPrefixStringValue(value
, static_cast<unsigned>(value
.length()));
2908 Value::Value(bool value
) {
2909 initBasic(booleanValue
);
2910 value_
.bool_
= value
;
2913 Value::Value(Value
const& other
)
2914 : type_(other
.type_
), allocated_(false)
2916 comments_(0), start_(other
.start_
), limit_(other
.limit_
)
2924 value_
= other
.value_
;
2927 if (other
.value_
.string_
&& other
.allocated_
) {
2930 decodePrefixedString(other
.allocated_
, other
.value_
.string_
,
2932 value_
.string_
= duplicateAndPrefixStringValue(str
, len
);
2935 value_
.string_
= other
.value_
.string_
;
2941 value_
.map_
= new ObjectValues(*other
.value_
.map_
);
2944 JSON_ASSERT_UNREACHABLE
;
2946 if (other
.comments_
) {
2947 comments_
= new CommentInfo
[numberOfCommentPlacement
];
2948 for (int comment
= 0; comment
< numberOfCommentPlacement
; ++comment
) {
2949 const CommentInfo
& otherComment
= other
.comments_
[comment
];
2950 if (otherComment
.comment_
)
2951 comments_
[comment
].setComment(
2952 otherComment
.comment_
, strlen(otherComment
.comment_
));
2957 #if JSON_HAS_RVALUE_REFERENCES
2959 Value::Value(Value
&& other
) {
2960 initBasic(nullValue
);
2975 releasePrefixedStringValue(value_
.string_
);
2982 JSON_ASSERT_UNREACHABLE
;
2990 Value
& Value::operator=(Value other
) {
2995 void Value::swapPayload(Value
& other
) {
2996 ValueType temp
= type_
;
2997 type_
= other
.type_
;
2999 std::swap(value_
, other
.value_
);
3000 int temp2
= allocated_
;
3001 allocated_
= other
.allocated_
;
3002 other
.allocated_
= temp2
& 0x1;
3005 void Value::copyPayload(const Value
& other
) {
3006 type_
= other
.type_
;
3007 value_
= other
.value_
;
3008 allocated_
= other
.allocated_
;
3011 void Value::swap(Value
& other
) {
3013 std::swap(comments_
, other
.comments_
);
3014 std::swap(start_
, other
.start_
);
3015 std::swap(limit_
, other
.limit_
);
3018 void Value::copy(const Value
& other
) {
3020 comments_
= other
.comments_
;
3021 start_
= other
.start_
;
3022 limit_
= other
.limit_
;
3025 ValueType
Value::type() const { return type_
; }
3027 int Value::compare(const Value
& other
) const {
3035 bool Value::operator<(const Value
& other
) const {
3036 int typeDelta
= type_
- other
.type_
;
3038 return typeDelta
< 0 ? true : false;
3043 return value_
.int_
< other
.value_
.int_
;
3045 return value_
.uint_
< other
.value_
.uint_
;
3047 return value_
.real_
< other
.value_
.real_
;
3049 return value_
.bool_
< other
.value_
.bool_
;
3052 if ((value_
.string_
== 0) || (other
.value_
.string_
== 0)) {
3053 if (other
.value_
.string_
) return true;
3058 char const* this_str
;
3059 char const* other_str
;
3060 decodePrefixedString(this->allocated_
, this->value_
.string_
, &this_len
, &this_str
);
3061 decodePrefixedString(other
.allocated_
, other
.value_
.string_
, &other_len
, &other_str
);
3062 unsigned min_len
= std::min
<unsigned>(this_len
, other_len
);
3063 JSON_ASSERT(this_str
&& other_str
);
3064 int comp
= memcmp(this_str
, other_str
, min_len
);
3065 if (comp
< 0) return true;
3066 if (comp
> 0) return false;
3067 return (this_len
< other_len
);
3071 int delta
= int(value_
.map_
->size() - other
.value_
.map_
->size());
3074 return (*value_
.map_
) < (*other
.value_
.map_
);
3077 JSON_ASSERT_UNREACHABLE
;
3079 return false; // unreachable
3082 bool Value::operator<=(const Value
& other
) const { return !(other
< *this); }
3084 bool Value::operator>=(const Value
& other
) const { return !(*this < other
); }
3086 bool Value::operator>(const Value
& other
) const { return other
< *this; }
3088 bool Value::operator==(const Value
& other
) const {
3089 // if ( type_ != other.type_ )
3091 // attempt to take address of bit-field structure member `Json::Value::type_'
3092 // Beats me, but a temp solves the problem.
3093 int temp
= other
.type_
;
3100 return value_
.int_
== other
.value_
.int_
;
3102 return value_
.uint_
== other
.value_
.uint_
;
3104 return value_
.real_
== other
.value_
.real_
;
3106 return value_
.bool_
== other
.value_
.bool_
;
3109 if ((value_
.string_
== 0) || (other
.value_
.string_
== 0)) {
3110 return (value_
.string_
== other
.value_
.string_
);
3114 char const* this_str
;
3115 char const* other_str
;
3116 decodePrefixedString(this->allocated_
, this->value_
.string_
, &this_len
, &this_str
);
3117 decodePrefixedString(other
.allocated_
, other
.value_
.string_
, &other_len
, &other_str
);
3118 if (this_len
!= other_len
) return false;
3119 JSON_ASSERT(this_str
&& other_str
);
3120 int comp
= memcmp(this_str
, other_str
, this_len
);
3125 return value_
.map_
->size() == other
.value_
.map_
->size() &&
3126 (*value_
.map_
) == (*other
.value_
.map_
);
3128 JSON_ASSERT_UNREACHABLE
;
3130 return false; // unreachable
3133 bool Value::operator!=(const Value
& other
) const { return !(*this == other
); }
3135 const char* Value::asCString() const {
3136 JSON_ASSERT_MESSAGE(type_
== stringValue
,
3137 "in Json::Value::asCString(): requires stringValue");
3138 if (value_
.string_
== 0) return 0;
3140 char const* this_str
;
3141 decodePrefixedString(this->allocated_
, this->value_
.string_
, &this_len
, &this_str
);
3145 #if JSONCPP_USING_SECURE_MEMORY
3146 unsigned Value::getCStringLength() const {
3147 JSON_ASSERT_MESSAGE(type_
== stringValue
,
3148 "in Json::Value::asCString(): requires stringValue");
3149 if (value_
.string_
== 0) return 0;
3151 char const* this_str
;
3152 decodePrefixedString(this->allocated_
, this->value_
.string_
, &this_len
, &this_str
);
3157 bool Value::getString(char const** str
, char const** cend
) const {
3158 if (type_
!= stringValue
) return false;
3159 if (value_
.string_
== 0) return false;
3161 decodePrefixedString(this->allocated_
, this->value_
.string_
, &length
, str
);
3162 *cend
= *str
+ length
;
3166 JSONCPP_STRING
Value::asString() const {
3172 if (value_
.string_
== 0) return "";
3174 char const* this_str
;
3175 decodePrefixedString(this->allocated_
, this->value_
.string_
, &this_len
, &this_str
);
3176 return JSONCPP_STRING(this_str
, this_len
);
3179 return value_
.bool_
? "true" : "false";
3181 return valueToString(value_
.int_
);
3183 return valueToString(value_
.uint_
);
3185 return valueToString(value_
.real_
);
3187 JSON_FAIL_MESSAGE("Type is not convertible to string");
3191 #ifdef JSON_USE_CPPTL
3192 CppTL::ConstString
Value::asConstString() const {
3195 decodePrefixedString(allocated_
, value_
.string_
,
3197 return CppTL::ConstString(str
, len
);
3201 Value::Int
Value::asInt() const {
3204 JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
3205 return Int(value_
.int_
);
3207 JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
3208 return Int(value_
.uint_
);
3210 JSON_ASSERT_MESSAGE(InRange(value_
.real_
, minInt
, maxInt
),
3211 "double out of Int range");
3212 return Int(value_
.real_
);
3216 return value_
.bool_
? 1 : 0;
3220 JSON_FAIL_MESSAGE("Value is not convertible to Int.");
3223 Value::UInt
Value::asUInt() const {
3226 JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
3227 return UInt(value_
.int_
);
3229 JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
3230 return UInt(value_
.uint_
);
3232 JSON_ASSERT_MESSAGE(InRange(value_
.real_
, 0, maxUInt
),
3233 "double out of UInt range");
3234 return UInt(value_
.real_
);
3238 return value_
.bool_
? 1 : 0;
3242 JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
3245 #if defined(JSON_HAS_INT64)
3247 Value::Int64
Value::asInt64() const {
3250 return Int64(value_
.int_
);
3252 JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
3253 return Int64(value_
.uint_
);
3255 JSON_ASSERT_MESSAGE(InRange(value_
.real_
, minInt64
, maxInt64
),
3256 "double out of Int64 range");
3257 return Int64(value_
.real_
);
3261 return value_
.bool_
? 1 : 0;
3265 JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
3268 Value::UInt64
Value::asUInt64() const {
3271 JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
3272 return UInt64(value_
.int_
);
3274 return UInt64(value_
.uint_
);
3276 JSON_ASSERT_MESSAGE(InRange(value_
.real_
, 0, maxUInt64
),
3277 "double out of UInt64 range");
3278 return UInt64(value_
.real_
);
3282 return value_
.bool_
? 1 : 0;
3286 JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
3288 #endif // if defined(JSON_HAS_INT64)
3290 LargestInt
Value::asLargestInt() const {
3291 #if defined(JSON_NO_INT64)
3298 LargestUInt
Value::asLargestUInt() const {
3299 #if defined(JSON_NO_INT64)
3306 double Value::asDouble() const {
3309 return static_cast<double>(value_
.int_
);
3311 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3312 return static_cast<double>(value_
.uint_
);
3313 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3314 return integerToDouble(value_
.uint_
);
3315 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3317 return value_
.real_
;
3321 return value_
.bool_
? 1.0 : 0.0;
3325 JSON_FAIL_MESSAGE("Value is not convertible to double.");
3328 float Value::asFloat() const {
3331 return static_cast<float>(value_
.int_
);
3333 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3334 return static_cast<float>(value_
.uint_
);
3335 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3336 // This can fail (silently?) if the value is bigger than MAX_FLOAT.
3337 return static_cast<float>(integerToDouble(value_
.uint_
));
3338 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3340 return static_cast<float>(value_
.real_
);
3344 return value_
.bool_
? 1.0f
: 0.0f
;
3348 JSON_FAIL_MESSAGE("Value is not convertible to float.");
3351 bool Value::asBool() const {
3354 return value_
.bool_
;
3358 return value_
.int_
? true : false;
3360 return value_
.uint_
? true : false;
3362 // This is kind of strange. Not recommended.
3363 return (value_
.real_
!= 0.0) ? true : false;
3367 JSON_FAIL_MESSAGE("Value is not convertible to bool.");
3370 bool Value::isConvertibleTo(ValueType other
) const {
3373 return (isNumeric() && asDouble() == 0.0) ||
3374 (type_
== booleanValue
&& value_
.bool_
== false) ||
3375 (type_
== stringValue
&& asString().empty()) ||
3376 (type_
== arrayValue
&& value_
.map_
->size() == 0) ||
3377 (type_
== objectValue
&& value_
.map_
->size() == 0) ||
3381 (type_
== realValue
&& InRange(value_
.real_
, minInt
, maxInt
)) ||
3382 type_
== booleanValue
|| type_
== nullValue
;
3385 (type_
== realValue
&& InRange(value_
.real_
, 0, maxUInt
)) ||
3386 type_
== booleanValue
|| type_
== nullValue
;
3388 return isNumeric() || type_
== booleanValue
|| type_
== nullValue
;
3390 return isNumeric() || type_
== booleanValue
|| type_
== nullValue
;
3392 return isNumeric() || type_
== booleanValue
|| type_
== stringValue
||
3395 return type_
== arrayValue
|| type_
== nullValue
;
3397 return type_
== objectValue
|| type_
== nullValue
;
3399 JSON_ASSERT_UNREACHABLE
;
3403 /// Number of values in array or object
3404 ArrayIndex
Value::size() const {
3413 case arrayValue
: // size of the array is highest index + 1
3414 if (!value_
.map_
->empty()) {
3415 ObjectValues::const_iterator itLast
= value_
.map_
->end();
3417 return (*itLast
).first
.index() + 1;
3421 return ArrayIndex(value_
.map_
->size());
3423 JSON_ASSERT_UNREACHABLE
;
3424 return 0; // unreachable;
3427 bool Value::empty() const {
3428 if (isNull() || isArray() || isObject())
3429 return size() == 0u;
3434 Value::operator bool() const { return ! isNull(); }
3436 void Value::clear() {
3437 JSON_ASSERT_MESSAGE(type_
== nullValue
|| type_
== arrayValue
||
3438 type_
== objectValue
,
3439 "in Json::Value::clear(): requires complex value");
3445 value_
.map_
->clear();
3452 void Value::resize(ArrayIndex newSize
) {
3453 JSON_ASSERT_MESSAGE(type_
== nullValue
|| type_
== arrayValue
,
3454 "in Json::Value::resize(): requires arrayValue");
3455 if (type_
== nullValue
)
3456 *this = Value(arrayValue
);
3457 ArrayIndex oldSize
= size();
3460 else if (newSize
> oldSize
)
3461 (*this)[newSize
- 1];
3463 for (ArrayIndex index
= newSize
; index
< oldSize
; ++index
) {
3464 value_
.map_
->erase(index
);
3466 JSON_ASSERT(size() == newSize
);
3470 Value
& Value::operator[](ArrayIndex index
) {
3471 JSON_ASSERT_MESSAGE(
3472 type_
== nullValue
|| type_
== arrayValue
,
3473 "in Json::Value::operator[](ArrayIndex): requires arrayValue");
3474 if (type_
== nullValue
)
3475 *this = Value(arrayValue
);
3476 CZString
key(index
);
3477 ObjectValues::iterator it
= value_
.map_
->lower_bound(key
);
3478 if (it
!= value_
.map_
->end() && (*it
).first
== key
)
3479 return (*it
).second
;
3481 ObjectValues::value_type
defaultValue(key
, nullSingleton());
3482 it
= value_
.map_
->insert(it
, defaultValue
);
3483 return (*it
).second
;
3486 Value
& Value::operator[](int index
) {
3487 JSON_ASSERT_MESSAGE(
3489 "in Json::Value::operator[](int index): index cannot be negative");
3490 return (*this)[ArrayIndex(index
)];
3493 const Value
& Value::operator[](ArrayIndex index
) const {
3494 JSON_ASSERT_MESSAGE(
3495 type_
== nullValue
|| type_
== arrayValue
,
3496 "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
3497 if (type_
== nullValue
)
3498 return nullSingleton();
3499 CZString
key(index
);
3500 ObjectValues::const_iterator it
= value_
.map_
->find(key
);
3501 if (it
== value_
.map_
->end())
3502 return nullSingleton();
3503 return (*it
).second
;
3506 const Value
& Value::operator[](int index
) const {
3507 JSON_ASSERT_MESSAGE(
3509 "in Json::Value::operator[](int index) const: index cannot be negative");
3510 return (*this)[ArrayIndex(index
)];
3513 void Value::initBasic(ValueType vtype
, bool allocated
) {
3515 allocated_
= allocated
;
3521 // Access an object value by name, create a null member if it does not exist.
3522 // @pre Type of '*this' is object or null.
3523 // @param key is null-terminated.
3524 Value
& Value::resolveReference(const char* key
) {
3525 JSON_ASSERT_MESSAGE(
3526 type_
== nullValue
|| type_
== objectValue
,
3527 "in Json::Value::resolveReference(): requires objectValue");
3528 if (type_
== nullValue
)
3529 *this = Value(objectValue
);
3531 key
, static_cast<unsigned>(strlen(key
)), CZString::noDuplication
); // NOTE!
3532 ObjectValues::iterator it
= value_
.map_
->lower_bound(actualKey
);
3533 if (it
!= value_
.map_
->end() && (*it
).first
== actualKey
)
3534 return (*it
).second
;
3536 ObjectValues::value_type
defaultValue(actualKey
, nullSingleton());
3537 it
= value_
.map_
->insert(it
, defaultValue
);
3538 Value
& value
= (*it
).second
;
3542 // @param key is not null-terminated.
3543 Value
& Value::resolveReference(char const* key
, char const* cend
)
3545 JSON_ASSERT_MESSAGE(
3546 type_
== nullValue
|| type_
== objectValue
,
3547 "in Json::Value::resolveReference(key, end): requires objectValue");
3548 if (type_
== nullValue
)
3549 *this = Value(objectValue
);
3551 key
, static_cast<unsigned>(cend
-key
), CZString::duplicateOnCopy
);
3552 ObjectValues::iterator it
= value_
.map_
->lower_bound(actualKey
);
3553 if (it
!= value_
.map_
->end() && (*it
).first
== actualKey
)
3554 return (*it
).second
;
3556 ObjectValues::value_type
defaultValue(actualKey
, nullSingleton());
3557 it
= value_
.map_
->insert(it
, defaultValue
);
3558 Value
& value
= (*it
).second
;
3562 Value
Value::get(ArrayIndex index
, const Value
& defaultValue
) const {
3563 const Value
* value
= &((*this)[index
]);
3564 return value
== &nullSingleton() ? defaultValue
: *value
;
3567 bool Value::isValidIndex(ArrayIndex index
) const { return index
< size(); }
3569 Value
const* Value::find(char const* key
, char const* cend
) const
3571 JSON_ASSERT_MESSAGE(
3572 type_
== nullValue
|| type_
== objectValue
,
3573 "in Json::Value::find(key, end, found): requires objectValue or nullValue");
3574 if (type_
== nullValue
) return NULL
;
3575 CZString
actualKey(key
, static_cast<unsigned>(cend
-key
), CZString::noDuplication
);
3576 ObjectValues::const_iterator it
= value_
.map_
->find(actualKey
);
3577 if (it
== value_
.map_
->end()) return NULL
;
3578 return &(*it
).second
;
3580 const Value
& Value::operator[](const char* key
) const
3582 Value
const* found
= find(key
, key
+ strlen(key
));
3583 if (!found
) return nullSingleton();
3586 Value
const& Value::operator[](JSONCPP_STRING
const& key
) const
3588 Value
const* found
= find(key
.data(), key
.data() + key
.length());
3589 if (!found
) return nullSingleton();
3593 Value
& Value::operator[](const char* key
) {
3594 return resolveReference(key
, key
+ strlen(key
));
3597 Value
& Value::operator[](const JSONCPP_STRING
& key
) {
3598 return resolveReference(key
.data(), key
.data() + key
.length());
3601 Value
& Value::operator[](const StaticString
& key
) {
3602 return resolveReference(key
.c_str());
3605 #ifdef JSON_USE_CPPTL
3606 Value
& Value::operator[](const CppTL::ConstString
& key
) {
3607 return resolveReference(key
.c_str(), key
.end_c_str());
3609 Value
const& Value::operator[](CppTL::ConstString
const& key
) const
3611 Value
const* found
= find(key
.c_str(), key
.end_c_str());
3612 if (!found
) return nullSingleton();
3617 Value
& Value::append(const Value
& value
) { return (*this)[size()] = value
; }
3619 #if JSON_HAS_RVALUE_REFERENCES
3620 Value
& Value::append(Value
&& value
) { return (*this)[size()] = std::move(value
); }
3623 Value
Value::get(char const* key
, char const* cend
, Value
const& defaultValue
) const
3625 Value
const* found
= find(key
, cend
);
3626 return !found
? defaultValue
: *found
;
3628 Value
Value::get(char const* key
, Value
const& defaultValue
) const
3630 return get(key
, key
+ strlen(key
), defaultValue
);
3632 Value
Value::get(JSONCPP_STRING
const& key
, Value
const& defaultValue
) const
3634 return get(key
.data(), key
.data() + key
.length(), defaultValue
);
3638 bool Value::removeMember(const char* key
, const char* cend
, Value
* removed
)
3640 if (type_
!= objectValue
) {
3643 CZString
actualKey(key
, static_cast<unsigned>(cend
-key
), CZString::noDuplication
);
3644 ObjectValues::iterator it
= value_
.map_
->find(actualKey
);
3645 if (it
== value_
.map_
->end())
3647 *removed
= it
->second
;
3648 value_
.map_
->erase(it
);
3651 bool Value::removeMember(const char* key
, Value
* removed
)
3653 return removeMember(key
, key
+ strlen(key
), removed
);
3655 bool Value::removeMember(JSONCPP_STRING
const& key
, Value
* removed
)
3657 return removeMember(key
.data(), key
.data() + key
.length(), removed
);
3659 void Value::removeMember(const char* key
)
3661 JSON_ASSERT_MESSAGE(type_
== nullValue
|| type_
== objectValue
,
3662 "in Json::Value::removeMember(): requires objectValue");
3663 if (type_
== nullValue
)
3666 CZString
actualKey(key
, unsigned(strlen(key
)), CZString::noDuplication
);
3667 value_
.map_
->erase(actualKey
);
3669 void Value::removeMember(const JSONCPP_STRING
& key
)
3671 removeMember(key
.c_str());
3674 bool Value::removeIndex(ArrayIndex index
, Value
* removed
) {
3675 if (type_
!= arrayValue
) {
3678 CZString
key(index
);
3679 ObjectValues::iterator it
= value_
.map_
->find(key
);
3680 if (it
== value_
.map_
->end()) {
3683 *removed
= it
->second
;
3684 ArrayIndex oldSize
= size();
3685 // shift left all items left, into the place of the "removed"
3686 for (ArrayIndex i
= index
; i
< (oldSize
- 1); ++i
){
3688 (*value_
.map_
)[keey
] = (*this)[i
+ 1];
3690 // erase the last one ("leftover")
3691 CZString
keyLast(oldSize
- 1);
3692 ObjectValues::iterator itLast
= value_
.map_
->find(keyLast
);
3693 value_
.map_
->erase(itLast
);
3697 #ifdef JSON_USE_CPPTL
3698 Value
Value::get(const CppTL::ConstString
& key
,
3699 const Value
& defaultValue
) const {
3700 return get(key
.c_str(), key
.end_c_str(), defaultValue
);
3704 bool Value::isMember(char const* key
, char const* cend
) const
3706 Value
const* value
= find(key
, cend
);
3707 return NULL
!= value
;
3709 bool Value::isMember(char const* key
) const
3711 return isMember(key
, key
+ strlen(key
));
3713 bool Value::isMember(JSONCPP_STRING
const& key
) const
3715 return isMember(key
.data(), key
.data() + key
.length());
3718 #ifdef JSON_USE_CPPTL
3719 bool Value::isMember(const CppTL::ConstString
& key
) const {
3720 return isMember(key
.c_str(), key
.end_c_str());
3724 Value::Members
Value::getMemberNames() const {
3725 JSON_ASSERT_MESSAGE(
3726 type_
== nullValue
|| type_
== objectValue
,
3727 "in Json::Value::getMemberNames(), value must be objectValue");
3728 if (type_
== nullValue
)
3729 return Value::Members();
3731 members
.reserve(value_
.map_
->size());
3732 ObjectValues::const_iterator it
= value_
.map_
->begin();
3733 ObjectValues::const_iterator itEnd
= value_
.map_
->end();
3734 for (; it
!= itEnd
; ++it
) {
3735 members
.push_back(JSONCPP_STRING((*it
).first
.data(),
3736 (*it
).first
.length()));
3741 //# ifdef JSON_USE_CPPTL
3743 // Value::enumMemberNames() const
3745 // if ( type_ == objectValue )
3747 // return CppTL::Enum::any( CppTL::Enum::transform(
3748 // CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
3749 // MemberNamesTransform() ) );
3751 // return EnumMemberNames();
3756 // Value::enumValues() const
3758 // if ( type_ == objectValue || type_ == arrayValue )
3759 // return CppTL::Enum::anyValues( *(value_.map_),
3760 // CppTL::Type<const Value &>() );
3761 // return EnumValues();
3766 static bool IsIntegral(double d
) {
3767 double integral_part
;
3768 return modf(d
, &integral_part
) == 0.0;
3771 bool Value::isNull() const { return type_
== nullValue
; }
3773 bool Value::isBool() const { return type_
== booleanValue
; }
3775 bool Value::isInt() const {
3778 #if defined(JSON_HAS_INT64)
3779 return value_
.int_
>= minInt
&& value_
.int_
<= maxInt
;
3784 return value_
.uint_
<= UInt(maxInt
);
3786 return value_
.real_
>= minInt
&& value_
.real_
<= maxInt
&&
3787 IsIntegral(value_
.real_
);
3794 bool Value::isUInt() const {
3797 #if defined(JSON_HAS_INT64)
3798 return value_
.int_
>= 0 && LargestUInt(value_
.int_
) <= LargestUInt(maxUInt
);
3800 return value_
.int_
>= 0;
3803 #if defined(JSON_HAS_INT64)
3804 return value_
.uint_
<= maxUInt
;
3809 return value_
.real_
>= 0 && value_
.real_
<= maxUInt
&&
3810 IsIntegral(value_
.real_
);
3817 bool Value::isInt64() const {
3818 #if defined(JSON_HAS_INT64)
3823 return value_
.uint_
<= UInt64(maxInt64
);
3825 // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
3826 // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
3827 // require the value to be strictly less than the limit.
3828 return value_
.real_
>= double(minInt64
) &&
3829 value_
.real_
< double(maxInt64
) && IsIntegral(value_
.real_
);
3833 #endif // JSON_HAS_INT64
3837 bool Value::isUInt64() const {
3838 #if defined(JSON_HAS_INT64)
3841 return value_
.int_
>= 0;
3845 // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
3846 // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
3847 // require the value to be strictly less than the limit.
3848 return value_
.real_
>= 0 && value_
.real_
< maxUInt64AsDouble
&&
3849 IsIntegral(value_
.real_
);
3853 #endif // JSON_HAS_INT64
3857 bool Value::isIntegral() const {
3863 #if defined(JSON_HAS_INT64)
3864 // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
3865 // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
3866 // require the value to be strictly less than the limit.
3867 return value_
.real_
>= double(minInt64
) && value_
.real_
< maxUInt64AsDouble
&& IsIntegral(value_
.real_
);
3869 return value_
.real_
>= minInt
&& value_
.real_
<= maxUInt
&& IsIntegral(value_
.real_
);
3870 #endif // JSON_HAS_INT64
3877 bool Value::isDouble() const { return type_
== intValue
|| type_
== uintValue
|| type_
== realValue
; }
3879 bool Value::isNumeric() const { return isDouble(); }
3881 bool Value::isString() const { return type_
== stringValue
; }
3883 bool Value::isArray() const { return type_
== arrayValue
; }
3885 bool Value::isObject() const { return type_
== objectValue
; }
3887 void Value::setComment(const char* comment
, size_t len
, CommentPlacement placement
) {
3889 comments_
= new CommentInfo
[numberOfCommentPlacement
];
3890 if ((len
> 0) && (comment
[len
-1] == '\n')) {
3891 // Always discard trailing newline, to aid indentation.
3894 comments_
[placement
].setComment(comment
, len
);
3897 void Value::setComment(const char* comment
, CommentPlacement placement
) {
3898 setComment(comment
, strlen(comment
), placement
);
3901 void Value::setComment(const JSONCPP_STRING
& comment
, CommentPlacement placement
) {
3902 setComment(comment
.c_str(), comment
.length(), placement
);
3905 bool Value::hasComment(CommentPlacement placement
) const {
3906 return comments_
!= 0 && comments_
[placement
].comment_
!= 0;
3909 JSONCPP_STRING
Value::getComment(CommentPlacement placement
) const {
3910 if (hasComment(placement
))
3911 return comments_
[placement
].comment_
;
3915 void Value::setOffsetStart(ptrdiff_t start
) { start_
= start
; }
3917 void Value::setOffsetLimit(ptrdiff_t limit
) { limit_
= limit
; }
3919 ptrdiff_t Value::getOffsetStart() const { return start_
; }
3921 ptrdiff_t Value::getOffsetLimit() const { return limit_
; }
3923 JSONCPP_STRING
Value::toStyledString() const {
3924 StreamWriterBuilder builder
;
3926 JSONCPP_STRING out
= this->hasComment(commentBefore
) ? "\n" : "";
3927 out
+= Json::writeString(builder
, *this);
3933 Value::const_iterator
Value::begin() const {
3938 return const_iterator(value_
.map_
->begin());
3943 return const_iterator();
3946 Value::const_iterator
Value::end() const {
3951 return const_iterator(value_
.map_
->end());
3956 return const_iterator();
3959 Value::iterator
Value::begin() {
3964 return iterator(value_
.map_
->begin());
3972 Value::iterator
Value::end() {
3977 return iterator(value_
.map_
->end());
3985 // class PathArgument
3986 // //////////////////////////////////////////////////////////////////
3988 PathArgument::PathArgument() : key_(), index_(), kind_(kindNone
) {}
3990 PathArgument::PathArgument(ArrayIndex index
)
3991 : key_(), index_(index
), kind_(kindIndex
) {}
3993 PathArgument::PathArgument(const char* key
)
3994 : key_(key
), index_(), kind_(kindKey
) {}
3996 PathArgument::PathArgument(const JSONCPP_STRING
& key
)
3997 : key_(key
.c_str()), index_(), kind_(kindKey
) {}
4000 // //////////////////////////////////////////////////////////////////
4002 Path::Path(const JSONCPP_STRING
& path
,
4003 const PathArgument
& a1
,
4004 const PathArgument
& a2
,
4005 const PathArgument
& a3
,
4006 const PathArgument
& a4
,
4007 const PathArgument
& a5
) {
4018 void Path::makePath(const JSONCPP_STRING
& path
, const InArgs
& in
) {
4019 const char* current
= path
.c_str();
4020 const char* end
= current
+ path
.length();
4021 InArgs::const_iterator itInArg
= in
.begin();
4022 while (current
!= end
) {
4023 if (*current
== '[') {
4025 if (*current
== '%')
4026 addPathInArg(path
, in
, itInArg
, PathArgument::kindIndex
);
4028 ArrayIndex index
= 0;
4029 for (; current
!= end
&& *current
>= '0' && *current
<= '9'; ++current
)
4030 index
= index
* 10 + ArrayIndex(*current
- '0');
4031 args_
.push_back(index
);
4033 if (current
== end
|| *++current
!= ']')
4034 invalidPath(path
, int(current
- path
.c_str()));
4035 } else if (*current
== '%') {
4036 addPathInArg(path
, in
, itInArg
, PathArgument::kindKey
);
4038 } else if (*current
== '.' || *current
== ']') {
4041 const char* beginName
= current
;
4042 while (current
!= end
&& !strchr("[.", *current
))
4044 args_
.push_back(JSONCPP_STRING(beginName
, current
));
4049 void Path::addPathInArg(const JSONCPP_STRING
& /*path*/,
4051 InArgs::const_iterator
& itInArg
,
4052 PathArgument::Kind kind
) {
4053 if (itInArg
== in
.end()) {
4054 // Error: missing argument %d
4055 } else if ((*itInArg
)->kind_
!= kind
) {
4056 // Error: bad argument type
4058 args_
.push_back(**itInArg
++);
4062 void Path::invalidPath(const JSONCPP_STRING
& /*path*/, int /*location*/) {
4063 // Error: invalid path.
4066 const Value
& Path::resolve(const Value
& root
) const {
4067 const Value
* node
= &root
;
4068 for (Args::const_iterator it
= args_
.begin(); it
!= args_
.end(); ++it
) {
4069 const PathArgument
& arg
= *it
;
4070 if (arg
.kind_
== PathArgument::kindIndex
) {
4071 if (!node
->isArray() || !node
->isValidIndex(arg
.index_
)) {
4072 // Error: unable to resolve path (array value expected at position...
4075 node
= &((*node
)[arg
.index_
]);
4076 } else if (arg
.kind_
== PathArgument::kindKey
) {
4077 if (!node
->isObject()) {
4078 // Error: unable to resolve path (object value expected at position...)
4081 node
= &((*node
)[arg
.key_
]);
4082 if (node
== &Value::nullSingleton()) {
4083 // Error: unable to resolve path (object has no member named '' at
4092 Value
Path::resolve(const Value
& root
, const Value
& defaultValue
) const {
4093 const Value
* node
= &root
;
4094 for (Args::const_iterator it
= args_
.begin(); it
!= args_
.end(); ++it
) {
4095 const PathArgument
& arg
= *it
;
4096 if (arg
.kind_
== PathArgument::kindIndex
) {
4097 if (!node
->isArray() || !node
->isValidIndex(arg
.index_
))
4098 return defaultValue
;
4099 node
= &((*node
)[arg
.index_
]);
4100 } else if (arg
.kind_
== PathArgument::kindKey
) {
4101 if (!node
->isObject())
4102 return defaultValue
;
4103 node
= &((*node
)[arg
.key_
]);
4104 if (node
== &Value::nullSingleton())
4105 return defaultValue
;
4111 Value
& Path::make(Value
& root
) const {
4112 Value
* node
= &root
;
4113 for (Args::const_iterator it
= args_
.begin(); it
!= args_
.end(); ++it
) {
4114 const PathArgument
& arg
= *it
;
4115 if (arg
.kind_
== PathArgument::kindIndex
) {
4116 if (!node
->isArray()) {
4117 // Error: node is not an array at position ...
4119 node
= &((*node
)[arg
.index_
]);
4120 } else if (arg
.kind_
== PathArgument::kindKey
) {
4121 if (!node
->isObject()) {
4122 // Error: node is not an object at position...
4124 node
= &((*node
)[arg
.key_
]);
4132 // //////////////////////////////////////////////////////////////////////
4133 // End of content of file: src/lib_json/json_value.cpp
4134 // //////////////////////////////////////////////////////////////////////
4141 // //////////////////////////////////////////////////////////////////////
4142 // Beginning of content of file: src/lib_json/json_writer.cpp
4143 // //////////////////////////////////////////////////////////////////////
4145 // Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
4146 // Distributed under MIT license, or public domain if desired and
4147 // recognized in your jurisdiction.
4148 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
4150 #if !defined(JSON_IS_AMALGAMATION)
4151 #include <json/writer.h>
4152 #include "json_tool.h"
4153 #endif // if !defined(JSON_IS_AMALGAMATION)
4163 #if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0
4165 #define isfinite _finite
4166 #elif defined(__sun) && defined(__SVR4) //Solaris
4167 #if !defined(isfinite)
4169 #define isfinite finite
4172 #if !defined(isfinite)
4174 #define isfinite finite
4176 #elif defined(__hpux)
4177 #if !defined(isfinite)
4178 #if defined(__ia64) && !defined(finite)
4179 #define isfinite(x) ((sizeof(x) == sizeof(float) ? \
4180 _Isfinitef(x) : _IsFinite(x)))
4183 #define isfinite finite
4188 #if !(defined(__QNXNTO__)) // QNX already defines isfinite
4189 #define isfinite std::isfinite
4193 #if defined(_MSC_VER)
4194 #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
4195 #define snprintf sprintf_s
4196 #elif _MSC_VER >= 1900 // VC++ 14.0 and above
4197 #define snprintf std::snprintf
4199 #define snprintf _snprintf
4201 #elif defined(__ANDROID__) || defined(__QNXNTO__)
4202 #define snprintf snprintf
4203 #elif __cplusplus >= 201103L
4204 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
4205 #define snprintf std::snprintf
4209 #if defined(__BORLANDC__)
4211 #define isfinite _finite
4212 #define snprintf _snprintf
4215 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
4216 // Disable warning about strdup being deprecated.
4217 #pragma warning(disable : 4996)
4222 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
4223 typedef std::unique_ptr
<StreamWriter
> StreamWriterPtr
;
4225 typedef std::auto_ptr
<StreamWriter
> StreamWriterPtr
;
4228 JSONCPP_STRING
valueToString(LargestInt value
) {
4229 UIntToStringBuffer buffer
;
4230 char* current
= buffer
+ sizeof(buffer
);
4231 if (value
== Value::minLargestInt
) {
4232 uintToString(LargestUInt(Value::maxLargestInt
) + 1, current
);
4234 } else if (value
< 0) {
4235 uintToString(LargestUInt(-value
), current
);
4238 uintToString(LargestUInt(value
), current
);
4240 assert(current
>= buffer
);
4244 JSONCPP_STRING
valueToString(LargestUInt value
) {
4245 UIntToStringBuffer buffer
;
4246 char* current
= buffer
+ sizeof(buffer
);
4247 uintToString(value
, current
);
4248 assert(current
>= buffer
);
4252 #if defined(JSON_HAS_INT64)
4254 JSONCPP_STRING
valueToString(Int value
) {
4255 return valueToString(LargestInt(value
));
4258 JSONCPP_STRING
valueToString(UInt value
) {
4259 return valueToString(LargestUInt(value
));
4262 #endif // # if defined(JSON_HAS_INT64)
4265 JSONCPP_STRING
valueToString(double value
, bool useSpecialFloats
, unsigned int precision
) {
4266 // Allocate a buffer that is more than large enough to store the 16 digits of
4267 // precision requested below.
4271 char formatString
[15];
4272 snprintf(formatString
, sizeof(formatString
), "%%.%ug", precision
);
4274 // Print into the buffer. We need not request the alternative representation
4275 // that always has a decimal point because JSON doesn't distinguish the
4276 // concepts of reals and integers.
4277 if (isfinite(value
)) {
4278 len
= snprintf(buffer
, sizeof(buffer
), formatString
, value
);
4279 fixNumericLocale(buffer
, buffer
+ len
);
4281 // try to ensure we preserve the fact that this was given to us as a double on input
4282 if (!strchr(buffer
, '.') && !strchr(buffer
, 'e')) {
4283 strcat(buffer
, ".0");
4287 // IEEE standard states that NaN values will not compare to themselves
4288 if (value
!= value
) {
4289 len
= snprintf(buffer
, sizeof(buffer
), useSpecialFloats
? "NaN" : "null");
4290 } else if (value
< 0) {
4291 len
= snprintf(buffer
, sizeof(buffer
), useSpecialFloats
? "-Infinity" : "-1e+9999");
4293 len
= snprintf(buffer
, sizeof(buffer
), useSpecialFloats
? "Infinity" : "1e+9999");
4301 JSONCPP_STRING
valueToString(double value
) { return valueToString(value
, false, 17); }
4303 JSONCPP_STRING
valueToString(bool value
) { return value
? "true" : "false"; }
4305 static bool isAnyCharRequiredQuoting(char const* s
, size_t n
) {
4308 char const* const end
= s
+ n
;
4309 for (char const* cur
= s
; cur
< end
; ++cur
) {
4310 if (*cur
== '\\' || *cur
== '\"' || *cur
< ' '
4311 || static_cast<unsigned char>(*cur
) < 0x80)
4317 static unsigned int utf8ToCodepoint(const char*& s
, const char* e
) {
4318 const unsigned int REPLACEMENT_CHARACTER
= 0xFFFD;
4320 unsigned int firstByte
= static_cast<unsigned char>(*s
);
4322 if (firstByte
< 0x80)
4325 if (firstByte
< 0xE0) {
4327 return REPLACEMENT_CHARACTER
;
4329 unsigned int calculated
= ((firstByte
& 0x1F) << 6)
4330 | (static_cast<unsigned int>(s
[1]) & 0x3F);
4332 // oversized encoded characters are invalid
4333 return calculated
< 0x80 ? REPLACEMENT_CHARACTER
: calculated
;
4336 if (firstByte
< 0xF0) {
4338 return REPLACEMENT_CHARACTER
;
4340 unsigned int calculated
= ((firstByte
& 0x0F) << 12)
4341 | ((static_cast<unsigned int>(s
[1]) & 0x3F) << 6)
4342 | (static_cast<unsigned int>(s
[2]) & 0x3F);
4344 // surrogates aren't valid codepoints itself
4345 // shouldn't be UTF-8 encoded
4346 if (calculated
>= 0xD800 && calculated
<= 0xDFFF)
4347 return REPLACEMENT_CHARACTER
;
4348 // oversized encoded characters are invalid
4349 return calculated
< 0x800 ? REPLACEMENT_CHARACTER
: calculated
;
4352 if (firstByte
< 0xF8) {
4354 return REPLACEMENT_CHARACTER
;
4356 unsigned int calculated
= ((firstByte
& 0x07) << 24)
4357 | ((static_cast<unsigned int>(s
[1]) & 0x3F) << 12)
4358 | ((static_cast<unsigned int>(s
[2]) & 0x3F) << 6)
4359 | (static_cast<unsigned int>(s
[3]) & 0x3F);
4361 // oversized encoded characters are invalid
4362 return calculated
< 0x10000 ? REPLACEMENT_CHARACTER
: calculated
;
4365 return REPLACEMENT_CHARACTER
;
4368 static const char hex2
[] =
4369 "000102030405060708090a0b0c0d0e0f"
4370 "101112131415161718191a1b1c1d1e1f"
4371 "202122232425262728292a2b2c2d2e2f"
4372 "303132333435363738393a3b3c3d3e3f"
4373 "404142434445464748494a4b4c4d4e4f"
4374 "505152535455565758595a5b5c5d5e5f"
4375 "606162636465666768696a6b6c6d6e6f"
4376 "707172737475767778797a7b7c7d7e7f"
4377 "808182838485868788898a8b8c8d8e8f"
4378 "909192939495969798999a9b9c9d9e9f"
4379 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
4380 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
4381 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
4382 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
4383 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
4384 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
4386 static JSONCPP_STRING
toHex16Bit(unsigned int x
) {
4387 const unsigned int hi
= (x
>> 8) & 0xff;
4388 const unsigned int lo
= x
& 0xff;
4389 JSONCPP_STRING
result(4, ' ');
4390 result
[0] = hex2
[2 * hi
];
4391 result
[1] = hex2
[2 * hi
+ 1];
4392 result
[2] = hex2
[2 * lo
];
4393 result
[3] = hex2
[2 * lo
+ 1];
4397 static JSONCPP_STRING
valueToQuotedStringN(const char* value
, unsigned length
) {
4401 if (!isAnyCharRequiredQuoting(value
, length
))
4402 return JSONCPP_STRING("\"") + value
+ "\"";
4403 // We have to walk value and escape any special characters.
4404 // Appending to JSONCPP_STRING is not efficient, but this should be rare.
4405 // (Note: forward slashes are *not* rare, but I am not escaping them.)
4406 JSONCPP_STRING::size_type maxsize
=
4407 length
* 2 + 3; // allescaped+quotes+NULL
4408 JSONCPP_STRING result
;
4409 result
.reserve(maxsize
); // to avoid lots of mallocs
4411 char const* end
= value
+ length
;
4412 for (const char* c
= value
; c
!= end
; ++c
) {
4436 // Even though \/ is considered a legal escape in JSON, a bare
4437 // slash is also legal, so I see no reason to escape it.
4438 // (I hope I am not misunderstanding something.)
4439 // blep notes: actually escaping \/ may be useful in javascript to avoid </
4441 // Should add a flag to allow this compatibility mode and prevent this
4442 // sequence from occurring.
4444 unsigned int cp
= utf8ToCodepoint(c
, end
);
4445 // don't escape non-control characters
4446 // (short escape sequence are applied above)
4447 if (cp
< 0x80 && cp
>= 0x20)
4448 result
+= static_cast<char>(cp
);
4449 else if (cp
< 0x10000) { // codepoint is in Basic Multilingual Plane
4451 result
+= toHex16Bit(cp
);
4453 else { // codepoint is not in Basic Multilingual Plane
4454 // convert to surrogate pair first
4457 result
+= toHex16Bit((cp
>> 10) + 0xD800);
4459 result
+= toHex16Bit((cp
& 0x3FF) + 0xDC00);
4469 JSONCPP_STRING
valueToQuotedString(const char* value
) {
4470 return valueToQuotedStringN(value
, static_cast<unsigned int>(strlen(value
)));
4474 // //////////////////////////////////////////////////////////////////
4475 Writer::~Writer() {}
4478 // //////////////////////////////////////////////////////////////////
4480 FastWriter::FastWriter()
4481 : yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false),
4482 omitEndingLineFeed_(false) {}
4484 void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_
= true; }
4486 void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_
= true; }
4488 void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_
= true; }
4490 JSONCPP_STRING
FastWriter::write(const Value
& root
) {
4493 if (!omitEndingLineFeed_
)
4498 void FastWriter::writeValue(const Value
& value
) {
4499 switch (value
.type()) {
4501 if (!dropNullPlaceholders_
)
4502 document_
+= "null";
4505 document_
+= valueToString(value
.asLargestInt());
4508 document_
+= valueToString(value
.asLargestUInt());
4511 document_
+= valueToString(value
.asDouble());
4515 // Is NULL possible for value.string_? No.
4518 bool ok
= value
.getString(&str
, &end
);
4519 if (ok
) document_
+= valueToQuotedStringN(str
, static_cast<unsigned>(end
-str
));
4523 document_
+= valueToString(value
.asBool());
4527 ArrayIndex size
= value
.size();
4528 for (ArrayIndex index
= 0; index
< size
; ++index
) {
4531 writeValue(value
[index
]);
4536 Value::Members
members(value
.getMemberNames());
4538 for (Value::Members::iterator it
= members
.begin(); it
!= members
.end();
4540 const JSONCPP_STRING
& name
= *it
;
4541 if (it
!= members
.begin())
4543 document_
+= valueToQuotedStringN(name
.data(), static_cast<unsigned>(name
.length()));
4544 document_
+= yamlCompatibilityEnabled_
? ": " : ":";
4545 writeValue(value
[name
]);
4552 // Class StyledWriter
4553 // //////////////////////////////////////////////////////////////////
4555 StyledWriter::StyledWriter()
4556 : rightMargin_(74), indentSize_(3), addChildValues_() {}
4558 JSONCPP_STRING
StyledWriter::write(const Value
& root
) {
4560 addChildValues_
= false;
4561 indentString_
.clear();
4562 writeCommentBeforeValue(root
);
4564 writeCommentAfterValueOnSameLine(root
);
4569 void StyledWriter::writeValue(const Value
& value
) {
4570 switch (value
.type()) {
4575 pushValue(valueToString(value
.asLargestInt()));
4578 pushValue(valueToString(value
.asLargestUInt()));
4581 pushValue(valueToString(value
.asDouble()));
4585 // Is NULL possible for value.string_? No.
4588 bool ok
= value
.getString(&str
, &end
);
4589 if (ok
) pushValue(valueToQuotedStringN(str
, static_cast<unsigned>(end
-str
)));
4594 pushValue(valueToString(value
.asBool()));
4597 writeArrayValue(value
);
4600 Value::Members
members(value
.getMemberNames());
4601 if (members
.empty())
4604 writeWithIndent("{");
4606 Value::Members::iterator it
= members
.begin();
4608 const JSONCPP_STRING
& name
= *it
;
4609 const Value
& childValue
= value
[name
];
4610 writeCommentBeforeValue(childValue
);
4611 writeWithIndent(valueToQuotedString(name
.c_str()));
4613 writeValue(childValue
);
4614 if (++it
== members
.end()) {
4615 writeCommentAfterValueOnSameLine(childValue
);
4619 writeCommentAfterValueOnSameLine(childValue
);
4622 writeWithIndent("}");
4628 void StyledWriter::writeArrayValue(const Value
& value
) {
4629 unsigned size
= value
.size();
4633 bool isArrayMultiLine
= isMultilineArray(value
);
4634 if (isArrayMultiLine
) {
4635 writeWithIndent("[");
4637 bool hasChildValue
= !childValues_
.empty();
4640 const Value
& childValue
= value
[index
];
4641 writeCommentBeforeValue(childValue
);
4643 writeWithIndent(childValues_
[index
]);
4646 writeValue(childValue
);
4648 if (++index
== size
) {
4649 writeCommentAfterValueOnSameLine(childValue
);
4653 writeCommentAfterValueOnSameLine(childValue
);
4656 writeWithIndent("]");
4657 } else // output on a single line
4659 assert(childValues_
.size() == size
);
4661 for (unsigned index
= 0; index
< size
; ++index
) {
4664 document_
+= childValues_
[index
];
4671 bool StyledWriter::isMultilineArray(const Value
& value
) {
4672 ArrayIndex
const size
= value
.size();
4673 bool isMultiLine
= size
* 3 >= rightMargin_
;
4674 childValues_
.clear();
4675 for (ArrayIndex index
= 0; index
< size
&& !isMultiLine
; ++index
) {
4676 const Value
& childValue
= value
[index
];
4677 isMultiLine
= ((childValue
.isArray() || childValue
.isObject()) &&
4678 childValue
.size() > 0);
4680 if (!isMultiLine
) // check if line length > max line length
4682 childValues_
.reserve(size
);
4683 addChildValues_
= true;
4684 ArrayIndex lineLength
= 4 + (size
- 1) * 2; // '[ ' + ', '*n + ' ]'
4685 for (ArrayIndex index
= 0; index
< size
; ++index
) {
4686 if (hasCommentForValue(value
[index
])) {
4689 writeValue(value
[index
]);
4690 lineLength
+= static_cast<ArrayIndex
>(childValues_
[index
].length());
4692 addChildValues_
= false;
4693 isMultiLine
= isMultiLine
|| lineLength
>= rightMargin_
;
4698 void StyledWriter::pushValue(const JSONCPP_STRING
& value
) {
4699 if (addChildValues_
)
4700 childValues_
.push_back(value
);
4705 void StyledWriter::writeIndent() {
4706 if (!document_
.empty()) {
4707 char last
= document_
[document_
.length() - 1];
4708 if (last
== ' ') // already indented
4710 if (last
!= '\n') // Comments may add new-line
4713 document_
+= indentString_
;
4716 void StyledWriter::writeWithIndent(const JSONCPP_STRING
& value
) {
4721 void StyledWriter::indent() { indentString_
+= JSONCPP_STRING(indentSize_
, ' '); }
4723 void StyledWriter::unindent() {
4724 assert(indentString_
.size() >= indentSize_
);
4725 indentString_
.resize(indentString_
.size() - indentSize_
);
4728 void StyledWriter::writeCommentBeforeValue(const Value
& root
) {
4729 if (!root
.hasComment(commentBefore
))
4734 const JSONCPP_STRING
& comment
= root
.getComment(commentBefore
);
4735 JSONCPP_STRING::const_iterator iter
= comment
.begin();
4736 while (iter
!= comment
.end()) {
4738 if (*iter
== '\n' &&
4739 ((iter
+1) != comment
.end() && *(iter
+ 1) == '/'))
4744 // Comments are stripped of trailing newlines, so add one here
4748 void StyledWriter::writeCommentAfterValueOnSameLine(const Value
& root
) {
4749 if (root
.hasComment(commentAfterOnSameLine
))
4750 document_
+= " " + root
.getComment(commentAfterOnSameLine
);
4752 if (root
.hasComment(commentAfter
)) {
4754 document_
+= root
.getComment(commentAfter
);
4759 bool StyledWriter::hasCommentForValue(const Value
& value
) {
4760 return value
.hasComment(commentBefore
) ||
4761 value
.hasComment(commentAfterOnSameLine
) ||
4762 value
.hasComment(commentAfter
);
4765 // Class StyledStreamWriter
4766 // //////////////////////////////////////////////////////////////////
4768 StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation
)
4769 : document_(NULL
), rightMargin_(74), indentation_(indentation
),
4770 addChildValues_() {}
4772 void StyledStreamWriter::write(JSONCPP_OSTREAM
& out
, const Value
& root
) {
4774 addChildValues_
= false;
4775 indentString_
.clear();
4777 writeCommentBeforeValue(root
);
4778 if (!indented_
) writeIndent();
4781 writeCommentAfterValueOnSameLine(root
);
4783 document_
= NULL
; // Forget the stream, for safety.
4786 void StyledStreamWriter::writeValue(const Value
& value
) {
4787 switch (value
.type()) {
4792 pushValue(valueToString(value
.asLargestInt()));
4795 pushValue(valueToString(value
.asLargestUInt()));
4798 pushValue(valueToString(value
.asDouble()));
4802 // Is NULL possible for value.string_? No.
4805 bool ok
= value
.getString(&str
, &end
);
4806 if (ok
) pushValue(valueToQuotedStringN(str
, static_cast<unsigned>(end
-str
)));
4811 pushValue(valueToString(value
.asBool()));
4814 writeArrayValue(value
);
4817 Value::Members
members(value
.getMemberNames());
4818 if (members
.empty())
4821 writeWithIndent("{");
4823 Value::Members::iterator it
= members
.begin();
4825 const JSONCPP_STRING
& name
= *it
;
4826 const Value
& childValue
= value
[name
];
4827 writeCommentBeforeValue(childValue
);
4828 writeWithIndent(valueToQuotedString(name
.c_str()));
4829 *document_
<< " : ";
4830 writeValue(childValue
);
4831 if (++it
== members
.end()) {
4832 writeCommentAfterValueOnSameLine(childValue
);
4836 writeCommentAfterValueOnSameLine(childValue
);
4839 writeWithIndent("}");
4845 void StyledStreamWriter::writeArrayValue(const Value
& value
) {
4846 unsigned size
= value
.size();
4850 bool isArrayMultiLine
= isMultilineArray(value
);
4851 if (isArrayMultiLine
) {
4852 writeWithIndent("[");
4854 bool hasChildValue
= !childValues_
.empty();
4857 const Value
& childValue
= value
[index
];
4858 writeCommentBeforeValue(childValue
);
4860 writeWithIndent(childValues_
[index
]);
4862 if (!indented_
) writeIndent();
4864 writeValue(childValue
);
4867 if (++index
== size
) {
4868 writeCommentAfterValueOnSameLine(childValue
);
4872 writeCommentAfterValueOnSameLine(childValue
);
4875 writeWithIndent("]");
4876 } else // output on a single line
4878 assert(childValues_
.size() == size
);
4880 for (unsigned index
= 0; index
< size
; ++index
) {
4883 *document_
<< childValues_
[index
];
4890 bool StyledStreamWriter::isMultilineArray(const Value
& value
) {
4891 ArrayIndex
const size
= value
.size();
4892 bool isMultiLine
= size
* 3 >= rightMargin_
;
4893 childValues_
.clear();
4894 for (ArrayIndex index
= 0; index
< size
&& !isMultiLine
; ++index
) {
4895 const Value
& childValue
= value
[index
];
4896 isMultiLine
= ((childValue
.isArray() || childValue
.isObject()) &&
4897 childValue
.size() > 0);
4899 if (!isMultiLine
) // check if line length > max line length
4901 childValues_
.reserve(size
);
4902 addChildValues_
= true;
4903 ArrayIndex lineLength
= 4 + (size
- 1) * 2; // '[ ' + ', '*n + ' ]'
4904 for (ArrayIndex index
= 0; index
< size
; ++index
) {
4905 if (hasCommentForValue(value
[index
])) {
4908 writeValue(value
[index
]);
4909 lineLength
+= static_cast<ArrayIndex
>(childValues_
[index
].length());
4911 addChildValues_
= false;
4912 isMultiLine
= isMultiLine
|| lineLength
>= rightMargin_
;
4917 void StyledStreamWriter::pushValue(const JSONCPP_STRING
& value
) {
4918 if (addChildValues_
)
4919 childValues_
.push_back(value
);
4921 *document_
<< value
;
4924 void StyledStreamWriter::writeIndent() {
4925 // blep intended this to look at the so-far-written string
4926 // to determine whether we are already indented, but
4927 // with a stream we cannot do that. So we rely on some saved state.
4928 // The caller checks indented_.
4929 *document_
<< '\n' << indentString_
;
4932 void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING
& value
) {
4933 if (!indented_
) writeIndent();
4934 *document_
<< value
;
4938 void StyledStreamWriter::indent() { indentString_
+= indentation_
; }
4940 void StyledStreamWriter::unindent() {
4941 assert(indentString_
.size() >= indentation_
.size());
4942 indentString_
.resize(indentString_
.size() - indentation_
.size());
4945 void StyledStreamWriter::writeCommentBeforeValue(const Value
& root
) {
4946 if (!root
.hasComment(commentBefore
))
4949 if (!indented_
) writeIndent();
4950 const JSONCPP_STRING
& comment
= root
.getComment(commentBefore
);
4951 JSONCPP_STRING::const_iterator iter
= comment
.begin();
4952 while (iter
!= comment
.end()) {
4953 *document_
<< *iter
;
4954 if (*iter
== '\n' &&
4955 ((iter
+1) != comment
.end() && *(iter
+ 1) == '/'))
4956 // writeIndent(); // would include newline
4957 *document_
<< indentString_
;
4963 void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value
& root
) {
4964 if (root
.hasComment(commentAfterOnSameLine
))
4965 *document_
<< ' ' << root
.getComment(commentAfterOnSameLine
);
4967 if (root
.hasComment(commentAfter
)) {
4969 *document_
<< root
.getComment(commentAfter
);
4974 bool StyledStreamWriter::hasCommentForValue(const Value
& value
) {
4975 return value
.hasComment(commentBefore
) ||
4976 value
.hasComment(commentAfterOnSameLine
) ||
4977 value
.hasComment(commentAfter
);
4980 //////////////////////////
4981 // BuiltStyledStreamWriter
4983 /// Scoped enums are not available until C++11.
4984 struct CommentStyle
{
4985 /// Decide whether to write comments.
4987 None
, ///< Drop all comments.
4988 Most
, ///< Recover odd behavior of previous versions (not implemented yet).
4989 All
///< Keep all comments.
4993 struct BuiltStyledStreamWriter
: public StreamWriter
4995 BuiltStyledStreamWriter(
4996 JSONCPP_STRING
const& indentation
,
4997 CommentStyle::Enum cs
,
4998 JSONCPP_STRING
const& colonSymbol
,
4999 JSONCPP_STRING
const& nullSymbol
,
5000 JSONCPP_STRING
const& endingLineFeedSymbol
,
5001 bool useSpecialFloats
,
5002 unsigned int precision
);
5003 int write(Value
const& root
, JSONCPP_OSTREAM
* sout
) JSONCPP_OVERRIDE
;
5005 void writeValue(Value
const& value
);
5006 void writeArrayValue(Value
const& value
);
5007 bool isMultilineArray(Value
const& value
);
5008 void pushValue(JSONCPP_STRING
const& value
);
5010 void writeWithIndent(JSONCPP_STRING
const& value
);
5013 void writeCommentBeforeValue(Value
const& root
);
5014 void writeCommentAfterValueOnSameLine(Value
const& root
);
5015 static bool hasCommentForValue(const Value
& value
);
5017 typedef std::vector
<JSONCPP_STRING
> ChildValues
;
5019 ChildValues childValues_
;
5020 JSONCPP_STRING indentString_
;
5021 unsigned int rightMargin_
;
5022 JSONCPP_STRING indentation_
;
5023 CommentStyle::Enum cs_
;
5024 JSONCPP_STRING colonSymbol_
;
5025 JSONCPP_STRING nullSymbol_
;
5026 JSONCPP_STRING endingLineFeedSymbol_
;
5027 bool addChildValues_
: 1;
5029 bool useSpecialFloats_
: 1;
5030 unsigned int precision_
;
5032 BuiltStyledStreamWriter::BuiltStyledStreamWriter(
5033 JSONCPP_STRING
const& indentation
,
5034 CommentStyle::Enum cs
,
5035 JSONCPP_STRING
const& colonSymbol
,
5036 JSONCPP_STRING
const& nullSymbol
,
5037 JSONCPP_STRING
const& endingLineFeedSymbol
,
5038 bool useSpecialFloats
,
5039 unsigned int precision
)
5041 , indentation_(indentation
)
5043 , colonSymbol_(colonSymbol
)
5044 , nullSymbol_(nullSymbol
)
5045 , endingLineFeedSymbol_(endingLineFeedSymbol
)
5046 , addChildValues_(false)
5048 , useSpecialFloats_(useSpecialFloats
)
5049 , precision_(precision
)
5052 int BuiltStyledStreamWriter::write(Value
const& root
, JSONCPP_OSTREAM
* sout
)
5055 addChildValues_
= false;
5057 indentString_
.clear();
5058 writeCommentBeforeValue(root
);
5059 if (!indented_
) writeIndent();
5062 writeCommentAfterValueOnSameLine(root
);
5063 *sout_
<< endingLineFeedSymbol_
;
5067 void BuiltStyledStreamWriter::writeValue(Value
const& value
) {
5068 switch (value
.type()) {
5070 pushValue(nullSymbol_
);
5073 pushValue(valueToString(value
.asLargestInt()));
5076 pushValue(valueToString(value
.asLargestUInt()));
5079 pushValue(valueToString(value
.asDouble(), useSpecialFloats_
, precision_
));
5083 // Is NULL is possible for value.string_? No.
5086 bool ok
= value
.getString(&str
, &end
);
5087 if (ok
) pushValue(valueToQuotedStringN(str
, static_cast<unsigned>(end
-str
)));
5092 pushValue(valueToString(value
.asBool()));
5095 writeArrayValue(value
);
5098 Value::Members
members(value
.getMemberNames());
5099 if (members
.empty())
5102 writeWithIndent("{");
5104 Value::Members::iterator it
= members
.begin();
5106 JSONCPP_STRING
const& name
= *it
;
5107 Value
const& childValue
= value
[name
];
5108 writeCommentBeforeValue(childValue
);
5109 writeWithIndent(valueToQuotedStringN(name
.data(), static_cast<unsigned>(name
.length())));
5110 *sout_
<< colonSymbol_
;
5111 writeValue(childValue
);
5112 if (++it
== members
.end()) {
5113 writeCommentAfterValueOnSameLine(childValue
);
5117 writeCommentAfterValueOnSameLine(childValue
);
5120 writeWithIndent("}");
5126 void BuiltStyledStreamWriter::writeArrayValue(Value
const& value
) {
5127 unsigned size
= value
.size();
5131 bool isMultiLine
= (cs_
== CommentStyle::All
) || isMultilineArray(value
);
5133 writeWithIndent("[");
5135 bool hasChildValue
= !childValues_
.empty();
5138 Value
const& childValue
= value
[index
];
5139 writeCommentBeforeValue(childValue
);
5141 writeWithIndent(childValues_
[index
]);
5143 if (!indented_
) writeIndent();
5145 writeValue(childValue
);
5148 if (++index
== size
) {
5149 writeCommentAfterValueOnSameLine(childValue
);
5153 writeCommentAfterValueOnSameLine(childValue
);
5156 writeWithIndent("]");
5157 } else // output on a single line
5159 assert(childValues_
.size() == size
);
5161 if (!indentation_
.empty()) *sout_
<< " ";
5162 for (unsigned index
= 0; index
< size
; ++index
) {
5164 *sout_
<< ((!indentation_
.empty()) ? ", " : ",");
5165 *sout_
<< childValues_
[index
];
5167 if (!indentation_
.empty()) *sout_
<< " ";
5173 bool BuiltStyledStreamWriter::isMultilineArray(Value
const& value
) {
5174 ArrayIndex
const size
= value
.size();
5175 bool isMultiLine
= size
* 3 >= rightMargin_
;
5176 childValues_
.clear();
5177 for (ArrayIndex index
= 0; index
< size
&& !isMultiLine
; ++index
) {
5178 Value
const& childValue
= value
[index
];
5179 isMultiLine
= ((childValue
.isArray() || childValue
.isObject()) &&
5180 childValue
.size() > 0);
5182 if (!isMultiLine
) // check if line length > max line length
5184 childValues_
.reserve(size
);
5185 addChildValues_
= true;
5186 ArrayIndex lineLength
= 4 + (size
- 1) * 2; // '[ ' + ', '*n + ' ]'
5187 for (ArrayIndex index
= 0; index
< size
; ++index
) {
5188 if (hasCommentForValue(value
[index
])) {
5191 writeValue(value
[index
]);
5192 lineLength
+= static_cast<ArrayIndex
>(childValues_
[index
].length());
5194 addChildValues_
= false;
5195 isMultiLine
= isMultiLine
|| lineLength
>= rightMargin_
;
5200 void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING
const& value
) {
5201 if (addChildValues_
)
5202 childValues_
.push_back(value
);
5207 void BuiltStyledStreamWriter::writeIndent() {
5208 // blep intended this to look at the so-far-written string
5209 // to determine whether we are already indented, but
5210 // with a stream we cannot do that. So we rely on some saved state.
5211 // The caller checks indented_.
5213 if (!indentation_
.empty()) {
5214 // In this case, drop newlines too.
5215 *sout_
<< '\n' << indentString_
;
5219 void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING
const& value
) {
5220 if (!indented_
) writeIndent();
5225 void BuiltStyledStreamWriter::indent() { indentString_
+= indentation_
; }
5227 void BuiltStyledStreamWriter::unindent() {
5228 assert(indentString_
.size() >= indentation_
.size());
5229 indentString_
.resize(indentString_
.size() - indentation_
.size());
5232 void BuiltStyledStreamWriter::writeCommentBeforeValue(Value
const& root
) {
5233 if (cs_
== CommentStyle::None
) return;
5234 if (!root
.hasComment(commentBefore
))
5237 if (!indented_
) writeIndent();
5238 const JSONCPP_STRING
& comment
= root
.getComment(commentBefore
);
5239 JSONCPP_STRING::const_iterator iter
= comment
.begin();
5240 while (iter
!= comment
.end()) {
5242 if (*iter
== '\n' &&
5243 ((iter
+1) != comment
.end() && *(iter
+ 1) == '/'))
5244 // writeIndent(); // would write extra newline
5245 *sout_
<< indentString_
;
5251 void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value
const& root
) {
5252 if (cs_
== CommentStyle::None
) return;
5253 if (root
.hasComment(commentAfterOnSameLine
))
5254 *sout_
<< " " + root
.getComment(commentAfterOnSameLine
);
5256 if (root
.hasComment(commentAfter
)) {
5258 *sout_
<< root
.getComment(commentAfter
);
5263 bool BuiltStyledStreamWriter::hasCommentForValue(const Value
& value
) {
5264 return value
.hasComment(commentBefore
) ||
5265 value
.hasComment(commentAfterOnSameLine
) ||
5266 value
.hasComment(commentAfter
);
5272 StreamWriter::StreamWriter()
5276 StreamWriter::~StreamWriter()
5279 StreamWriter::Factory::~Factory()
5281 StreamWriterBuilder::StreamWriterBuilder()
5283 setDefaults(&settings_
);
5285 StreamWriterBuilder::~StreamWriterBuilder()
5287 StreamWriter
* StreamWriterBuilder::newStreamWriter() const
5289 JSONCPP_STRING indentation
= settings_
["indentation"].asString();
5290 JSONCPP_STRING cs_str
= settings_
["commentStyle"].asString();
5291 bool eyc
= settings_
["enableYAMLCompatibility"].asBool();
5292 bool dnp
= settings_
["dropNullPlaceholders"].asBool();
5293 bool usf
= settings_
["useSpecialFloats"].asBool();
5294 unsigned int pre
= settings_
["precision"].asUInt();
5295 CommentStyle::Enum cs
= CommentStyle::All
;
5296 if (cs_str
== "All") {
5297 cs
= CommentStyle::All
;
5298 } else if (cs_str
== "None") {
5299 cs
= CommentStyle::None
;
5301 throwRuntimeError("commentStyle must be 'All' or 'None'");
5303 JSONCPP_STRING colonSymbol
= " : ";
5306 } else if (indentation
.empty()) {
5309 JSONCPP_STRING nullSymbol
= "null";
5313 if (pre
> 17) pre
= 17;
5314 JSONCPP_STRING endingLineFeedSymbol
;
5315 return new BuiltStyledStreamWriter(
5317 colonSymbol
, nullSymbol
, endingLineFeedSymbol
, usf
, pre
);
5319 static void getValidWriterKeys(std::set
<JSONCPP_STRING
>* valid_keys
)
5321 valid_keys
->clear();
5322 valid_keys
->insert("indentation");
5323 valid_keys
->insert("commentStyle");
5324 valid_keys
->insert("enableYAMLCompatibility");
5325 valid_keys
->insert("dropNullPlaceholders");
5326 valid_keys
->insert("useSpecialFloats");
5327 valid_keys
->insert("precision");
5329 bool StreamWriterBuilder::validate(Json::Value
* invalid
) const
5331 Json::Value my_invalid
;
5332 if (!invalid
) invalid
= &my_invalid
; // so we do not need to test for NULL
5333 Json::Value
& inv
= *invalid
;
5334 std::set
<JSONCPP_STRING
> valid_keys
;
5335 getValidWriterKeys(&valid_keys
);
5336 Value::Members keys
= settings_
.getMemberNames();
5337 size_t n
= keys
.size();
5338 for (size_t i
= 0; i
< n
; ++i
) {
5339 JSONCPP_STRING
const& key
= keys
[i
];
5340 if (valid_keys
.find(key
) == valid_keys
.end()) {
5341 inv
[key
] = settings_
[key
];
5344 return 0u == inv
.size();
5346 Value
& StreamWriterBuilder::operator[](JSONCPP_STRING key
)
5348 return settings_
[key
];
5351 void StreamWriterBuilder::setDefaults(Json::Value
* settings
)
5353 //! [StreamWriterBuilderDefaults]
5354 (*settings
)["commentStyle"] = "All";
5355 (*settings
)["indentation"] = "\t";
5356 (*settings
)["enableYAMLCompatibility"] = false;
5357 (*settings
)["dropNullPlaceholders"] = false;
5358 (*settings
)["useSpecialFloats"] = false;
5359 (*settings
)["precision"] = 17;
5360 //! [StreamWriterBuilderDefaults]
5363 JSONCPP_STRING
writeString(StreamWriter::Factory
const& builder
, Value
const& root
) {
5364 JSONCPP_OSTRINGSTREAM sout
;
5365 StreamWriterPtr
const writer(builder
.newStreamWriter());
5366 writer
->write(root
, &sout
);
5370 JSONCPP_OSTREAM
& operator<<(JSONCPP_OSTREAM
& sout
, Value
const& root
) {
5371 StreamWriterBuilder builder
;
5372 StreamWriterPtr
const writer(builder
.newStreamWriter());
5373 writer
->write(root
, &sout
);
5379 // //////////////////////////////////////////////////////////////////////
5380 // End of content of file: src/lib_json/json_writer.cpp
5381 // //////////////////////////////////////////////////////////////////////