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