Path: blob/trunk/third_party/cpp/json-cpp/src/jsoncpp.cpp
2868 views
/// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/).1/// It is intended to be used with #include "json/json.h"23// //////////////////////////////////////////////////////////////////////4// Beginning of content of file: LICENSE5// //////////////////////////////////////////////////////////////////////67/*8The JsonCpp library's source code, including accompanying documentation,9tests and demonstration applications, are licensed under the following10conditions...1112Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all13jurisdictions which recognize such a disclaimer. In such jurisdictions,14this software is released into the Public Domain.1516In jurisdictions which do not recognize Public Domain property (e.g. Germany as of172010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and18The JsonCpp Authors, and is released under the terms of the MIT License (see below).1920In jurisdictions which recognize Public Domain property, the user of this21software may choose to accept it either as 1) Public Domain, 2) under the22conditions of the MIT License (see below), or 3) under the terms of dual23Public Domain/MIT License conditions described here, as they choose.2425The MIT License is about as close to Public Domain as a license can get, and is26described in clear, concise terms at:2728http://en.wikipedia.org/wiki/MIT_License2930The full text of the MIT License follows:3132========================================================================33Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors3435Permission is hereby granted, free of charge, to any person36obtaining a copy of this software and associated documentation37files (the "Software"), to deal in the Software without38restriction, including without limitation the rights to use, copy,39modify, merge, publish, distribute, sublicense, and/or sell copies40of the Software, and to permit persons to whom the Software is41furnished to do so, subject to the following conditions:4243The above copyright notice and this permission notice shall be44included in all copies or substantial portions of the Software.4546THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,47EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF48MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND49NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS50BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN51ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN52CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE53SOFTWARE.54========================================================================55(END LICENSE TEXT)5657The MIT license is compatible with both the GPL and commercial58software, affording one all of the rights of Public Domain with the59minor nuisance of being required to keep the above copyright notice60and license text in the source code. Note also that by accepting the61Public Domain "license" you can re-license your copy using whatever62license you like.6364*/6566// //////////////////////////////////////////////////////////////////////67// End of content of file: LICENSE68// //////////////////////////////////////////////////////////////////////69707172737475#include "json/json.h"7677#ifndef JSON_IS_AMALGAMATION78#error "Compile with -I PATH_TO_JSON_DIRECTORY"79#endif808182// //////////////////////////////////////////////////////////////////////83// Beginning of content of file: src/lib_json/json_tool.h84// //////////////////////////////////////////////////////////////////////8586// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors87// Distributed under MIT license, or public domain if desired and88// recognized in your jurisdiction.89// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE9091#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED92#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED939495// Also support old flag NO_LOCALE_SUPPORT96#ifdef NO_LOCALE_SUPPORT97#define JSONCPP_NO_LOCALE_SUPPORT98#endif99100#ifndef JSONCPP_NO_LOCALE_SUPPORT101#include <clocale>102#endif103104/* This header provides common string manipulation support, such as UTF-8,105* portable conversion from/to string...106*107* It is an internal header that must not be exposed.108*/109110namespace Json {111static char getDecimalPoint() {112#ifdef JSONCPP_NO_LOCALE_SUPPORT113return '\0';114#else115struct lconv* lc = localeconv();116return lc ? *(lc->decimal_point) : '\0';117#endif118}119120/// Converts a unicode code-point to UTF-8.121static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) {122JSONCPP_STRING result;123124// based on description from http://en.wikipedia.org/wiki/UTF-8125126if (cp <= 0x7f) {127result.resize(1);128result[0] = static_cast<char>(cp);129} else if (cp <= 0x7FF) {130result.resize(2);131result[1] = static_cast<char>(0x80 | (0x3f & cp));132result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));133} else if (cp <= 0xFFFF) {134result.resize(3);135result[2] = static_cast<char>(0x80 | (0x3f & cp));136result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));137result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));138} else if (cp <= 0x10FFFF) {139result.resize(4);140result[3] = static_cast<char>(0x80 | (0x3f & cp));141result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));142result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));143result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));144}145146return result;147}148149enum {150/// Constant that specify the size of the buffer that must be passed to151/// uintToString.152uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1153};154155// Defines a char buffer for use with uintToString().156typedef char UIntToStringBuffer[uintToStringBufferSize];157158/** Converts an unsigned integer to string.159* @param value Unsigned integer to convert to string160* @param current Input/Output string buffer.161* Must have at least uintToStringBufferSize chars free.162*/163static inline void uintToString(LargestUInt value, char*& current) {164*--current = 0;165do {166*--current = static_cast<char>(value % 10U + static_cast<unsigned>('0'));167value /= 10;168} while (value != 0);169}170171/** Change ',' to '.' everywhere in buffer.172*173* We had a sophisticated way, but it did not work in WinCE.174* @see https://github.com/open-source-parsers/jsoncpp/pull/9175*/176static inline void fixNumericLocale(char* begin, char* end) {177while (begin < end) {178if (*begin == ',') {179*begin = '.';180}181++begin;182}183}184185static inline void fixNumericLocaleInput(char* begin, char* end) {186char decimalPoint = getDecimalPoint();187if (decimalPoint != '\0' && decimalPoint != '.') {188while (begin < end) {189if (*begin == '.') {190*begin = decimalPoint;191}192++begin;193}194}195}196197/**198* Delete zeros in the end of string, if it isn't last zero before '.' character.199*/200static inline void fixZerosInTheEnd(char* begin, char* end) {201end--;202while ((begin < end) && (*end == '0')) {203// don't delete last zero before point.204if (*(end - 1) != '.') {205*end = '\0';206}207end--;208}209}210211} // namespace Json {212213#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED214215// //////////////////////////////////////////////////////////////////////216// End of content of file: src/lib_json/json_tool.h217// //////////////////////////////////////////////////////////////////////218219220221222223224// //////////////////////////////////////////////////////////////////////225// Beginning of content of file: src/lib_json/json_reader.cpp226// //////////////////////////////////////////////////////////////////////227228// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors229// Copyright (C) 2016 InfoTeCS JSC. All rights reserved.230// Distributed under MIT license, or public domain if desired and231// recognized in your jurisdiction.232// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE233234#if !defined(JSON_IS_AMALGAMATION)235#include <json/assertions.h>236#include <json/reader.h>237#include <json/value.h>238#include "json_tool.h"239#endif // if !defined(JSON_IS_AMALGAMATION)240#include <utility>241#include <cstdio>242#include <cassert>243#include <cstring>244#include <istream>245#include <sstream>246#include <memory>247#include <set>248#include <limits>249250#if defined(_MSC_VER)251#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above252#define snprintf sprintf_s253#elif _MSC_VER >= 1900 // VC++ 14.0 and above254#define snprintf std::snprintf255#else256#define snprintf _snprintf257#endif258#elif defined(__ANDROID__) || defined(__QNXNTO__)259#define snprintf snprintf260#elif __cplusplus >= 201103L261#if !defined(__MINGW32__) && !defined(__CYGWIN__)262#define snprintf std::snprintf263#endif264#endif265266#if defined(__QNXNTO__)267#define sscanf std::sscanf268#endif269270#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0271// Disable warning about strdup being deprecated.272#pragma warning(disable : 4996)273#endif274275// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile time to change the stack limit276#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)277#define JSONCPP_DEPRECATED_STACK_LIMIT 1000278#endif279280static size_t const stackLimit_g = JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()281282namespace Json {283284#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)285typedef std::unique_ptr<CharReader> CharReaderPtr;286#else287typedef std::auto_ptr<CharReader> CharReaderPtr;288#endif289290// Implementation of class Features291// ////////////////////////////////292293Features::Features()294: allowComments_(true), strictRoot_(false),295allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}296297Features Features::all() { return Features(); }298299Features Features::strictMode() {300Features features;301features.allowComments_ = false;302features.strictRoot_ = true;303features.allowDroppedNullPlaceholders_ = false;304features.allowNumericKeys_ = false;305return features;306}307308// Implementation of class Reader309// ////////////////////////////////310311bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {312for (; begin < end; ++begin)313if (*begin == '\n' || *begin == '\r')314return true;315return false;316}317318// Class Reader319// //////////////////////////////////////////////////////////////////320321Reader::Reader()322: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),323lastValue_(), commentsBefore_(), features_(Features::all()),324collectComments_() {}325326Reader::Reader(const Features& features)327: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),328lastValue_(), commentsBefore_(), features_(features), collectComments_() {329}330331bool332Reader::parse(const std::string& document, Value& root, bool collectComments) {333document_.assign(document.begin(), document.end());334const char* begin = document_.c_str();335const char* end = begin + document_.length();336return parse(begin, end, root, collectComments);337}338339bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {340// std::istream_iterator<char> begin(sin);341// std::istream_iterator<char> end;342// Those would allow streamed input from a file, if parse() were a343// template function.344345// Since JSONCPP_STRING is reference-counted, this at least does not346// create an extra copy.347JSONCPP_STRING doc;348std::getline(sin, doc, (char)EOF);349return parse(doc.data(), doc.data() + doc.size(), root, collectComments);350}351352bool Reader::parse(const char* beginDoc,353const char* endDoc,354Value& root,355bool collectComments) {356if (!features_.allowComments_) {357collectComments = false;358}359360begin_ = beginDoc;361end_ = endDoc;362collectComments_ = collectComments;363current_ = begin_;364lastValueEnd_ = 0;365lastValue_ = 0;366commentsBefore_.clear();367errors_.clear();368while (!nodes_.empty())369nodes_.pop();370nodes_.push(&root);371372bool successful = readValue();373Token token;374skipCommentTokens(token);375if (collectComments_ && !commentsBefore_.empty())376root.setComment(commentsBefore_, commentAfter);377if (features_.strictRoot_) {378if (!root.isArray() && !root.isObject()) {379// Set error location to start of doc, ideally should be first token found380// in doc381token.type_ = tokenError;382token.start_ = beginDoc;383token.end_ = endDoc;384addError(385"A valid JSON document must be either an array or an object value.",386token);387return false;388}389}390return successful;391}392393bool Reader::readValue() {394// readValue() may call itself only if it calls readObject() or ReadArray().395// These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue().396// parse() executes one nodes_.push(), so > instead of >=.397if (nodes_.size() > stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");398399Token token;400skipCommentTokens(token);401bool successful = true;402403if (collectComments_ && !commentsBefore_.empty()) {404currentValue().setComment(commentsBefore_, commentBefore);405commentsBefore_.clear();406}407408switch (token.type_) {409case tokenObjectBegin:410successful = readObject(token);411currentValue().setOffsetLimit(current_ - begin_);412break;413case tokenArrayBegin:414successful = readArray(token);415currentValue().setOffsetLimit(current_ - begin_);416break;417case tokenNumber:418successful = decodeNumber(token);419break;420case tokenString:421successful = decodeString(token);422break;423case tokenTrue:424{425Value v(true);426currentValue().swapPayload(v);427currentValue().setOffsetStart(token.start_ - begin_);428currentValue().setOffsetLimit(token.end_ - begin_);429}430break;431case tokenFalse:432{433Value v(false);434currentValue().swapPayload(v);435currentValue().setOffsetStart(token.start_ - begin_);436currentValue().setOffsetLimit(token.end_ - begin_);437}438break;439case tokenNull:440{441Value v;442currentValue().swapPayload(v);443currentValue().setOffsetStart(token.start_ - begin_);444currentValue().setOffsetLimit(token.end_ - begin_);445}446break;447case tokenArraySeparator:448case tokenObjectEnd:449case tokenArrayEnd:450if (features_.allowDroppedNullPlaceholders_) {451// "Un-read" the current token and mark the current value as a null452// token.453current_--;454Value v;455currentValue().swapPayload(v);456currentValue().setOffsetStart(current_ - begin_ - 1);457currentValue().setOffsetLimit(current_ - begin_);458break;459} // Else, fall through...460default:461currentValue().setOffsetStart(token.start_ - begin_);462currentValue().setOffsetLimit(token.end_ - begin_);463return addError("Syntax error: value, object or array expected.", token);464}465466if (collectComments_) {467lastValueEnd_ = current_;468lastValue_ = ¤tValue();469}470471return successful;472}473474void Reader::skipCommentTokens(Token& token) {475if (features_.allowComments_) {476do {477readToken(token);478} while (token.type_ == tokenComment);479} else {480readToken(token);481}482}483484bool Reader::readToken(Token& token) {485skipSpaces();486token.start_ = current_;487Char c = getNextChar();488bool ok = true;489switch (c) {490case '{':491token.type_ = tokenObjectBegin;492break;493case '}':494token.type_ = tokenObjectEnd;495break;496case '[':497token.type_ = tokenArrayBegin;498break;499case ']':500token.type_ = tokenArrayEnd;501break;502case '"':503token.type_ = tokenString;504ok = readString();505break;506case '/':507token.type_ = tokenComment;508ok = readComment();509break;510case '0':511case '1':512case '2':513case '3':514case '4':515case '5':516case '6':517case '7':518case '8':519case '9':520case '-':521token.type_ = tokenNumber;522readNumber();523break;524case 't':525token.type_ = tokenTrue;526ok = match("rue", 3);527break;528case 'f':529token.type_ = tokenFalse;530ok = match("alse", 4);531break;532case 'n':533token.type_ = tokenNull;534ok = match("ull", 3);535break;536case ',':537token.type_ = tokenArraySeparator;538break;539case ':':540token.type_ = tokenMemberSeparator;541break;542case 0:543token.type_ = tokenEndOfStream;544break;545default:546ok = false;547break;548}549if (!ok)550token.type_ = tokenError;551token.end_ = current_;552return true;553}554555void Reader::skipSpaces() {556while (current_ != end_) {557Char c = *current_;558if (c == ' ' || c == '\t' || c == '\r' || c == '\n')559++current_;560else561break;562}563}564565bool Reader::match(Location pattern, int patternLength) {566if (end_ - current_ < patternLength)567return false;568int index = patternLength;569while (index--)570if (current_[index] != pattern[index])571return false;572current_ += patternLength;573return true;574}575576bool Reader::readComment() {577Location commentBegin = current_ - 1;578Char c = getNextChar();579bool successful = false;580if (c == '*')581successful = readCStyleComment();582else if (c == '/')583successful = readCppStyleComment();584if (!successful)585return false;586587if (collectComments_) {588CommentPlacement placement = commentBefore;589if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {590if (c != '*' || !containsNewLine(commentBegin, current_))591placement = commentAfterOnSameLine;592}593594addComment(commentBegin, current_, placement);595}596return true;597}598599JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {600JSONCPP_STRING normalized;601normalized.reserve(static_cast<size_t>(end - begin));602Reader::Location current = begin;603while (current != end) {604char c = *current++;605if (c == '\r') {606if (current != end && *current == '\n')607// convert dos EOL608++current;609// convert Mac EOL610normalized += '\n';611} else {612normalized += c;613}614}615return normalized;616}617618void619Reader::addComment(Location begin, Location end, CommentPlacement placement) {620assert(collectComments_);621const JSONCPP_STRING& normalized = normalizeEOL(begin, end);622if (placement == commentAfterOnSameLine) {623assert(lastValue_ != 0);624lastValue_->setComment(normalized, placement);625} else {626commentsBefore_ += normalized;627}628}629630bool Reader::readCStyleComment() {631while ((current_ + 1) < end_) {632Char c = getNextChar();633if (c == '*' && *current_ == '/')634break;635}636return getNextChar() == '/';637}638639bool Reader::readCppStyleComment() {640while (current_ != end_) {641Char c = getNextChar();642if (c == '\n')643break;644if (c == '\r') {645// Consume DOS EOL. It will be normalized in addComment.646if (current_ != end_ && *current_ == '\n')647getNextChar();648// Break on Moc OS 9 EOL.649break;650}651}652return true;653}654655void Reader::readNumber() {656const char *p = current_;657char c = '0'; // stopgap for already consumed character658// integral part659while (c >= '0' && c <= '9')660c = (current_ = p) < end_ ? *p++ : '\0';661// fractional part662if (c == '.') {663c = (current_ = p) < end_ ? *p++ : '\0';664while (c >= '0' && c <= '9')665c = (current_ = p) < end_ ? *p++ : '\0';666}667// exponential part668if (c == 'e' || c == 'E') {669c = (current_ = p) < end_ ? *p++ : '\0';670if (c == '+' || c == '-')671c = (current_ = p) < end_ ? *p++ : '\0';672while (c >= '0' && c <= '9')673c = (current_ = p) < end_ ? *p++ : '\0';674}675}676677bool Reader::readString() {678Char c = '\0';679while (current_ != end_) {680c = getNextChar();681if (c == '\\')682getNextChar();683else if (c == '"')684break;685}686return c == '"';687}688689bool Reader::readObject(Token& tokenStart) {690Token tokenName;691JSONCPP_STRING name;692Value init(objectValue);693currentValue().swapPayload(init);694currentValue().setOffsetStart(tokenStart.start_ - begin_);695while (readToken(tokenName)) {696bool initialTokenOk = true;697while (tokenName.type_ == tokenComment && initialTokenOk)698initialTokenOk = readToken(tokenName);699if (!initialTokenOk)700break;701if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object702return true;703name.clear();704if (tokenName.type_ == tokenString) {705if (!decodeString(tokenName, name))706return recoverFromError(tokenObjectEnd);707} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {708Value numberName;709if (!decodeNumber(tokenName, numberName))710return recoverFromError(tokenObjectEnd);711name = JSONCPP_STRING(numberName.asCString());712} else {713break;714}715716Token colon;717if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {718return addErrorAndRecover(719"Missing ':' after object member name", colon, tokenObjectEnd);720}721Value& value = currentValue()[name];722nodes_.push(&value);723bool ok = readValue();724nodes_.pop();725if (!ok) // error already set726return recoverFromError(tokenObjectEnd);727728Token comma;729if (!readToken(comma) ||730(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&731comma.type_ != tokenComment)) {732return addErrorAndRecover(733"Missing ',' or '}' in object declaration", comma, tokenObjectEnd);734}735bool finalizeTokenOk = true;736while (comma.type_ == tokenComment && finalizeTokenOk)737finalizeTokenOk = readToken(comma);738if (comma.type_ == tokenObjectEnd)739return true;740}741return addErrorAndRecover(742"Missing '}' or object member name", tokenName, tokenObjectEnd);743}744745bool Reader::readArray(Token& tokenStart) {746Value init(arrayValue);747currentValue().swapPayload(init);748currentValue().setOffsetStart(tokenStart.start_ - begin_);749skipSpaces();750if (current_ != end_ && *current_ == ']') // empty array751{752Token endArray;753readToken(endArray);754return true;755}756int index = 0;757for (;;) {758Value& value = currentValue()[index++];759nodes_.push(&value);760bool ok = readValue();761nodes_.pop();762if (!ok) // error already set763return recoverFromError(tokenArrayEnd);764765Token token;766// Accept Comment after last item in the array.767ok = readToken(token);768while (token.type_ == tokenComment && ok) {769ok = readToken(token);770}771bool badTokenType =772(token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);773if (!ok || badTokenType) {774return addErrorAndRecover(775"Missing ',' or ']' in array declaration", token, tokenArrayEnd);776}777if (token.type_ == tokenArrayEnd)778break;779}780return true;781}782783bool Reader::decodeNumber(Token& token) {784Value decoded;785if (!decodeNumber(token, decoded))786return false;787currentValue().swapPayload(decoded);788currentValue().setOffsetStart(token.start_ - begin_);789currentValue().setOffsetLimit(token.end_ - begin_);790return true;791}792793bool Reader::decodeNumber(Token& token, Value& decoded) {794// Attempts to parse the number as an integer. If the number is795// larger than the maximum supported value of an integer then796// we decode the number as a double.797Location current = token.start_;798bool isNegative = *current == '-';799if (isNegative)800++current;801// TODO: Help the compiler do the div and mod at compile time or get rid of them.802Value::LargestUInt maxIntegerValue =803isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1804: Value::maxLargestUInt;805Value::LargestUInt threshold = maxIntegerValue / 10;806Value::LargestUInt value = 0;807while (current < token.end_) {808Char c = *current++;809if (c < '0' || c > '9')810return decodeDouble(token, decoded);811Value::UInt digit(static_cast<Value::UInt>(c - '0'));812if (value >= threshold) {813// We've hit or exceeded the max value divided by 10 (rounded down). If814// a) we've only just touched the limit, b) this is the last digit, and815// c) it's small enough to fit in that rounding delta, we're okay.816// Otherwise treat this number as a double to avoid overflow.817if (value > threshold || current != token.end_ ||818digit > maxIntegerValue % 10) {819return decodeDouble(token, decoded);820}821}822value = value * 10 + digit;823}824if (isNegative && value == maxIntegerValue)825decoded = Value::minLargestInt;826else if (isNegative)827decoded = -Value::LargestInt(value);828else if (value <= Value::LargestUInt(Value::maxInt))829decoded = Value::LargestInt(value);830else831decoded = value;832return true;833}834835bool Reader::decodeDouble(Token& token) {836Value decoded;837if (!decodeDouble(token, decoded))838return false;839currentValue().swapPayload(decoded);840currentValue().setOffsetStart(token.start_ - begin_);841currentValue().setOffsetLimit(token.end_ - begin_);842return true;843}844845bool Reader::decodeDouble(Token& token, Value& decoded) {846double value = 0;847JSONCPP_STRING buffer(token.start_, token.end_);848JSONCPP_ISTRINGSTREAM is(buffer);849if (!(is >> value))850return addError("'" + JSONCPP_STRING(token.start_, token.end_) +851"' is not a number.",852token);853decoded = value;854return true;855}856857bool Reader::decodeString(Token& token) {858JSONCPP_STRING decoded_string;859if (!decodeString(token, decoded_string))860return false;861Value decoded(decoded_string);862currentValue().swapPayload(decoded);863currentValue().setOffsetStart(token.start_ - begin_);864currentValue().setOffsetLimit(token.end_ - begin_);865return true;866}867868bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) {869decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));870Location current = token.start_ + 1; // skip '"'871Location end = token.end_ - 1; // do not include '"'872while (current != end) {873Char c = *current++;874if (c == '"')875break;876else if (c == '\\') {877if (current == end)878return addError("Empty escape sequence in string", token, current);879Char escape = *current++;880switch (escape) {881case '"':882decoded += '"';883break;884case '/':885decoded += '/';886break;887case '\\':888decoded += '\\';889break;890case 'b':891decoded += '\b';892break;893case 'f':894decoded += '\f';895break;896case 'n':897decoded += '\n';898break;899case 'r':900decoded += '\r';901break;902case 't':903decoded += '\t';904break;905case 'u': {906unsigned int unicode;907if (!decodeUnicodeCodePoint(token, current, end, unicode))908return false;909decoded += codePointToUTF8(unicode);910} break;911default:912return addError("Bad escape sequence in string", token, current);913}914} else {915decoded += c;916}917}918return true;919}920921bool Reader::decodeUnicodeCodePoint(Token& token,922Location& current,923Location end,924unsigned int& unicode) {925926if (!decodeUnicodeEscapeSequence(token, current, end, unicode))927return false;928if (unicode >= 0xD800 && unicode <= 0xDBFF) {929// surrogate pairs930if (end - current < 6)931return addError(932"additional six characters expected to parse unicode surrogate pair.",933token,934current);935unsigned int surrogatePair;936if (*(current++) == '\\' && *(current++) == 'u') {937if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {938unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);939} else940return false;941} else942return addError("expecting another \\u token to begin the second half of "943"a unicode surrogate pair",944token,945current);946}947return true;948}949950bool Reader::decodeUnicodeEscapeSequence(Token& token,951Location& current,952Location end,953unsigned int& ret_unicode) {954if (end - current < 4)955return addError(956"Bad unicode escape sequence in string: four digits expected.",957token,958current);959int unicode = 0;960for (int index = 0; index < 4; ++index) {961Char c = *current++;962unicode *= 16;963if (c >= '0' && c <= '9')964unicode += c - '0';965else if (c >= 'a' && c <= 'f')966unicode += c - 'a' + 10;967else if (c >= 'A' && c <= 'F')968unicode += c - 'A' + 10;969else970return addError(971"Bad unicode escape sequence in string: hexadecimal digit expected.",972token,973current);974}975ret_unicode = static_cast<unsigned int>(unicode);976return true;977}978979bool980Reader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {981ErrorInfo info;982info.token_ = token;983info.message_ = message;984info.extra_ = extra;985errors_.push_back(info);986return false;987}988989bool Reader::recoverFromError(TokenType skipUntilToken) {990size_t const errorCount = errors_.size();991Token skip;992for (;;) {993if (!readToken(skip))994errors_.resize(errorCount); // discard errors caused by recovery995if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)996break;997}998errors_.resize(errorCount);999return false;1000}10011002bool Reader::addErrorAndRecover(const JSONCPP_STRING& message,1003Token& token,1004TokenType skipUntilToken) {1005addError(message, token);1006return recoverFromError(skipUntilToken);1007}10081009Value& Reader::currentValue() { return *(nodes_.top()); }10101011Reader::Char Reader::getNextChar() {1012if (current_ == end_)1013return 0;1014return *current_++;1015}10161017void Reader::getLocationLineAndColumn(Location location,1018int& line,1019int& column) const {1020Location current = begin_;1021Location lastLineStart = current;1022line = 0;1023while (current < location && current != end_) {1024Char c = *current++;1025if (c == '\r') {1026if (*current == '\n')1027++current;1028lastLineStart = current;1029++line;1030} else if (c == '\n') {1031lastLineStart = current;1032++line;1033}1034}1035// column & line start at 11036column = int(location - lastLineStart) + 1;1037++line;1038}10391040JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const {1041int line, column;1042getLocationLineAndColumn(location, line, column);1043char buffer[18 + 16 + 16 + 1];1044snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);1045return buffer;1046}10471048// Deprecated. Preserved for backward compatibility1049JSONCPP_STRING Reader::getFormatedErrorMessages() const {1050return getFormattedErrorMessages();1051}10521053JSONCPP_STRING Reader::getFormattedErrorMessages() const {1054JSONCPP_STRING formattedMessage;1055for (Errors::const_iterator itError = errors_.begin();1056itError != errors_.end();1057++itError) {1058const ErrorInfo& error = *itError;1059formattedMessage +=1060"* " + getLocationLineAndColumn(error.token_.start_) + "\n";1061formattedMessage += " " + error.message_ + "\n";1062if (error.extra_)1063formattedMessage +=1064"See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";1065}1066return formattedMessage;1067}10681069std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {1070std::vector<Reader::StructuredError> allErrors;1071for (Errors::const_iterator itError = errors_.begin();1072itError != errors_.end();1073++itError) {1074const ErrorInfo& error = *itError;1075Reader::StructuredError structured;1076structured.offset_start = error.token_.start_ - begin_;1077structured.offset_limit = error.token_.end_ - begin_;1078structured.message = error.message_;1079allErrors.push_back(structured);1080}1081return allErrors;1082}10831084bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) {1085ptrdiff_t const length = end_ - begin_;1086if(value.getOffsetStart() > length1087|| value.getOffsetLimit() > length)1088return false;1089Token token;1090token.type_ = tokenError;1091token.start_ = begin_ + value.getOffsetStart();1092token.end_ = end_ + value.getOffsetLimit();1093ErrorInfo info;1094info.token_ = token;1095info.message_ = message;1096info.extra_ = 0;1097errors_.push_back(info);1098return true;1099}11001101bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {1102ptrdiff_t const length = end_ - begin_;1103if(value.getOffsetStart() > length1104|| value.getOffsetLimit() > length1105|| extra.getOffsetLimit() > length)1106return false;1107Token token;1108token.type_ = tokenError;1109token.start_ = begin_ + value.getOffsetStart();1110token.end_ = begin_ + value.getOffsetLimit();1111ErrorInfo info;1112info.token_ = token;1113info.message_ = message;1114info.extra_ = begin_ + extra.getOffsetStart();1115errors_.push_back(info);1116return true;1117}11181119bool Reader::good() const {1120return !errors_.size();1121}11221123// exact copy of Features1124class OurFeatures {1125public:1126static OurFeatures all();1127bool allowComments_;1128bool strictRoot_;1129bool allowDroppedNullPlaceholders_;1130bool allowNumericKeys_;1131bool allowSingleQuotes_;1132bool failIfExtra_;1133bool rejectDupKeys_;1134bool allowSpecialFloats_;1135int stackLimit_;1136}; // OurFeatures11371138// exact copy of Implementation of class Features1139// ////////////////////////////////11401141OurFeatures OurFeatures::all() { return OurFeatures(); }11421143// Implementation of class Reader1144// ////////////////////////////////11451146// exact copy of Reader, renamed to OurReader1147class OurReader {1148public:1149typedef char Char;1150typedef const Char* Location;1151struct StructuredError {1152ptrdiff_t offset_start;1153ptrdiff_t offset_limit;1154JSONCPP_STRING message;1155};11561157OurReader(OurFeatures const& features);1158bool parse(const char* beginDoc,1159const char* endDoc,1160Value& root,1161bool collectComments = true);1162JSONCPP_STRING getFormattedErrorMessages() const;1163std::vector<StructuredError> getStructuredErrors() const;1164bool pushError(const Value& value, const JSONCPP_STRING& message);1165bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra);1166bool good() const;11671168private:1169OurReader(OurReader const&); // no impl1170void operator=(OurReader const&); // no impl11711172enum TokenType {1173tokenEndOfStream = 0,1174tokenObjectBegin,1175tokenObjectEnd,1176tokenArrayBegin,1177tokenArrayEnd,1178tokenString,1179tokenNumber,1180tokenTrue,1181tokenFalse,1182tokenNull,1183tokenNaN,1184tokenPosInf,1185tokenNegInf,1186tokenArraySeparator,1187tokenMemberSeparator,1188tokenComment,1189tokenError1190};11911192class Token {1193public:1194TokenType type_;1195Location start_;1196Location end_;1197};11981199class ErrorInfo {1200public:1201Token token_;1202JSONCPP_STRING message_;1203Location extra_;1204};12051206typedef std::deque<ErrorInfo> Errors;12071208bool readToken(Token& token);1209void skipSpaces();1210bool match(Location pattern, int patternLength);1211bool readComment();1212bool readCStyleComment();1213bool readCppStyleComment();1214bool readString();1215bool readStringSingleQuote();1216bool readNumber(bool checkInf);1217bool readValue();1218bool readObject(Token& token);1219bool readArray(Token& token);1220bool decodeNumber(Token& token);1221bool decodeNumber(Token& token, Value& decoded);1222bool decodeString(Token& token);1223bool decodeString(Token& token, JSONCPP_STRING& decoded);1224bool decodeDouble(Token& token);1225bool decodeDouble(Token& token, Value& decoded);1226bool decodeUnicodeCodePoint(Token& token,1227Location& current,1228Location end,1229unsigned int& unicode);1230bool decodeUnicodeEscapeSequence(Token& token,1231Location& current,1232Location end,1233unsigned int& unicode);1234bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0);1235bool recoverFromError(TokenType skipUntilToken);1236bool addErrorAndRecover(const JSONCPP_STRING& message,1237Token& token,1238TokenType skipUntilToken);1239void skipUntilSpace();1240Value& currentValue();1241Char getNextChar();1242void1243getLocationLineAndColumn(Location location, int& line, int& column) const;1244JSONCPP_STRING getLocationLineAndColumn(Location location) const;1245void addComment(Location begin, Location end, CommentPlacement placement);1246void skipCommentTokens(Token& token);12471248static JSONCPP_STRING normalizeEOL(Location begin, Location end);1249static bool containsNewLine(Location begin, Location end);12501251typedef std::stack<Value*> Nodes;1252Nodes nodes_;1253Errors errors_;1254JSONCPP_STRING document_;1255Location begin_;1256Location end_;1257Location current_;1258Location lastValueEnd_;1259Value* lastValue_;1260JSONCPP_STRING commentsBefore_;12611262OurFeatures const features_;1263bool collectComments_;1264}; // OurReader12651266// complete copy of Read impl, for OurReader12671268bool OurReader::containsNewLine(OurReader::Location begin, OurReader::Location end) {1269for (; begin < end; ++begin)1270if (*begin == '\n' || *begin == '\r')1271return true;1272return false;1273}12741275OurReader::OurReader(OurFeatures const& features)1276: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),1277lastValue_(), commentsBefore_(),1278features_(features), collectComments_() {1279}12801281bool OurReader::parse(const char* beginDoc,1282const char* endDoc,1283Value& root,1284bool collectComments) {1285if (!features_.allowComments_) {1286collectComments = false;1287}12881289begin_ = beginDoc;1290end_ = endDoc;1291collectComments_ = collectComments;1292current_ = begin_;1293lastValueEnd_ = 0;1294lastValue_ = 0;1295commentsBefore_.clear();1296errors_.clear();1297while (!nodes_.empty())1298nodes_.pop();1299nodes_.push(&root);13001301bool successful = readValue();1302Token token;1303skipCommentTokens(token);1304if (features_.failIfExtra_) {1305if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) {1306addError("Extra non-whitespace after JSON value.", token);1307return false;1308}1309}1310if (collectComments_ && !commentsBefore_.empty())1311root.setComment(commentsBefore_, commentAfter);1312if (features_.strictRoot_) {1313if (!root.isArray() && !root.isObject()) {1314// Set error location to start of doc, ideally should be first token found1315// in doc1316token.type_ = tokenError;1317token.start_ = beginDoc;1318token.end_ = endDoc;1319addError(1320"A valid JSON document must be either an array or an object value.",1321token);1322return false;1323}1324}1325return successful;1326}13271328bool OurReader::readValue() {1329// To preserve the old behaviour we cast size_t to int.1330if (static_cast<int>(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");1331Token token;1332skipCommentTokens(token);1333bool successful = true;13341335if (collectComments_ && !commentsBefore_.empty()) {1336currentValue().setComment(commentsBefore_, commentBefore);1337commentsBefore_.clear();1338}13391340switch (token.type_) {1341case tokenObjectBegin:1342successful = readObject(token);1343currentValue().setOffsetLimit(current_ - begin_);1344break;1345case tokenArrayBegin:1346successful = readArray(token);1347currentValue().setOffsetLimit(current_ - begin_);1348break;1349case tokenNumber:1350successful = decodeNumber(token);1351break;1352case tokenString:1353successful = decodeString(token);1354break;1355case tokenTrue:1356{1357Value v(true);1358currentValue().swapPayload(v);1359currentValue().setOffsetStart(token.start_ - begin_);1360currentValue().setOffsetLimit(token.end_ - begin_);1361}1362break;1363case tokenFalse:1364{1365Value v(false);1366currentValue().swapPayload(v);1367currentValue().setOffsetStart(token.start_ - begin_);1368currentValue().setOffsetLimit(token.end_ - begin_);1369}1370break;1371case tokenNull:1372{1373Value v;1374currentValue().swapPayload(v);1375currentValue().setOffsetStart(token.start_ - begin_);1376currentValue().setOffsetLimit(token.end_ - begin_);1377}1378break;1379case tokenNaN:1380{1381Value v(std::numeric_limits<double>::quiet_NaN());1382currentValue().swapPayload(v);1383currentValue().setOffsetStart(token.start_ - begin_);1384currentValue().setOffsetLimit(token.end_ - begin_);1385}1386break;1387case tokenPosInf:1388{1389Value v(std::numeric_limits<double>::infinity());1390currentValue().swapPayload(v);1391currentValue().setOffsetStart(token.start_ - begin_);1392currentValue().setOffsetLimit(token.end_ - begin_);1393}1394break;1395case tokenNegInf:1396{1397Value v(-std::numeric_limits<double>::infinity());1398currentValue().swapPayload(v);1399currentValue().setOffsetStart(token.start_ - begin_);1400currentValue().setOffsetLimit(token.end_ - begin_);1401}1402break;1403case tokenArraySeparator:1404case tokenObjectEnd:1405case tokenArrayEnd:1406if (features_.allowDroppedNullPlaceholders_) {1407// "Un-read" the current token and mark the current value as a null1408// token.1409current_--;1410Value v;1411currentValue().swapPayload(v);1412currentValue().setOffsetStart(current_ - begin_ - 1);1413currentValue().setOffsetLimit(current_ - begin_);1414break;1415} // else, fall through ...1416default:1417currentValue().setOffsetStart(token.start_ - begin_);1418currentValue().setOffsetLimit(token.end_ - begin_);1419return addError("Syntax error: value, object or array expected.", token);1420}14211422if (collectComments_) {1423lastValueEnd_ = current_;1424lastValue_ = ¤tValue();1425}14261427return successful;1428}14291430void OurReader::skipCommentTokens(Token& token) {1431if (features_.allowComments_) {1432do {1433readToken(token);1434} while (token.type_ == tokenComment);1435} else {1436readToken(token);1437}1438}14391440bool OurReader::readToken(Token& token) {1441skipSpaces();1442token.start_ = current_;1443Char c = getNextChar();1444bool ok = true;1445switch (c) {1446case '{':1447token.type_ = tokenObjectBegin;1448break;1449case '}':1450token.type_ = tokenObjectEnd;1451break;1452case '[':1453token.type_ = tokenArrayBegin;1454break;1455case ']':1456token.type_ = tokenArrayEnd;1457break;1458case '"':1459token.type_ = tokenString;1460ok = readString();1461break;1462case '\'':1463if (features_.allowSingleQuotes_) {1464token.type_ = tokenString;1465ok = readStringSingleQuote();1466break;1467} // else fall through1468case '/':1469token.type_ = tokenComment;1470ok = readComment();1471break;1472case '0':1473case '1':1474case '2':1475case '3':1476case '4':1477case '5':1478case '6':1479case '7':1480case '8':1481case '9':1482token.type_ = tokenNumber;1483readNumber(false);1484break;1485case '-':1486if (readNumber(true)) {1487token.type_ = tokenNumber;1488} else {1489token.type_ = tokenNegInf;1490ok = features_.allowSpecialFloats_ && match("nfinity", 7);1491}1492break;1493case 't':1494token.type_ = tokenTrue;1495ok = match("rue", 3);1496break;1497case 'f':1498token.type_ = tokenFalse;1499ok = match("alse", 4);1500break;1501case 'n':1502token.type_ = tokenNull;1503ok = match("ull", 3);1504break;1505case 'N':1506if (features_.allowSpecialFloats_) {1507token.type_ = tokenNaN;1508ok = match("aN", 2);1509} else {1510ok = false;1511}1512break;1513case 'I':1514if (features_.allowSpecialFloats_) {1515token.type_ = tokenPosInf;1516ok = match("nfinity", 7);1517} else {1518ok = false;1519}1520break;1521case ',':1522token.type_ = tokenArraySeparator;1523break;1524case ':':1525token.type_ = tokenMemberSeparator;1526break;1527case 0:1528token.type_ = tokenEndOfStream;1529break;1530default:1531ok = false;1532break;1533}1534if (!ok)1535token.type_ = tokenError;1536token.end_ = current_;1537return true;1538}15391540void OurReader::skipSpaces() {1541while (current_ != end_) {1542Char c = *current_;1543if (c == ' ' || c == '\t' || c == '\r' || c == '\n')1544++current_;1545else1546break;1547}1548}15491550bool OurReader::match(Location pattern, int patternLength) {1551if (end_ - current_ < patternLength)1552return false;1553int index = patternLength;1554while (index--)1555if (current_[index] != pattern[index])1556return false;1557current_ += patternLength;1558return true;1559}15601561bool OurReader::readComment() {1562Location commentBegin = current_ - 1;1563Char c = getNextChar();1564bool successful = false;1565if (c == '*')1566successful = readCStyleComment();1567else if (c == '/')1568successful = readCppStyleComment();1569if (!successful)1570return false;15711572if (collectComments_) {1573CommentPlacement placement = commentBefore;1574if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {1575if (c != '*' || !containsNewLine(commentBegin, current_))1576placement = commentAfterOnSameLine;1577}15781579addComment(commentBegin, current_, placement);1580}1581return true;1582}15831584JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, OurReader::Location end) {1585JSONCPP_STRING normalized;1586normalized.reserve(static_cast<size_t>(end - begin));1587OurReader::Location current = begin;1588while (current != end) {1589char c = *current++;1590if (c == '\r') {1591if (current != end && *current == '\n')1592// convert dos EOL1593++current;1594// convert Mac EOL1595normalized += '\n';1596} else {1597normalized += c;1598}1599}1600return normalized;1601}16021603void1604OurReader::addComment(Location begin, Location end, CommentPlacement placement) {1605assert(collectComments_);1606const JSONCPP_STRING& normalized = normalizeEOL(begin, end);1607if (placement == commentAfterOnSameLine) {1608assert(lastValue_ != 0);1609lastValue_->setComment(normalized, placement);1610} else {1611commentsBefore_ += normalized;1612}1613}16141615bool OurReader::readCStyleComment() {1616while ((current_ + 1) < end_) {1617Char c = getNextChar();1618if (c == '*' && *current_ == '/')1619break;1620}1621return getNextChar() == '/';1622}16231624bool OurReader::readCppStyleComment() {1625while (current_ != end_) {1626Char c = getNextChar();1627if (c == '\n')1628break;1629if (c == '\r') {1630// Consume DOS EOL. It will be normalized in addComment.1631if (current_ != end_ && *current_ == '\n')1632getNextChar();1633// Break on Moc OS 9 EOL.1634break;1635}1636}1637return true;1638}16391640bool OurReader::readNumber(bool checkInf) {1641const char *p = current_;1642if (checkInf && p != end_ && *p == 'I') {1643current_ = ++p;1644return false;1645}1646char c = '0'; // stopgap for already consumed character1647// integral part1648while (c >= '0' && c <= '9')1649c = (current_ = p) < end_ ? *p++ : '\0';1650// fractional part1651if (c == '.') {1652c = (current_ = p) < end_ ? *p++ : '\0';1653while (c >= '0' && c <= '9')1654c = (current_ = p) < end_ ? *p++ : '\0';1655}1656// exponential part1657if (c == 'e' || c == 'E') {1658c = (current_ = p) < end_ ? *p++ : '\0';1659if (c == '+' || c == '-')1660c = (current_ = p) < end_ ? *p++ : '\0';1661while (c >= '0' && c <= '9')1662c = (current_ = p) < end_ ? *p++ : '\0';1663}1664return true;1665}1666bool OurReader::readString() {1667Char c = 0;1668while (current_ != end_) {1669c = getNextChar();1670if (c == '\\')1671getNextChar();1672else if (c == '"')1673break;1674}1675return c == '"';1676}167716781679bool OurReader::readStringSingleQuote() {1680Char c = 0;1681while (current_ != end_) {1682c = getNextChar();1683if (c == '\\')1684getNextChar();1685else if (c == '\'')1686break;1687}1688return c == '\'';1689}16901691bool OurReader::readObject(Token& tokenStart) {1692Token tokenName;1693JSONCPP_STRING name;1694Value init(objectValue);1695currentValue().swapPayload(init);1696currentValue().setOffsetStart(tokenStart.start_ - begin_);1697while (readToken(tokenName)) {1698bool initialTokenOk = true;1699while (tokenName.type_ == tokenComment && initialTokenOk)1700initialTokenOk = readToken(tokenName);1701if (!initialTokenOk)1702break;1703if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object1704return true;1705name.clear();1706if (tokenName.type_ == tokenString) {1707if (!decodeString(tokenName, name))1708return recoverFromError(tokenObjectEnd);1709} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {1710Value numberName;1711if (!decodeNumber(tokenName, numberName))1712return recoverFromError(tokenObjectEnd);1713name = numberName.asString();1714} else {1715break;1716}17171718Token colon;1719if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {1720return addErrorAndRecover(1721"Missing ':' after object member name", colon, tokenObjectEnd);1722}1723if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");1724if (features_.rejectDupKeys_ && currentValue().isMember(name)) {1725JSONCPP_STRING msg = "Duplicate key: '" + name + "'";1726return addErrorAndRecover(1727msg, tokenName, tokenObjectEnd);1728}1729Value& value = currentValue()[name];1730nodes_.push(&value);1731bool ok = readValue();1732nodes_.pop();1733if (!ok) // error already set1734return recoverFromError(tokenObjectEnd);17351736Token comma;1737if (!readToken(comma) ||1738(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&1739comma.type_ != tokenComment)) {1740return addErrorAndRecover(1741"Missing ',' or '}' in object declaration", comma, tokenObjectEnd);1742}1743bool finalizeTokenOk = true;1744while (comma.type_ == tokenComment && finalizeTokenOk)1745finalizeTokenOk = readToken(comma);1746if (comma.type_ == tokenObjectEnd)1747return true;1748}1749return addErrorAndRecover(1750"Missing '}' or object member name", tokenName, tokenObjectEnd);1751}17521753bool OurReader::readArray(Token& tokenStart) {1754Value init(arrayValue);1755currentValue().swapPayload(init);1756currentValue().setOffsetStart(tokenStart.start_ - begin_);1757skipSpaces();1758if (current_ != end_ && *current_ == ']') // empty array1759{1760Token endArray;1761readToken(endArray);1762return true;1763}1764int index = 0;1765for (;;) {1766Value& value = currentValue()[index++];1767nodes_.push(&value);1768bool ok = readValue();1769nodes_.pop();1770if (!ok) // error already set1771return recoverFromError(tokenArrayEnd);17721773Token token;1774// Accept Comment after last item in the array.1775ok = readToken(token);1776while (token.type_ == tokenComment && ok) {1777ok = readToken(token);1778}1779bool badTokenType =1780(token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);1781if (!ok || badTokenType) {1782return addErrorAndRecover(1783"Missing ',' or ']' in array declaration", token, tokenArrayEnd);1784}1785if (token.type_ == tokenArrayEnd)1786break;1787}1788return true;1789}17901791bool OurReader::decodeNumber(Token& token) {1792Value decoded;1793if (!decodeNumber(token, decoded))1794return false;1795currentValue().swapPayload(decoded);1796currentValue().setOffsetStart(token.start_ - begin_);1797currentValue().setOffsetLimit(token.end_ - begin_);1798return true;1799}18001801bool OurReader::decodeNumber(Token& token, Value& decoded) {1802// Attempts to parse the number as an integer. If the number is1803// larger than the maximum supported value of an integer then1804// we decode the number as a double.1805Location current = token.start_;1806bool isNegative = *current == '-';1807if (isNegative)1808++current;1809// TODO: Help the compiler do the div and mod at compile time or get rid of them.1810Value::LargestUInt maxIntegerValue =1811isNegative ? Value::LargestUInt(-Value::minLargestInt)1812: Value::maxLargestUInt;1813Value::LargestUInt threshold = maxIntegerValue / 10;1814Value::LargestUInt value = 0;1815while (current < token.end_) {1816Char c = *current++;1817if (c < '0' || c > '9')1818return decodeDouble(token, decoded);1819Value::UInt digit(static_cast<Value::UInt>(c - '0'));1820if (value >= threshold) {1821// We've hit or exceeded the max value divided by 10 (rounded down). If1822// a) we've only just touched the limit, b) this is the last digit, and1823// c) it's small enough to fit in that rounding delta, we're okay.1824// Otherwise treat this number as a double to avoid overflow.1825if (value > threshold || current != token.end_ ||1826digit > maxIntegerValue % 10) {1827return decodeDouble(token, decoded);1828}1829}1830value = value * 10 + digit;1831}1832if (isNegative)1833decoded = -Value::LargestInt(value);1834else if (value <= Value::LargestUInt(Value::maxInt))1835decoded = Value::LargestInt(value);1836else1837decoded = value;1838return true;1839}18401841bool OurReader::decodeDouble(Token& token) {1842Value decoded;1843if (!decodeDouble(token, decoded))1844return false;1845currentValue().swapPayload(decoded);1846currentValue().setOffsetStart(token.start_ - begin_);1847currentValue().setOffsetLimit(token.end_ - begin_);1848return true;1849}18501851bool OurReader::decodeDouble(Token& token, Value& decoded) {1852double value = 0;1853const int bufferSize = 32;1854int count;1855ptrdiff_t const length = token.end_ - token.start_;18561857// Sanity check to avoid buffer overflow exploits.1858if (length < 0) {1859return addError("Unable to parse token length", token);1860}1861size_t const ulength = static_cast<size_t>(length);18621863// Avoid using a string constant for the format control string given to1864// sscanf, as this can cause hard to debug crashes on OS X. See here for more1865// info:1866//1867// http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html1868char format[] = "%lf";18691870if (length <= bufferSize) {1871Char buffer[bufferSize + 1];1872memcpy(buffer, token.start_, ulength);1873buffer[length] = 0;1874fixNumericLocaleInput(buffer, buffer + length);1875count = sscanf(buffer, format, &value);1876} else {1877JSONCPP_STRING buffer(token.start_, token.end_);1878count = sscanf(buffer.c_str(), format, &value);1879}18801881if (count != 1)1882return addError("'" + JSONCPP_STRING(token.start_, token.end_) +1883"' is not a number.",1884token);1885decoded = value;1886return true;1887}18881889bool OurReader::decodeString(Token& token) {1890JSONCPP_STRING decoded_string;1891if (!decodeString(token, decoded_string))1892return false;1893Value decoded(decoded_string);1894currentValue().swapPayload(decoded);1895currentValue().setOffsetStart(token.start_ - begin_);1896currentValue().setOffsetLimit(token.end_ - begin_);1897return true;1898}18991900bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) {1901decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));1902Location current = token.start_ + 1; // skip '"'1903Location end = token.end_ - 1; // do not include '"'1904while (current != end) {1905Char c = *current++;1906if (c == '"')1907break;1908else if (c == '\\') {1909if (current == end)1910return addError("Empty escape sequence in string", token, current);1911Char escape = *current++;1912switch (escape) {1913case '"':1914decoded += '"';1915break;1916case '/':1917decoded += '/';1918break;1919case '\\':1920decoded += '\\';1921break;1922case 'b':1923decoded += '\b';1924break;1925case 'f':1926decoded += '\f';1927break;1928case 'n':1929decoded += '\n';1930break;1931case 'r':1932decoded += '\r';1933break;1934case 't':1935decoded += '\t';1936break;1937case 'u': {1938unsigned int unicode;1939if (!decodeUnicodeCodePoint(token, current, end, unicode))1940return false;1941decoded += codePointToUTF8(unicode);1942} break;1943default:1944return addError("Bad escape sequence in string", token, current);1945}1946} else {1947decoded += c;1948}1949}1950return true;1951}19521953bool OurReader::decodeUnicodeCodePoint(Token& token,1954Location& current,1955Location end,1956unsigned int& unicode) {19571958if (!decodeUnicodeEscapeSequence(token, current, end, unicode))1959return false;1960if (unicode >= 0xD800 && unicode <= 0xDBFF) {1961// surrogate pairs1962if (end - current < 6)1963return addError(1964"additional six characters expected to parse unicode surrogate pair.",1965token,1966current);1967unsigned int surrogatePair;1968if (*(current++) == '\\' && *(current++) == 'u') {1969if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {1970unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);1971} else1972return false;1973} else1974return addError("expecting another \\u token to begin the second half of "1975"a unicode surrogate pair",1976token,1977current);1978}1979return true;1980}19811982bool OurReader::decodeUnicodeEscapeSequence(Token& token,1983Location& current,1984Location end,1985unsigned int& ret_unicode) {1986if (end - current < 4)1987return addError(1988"Bad unicode escape sequence in string: four digits expected.",1989token,1990current);1991int unicode = 0;1992for (int index = 0; index < 4; ++index) {1993Char c = *current++;1994unicode *= 16;1995if (c >= '0' && c <= '9')1996unicode += c - '0';1997else if (c >= 'a' && c <= 'f')1998unicode += c - 'a' + 10;1999else if (c >= 'A' && c <= 'F')2000unicode += c - 'A' + 10;2001else2002return addError(2003"Bad unicode escape sequence in string: hexadecimal digit expected.",2004token,2005current);2006}2007ret_unicode = static_cast<unsigned int>(unicode);2008return true;2009}20102011bool2012OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {2013ErrorInfo info;2014info.token_ = token;2015info.message_ = message;2016info.extra_ = extra;2017errors_.push_back(info);2018return false;2019}20202021bool OurReader::recoverFromError(TokenType skipUntilToken) {2022size_t errorCount = errors_.size();2023Token skip;2024for (;;) {2025if (!readToken(skip))2026errors_.resize(errorCount); // discard errors caused by recovery2027if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)2028break;2029}2030errors_.resize(errorCount);2031return false;2032}20332034bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message,2035Token& token,2036TokenType skipUntilToken) {2037addError(message, token);2038return recoverFromError(skipUntilToken);2039}20402041Value& OurReader::currentValue() { return *(nodes_.top()); }20422043OurReader::Char OurReader::getNextChar() {2044if (current_ == end_)2045return 0;2046return *current_++;2047}20482049void OurReader::getLocationLineAndColumn(Location location,2050int& line,2051int& column) const {2052Location current = begin_;2053Location lastLineStart = current;2054line = 0;2055while (current < location && current != end_) {2056Char c = *current++;2057if (c == '\r') {2058if (*current == '\n')2059++current;2060lastLineStart = current;2061++line;2062} else if (c == '\n') {2063lastLineStart = current;2064++line;2065}2066}2067// column & line start at 12068column = int(location - lastLineStart) + 1;2069++line;2070}20712072JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const {2073int line, column;2074getLocationLineAndColumn(location, line, column);2075char buffer[18 + 16 + 16 + 1];2076snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);2077return buffer;2078}20792080JSONCPP_STRING OurReader::getFormattedErrorMessages() const {2081JSONCPP_STRING formattedMessage;2082for (Errors::const_iterator itError = errors_.begin();2083itError != errors_.end();2084++itError) {2085const ErrorInfo& error = *itError;2086formattedMessage +=2087"* " + getLocationLineAndColumn(error.token_.start_) + "\n";2088formattedMessage += " " + error.message_ + "\n";2089if (error.extra_)2090formattedMessage +=2091"See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";2092}2093return formattedMessage;2094}20952096std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {2097std::vector<OurReader::StructuredError> allErrors;2098for (Errors::const_iterator itError = errors_.begin();2099itError != errors_.end();2100++itError) {2101const ErrorInfo& error = *itError;2102OurReader::StructuredError structured;2103structured.offset_start = error.token_.start_ - begin_;2104structured.offset_limit = error.token_.end_ - begin_;2105structured.message = error.message_;2106allErrors.push_back(structured);2107}2108return allErrors;2109}21102111bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) {2112ptrdiff_t length = end_ - begin_;2113if(value.getOffsetStart() > length2114|| value.getOffsetLimit() > length)2115return false;2116Token token;2117token.type_ = tokenError;2118token.start_ = begin_ + value.getOffsetStart();2119token.end_ = end_ + value.getOffsetLimit();2120ErrorInfo info;2121info.token_ = token;2122info.message_ = message;2123info.extra_ = 0;2124errors_.push_back(info);2125return true;2126}21272128bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {2129ptrdiff_t length = end_ - begin_;2130if(value.getOffsetStart() > length2131|| value.getOffsetLimit() > length2132|| extra.getOffsetLimit() > length)2133return false;2134Token token;2135token.type_ = tokenError;2136token.start_ = begin_ + value.getOffsetStart();2137token.end_ = begin_ + value.getOffsetLimit();2138ErrorInfo info;2139info.token_ = token;2140info.message_ = message;2141info.extra_ = begin_ + extra.getOffsetStart();2142errors_.push_back(info);2143return true;2144}21452146bool OurReader::good() const {2147return !errors_.size();2148}214921502151class OurCharReader : public CharReader {2152bool const collectComments_;2153OurReader reader_;2154public:2155OurCharReader(2156bool collectComments,2157OurFeatures const& features)2158: collectComments_(collectComments)2159, reader_(features)2160{}2161bool parse(2162char const* beginDoc, char const* endDoc,2163Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE {2164bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);2165if (errs) {2166*errs = reader_.getFormattedErrorMessages();2167}2168return ok;2169}2170};21712172CharReaderBuilder::CharReaderBuilder()2173{2174setDefaults(&settings_);2175}2176CharReaderBuilder::~CharReaderBuilder()2177{}2178CharReader* CharReaderBuilder::newCharReader() const2179{2180bool collectComments = settings_["collectComments"].asBool();2181OurFeatures features = OurFeatures::all();2182features.allowComments_ = settings_["allowComments"].asBool();2183features.strictRoot_ = settings_["strictRoot"].asBool();2184features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();2185features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();2186features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();2187features.stackLimit_ = settings_["stackLimit"].asInt();2188features.failIfExtra_ = settings_["failIfExtra"].asBool();2189features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();2190features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();2191return new OurCharReader(collectComments, features);2192}2193static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys)2194{2195valid_keys->clear();2196valid_keys->insert("collectComments");2197valid_keys->insert("allowComments");2198valid_keys->insert("strictRoot");2199valid_keys->insert("allowDroppedNullPlaceholders");2200valid_keys->insert("allowNumericKeys");2201valid_keys->insert("allowSingleQuotes");2202valid_keys->insert("stackLimit");2203valid_keys->insert("failIfExtra");2204valid_keys->insert("rejectDupKeys");2205valid_keys->insert("allowSpecialFloats");2206}2207bool CharReaderBuilder::validate(Json::Value* invalid) const2208{2209Json::Value my_invalid;2210if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL2211Json::Value& inv = *invalid;2212std::set<JSONCPP_STRING> valid_keys;2213getValidReaderKeys(&valid_keys);2214Value::Members keys = settings_.getMemberNames();2215size_t n = keys.size();2216for (size_t i = 0; i < n; ++i) {2217JSONCPP_STRING const& key = keys[i];2218if (valid_keys.find(key) == valid_keys.end()) {2219inv[key] = settings_[key];2220}2221}2222return 0u == inv.size();2223}2224Value& CharReaderBuilder::operator[](JSONCPP_STRING key)2225{2226return settings_[key];2227}2228// static2229void CharReaderBuilder::strictMode(Json::Value* settings)2230{2231//! [CharReaderBuilderStrictMode]2232(*settings)["allowComments"] = false;2233(*settings)["strictRoot"] = true;2234(*settings)["allowDroppedNullPlaceholders"] = false;2235(*settings)["allowNumericKeys"] = false;2236(*settings)["allowSingleQuotes"] = false;2237(*settings)["stackLimit"] = 1000;2238(*settings)["failIfExtra"] = true;2239(*settings)["rejectDupKeys"] = true;2240(*settings)["allowSpecialFloats"] = false;2241//! [CharReaderBuilderStrictMode]2242}2243// static2244void CharReaderBuilder::setDefaults(Json::Value* settings)2245{2246//! [CharReaderBuilderDefaults]2247(*settings)["collectComments"] = true;2248(*settings)["allowComments"] = true;2249(*settings)["strictRoot"] = false;2250(*settings)["allowDroppedNullPlaceholders"] = false;2251(*settings)["allowNumericKeys"] = false;2252(*settings)["allowSingleQuotes"] = false;2253(*settings)["stackLimit"] = 1000;2254(*settings)["failIfExtra"] = false;2255(*settings)["rejectDupKeys"] = false;2256(*settings)["allowSpecialFloats"] = false;2257//! [CharReaderBuilderDefaults]2258}22592260//////////////////////////////////2261// global functions22622263bool parseFromStream(2264CharReader::Factory const& fact, JSONCPP_ISTREAM& sin,2265Value* root, JSONCPP_STRING* errs)2266{2267JSONCPP_OSTRINGSTREAM ssin;2268ssin << sin.rdbuf();2269JSONCPP_STRING doc = ssin.str();2270char const* begin = doc.data();2271char const* end = begin + doc.size();2272// Note that we do not actually need a null-terminator.2273CharReaderPtr const reader(fact.newCharReader());2274return reader->parse(begin, end, root, errs);2275}22762277JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) {2278CharReaderBuilder b;2279JSONCPP_STRING errs;2280bool ok = parseFromStream(b, sin, &root, &errs);2281if (!ok) {2282throwRuntimeError(errs);2283}2284return sin;2285}22862287} // namespace Json22882289// //////////////////////////////////////////////////////////////////////2290// End of content of file: src/lib_json/json_reader.cpp2291// //////////////////////////////////////////////////////////////////////2292229322942295229622972298// //////////////////////////////////////////////////////////////////////2299// Beginning of content of file: src/lib_json/json_valueiterator.inl2300// //////////////////////////////////////////////////////////////////////23012302// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors2303// Distributed under MIT license, or public domain if desired and2304// recognized in your jurisdiction.2305// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE23062307// included by json_value.cpp23082309namespace Json {23102311// //////////////////////////////////////////////////////////////////2312// //////////////////////////////////////////////////////////////////2313// //////////////////////////////////////////////////////////////////2314// class ValueIteratorBase2315// //////////////////////////////////////////////////////////////////2316// //////////////////////////////////////////////////////////////////2317// //////////////////////////////////////////////////////////////////23182319ValueIteratorBase::ValueIteratorBase()2320: current_(), isNull_(true) {2321}23222323ValueIteratorBase::ValueIteratorBase(2324const Value::ObjectValues::iterator& current)2325: current_(current), isNull_(false) {}23262327Value& ValueIteratorBase::deref() const {2328return current_->second;2329}23302331void ValueIteratorBase::increment() {2332++current_;2333}23342335void ValueIteratorBase::decrement() {2336--current_;2337}23382339ValueIteratorBase::difference_type2340ValueIteratorBase::computeDistance(const SelfType& other) const {2341#ifdef JSON_USE_CPPTL_SMALLMAP2342return other.current_ - current_;2343#else2344// Iterator for null value are initialized using the default2345// constructor, which initialize current_ to the default2346// std::map::iterator. As begin() and end() are two instance2347// of the default std::map::iterator, they can not be compared.2348// To allow this, we handle this comparison specifically.2349if (isNull_ && other.isNull_) {2350return 0;2351}23522353// Usage of std::distance is not portable (does not compile with Sun Studio 122354// RogueWave STL,2355// which is the one used by default).2356// Using a portable hand-made version for non random iterator instead:2357// return difference_type( std::distance( current_, other.current_ ) );2358difference_type myDistance = 0;2359for (Value::ObjectValues::iterator it = current_; it != other.current_;2360++it) {2361++myDistance;2362}2363return myDistance;2364#endif2365}23662367bool ValueIteratorBase::isEqual(const SelfType& other) const {2368if (isNull_) {2369return other.isNull_;2370}2371return current_ == other.current_;2372}23732374void ValueIteratorBase::copy(const SelfType& other) {2375current_ = other.current_;2376isNull_ = other.isNull_;2377}23782379Value ValueIteratorBase::key() const {2380const Value::CZString czstring = (*current_).first;2381if (czstring.data()) {2382if (czstring.isStaticString())2383return Value(StaticString(czstring.data()));2384return Value(czstring.data(), czstring.data() + czstring.length());2385}2386return Value(czstring.index());2387}23882389UInt ValueIteratorBase::index() const {2390const Value::CZString czstring = (*current_).first;2391if (!czstring.data())2392return czstring.index();2393return Value::UInt(-1);2394}23952396JSONCPP_STRING ValueIteratorBase::name() const {2397char const* keey;2398char const* end;2399keey = memberName(&end);2400if (!keey) return JSONCPP_STRING();2401return JSONCPP_STRING(keey, end);2402}24032404char const* ValueIteratorBase::memberName() const {2405const char* cname = (*current_).first.data();2406return cname ? cname : "";2407}24082409char const* ValueIteratorBase::memberName(char const** end) const {2410const char* cname = (*current_).first.data();2411if (!cname) {2412*end = NULL;2413return NULL;2414}2415*end = cname + (*current_).first.length();2416return cname;2417}24182419// //////////////////////////////////////////////////////////////////2420// //////////////////////////////////////////////////////////////////2421// //////////////////////////////////////////////////////////////////2422// class ValueConstIterator2423// //////////////////////////////////////////////////////////////////2424// //////////////////////////////////////////////////////////////////2425// //////////////////////////////////////////////////////////////////24262427ValueConstIterator::ValueConstIterator() {}24282429ValueConstIterator::ValueConstIterator(2430const Value::ObjectValues::iterator& current)2431: ValueIteratorBase(current) {}24322433ValueConstIterator::ValueConstIterator(ValueIterator const& other)2434: ValueIteratorBase(other) {}24352436ValueConstIterator& ValueConstIterator::2437operator=(const ValueIteratorBase& other) {2438copy(other);2439return *this;2440}24412442// //////////////////////////////////////////////////////////////////2443// //////////////////////////////////////////////////////////////////2444// //////////////////////////////////////////////////////////////////2445// class ValueIterator2446// //////////////////////////////////////////////////////////////////2447// //////////////////////////////////////////////////////////////////2448// //////////////////////////////////////////////////////////////////24492450ValueIterator::ValueIterator() {}24512452ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)2453: ValueIteratorBase(current) {}24542455ValueIterator::ValueIterator(const ValueConstIterator& other)2456: ValueIteratorBase(other) {2457throwRuntimeError("ConstIterator to Iterator should never be allowed.");2458}24592460ValueIterator::ValueIterator(const ValueIterator& other)2461: ValueIteratorBase(other) {}24622463ValueIterator& ValueIterator::operator=(const SelfType& other) {2464copy(other);2465return *this;2466}24672468} // namespace Json24692470// //////////////////////////////////////////////////////////////////////2471// End of content of file: src/lib_json/json_valueiterator.inl2472// //////////////////////////////////////////////////////////////////////2473247424752476247724782479// //////////////////////////////////////////////////////////////////////2480// Beginning of content of file: src/lib_json/json_value.cpp2481// //////////////////////////////////////////////////////////////////////24822483// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors2484// Distributed under MIT license, or public domain if desired and2485// recognized in your jurisdiction.2486// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE24872488#if !defined(JSON_IS_AMALGAMATION)2489#include <json/assertions.h>2490#include <json/value.h>2491#include <json/writer.h>2492#endif // if !defined(JSON_IS_AMALGAMATION)2493#include <math.h>2494#include <sstream>2495#include <utility>2496#include <cstring>2497#include <cassert>2498#ifdef JSON_USE_CPPTL2499#include <cpptl/conststring.h>2500#endif2501#include <cstddef> // size_t2502#include <algorithm> // min()25032504#define JSON_ASSERT_UNREACHABLE assert(false)25052506namespace Json {25072508// This is a walkaround to avoid the static initialization of Value::null.2509// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of2510// 8 (instead of 4) as a bit of future-proofing.2511#if defined(__ARMEL__)2512#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))2513#else2514#define ALIGNAS(byte_alignment)2515#endif2516//static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };2517//const unsigned char& kNullRef = kNull[0];2518//const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);2519//const Value& Value::nullRef = null;25202521// static2522Value const& Value::nullSingleton()2523{2524static Value const nullStatic;2525return nullStatic;2526}25272528// for backwards compatibility, we'll leave these global references around, but DO NOT2529// use them in JSONCPP library code any more!2530Value const& Value::null = Value::nullSingleton();2531Value const& Value::nullRef = Value::nullSingleton();25322533const Int Value::minInt = Int(~(UInt(-1) / 2));2534const Int Value::maxInt = Int(UInt(-1) / 2);2535const UInt Value::maxUInt = UInt(-1);2536#if defined(JSON_HAS_INT64)2537const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));2538const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);2539const UInt64 Value::maxUInt64 = UInt64(-1);2540// The constant is hard-coded because some compiler have trouble2541// converting Value::maxUInt64 to a double correctly (AIX/xlC).2542// Assumes that UInt64 is a 64 bits integer.2543static const double maxUInt64AsDouble = 18446744073709551615.0;2544#endif // defined(JSON_HAS_INT64)2545const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));2546const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);2547const LargestUInt Value::maxLargestUInt = LargestUInt(-1);25482549const UInt Value::defaultRealPrecision = 17;25502551#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)2552template <typename T, typename U>2553static inline bool InRange(double d, T min, U max) {2554// The casts can lose precision, but we are looking only for2555// an approximate range. Might fail on edge cases though. ~cdunn2556//return d >= static_cast<double>(min) && d <= static_cast<double>(max);2557return d >= min && d <= max;2558}2559#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)2560static inline double integerToDouble(Json::UInt64 value) {2561return static_cast<double>(Int64(value / 2)) * 2.0 + static_cast<double>(Int64(value & 1));2562}25632564template <typename T> static inline double integerToDouble(T value) {2565return static_cast<double>(value);2566}25672568template <typename T, typename U>2569static inline bool InRange(double d, T min, U max) {2570return d >= integerToDouble(min) && d <= integerToDouble(max);2571}2572#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)25732574/** Duplicates the specified string value.2575* @param value Pointer to the string to duplicate. Must be zero-terminated if2576* length is "unknown".2577* @param length Length of the value. if equals to unknown, then it will be2578* computed using strlen(value).2579* @return Pointer on the duplicate instance of string.2580*/2581static inline char* duplicateStringValue(const char* value,2582size_t length)2583{2584// Avoid an integer overflow in the call to malloc below by limiting length2585// to a sane value.2586if (length >= static_cast<size_t>(Value::maxInt))2587length = Value::maxInt - 1;25882589char* newString = static_cast<char*>(malloc(length + 1));2590if (newString == NULL) {2591throwRuntimeError(2592"in Json::Value::duplicateStringValue(): "2593"Failed to allocate string value buffer");2594}2595memcpy(newString, value, length);2596newString[length] = 0;2597return newString;2598}25992600/* Record the length as a prefix.2601*/2602static inline char* duplicateAndPrefixStringValue(2603const char* value,2604unsigned int length)2605{2606// Avoid an integer overflow in the call to malloc below by limiting length2607// to a sane value.2608JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) - sizeof(unsigned) - 1U,2609"in Json::Value::duplicateAndPrefixStringValue(): "2610"length too big for prefixing");2611unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;2612char* newString = static_cast<char*>(malloc(actualLength));2613if (newString == 0) {2614throwRuntimeError(2615"in Json::Value::duplicateAndPrefixStringValue(): "2616"Failed to allocate string value buffer");2617}2618*reinterpret_cast<unsigned*>(newString) = length;2619memcpy(newString + sizeof(unsigned), value, length);2620newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later2621return newString;2622}2623inline static void decodePrefixedString(2624bool isPrefixed, char const* prefixed,2625unsigned* length, char const** value)2626{2627if (!isPrefixed) {2628*length = static_cast<unsigned>(strlen(prefixed));2629*value = prefixed;2630} else {2631*length = *reinterpret_cast<unsigned const*>(prefixed);2632*value = prefixed + sizeof(unsigned);2633}2634}2635/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue().2636*/2637#if JSONCPP_USING_SECURE_MEMORY2638static inline void releasePrefixedStringValue(char* value) {2639unsigned length = 0;2640char const* valueDecoded;2641decodePrefixedString(true, value, &length, &valueDecoded);2642size_t const size = sizeof(unsigned) + length + 1U;2643memset(value, 0, size);2644free(value);2645}2646static inline void releaseStringValue(char* value, unsigned length) {2647// length==0 => we allocated the strings memory2648size_t size = (length==0) ? strlen(value) : length;2649memset(value, 0, size);2650free(value);2651}2652#else // !JSONCPP_USING_SECURE_MEMORY2653static inline void releasePrefixedStringValue(char* value) {2654free(value);2655}2656static inline void releaseStringValue(char* value, unsigned) {2657free(value);2658}2659#endif // JSONCPP_USING_SECURE_MEMORY26602661} // namespace Json26622663// //////////////////////////////////////////////////////////////////2664// //////////////////////////////////////////////////////////////////2665// //////////////////////////////////////////////////////////////////2666// ValueInternals...2667// //////////////////////////////////////////////////////////////////2668// //////////////////////////////////////////////////////////////////2669// //////////////////////////////////////////////////////////////////2670#if !defined(JSON_IS_AMALGAMATION)26712672#include "json_valueiterator.inl"2673#endif // if !defined(JSON_IS_AMALGAMATION)26742675namespace Json {26762677Exception::Exception(JSONCPP_STRING const& msg)2678: msg_(msg)2679{}2680Exception::~Exception() JSONCPP_NOEXCEPT2681{}2682char const* Exception::what() const JSONCPP_NOEXCEPT2683{2684return msg_.c_str();2685}2686RuntimeError::RuntimeError(JSONCPP_STRING const& msg)2687: Exception(msg)2688{}2689LogicError::LogicError(JSONCPP_STRING const& msg)2690: Exception(msg)2691{}2692JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg)2693{2694throw RuntimeError(msg);2695}2696JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg)2697{2698throw LogicError(msg);2699}27002701// //////////////////////////////////////////////////////////////////2702// //////////////////////////////////////////////////////////////////2703// //////////////////////////////////////////////////////////////////2704// class Value::CommentInfo2705// //////////////////////////////////////////////////////////////////2706// //////////////////////////////////////////////////////////////////2707// //////////////////////////////////////////////////////////////////27082709Value::CommentInfo::CommentInfo() : comment_(0)2710{}27112712Value::CommentInfo::~CommentInfo() {2713if (comment_)2714releaseStringValue(comment_, 0u);2715}27162717void Value::CommentInfo::setComment(const char* text, size_t len) {2718if (comment_) {2719releaseStringValue(comment_, 0u);2720comment_ = 0;2721}2722JSON_ASSERT(text != 0);2723JSON_ASSERT_MESSAGE(2724text[0] == '\0' || text[0] == '/',2725"in Json::Value::setComment(): Comments must start with /");2726// It seems that /**/ style comments are acceptable as well.2727comment_ = duplicateStringValue(text, len);2728}27292730// //////////////////////////////////////////////////////////////////2731// //////////////////////////////////////////////////////////////////2732// //////////////////////////////////////////////////////////////////2733// class Value::CZString2734// //////////////////////////////////////////////////////////////////2735// //////////////////////////////////////////////////////////////////2736// //////////////////////////////////////////////////////////////////27372738// Notes: policy_ indicates if the string was allocated when2739// a string is stored.27402741Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {}27422743Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate)2744: cstr_(str) {2745// allocate != duplicate2746storage_.policy_ = allocate & 0x3;2747storage_.length_ = ulength & 0x3FFFFFFF;2748}27492750Value::CZString::CZString(const CZString& other) {2751cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 02752? duplicateStringValue(other.cstr_, other.storage_.length_)2753: other.cstr_);2754storage_.policy_ = static_cast<unsigned>(other.cstr_2755? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication2756? noDuplication : duplicate)2757: static_cast<DuplicationPolicy>(other.storage_.policy_)) & 3U;2758storage_.length_ = other.storage_.length_;2759}27602761#if JSON_HAS_RVALUE_REFERENCES2762Value::CZString::CZString(CZString&& other)2763: cstr_(other.cstr_), index_(other.index_) {2764other.cstr_ = nullptr;2765}2766#endif27672768Value::CZString::~CZString() {2769if (cstr_ && storage_.policy_ == duplicate) {2770releaseStringValue(const_cast<char*>(cstr_), storage_.length_ + 1u); //+1 for null terminating character for sake of completeness but not actually necessary2771}2772}27732774void Value::CZString::swap(CZString& other) {2775std::swap(cstr_, other.cstr_);2776std::swap(index_, other.index_);2777}27782779Value::CZString& Value::CZString::operator=(const CZString& other) {2780cstr_ = other.cstr_;2781index_ = other.index_;2782return *this;2783}27842785#if JSON_HAS_RVALUE_REFERENCES2786Value::CZString& Value::CZString::operator=(CZString&& other) {2787cstr_ = other.cstr_;2788index_ = other.index_;2789other.cstr_ = nullptr;2790return *this;2791}2792#endif27932794bool Value::CZString::operator<(const CZString& other) const {2795if (!cstr_) return index_ < other.index_;2796//return strcmp(cstr_, other.cstr_) < 0;2797// Assume both are strings.2798unsigned this_len = this->storage_.length_;2799unsigned other_len = other.storage_.length_;2800unsigned min_len = std::min<unsigned>(this_len, other_len);2801JSON_ASSERT(this->cstr_ && other.cstr_);2802int comp = memcmp(this->cstr_, other.cstr_, min_len);2803if (comp < 0) return true;2804if (comp > 0) return false;2805return (this_len < other_len);2806}28072808bool Value::CZString::operator==(const CZString& other) const {2809if (!cstr_) return index_ == other.index_;2810//return strcmp(cstr_, other.cstr_) == 0;2811// Assume both are strings.2812unsigned this_len = this->storage_.length_;2813unsigned other_len = other.storage_.length_;2814if (this_len != other_len) return false;2815JSON_ASSERT(this->cstr_ && other.cstr_);2816int comp = memcmp(this->cstr_, other.cstr_, this_len);2817return comp == 0;2818}28192820ArrayIndex Value::CZString::index() const { return index_; }28212822//const char* Value::CZString::c_str() const { return cstr_; }2823const char* Value::CZString::data() const { return cstr_; }2824unsigned Value::CZString::length() const { return storage_.length_; }2825bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; }28262827// //////////////////////////////////////////////////////////////////2828// //////////////////////////////////////////////////////////////////2829// //////////////////////////////////////////////////////////////////2830// class Value::Value2831// //////////////////////////////////////////////////////////////////2832// //////////////////////////////////////////////////////////////////2833// //////////////////////////////////////////////////////////////////28342835/*! \internal Default constructor initialization must be equivalent to:2836* memset( this, 0, sizeof(Value) )2837* This optimization is used in ValueInternalMap fast allocator.2838*/2839Value::Value(ValueType vtype) {2840static char const emptyString[] = "";2841initBasic(vtype);2842switch (vtype) {2843case nullValue:2844break;2845case intValue:2846case uintValue:2847value_.int_ = 0;2848break;2849case realValue:2850value_.real_ = 0.0;2851break;2852case stringValue:2853// allocated_ == false, so this is safe.2854value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));2855break;2856case arrayValue:2857case objectValue:2858value_.map_ = new ObjectValues();2859break;2860case booleanValue:2861value_.bool_ = false;2862break;2863default:2864JSON_ASSERT_UNREACHABLE;2865}2866}28672868Value::Value(Int value) {2869initBasic(intValue);2870value_.int_ = value;2871}28722873Value::Value(UInt value) {2874initBasic(uintValue);2875value_.uint_ = value;2876}2877#if defined(JSON_HAS_INT64)2878Value::Value(Int64 value) {2879initBasic(intValue);2880value_.int_ = value;2881}2882Value::Value(UInt64 value) {2883initBasic(uintValue);2884value_.uint_ = value;2885}2886#endif // defined(JSON_HAS_INT64)28872888Value::Value(double value) {2889initBasic(realValue);2890value_.real_ = value;2891}28922893Value::Value(const char* value) {2894initBasic(stringValue, true);2895JSON_ASSERT_MESSAGE(value != NULL, "Null Value Passed to Value Constructor");2896value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value)));2897}28982899Value::Value(const char* beginValue, const char* endValue) {2900initBasic(stringValue, true);2901value_.string_ =2902duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue));2903}29042905Value::Value(const JSONCPP_STRING& value) {2906initBasic(stringValue, true);2907value_.string_ =2908duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length()));2909}29102911Value::Value(const StaticString& value) {2912initBasic(stringValue);2913value_.string_ = const_cast<char*>(value.c_str());2914}29152916#ifdef JSON_USE_CPPTL2917Value::Value(const CppTL::ConstString& value) {2918initBasic(stringValue, true);2919value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length()));2920}2921#endif29222923Value::Value(bool value) {2924initBasic(booleanValue);2925value_.bool_ = value;2926}29272928Value::Value(const Value& other) {2929dupPayload(other);2930dupMeta(other);2931}29322933#if JSON_HAS_RVALUE_REFERENCES2934// Move constructor2935Value::Value(Value&& other) {2936initBasic(nullValue);2937swap(other);2938}2939#endif29402941Value::~Value() {2942releasePayload();29432944delete[] comments_;29452946value_.uint_ = 0;2947}29482949Value& Value::operator=(Value other) {2950swap(other);2951return *this;2952}29532954void Value::swapPayload(Value& other) {2955ValueType temp = type_;2956type_ = other.type_;2957other.type_ = temp;2958std::swap(value_, other.value_);2959int temp2 = allocated_;2960allocated_ = other.allocated_;2961other.allocated_ = temp2 & 0x1;2962}29632964void Value::copyPayload(const Value& other) {2965releasePayload();2966dupPayload(other);2967}29682969void Value::swap(Value& other) {2970swapPayload(other);2971std::swap(comments_, other.comments_);2972std::swap(start_, other.start_);2973std::swap(limit_, other.limit_);2974}29752976void Value::copy(const Value& other) {2977copyPayload(other);2978delete[] comments_;2979dupMeta(other);2980}29812982ValueType Value::type() const { return type_; }29832984int Value::compare(const Value& other) const {2985if (*this < other)2986return -1;2987if (*this > other)2988return 1;2989return 0;2990}29912992bool Value::operator<(const Value& other) const {2993int typeDelta = type_ - other.type_;2994if (typeDelta)2995return typeDelta < 0 ? true : false;2996switch (type_) {2997case nullValue:2998return false;2999case intValue:3000return value_.int_ < other.value_.int_;3001case uintValue:3002return value_.uint_ < other.value_.uint_;3003case realValue:3004return value_.real_ < other.value_.real_;3005case booleanValue:3006return value_.bool_ < other.value_.bool_;3007case stringValue:3008{3009if ((value_.string_ == 0) || (other.value_.string_ == 0)) {3010if (other.value_.string_) return true;3011else return false;3012}3013unsigned this_len;3014unsigned other_len;3015char const* this_str;3016char const* other_str;3017decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);3018decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);3019unsigned min_len = std::min<unsigned>(this_len, other_len);3020JSON_ASSERT(this_str && other_str);3021int comp = memcmp(this_str, other_str, min_len);3022if (comp < 0) return true;3023if (comp > 0) return false;3024return (this_len < other_len);3025}3026case arrayValue:3027case objectValue: {3028int delta = int(value_.map_->size() - other.value_.map_->size());3029if (delta)3030return delta < 0;3031return (*value_.map_) < (*other.value_.map_);3032}3033default:3034JSON_ASSERT_UNREACHABLE;3035}3036return false; // unreachable3037}30383039bool Value::operator<=(const Value& other) const { return !(other < *this); }30403041bool Value::operator>=(const Value& other) const { return !(*this < other); }30423043bool Value::operator>(const Value& other) const { return other < *this; }30443045bool Value::operator==(const Value& other) const {3046// if ( type_ != other.type_ )3047// GCC 2.95.3 says:3048// attempt to take address of bit-field structure member `Json::Value::type_'3049// Beats me, but a temp solves the problem.3050int temp = other.type_;3051if (type_ != temp)3052return false;3053switch (type_) {3054case nullValue:3055return true;3056case intValue:3057return value_.int_ == other.value_.int_;3058case uintValue:3059return value_.uint_ == other.value_.uint_;3060case realValue:3061return value_.real_ == other.value_.real_;3062case booleanValue:3063return value_.bool_ == other.value_.bool_;3064case stringValue:3065{3066if ((value_.string_ == 0) || (other.value_.string_ == 0)) {3067return (value_.string_ == other.value_.string_);3068}3069unsigned this_len;3070unsigned other_len;3071char const* this_str;3072char const* other_str;3073decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);3074decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);3075if (this_len != other_len) return false;3076JSON_ASSERT(this_str && other_str);3077int comp = memcmp(this_str, other_str, this_len);3078return comp == 0;3079}3080case arrayValue:3081case objectValue:3082return value_.map_->size() == other.value_.map_->size() &&3083(*value_.map_) == (*other.value_.map_);3084default:3085JSON_ASSERT_UNREACHABLE;3086}3087return false; // unreachable3088}30893090bool Value::operator!=(const Value& other) const { return !(*this == other); }30913092const char* Value::asCString() const {3093JSON_ASSERT_MESSAGE(type_ == stringValue,3094"in Json::Value::asCString(): requires stringValue");3095if (value_.string_ == 0) return 0;3096unsigned this_len;3097char const* this_str;3098decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);3099return this_str;3100}31013102#if JSONCPP_USING_SECURE_MEMORY3103unsigned Value::getCStringLength() const {3104JSON_ASSERT_MESSAGE(type_ == stringValue,3105"in Json::Value::asCString(): requires stringValue");3106if (value_.string_ == 0) return 0;3107unsigned this_len;3108char const* this_str;3109decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);3110return this_len;3111}3112#endif31133114bool Value::getString(char const** str, char const** cend) const {3115if (type_ != stringValue) return false;3116if (value_.string_ == 0) return false;3117unsigned length;3118decodePrefixedString(this->allocated_, this->value_.string_, &length, str);3119*cend = *str + length;3120return true;3121}31223123JSONCPP_STRING Value::asString() const {3124switch (type_) {3125case nullValue:3126return "";3127case stringValue:3128{3129if (value_.string_ == 0) return "";3130unsigned this_len;3131char const* this_str;3132decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);3133return JSONCPP_STRING(this_str, this_len);3134}3135case booleanValue:3136return value_.bool_ ? "true" : "false";3137case intValue:3138return valueToString(value_.int_);3139case uintValue:3140return valueToString(value_.uint_);3141case realValue:3142return valueToString(value_.real_);3143default:3144JSON_FAIL_MESSAGE("Type is not convertible to string");3145}3146}31473148#ifdef JSON_USE_CPPTL3149CppTL::ConstString Value::asConstString() const {3150unsigned len;3151char const* str;3152decodePrefixedString(allocated_, value_.string_,3153&len, &str);3154return CppTL::ConstString(str, len);3155}3156#endif31573158Value::Int Value::asInt() const {3159switch (type_) {3160case intValue:3161JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");3162return Int(value_.int_);3163case uintValue:3164JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");3165return Int(value_.uint_);3166case realValue:3167JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),3168"double out of Int range");3169return Int(value_.real_);3170case nullValue:3171return 0;3172case booleanValue:3173return value_.bool_ ? 1 : 0;3174default:3175break;3176}3177JSON_FAIL_MESSAGE("Value is not convertible to Int.");3178}31793180Value::UInt Value::asUInt() const {3181switch (type_) {3182case intValue:3183JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");3184return UInt(value_.int_);3185case uintValue:3186JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");3187return UInt(value_.uint_);3188case realValue:3189JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),3190"double out of UInt range");3191return UInt(value_.real_);3192case nullValue:3193return 0;3194case booleanValue:3195return value_.bool_ ? 1 : 0;3196default:3197break;3198}3199JSON_FAIL_MESSAGE("Value is not convertible to UInt.");3200}32013202#if defined(JSON_HAS_INT64)32033204Value::Int64 Value::asInt64() const {3205switch (type_) {3206case intValue:3207return Int64(value_.int_);3208case uintValue:3209JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");3210return Int64(value_.uint_);3211case realValue:3212JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),3213"double out of Int64 range");3214return Int64(value_.real_);3215case nullValue:3216return 0;3217case booleanValue:3218return value_.bool_ ? 1 : 0;3219default:3220break;3221}3222JSON_FAIL_MESSAGE("Value is not convertible to Int64.");3223}32243225Value::UInt64 Value::asUInt64() const {3226switch (type_) {3227case intValue:3228JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");3229return UInt64(value_.int_);3230case uintValue:3231return UInt64(value_.uint_);3232case realValue:3233JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),3234"double out of UInt64 range");3235return UInt64(value_.real_);3236case nullValue:3237return 0;3238case booleanValue:3239return value_.bool_ ? 1 : 0;3240default:3241break;3242}3243JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");3244}3245#endif // if defined(JSON_HAS_INT64)32463247LargestInt Value::asLargestInt() const {3248#if defined(JSON_NO_INT64)3249return asInt();3250#else3251return asInt64();3252#endif3253}32543255LargestUInt Value::asLargestUInt() const {3256#if defined(JSON_NO_INT64)3257return asUInt();3258#else3259return asUInt64();3260#endif3261}32623263double Value::asDouble() const {3264switch (type_) {3265case intValue:3266return static_cast<double>(value_.int_);3267case uintValue:3268#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)3269return static_cast<double>(value_.uint_);3270#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)3271return integerToDouble(value_.uint_);3272#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)3273case realValue:3274return value_.real_;3275case nullValue:3276return 0.0;3277case booleanValue:3278return value_.bool_ ? 1.0 : 0.0;3279default:3280break;3281}3282JSON_FAIL_MESSAGE("Value is not convertible to double.");3283}32843285float Value::asFloat() const {3286switch (type_) {3287case intValue:3288return static_cast<float>(value_.int_);3289case uintValue:3290#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)3291return static_cast<float>(value_.uint_);3292#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)3293// This can fail (silently?) if the value is bigger than MAX_FLOAT.3294return static_cast<float>(integerToDouble(value_.uint_));3295#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)3296case realValue:3297return static_cast<float>(value_.real_);3298case nullValue:3299return 0.0;3300case booleanValue:3301return value_.bool_ ? 1.0f : 0.0f;3302default:3303break;3304}3305JSON_FAIL_MESSAGE("Value is not convertible to float.");3306}33073308bool Value::asBool() const {3309switch (type_) {3310case booleanValue:3311return value_.bool_;3312case nullValue:3313return false;3314case intValue:3315return value_.int_ ? true : false;3316case uintValue:3317return value_.uint_ ? true : false;3318case realValue:3319// This is kind of strange. Not recommended.3320return (value_.real_ != 0.0) ? true : false;3321default:3322break;3323}3324JSON_FAIL_MESSAGE("Value is not convertible to bool.");3325}33263327bool Value::isConvertibleTo(ValueType other) const {3328switch (other) {3329case nullValue:3330return (isNumeric() && asDouble() == 0.0) ||3331(type_ == booleanValue && value_.bool_ == false) ||3332(type_ == stringValue && asString().empty()) ||3333(type_ == arrayValue && value_.map_->size() == 0) ||3334(type_ == objectValue && value_.map_->size() == 0) ||3335type_ == nullValue;3336case intValue:3337return isInt() ||3338(type_ == realValue && InRange(value_.real_, minInt, maxInt)) ||3339type_ == booleanValue || type_ == nullValue;3340case uintValue:3341return isUInt() ||3342(type_ == realValue && InRange(value_.real_, 0, maxUInt)) ||3343type_ == booleanValue || type_ == nullValue;3344case realValue:3345return isNumeric() || type_ == booleanValue || type_ == nullValue;3346case booleanValue:3347return isNumeric() || type_ == booleanValue || type_ == nullValue;3348case stringValue:3349return isNumeric() || type_ == booleanValue || type_ == stringValue ||3350type_ == nullValue;3351case arrayValue:3352return type_ == arrayValue || type_ == nullValue;3353case objectValue:3354return type_ == objectValue || type_ == nullValue;3355}3356JSON_ASSERT_UNREACHABLE;3357return false;3358}33593360/// Number of values in array or object3361ArrayIndex Value::size() const {3362switch (type_) {3363case nullValue:3364case intValue:3365case uintValue:3366case realValue:3367case booleanValue:3368case stringValue:3369return 0;3370case arrayValue: // size of the array is highest index + 13371if (!value_.map_->empty()) {3372ObjectValues::const_iterator itLast = value_.map_->end();3373--itLast;3374return (*itLast).first.index() + 1;3375}3376return 0;3377case objectValue:3378return ArrayIndex(value_.map_->size());3379}3380JSON_ASSERT_UNREACHABLE;3381return 0; // unreachable;3382}33833384bool Value::empty() const {3385if (isNull() || isArray() || isObject())3386return size() == 0u;3387else3388return false;3389}33903391Value::operator bool() const { return ! isNull(); }33923393void Value::clear() {3394JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||3395type_ == objectValue,3396"in Json::Value::clear(): requires complex value");3397start_ = 0;3398limit_ = 0;3399switch (type_) {3400case arrayValue:3401case objectValue:3402value_.map_->clear();3403break;3404default:3405break;3406}3407}34083409void Value::resize(ArrayIndex newSize) {3410JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,3411"in Json::Value::resize(): requires arrayValue");3412if (type_ == nullValue)3413*this = Value(arrayValue);3414ArrayIndex oldSize = size();3415if (newSize == 0)3416clear();3417else if (newSize > oldSize)3418this->operator[](newSize - 1);3419else {3420for (ArrayIndex index = newSize; index < oldSize; ++index) {3421value_.map_->erase(index);3422}3423JSON_ASSERT(size() == newSize);3424}3425}34263427Value& Value::operator[](ArrayIndex index) {3428JSON_ASSERT_MESSAGE(3429type_ == nullValue || type_ == arrayValue,3430"in Json::Value::operator[](ArrayIndex): requires arrayValue");3431if (type_ == nullValue)3432*this = Value(arrayValue);3433CZString key(index);3434ObjectValues::iterator it = value_.map_->lower_bound(key);3435if (it != value_.map_->end() && (*it).first == key)3436return (*it).second;34373438ObjectValues::value_type defaultValue(key, nullSingleton());3439it = value_.map_->insert(it, defaultValue);3440return (*it).second;3441}34423443Value& Value::operator[](int index) {3444JSON_ASSERT_MESSAGE(3445index >= 0,3446"in Json::Value::operator[](int index): index cannot be negative");3447return (*this)[ArrayIndex(index)];3448}34493450const Value& Value::operator[](ArrayIndex index) const {3451JSON_ASSERT_MESSAGE(3452type_ == nullValue || type_ == arrayValue,3453"in Json::Value::operator[](ArrayIndex)const: requires arrayValue");3454if (type_ == nullValue)3455return nullSingleton();3456CZString key(index);3457ObjectValues::const_iterator it = value_.map_->find(key);3458if (it == value_.map_->end())3459return nullSingleton();3460return (*it).second;3461}34623463const Value& Value::operator[](int index) const {3464JSON_ASSERT_MESSAGE(3465index >= 0,3466"in Json::Value::operator[](int index) const: index cannot be negative");3467return (*this)[ArrayIndex(index)];3468}34693470void Value::initBasic(ValueType vtype, bool allocated) {3471type_ = vtype;3472allocated_ = allocated;3473comments_ = 0;3474start_ = 0;3475limit_ = 0;3476}34773478void Value::dupPayload(const Value& other) {3479type_ = other.type_;3480allocated_ = false;3481switch (type_) {3482case nullValue:3483case intValue:3484case uintValue:3485case realValue:3486case booleanValue:3487value_ = other.value_;3488break;3489case stringValue:3490if (other.value_.string_ && other.allocated_) {3491unsigned len;3492char const* str;3493decodePrefixedString(other.allocated_, other.value_.string_,3494&len, &str);3495value_.string_ = duplicateAndPrefixStringValue(str, len);3496allocated_ = true;3497} else {3498value_.string_ = other.value_.string_;3499}3500break;3501case arrayValue:3502case objectValue:3503value_.map_ = new ObjectValues(*other.value_.map_);3504break;3505default:3506JSON_ASSERT_UNREACHABLE;3507}3508}35093510void Value::releasePayload() {3511switch (type_) {3512case nullValue:3513case intValue:3514case uintValue:3515case realValue:3516case booleanValue:3517break;3518case stringValue:3519if (allocated_)3520releasePrefixedStringValue(value_.string_);3521break;3522case arrayValue:3523case objectValue:3524delete value_.map_;3525break;3526default:3527JSON_ASSERT_UNREACHABLE;3528}3529}35303531void Value::dupMeta(const Value& other) {3532if (other.comments_) {3533comments_ = new CommentInfo[numberOfCommentPlacement];3534for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {3535const CommentInfo& otherComment = other.comments_[comment];3536if (otherComment.comment_)3537comments_[comment].setComment(3538otherComment.comment_, strlen(otherComment.comment_));3539}3540} else {3541comments_ = 0;3542}3543start_ = other.start_;3544limit_ = other.limit_;3545}35463547// Access an object value by name, create a null member if it does not exist.3548// @pre Type of '*this' is object or null.3549// @param key is null-terminated.3550Value& Value::resolveReference(const char* key) {3551JSON_ASSERT_MESSAGE(3552type_ == nullValue || type_ == objectValue,3553"in Json::Value::resolveReference(): requires objectValue");3554if (type_ == nullValue)3555*this = Value(objectValue);3556CZString actualKey(3557key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE!3558ObjectValues::iterator it = value_.map_->lower_bound(actualKey);3559if (it != value_.map_->end() && (*it).first == actualKey)3560return (*it).second;35613562ObjectValues::value_type defaultValue(actualKey, nullSingleton());3563it = value_.map_->insert(it, defaultValue);3564Value& value = (*it).second;3565return value;3566}35673568// @param key is not null-terminated.3569Value& Value::resolveReference(char const* key, char const* cend)3570{3571JSON_ASSERT_MESSAGE(3572type_ == nullValue || type_ == objectValue,3573"in Json::Value::resolveReference(key, end): requires objectValue");3574if (type_ == nullValue)3575*this = Value(objectValue);3576CZString actualKey(3577key, static_cast<unsigned>(cend-key), CZString::duplicateOnCopy);3578ObjectValues::iterator it = value_.map_->lower_bound(actualKey);3579if (it != value_.map_->end() && (*it).first == actualKey)3580return (*it).second;35813582ObjectValues::value_type defaultValue(actualKey, nullSingleton());3583it = value_.map_->insert(it, defaultValue);3584Value& value = (*it).second;3585return value;3586}35873588Value Value::get(ArrayIndex index, const Value& defaultValue) const {3589const Value* value = &((*this)[index]);3590return value == &nullSingleton() ? defaultValue : *value;3591}35923593bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }35943595Value const* Value::find(char const* key, char const* cend) const3596{3597JSON_ASSERT_MESSAGE(3598type_ == nullValue || type_ == objectValue,3599"in Json::Value::find(key, end, found): requires objectValue or nullValue");3600if (type_ == nullValue) return NULL;3601CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);3602ObjectValues::const_iterator it = value_.map_->find(actualKey);3603if (it == value_.map_->end()) return NULL;3604return &(*it).second;3605}3606const Value& Value::operator[](const char* key) const3607{3608Value const* found = find(key, key + strlen(key));3609if (!found) return nullSingleton();3610return *found;3611}3612Value const& Value::operator[](JSONCPP_STRING const& key) const3613{3614Value const* found = find(key.data(), key.data() + key.length());3615if (!found) return nullSingleton();3616return *found;3617}36183619Value& Value::operator[](const char* key) {3620return resolveReference(key, key + strlen(key));3621}36223623Value& Value::operator[](const JSONCPP_STRING& key) {3624return resolveReference(key.data(), key.data() + key.length());3625}36263627Value& Value::operator[](const StaticString& key) {3628return resolveReference(key.c_str());3629}36303631#ifdef JSON_USE_CPPTL3632Value& Value::operator[](const CppTL::ConstString& key) {3633return resolveReference(key.c_str(), key.end_c_str());3634}3635Value const& Value::operator[](CppTL::ConstString const& key) const3636{3637Value const* found = find(key.c_str(), key.end_c_str());3638if (!found) return nullSingleton();3639return *found;3640}3641#endif36423643Value& Value::append(const Value& value) { return (*this)[size()] = value; }36443645#if JSON_HAS_RVALUE_REFERENCES3646Value& Value::append(Value&& value) { return (*this)[size()] = std::move(value); }3647#endif36483649Value Value::get(char const* key, char const* cend, Value const& defaultValue) const3650{3651Value const* found = find(key, cend);3652return !found ? defaultValue : *found;3653}3654Value Value::get(char const* key, Value const& defaultValue) const3655{3656return get(key, key + strlen(key), defaultValue);3657}3658Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const3659{3660return get(key.data(), key.data() + key.length(), defaultValue);3661}366236633664bool Value::removeMember(const char* key, const char* cend, Value* removed)3665{3666if (type_ != objectValue) {3667return false;3668}3669CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);3670ObjectValues::iterator it = value_.map_->find(actualKey);3671if (it == value_.map_->end())3672return false;3673if (removed)3674#if JSON_HAS_RVALUE_REFERENCES3675*removed = std::move(it->second);3676#else3677*removed = it->second;3678#endif3679value_.map_->erase(it);3680return true;3681}3682bool Value::removeMember(const char* key, Value* removed)3683{3684return removeMember(key, key + strlen(key), removed);3685}3686bool Value::removeMember(JSONCPP_STRING const& key, Value* removed)3687{3688return removeMember(key.data(), key.data() + key.length(), removed);3689}3690void Value::removeMember(const char* key)3691{3692JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,3693"in Json::Value::removeMember(): requires objectValue");3694if (type_ == nullValue)3695return;36963697CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication);3698value_.map_->erase(actualKey);3699}3700void Value::removeMember(const JSONCPP_STRING& key)3701{3702removeMember(key.c_str());3703}37043705bool Value::removeIndex(ArrayIndex index, Value* removed) {3706if (type_ != arrayValue) {3707return false;3708}3709CZString key(index);3710ObjectValues::iterator it = value_.map_->find(key);3711if (it == value_.map_->end()) {3712return false;3713}3714*removed = it->second;3715ArrayIndex oldSize = size();3716// shift left all items left, into the place of the "removed"3717for (ArrayIndex i = index; i < (oldSize - 1); ++i){3718CZString keey(i);3719(*value_.map_)[keey] = (*this)[i + 1];3720}3721// erase the last one ("leftover")3722CZString keyLast(oldSize - 1);3723ObjectValues::iterator itLast = value_.map_->find(keyLast);3724value_.map_->erase(itLast);3725return true;3726}37273728#ifdef JSON_USE_CPPTL3729Value Value::get(const CppTL::ConstString& key,3730const Value& defaultValue) const {3731return get(key.c_str(), key.end_c_str(), defaultValue);3732}3733#endif37343735bool Value::isMember(char const* key, char const* cend) const3736{3737Value const* value = find(key, cend);3738return NULL != value;3739}3740bool Value::isMember(char const* key) const3741{3742return isMember(key, key + strlen(key));3743}3744bool Value::isMember(JSONCPP_STRING const& key) const3745{3746return isMember(key.data(), key.data() + key.length());3747}37483749#ifdef JSON_USE_CPPTL3750bool Value::isMember(const CppTL::ConstString& key) const {3751return isMember(key.c_str(), key.end_c_str());3752}3753#endif37543755Value::Members Value::getMemberNames() const {3756JSON_ASSERT_MESSAGE(3757type_ == nullValue || type_ == objectValue,3758"in Json::Value::getMemberNames(), value must be objectValue");3759if (type_ == nullValue)3760return Value::Members();3761Members members;3762members.reserve(value_.map_->size());3763ObjectValues::const_iterator it = value_.map_->begin();3764ObjectValues::const_iterator itEnd = value_.map_->end();3765for (; it != itEnd; ++it) {3766members.push_back(JSONCPP_STRING((*it).first.data(),3767(*it).first.length()));3768}3769return members;3770}3771//3772//# ifdef JSON_USE_CPPTL3773// EnumMemberNames3774// Value::enumMemberNames() const3775//{3776// if ( type_ == objectValue )3777// {3778// return CppTL::Enum::any( CppTL::Enum::transform(3779// CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),3780// MemberNamesTransform() ) );3781// }3782// return EnumMemberNames();3783//}3784//3785//3786// EnumValues3787// Value::enumValues() const3788//{3789// if ( type_ == objectValue || type_ == arrayValue )3790// return CppTL::Enum::anyValues( *(value_.map_),3791// CppTL::Type<const Value &>() );3792// return EnumValues();3793//}3794//3795//# endif37963797static bool IsIntegral(double d) {3798double integral_part;3799return modf(d, &integral_part) == 0.0;3800}38013802bool Value::isNull() const { return type_ == nullValue; }38033804bool Value::isBool() const { return type_ == booleanValue; }38053806bool Value::isInt() const {3807switch (type_) {3808case intValue:3809#if defined(JSON_HAS_INT64)3810return value_.int_ >= minInt && value_.int_ <= maxInt;3811#else3812return true;3813#endif3814case uintValue:3815return value_.uint_ <= UInt(maxInt);3816case realValue:3817return value_.real_ >= minInt && value_.real_ <= maxInt &&3818IsIntegral(value_.real_);3819default:3820break;3821}3822return false;3823}38243825bool Value::isUInt() const {3826switch (type_) {3827case intValue:3828#if defined(JSON_HAS_INT64)3829return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);3830#else3831return value_.int_ >= 0;3832#endif3833case uintValue:3834#if defined(JSON_HAS_INT64)3835return value_.uint_ <= maxUInt;3836#else3837return true;3838#endif3839case realValue:3840return value_.real_ >= 0 && value_.real_ <= maxUInt &&3841IsIntegral(value_.real_);3842default:3843break;3844}3845return false;3846}38473848bool Value::isInt64() const {3849#if defined(JSON_HAS_INT64)3850switch (type_) {3851case intValue:3852return true;3853case uintValue:3854return value_.uint_ <= UInt64(maxInt64);3855case realValue:3856// Note that maxInt64 (= 2^63 - 1) is not exactly representable as a3857// double, so double(maxInt64) will be rounded up to 2^63. Therefore we3858// require the value to be strictly less than the limit.3859return value_.real_ >= double(minInt64) &&3860value_.real_ < double(maxInt64) && IsIntegral(value_.real_);3861default:3862break;3863}3864#endif // JSON_HAS_INT643865return false;3866}38673868bool Value::isUInt64() const {3869#if defined(JSON_HAS_INT64)3870switch (type_) {3871case intValue:3872return value_.int_ >= 0;3873case uintValue:3874return true;3875case realValue:3876// Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a3877// double, so double(maxUInt64) will be rounded up to 2^64. Therefore we3878// require the value to be strictly less than the limit.3879return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&3880IsIntegral(value_.real_);3881default:3882break;3883}3884#endif // JSON_HAS_INT643885return false;3886}38873888bool Value::isIntegral() const {3889switch (type_) {3890case intValue:3891case uintValue:3892return true;3893case realValue:3894#if defined(JSON_HAS_INT64)3895// Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a3896// double, so double(maxUInt64) will be rounded up to 2^64. Therefore we3897// require the value to be strictly less than the limit.3898return value_.real_ >= double(minInt64) && value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);3899#else3900return value_.real_ >= minInt && value_.real_ <= maxUInt && IsIntegral(value_.real_);3901#endif // JSON_HAS_INT643902default:3903break;3904}3905return false;3906}39073908bool Value::isDouble() const { return type_ == intValue || type_ == uintValue || type_ == realValue; }39093910bool Value::isNumeric() const { return isDouble(); }39113912bool Value::isString() const { return type_ == stringValue; }39133914bool Value::isArray() const { return type_ == arrayValue; }39153916bool Value::isObject() const { return type_ == objectValue; }39173918void Value::setComment(const char* comment, size_t len, CommentPlacement placement) {3919if (!comments_)3920comments_ = new CommentInfo[numberOfCommentPlacement];3921if ((len > 0) && (comment[len-1] == '\n')) {3922// Always discard trailing newline, to aid indentation.3923len -= 1;3924}3925comments_[placement].setComment(comment, len);3926}39273928void Value::setComment(const char* comment, CommentPlacement placement) {3929setComment(comment, strlen(comment), placement);3930}39313932void Value::setComment(const JSONCPP_STRING& comment, CommentPlacement placement) {3933setComment(comment.c_str(), comment.length(), placement);3934}39353936bool Value::hasComment(CommentPlacement placement) const {3937return comments_ != 0 && comments_[placement].comment_ != 0;3938}39393940JSONCPP_STRING Value::getComment(CommentPlacement placement) const {3941if (hasComment(placement))3942return comments_[placement].comment_;3943return "";3944}39453946void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }39473948void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; }39493950ptrdiff_t Value::getOffsetStart() const { return start_; }39513952ptrdiff_t Value::getOffsetLimit() const { return limit_; }39533954JSONCPP_STRING Value::toStyledString() const {3955StreamWriterBuilder builder;39563957JSONCPP_STRING out = this->hasComment(commentBefore) ? "\n" : "";3958out += Json::writeString(builder, *this);3959out += "\n";39603961return out;3962}39633964Value::const_iterator Value::begin() const {3965switch (type_) {3966case arrayValue:3967case objectValue:3968if (value_.map_)3969return const_iterator(value_.map_->begin());3970break;3971default:3972break;3973}3974return const_iterator();3975}39763977Value::const_iterator Value::end() const {3978switch (type_) {3979case arrayValue:3980case objectValue:3981if (value_.map_)3982return const_iterator(value_.map_->end());3983break;3984default:3985break;3986}3987return const_iterator();3988}39893990Value::iterator Value::begin() {3991switch (type_) {3992case arrayValue:3993case objectValue:3994if (value_.map_)3995return iterator(value_.map_->begin());3996break;3997default:3998break;3999}4000return iterator();4001}40024003Value::iterator Value::end() {4004switch (type_) {4005case arrayValue:4006case objectValue:4007if (value_.map_)4008return iterator(value_.map_->end());4009break;4010default:4011break;4012}4013return iterator();4014}40154016// class PathArgument4017// //////////////////////////////////////////////////////////////////40184019PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {}40204021PathArgument::PathArgument(ArrayIndex index)4022: key_(), index_(index), kind_(kindIndex) {}40234024PathArgument::PathArgument(const char* key)4025: key_(key), index_(), kind_(kindKey) {}40264027PathArgument::PathArgument(const JSONCPP_STRING& key)4028: key_(key.c_str()), index_(), kind_(kindKey) {}40294030// class Path4031// //////////////////////////////////////////////////////////////////40324033Path::Path(const JSONCPP_STRING& path,4034const PathArgument& a1,4035const PathArgument& a2,4036const PathArgument& a3,4037const PathArgument& a4,4038const PathArgument& a5) {4039InArgs in;4040in.reserve(5);4041in.push_back(&a1);4042in.push_back(&a2);4043in.push_back(&a3);4044in.push_back(&a4);4045in.push_back(&a5);4046makePath(path, in);4047}40484049void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) {4050const char* current = path.c_str();4051const char* end = current + path.length();4052InArgs::const_iterator itInArg = in.begin();4053while (current != end) {4054if (*current == '[') {4055++current;4056if (*current == '%')4057addPathInArg(path, in, itInArg, PathArgument::kindIndex);4058else {4059ArrayIndex index = 0;4060for (; current != end && *current >= '0' && *current <= '9'; ++current)4061index = index * 10 + ArrayIndex(*current - '0');4062args_.push_back(index);4063}4064if (current == end || *++current != ']')4065invalidPath(path, int(current - path.c_str()));4066} else if (*current == '%') {4067addPathInArg(path, in, itInArg, PathArgument::kindKey);4068++current;4069} else if (*current == '.' || *current == ']') {4070++current;4071} else {4072const char* beginName = current;4073while (current != end && !strchr("[.", *current))4074++current;4075args_.push_back(JSONCPP_STRING(beginName, current));4076}4077}4078}40794080void Path::addPathInArg(const JSONCPP_STRING& /*path*/,4081const InArgs& in,4082InArgs::const_iterator& itInArg,4083PathArgument::Kind kind) {4084if (itInArg == in.end()) {4085// Error: missing argument %d4086} else if ((*itInArg)->kind_ != kind) {4087// Error: bad argument type4088} else {4089args_.push_back(**itInArg++);4090}4091}40924093void Path::invalidPath(const JSONCPP_STRING& /*path*/, int /*location*/) {4094// Error: invalid path.4095}40964097const Value& Path::resolve(const Value& root) const {4098const Value* node = &root;4099for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {4100const PathArgument& arg = *it;4101if (arg.kind_ == PathArgument::kindIndex) {4102if (!node->isArray() || !node->isValidIndex(arg.index_)) {4103// Error: unable to resolve path (array value expected at position...4104return Value::null;4105}4106node = &((*node)[arg.index_]);4107} else if (arg.kind_ == PathArgument::kindKey) {4108if (!node->isObject()) {4109// Error: unable to resolve path (object value expected at position...)4110return Value::null;4111}4112node = &((*node)[arg.key_]);4113if (node == &Value::nullSingleton()) {4114// Error: unable to resolve path (object has no member named '' at4115// position...)4116return Value::null;4117}4118}4119}4120return *node;4121}41224123Value Path::resolve(const Value& root, const Value& defaultValue) const {4124const Value* node = &root;4125for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {4126const PathArgument& arg = *it;4127if (arg.kind_ == PathArgument::kindIndex) {4128if (!node->isArray() || !node->isValidIndex(arg.index_))4129return defaultValue;4130node = &((*node)[arg.index_]);4131} else if (arg.kind_ == PathArgument::kindKey) {4132if (!node->isObject())4133return defaultValue;4134node = &((*node)[arg.key_]);4135if (node == &Value::nullSingleton())4136return defaultValue;4137}4138}4139return *node;4140}41414142Value& Path::make(Value& root) const {4143Value* node = &root;4144for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {4145const PathArgument& arg = *it;4146if (arg.kind_ == PathArgument::kindIndex) {4147if (!node->isArray()) {4148// Error: node is not an array at position ...4149}4150node = &((*node)[arg.index_]);4151} else if (arg.kind_ == PathArgument::kindKey) {4152if (!node->isObject()) {4153// Error: node is not an object at position...4154}4155node = &((*node)[arg.key_]);4156}4157}4158return *node;4159}41604161} // namespace Json41624163// //////////////////////////////////////////////////////////////////////4164// End of content of file: src/lib_json/json_value.cpp4165// //////////////////////////////////////////////////////////////////////4166416741684169417041714172// //////////////////////////////////////////////////////////////////////4173// Beginning of content of file: src/lib_json/json_writer.cpp4174// //////////////////////////////////////////////////////////////////////41754176// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors4177// Distributed under MIT license, or public domain if desired and4178// recognized in your jurisdiction.4179// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE41804181#if !defined(JSON_IS_AMALGAMATION)4182#include <json/writer.h>4183#include "json_tool.h"4184#endif // if !defined(JSON_IS_AMALGAMATION)4185#include <iomanip>4186#include <memory>4187#include <sstream>4188#include <utility>4189#include <set>4190#include <cassert>4191#include <cstring>4192#include <cstdio>41934194#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.04195#include <float.h>4196#define isfinite _finite4197#elif defined(__sun) && defined(__SVR4) //Solaris4198#if !defined(isfinite)4199#include <ieeefp.h>4200#define isfinite finite4201#endif4202#elif defined(_AIX)4203#if !defined(isfinite)4204#include <math.h>4205#define isfinite finite4206#endif4207#elif defined(__hpux)4208#if !defined(isfinite)4209#if defined(__ia64) && !defined(finite)4210#define isfinite(x) ((sizeof(x) == sizeof(float) ? \4211_Isfinitef(x) : _IsFinite(x)))4212#else4213#include <math.h>4214#define isfinite finite4215#endif4216#endif4217#else4218#include <cmath>4219#if !(defined(__QNXNTO__)) // QNX already defines isfinite4220#define isfinite std::isfinite4221#endif4222#endif42234224#if defined(_MSC_VER)4225#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above4226#define snprintf sprintf_s4227#elif _MSC_VER >= 1900 // VC++ 14.0 and above4228#define snprintf std::snprintf4229#else4230#define snprintf _snprintf4231#endif4232#elif defined(__ANDROID__) || defined(__QNXNTO__)4233#define snprintf snprintf4234#elif __cplusplus >= 201103L4235#if !defined(__MINGW32__) && !defined(__CYGWIN__)4236#define snprintf std::snprintf4237#endif4238#endif42394240#if defined(__BORLANDC__)4241#include <float.h>4242#define isfinite _finite4243#define snprintf _snprintf4244#endif42454246#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.04247// Disable warning about strdup being deprecated.4248#pragma warning(disable : 4996)4249#endif42504251namespace Json {42524253#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)4254typedef std::unique_ptr<StreamWriter> StreamWriterPtr;4255#else4256typedef std::auto_ptr<StreamWriter> StreamWriterPtr;4257#endif42584259JSONCPP_STRING valueToString(LargestInt value) {4260UIntToStringBuffer buffer;4261char* current = buffer + sizeof(buffer);4262if (value == Value::minLargestInt) {4263uintToString(LargestUInt(Value::maxLargestInt) + 1, current);4264*--current = '-';4265} else if (value < 0) {4266uintToString(LargestUInt(-value), current);4267*--current = '-';4268} else {4269uintToString(LargestUInt(value), current);4270}4271assert(current >= buffer);4272return current;4273}42744275JSONCPP_STRING valueToString(LargestUInt value) {4276UIntToStringBuffer buffer;4277char* current = buffer + sizeof(buffer);4278uintToString(value, current);4279assert(current >= buffer);4280return current;4281}42824283#if defined(JSON_HAS_INT64)42844285JSONCPP_STRING valueToString(Int value) {4286return valueToString(LargestInt(value));4287}42884289JSONCPP_STRING valueToString(UInt value) {4290return valueToString(LargestUInt(value));4291}42924293#endif // # if defined(JSON_HAS_INT64)42944295namespace {4296JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision, PrecisionType precisionType) {4297// Allocate a buffer that is more than large enough to store the 16 digits of4298// precision requested below.4299char buffer[36];4300int len = -1;43014302char formatString[15];4303if (precisionType == PrecisionType::significantDigits) {4304snprintf(formatString, sizeof(formatString), "%%.%ug", precision);4305} else {4306snprintf(formatString, sizeof(formatString), "%%.%uf", precision);4307}43084309// Print into the buffer. We need not request the alternative representation4310// that always has a decimal point because JSON doesn't distinguish the4311// concepts of reals and integers.4312if (isfinite(value)) {4313len = snprintf(buffer, sizeof(buffer), formatString, value);4314fixNumericLocale(buffer, buffer + len);4315// to delete use-less too much zeros in the end of string4316if (precisionType == PrecisionType::decimalPlaces) {4317fixZerosInTheEnd(buffer, buffer + len);4318}43194320// try to ensure we preserve the fact that this was given to us as a double on input4321if (!strchr(buffer, '.') && !strchr(buffer, 'e')) {4322strcat(buffer, ".0");4323}43244325} else {4326// IEEE standard states that NaN values will not compare to themselves4327if (value != value) {4328len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");4329} else if (value < 0) {4330len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");4331} else {4332len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");4333}4334}4335assert(len >= 0);4336return buffer;4337}4338}43394340JSONCPP_STRING valueToString(double value, unsigned int precision, PrecisionType precisionType) {4341return valueToString(value, false, precision, precisionType);4342}43434344JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; }43454346static bool isAnyCharRequiredQuoting(char const* s, size_t n) {4347assert(s || !n);43484349char const* const end = s + n;4350for (char const* cur = s; cur < end; ++cur) {4351if (*cur == '\\' || *cur == '\"' || *cur < ' '4352|| static_cast<unsigned char>(*cur) < 0x80)4353return true;4354}4355return false;4356}43574358static unsigned int utf8ToCodepoint(const char*& s, const char* e) {4359const unsigned int REPLACEMENT_CHARACTER = 0xFFFD;43604361unsigned int firstByte = static_cast<unsigned char>(*s);43624363if (firstByte < 0x80)4364return firstByte;43654366if (firstByte < 0xE0) {4367if (e - s < 2)4368return REPLACEMENT_CHARACTER;43694370unsigned int calculated = ((firstByte & 0x1F) << 6)4371| (static_cast<unsigned int>(s[1]) & 0x3F);4372s += 1;4373// oversized encoded characters are invalid4374return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated;4375}43764377if (firstByte < 0xF0) {4378if (e - s < 3)4379return REPLACEMENT_CHARACTER;43804381unsigned int calculated = ((firstByte & 0x0F) << 12)4382| ((static_cast<unsigned int>(s[1]) & 0x3F) << 6)4383| (static_cast<unsigned int>(s[2]) & 0x3F);4384s += 2;4385// surrogates aren't valid codepoints itself4386// shouldn't be UTF-8 encoded4387if (calculated >= 0xD800 && calculated <= 0xDFFF)4388return REPLACEMENT_CHARACTER;4389// oversized encoded characters are invalid4390return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated;4391}43924393if (firstByte < 0xF8) {4394if (e - s < 4)4395return REPLACEMENT_CHARACTER;43964397unsigned int calculated = ((firstByte & 0x07) << 18)4398| ((static_cast<unsigned int>(s[1]) & 0x3F) << 12)4399| ((static_cast<unsigned int>(s[2]) & 0x3F) << 6)4400| (static_cast<unsigned int>(s[3]) & 0x3F);4401s += 3;4402// oversized encoded characters are invalid4403return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated;4404}44054406return REPLACEMENT_CHARACTER;4407}44084409static const char hex2[] =4410"000102030405060708090a0b0c0d0e0f"4411"101112131415161718191a1b1c1d1e1f"4412"202122232425262728292a2b2c2d2e2f"4413"303132333435363738393a3b3c3d3e3f"4414"404142434445464748494a4b4c4d4e4f"4415"505152535455565758595a5b5c5d5e5f"4416"606162636465666768696a6b6c6d6e6f"4417"707172737475767778797a7b7c7d7e7f"4418"808182838485868788898a8b8c8d8e8f"4419"909192939495969798999a9b9c9d9e9f"4420"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"4421"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"4422"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"4423"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"4424"e0e1e2e3e4e5e6e7e8e9eaebecedeeef"4425"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";44264427static JSONCPP_STRING toHex16Bit(unsigned int x) {4428const unsigned int hi = (x >> 8) & 0xff;4429const unsigned int lo = x & 0xff;4430JSONCPP_STRING result(4, ' ');4431result[0] = hex2[2 * hi];4432result[1] = hex2[2 * hi + 1];4433result[2] = hex2[2 * lo];4434result[3] = hex2[2 * lo + 1];4435return result;4436}44374438static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) {4439if (value == NULL)4440return "";44414442if (!isAnyCharRequiredQuoting(value, length))4443return JSONCPP_STRING("\"") + value + "\"";4444// We have to walk value and escape any special characters.4445// Appending to JSONCPP_STRING is not efficient, but this should be rare.4446// (Note: forward slashes are *not* rare, but I am not escaping them.)4447JSONCPP_STRING::size_type maxsize =4448length * 2 + 3; // allescaped+quotes+NULL4449JSONCPP_STRING result;4450result.reserve(maxsize); // to avoid lots of mallocs4451result += "\"";4452char const* end = value + length;4453for (const char* c = value; c != end; ++c) {4454switch (*c) {4455case '\"':4456result += "\\\"";4457break;4458case '\\':4459result += "\\\\";4460break;4461case '\b':4462result += "\\b";4463break;4464case '\f':4465result += "\\f";4466break;4467case '\n':4468result += "\\n";4469break;4470case '\r':4471result += "\\r";4472break;4473case '\t':4474result += "\\t";4475break;4476// case '/':4477// Even though \/ is considered a legal escape in JSON, a bare4478// slash is also legal, so I see no reason to escape it.4479// (I hope I am not misunderstanding something.)4480// blep notes: actually escaping \/ may be useful in javascript to avoid </4481// sequence.4482// Should add a flag to allow this compatibility mode and prevent this4483// sequence from occurring.4484default: {4485unsigned int cp = utf8ToCodepoint(c, end);4486// don't escape non-control characters4487// (short escape sequence are applied above)4488if (cp < 0x80 && cp >= 0x20)4489result += static_cast<char>(cp);4490else if (cp < 0x10000) { // codepoint is in Basic Multilingual Plane4491result += "\\u";4492result += toHex16Bit(cp);4493}4494else { // codepoint is not in Basic Multilingual Plane4495// convert to surrogate pair first4496cp -= 0x10000;4497result += "\\u";4498result += toHex16Bit((cp >> 10) + 0xD800);4499result += "\\u";4500result += toHex16Bit((cp & 0x3FF) + 0xDC00);4501}4502}4503break;4504}4505}4506result += "\"";4507return result;4508}45094510JSONCPP_STRING valueToQuotedString(const char* value) {4511return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));4512}45134514// Class Writer4515// //////////////////////////////////////////////////////////////////4516Writer::~Writer() {}45174518// Class FastWriter4519// //////////////////////////////////////////////////////////////////45204521FastWriter::FastWriter()4522: yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false),4523omitEndingLineFeed_(false) {}45244525void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; }45264527void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }45284529void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }45304531JSONCPP_STRING FastWriter::write(const Value& root) {4532document_.clear();4533writeValue(root);4534if (!omitEndingLineFeed_)4535document_ += "\n";4536return document_;4537}45384539void FastWriter::writeValue(const Value& value) {4540switch (value.type()) {4541case nullValue:4542if (!dropNullPlaceholders_)4543document_ += "null";4544break;4545case intValue:4546document_ += valueToString(value.asLargestInt());4547break;4548case uintValue:4549document_ += valueToString(value.asLargestUInt());4550break;4551case realValue:4552document_ += valueToString(value.asDouble());4553break;4554case stringValue:4555{4556// Is NULL possible for value.string_? No.4557char const* str;4558char const* end;4559bool ok = value.getString(&str, &end);4560if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str));4561break;4562}4563case booleanValue:4564document_ += valueToString(value.asBool());4565break;4566case arrayValue: {4567document_ += '[';4568ArrayIndex size = value.size();4569for (ArrayIndex index = 0; index < size; ++index) {4570if (index > 0)4571document_ += ',';4572writeValue(value[index]);4573}4574document_ += ']';4575} break;4576case objectValue: {4577Value::Members members(value.getMemberNames());4578document_ += '{';4579for (Value::Members::iterator it = members.begin(); it != members.end();4580++it) {4581const JSONCPP_STRING& name = *it;4582if (it != members.begin())4583document_ += ',';4584document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()));4585document_ += yamlCompatibilityEnabled_ ? ": " : ":";4586writeValue(value[name]);4587}4588document_ += '}';4589} break;4590}4591}45924593// Class StyledWriter4594// //////////////////////////////////////////////////////////////////45954596StyledWriter::StyledWriter()4597: rightMargin_(74), indentSize_(3), addChildValues_() {}45984599JSONCPP_STRING StyledWriter::write(const Value& root) {4600document_.clear();4601addChildValues_ = false;4602indentString_.clear();4603writeCommentBeforeValue(root);4604writeValue(root);4605writeCommentAfterValueOnSameLine(root);4606document_ += "\n";4607return document_;4608}46094610void StyledWriter::writeValue(const Value& value) {4611switch (value.type()) {4612case nullValue:4613pushValue("null");4614break;4615case intValue:4616pushValue(valueToString(value.asLargestInt()));4617break;4618case uintValue:4619pushValue(valueToString(value.asLargestUInt()));4620break;4621case realValue:4622pushValue(valueToString(value.asDouble()));4623break;4624case stringValue:4625{4626// Is NULL possible for value.string_? No.4627char const* str;4628char const* end;4629bool ok = value.getString(&str, &end);4630if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));4631else pushValue("");4632break;4633}4634case booleanValue:4635pushValue(valueToString(value.asBool()));4636break;4637case arrayValue:4638writeArrayValue(value);4639break;4640case objectValue: {4641Value::Members members(value.getMemberNames());4642if (members.empty())4643pushValue("{}");4644else {4645writeWithIndent("{");4646indent();4647Value::Members::iterator it = members.begin();4648for (;;) {4649const JSONCPP_STRING& name = *it;4650const Value& childValue = value[name];4651writeCommentBeforeValue(childValue);4652writeWithIndent(valueToQuotedString(name.c_str()));4653document_ += " : ";4654writeValue(childValue);4655if (++it == members.end()) {4656writeCommentAfterValueOnSameLine(childValue);4657break;4658}4659document_ += ',';4660writeCommentAfterValueOnSameLine(childValue);4661}4662unindent();4663writeWithIndent("}");4664}4665} break;4666}4667}46684669void StyledWriter::writeArrayValue(const Value& value) {4670unsigned size = value.size();4671if (size == 0)4672pushValue("[]");4673else {4674bool isArrayMultiLine = isMultilineArray(value);4675if (isArrayMultiLine) {4676writeWithIndent("[");4677indent();4678bool hasChildValue = !childValues_.empty();4679unsigned index = 0;4680for (;;) {4681const Value& childValue = value[index];4682writeCommentBeforeValue(childValue);4683if (hasChildValue)4684writeWithIndent(childValues_[index]);4685else {4686writeIndent();4687writeValue(childValue);4688}4689if (++index == size) {4690writeCommentAfterValueOnSameLine(childValue);4691break;4692}4693document_ += ',';4694writeCommentAfterValueOnSameLine(childValue);4695}4696unindent();4697writeWithIndent("]");4698} else // output on a single line4699{4700assert(childValues_.size() == size);4701document_ += "[ ";4702for (unsigned index = 0; index < size; ++index) {4703if (index > 0)4704document_ += ", ";4705document_ += childValues_[index];4706}4707document_ += " ]";4708}4709}4710}47114712bool StyledWriter::isMultilineArray(const Value& value) {4713ArrayIndex const size = value.size();4714bool isMultiLine = size * 3 >= rightMargin_;4715childValues_.clear();4716for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {4717const Value& childValue = value[index];4718isMultiLine = ((childValue.isArray() || childValue.isObject()) &&4719childValue.size() > 0);4720}4721if (!isMultiLine) // check if line length > max line length4722{4723childValues_.reserve(size);4724addChildValues_ = true;4725ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'4726for (ArrayIndex index = 0; index < size; ++index) {4727if (hasCommentForValue(value[index])) {4728isMultiLine = true;4729}4730writeValue(value[index]);4731lineLength += static_cast<ArrayIndex>(childValues_[index].length());4732}4733addChildValues_ = false;4734isMultiLine = isMultiLine || lineLength >= rightMargin_;4735}4736return isMultiLine;4737}47384739void StyledWriter::pushValue(const JSONCPP_STRING& value) {4740if (addChildValues_)4741childValues_.push_back(value);4742else4743document_ += value;4744}47454746void StyledWriter::writeIndent() {4747if (!document_.empty()) {4748char last = document_[document_.length() - 1];4749if (last == ' ') // already indented4750return;4751if (last != '\n') // Comments may add new-line4752document_ += '\n';4753}4754document_ += indentString_;4755}47564757void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) {4758writeIndent();4759document_ += value;4760}47614762void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); }47634764void StyledWriter::unindent() {4765assert(indentString_.size() >= indentSize_);4766indentString_.resize(indentString_.size() - indentSize_);4767}47684769void StyledWriter::writeCommentBeforeValue(const Value& root) {4770if (!root.hasComment(commentBefore))4771return;47724773document_ += "\n";4774writeIndent();4775const JSONCPP_STRING& comment = root.getComment(commentBefore);4776JSONCPP_STRING::const_iterator iter = comment.begin();4777while (iter != comment.end()) {4778document_ += *iter;4779if (*iter == '\n' &&4780((iter+1) != comment.end() && *(iter + 1) == '/'))4781writeIndent();4782++iter;4783}47844785// Comments are stripped of trailing newlines, so add one here4786document_ += "\n";4787}47884789void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {4790if (root.hasComment(commentAfterOnSameLine))4791document_ += " " + root.getComment(commentAfterOnSameLine);47924793if (root.hasComment(commentAfter)) {4794document_ += "\n";4795document_ += root.getComment(commentAfter);4796document_ += "\n";4797}4798}47994800bool StyledWriter::hasCommentForValue(const Value& value) {4801return value.hasComment(commentBefore) ||4802value.hasComment(commentAfterOnSameLine) ||4803value.hasComment(commentAfter);4804}48054806// Class StyledStreamWriter4807// //////////////////////////////////////////////////////////////////48084809StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation)4810: document_(NULL), rightMargin_(74), indentation_(indentation),4811addChildValues_(), indented_(false)4812{}48134814void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) {4815document_ = &out;4816addChildValues_ = false;4817indentString_.clear();4818indented_ = true;4819writeCommentBeforeValue(root);4820if (!indented_) writeIndent();4821indented_ = true;4822writeValue(root);4823writeCommentAfterValueOnSameLine(root);4824*document_ << "\n";4825document_ = NULL; // Forget the stream, for safety.4826}48274828void StyledStreamWriter::writeValue(const Value& value) {4829switch (value.type()) {4830case nullValue:4831pushValue("null");4832break;4833case intValue:4834pushValue(valueToString(value.asLargestInt()));4835break;4836case uintValue:4837pushValue(valueToString(value.asLargestUInt()));4838break;4839case realValue:4840pushValue(valueToString(value.asDouble()));4841break;4842case stringValue:4843{4844// Is NULL possible for value.string_? No.4845char const* str;4846char const* end;4847bool ok = value.getString(&str, &end);4848if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));4849else pushValue("");4850break;4851}4852case booleanValue:4853pushValue(valueToString(value.asBool()));4854break;4855case arrayValue:4856writeArrayValue(value);4857break;4858case objectValue: {4859Value::Members members(value.getMemberNames());4860if (members.empty())4861pushValue("{}");4862else {4863writeWithIndent("{");4864indent();4865Value::Members::iterator it = members.begin();4866for (;;) {4867const JSONCPP_STRING& name = *it;4868const Value& childValue = value[name];4869writeCommentBeforeValue(childValue);4870writeWithIndent(valueToQuotedString(name.c_str()));4871*document_ << " : ";4872writeValue(childValue);4873if (++it == members.end()) {4874writeCommentAfterValueOnSameLine(childValue);4875break;4876}4877*document_ << ",";4878writeCommentAfterValueOnSameLine(childValue);4879}4880unindent();4881writeWithIndent("}");4882}4883} break;4884}4885}48864887void StyledStreamWriter::writeArrayValue(const Value& value) {4888unsigned size = value.size();4889if (size == 0)4890pushValue("[]");4891else {4892bool isArrayMultiLine = isMultilineArray(value);4893if (isArrayMultiLine) {4894writeWithIndent("[");4895indent();4896bool hasChildValue = !childValues_.empty();4897unsigned index = 0;4898for (;;) {4899const Value& childValue = value[index];4900writeCommentBeforeValue(childValue);4901if (hasChildValue)4902writeWithIndent(childValues_[index]);4903else {4904if (!indented_) writeIndent();4905indented_ = true;4906writeValue(childValue);4907indented_ = false;4908}4909if (++index == size) {4910writeCommentAfterValueOnSameLine(childValue);4911break;4912}4913*document_ << ",";4914writeCommentAfterValueOnSameLine(childValue);4915}4916unindent();4917writeWithIndent("]");4918} else // output on a single line4919{4920assert(childValues_.size() == size);4921*document_ << "[ ";4922for (unsigned index = 0; index < size; ++index) {4923if (index > 0)4924*document_ << ", ";4925*document_ << childValues_[index];4926}4927*document_ << " ]";4928}4929}4930}49314932bool StyledStreamWriter::isMultilineArray(const Value& value) {4933ArrayIndex const size = value.size();4934bool isMultiLine = size * 3 >= rightMargin_;4935childValues_.clear();4936for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {4937const Value& childValue = value[index];4938isMultiLine = ((childValue.isArray() || childValue.isObject()) &&4939childValue.size() > 0);4940}4941if (!isMultiLine) // check if line length > max line length4942{4943childValues_.reserve(size);4944addChildValues_ = true;4945ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'4946for (ArrayIndex index = 0; index < size; ++index) {4947if (hasCommentForValue(value[index])) {4948isMultiLine = true;4949}4950writeValue(value[index]);4951lineLength += static_cast<ArrayIndex>(childValues_[index].length());4952}4953addChildValues_ = false;4954isMultiLine = isMultiLine || lineLength >= rightMargin_;4955}4956return isMultiLine;4957}49584959void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) {4960if (addChildValues_)4961childValues_.push_back(value);4962else4963*document_ << value;4964}49654966void StyledStreamWriter::writeIndent() {4967// blep intended this to look at the so-far-written string4968// to determine whether we are already indented, but4969// with a stream we cannot do that. So we rely on some saved state.4970// The caller checks indented_.4971*document_ << '\n' << indentString_;4972}49734974void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) {4975if (!indented_) writeIndent();4976*document_ << value;4977indented_ = false;4978}49794980void StyledStreamWriter::indent() { indentString_ += indentation_; }49814982void StyledStreamWriter::unindent() {4983assert(indentString_.size() >= indentation_.size());4984indentString_.resize(indentString_.size() - indentation_.size());4985}49864987void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {4988if (!root.hasComment(commentBefore))4989return;49904991if (!indented_) writeIndent();4992const JSONCPP_STRING& comment = root.getComment(commentBefore);4993JSONCPP_STRING::const_iterator iter = comment.begin();4994while (iter != comment.end()) {4995*document_ << *iter;4996if (*iter == '\n' &&4997((iter+1) != comment.end() && *(iter + 1) == '/'))4998// writeIndent(); // would include newline4999*document_ << indentString_;5000++iter;5001}5002indented_ = false;5003}50045005void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {5006if (root.hasComment(commentAfterOnSameLine))5007*document_ << ' ' << root.getComment(commentAfterOnSameLine);50085009if (root.hasComment(commentAfter)) {5010writeIndent();5011*document_ << root.getComment(commentAfter);5012}5013indented_ = false;5014}50155016bool StyledStreamWriter::hasCommentForValue(const Value& value) {5017return value.hasComment(commentBefore) ||5018value.hasComment(commentAfterOnSameLine) ||5019value.hasComment(commentAfter);5020}50215022//////////////////////////5023// BuiltStyledStreamWriter50245025/// Scoped enums are not available until C++11.5026struct CommentStyle {5027/// Decide whether to write comments.5028enum Enum {5029None, ///< Drop all comments.5030Most, ///< Recover odd behavior of previous versions (not implemented yet).5031All ///< Keep all comments.5032};5033};50345035struct BuiltStyledStreamWriter : public StreamWriter5036{5037BuiltStyledStreamWriter(5038JSONCPP_STRING const& indentation,5039CommentStyle::Enum cs,5040JSONCPP_STRING const& colonSymbol,5041JSONCPP_STRING const& nullSymbol,5042JSONCPP_STRING const& endingLineFeedSymbol,5043bool useSpecialFloats,5044unsigned int precision,5045PrecisionType precisionType);5046int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE;5047private:5048void writeValue(Value const& value);5049void writeArrayValue(Value const& value);5050bool isMultilineArray(Value const& value);5051void pushValue(JSONCPP_STRING const& value);5052void writeIndent();5053void writeWithIndent(JSONCPP_STRING const& value);5054void indent();5055void unindent();5056void writeCommentBeforeValue(Value const& root);5057void writeCommentAfterValueOnSameLine(Value const& root);5058static bool hasCommentForValue(const Value& value);50595060typedef std::vector<JSONCPP_STRING> ChildValues;50615062ChildValues childValues_;5063JSONCPP_STRING indentString_;5064unsigned int rightMargin_;5065JSONCPP_STRING indentation_;5066CommentStyle::Enum cs_;5067JSONCPP_STRING colonSymbol_;5068JSONCPP_STRING nullSymbol_;5069JSONCPP_STRING endingLineFeedSymbol_;5070bool addChildValues_ : 1;5071bool indented_ : 1;5072bool useSpecialFloats_ : 1;5073unsigned int precision_;5074PrecisionType precisionType_;5075};5076BuiltStyledStreamWriter::BuiltStyledStreamWriter(5077JSONCPP_STRING const& indentation,5078CommentStyle::Enum cs,5079JSONCPP_STRING const& colonSymbol,5080JSONCPP_STRING const& nullSymbol,5081JSONCPP_STRING const& endingLineFeedSymbol,5082bool useSpecialFloats,5083unsigned int precision,5084PrecisionType precisionType)5085: rightMargin_(74)5086, indentation_(indentation)5087, cs_(cs)5088, colonSymbol_(colonSymbol)5089, nullSymbol_(nullSymbol)5090, endingLineFeedSymbol_(endingLineFeedSymbol)5091, addChildValues_(false)5092, indented_(false)5093, useSpecialFloats_(useSpecialFloats)5094, precision_(precision)5095, precisionType_(precisionType)5096{5097}5098int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout)5099{5100sout_ = sout;5101addChildValues_ = false;5102indented_ = true;5103indentString_.clear();5104writeCommentBeforeValue(root);5105if (!indented_) writeIndent();5106indented_ = true;5107writeValue(root);5108writeCommentAfterValueOnSameLine(root);5109*sout_ << endingLineFeedSymbol_;5110sout_ = NULL;5111return 0;5112}5113void BuiltStyledStreamWriter::writeValue(Value const& value) {5114switch (value.type()) {5115case nullValue:5116pushValue(nullSymbol_);5117break;5118case intValue:5119pushValue(valueToString(value.asLargestInt()));5120break;5121case uintValue:5122pushValue(valueToString(value.asLargestUInt()));5123break;5124case realValue:5125pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_, precisionType_));5126break;5127case stringValue:5128{5129// Is NULL is possible for value.string_? No.5130char const* str;5131char const* end;5132bool ok = value.getString(&str, &end);5133if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));5134else pushValue("");5135break;5136}5137case booleanValue:5138pushValue(valueToString(value.asBool()));5139break;5140case arrayValue:5141writeArrayValue(value);5142break;5143case objectValue: {5144Value::Members members(value.getMemberNames());5145if (members.empty())5146pushValue("{}");5147else {5148writeWithIndent("{");5149indent();5150Value::Members::iterator it = members.begin();5151for (;;) {5152JSONCPP_STRING const& name = *it;5153Value const& childValue = value[name];5154writeCommentBeforeValue(childValue);5155writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())));5156*sout_ << colonSymbol_;5157writeValue(childValue);5158if (++it == members.end()) {5159writeCommentAfterValueOnSameLine(childValue);5160break;5161}5162*sout_ << ",";5163writeCommentAfterValueOnSameLine(childValue);5164}5165unindent();5166writeWithIndent("}");5167}5168} break;5169}5170}51715172void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {5173unsigned size = value.size();5174if (size == 0)5175pushValue("[]");5176else {5177bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value);5178if (isMultiLine) {5179writeWithIndent("[");5180indent();5181bool hasChildValue = !childValues_.empty();5182unsigned index = 0;5183for (;;) {5184Value const& childValue = value[index];5185writeCommentBeforeValue(childValue);5186if (hasChildValue)5187writeWithIndent(childValues_[index]);5188else {5189if (!indented_) writeIndent();5190indented_ = true;5191writeValue(childValue);5192indented_ = false;5193}5194if (++index == size) {5195writeCommentAfterValueOnSameLine(childValue);5196break;5197}5198*sout_ << ",";5199writeCommentAfterValueOnSameLine(childValue);5200}5201unindent();5202writeWithIndent("]");5203} else // output on a single line5204{5205assert(childValues_.size() == size);5206*sout_ << "[";5207if (!indentation_.empty()) *sout_ << " ";5208for (unsigned index = 0; index < size; ++index) {5209if (index > 0)5210*sout_ << ((!indentation_.empty()) ? ", " : ",");5211*sout_ << childValues_[index];5212}5213if (!indentation_.empty()) *sout_ << " ";5214*sout_ << "]";5215}5216}5217}52185219bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) {5220ArrayIndex const size = value.size();5221bool isMultiLine = size * 3 >= rightMargin_;5222childValues_.clear();5223for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {5224Value const& childValue = value[index];5225isMultiLine = ((childValue.isArray() || childValue.isObject()) &&5226childValue.size() > 0);5227}5228if (!isMultiLine) // check if line length > max line length5229{5230childValues_.reserve(size);5231addChildValues_ = true;5232ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'5233for (ArrayIndex index = 0; index < size; ++index) {5234if (hasCommentForValue(value[index])) {5235isMultiLine = true;5236}5237writeValue(value[index]);5238lineLength += static_cast<ArrayIndex>(childValues_[index].length());5239}5240addChildValues_ = false;5241isMultiLine = isMultiLine || lineLength >= rightMargin_;5242}5243return isMultiLine;5244}52455246void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) {5247if (addChildValues_)5248childValues_.push_back(value);5249else5250*sout_ << value;5251}52525253void BuiltStyledStreamWriter::writeIndent() {5254// blep intended this to look at the so-far-written string5255// to determine whether we are already indented, but5256// with a stream we cannot do that. So we rely on some saved state.5257// The caller checks indented_.52585259if (!indentation_.empty()) {5260// In this case, drop newlines too.5261*sout_ << '\n' << indentString_;5262}5263}52645265void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) {5266if (!indented_) writeIndent();5267*sout_ << value;5268indented_ = false;5269}52705271void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }52725273void BuiltStyledStreamWriter::unindent() {5274assert(indentString_.size() >= indentation_.size());5275indentString_.resize(indentString_.size() - indentation_.size());5276}52775278void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {5279if (cs_ == CommentStyle::None) return;5280if (!root.hasComment(commentBefore))5281return;52825283if (!indented_) writeIndent();5284const JSONCPP_STRING& comment = root.getComment(commentBefore);5285JSONCPP_STRING::const_iterator iter = comment.begin();5286while (iter != comment.end()) {5287*sout_ << *iter;5288if (*iter == '\n' &&5289((iter+1) != comment.end() && *(iter + 1) == '/'))5290// writeIndent(); // would write extra newline5291*sout_ << indentString_;5292++iter;5293}5294indented_ = false;5295}52965297void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {5298if (cs_ == CommentStyle::None) return;5299if (root.hasComment(commentAfterOnSameLine))5300*sout_ << " " + root.getComment(commentAfterOnSameLine);53015302if (root.hasComment(commentAfter)) {5303writeIndent();5304*sout_ << root.getComment(commentAfter);5305}5306}53075308// static5309bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {5310return value.hasComment(commentBefore) ||5311value.hasComment(commentAfterOnSameLine) ||5312value.hasComment(commentAfter);5313}53145315///////////////5316// StreamWriter53175318StreamWriter::StreamWriter()5319: sout_(NULL)5320{5321}5322StreamWriter::~StreamWriter()5323{5324}5325StreamWriter::Factory::~Factory()5326{}5327StreamWriterBuilder::StreamWriterBuilder()5328{5329setDefaults(&settings_);5330}5331StreamWriterBuilder::~StreamWriterBuilder()5332{}5333StreamWriter* StreamWriterBuilder::newStreamWriter() const5334{5335JSONCPP_STRING indentation = settings_["indentation"].asString();5336JSONCPP_STRING cs_str = settings_["commentStyle"].asString();5337JSONCPP_STRING pt_str = settings_["precisionType"].asString();5338bool eyc = settings_["enableYAMLCompatibility"].asBool();5339bool dnp = settings_["dropNullPlaceholders"].asBool();5340bool usf = settings_["useSpecialFloats"].asBool();5341unsigned int pre = settings_["precision"].asUInt();5342CommentStyle::Enum cs = CommentStyle::All;5343if (cs_str == "All") {5344cs = CommentStyle::All;5345} else if (cs_str == "None") {5346cs = CommentStyle::None;5347} else {5348throwRuntimeError("commentStyle must be 'All' or 'None'");5349}5350PrecisionType precisionType(significantDigits);5351if (pt_str == "significant") {5352precisionType = PrecisionType::significantDigits;5353} else if (pt_str == "decimal") {5354precisionType = PrecisionType::decimalPlaces;5355} else {5356throwRuntimeError("precisionType must be 'significant' or 'decimal'");5357}5358JSONCPP_STRING colonSymbol = " : ";5359if (eyc) {5360colonSymbol = ": ";5361} else if (indentation.empty()) {5362colonSymbol = ":";5363}5364JSONCPP_STRING nullSymbol = "null";5365if (dnp) {5366nullSymbol.clear();5367}5368if (pre > 17) pre = 17;5369JSONCPP_STRING endingLineFeedSymbol;5370return new BuiltStyledStreamWriter(5371indentation, cs,5372colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre, precisionType);5373}5374static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys)5375{5376valid_keys->clear();5377valid_keys->insert("indentation");5378valid_keys->insert("commentStyle");5379valid_keys->insert("enableYAMLCompatibility");5380valid_keys->insert("dropNullPlaceholders");5381valid_keys->insert("useSpecialFloats");5382valid_keys->insert("precision");5383valid_keys->insert("precisionType");5384}5385bool StreamWriterBuilder::validate(Json::Value* invalid) const5386{5387Json::Value my_invalid;5388if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL5389Json::Value& inv = *invalid;5390std::set<JSONCPP_STRING> valid_keys;5391getValidWriterKeys(&valid_keys);5392Value::Members keys = settings_.getMemberNames();5393size_t n = keys.size();5394for (size_t i = 0; i < n; ++i) {5395JSONCPP_STRING const& key = keys[i];5396if (valid_keys.find(key) == valid_keys.end()) {5397inv[key] = settings_[key];5398}5399}5400return 0u == inv.size();5401}5402Value& StreamWriterBuilder::operator[](JSONCPP_STRING key)5403{5404return settings_[key];5405}5406// static5407void StreamWriterBuilder::setDefaults(Json::Value* settings)5408{5409//! [StreamWriterBuilderDefaults]5410(*settings)["commentStyle"] = "All";5411(*settings)["indentation"] = "\t";5412(*settings)["enableYAMLCompatibility"] = false;5413(*settings)["dropNullPlaceholders"] = false;5414(*settings)["useSpecialFloats"] = false;5415(*settings)["precision"] = 17;5416(*settings)["precisionType"] = "significant";5417//! [StreamWriterBuilderDefaults]5418}54195420JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) {5421JSONCPP_OSTRINGSTREAM sout;5422StreamWriterPtr const writer(builder.newStreamWriter());5423writer->write(root, &sout);5424return sout.str();5425}54265427JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) {5428StreamWriterBuilder builder;5429StreamWriterPtr const writer(builder.newStreamWriter());5430writer->write(root, &sout);5431return sout;5432}54335434} // namespace Json54355436// //////////////////////////////////////////////////////////////////////5437// End of content of file: src/lib_json/json_writer.cpp5438// //////////////////////////////////////////////////////////////////////54395440544154425443544454455446