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