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. 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[). 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 */ 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 */ 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 231 Features::Features() 232 : allowComments_(true), strictRoot_(false), 233 allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} 234 235 Features Features::all() { return Features(); } 236 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 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 259 Reader::Reader() 260 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), 261 lastValue_(), commentsBefore_(), features_(Features::all()), 262 collectComments_() {} 263 264 Reader::Reader(const Features& features) 265 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), 266 lastValue_(), commentsBefore_(), features_(features), collectComments_() { 267 } 268 269 bool 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 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 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 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 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 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 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 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 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 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 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 572 bool Reader::readCStyleComment() { 573 while (current_ != end_) { 574 Char c = getNextChar(); 575 if (c == '*' && *current_ == '/') 576 break; 577 } 578 return getNextChar() == '/'; 579 } 580 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 965 bool Reader::addErrorAndRecover(const std::string& message, 966 Token& token, 967 TokenType skipUntilToken) { 968 addError(message, token); 969 return recoverFromError(skipUntilToken); 970 } 971 972 Value& Reader::currentValue() { return *(nodes_.top()); } 973 974 Reader::Char Reader::getNextChar() { 975 if (current_ == end_) 976 return 0; 977 return *current_++; 978 } 979 980 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 1003 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 1020 std::string Reader::getFormatedErrorMessages() const { 1021 return getFormattedErrorMessages(); 1022 } 1023 1024 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 1040 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 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 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 1090 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 1112 OurFeatures::OurFeatures() 1113 : allowComments_(true), strictRoot_(false) 1114 , allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) 1115 , allowSingleQuotes_(false) 1116 , failIfExtra_(false) 1117 { 1118 } 1119 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 1242 OurReader::OurReader(OurFeatures const& features) 1243 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), 1244 lastValue_(), commentsBefore_(), features_(features), collectComments_() { 1245 } 1246 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 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 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 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 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 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 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 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 1517 bool OurReader::readCStyleComment() { 1518 while (current_ != end_) { 1519 Char c = getNextChar(); 1520 if (c == '*' && *current_ == '/') 1521 break; 1522 } 1523 return getNextChar() == '/'; 1524 } 1525 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 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 } 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1928 bool OurReader::addErrorAndRecover(const std::string& message, 1929 Token& token, 1930 TokenType skipUntilToken) { 1931 addError(message, token); 1932 return recoverFromError(skipUntilToken); 1933 } 1934 1935 Value& OurReader::currentValue() { return *(nodes_.top()); } 1936 1937 OurReader::Char OurReader::getNextChar() { 1938 if (current_ == end_) 1939 return 0; 1940 return *current_++; 1941 } 1942 1943 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 1966 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 1982 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 1998 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 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 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 2048 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: 2057 OurCharReader( 2058 bool collectComments, 2059 OurFeatures const& features) 2060 : collectComments_(collectComments) 2061 , reader_(features) 2062 {} 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 2074 CharReaderBuilder::CharReaderBuilder() 2075 { 2076 setDefaults(&settings_); 2077 } 2078 CharReaderBuilder::~CharReaderBuilder() 2079 {} 2080 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 } 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 } 2107 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 } 2124 Value& CharReaderBuilder::operator[](std::string key) 2125 { 2126 return settings_[key]; 2127 } 2128 // static 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 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 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 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 2220 ValueIteratorBase::ValueIteratorBase() 2221 : current_(), isNull_(true) { 2222 } 2223 2224 ValueIteratorBase::ValueIteratorBase( 2225 const Value::ObjectValues::iterator& current) 2226 : current_(current), isNull_(false) {} 2227 2228 Value& ValueIteratorBase::deref() const { 2229 return current_->second; 2230 } 2231 2232 void ValueIteratorBase::increment() { 2233 ++current_; 2234 } 2235 2236 void ValueIteratorBase::decrement() { 2237 --current_; 2238 } 2239 2240 ValueIteratorBase::difference_type 2241 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 2268 bool ValueIteratorBase::isEqual(const SelfType& other) const { 2269 if (isNull_) { 2270 return other.isNull_; 2271 } 2272 return current_ == other.current_; 2273 } 2274 2275 void ValueIteratorBase::copy(const SelfType& other) { 2276 current_ = other.current_; 2277 isNull_ = other.isNull_; 2278 } 2279 2280 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 2290 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 2297 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 2305 char const* ValueIteratorBase::memberName() const { 2306 const char* name = (*current_).first.data(); 2307 return name ? name : ""; 2308 } 2309 2310 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 2328 ValueConstIterator::ValueConstIterator() {} 2329 2330 ValueConstIterator::ValueConstIterator( 2331 const Value::ObjectValues::iterator& current) 2332 : ValueIteratorBase(current) {} 2333 2334 ValueConstIterator& ValueConstIterator:: 2335 operator=(const ValueIteratorBase& other) { 2336 copy(other); 2337 return *this; 2338 } 2339 2340 // ////////////////////////////////////////////////////////////////// 2341 // ////////////////////////////////////////////////////////////////// 2342 // ////////////////////////////////////////////////////////////////// 2343 // class ValueIterator 2344 // ////////////////////////////////////////////////////////////////// 2345 // ////////////////////////////////////////////////////////////////// 2346 // ////////////////////////////////////////////////////////////////// 2347 2348 ValueIterator::ValueIterator() {} 2349 2350 ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) 2351 : ValueIteratorBase(current) {} 2352 2353 ValueIterator::ValueIterator(const ValueConstIterator& other) 2354 : ValueIteratorBase(other) {} 2355 2356 ValueIterator::ValueIterator(const ValueIterator& other) 2357 : ValueIteratorBase(other) {} 2358 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> 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) 2439 static inline double integerToDouble(Json::UInt64 value) { 2440 return static_cast<double>(Int64(value / 2)) * 2.0 + Int64(value & 1); 2441 } 2442 2443 template <typename T> static inline double integerToDouble(T value) { 2444 return static_cast<double>(value); 2445 } 2446 2447 template <typename T, typename U> 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 */ 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 */ 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 } 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 */ 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 2550 Exception::Exception(std::string const& msg) 2551 : msg_(msg) 2552 {} 2553 Exception::~Exception() throw() 2554 {} 2555 char const* Exception::what() const throw() 2556 { 2557 return msg_.c_str(); 2558 } 2559 RuntimeError::RuntimeError(std::string const& msg) 2560 : Exception(msg) 2561 {} 2562 LogicError::LogicError(std::string const& msg) 2563 : Exception(msg) 2564 {} 2565 void throwRuntimeError(std::string const& msg) 2566 { 2567 throw RuntimeError(msg); 2568 } 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 2582 Value::CommentInfo::CommentInfo() : comment_(0) {} 2583 2584 Value::CommentInfo::~CommentInfo() { 2585 if (comment_) 2586 releaseStringValue(comment_); 2587 } 2588 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 2613 Value::CZString::CZString(ArrayIndex index) : cstr_(0), index_(index) {} 2614 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 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 2635 Value::CZString::~CZString() { 2636 if (cstr_ && storage_.policy_ == duplicate) 2637 releaseStringValue(const_cast<char*>(cstr_)); 2638 } 2639 2640 void Value::CZString::swap(CZString& other) { 2641 std::swap(cstr_, other.cstr_); 2642 std::swap(index_, other.index_); 2643 } 2644 2645 Value::CZString& Value::CZString::operator=(CZString other) { 2646 swap(other); 2647 return *this; 2648 } 2649 2650 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 2663 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 2674 ArrayIndex Value::CZString::index() const { return index_; } 2675 2676 //const char* Value::CZString::c_str() const { return cstr_; } 2677 const char* Value::CZString::data() const { return cstr_; } 2678 unsigned Value::CZString::length() const { return storage_.length_; } 2679 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 */ 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 2720 Value::Value(Int value) { 2721 initBasic(intValue); 2722 value_.int_ = value; 2723 } 2724 2725 Value::Value(UInt value) { 2726 initBasic(uintValue); 2727 value_.uint_ = value; 2728 } 2729 #if defined(JSON_HAS_INT64) 2730 Value::Value(Int64 value) { 2731 initBasic(intValue); 2732 value_.int_ = value; 2733 } 2734 Value::Value(UInt64 value) { 2735 initBasic(uintValue); 2736 value_.uint_ = value; 2737 } 2738 #endif // defined(JSON_HAS_INT64) 2739 2740 Value::Value(double value) { 2741 initBasic(realValue); 2742 value_.real_ = value; 2743 } 2744 2745 Value::Value(const char* value) { 2746 initBasic(stringValue, true); 2747 value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value))); 2748 } 2749 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 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 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 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 2774 Value::Value(bool value) { 2775 initBasic(booleanValue); 2776 value_.bool_ = value; 2777 } 2778 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 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 2847 Value& Value::operator=(Value other) { 2848 swap(other); 2849 return *this; 2850 } 2851 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 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 2869 ValueType Value::type() const { return type_; } 2870 2871 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 2879 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 2925 bool Value::operator<=(const Value& other) const { return !(other < *this); } 2926 2927 bool Value::operator>=(const Value& other) const { return !(*this < other); } 2928 2929 bool Value::operator>(const Value& other) const { return other < *this; } 2930 2931 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 2975 bool Value::operator!=(const Value& other) const { return !(*this == other); } 2976 2977 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 2987 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 2996 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 3022 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 3031 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 3053 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 3077 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 3098 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 3120 LargestInt Value::asLargestInt() const { 3121 #if defined(JSON_NO_INT64) 3122 return asInt(); 3123 #else 3124 return asInt64(); 3125 #endif 3126 } 3127 3128 LargestUInt Value::asLargestUInt() const { 3129 #if defined(JSON_NO_INT64) 3130 return asUInt(); 3131 #else 3132 return asUInt64(); 3133 #endif 3134 } 3135 3136 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 3158 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 3180 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 3198 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 3232 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 3255 bool Value::empty() const { 3256 if (isNull() || isArray() || isObject()) 3257 return size() == 0u; 3258 else 3259 return false; 3260 } 3261 3262 bool Value::operator!() const { return isNull(); } 3263 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 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 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 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 3321 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 3334 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 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. 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. 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 3390 Value Value::get(ArrayIndex index, const Value& defaultValue) const { 3391 const Value* value = &((*this)[index]); 3392 return value == &nullRef ? defaultValue : *value; 3393 } 3394 3395 bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } 3396 3397 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 } 3408 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 } 3414 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 3421 Value& Value::operator[](const char* key) { 3422 return resolveReference(key, key + strlen(key)); 3423 } 3424 3425 Value& Value::operator[](const std::string& key) { 3426 return resolveReference(key.data(), key.data() + key.length()); 3427 } 3428 3429 Value& Value::operator[](const StaticString& key) { 3430 return resolveReference(key.c_str()); 3431 } 3432 3433 #ifdef JSON_USE_CPPTL 3434 Value& Value::operator[](const CppTL::ConstString& key) { 3435 return resolveReference(key.c_str(), key.end_c_str()); 3436 } 3437 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 3445 Value& Value::append(const Value& value) { return (*this)[size()] = value; } 3446 3447 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 } 3452 Value Value::get(char const* key, Value const& defaultValue) const 3453 { 3454 return get(key, key + strlen(key), defaultValue); 3455 } 3456 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 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 } 3475 bool Value::removeMember(const char* key, Value* removed) 3476 { 3477 return removeMember(key, key + strlen(key), removed); 3478 } 3479 bool Value::removeMember(std::string const& key, Value* removed) 3480 { 3481 return removeMember(key.data(), key.data() + key.length(), removed); 3482 } 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 } 3494 Value Value::removeMember(const std::string& key) 3495 { 3496 return removeMember(key.c_str()); 3497 } 3498 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 3523 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 3529 bool Value::isMember(char const* key, char const* end) const 3530 { 3531 Value const* value = find(key, end); 3532 return NULL != value; 3533 } 3534 bool Value::isMember(char const* key) const 3535 { 3536 return isMember(key, key + strlen(key)); 3537 } 3538 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 3544 bool Value::isMember(const CppTL::ConstString& key) const { 3545 return isMember(key.c_str(), key.end_c_str()); 3546 } 3547 #endif 3548 3549 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 3591 static bool IsIntegral(double d) { 3592 double integral_part; 3593 return modf(d, &integral_part) == 0.0; 3594 } 3595 3596 bool Value::isNull() const { return type_ == nullValue; } 3597 3598 bool Value::isBool() const { return type_ == booleanValue; } 3599 3600 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 3615 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 3630 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 3650 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 3670 bool Value::isIntegral() const { 3671 #if defined(JSON_HAS_INT64) 3672 return isInt64() || isUInt64(); 3673 #else 3674 return isInt() || isUInt(); 3675 #endif 3676 } 3677 3678 bool Value::isDouble() const { return type_ == realValue || isIntegral(); } 3679 3680 bool Value::isNumeric() const { return isIntegral() || isDouble(); } 3681 3682 bool Value::isString() const { return type_ == stringValue; } 3683 3684 bool Value::isArray() const { return type_ == arrayValue; } 3685 3686 bool Value::isObject() const { return type_ == objectValue; } 3687 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 3698 void Value::setComment(const char* comment, CommentPlacement placement) { 3699 setComment(comment, strlen(comment), placement); 3700 } 3701 3702 void Value::setComment(const std::string& comment, CommentPlacement placement) { 3703 setComment(comment.c_str(), comment.length(), placement); 3704 } 3705 3706 bool Value::hasComment(CommentPlacement placement) const { 3707 return comments_ != 0 && comments_[placement].comment_ != 0; 3708 } 3709 3710 std::string Value::getComment(CommentPlacement placement) const { 3711 if (hasComment(placement)) 3712 return comments_[placement].comment_; 3713 return ""; 3714 } 3715 3716 void Value::setOffsetStart(size_t start) { start_ = start; } 3717 3718 void Value::setOffsetLimit(size_t limit) { limit_ = limit; } 3719 3720 size_t Value::getOffsetStart() const { return start_; } 3721 3722 size_t Value::getOffsetLimit() const { return limit_; } 3723 3724 std::string Value::toStyledString() const { 3725 StyledWriter writer; 3726 return writer.write(*this); 3727 } 3728 3729 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 3742 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 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 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 3784 PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} 3785 3786 PathArgument::PathArgument(ArrayIndex index) 3787 : key_(), index_(index), kind_(kindIndex) {} 3788 3789 PathArgument::PathArgument(const char* key) 3790 : key_(key), index_(), kind_(kindKey) {} 3791 3792 PathArgument::PathArgument(const std::string& key) 3793 : key_(key.c_str()), index_(), kind_(kindKey) {} 3794 3795 // class Path 3796 // ////////////////////////////////////////////////////////////////// 3797 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 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 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 3857 void Path::invalidPath(const std::string& /*path*/, int /*location*/) { 3858 // Error: invalid path. 3859 } 3860 3861 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 3884 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 3903 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 3993 static bool containsControlCharacter(const char* str) { 3994 while (*str) { 3995 if (isControlCharacter(*(str++))) 3996 return true; 3997 } 3998 return false; 3999 } 4000 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 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 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 4034 std::string valueToString(Int value) { 4035 return valueToString(LargestInt(value)); 4036 } 4037 4038 std::string valueToString(UInt value) { 4039 return valueToString(LargestUInt(value)); 4040 } 4041 4042 #endif // # if defined(JSON_HAS_INT64) 4043 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 4081 std::string valueToString(bool value) { return value ? "true" : "false"; } 4082 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 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 } 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 // ////////////////////////////////////////////////////////////////// 4225 Writer::~Writer() {} 4226 4227 // Class FastWriter 4228 // ////////////////////////////////////////////////////////////////// 4229 4230 FastWriter::FastWriter() 4231 : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), 4232 omitEndingLineFeed_(false) {} 4233 4234 void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } 4235 4236 void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } 4237 4238 void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } 4239 4240 std::string FastWriter::write(const Value& root) { 4241 document_ = ""; 4242 writeValue(root); 4243 if (!omitEndingLineFeed_) 4244 document_ += "\n"; 4245 return document_; 4246 } 4247 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 4305 StyledWriter::StyledWriter() 4306 : rightMargin_(74), indentSize_(3), addChildValues_() {} 4307 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 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 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 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 4449 void StyledWriter::pushValue(const std::string& value) { 4450 if (addChildValues_) 4451 childValues_.push_back(value); 4452 else 4453 document_ += value; 4454 } 4455 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 4467 void StyledWriter::writeWithIndent(const std::string& value) { 4468 writeIndent(); 4469 document_ += value; 4470 } 4471 4472 void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); } 4473 4474 void StyledWriter::unindent() { 4475 assert(int(indentString_.size()) >= indentSize_); 4476 indentString_.resize(indentString_.size() - indentSize_); 4477 } 4478 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 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 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 4519 StyledStreamWriter::StyledStreamWriter(std::string indentation) 4520 : document_(NULL), rightMargin_(74), indentation_(indentation), 4521 addChildValues_() {} 4522 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 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 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 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 4669 void StyledStreamWriter::pushValue(const std::string& value) { 4670 if (addChildValues_) 4671 childValues_.push_back(value); 4672 else 4673 *document_ << value; 4674 } 4675 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 4684 void StyledStreamWriter::writeWithIndent(const std::string& value) { 4685 if (!indented_) writeIndent(); 4686 *document_ << value; 4687 indented_ = false; 4688 } 4689 4690 void StyledStreamWriter::indent() { indentString_ += indentation_; } 4691 4692 void StyledStreamWriter::unindent() { 4693 assert(indentString_.size() >= indentation_.size()); 4694 indentString_.resize(indentString_.size() - indentation_.size()); 4695 } 4696 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 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 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 }; 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 } 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 } 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 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 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 4945 void BuiltStyledStreamWriter::pushValue(std::string const& value) { 4946 if (addChildValues_) 4947 childValues_.push_back(value); 4948 else 4949 *sout_ << value; 4950 } 4951 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 4964 void BuiltStyledStreamWriter::writeWithIndent(std::string const& value) { 4965 if (!indented_) writeIndent(); 4966 *sout_ << value; 4967 indented_ = false; 4968 } 4969 4970 void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } 4971 4972 void BuiltStyledStreamWriter::unindent() { 4973 assert(indentString_.size() >= indentation_.size()); 4974 indentString_.resize(indentString_.size() - indentation_.size()); 4975 } 4976 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 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 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 5017 StreamWriter::StreamWriter() 5018 : sout_(NULL) 5019 { 5020 } 5021 StreamWriter::~StreamWriter() 5022 { 5023 } 5024 StreamWriter::Factory::~Factory() 5025 {} 5026 StreamWriterBuilder::StreamWriterBuilder() 5027 { 5028 setDefaults(&settings_); 5029 } 5030 StreamWriterBuilder::~StreamWriterBuilder() 5031 {} 5032 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 } 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 } 5069 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 } 5086 Value& StreamWriterBuilder::operator[](std::string key) 5087 { 5088 return settings_[key]; 5089 } 5090 // static 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 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 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