Path: blob/master/cpp/linux/json/jsoncpp.cpp
644 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_INCLUDED9394#if !defined(JSON_IS_AMALGAMATION)95#include <json/config.h>96#endif9798// Also support old flag NO_LOCALE_SUPPORT99#ifdef NO_LOCALE_SUPPORT100#define JSONCPP_NO_LOCALE_SUPPORT101#endif102103#ifndef JSONCPP_NO_LOCALE_SUPPORT104#include <clocale>105#endif106107/* This header provides common string manipulation support, such as UTF-8,108* portable conversion from/to string...109*110* It is an internal header that must not be exposed.111*/112113namespace Json {114static inline char getDecimalPoint() {115#ifdef JSONCPP_NO_LOCALE_SUPPORT116return '\0';117#else118struct lconv* lc = localeconv();119return lc ? *(lc->decimal_point) : '\0';120#endif121}122123/// Converts a unicode code-point to UTF-8.124static inline String codePointToUTF8(unsigned int cp) {125String result;126127// based on description from http://en.wikipedia.org/wiki/UTF-8128129if (cp <= 0x7f) {130result.resize(1);131result[0] = static_cast<char>(cp);132} else if (cp <= 0x7FF) {133result.resize(2);134result[1] = static_cast<char>(0x80 | (0x3f & cp));135result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));136} else if (cp <= 0xFFFF) {137result.resize(3);138result[2] = static_cast<char>(0x80 | (0x3f & cp));139result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));140result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));141} else if (cp <= 0x10FFFF) {142result.resize(4);143result[3] = static_cast<char>(0x80 | (0x3f & cp));144result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));145result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));146result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));147}148149return result;150}151152enum {153/// Constant that specify the size of the buffer that must be passed to154/// uintToString.155uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1156};157158// Defines a char buffer for use with uintToString().159typedef char UIntToStringBuffer[uintToStringBufferSize];160161/** Converts an unsigned integer to string.162* @param value Unsigned integer to convert to string163* @param current Input/Output string buffer.164* Must have at least uintToStringBufferSize chars free.165*/166static inline void uintToString(LargestUInt value, char*& current) {167*--current = 0;168do {169*--current = static_cast<char>(value % 10U + static_cast<unsigned>('0'));170value /= 10;171} while (value != 0);172}173174/** Change ',' to '.' everywhere in buffer.175*176* We had a sophisticated way, but it did not work in WinCE.177* @see https://github.com/open-source-parsers/jsoncpp/pull/9178*/179template <typename Iter> Iter fixNumericLocale(Iter begin, Iter end) {180for (; begin != end; ++begin) {181if (*begin == ',') {182*begin = '.';183}184}185return begin;186}187188template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) {189char decimalPoint = getDecimalPoint();190if (decimalPoint == '\0' || decimalPoint == '.') {191return;192}193for (; begin != end; ++begin) {194if (*begin == '.') {195*begin = decimalPoint;196}197}198}199200/**201* Return iterator that would be the new end of the range [begin,end), if we202* were to delete zeros in the end of string, but not the last zero before '.'.203*/204template <typename Iter> Iter fixZerosInTheEnd(Iter begin, Iter end) {205for (; begin != end; --end) {206if (*(end - 1) != '0') {207return end;208}209// Don't delete the last zero before the decimal point.210if (begin != (end - 1) && *(end - 2) == '.') {211return end;212}213}214return end;215}216217} // namespace Json218219#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED220221// //////////////////////////////////////////////////////////////////////222// End of content of file: src/lib_json/json_tool.h223// //////////////////////////////////////////////////////////////////////224225226227228229230// //////////////////////////////////////////////////////////////////////231// Beginning of content of file: src/lib_json/json_reader.cpp232// //////////////////////////////////////////////////////////////////////233234// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors235// Copyright (C) 2016 InfoTeCS JSC. All rights reserved.236// Distributed under MIT license, or public domain if desired and237// recognized in your jurisdiction.238// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE239240#if !defined(JSON_IS_AMALGAMATION)241#include "json_tool.h"242#include <json/assertions.h>243#include <json/reader.h>244#include <json/value.h>245#endif // if !defined(JSON_IS_AMALGAMATION)246#include <cassert>247#include <cstring>248#include <istream>249#include <limits>250#include <memory>251#include <set>252#include <sstream>253#include <utility>254255#include <cstdio>256#if __cplusplus >= 201103L257258#if !defined(sscanf)259#define sscanf std::sscanf260#endif261262#endif //__cplusplus263264#if defined(_MSC_VER)265#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)266#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1267#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES268#endif //_MSC_VER269270#if defined(_MSC_VER)271// Disable warning about strdup being deprecated.272#pragma warning(disable : 4996)273#endif274275// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile276// time to change the stack limit277#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)278#define JSONCPP_DEPRECATED_STACK_LIMIT 1000279#endif280281static size_t const stackLimit_g =282JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()283284namespace Json {285286#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)287typedef std::unique_ptr<CharReader> CharReaderPtr;288#else289typedef std::auto_ptr<CharReader> CharReaderPtr;290#endif291292// Implementation of class Features293// ////////////////////////////////294295Features::Features() = default;296297Features Features::all() { return {}; }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_(), commentsBefore_(), features_(Features::all()) {}323324Reader::Reader(const Features& features)325: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),326lastValue_(), commentsBefore_(), features_(features), collectComments_() {327}328329bool Reader::parse(const std::string& document,330Value& root,331bool collectComments) {332document_.assign(document.begin(), document.end());333const char* begin = document_.c_str();334const char* end = begin + document_.length();335return parse(begin, end, root, collectComments);336}337338bool Reader::parse(std::istream& is, Value& root, bool collectComments) {339// std::istream_iterator<char> begin(is);340// std::istream_iterator<char> end;341// Those would allow streamed input from a file, if parse() were a342// template function.343344// Since String is reference-counted, this at least does not345// create an extra copy.346String doc;347std::getline(is, doc, (char)EOF);348return parse(doc.data(), doc.data() + doc.size(), root, collectComments);349}350351bool Reader::parse(const char* beginDoc,352const char* endDoc,353Value& root,354bool collectComments) {355if (!features_.allowComments_) {356collectComments = false;357}358359begin_ = beginDoc;360end_ = endDoc;361collectComments_ = collectComments;362current_ = begin_;363lastValueEnd_ = nullptr;364lastValue_ = nullptr;365commentsBefore_.clear();366errors_.clear();367while (!nodes_.empty())368nodes_.pop();369nodes_.push(&root);370371bool successful = readValue();372Token token;373skipCommentTokens(token);374if (collectComments_ && !commentsBefore_.empty())375root.setComment(commentsBefore_, commentAfter);376if (features_.strictRoot_) {377if (!root.isArray() && !root.isObject()) {378// Set error location to start of doc, ideally should be first token found379// in doc380token.type_ = tokenError;381token.start_ = beginDoc;382token.end_ = endDoc;383addError(384"A valid JSON document must be either an array or an object value.",385token);386return false;387}388}389return successful;390}391392bool Reader::readValue() {393// readValue() may call itself only if it calls readObject() or ReadArray().394// These methods execute nodes_.push() just before and nodes_.pop)() just395// after calling readValue(). parse() executes one nodes_.push(), so > instead396// of >=.397if (nodes_.size() > stackLimit_g)398throwRuntimeError("Exceeded stackLimit in readValue().");399400Token token;401skipCommentTokens(token);402bool successful = true;403404if (collectComments_ && !commentsBefore_.empty()) {405currentValue().setComment(commentsBefore_, commentBefore);406commentsBefore_.clear();407}408409switch (token.type_) {410case tokenObjectBegin:411successful = readObject(token);412currentValue().setOffsetLimit(current_ - begin_);413break;414case tokenArrayBegin:415successful = readArray(token);416currentValue().setOffsetLimit(current_ - begin_);417break;418case tokenNumber:419successful = decodeNumber(token);420break;421case tokenString:422successful = decodeString(token);423break;424case tokenTrue: {425Value v(true);426currentValue().swapPayload(v);427currentValue().setOffsetStart(token.start_ - begin_);428currentValue().setOffsetLimit(token.end_ - begin_);429} break;430case tokenFalse: {431Value v(false);432currentValue().swapPayload(v);433currentValue().setOffsetStart(token.start_ - begin_);434currentValue().setOffsetLimit(token.end_ - begin_);435} break;436case tokenNull: {437Value v;438currentValue().swapPayload(v);439currentValue().setOffsetStart(token.start_ - begin_);440currentValue().setOffsetLimit(token.end_ - begin_);441} break;442case tokenArraySeparator:443case tokenObjectEnd:444case tokenArrayEnd:445if (features_.allowDroppedNullPlaceholders_) {446// "Un-read" the current token and mark the current value as a null447// token.448current_--;449Value v;450currentValue().swapPayload(v);451currentValue().setOffsetStart(current_ - begin_ - 1);452currentValue().setOffsetLimit(current_ - begin_);453break;454} // Else, fall through...455default:456currentValue().setOffsetStart(token.start_ - begin_);457currentValue().setOffsetLimit(token.end_ - begin_);458return addError("Syntax error: value, object or array expected.", token);459}460461if (collectComments_) {462lastValueEnd_ = current_;463lastValue_ = ¤tValue();464}465466return successful;467}468469void Reader::skipCommentTokens(Token& token) {470if (features_.allowComments_) {471do {472readToken(token);473} while (token.type_ == tokenComment);474} else {475readToken(token);476}477}478479bool Reader::readToken(Token& token) {480skipSpaces();481token.start_ = current_;482Char c = getNextChar();483bool ok = true;484switch (c) {485case '{':486token.type_ = tokenObjectBegin;487break;488case '}':489token.type_ = tokenObjectEnd;490break;491case '[':492token.type_ = tokenArrayBegin;493break;494case ']':495token.type_ = tokenArrayEnd;496break;497case '"':498token.type_ = tokenString;499ok = readString();500break;501case '/':502token.type_ = tokenComment;503ok = readComment();504break;505case '0':506case '1':507case '2':508case '3':509case '4':510case '5':511case '6':512case '7':513case '8':514case '9':515case '-':516token.type_ = tokenNumber;517readNumber();518break;519case 't':520token.type_ = tokenTrue;521ok = match("rue", 3);522break;523case 'f':524token.type_ = tokenFalse;525ok = match("alse", 4);526break;527case 'n':528token.type_ = tokenNull;529ok = match("ull", 3);530break;531case ',':532token.type_ = tokenArraySeparator;533break;534case ':':535token.type_ = tokenMemberSeparator;536break;537case 0:538token.type_ = tokenEndOfStream;539break;540default:541ok = false;542break;543}544if (!ok)545token.type_ = tokenError;546token.end_ = current_;547return true;548}549550void Reader::skipSpaces() {551while (current_ != end_) {552Char c = *current_;553if (c == ' ' || c == '\t' || c == '\r' || c == '\n')554++current_;555else556break;557}558}559560bool Reader::match(Location pattern, int patternLength) {561if (end_ - current_ < patternLength)562return false;563int index = patternLength;564while (index--)565if (current_[index] != pattern[index])566return false;567current_ += patternLength;568return true;569}570571bool Reader::readComment() {572Location commentBegin = current_ - 1;573Char c = getNextChar();574bool successful = false;575if (c == '*')576successful = readCStyleComment();577else if (c == '/')578successful = readCppStyleComment();579if (!successful)580return false;581582if (collectComments_) {583CommentPlacement placement = commentBefore;584if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {585if (c != '*' || !containsNewLine(commentBegin, current_))586placement = commentAfterOnSameLine;587}588589addComment(commentBegin, current_, placement);590}591return true;592}593594String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {595String normalized;596normalized.reserve(static_cast<size_t>(end - begin));597Reader::Location current = begin;598while (current != end) {599char c = *current++;600if (c == '\r') {601if (current != end && *current == '\n')602// convert dos EOL603++current;604// convert Mac EOL605normalized += '\n';606} else {607normalized += c;608}609}610return normalized;611}612613void Reader::addComment(Location begin,614Location end,615CommentPlacement placement) {616assert(collectComments_);617const String& normalized = normalizeEOL(begin, end);618if (placement == commentAfterOnSameLine) {619assert(lastValue_ != nullptr);620lastValue_->setComment(normalized, placement);621} else {622commentsBefore_ += normalized;623}624}625626bool Reader::readCStyleComment() {627while ((current_ + 1) < end_) {628Char c = getNextChar();629if (c == '*' && *current_ == '/')630break;631}632return getNextChar() == '/';633}634635bool Reader::readCppStyleComment() {636while (current_ != end_) {637Char c = getNextChar();638if (c == '\n')639break;640if (c == '\r') {641// Consume DOS EOL. It will be normalized in addComment.642if (current_ != end_ && *current_ == '\n')643getNextChar();644// Break on Moc OS 9 EOL.645break;646}647}648return true;649}650651void Reader::readNumber() {652const char* p = current_;653char c = '0'; // stopgap for already consumed character654// integral part655while (c >= '0' && c <= '9')656c = (current_ = p) < end_ ? *p++ : '\0';657// fractional part658if (c == '.') {659c = (current_ = p) < end_ ? *p++ : '\0';660while (c >= '0' && c <= '9')661c = (current_ = p) < end_ ? *p++ : '\0';662}663// exponential part664if (c == 'e' || c == 'E') {665c = (current_ = p) < end_ ? *p++ : '\0';666if (c == '+' || c == '-')667c = (current_ = p) < end_ ? *p++ : '\0';668while (c >= '0' && c <= '9')669c = (current_ = p) < end_ ? *p++ : '\0';670}671}672673bool Reader::readString() {674Char c = '\0';675while (current_ != end_) {676c = getNextChar();677if (c == '\\')678getNextChar();679else if (c == '"')680break;681}682return c == '"';683}684685bool Reader::readObject(Token& token) {686Token tokenName;687String name;688Value init(objectValue);689currentValue().swapPayload(init);690currentValue().setOffsetStart(token.start_ - begin_);691while (readToken(tokenName)) {692bool initialTokenOk = true;693while (tokenName.type_ == tokenComment && initialTokenOk)694initialTokenOk = readToken(tokenName);695if (!initialTokenOk)696break;697if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object698return true;699name.clear();700if (tokenName.type_ == tokenString) {701if (!decodeString(tokenName, name))702return recoverFromError(tokenObjectEnd);703} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {704Value numberName;705if (!decodeNumber(tokenName, numberName))706return recoverFromError(tokenObjectEnd);707name = String(numberName.asCString());708} else {709break;710}711712Token colon;713if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {714return addErrorAndRecover("Missing ':' after object member name", colon,715tokenObjectEnd);716}717Value& value = currentValue()[name];718nodes_.push(&value);719bool ok = readValue();720nodes_.pop();721if (!ok) // error already set722return recoverFromError(tokenObjectEnd);723724Token comma;725if (!readToken(comma) ||726(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&727comma.type_ != tokenComment)) {728return addErrorAndRecover("Missing ',' or '}' in object declaration",729comma, tokenObjectEnd);730}731bool finalizeTokenOk = true;732while (comma.type_ == tokenComment && finalizeTokenOk)733finalizeTokenOk = readToken(comma);734if (comma.type_ == tokenObjectEnd)735return true;736}737return addErrorAndRecover("Missing '}' or object member name", tokenName,738tokenObjectEnd);739}740741bool Reader::readArray(Token& token) {742Value init(arrayValue);743currentValue().swapPayload(init);744currentValue().setOffsetStart(token.start_ - begin_);745skipSpaces();746if (current_ != end_ && *current_ == ']') // empty array747{748Token endArray;749readToken(endArray);750return true;751}752int index = 0;753for (;;) {754Value& value = currentValue()[index++];755nodes_.push(&value);756bool ok = readValue();757nodes_.pop();758if (!ok) // error already set759return recoverFromError(tokenArrayEnd);760761Token currentToken;762// Accept Comment after last item in the array.763ok = readToken(currentToken);764while (currentToken.type_ == tokenComment && ok) {765ok = readToken(currentToken);766}767bool badTokenType = (currentToken.type_ != tokenArraySeparator &&768currentToken.type_ != tokenArrayEnd);769if (!ok || badTokenType) {770return addErrorAndRecover("Missing ',' or ']' in array declaration",771currentToken, tokenArrayEnd);772}773if (currentToken.type_ == tokenArrayEnd)774break;775}776return true;777}778779bool Reader::decodeNumber(Token& token) {780Value decoded;781if (!decodeNumber(token, decoded))782return false;783currentValue().swapPayload(decoded);784currentValue().setOffsetStart(token.start_ - begin_);785currentValue().setOffsetLimit(token.end_ - begin_);786return true;787}788789bool Reader::decodeNumber(Token& token, Value& decoded) {790// Attempts to parse the number as an integer. If the number is791// larger than the maximum supported value of an integer then792// we decode the number as a double.793Location current = token.start_;794bool isNegative = *current == '-';795if (isNegative)796++current;797// TODO: Help the compiler do the div and mod at compile time or get rid of798// them.799Value::LargestUInt maxIntegerValue =800isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1801: Value::maxLargestUInt;802Value::LargestUInt threshold = maxIntegerValue / 10;803Value::LargestUInt value = 0;804while (current < token.end_) {805Char c = *current++;806if (c < '0' || c > '9')807return decodeDouble(token, decoded);808auto digit(static_cast<Value::UInt>(c - '0'));809if (value >= threshold) {810// We've hit or exceeded the max value divided by 10 (rounded down). If811// a) we've only just touched the limit, b) this is the last digit, and812// c) it's small enough to fit in that rounding delta, we're okay.813// Otherwise treat this number as a double to avoid overflow.814if (value > threshold || current != token.end_ ||815digit > maxIntegerValue % 10) {816return decodeDouble(token, decoded);817}818}819value = value * 10 + digit;820}821if (isNegative && value == maxIntegerValue)822decoded = Value::minLargestInt;823else if (isNegative)824decoded = -Value::LargestInt(value);825else if (value <= Value::LargestUInt(Value::maxInt))826decoded = Value::LargestInt(value);827else828decoded = value;829return true;830}831832bool Reader::decodeDouble(Token& token) {833Value decoded;834if (!decodeDouble(token, decoded))835return false;836currentValue().swapPayload(decoded);837currentValue().setOffsetStart(token.start_ - begin_);838currentValue().setOffsetLimit(token.end_ - begin_);839return true;840}841842bool Reader::decodeDouble(Token& token, Value& decoded) {843double value = 0;844String buffer(token.start_, token.end_);845IStringStream is(buffer);846if (!(is >> value))847return addError(848"'" + String(token.start_, token.end_) + "' is not a number.", token);849decoded = value;850return true;851}852853bool Reader::decodeString(Token& token) {854String decoded_string;855if (!decodeString(token, decoded_string))856return false;857Value decoded(decoded_string);858currentValue().swapPayload(decoded);859currentValue().setOffsetStart(token.start_ - begin_);860currentValue().setOffsetLimit(token.end_ - begin_);861return true;862}863864bool Reader::decodeString(Token& token, String& decoded) {865decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));866Location current = token.start_ + 1; // skip '"'867Location end = token.end_ - 1; // do not include '"'868while (current != end) {869Char c = *current++;870if (c == '"')871break;872else if (c == '\\') {873if (current == end)874return addError("Empty escape sequence in string", token, current);875Char escape = *current++;876switch (escape) {877case '"':878decoded += '"';879break;880case '/':881decoded += '/';882break;883case '\\':884decoded += '\\';885break;886case 'b':887decoded += '\b';888break;889case 'f':890decoded += '\f';891break;892case 'n':893decoded += '\n';894break;895case 'r':896decoded += '\r';897break;898case 't':899decoded += '\t';900break;901case 'u': {902unsigned int unicode;903if (!decodeUnicodeCodePoint(token, current, end, unicode))904return false;905decoded += codePointToUTF8(unicode);906} break;907default:908return addError("Bad escape sequence in string", token, current);909}910} else {911decoded += c;912}913}914return true;915}916917bool Reader::decodeUnicodeCodePoint(Token& token,918Location& current,919Location end,920unsigned int& unicode) {921922if (!decodeUnicodeEscapeSequence(token, current, end, unicode))923return false;924if (unicode >= 0xD800 && unicode <= 0xDBFF) {925// surrogate pairs926if (end - current < 6)927return addError(928"additional six characters expected to parse unicode surrogate pair.",929token, current);930if (*(current++) == '\\' && *(current++) == 'u') {931unsigned int surrogatePair;932if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {933unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);934} else935return false;936} else937return addError("expecting another \\u token to begin the second half of "938"a unicode surrogate pair",939token, current);940}941return true;942}943944bool Reader::decodeUnicodeEscapeSequence(Token& token,945Location& current,946Location end,947unsigned int& ret_unicode) {948if (end - current < 4)949return addError(950"Bad unicode escape sequence in string: four digits expected.", token,951current);952int unicode = 0;953for (int index = 0; index < 4; ++index) {954Char c = *current++;955unicode *= 16;956if (c >= '0' && c <= '9')957unicode += c - '0';958else if (c >= 'a' && c <= 'f')959unicode += c - 'a' + 10;960else if (c >= 'A' && c <= 'F')961unicode += c - 'A' + 10;962else963return addError(964"Bad unicode escape sequence in string: hexadecimal digit expected.",965token, current);966}967ret_unicode = static_cast<unsigned int>(unicode);968return true;969}970971bool Reader::addError(const String& message, Token& token, Location extra) {972ErrorInfo info;973info.token_ = token;974info.message_ = message;975info.extra_ = extra;976errors_.push_back(info);977return false;978}979980bool Reader::recoverFromError(TokenType skipUntilToken) {981size_t const errorCount = errors_.size();982Token skip;983for (;;) {984if (!readToken(skip))985errors_.resize(errorCount); // discard errors caused by recovery986if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)987break;988}989errors_.resize(errorCount);990return false;991}992993bool Reader::addErrorAndRecover(const String& message,994Token& token,995TokenType skipUntilToken) {996addError(message, token);997return recoverFromError(skipUntilToken);998}9991000Value& Reader::currentValue() { return *(nodes_.top()); }10011002Reader::Char Reader::getNextChar() {1003if (current_ == end_)1004return 0;1005return *current_++;1006}10071008void Reader::getLocationLineAndColumn(Location location,1009int& line,1010int& column) const {1011Location current = begin_;1012Location lastLineStart = current;1013line = 0;1014while (current < location && current != end_) {1015Char c = *current++;1016if (c == '\r') {1017if (*current == '\n')1018++current;1019lastLineStart = current;1020++line;1021} else if (c == '\n') {1022lastLineStart = current;1023++line;1024}1025}1026// column & line start at 11027column = int(location - lastLineStart) + 1;1028++line;1029}10301031String Reader::getLocationLineAndColumn(Location location) const {1032int line, column;1033getLocationLineAndColumn(location, line, column);1034char buffer[18 + 16 + 16 + 1];1035jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);1036return buffer;1037}10381039// Deprecated. Preserved for backward compatibility1040String Reader::getFormatedErrorMessages() const {1041return getFormattedErrorMessages();1042}10431044String Reader::getFormattedErrorMessages() const {1045String formattedMessage;1046for (const auto& error : errors_) {1047formattedMessage +=1048"* " + getLocationLineAndColumn(error.token_.start_) + "\n";1049formattedMessage += " " + error.message_ + "\n";1050if (error.extra_)1051formattedMessage +=1052"See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";1053}1054return formattedMessage;1055}10561057std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {1058std::vector<Reader::StructuredError> allErrors;1059for (const auto& error : errors_) {1060Reader::StructuredError structured;1061structured.offset_start = error.token_.start_ - begin_;1062structured.offset_limit = error.token_.end_ - begin_;1063structured.message = error.message_;1064allErrors.push_back(structured);1065}1066return allErrors;1067}10681069bool Reader::pushError(const Value& value, const String& message) {1070ptrdiff_t const length = end_ - begin_;1071if (value.getOffsetStart() > length || value.getOffsetLimit() > length)1072return false;1073Token token;1074token.type_ = tokenError;1075token.start_ = begin_ + value.getOffsetStart();1076token.end_ = begin_ + value.getOffsetLimit();1077ErrorInfo info;1078info.token_ = token;1079info.message_ = message;1080info.extra_ = nullptr;1081errors_.push_back(info);1082return true;1083}10841085bool Reader::pushError(const Value& value,1086const String& message,1087const Value& extra) {1088ptrdiff_t const length = end_ - begin_;1089if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||1090extra.getOffsetLimit() > length)1091return false;1092Token token;1093token.type_ = tokenError;1094token.start_ = begin_ + value.getOffsetStart();1095token.end_ = begin_ + value.getOffsetLimit();1096ErrorInfo info;1097info.token_ = token;1098info.message_ = message;1099info.extra_ = begin_ + extra.getOffsetStart();1100errors_.push_back(info);1101return true;1102}11031104bool Reader::good() const { return errors_.empty(); }11051106// Originally copied from the Features class (now deprecated), used internally1107// for features implementation.1108class OurFeatures {1109public:1110static OurFeatures all();1111bool allowComments_;1112bool strictRoot_;1113bool allowDroppedNullPlaceholders_;1114bool allowNumericKeys_;1115bool allowSingleQuotes_;1116bool failIfExtra_;1117bool rejectDupKeys_;1118bool allowSpecialFloats_;1119size_t stackLimit_;1120}; // OurFeatures11211122OurFeatures OurFeatures::all() { return {}; }11231124// Implementation of class Reader1125// ////////////////////////////////11261127// Originally copied from the Reader class (now deprecated), used internally1128// for implementing JSON reading.1129class OurReader {1130public:1131typedef char Char;1132typedef const Char* Location;1133struct StructuredError {1134ptrdiff_t offset_start;1135ptrdiff_t offset_limit;1136String message;1137};11381139OurReader(OurFeatures const& features);1140bool parse(const char* beginDoc,1141const char* endDoc,1142Value& root,1143bool collectComments = true);1144String getFormattedErrorMessages() const;1145std::vector<StructuredError> getStructuredErrors() const;1146bool pushError(const Value& value, const String& message);1147bool pushError(const Value& value, const String& message, const Value& extra);1148bool good() const;11491150private:1151OurReader(OurReader const&); // no impl1152void operator=(OurReader const&); // no impl11531154enum TokenType {1155tokenEndOfStream = 0,1156tokenObjectBegin,1157tokenObjectEnd,1158tokenArrayBegin,1159tokenArrayEnd,1160tokenString,1161tokenNumber,1162tokenTrue,1163tokenFalse,1164tokenNull,1165tokenNaN,1166tokenPosInf,1167tokenNegInf,1168tokenArraySeparator,1169tokenMemberSeparator,1170tokenComment,1171tokenError1172};11731174class Token {1175public:1176TokenType type_;1177Location start_;1178Location end_;1179};11801181class ErrorInfo {1182public:1183Token token_;1184String message_;1185Location extra_;1186};11871188typedef std::deque<ErrorInfo> Errors;11891190bool readToken(Token& token);1191void skipSpaces();1192bool match(Location pattern, int patternLength);1193bool readComment();1194bool readCStyleComment();1195bool readCppStyleComment();1196bool readString();1197bool readStringSingleQuote();1198bool readNumber(bool checkInf);1199bool readValue();1200bool readObject(Token& token);1201bool readArray(Token& token);1202bool decodeNumber(Token& token);1203bool decodeNumber(Token& token, Value& decoded);1204bool decodeString(Token& token);1205bool decodeString(Token& token, String& decoded);1206bool decodeDouble(Token& token);1207bool decodeDouble(Token& token, Value& decoded);1208bool decodeUnicodeCodePoint(Token& token,1209Location& current,1210Location end,1211unsigned int& unicode);1212bool decodeUnicodeEscapeSequence(Token& token,1213Location& current,1214Location end,1215unsigned int& unicode);1216bool addError(const String& message, Token& token, Location extra = nullptr);1217bool recoverFromError(TokenType skipUntilToken);1218bool addErrorAndRecover(const String& message,1219Token& token,1220TokenType skipUntilToken);1221void skipUntilSpace();1222Value& currentValue();1223Char getNextChar();1224void1225getLocationLineAndColumn(Location location, int& line, int& column) const;1226String getLocationLineAndColumn(Location location) const;1227void addComment(Location begin, Location end, CommentPlacement placement);1228void skipCommentTokens(Token& token);12291230static String normalizeEOL(Location begin, Location end);1231static bool containsNewLine(Location begin, Location end);12321233typedef std::stack<Value*> Nodes;1234Nodes nodes_;1235Errors errors_;1236String document_;1237Location begin_;1238Location end_;1239Location current_;1240Location lastValueEnd_;1241Value* lastValue_;1242String commentsBefore_;12431244OurFeatures const features_;1245bool collectComments_;1246}; // OurReader12471248// complete copy of Read impl, for OurReader12491250bool OurReader::containsNewLine(OurReader::Location begin,1251OurReader::Location end) {1252for (; begin < end; ++begin)1253if (*begin == '\n' || *begin == '\r')1254return true;1255return false;1256}12571258OurReader::OurReader(OurFeatures const& features)1259: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),1260lastValue_(), commentsBefore_(), features_(features), collectComments_() {1261}12621263bool OurReader::parse(const char* beginDoc,1264const char* endDoc,1265Value& root,1266bool collectComments) {1267if (!features_.allowComments_) {1268collectComments = false;1269}12701271begin_ = beginDoc;1272end_ = endDoc;1273collectComments_ = collectComments;1274current_ = begin_;1275lastValueEnd_ = nullptr;1276lastValue_ = nullptr;1277commentsBefore_.clear();1278errors_.clear();1279while (!nodes_.empty())1280nodes_.pop();1281nodes_.push(&root);12821283bool successful = readValue();1284nodes_.pop();1285Token token;1286skipCommentTokens(token);1287if (features_.failIfExtra_) {1288if ((features_.strictRoot_ || token.type_ != tokenError) &&1289token.type_ != tokenEndOfStream) {1290addError("Extra non-whitespace after JSON value.", token);1291return false;1292}1293}1294if (collectComments_ && !commentsBefore_.empty())1295root.setComment(commentsBefore_, commentAfter);1296if (features_.strictRoot_) {1297if (!root.isArray() && !root.isObject()) {1298// Set error location to start of doc, ideally should be first token found1299// in doc1300token.type_ = tokenError;1301token.start_ = beginDoc;1302token.end_ = endDoc;1303addError(1304"A valid JSON document must be either an array or an object value.",1305token);1306return false;1307}1308}1309return successful;1310}13111312bool OurReader::readValue() {1313// To preserve the old behaviour we cast size_t to int.1314if (nodes_.size() > features_.stackLimit_)1315throwRuntimeError("Exceeded stackLimit in readValue().");1316Token token;1317skipCommentTokens(token);1318bool successful = true;13191320if (collectComments_ && !commentsBefore_.empty()) {1321currentValue().setComment(commentsBefore_, commentBefore);1322commentsBefore_.clear();1323}13241325switch (token.type_) {1326case tokenObjectBegin:1327successful = readObject(token);1328currentValue().setOffsetLimit(current_ - begin_);1329break;1330case tokenArrayBegin:1331successful = readArray(token);1332currentValue().setOffsetLimit(current_ - begin_);1333break;1334case tokenNumber:1335successful = decodeNumber(token);1336break;1337case tokenString:1338successful = decodeString(token);1339break;1340case tokenTrue: {1341Value v(true);1342currentValue().swapPayload(v);1343currentValue().setOffsetStart(token.start_ - begin_);1344currentValue().setOffsetLimit(token.end_ - begin_);1345} break;1346case tokenFalse: {1347Value v(false);1348currentValue().swapPayload(v);1349currentValue().setOffsetStart(token.start_ - begin_);1350currentValue().setOffsetLimit(token.end_ - begin_);1351} break;1352case tokenNull: {1353Value v;1354currentValue().swapPayload(v);1355currentValue().setOffsetStart(token.start_ - begin_);1356currentValue().setOffsetLimit(token.end_ - begin_);1357} break;1358case tokenNaN: {1359Value v(std::numeric_limits<double>::quiet_NaN());1360currentValue().swapPayload(v);1361currentValue().setOffsetStart(token.start_ - begin_);1362currentValue().setOffsetLimit(token.end_ - begin_);1363} break;1364case tokenPosInf: {1365Value v(std::numeric_limits<double>::infinity());1366currentValue().swapPayload(v);1367currentValue().setOffsetStart(token.start_ - begin_);1368currentValue().setOffsetLimit(token.end_ - begin_);1369} break;1370case tokenNegInf: {1371Value v(-std::numeric_limits<double>::infinity());1372currentValue().swapPayload(v);1373currentValue().setOffsetStart(token.start_ - begin_);1374currentValue().setOffsetLimit(token.end_ - begin_);1375} break;1376case tokenArraySeparator:1377case tokenObjectEnd:1378case tokenArrayEnd:1379if (features_.allowDroppedNullPlaceholders_) {1380// "Un-read" the current token and mark the current value as a null1381// token.1382current_--;1383Value v;1384currentValue().swapPayload(v);1385currentValue().setOffsetStart(current_ - begin_ - 1);1386currentValue().setOffsetLimit(current_ - begin_);1387break;1388} // else, fall through ...1389default:1390currentValue().setOffsetStart(token.start_ - begin_);1391currentValue().setOffsetLimit(token.end_ - begin_);1392return addError("Syntax error: value, object or array expected.", token);1393}13941395if (collectComments_) {1396lastValueEnd_ = current_;1397lastValue_ = ¤tValue();1398}13991400return successful;1401}14021403void OurReader::skipCommentTokens(Token& token) {1404if (features_.allowComments_) {1405do {1406readToken(token);1407} while (token.type_ == tokenComment);1408} else {1409readToken(token);1410}1411}14121413bool OurReader::readToken(Token& token) {1414skipSpaces();1415token.start_ = current_;1416Char c = getNextChar();1417bool ok = true;1418switch (c) {1419case '{':1420token.type_ = tokenObjectBegin;1421break;1422case '}':1423token.type_ = tokenObjectEnd;1424break;1425case '[':1426token.type_ = tokenArrayBegin;1427break;1428case ']':1429token.type_ = tokenArrayEnd;1430break;1431case '"':1432token.type_ = tokenString;1433ok = readString();1434break;1435case '\'':1436if (features_.allowSingleQuotes_) {1437token.type_ = tokenString;1438ok = readStringSingleQuote();1439break;1440} // else fall through1441case '/':1442token.type_ = tokenComment;1443ok = readComment();1444break;1445case '0':1446case '1':1447case '2':1448case '3':1449case '4':1450case '5':1451case '6':1452case '7':1453case '8':1454case '9':1455token.type_ = tokenNumber;1456readNumber(false);1457break;1458case '-':1459if (readNumber(true)) {1460token.type_ = tokenNumber;1461} else {1462token.type_ = tokenNegInf;1463ok = features_.allowSpecialFloats_ && match("nfinity", 7);1464}1465break;1466case 't':1467token.type_ = tokenTrue;1468ok = match("rue", 3);1469break;1470case 'f':1471token.type_ = tokenFalse;1472ok = match("alse", 4);1473break;1474case 'n':1475token.type_ = tokenNull;1476ok = match("ull", 3);1477break;1478case 'N':1479if (features_.allowSpecialFloats_) {1480token.type_ = tokenNaN;1481ok = match("aN", 2);1482} else {1483ok = false;1484}1485break;1486case 'I':1487if (features_.allowSpecialFloats_) {1488token.type_ = tokenPosInf;1489ok = match("nfinity", 7);1490} else {1491ok = false;1492}1493break;1494case ',':1495token.type_ = tokenArraySeparator;1496break;1497case ':':1498token.type_ = tokenMemberSeparator;1499break;1500case 0:1501token.type_ = tokenEndOfStream;1502break;1503default:1504ok = false;1505break;1506}1507if (!ok)1508token.type_ = tokenError;1509token.end_ = current_;1510return true;1511}15121513void OurReader::skipSpaces() {1514while (current_ != end_) {1515Char c = *current_;1516if (c == ' ' || c == '\t' || c == '\r' || c == '\n')1517++current_;1518else1519break;1520}1521}15221523bool OurReader::match(Location pattern, int patternLength) {1524if (end_ - current_ < patternLength)1525return false;1526int index = patternLength;1527while (index--)1528if (current_[index] != pattern[index])1529return false;1530current_ += patternLength;1531return true;1532}15331534bool OurReader::readComment() {1535Location commentBegin = current_ - 1;1536Char c = getNextChar();1537bool successful = false;1538if (c == '*')1539successful = readCStyleComment();1540else if (c == '/')1541successful = readCppStyleComment();1542if (!successful)1543return false;15441545if (collectComments_) {1546CommentPlacement placement = commentBefore;1547if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {1548if (c != '*' || !containsNewLine(commentBegin, current_))1549placement = commentAfterOnSameLine;1550}15511552addComment(commentBegin, current_, placement);1553}1554return true;1555}15561557String OurReader::normalizeEOL(OurReader::Location begin,1558OurReader::Location end) {1559String normalized;1560normalized.reserve(static_cast<size_t>(end - begin));1561OurReader::Location current = begin;1562while (current != end) {1563char c = *current++;1564if (c == '\r') {1565if (current != end && *current == '\n')1566// convert dos EOL1567++current;1568// convert Mac EOL1569normalized += '\n';1570} else {1571normalized += c;1572}1573}1574return normalized;1575}15761577void OurReader::addComment(Location begin,1578Location end,1579CommentPlacement placement) {1580assert(collectComments_);1581const String& normalized = normalizeEOL(begin, end);1582if (placement == commentAfterOnSameLine) {1583assert(lastValue_ != nullptr);1584lastValue_->setComment(normalized, placement);1585} else {1586commentsBefore_ += normalized;1587}1588}15891590bool OurReader::readCStyleComment() {1591while ((current_ + 1) < end_) {1592Char c = getNextChar();1593if (c == '*' && *current_ == '/')1594break;1595}1596return getNextChar() == '/';1597}15981599bool OurReader::readCppStyleComment() {1600while (current_ != end_) {1601Char c = getNextChar();1602if (c == '\n')1603break;1604if (c == '\r') {1605// Consume DOS EOL. It will be normalized in addComment.1606if (current_ != end_ && *current_ == '\n')1607getNextChar();1608// Break on Moc OS 9 EOL.1609break;1610}1611}1612return true;1613}16141615bool OurReader::readNumber(bool checkInf) {1616const char* p = current_;1617if (checkInf && p != end_ && *p == 'I') {1618current_ = ++p;1619return false;1620}1621char c = '0'; // stopgap for already consumed character1622// integral part1623while (c >= '0' && c <= '9')1624c = (current_ = p) < end_ ? *p++ : '\0';1625// fractional part1626if (c == '.') {1627c = (current_ = p) < end_ ? *p++ : '\0';1628while (c >= '0' && c <= '9')1629c = (current_ = p) < end_ ? *p++ : '\0';1630}1631// exponential part1632if (c == 'e' || c == 'E') {1633c = (current_ = p) < end_ ? *p++ : '\0';1634if (c == '+' || c == '-')1635c = (current_ = p) < end_ ? *p++ : '\0';1636while (c >= '0' && c <= '9')1637c = (current_ = p) < end_ ? *p++ : '\0';1638}1639return true;1640}1641bool OurReader::readString() {1642Char c = 0;1643while (current_ != end_) {1644c = getNextChar();1645if (c == '\\')1646getNextChar();1647else if (c == '"')1648break;1649}1650return c == '"';1651}16521653bool OurReader::readStringSingleQuote() {1654Char c = 0;1655while (current_ != end_) {1656c = getNextChar();1657if (c == '\\')1658getNextChar();1659else if (c == '\'')1660break;1661}1662return c == '\'';1663}16641665bool OurReader::readObject(Token& token) {1666Token tokenName;1667String name;1668Value init(objectValue);1669currentValue().swapPayload(init);1670currentValue().setOffsetStart(token.start_ - begin_);1671while (readToken(tokenName)) {1672bool initialTokenOk = true;1673while (tokenName.type_ == tokenComment && initialTokenOk)1674initialTokenOk = readToken(tokenName);1675if (!initialTokenOk)1676break;1677if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object1678return true;1679name.clear();1680if (tokenName.type_ == tokenString) {1681if (!decodeString(tokenName, name))1682return recoverFromError(tokenObjectEnd);1683} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {1684Value numberName;1685if (!decodeNumber(tokenName, numberName))1686return recoverFromError(tokenObjectEnd);1687name = numberName.asString();1688} else {1689break;1690}1691if (name.length() >= (1U << 30))1692throwRuntimeError("keylength >= 2^30");1693if (features_.rejectDupKeys_ && currentValue().isMember(name)) {1694String msg = "Duplicate key: '" + name + "'";1695return addErrorAndRecover(msg, tokenName, tokenObjectEnd);1696}16971698Token colon;1699if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {1700return addErrorAndRecover("Missing ':' after object member name", colon,1701tokenObjectEnd);1702}1703Value& value = currentValue()[name];1704nodes_.push(&value);1705bool ok = readValue();1706nodes_.pop();1707if (!ok) // error already set1708return recoverFromError(tokenObjectEnd);17091710Token comma;1711if (!readToken(comma) ||1712(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&1713comma.type_ != tokenComment)) {1714return addErrorAndRecover("Missing ',' or '}' in object declaration",1715comma, tokenObjectEnd);1716}1717bool finalizeTokenOk = true;1718while (comma.type_ == tokenComment && finalizeTokenOk)1719finalizeTokenOk = readToken(comma);1720if (comma.type_ == tokenObjectEnd)1721return true;1722}1723return addErrorAndRecover("Missing '}' or object member name", tokenName,1724tokenObjectEnd);1725}17261727bool OurReader::readArray(Token& token) {1728Value init(arrayValue);1729currentValue().swapPayload(init);1730currentValue().setOffsetStart(token.start_ - begin_);1731skipSpaces();1732if (current_ != end_ && *current_ == ']') // empty array1733{1734Token endArray;1735readToken(endArray);1736return true;1737}1738int index = 0;1739for (;;) {1740Value& value = currentValue()[index++];1741nodes_.push(&value);1742bool ok = readValue();1743nodes_.pop();1744if (!ok) // error already set1745return recoverFromError(tokenArrayEnd);17461747Token currentToken;1748// Accept Comment after last item in the array.1749ok = readToken(currentToken);1750while (currentToken.type_ == tokenComment && ok) {1751ok = readToken(currentToken);1752}1753bool badTokenType = (currentToken.type_ != tokenArraySeparator &&1754currentToken.type_ != tokenArrayEnd);1755if (!ok || badTokenType) {1756return addErrorAndRecover("Missing ',' or ']' in array declaration",1757currentToken, tokenArrayEnd);1758}1759if (currentToken.type_ == tokenArrayEnd)1760break;1761}1762return true;1763}17641765bool OurReader::decodeNumber(Token& token) {1766Value decoded;1767if (!decodeNumber(token, decoded))1768return false;1769currentValue().swapPayload(decoded);1770currentValue().setOffsetStart(token.start_ - begin_);1771currentValue().setOffsetLimit(token.end_ - begin_);1772return true;1773}17741775bool OurReader::decodeNumber(Token& token, Value& decoded) {1776// Attempts to parse the number as an integer. If the number is1777// larger than the maximum supported value of an integer then1778// we decode the number as a double.1779Location current = token.start_;1780bool isNegative = *current == '-';1781if (isNegative)1782++current;17831784// TODO(issue #960): Change to constexpr1785static const auto positive_threshold = Value::maxLargestUInt / 10;1786static const auto positive_last_digit = Value::maxLargestUInt % 10;1787static const auto negative_threshold =1788Value::LargestUInt(Value::minLargestInt) / 10;1789static const auto negative_last_digit =1790Value::LargestUInt(Value::minLargestInt) % 10;17911792const auto threshold = isNegative ? negative_threshold : positive_threshold;1793const auto last_digit =1794isNegative ? negative_last_digit : positive_last_digit;17951796Value::LargestUInt value = 0;1797while (current < token.end_) {1798Char c = *current++;1799if (c < '0' || c > '9')1800return decodeDouble(token, decoded);18011802const auto digit(static_cast<Value::UInt>(c - '0'));1803if (value >= threshold) {1804// We've hit or exceeded the max value divided by 10 (rounded down). If1805// a) we've only just touched the limit, meaing value == threshold,1806// b) this is the last digit, or1807// c) it's small enough to fit in that rounding delta, we're okay.1808// Otherwise treat this number as a double to avoid overflow.1809if (value > threshold || current != token.end_ || digit > last_digit) {1810return decodeDouble(token, decoded);1811}1812}1813value = value * 10 + digit;1814}18151816if (isNegative)1817decoded = -Value::LargestInt(value);1818else if (value <= Value::LargestUInt(Value::maxLargestInt))1819decoded = Value::LargestInt(value);1820else1821decoded = value;18221823return true;1824}18251826bool OurReader::decodeDouble(Token& token) {1827Value decoded;1828if (!decodeDouble(token, decoded))1829return false;1830currentValue().swapPayload(decoded);1831currentValue().setOffsetStart(token.start_ - begin_);1832currentValue().setOffsetLimit(token.end_ - begin_);1833return true;1834}18351836bool OurReader::decodeDouble(Token& token, Value& decoded) {1837double value = 0;1838const int bufferSize = 32;1839int count;1840ptrdiff_t const length = token.end_ - token.start_;18411842// Sanity check to avoid buffer overflow exploits.1843if (length < 0) {1844return addError("Unable to parse token length", token);1845}1846auto const ulength = static_cast<size_t>(length);18471848// Avoid using a string constant for the format control string given to1849// sscanf, as this can cause hard to debug crashes on OS X. See here for more1850// info:1851//1852// http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html1853char format[] = "%lf";18541855if (length <= bufferSize) {1856Char buffer[bufferSize + 1];1857memcpy(buffer, token.start_, ulength);1858buffer[length] = 0;1859fixNumericLocaleInput(buffer, buffer + length);1860count = sscanf(buffer, format, &value);1861} else {1862String buffer(token.start_, token.end_);1863count = sscanf(buffer.c_str(), format, &value);1864}18651866if (count != 1)1867return addError(1868"'" + String(token.start_, token.end_) + "' is not a number.", token);1869decoded = value;1870return true;1871}18721873bool OurReader::decodeString(Token& token) {1874String decoded_string;1875if (!decodeString(token, decoded_string))1876return false;1877Value decoded(decoded_string);1878currentValue().swapPayload(decoded);1879currentValue().setOffsetStart(token.start_ - begin_);1880currentValue().setOffsetLimit(token.end_ - begin_);1881return true;1882}18831884bool OurReader::decodeString(Token& token, String& decoded) {1885decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));1886Location current = token.start_ + 1; // skip '"'1887Location end = token.end_ - 1; // do not include '"'1888while (current != end) {1889Char c = *current++;1890if (c == '"')1891break;1892else if (c == '\\') {1893if (current == end)1894return addError("Empty escape sequence in string", token, current);1895Char escape = *current++;1896switch (escape) {1897case '"':1898decoded += '"';1899break;1900case '/':1901decoded += '/';1902break;1903case '\\':1904decoded += '\\';1905break;1906case 'b':1907decoded += '\b';1908break;1909case 'f':1910decoded += '\f';1911break;1912case 'n':1913decoded += '\n';1914break;1915case 'r':1916decoded += '\r';1917break;1918case 't':1919decoded += '\t';1920break;1921case 'u': {1922unsigned int unicode;1923if (!decodeUnicodeCodePoint(token, current, end, unicode))1924return false;1925decoded += codePointToUTF8(unicode);1926} break;1927default:1928return addError("Bad escape sequence in string", token, current);1929}1930} else {1931decoded += c;1932}1933}1934return true;1935}19361937bool OurReader::decodeUnicodeCodePoint(Token& token,1938Location& current,1939Location end,1940unsigned int& unicode) {19411942if (!decodeUnicodeEscapeSequence(token, current, end, unicode))1943return false;1944if (unicode >= 0xD800 && unicode <= 0xDBFF) {1945// surrogate pairs1946if (end - current < 6)1947return addError(1948"additional six characters expected to parse unicode surrogate pair.",1949token, current);1950if (*(current++) == '\\' && *(current++) == 'u') {1951unsigned int surrogatePair;1952if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {1953unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);1954} else1955return false;1956} else1957return addError("expecting another \\u token to begin the second half of "1958"a unicode surrogate pair",1959token, current);1960}1961return true;1962}19631964bool OurReader::decodeUnicodeEscapeSequence(Token& token,1965Location& current,1966Location end,1967unsigned int& ret_unicode) {1968if (end - current < 4)1969return addError(1970"Bad unicode escape sequence in string: four digits expected.", token,1971current);1972int unicode = 0;1973for (int index = 0; index < 4; ++index) {1974Char c = *current++;1975unicode *= 16;1976if (c >= '0' && c <= '9')1977unicode += c - '0';1978else if (c >= 'a' && c <= 'f')1979unicode += c - 'a' + 10;1980else if (c >= 'A' && c <= 'F')1981unicode += c - 'A' + 10;1982else1983return addError(1984"Bad unicode escape sequence in string: hexadecimal digit expected.",1985token, current);1986}1987ret_unicode = static_cast<unsigned int>(unicode);1988return true;1989}19901991bool OurReader::addError(const String& message, Token& token, Location extra) {1992ErrorInfo info;1993info.token_ = token;1994info.message_ = message;1995info.extra_ = extra;1996errors_.push_back(info);1997return false;1998}19992000bool OurReader::recoverFromError(TokenType skipUntilToken) {2001size_t errorCount = errors_.size();2002Token skip;2003for (;;) {2004if (!readToken(skip))2005errors_.resize(errorCount); // discard errors caused by recovery2006if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)2007break;2008}2009errors_.resize(errorCount);2010return false;2011}20122013bool OurReader::addErrorAndRecover(const String& message,2014Token& token,2015TokenType skipUntilToken) {2016addError(message, token);2017return recoverFromError(skipUntilToken);2018}20192020Value& OurReader::currentValue() { return *(nodes_.top()); }20212022OurReader::Char OurReader::getNextChar() {2023if (current_ == end_)2024return 0;2025return *current_++;2026}20272028void OurReader::getLocationLineAndColumn(Location location,2029int& line,2030int& column) const {2031Location current = begin_;2032Location lastLineStart = current;2033line = 0;2034while (current < location && current != end_) {2035Char c = *current++;2036if (c == '\r') {2037if (*current == '\n')2038++current;2039lastLineStart = current;2040++line;2041} else if (c == '\n') {2042lastLineStart = current;2043++line;2044}2045}2046// column & line start at 12047column = int(location - lastLineStart) + 1;2048++line;2049}20502051String OurReader::getLocationLineAndColumn(Location location) const {2052int line, column;2053getLocationLineAndColumn(location, line, column);2054char buffer[18 + 16 + 16 + 1];2055jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);2056return buffer;2057}20582059String OurReader::getFormattedErrorMessages() const {2060String formattedMessage;2061for (const auto& error : errors_) {2062formattedMessage +=2063"* " + getLocationLineAndColumn(error.token_.start_) + "\n";2064formattedMessage += " " + error.message_ + "\n";2065if (error.extra_)2066formattedMessage +=2067"See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";2068}2069return formattedMessage;2070}20712072std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {2073std::vector<OurReader::StructuredError> allErrors;2074for (const auto& error : errors_) {2075OurReader::StructuredError structured;2076structured.offset_start = error.token_.start_ - begin_;2077structured.offset_limit = error.token_.end_ - begin_;2078structured.message = error.message_;2079allErrors.push_back(structured);2080}2081return allErrors;2082}20832084bool OurReader::pushError(const Value& value, const String& message) {2085ptrdiff_t length = end_ - begin_;2086if (value.getOffsetStart() > length || value.getOffsetLimit() > length)2087return false;2088Token token;2089token.type_ = tokenError;2090token.start_ = begin_ + value.getOffsetStart();2091token.end_ = begin_ + value.getOffsetLimit();2092ErrorInfo info;2093info.token_ = token;2094info.message_ = message;2095info.extra_ = nullptr;2096errors_.push_back(info);2097return true;2098}20992100bool OurReader::pushError(const Value& value,2101const String& message,2102const Value& extra) {2103ptrdiff_t length = end_ - begin_;2104if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||2105extra.getOffsetLimit() > length)2106return false;2107Token token;2108token.type_ = tokenError;2109token.start_ = begin_ + value.getOffsetStart();2110token.end_ = begin_ + value.getOffsetLimit();2111ErrorInfo info;2112info.token_ = token;2113info.message_ = message;2114info.extra_ = begin_ + extra.getOffsetStart();2115errors_.push_back(info);2116return true;2117}21182119bool OurReader::good() const { return errors_.empty(); }21202121class OurCharReader : public CharReader {2122bool const collectComments_;2123OurReader reader_;21242125public:2126OurCharReader(bool collectComments, OurFeatures const& features)2127: collectComments_(collectComments), reader_(features) {}2128bool parse(char const* beginDoc,2129char const* endDoc,2130Value* root,2131String* errs) override {2132bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);2133if (errs) {2134*errs = reader_.getFormattedErrorMessages();2135}2136return ok;2137}2138};21392140CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }2141CharReaderBuilder::~CharReaderBuilder() = default;2142CharReader* CharReaderBuilder::newCharReader() const {2143bool collectComments = settings_["collectComments"].asBool();2144OurFeatures features = OurFeatures::all();2145features.allowComments_ = settings_["allowComments"].asBool();2146features.strictRoot_ = settings_["strictRoot"].asBool();2147features.allowDroppedNullPlaceholders_ =2148settings_["allowDroppedNullPlaceholders"].asBool();2149features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();2150features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();21512152// Stack limit is always a size_t, so we get this as an unsigned int2153// regardless of it we have 64-bit integer support enabled.2154features.stackLimit_ = static_cast<size_t>(settings_["stackLimit"].asUInt());2155features.failIfExtra_ = settings_["failIfExtra"].asBool();2156features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();2157features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();2158return new OurCharReader(collectComments, features);2159}2160static void getValidReaderKeys(std::set<String>* valid_keys) {2161valid_keys->clear();2162valid_keys->insert("collectComments");2163valid_keys->insert("allowComments");2164valid_keys->insert("strictRoot");2165valid_keys->insert("allowDroppedNullPlaceholders");2166valid_keys->insert("allowNumericKeys");2167valid_keys->insert("allowSingleQuotes");2168valid_keys->insert("stackLimit");2169valid_keys->insert("failIfExtra");2170valid_keys->insert("rejectDupKeys");2171valid_keys->insert("allowSpecialFloats");2172}2173bool CharReaderBuilder::validate(Json::Value* invalid) const {2174Json::Value my_invalid;2175if (!invalid)2176invalid = &my_invalid; // so we do not need to test for NULL2177Json::Value& inv = *invalid;2178std::set<String> valid_keys;2179getValidReaderKeys(&valid_keys);2180Value::Members keys = settings_.getMemberNames();2181size_t n = keys.size();2182for (size_t i = 0; i < n; ++i) {2183String const& key = keys[i];2184if (valid_keys.find(key) == valid_keys.end()) {2185inv[key] = settings_[key];2186}2187}2188return inv.empty();2189}2190Value& CharReaderBuilder::operator[](const String& key) {2191return settings_[key];2192}2193// static2194void CharReaderBuilder::strictMode(Json::Value* settings) {2195//! [CharReaderBuilderStrictMode]2196(*settings)["allowComments"] = false;2197(*settings)["strictRoot"] = true;2198(*settings)["allowDroppedNullPlaceholders"] = false;2199(*settings)["allowNumericKeys"] = false;2200(*settings)["allowSingleQuotes"] = false;2201(*settings)["stackLimit"] = 1000;2202(*settings)["failIfExtra"] = true;2203(*settings)["rejectDupKeys"] = true;2204(*settings)["allowSpecialFloats"] = false;2205//! [CharReaderBuilderStrictMode]2206}2207// static2208void CharReaderBuilder::setDefaults(Json::Value* settings) {2209//! [CharReaderBuilderDefaults]2210(*settings)["collectComments"] = true;2211(*settings)["allowComments"] = true;2212(*settings)["strictRoot"] = false;2213(*settings)["allowDroppedNullPlaceholders"] = false;2214(*settings)["allowNumericKeys"] = false;2215(*settings)["allowSingleQuotes"] = false;2216(*settings)["stackLimit"] = 1000;2217(*settings)["failIfExtra"] = false;2218(*settings)["rejectDupKeys"] = false;2219(*settings)["allowSpecialFloats"] = false;2220//! [CharReaderBuilderDefaults]2221}22222223//////////////////////////////////2224// global functions22252226bool parseFromStream(CharReader::Factory const& fact,2227IStream& sin,2228Value* root,2229String* errs) {2230OStringStream ssin;2231ssin << sin.rdbuf();2232String doc = ssin.str();2233char const* begin = doc.data();2234char const* end = begin + doc.size();2235// Note that we do not actually need a null-terminator.2236CharReaderPtr const reader(fact.newCharReader());2237return reader->parse(begin, end, root, errs);2238}22392240IStream& operator>>(IStream& sin, Value& root) {2241CharReaderBuilder b;2242String errs;2243bool ok = parseFromStream(b, sin, &root, &errs);2244if (!ok) {2245throwRuntimeError(errs);2246}2247return sin;2248}22492250} // namespace Json22512252// //////////////////////////////////////////////////////////////////////2253// End of content of file: src/lib_json/json_reader.cpp2254// //////////////////////////////////////////////////////////////////////2255225622572258225922602261// //////////////////////////////////////////////////////////////////////2262// Beginning of content of file: src/lib_json/json_valueiterator.inl2263// //////////////////////////////////////////////////////////////////////22642265// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors2266// Distributed under MIT license, or public domain if desired and2267// recognized in your jurisdiction.2268// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE22692270// included by json_value.cpp22712272namespace Json {22732274// //////////////////////////////////////////////////////////////////2275// //////////////////////////////////////////////////////////////////2276// //////////////////////////////////////////////////////////////////2277// class ValueIteratorBase2278// //////////////////////////////////////////////////////////////////2279// //////////////////////////////////////////////////////////////////2280// //////////////////////////////////////////////////////////////////22812282ValueIteratorBase::ValueIteratorBase() : current_() {}22832284ValueIteratorBase::ValueIteratorBase(2285const Value::ObjectValues::iterator& current)2286: current_(current), isNull_(false) {}22872288Value& ValueIteratorBase::deref() const { return current_->second; }22892290void ValueIteratorBase::increment() { ++current_; }22912292void ValueIteratorBase::decrement() { --current_; }22932294ValueIteratorBase::difference_type2295ValueIteratorBase::computeDistance(const SelfType& other) const {2296#ifdef JSON_USE_CPPTL_SMALLMAP2297return other.current_ - current_;2298#else2299// Iterator for null value are initialized using the default2300// constructor, which initialize current_ to the default2301// std::map::iterator. As begin() and end() are two instance2302// of the default std::map::iterator, they can not be compared.2303// To allow this, we handle this comparison specifically.2304if (isNull_ && other.isNull_) {2305return 0;2306}23072308// Usage of std::distance is not portable (does not compile with Sun Studio 122309// RogueWave STL,2310// which is the one used by default).2311// Using a portable hand-made version for non random iterator instead:2312// return difference_type( std::distance( current_, other.current_ ) );2313difference_type myDistance = 0;2314for (Value::ObjectValues::iterator it = current_; it != other.current_;2315++it) {2316++myDistance;2317}2318return myDistance;2319#endif2320}23212322bool ValueIteratorBase::isEqual(const SelfType& other) const {2323if (isNull_) {2324return other.isNull_;2325}2326return current_ == other.current_;2327}23282329void ValueIteratorBase::copy(const SelfType& other) {2330current_ = other.current_;2331isNull_ = other.isNull_;2332}23332334Value ValueIteratorBase::key() const {2335const Value::CZString czstring = (*current_).first;2336if (czstring.data()) {2337if (czstring.isStaticString())2338return Value(StaticString(czstring.data()));2339return Value(czstring.data(), czstring.data() + czstring.length());2340}2341return Value(czstring.index());2342}23432344UInt ValueIteratorBase::index() const {2345const Value::CZString czstring = (*current_).first;2346if (!czstring.data())2347return czstring.index();2348return Value::UInt(-1);2349}23502351String ValueIteratorBase::name() const {2352char const* keey;2353char const* end;2354keey = memberName(&end);2355if (!keey)2356return String();2357return String(keey, end);2358}23592360char const* ValueIteratorBase::memberName() const {2361const char* cname = (*current_).first.data();2362return cname ? cname : "";2363}23642365char const* ValueIteratorBase::memberName(char const** end) const {2366const char* cname = (*current_).first.data();2367if (!cname) {2368*end = nullptr;2369return nullptr;2370}2371*end = cname + (*current_).first.length();2372return cname;2373}23742375// //////////////////////////////////////////////////////////////////2376// //////////////////////////////////////////////////////////////////2377// //////////////////////////////////////////////////////////////////2378// class ValueConstIterator2379// //////////////////////////////////////////////////////////////////2380// //////////////////////////////////////////////////////////////////2381// //////////////////////////////////////////////////////////////////23822383ValueConstIterator::ValueConstIterator() = default;23842385ValueConstIterator::ValueConstIterator(2386const Value::ObjectValues::iterator& current)2387: ValueIteratorBase(current) {}23882389ValueConstIterator::ValueConstIterator(ValueIterator const& other)2390: ValueIteratorBase(other) {}23912392ValueConstIterator& ValueConstIterator::2393operator=(const ValueIteratorBase& other) {2394copy(other);2395return *this;2396}23972398// //////////////////////////////////////////////////////////////////2399// //////////////////////////////////////////////////////////////////2400// //////////////////////////////////////////////////////////////////2401// class ValueIterator2402// //////////////////////////////////////////////////////////////////2403// //////////////////////////////////////////////////////////////////2404// //////////////////////////////////////////////////////////////////24052406ValueIterator::ValueIterator() = default;24072408ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)2409: ValueIteratorBase(current) {}24102411ValueIterator::ValueIterator(const ValueConstIterator& other)2412: ValueIteratorBase(other) {2413throwRuntimeError("ConstIterator to Iterator should never be allowed.");2414}24152416ValueIterator::ValueIterator(const ValueIterator& other) = default;24172418ValueIterator& ValueIterator::operator=(const SelfType& other) {2419copy(other);2420return *this;2421}24222423} // namespace Json24242425// //////////////////////////////////////////////////////////////////////2426// End of content of file: src/lib_json/json_valueiterator.inl2427// //////////////////////////////////////////////////////////////////////2428242924302431243224332434// //////////////////////////////////////////////////////////////////////2435// Beginning of content of file: src/lib_json/json_value.cpp2436// //////////////////////////////////////////////////////////////////////24372438// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors2439// Distributed under MIT license, or public domain if desired and2440// recognized in your jurisdiction.2441// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE24422443#if !defined(JSON_IS_AMALGAMATION)2444#include <json/assertions.h>2445#include <json/value.h>2446#include <json/writer.h>2447#endif // if !defined(JSON_IS_AMALGAMATION)2448#include <cassert>2449#include <cmath>2450#include <cstring>2451#include <sstream>2452#include <utility>2453#ifdef JSON_USE_CPPTL2454#include <cpptl/conststring.h>2455#endif2456#include <algorithm> // min()2457#include <cstddef> // size_t24582459// Provide implementation equivalent of std::snprintf for older _MSC compilers2460#if defined(_MSC_VER) && _MSC_VER < 19002461#include <stdarg.h>2462static int msvc_pre1900_c99_vsnprintf(char* outBuf,2463size_t size,2464const char* format,2465va_list ap) {2466int count = -1;2467if (size != 0)2468count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);2469if (count == -1)2470count = _vscprintf(format, ap);2471return count;2472}24732474int JSON_API msvc_pre1900_c99_snprintf(char* outBuf,2475size_t size,2476const char* format,2477...) {2478va_list ap;2479va_start(ap, format);2480const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap);2481va_end(ap);2482return count;2483}2484#endif24852486// Disable warning C4702 : unreachable code2487#if defined(_MSC_VER)2488#pragma warning(disable : 4702)2489#endif24902491#define JSON_ASSERT_UNREACHABLE assert(false)24922493namespace Json {2494template <typename T>2495static std::unique_ptr<T> cloneUnique(const std::unique_ptr<T>& p) {2496std::unique_ptr<T> r;2497if (p) {2498r = std::unique_ptr<T>(new T(*p));2499}2500return r;2501}25022503// This is a walkaround to avoid the static initialization of Value::null.2504// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of2505// 8 (instead of 4) as a bit of future-proofing.2506#if defined(__ARMEL__)2507#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))2508#else2509#define ALIGNAS(byte_alignment)2510#endif25112512// static2513Value const& Value::nullSingleton() {2514static Value const nullStatic;2515return nullStatic;2516}25172518#if JSON_USE_NULLREF2519// for backwards compatibility, we'll leave these global references around, but2520// DO NOT use them in JSONCPP library code any more!2521// static2522Value const& Value::null = Value::nullSingleton();25232524// static2525Value const& Value::nullRef = Value::nullSingleton();2526#endif25272528const Int Value::minInt = Int(~(UInt(-1) / 2));2529const Int Value::maxInt = Int(UInt(-1) / 2);2530const UInt Value::maxUInt = UInt(-1);2531#if defined(JSON_HAS_INT64)2532const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));2533const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);2534const UInt64 Value::maxUInt64 = UInt64(-1);2535// The constant is hard-coded because some compiler have trouble2536// converting Value::maxUInt64 to a double correctly (AIX/xlC).2537// Assumes that UInt64 is a 64 bits integer.2538static const double maxUInt64AsDouble = 18446744073709551615.0;2539#endif // defined(JSON_HAS_INT64)2540const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));2541const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);2542const LargestUInt Value::maxLargestUInt = LargestUInt(-1);25432544const UInt Value::defaultRealPrecision = 17;25452546#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)2547template <typename T, typename U>2548static inline bool InRange(double d, T min, U max) {2549// The casts can lose precision, but we are looking only for2550// an approximate range. Might fail on edge cases though. ~cdunn2551// return d >= static_cast<double>(min) && d <= static_cast<double>(max);2552return d >= min && d <= max;2553}2554#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)2555static inline double integerToDouble(Json::UInt64 value) {2556return static_cast<double>(Int64(value / 2)) * 2.0 +2557static_cast<double>(Int64(value & 1));2558}25592560template <typename T> static inline double integerToDouble(T value) {2561return static_cast<double>(value);2562}25632564template <typename T, typename U>2565static inline bool InRange(double d, T min, U max) {2566return d >= integerToDouble(min) && d <= integerToDouble(max);2567}2568#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)25692570/** Duplicates the specified string value.2571* @param value Pointer to the string to duplicate. Must be zero-terminated if2572* length is "unknown".2573* @param length Length of the value. if equals to unknown, then it will be2574* computed using strlen(value).2575* @return Pointer on the duplicate instance of string.2576*/2577static inline char* duplicateStringValue(const char* value, size_t length) {2578// Avoid an integer overflow in the call to malloc below by limiting length2579// to a sane value.2580if (length >= static_cast<size_t>(Value::maxInt))2581length = Value::maxInt - 1;25822583char* newString = static_cast<char*>(malloc(length + 1));2584if (newString == nullptr) {2585throwRuntimeError("in Json::Value::duplicateStringValue(): "2586"Failed to allocate string value buffer");2587}2588memcpy(newString, value, length);2589newString[length] = 0;2590return newString;2591}25922593/* Record the length as a prefix.2594*/2595static inline char* duplicateAndPrefixStringValue(const char* value,2596unsigned int length) {2597// Avoid an integer overflow in the call to malloc below by limiting length2598// to a sane value.2599JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) -2600sizeof(unsigned) - 1U,2601"in Json::Value::duplicateAndPrefixStringValue(): "2602"length too big for prefixing");2603unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;2604char* newString = static_cast<char*>(malloc(actualLength));2605if (newString == nullptr) {2606throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "2607"Failed to allocate string value buffer");2608}2609*reinterpret_cast<unsigned*>(newString) = length;2610memcpy(newString + sizeof(unsigned), value, length);2611newString[actualLength - 1U] =26120; // to avoid buffer over-run accidents by users later2613return newString;2614}2615inline static void decodePrefixedString(bool isPrefixed,2616char const* prefixed,2617unsigned* length,2618char const** value) {2619if (!isPrefixed) {2620*length = static_cast<unsigned>(strlen(prefixed));2621*value = prefixed;2622} else {2623*length = *reinterpret_cast<unsigned const*>(prefixed);2624*value = prefixed + sizeof(unsigned);2625}2626}2627/** Free the string duplicated by2628* duplicateStringValue()/duplicateAndPrefixStringValue().2629*/2630#if JSONCPP_USING_SECURE_MEMORY2631static inline void releasePrefixedStringValue(char* value) {2632unsigned length = 0;2633char const* valueDecoded;2634decodePrefixedString(true, value, &length, &valueDecoded);2635size_t const size = sizeof(unsigned) + length + 1U;2636memset(value, 0, size);2637free(value);2638}2639static inline void releaseStringValue(char* value, unsigned length) {2640// length==0 => we allocated the strings memory2641size_t size = (length == 0) ? strlen(value) : length;2642memset(value, 0, size);2643free(value);2644}2645#else // !JSONCPP_USING_SECURE_MEMORY2646static inline void releasePrefixedStringValue(char* value) { free(value); }2647static inline void releaseStringValue(char* value, unsigned) { free(value); }2648#endif // JSONCPP_USING_SECURE_MEMORY26492650} // namespace Json26512652// //////////////////////////////////////////////////////////////////2653// //////////////////////////////////////////////////////////////////2654// //////////////////////////////////////////////////////////////////2655// ValueInternals...2656// //////////////////////////////////////////////////////////////////2657// //////////////////////////////////////////////////////////////////2658// //////////////////////////////////////////////////////////////////2659#if !defined(JSON_IS_AMALGAMATION)26602661#include "json_valueiterator.inl"2662#endif // if !defined(JSON_IS_AMALGAMATION)26632664namespace Json {26652666#if JSON_USE_EXCEPTION2667Exception::Exception(String msg) : msg_(std::move(msg)) {}2668Exception::~Exception() JSONCPP_NOEXCEPT {}2669char const* Exception::what() const JSONCPP_NOEXCEPT { return msg_.c_str(); }2670RuntimeError::RuntimeError(String const& msg) : Exception(msg) {}2671LogicError::LogicError(String const& msg) : Exception(msg) {}2672[[noreturn]] void throwRuntimeError(String const& msg) {2673throw RuntimeError(msg);2674}2675[[noreturn]] void throwLogicError(String const& msg) { throw LogicError(msg); }2676#else // !JSON_USE_EXCEPTION2677[[noreturn]] void throwRuntimeError(String const& msg) { abort(); }2678[[noreturn]] void throwLogicError(String const& msg) { abort(); }2679#endif26802681// //////////////////////////////////////////////////////////////////2682// //////////////////////////////////////////////////////////////////2683// //////////////////////////////////////////////////////////////////2684// class Value::CZString2685// //////////////////////////////////////////////////////////////////2686// //////////////////////////////////////////////////////////////////2687// //////////////////////////////////////////////////////////////////26882689// Notes: policy_ indicates if the string was allocated when2690// a string is stored.26912692Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {}26932694Value::CZString::CZString(char const* str,2695unsigned length,2696DuplicationPolicy allocate)2697: cstr_(str) {2698// allocate != duplicate2699storage_.policy_ = allocate & 0x3;2700storage_.length_ = length & 0x3FFFFFFF;2701}27022703Value::CZString::CZString(const CZString& other) {2704cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr2705? duplicateStringValue(other.cstr_, other.storage_.length_)2706: other.cstr_);2707storage_.policy_ =2708static_cast<unsigned>(2709other.cstr_2710? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==2711noDuplication2712? noDuplication2713: duplicate)2714: static_cast<DuplicationPolicy>(other.storage_.policy_)) &27153U;2716storage_.length_ = other.storage_.length_;2717}27182719Value::CZString::CZString(CZString&& other)2720: cstr_(other.cstr_), index_(other.index_) {2721other.cstr_ = nullptr;2722}27232724Value::CZString::~CZString() {2725if (cstr_ && storage_.policy_ == duplicate) {2726releaseStringValue(const_cast<char*>(cstr_),2727storage_.length_ + 1u); // +1 for null terminating2728// character for sake of2729// completeness but not actually2730// necessary2731}2732}27332734void Value::CZString::swap(CZString& other) {2735std::swap(cstr_, other.cstr_);2736std::swap(index_, other.index_);2737}27382739Value::CZString& Value::CZString::operator=(const CZString& other) {2740cstr_ = other.cstr_;2741index_ = other.index_;2742return *this;2743}27442745Value::CZString& Value::CZString::operator=(CZString&& other) {2746cstr_ = other.cstr_;2747index_ = other.index_;2748other.cstr_ = nullptr;2749return *this;2750}27512752bool Value::CZString::operator<(const CZString& other) const {2753if (!cstr_)2754return index_ < other.index_;2755// return strcmp(cstr_, other.cstr_) < 0;2756// Assume both are strings.2757unsigned this_len = this->storage_.length_;2758unsigned other_len = other.storage_.length_;2759unsigned min_len = std::min<unsigned>(this_len, other_len);2760JSON_ASSERT(this->cstr_ && other.cstr_);2761int comp = memcmp(this->cstr_, other.cstr_, min_len);2762if (comp < 0)2763return true;2764if (comp > 0)2765return false;2766return (this_len < other_len);2767}27682769bool Value::CZString::operator==(const CZString& other) const {2770if (!cstr_)2771return index_ == other.index_;2772// return strcmp(cstr_, other.cstr_) == 0;2773// Assume both are strings.2774unsigned this_len = this->storage_.length_;2775unsigned other_len = other.storage_.length_;2776if (this_len != other_len)2777return false;2778JSON_ASSERT(this->cstr_ && other.cstr_);2779int comp = memcmp(this->cstr_, other.cstr_, this_len);2780return comp == 0;2781}27822783ArrayIndex Value::CZString::index() const { return index_; }27842785// const char* Value::CZString::c_str() const { return cstr_; }2786const char* Value::CZString::data() const { return cstr_; }2787unsigned Value::CZString::length() const { return storage_.length_; }2788bool Value::CZString::isStaticString() const {2789return storage_.policy_ == noDuplication;2790}27912792// //////////////////////////////////////////////////////////////////2793// //////////////////////////////////////////////////////////////////2794// //////////////////////////////////////////////////////////////////2795// class Value::Value2796// //////////////////////////////////////////////////////////////////2797// //////////////////////////////////////////////////////////////////2798// //////////////////////////////////////////////////////////////////27992800/*! \internal Default constructor initialization must be equivalent to:2801* memset( this, 0, sizeof(Value) )2802* This optimization is used in ValueInternalMap fast allocator.2803*/2804Value::Value(ValueType type) {2805static char const emptyString[] = "";2806initBasic(type);2807switch (type) {2808case nullValue:2809break;2810case intValue:2811case uintValue:2812value_.int_ = 0;2813break;2814case realValue:2815value_.real_ = 0.0;2816break;2817case stringValue:2818// allocated_ == false, so this is safe.2819value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));2820break;2821case arrayValue:2822case objectValue:2823value_.map_ = new ObjectValues();2824break;2825case booleanValue:2826value_.bool_ = false;2827break;2828default:2829JSON_ASSERT_UNREACHABLE;2830}2831}28322833Value::Value(Int value) {2834initBasic(intValue);2835value_.int_ = value;2836}28372838Value::Value(UInt value) {2839initBasic(uintValue);2840value_.uint_ = value;2841}2842#if defined(JSON_HAS_INT64)2843Value::Value(Int64 value) {2844initBasic(intValue);2845value_.int_ = value;2846}2847Value::Value(UInt64 value) {2848initBasic(uintValue);2849value_.uint_ = value;2850}2851#endif // defined(JSON_HAS_INT64)28522853Value::Value(double value) {2854initBasic(realValue);2855value_.real_ = value;2856}28572858Value::Value(const char* value) {2859initBasic(stringValue, true);2860JSON_ASSERT_MESSAGE(value != nullptr,2861"Null Value Passed to Value Constructor");2862value_.string_ = duplicateAndPrefixStringValue(2863value, static_cast<unsigned>(strlen(value)));2864}28652866Value::Value(const char* begin, const char* end) {2867initBasic(stringValue, true);2868value_.string_ =2869duplicateAndPrefixStringValue(begin, static_cast<unsigned>(end - begin));2870}28712872Value::Value(const String& value) {2873initBasic(stringValue, true);2874value_.string_ = duplicateAndPrefixStringValue(2875value.data(), static_cast<unsigned>(value.length()));2876}28772878Value::Value(const StaticString& value) {2879initBasic(stringValue);2880value_.string_ = const_cast<char*>(value.c_str());2881}28822883#ifdef JSON_USE_CPPTL2884Value::Value(const CppTL::ConstString& value) {2885initBasic(stringValue, true);2886value_.string_ = duplicateAndPrefixStringValue(2887value, static_cast<unsigned>(value.length()));2888}2889#endif28902891Value::Value(bool value) {2892initBasic(booleanValue);2893value_.bool_ = value;2894}28952896Value::Value(const Value& other) {2897dupPayload(other);2898dupMeta(other);2899}29002901Value::Value(Value&& other) {2902initBasic(nullValue);2903swap(other);2904}29052906Value::~Value() {2907releasePayload();2908value_.uint_ = 0;2909}29102911Value& Value::operator=(const Value& other) {2912Value(other).swap(*this);2913return *this;2914}29152916Value& Value::operator=(Value&& other) {2917other.swap(*this);2918return *this;2919}29202921void Value::swapPayload(Value& other) {2922std::swap(bits_, other.bits_);2923std::swap(value_, other.value_);2924}29252926void Value::copyPayload(const Value& other) {2927releasePayload();2928dupPayload(other);2929}29302931void Value::swap(Value& other) {2932swapPayload(other);2933std::swap(comments_, other.comments_);2934std::swap(start_, other.start_);2935std::swap(limit_, other.limit_);2936}29372938void Value::copy(const Value& other) {2939copyPayload(other);2940dupMeta(other);2941}29422943ValueType Value::type() const {2944return static_cast<ValueType>(bits_.value_type_);2945}29462947int Value::compare(const Value& other) const {2948if (*this < other)2949return -1;2950if (*this > other)2951return 1;2952return 0;2953}29542955bool Value::operator<(const Value& other) const {2956int typeDelta = type() - other.type();2957if (typeDelta)2958return typeDelta < 0 ? true : false;2959switch (type()) {2960case nullValue:2961return false;2962case intValue:2963return value_.int_ < other.value_.int_;2964case uintValue:2965return value_.uint_ < other.value_.uint_;2966case realValue:2967return value_.real_ < other.value_.real_;2968case booleanValue:2969return value_.bool_ < other.value_.bool_;2970case stringValue: {2971if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {2972if (other.value_.string_)2973return true;2974else2975return false;2976}2977unsigned this_len;2978unsigned other_len;2979char const* this_str;2980char const* other_str;2981decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,2982&this_str);2983decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,2984&other_str);2985unsigned min_len = std::min<unsigned>(this_len, other_len);2986JSON_ASSERT(this_str && other_str);2987int comp = memcmp(this_str, other_str, min_len);2988if (comp < 0)2989return true;2990if (comp > 0)2991return false;2992return (this_len < other_len);2993}2994case arrayValue:2995case objectValue: {2996int delta = int(value_.map_->size() - other.value_.map_->size());2997if (delta)2998return delta < 0;2999return (*value_.map_) < (*other.value_.map_);3000}3001default:3002JSON_ASSERT_UNREACHABLE;3003}3004return false; // unreachable3005}30063007bool Value::operator<=(const Value& other) const { return !(other < *this); }30083009bool Value::operator>=(const Value& other) const { return !(*this < other); }30103011bool Value::operator>(const Value& other) const { return other < *this; }30123013bool Value::operator==(const Value& other) const {3014if (type() != other.type())3015return false;3016switch (type()) {3017case nullValue:3018return true;3019case intValue:3020return value_.int_ == other.value_.int_;3021case uintValue:3022return value_.uint_ == other.value_.uint_;3023case realValue:3024return value_.real_ == other.value_.real_;3025case booleanValue:3026return value_.bool_ == other.value_.bool_;3027case stringValue: {3028if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {3029return (value_.string_ == other.value_.string_);3030}3031unsigned this_len;3032unsigned other_len;3033char const* this_str;3034char const* other_str;3035decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,3036&this_str);3037decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,3038&other_str);3039if (this_len != other_len)3040return false;3041JSON_ASSERT(this_str && other_str);3042int comp = memcmp(this_str, other_str, this_len);3043return comp == 0;3044}3045case arrayValue:3046case objectValue:3047return value_.map_->size() == other.value_.map_->size() &&3048(*value_.map_) == (*other.value_.map_);3049default:3050JSON_ASSERT_UNREACHABLE;3051}3052return false; // unreachable3053}30543055bool Value::operator!=(const Value& other) const { return !(*this == other); }30563057const char* Value::asCString() const {3058JSON_ASSERT_MESSAGE(type() == stringValue,3059"in Json::Value::asCString(): requires stringValue");3060if (value_.string_ == nullptr)3061return nullptr;3062unsigned this_len;3063char const* this_str;3064decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,3065&this_str);3066return this_str;3067}30683069#if JSONCPP_USING_SECURE_MEMORY3070unsigned Value::getCStringLength() const {3071JSON_ASSERT_MESSAGE(type() == stringValue,3072"in Json::Value::asCString(): requires stringValue");3073if (value_.string_ == 0)3074return 0;3075unsigned this_len;3076char const* this_str;3077decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,3078&this_str);3079return this_len;3080}3081#endif30823083bool Value::getString(char const** begin, char const** end) const {3084if (type() != stringValue)3085return false;3086if (value_.string_ == nullptr)3087return false;3088unsigned length;3089decodePrefixedString(this->isAllocated(), this->value_.string_, &length,3090begin);3091*end = *begin + length;3092return true;3093}30943095String Value::asString() const {3096switch (type()) {3097case nullValue:3098return "";3099case stringValue: {3100if (value_.string_ == nullptr)3101return "";3102unsigned this_len;3103char const* this_str;3104decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,3105&this_str);3106return String(this_str, this_len);3107}3108case booleanValue:3109return value_.bool_ ? "true" : "false";3110case intValue:3111return valueToString(value_.int_);3112case uintValue:3113return valueToString(value_.uint_);3114case realValue:3115return valueToString(value_.real_);3116default:3117JSON_FAIL_MESSAGE("Type is not convertible to string");3118}3119}31203121#ifdef JSON_USE_CPPTL3122CppTL::ConstString Value::asConstString() const {3123unsigned len;3124char const* str;3125decodePrefixedString(isAllocated(), value_.string_, &len, &str);3126return CppTL::ConstString(str, len);3127}3128#endif31293130Value::Int Value::asInt() const {3131switch (type()) {3132case intValue:3133JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");3134return Int(value_.int_);3135case uintValue:3136JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");3137return Int(value_.uint_);3138case realValue:3139JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),3140"double out of Int range");3141return Int(value_.real_);3142case nullValue:3143return 0;3144case booleanValue:3145return value_.bool_ ? 1 : 0;3146default:3147break;3148}3149JSON_FAIL_MESSAGE("Value is not convertible to Int.");3150}31513152Value::UInt Value::asUInt() const {3153switch (type()) {3154case intValue:3155JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");3156return UInt(value_.int_);3157case uintValue:3158JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");3159return UInt(value_.uint_);3160case realValue:3161JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),3162"double out of UInt range");3163return UInt(value_.real_);3164case nullValue:3165return 0;3166case booleanValue:3167return value_.bool_ ? 1 : 0;3168default:3169break;3170}3171JSON_FAIL_MESSAGE("Value is not convertible to UInt.");3172}31733174#if defined(JSON_HAS_INT64)31753176Value::Int64 Value::asInt64() const {3177switch (type()) {3178case intValue:3179return Int64(value_.int_);3180case uintValue:3181JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");3182return Int64(value_.uint_);3183case realValue:3184JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),3185"double out of Int64 range");3186return Int64(value_.real_);3187case nullValue:3188return 0;3189case booleanValue:3190return value_.bool_ ? 1 : 0;3191default:3192break;3193}3194JSON_FAIL_MESSAGE("Value is not convertible to Int64.");3195}31963197Value::UInt64 Value::asUInt64() const {3198switch (type()) {3199case intValue:3200JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");3201return UInt64(value_.int_);3202case uintValue:3203return UInt64(value_.uint_);3204case realValue:3205JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),3206"double out of UInt64 range");3207return UInt64(value_.real_);3208case nullValue:3209return 0;3210case booleanValue:3211return value_.bool_ ? 1 : 0;3212default:3213break;3214}3215JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");3216}3217#endif // if defined(JSON_HAS_INT64)32183219LargestInt Value::asLargestInt() const {3220#if defined(JSON_NO_INT64)3221return asInt();3222#else3223return asInt64();3224#endif3225}32263227LargestUInt Value::asLargestUInt() const {3228#if defined(JSON_NO_INT64)3229return asUInt();3230#else3231return asUInt64();3232#endif3233}32343235double Value::asDouble() const {3236switch (type()) {3237case intValue:3238return static_cast<double>(value_.int_);3239case uintValue:3240#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)3241return static_cast<double>(value_.uint_);3242#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)3243return integerToDouble(value_.uint_);3244#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)3245case realValue:3246return value_.real_;3247case nullValue:3248return 0.0;3249case booleanValue:3250return value_.bool_ ? 1.0 : 0.0;3251default:3252break;3253}3254JSON_FAIL_MESSAGE("Value is not convertible to double.");3255}32563257float Value::asFloat() const {3258switch (type()) {3259case intValue:3260return static_cast<float>(value_.int_);3261case uintValue:3262#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)3263return static_cast<float>(value_.uint_);3264#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)3265// This can fail (silently?) if the value is bigger than MAX_FLOAT.3266return static_cast<float>(integerToDouble(value_.uint_));3267#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)3268case realValue:3269return static_cast<float>(value_.real_);3270case nullValue:3271return 0.0;3272case booleanValue:3273return value_.bool_ ? 1.0f : 0.0f;3274default:3275break;3276}3277JSON_FAIL_MESSAGE("Value is not convertible to float.");3278}32793280bool Value::asBool() const {3281switch (type()) {3282case booleanValue:3283return value_.bool_;3284case nullValue:3285return false;3286case intValue:3287return value_.int_ ? true : false;3288case uintValue:3289return value_.uint_ ? true : false;3290case realValue: {3291// According to JavaScript language zero or NaN is regarded as false3292const auto value_classification = std::fpclassify(value_.real_);3293return value_classification != FP_ZERO && value_classification != FP_NAN;3294}3295default:3296break;3297}3298JSON_FAIL_MESSAGE("Value is not convertible to bool.");3299}33003301bool Value::isConvertibleTo(ValueType other) const {3302switch (other) {3303case nullValue:3304return (isNumeric() && asDouble() == 0.0) ||3305(type() == booleanValue && value_.bool_ == false) ||3306(type() == stringValue && asString().empty()) ||3307(type() == arrayValue && value_.map_->empty()) ||3308(type() == objectValue && value_.map_->empty()) ||3309type() == nullValue;3310case intValue:3311return isInt() ||3312(type() == realValue && InRange(value_.real_, minInt, maxInt)) ||3313type() == booleanValue || type() == nullValue;3314case uintValue:3315return isUInt() ||3316(type() == realValue && InRange(value_.real_, 0, maxUInt)) ||3317type() == booleanValue || type() == nullValue;3318case realValue:3319return isNumeric() || type() == booleanValue || type() == nullValue;3320case booleanValue:3321return isNumeric() || type() == booleanValue || type() == nullValue;3322case stringValue:3323return isNumeric() || type() == booleanValue || type() == stringValue ||3324type() == nullValue;3325case arrayValue:3326return type() == arrayValue || type() == nullValue;3327case objectValue:3328return type() == objectValue || type() == nullValue;3329}3330JSON_ASSERT_UNREACHABLE;3331return false;3332}33333334/// Number of values in array or object3335ArrayIndex Value::size() const {3336switch (type()) {3337case nullValue:3338case intValue:3339case uintValue:3340case realValue:3341case booleanValue:3342case stringValue:3343return 0;3344case arrayValue: // size of the array is highest index + 13345if (!value_.map_->empty()) {3346ObjectValues::const_iterator itLast = value_.map_->end();3347--itLast;3348return (*itLast).first.index() + 1;3349}3350return 0;3351case objectValue:3352return ArrayIndex(value_.map_->size());3353}3354JSON_ASSERT_UNREACHABLE;3355return 0; // unreachable;3356}33573358bool Value::empty() const {3359if (isNull() || isArray() || isObject())3360return size() == 0u;3361else3362return false;3363}33643365Value::operator bool() const { return !isNull(); }33663367void Value::clear() {3368JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue ||3369type() == objectValue,3370"in Json::Value::clear(): requires complex value");3371start_ = 0;3372limit_ = 0;3373switch (type()) {3374case arrayValue:3375case objectValue:3376value_.map_->clear();3377break;3378default:3379break;3380}3381}33823383void Value::resize(ArrayIndex newSize) {3384JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,3385"in Json::Value::resize(): requires arrayValue");3386if (type() == nullValue)3387*this = Value(arrayValue);3388ArrayIndex oldSize = size();3389if (newSize == 0)3390clear();3391else if (newSize > oldSize)3392this->operator[](newSize - 1);3393else {3394for (ArrayIndex index = newSize; index < oldSize; ++index) {3395value_.map_->erase(index);3396}3397JSON_ASSERT(size() == newSize);3398}3399}34003401Value& Value::operator[](ArrayIndex index) {3402JSON_ASSERT_MESSAGE(3403type() == nullValue || type() == arrayValue,3404"in Json::Value::operator[](ArrayIndex): requires arrayValue");3405if (type() == nullValue)3406*this = Value(arrayValue);3407CZString key(index);3408auto it = value_.map_->lower_bound(key);3409if (it != value_.map_->end() && (*it).first == key)3410return (*it).second;34113412ObjectValues::value_type defaultValue(key, nullSingleton());3413it = value_.map_->insert(it, defaultValue);3414return (*it).second;3415}34163417Value& Value::operator[](int index) {3418JSON_ASSERT_MESSAGE(3419index >= 0,3420"in Json::Value::operator[](int index): index cannot be negative");3421return (*this)[ArrayIndex(index)];3422}34233424const Value& Value::operator[](ArrayIndex index) const {3425JSON_ASSERT_MESSAGE(3426type() == nullValue || type() == arrayValue,3427"in Json::Value::operator[](ArrayIndex)const: requires arrayValue");3428if (type() == nullValue)3429return nullSingleton();3430CZString key(index);3431ObjectValues::const_iterator it = value_.map_->find(key);3432if (it == value_.map_->end())3433return nullSingleton();3434return (*it).second;3435}34363437const Value& Value::operator[](int index) const {3438JSON_ASSERT_MESSAGE(3439index >= 0,3440"in Json::Value::operator[](int index) const: index cannot be negative");3441return (*this)[ArrayIndex(index)];3442}34433444void Value::initBasic(ValueType type, bool allocated) {3445setType(type);3446setIsAllocated(allocated);3447comments_ = Comments{};3448start_ = 0;3449limit_ = 0;3450}34513452void Value::dupPayload(const Value& other) {3453setType(other.type());3454setIsAllocated(false);3455switch (type()) {3456case nullValue:3457case intValue:3458case uintValue:3459case realValue:3460case booleanValue:3461value_ = other.value_;3462break;3463case stringValue:3464if (other.value_.string_ && other.isAllocated()) {3465unsigned len;3466char const* str;3467decodePrefixedString(other.isAllocated(), other.value_.string_, &len,3468&str);3469value_.string_ = duplicateAndPrefixStringValue(str, len);3470setIsAllocated(true);3471} else {3472value_.string_ = other.value_.string_;3473}3474break;3475case arrayValue:3476case objectValue:3477value_.map_ = new ObjectValues(*other.value_.map_);3478break;3479default:3480JSON_ASSERT_UNREACHABLE;3481}3482}34833484void Value::releasePayload() {3485switch (type()) {3486case nullValue:3487case intValue:3488case uintValue:3489case realValue:3490case booleanValue:3491break;3492case stringValue:3493if (isAllocated())3494releasePrefixedStringValue(value_.string_);3495break;3496case arrayValue:3497case objectValue:3498delete value_.map_;3499break;3500default:3501JSON_ASSERT_UNREACHABLE;3502}3503}35043505void Value::dupMeta(const Value& other) {3506comments_ = other.comments_;3507start_ = other.start_;3508limit_ = other.limit_;3509}35103511// Access an object value by name, create a null member if it does not exist.3512// @pre Type of '*this' is object or null.3513// @param key is null-terminated.3514Value& Value::resolveReference(const char* key) {3515JSON_ASSERT_MESSAGE(3516type() == nullValue || type() == objectValue,3517"in Json::Value::resolveReference(): requires objectValue");3518if (type() == nullValue)3519*this = Value(objectValue);3520CZString actualKey(key, static_cast<unsigned>(strlen(key)),3521CZString::noDuplication); // NOTE!3522auto it = value_.map_->lower_bound(actualKey);3523if (it != value_.map_->end() && (*it).first == actualKey)3524return (*it).second;35253526ObjectValues::value_type defaultValue(actualKey, nullSingleton());3527it = value_.map_->insert(it, defaultValue);3528Value& value = (*it).second;3529return value;3530}35313532// @param key is not null-terminated.3533Value& Value::resolveReference(char const* key, char const* end) {3534JSON_ASSERT_MESSAGE(3535type() == nullValue || type() == objectValue,3536"in Json::Value::resolveReference(key, end): requires objectValue");3537if (type() == nullValue)3538*this = Value(objectValue);3539CZString actualKey(key, static_cast<unsigned>(end - key),3540CZString::duplicateOnCopy);3541auto it = value_.map_->lower_bound(actualKey);3542if (it != value_.map_->end() && (*it).first == actualKey)3543return (*it).second;35443545ObjectValues::value_type defaultValue(actualKey, nullSingleton());3546it = value_.map_->insert(it, defaultValue);3547Value& value = (*it).second;3548return value;3549}35503551Value Value::get(ArrayIndex index, const Value& defaultValue) const {3552const Value* value = &((*this)[index]);3553return value == &nullSingleton() ? defaultValue : *value;3554}35553556bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }35573558Value const* Value::find(char const* begin, char const* end) const {3559JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,3560"in Json::Value::find(begin, end): requires "3561"objectValue or nullValue");3562if (type() == nullValue)3563return nullptr;3564CZString actualKey(begin, static_cast<unsigned>(end - begin),3565CZString::noDuplication);3566ObjectValues::const_iterator it = value_.map_->find(actualKey);3567if (it == value_.map_->end())3568return nullptr;3569return &(*it).second;3570}3571Value* Value::demand(char const* begin, char const* end) {3572JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,3573"in Json::Value::demand(begin, end): requires "3574"objectValue or nullValue");3575return &resolveReference(begin, end);3576}3577const Value& Value::operator[](const char* key) const {3578Value const* found = find(key, key + strlen(key));3579if (!found)3580return nullSingleton();3581return *found;3582}3583Value const& Value::operator[](const String& key) const {3584Value const* found = find(key.data(), key.data() + key.length());3585if (!found)3586return nullSingleton();3587return *found;3588}35893590Value& Value::operator[](const char* key) {3591return resolveReference(key, key + strlen(key));3592}35933594Value& Value::operator[](const String& key) {3595return resolveReference(key.data(), key.data() + key.length());3596}35973598Value& Value::operator[](const StaticString& key) {3599return resolveReference(key.c_str());3600}36013602#ifdef JSON_USE_CPPTL3603Value& Value::operator[](const CppTL::ConstString& key) {3604return resolveReference(key.c_str(), key.end_c_str());3605}3606Value const& Value::operator[](CppTL::ConstString const& key) const {3607Value const* found = find(key.c_str(), key.end_c_str());3608if (!found)3609return nullSingleton();3610return *found;3611}3612#endif36133614Value& Value::append(const Value& value) { return (*this)[size()] = value; }36153616Value& Value::append(Value&& value) {3617return (*this)[size()] = std::move(value);3618}36193620Value Value::get(char const* begin,3621char const* end,3622Value const& defaultValue) const {3623Value const* found = find(begin, end);3624return !found ? defaultValue : *found;3625}3626Value Value::get(char const* key, Value const& defaultValue) const {3627return get(key, key + strlen(key), defaultValue);3628}3629Value Value::get(String const& key, Value const& defaultValue) const {3630return get(key.data(), key.data() + key.length(), defaultValue);3631}36323633bool Value::removeMember(const char* begin, const char* end, Value* removed) {3634if (type() != objectValue) {3635return false;3636}3637CZString actualKey(begin, static_cast<unsigned>(end - begin),3638CZString::noDuplication);3639auto it = value_.map_->find(actualKey);3640if (it == value_.map_->end())3641return false;3642if (removed)3643*removed = std::move(it->second);3644value_.map_->erase(it);3645return true;3646}3647bool Value::removeMember(const char* key, Value* removed) {3648return removeMember(key, key + strlen(key), removed);3649}3650bool Value::removeMember(String const& key, Value* removed) {3651return removeMember(key.data(), key.data() + key.length(), removed);3652}3653void Value::removeMember(const char* key) {3654JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,3655"in Json::Value::removeMember(): requires objectValue");3656if (type() == nullValue)3657return;36583659CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication);3660value_.map_->erase(actualKey);3661}3662void Value::removeMember(const String& key) { removeMember(key.c_str()); }36633664bool Value::removeIndex(ArrayIndex index, Value* removed) {3665if (type() != arrayValue) {3666return false;3667}3668CZString key(index);3669auto it = value_.map_->find(key);3670if (it == value_.map_->end()) {3671return false;3672}3673if (removed)3674*removed = it->second;3675ArrayIndex oldSize = size();3676// shift left all items left, into the place of the "removed"3677for (ArrayIndex i = index; i < (oldSize - 1); ++i) {3678CZString keey(i);3679(*value_.map_)[keey] = (*this)[i + 1];3680}3681// erase the last one ("leftover")3682CZString keyLast(oldSize - 1);3683auto itLast = value_.map_->find(keyLast);3684value_.map_->erase(itLast);3685return true;3686}36873688#ifdef JSON_USE_CPPTL3689Value Value::get(const CppTL::ConstString& key,3690const Value& defaultValue) const {3691return get(key.c_str(), key.end_c_str(), defaultValue);3692}3693#endif36943695bool Value::isMember(char const* begin, char const* end) const {3696Value const* value = find(begin, end);3697return nullptr != value;3698}3699bool Value::isMember(char const* key) const {3700return isMember(key, key + strlen(key));3701}3702bool Value::isMember(String const& key) const {3703return isMember(key.data(), key.data() + key.length());3704}37053706#ifdef JSON_USE_CPPTL3707bool Value::isMember(const CppTL::ConstString& key) const {3708return isMember(key.c_str(), key.end_c_str());3709}3710#endif37113712Value::Members Value::getMemberNames() const {3713JSON_ASSERT_MESSAGE(3714type() == nullValue || type() == objectValue,3715"in Json::Value::getMemberNames(), value must be objectValue");3716if (type() == nullValue)3717return Value::Members();3718Members members;3719members.reserve(value_.map_->size());3720ObjectValues::const_iterator it = value_.map_->begin();3721ObjectValues::const_iterator itEnd = value_.map_->end();3722for (; it != itEnd; ++it) {3723members.push_back(String((*it).first.data(), (*it).first.length()));3724}3725return members;3726}3727//3728//# ifdef JSON_USE_CPPTL3729// EnumMemberNames3730// Value::enumMemberNames() const3731//{3732// if ( type() == objectValue )3733// {3734// return CppTL::Enum::any( CppTL::Enum::transform(3735// CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),3736// MemberNamesTransform() ) );3737// }3738// return EnumMemberNames();3739//}3740//3741//3742// EnumValues3743// Value::enumValues() const3744//{3745// if ( type() == objectValue || type() == arrayValue )3746// return CppTL::Enum::anyValues( *(value_.map_),3747// CppTL::Type<const Value &>() );3748// return EnumValues();3749//}3750//3751//# endif37523753static bool IsIntegral(double d) {3754double integral_part;3755return modf(d, &integral_part) == 0.0;3756}37573758bool Value::isNull() const { return type() == nullValue; }37593760bool Value::isBool() const { return type() == booleanValue; }37613762bool Value::isInt() const {3763switch (type()) {3764case intValue:3765#if defined(JSON_HAS_INT64)3766return value_.int_ >= minInt && value_.int_ <= maxInt;3767#else3768return true;3769#endif3770case uintValue:3771return value_.uint_ <= UInt(maxInt);3772case realValue:3773return value_.real_ >= minInt && value_.real_ <= maxInt &&3774IsIntegral(value_.real_);3775default:3776break;3777}3778return false;3779}37803781bool Value::isUInt() const {3782switch (type()) {3783case intValue:3784#if defined(JSON_HAS_INT64)3785return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);3786#else3787return value_.int_ >= 0;3788#endif3789case uintValue:3790#if defined(JSON_HAS_INT64)3791return value_.uint_ <= maxUInt;3792#else3793return true;3794#endif3795case realValue:3796return value_.real_ >= 0 && value_.real_ <= maxUInt &&3797IsIntegral(value_.real_);3798default:3799break;3800}3801return false;3802}38033804bool Value::isInt64() const {3805#if defined(JSON_HAS_INT64)3806switch (type()) {3807case intValue:3808return true;3809case uintValue:3810return value_.uint_ <= UInt64(maxInt64);3811case realValue:3812// Note that maxInt64 (= 2^63 - 1) is not exactly representable as a3813// double, so double(maxInt64) will be rounded up to 2^63. Therefore we3814// require the value to be strictly less than the limit.3815return value_.real_ >= double(minInt64) &&3816value_.real_ < double(maxInt64) && IsIntegral(value_.real_);3817default:3818break;3819}3820#endif // JSON_HAS_INT643821return false;3822}38233824bool Value::isUInt64() const {3825#if defined(JSON_HAS_INT64)3826switch (type()) {3827case intValue:3828return value_.int_ >= 0;3829case uintValue:3830return true;3831case realValue:3832// Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a3833// double, so double(maxUInt64) will be rounded up to 2^64. Therefore we3834// require the value to be strictly less than the limit.3835return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&3836IsIntegral(value_.real_);3837default:3838break;3839}3840#endif // JSON_HAS_INT643841return false;3842}38433844bool Value::isIntegral() const {3845switch (type()) {3846case intValue:3847case uintValue:3848return true;3849case realValue:3850#if defined(JSON_HAS_INT64)3851// Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a3852// double, so double(maxUInt64) will be rounded up to 2^64. Therefore we3853// require the value to be strictly less than the limit.3854return value_.real_ >= double(minInt64) &&3855value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);3856#else3857return value_.real_ >= minInt && value_.real_ <= maxUInt &&3858IsIntegral(value_.real_);3859#endif // JSON_HAS_INT643860default:3861break;3862}3863return false;3864}38653866bool Value::isDouble() const {3867return type() == intValue || type() == uintValue || type() == realValue;3868}38693870bool Value::isNumeric() const { return isDouble(); }38713872bool Value::isString() const { return type() == stringValue; }38733874bool Value::isArray() const { return type() == arrayValue; }38753876bool Value::isObject() const { return type() == objectValue; }38773878Value::Comments::Comments(const Comments& that)3879: ptr_{cloneUnique(that.ptr_)} {}38803881Value::Comments::Comments(Comments&& that) : ptr_{std::move(that.ptr_)} {}38823883Value::Comments& Value::Comments::operator=(const Comments& that) {3884ptr_ = cloneUnique(that.ptr_);3885return *this;3886}38873888Value::Comments& Value::Comments::operator=(Comments&& that) {3889ptr_ = std::move(that.ptr_);3890return *this;3891}38923893bool Value::Comments::has(CommentPlacement slot) const {3894return ptr_ && !(*ptr_)[slot].empty();3895}38963897String Value::Comments::get(CommentPlacement slot) const {3898if (!ptr_)3899return {};3900return (*ptr_)[slot];3901}39023903void Value::Comments::set(CommentPlacement slot, String comment) {3904if (!ptr_) {3905ptr_ = std::unique_ptr<Array>(new Array());3906}3907(*ptr_)[slot] = std::move(comment);3908}39093910void Value::setComment(String comment, CommentPlacement placement) {3911if (!comment.empty() && (comment.back() == '\n')) {3912// Always discard trailing newline, to aid indentation.3913comment.pop_back();3914}3915JSON_ASSERT(!comment.empty());3916JSON_ASSERT_MESSAGE(3917comment[0] == '\0' || comment[0] == '/',3918"in Json::Value::setComment(): Comments must start with /");3919comments_.set(placement, std::move(comment));3920}39213922bool Value::hasComment(CommentPlacement placement) const {3923return comments_.has(placement);3924}39253926String Value::getComment(CommentPlacement placement) const {3927return comments_.get(placement);3928}39293930void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }39313932void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; }39333934ptrdiff_t Value::getOffsetStart() const { return start_; }39353936ptrdiff_t Value::getOffsetLimit() const { return limit_; }39373938String Value::toStyledString() const {3939StreamWriterBuilder builder;39403941String out = this->hasComment(commentBefore) ? "\n" : "";3942out += Json::writeString(builder, *this);3943out += '\n';39443945return out;3946}39473948Value::const_iterator Value::begin() const {3949switch (type()) {3950case arrayValue:3951case objectValue:3952if (value_.map_)3953return const_iterator(value_.map_->begin());3954break;3955default:3956break;3957}3958return {};3959}39603961Value::const_iterator Value::end() const {3962switch (type()) {3963case arrayValue:3964case objectValue:3965if (value_.map_)3966return const_iterator(value_.map_->end());3967break;3968default:3969break;3970}3971return {};3972}39733974Value::iterator Value::begin() {3975switch (type()) {3976case arrayValue:3977case objectValue:3978if (value_.map_)3979return iterator(value_.map_->begin());3980break;3981default:3982break;3983}3984return iterator();3985}39863987Value::iterator Value::end() {3988switch (type()) {3989case arrayValue:3990case objectValue:3991if (value_.map_)3992return iterator(value_.map_->end());3993break;3994default:3995break;3996}3997return iterator();3998}39994000// class PathArgument4001// //////////////////////////////////////////////////////////////////40024003PathArgument::PathArgument() : key_() {}40044005PathArgument::PathArgument(ArrayIndex index)4006: key_(), index_(index), kind_(kindIndex) {}40074008PathArgument::PathArgument(const char* key)4009: key_(key), index_(), kind_(kindKey) {}40104011PathArgument::PathArgument(const String& key)4012: key_(key.c_str()), index_(), kind_(kindKey) {}40134014// class Path4015// //////////////////////////////////////////////////////////////////40164017Path::Path(const String& path,4018const PathArgument& a1,4019const PathArgument& a2,4020const PathArgument& a3,4021const PathArgument& a4,4022const PathArgument& a5) {4023InArgs in;4024in.reserve(5);4025in.push_back(&a1);4026in.push_back(&a2);4027in.push_back(&a3);4028in.push_back(&a4);4029in.push_back(&a5);4030makePath(path, in);4031}40324033void Path::makePath(const String& path, const InArgs& in) {4034const char* current = path.c_str();4035const char* end = current + path.length();4036auto itInArg = in.begin();4037while (current != end) {4038if (*current == '[') {4039++current;4040if (*current == '%')4041addPathInArg(path, in, itInArg, PathArgument::kindIndex);4042else {4043ArrayIndex index = 0;4044for (; current != end && *current >= '0' && *current <= '9'; ++current)4045index = index * 10 + ArrayIndex(*current - '0');4046args_.push_back(index);4047}4048if (current == end || *++current != ']')4049invalidPath(path, int(current - path.c_str()));4050} else if (*current == '%') {4051addPathInArg(path, in, itInArg, PathArgument::kindKey);4052++current;4053} else if (*current == '.' || *current == ']') {4054++current;4055} else {4056const char* beginName = current;4057while (current != end && !strchr("[.", *current))4058++current;4059args_.push_back(String(beginName, current));4060}4061}4062}40634064void Path::addPathInArg(const String& /*path*/,4065const InArgs& in,4066InArgs::const_iterator& itInArg,4067PathArgument::Kind kind) {4068if (itInArg == in.end()) {4069// Error: missing argument %d4070} else if ((*itInArg)->kind_ != kind) {4071// Error: bad argument type4072} else {4073args_.push_back(**itInArg++);4074}4075}40764077void Path::invalidPath(const String& /*path*/, int /*location*/) {4078// Error: invalid path.4079}40804081const Value& Path::resolve(const Value& root) const {4082const Value* node = &root;4083for (const auto& arg : args_) {4084if (arg.kind_ == PathArgument::kindIndex) {4085if (!node->isArray() || !node->isValidIndex(arg.index_)) {4086// Error: unable to resolve path (array value expected at position... )4087return Value::nullSingleton();4088}4089node = &((*node)[arg.index_]);4090} else if (arg.kind_ == PathArgument::kindKey) {4091if (!node->isObject()) {4092// Error: unable to resolve path (object value expected at position...)4093return Value::nullSingleton();4094}4095node = &((*node)[arg.key_]);4096if (node == &Value::nullSingleton()) {4097// Error: unable to resolve path (object has no member named '' at4098// position...)4099return Value::nullSingleton();4100}4101}4102}4103return *node;4104}41054106Value Path::resolve(const Value& root, const Value& defaultValue) const {4107const Value* node = &root;4108for (const auto& arg : args_) {4109if (arg.kind_ == PathArgument::kindIndex) {4110if (!node->isArray() || !node->isValidIndex(arg.index_))4111return defaultValue;4112node = &((*node)[arg.index_]);4113} else if (arg.kind_ == PathArgument::kindKey) {4114if (!node->isObject())4115return defaultValue;4116node = &((*node)[arg.key_]);4117if (node == &Value::nullSingleton())4118return defaultValue;4119}4120}4121return *node;4122}41234124Value& Path::make(Value& root) const {4125Value* node = &root;4126for (const auto& arg : args_) {4127if (arg.kind_ == PathArgument::kindIndex) {4128if (!node->isArray()) {4129// Error: node is not an array at position ...4130}4131node = &((*node)[arg.index_]);4132} else if (arg.kind_ == PathArgument::kindKey) {4133if (!node->isObject()) {4134// Error: node is not an object at position...4135}4136node = &((*node)[arg.key_]);4137}4138}4139return *node;4140}41414142} // namespace Json41434144// //////////////////////////////////////////////////////////////////////4145// End of content of file: src/lib_json/json_value.cpp4146// //////////////////////////////////////////////////////////////////////4147414841494150415141524153// //////////////////////////////////////////////////////////////////////4154// Beginning of content of file: src/lib_json/json_writer.cpp4155// //////////////////////////////////////////////////////////////////////41564157// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors4158// Distributed under MIT license, or public domain if desired and4159// recognized in your jurisdiction.4160// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE41614162#if !defined(JSON_IS_AMALGAMATION)4163#include "json_tool.h"4164#include <json/writer.h>4165#endif // if !defined(JSON_IS_AMALGAMATION)4166#include <cassert>4167#include <cstring>4168#include <iomanip>4169#include <memory>4170#include <set>4171#include <sstream>4172#include <utility>41734174#if __cplusplus >= 201103L4175#include <cmath>4176#include <cstdio>41774178#if !defined(isnan)4179#define isnan std::isnan4180#endif41814182#if !defined(isfinite)4183#define isfinite std::isfinite4184#endif41854186#else4187#include <cmath>4188#include <cstdio>41894190#if defined(_MSC_VER)4191#if !defined(isnan)4192#include <float.h>4193#define isnan _isnan4194#endif41954196#if !defined(isfinite)4197#include <float.h>4198#define isfinite _finite4199#endif42004201#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)4202#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 14203#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES42044205#endif //_MSC_VER42064207#if defined(__sun) && defined(__SVR4) // Solaris4208#if !defined(isfinite)4209#include <ieeefp.h>4210#define isfinite finite4211#endif4212#endif42134214#if defined(__hpux)4215#if !defined(isfinite)4216#if defined(__ia64) && !defined(finite)4217#define isfinite(x) \4218((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x)))4219#endif4220#endif4221#endif42224223#if !defined(isnan)4224// IEEE standard states that NaN values will not compare to themselves4225#define isnan(x) (x != x)4226#endif42274228#if !defined(__APPLE__)4229#if !defined(isfinite)4230#define isfinite finite4231#endif4232#endif4233#endif42344235#if defined(_MSC_VER)4236// Disable warning about strdup being deprecated.4237#pragma warning(disable : 4996)4238#endif42394240namespace Json {42414242#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)4243typedef std::unique_ptr<StreamWriter> StreamWriterPtr;4244#else4245typedef std::auto_ptr<StreamWriter> StreamWriterPtr;4246#endif42474248String valueToString(LargestInt value) {4249UIntToStringBuffer buffer;4250char* current = buffer + sizeof(buffer);4251if (value == Value::minLargestInt) {4252uintToString(LargestUInt(Value::maxLargestInt) + 1, current);4253*--current = '-';4254} else if (value < 0) {4255uintToString(LargestUInt(-value), current);4256*--current = '-';4257} else {4258uintToString(LargestUInt(value), current);4259}4260assert(current >= buffer);4261return current;4262}42634264String valueToString(LargestUInt value) {4265UIntToStringBuffer buffer;4266char* current = buffer + sizeof(buffer);4267uintToString(value, current);4268assert(current >= buffer);4269return current;4270}42714272#if defined(JSON_HAS_INT64)42734274String valueToString(Int value) { return valueToString(LargestInt(value)); }42754276String valueToString(UInt value) { return valueToString(LargestUInt(value)); }42774278#endif // # if defined(JSON_HAS_INT64)42794280namespace {4281String valueToString(double value,4282bool useSpecialFloats,4283unsigned int precision,4284PrecisionType precisionType) {4285// Print into the buffer. We need not request the alternative representation4286// that always has a decimal point because JSON doesn't distinguish the4287// concepts of reals and integers.4288if (!isfinite(value)) {4289static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"},4290{"null", "-1e+9999", "1e+9999"}};4291return reps[useSpecialFloats ? 0 : 1]4292[isnan(value) ? 0 : (value < 0) ? 1 : 2];4293}42944295String buffer(size_t(36), '\0');4296while (true) {4297int len = jsoncpp_snprintf(4298&*buffer.begin(), buffer.size(),4299(precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f",4300precision, value);4301assert(len >= 0);4302auto wouldPrint = static_cast<size_t>(len);4303if (wouldPrint >= buffer.size()) {4304buffer.resize(wouldPrint + 1);4305continue;4306}4307buffer.resize(wouldPrint);4308break;4309}43104311buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end());43124313// strip the zero padding from the right4314if (precisionType == PrecisionType::decimalPlaces) {4315buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end());4316}43174318// try to ensure we preserve the fact that this was given to us as a double on4319// input4320if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) {4321buffer += ".0";4322}4323return buffer;4324}4325} // namespace43264327String valueToString(double value,4328unsigned int precision,4329PrecisionType precisionType) {4330return valueToString(value, false, precision, precisionType);4331}43324333String valueToString(bool value) { return value ? "true" : "false"; }43344335static bool isAnyCharRequiredQuoting(char const* s, size_t n) {4336assert(s || !n);43374338char const* const end = s + n;4339for (char const* cur = s; cur < end; ++cur) {4340if (*cur == '\\' || *cur == '\"' || *cur < ' ' ||4341static_cast<unsigned char>(*cur) < 0x80)4342return true;4343}4344return false;4345}43464347static unsigned int utf8ToCodepoint(const char*& s, const char* e) {4348const unsigned int REPLACEMENT_CHARACTER = 0xFFFD;43494350unsigned int firstByte = static_cast<unsigned char>(*s);43514352if (firstByte < 0x80)4353return firstByte;43544355if (firstByte < 0xE0) {4356if (e - s < 2)4357return REPLACEMENT_CHARACTER;43584359unsigned int calculated =4360((firstByte & 0x1F) << 6) | (static_cast<unsigned int>(s[1]) & 0x3F);4361s += 1;4362// oversized encoded characters are invalid4363return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated;4364}43654366if (firstByte < 0xF0) {4367if (e - s < 3)4368return REPLACEMENT_CHARACTER;43694370unsigned int calculated = ((firstByte & 0x0F) << 12) |4371((static_cast<unsigned int>(s[1]) & 0x3F) << 6) |4372(static_cast<unsigned int>(s[2]) & 0x3F);4373s += 2;4374// surrogates aren't valid codepoints itself4375// shouldn't be UTF-8 encoded4376if (calculated >= 0xD800 && calculated <= 0xDFFF)4377return REPLACEMENT_CHARACTER;4378// oversized encoded characters are invalid4379return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated;4380}43814382if (firstByte < 0xF8) {4383if (e - s < 4)4384return REPLACEMENT_CHARACTER;43854386unsigned int calculated = ((firstByte & 0x07) << 18) |4387((static_cast<unsigned int>(s[1]) & 0x3F) << 12) |4388((static_cast<unsigned int>(s[2]) & 0x3F) << 6) |4389(static_cast<unsigned int>(s[3]) & 0x3F);4390s += 3;4391// oversized encoded characters are invalid4392return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated;4393}43944395return REPLACEMENT_CHARACTER;4396}43974398static const char hex2[] = "000102030405060708090a0b0c0d0e0f"4399"101112131415161718191a1b1c1d1e1f"4400"202122232425262728292a2b2c2d2e2f"4401"303132333435363738393a3b3c3d3e3f"4402"404142434445464748494a4b4c4d4e4f"4403"505152535455565758595a5b5c5d5e5f"4404"606162636465666768696a6b6c6d6e6f"4405"707172737475767778797a7b7c7d7e7f"4406"808182838485868788898a8b8c8d8e8f"4407"909192939495969798999a9b9c9d9e9f"4408"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"4409"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"4410"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"4411"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"4412"e0e1e2e3e4e5e6e7e8e9eaebecedeeef"4413"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";44144415static String toHex16Bit(unsigned int x) {4416const unsigned int hi = (x >> 8) & 0xff;4417const unsigned int lo = x & 0xff;4418String result(4, ' ');4419result[0] = hex2[2 * hi];4420result[1] = hex2[2 * hi + 1];4421result[2] = hex2[2 * lo];4422result[3] = hex2[2 * lo + 1];4423return result;4424}44254426static String valueToQuotedStringN(const char* value, unsigned length) {4427if (value == nullptr)4428return "";44294430if (!isAnyCharRequiredQuoting(value, length))4431return String("\"") + value + "\"";4432// We have to walk value and escape any special characters.4433// Appending to String is not efficient, but this should be rare.4434// (Note: forward slashes are *not* rare, but I am not escaping them.)4435String::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL4436String result;4437result.reserve(maxsize); // to avoid lots of mallocs4438result += "\"";4439char const* end = value + length;4440for (const char* c = value; c != end; ++c) {4441switch (*c) {4442case '\"':4443result += "\\\"";4444break;4445case '\\':4446result += "\\\\";4447break;4448case '\b':4449result += "\\b";4450break;4451case '\f':4452result += "\\f";4453break;4454case '\n':4455result += "\\n";4456break;4457case '\r':4458result += "\\r";4459break;4460case '\t':4461result += "\\t";4462break;4463// case '/':4464// Even though \/ is considered a legal escape in JSON, a bare4465// slash is also legal, so I see no reason to escape it.4466// (I hope I am not misunderstanding something.)4467// blep notes: actually escaping \/ may be useful in javascript to avoid </4468// sequence.4469// Should add a flag to allow this compatibility mode and prevent this4470// sequence from occurring.4471default: {4472unsigned int cp = utf8ToCodepoint(c, end);4473// don't escape non-control characters4474// (short escape sequence are applied above)4475if (cp < 0x80 && cp >= 0x20)4476result += static_cast<char>(cp);4477else if (cp < 0x10000) { // codepoint is in Basic Multilingual Plane4478result += "\\u";4479result += toHex16Bit(cp);4480} else { // codepoint is not in Basic Multilingual Plane4481// convert to surrogate pair first4482cp -= 0x10000;4483result += "\\u";4484result += toHex16Bit((cp >> 10) + 0xD800);4485result += "\\u";4486result += toHex16Bit((cp & 0x3FF) + 0xDC00);4487}4488} break;4489}4490}4491result += "\"";4492return result;4493}44944495String valueToQuotedString(const char* value) {4496return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));4497}44984499// Class Writer4500// //////////////////////////////////////////////////////////////////4501Writer::~Writer() = default;45024503// Class FastWriter4504// //////////////////////////////////////////////////////////////////45054506FastWriter::FastWriter()45074508= default;45094510void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; }45114512void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }45134514void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }45154516String FastWriter::write(const Value& root) {4517document_.clear();4518writeValue(root);4519if (!omitEndingLineFeed_)4520document_ += '\n';4521return document_;4522}45234524void FastWriter::writeValue(const Value& value) {4525switch (value.type()) {4526case nullValue:4527if (!dropNullPlaceholders_)4528document_ += "null";4529break;4530case intValue:4531document_ += valueToString(value.asLargestInt());4532break;4533case uintValue:4534document_ += valueToString(value.asLargestUInt());4535break;4536case realValue:4537document_ += valueToString(value.asDouble());4538break;4539case stringValue: {4540// Is NULL possible for value.string_? No.4541char const* str;4542char const* end;4543bool ok = value.getString(&str, &end);4544if (ok)4545document_ += valueToQuotedStringN(str, static_cast<unsigned>(end - str));4546break;4547}4548case booleanValue:4549document_ += valueToString(value.asBool());4550break;4551case arrayValue: {4552document_ += '[';4553ArrayIndex size = value.size();4554for (ArrayIndex index = 0; index < size; ++index) {4555if (index > 0)4556document_ += ',';4557writeValue(value[index]);4558}4559document_ += ']';4560} break;4561case objectValue: {4562Value::Members members(value.getMemberNames());4563document_ += '{';4564for (auto it = members.begin(); it != members.end(); ++it) {4565const String& name = *it;4566if (it != members.begin())4567document_ += ',';4568document_ += valueToQuotedStringN(name.data(),4569static_cast<unsigned>(name.length()));4570document_ += yamlCompatibilityEnabled_ ? ": " : ":";4571writeValue(value[name]);4572}4573document_ += '}';4574} break;4575}4576}45774578// Class StyledWriter4579// //////////////////////////////////////////////////////////////////45804581StyledWriter::StyledWriter() = default;45824583String StyledWriter::write(const Value& root) {4584document_.clear();4585addChildValues_ = false;4586indentString_.clear();4587writeCommentBeforeValue(root);4588writeValue(root);4589writeCommentAfterValueOnSameLine(root);4590document_ += '\n';4591return document_;4592}45934594void StyledWriter::writeValue(const Value& value) {4595switch (value.type()) {4596case nullValue:4597pushValue("null");4598break;4599case intValue:4600pushValue(valueToString(value.asLargestInt()));4601break;4602case uintValue:4603pushValue(valueToString(value.asLargestUInt()));4604break;4605case realValue:4606pushValue(valueToString(value.asDouble()));4607break;4608case stringValue: {4609// Is NULL possible for value.string_? No.4610char const* str;4611char const* end;4612bool ok = value.getString(&str, &end);4613if (ok)4614pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));4615else4616pushValue("");4617break;4618}4619case booleanValue:4620pushValue(valueToString(value.asBool()));4621break;4622case arrayValue:4623writeArrayValue(value);4624break;4625case objectValue: {4626Value::Members members(value.getMemberNames());4627if (members.empty())4628pushValue("{}");4629else {4630writeWithIndent("{");4631indent();4632auto it = members.begin();4633for (;;) {4634const String& name = *it;4635const Value& childValue = value[name];4636writeCommentBeforeValue(childValue);4637writeWithIndent(valueToQuotedString(name.c_str()));4638document_ += " : ";4639writeValue(childValue);4640if (++it == members.end()) {4641writeCommentAfterValueOnSameLine(childValue);4642break;4643}4644document_ += ',';4645writeCommentAfterValueOnSameLine(childValue);4646}4647unindent();4648writeWithIndent("}");4649}4650} break;4651}4652}46534654void StyledWriter::writeArrayValue(const Value& value) {4655unsigned size = value.size();4656if (size == 0)4657pushValue("[]");4658else {4659bool isArrayMultiLine = isMultilineArray(value);4660if (isArrayMultiLine) {4661writeWithIndent("[");4662indent();4663bool hasChildValue = !childValues_.empty();4664unsigned index = 0;4665for (;;) {4666const Value& childValue = value[index];4667writeCommentBeforeValue(childValue);4668if (hasChildValue)4669writeWithIndent(childValues_[index]);4670else {4671writeIndent();4672writeValue(childValue);4673}4674if (++index == size) {4675writeCommentAfterValueOnSameLine(childValue);4676break;4677}4678document_ += ',';4679writeCommentAfterValueOnSameLine(childValue);4680}4681unindent();4682writeWithIndent("]");4683} else // output on a single line4684{4685assert(childValues_.size() == size);4686document_ += "[ ";4687for (unsigned index = 0; index < size; ++index) {4688if (index > 0)4689document_ += ", ";4690document_ += childValues_[index];4691}4692document_ += " ]";4693}4694}4695}46964697bool StyledWriter::isMultilineArray(const Value& value) {4698ArrayIndex const size = value.size();4699bool isMultiLine = size * 3 >= rightMargin_;4700childValues_.clear();4701for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {4702const Value& childValue = value[index];4703isMultiLine = ((childValue.isArray() || childValue.isObject()) &&4704!childValue.empty());4705}4706if (!isMultiLine) // check if line length > max line length4707{4708childValues_.reserve(size);4709addChildValues_ = true;4710ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'4711for (ArrayIndex index = 0; index < size; ++index) {4712if (hasCommentForValue(value[index])) {4713isMultiLine = true;4714}4715writeValue(value[index]);4716lineLength += static_cast<ArrayIndex>(childValues_[index].length());4717}4718addChildValues_ = false;4719isMultiLine = isMultiLine || lineLength >= rightMargin_;4720}4721return isMultiLine;4722}47234724void StyledWriter::pushValue(const String& value) {4725if (addChildValues_)4726childValues_.push_back(value);4727else4728document_ += value;4729}47304731void StyledWriter::writeIndent() {4732if (!document_.empty()) {4733char last = document_[document_.length() - 1];4734if (last == ' ') // already indented4735return;4736if (last != '\n') // Comments may add new-line4737document_ += '\n';4738}4739document_ += indentString_;4740}47414742void StyledWriter::writeWithIndent(const String& value) {4743writeIndent();4744document_ += value;4745}47464747void StyledWriter::indent() { indentString_ += String(indentSize_, ' '); }47484749void StyledWriter::unindent() {4750assert(indentString_.size() >= indentSize_);4751indentString_.resize(indentString_.size() - indentSize_);4752}47534754void StyledWriter::writeCommentBeforeValue(const Value& root) {4755if (!root.hasComment(commentBefore))4756return;47574758document_ += '\n';4759writeIndent();4760const String& comment = root.getComment(commentBefore);4761String::const_iterator iter = comment.begin();4762while (iter != comment.end()) {4763document_ += *iter;4764if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))4765writeIndent();4766++iter;4767}47684769// Comments are stripped of trailing newlines, so add one here4770document_ += '\n';4771}47724773void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {4774if (root.hasComment(commentAfterOnSameLine))4775document_ += " " + root.getComment(commentAfterOnSameLine);47764777if (root.hasComment(commentAfter)) {4778document_ += '\n';4779document_ += root.getComment(commentAfter);4780document_ += '\n';4781}4782}47834784bool StyledWriter::hasCommentForValue(const Value& value) {4785return value.hasComment(commentBefore) ||4786value.hasComment(commentAfterOnSameLine) ||4787value.hasComment(commentAfter);4788}47894790// Class StyledStreamWriter4791// //////////////////////////////////////////////////////////////////47924793StyledStreamWriter::StyledStreamWriter(String indentation)4794: document_(nullptr), indentation_(std::move(indentation)),4795addChildValues_(), indented_(false) {}47964797void StyledStreamWriter::write(OStream& out, const Value& root) {4798document_ = &out;4799addChildValues_ = false;4800indentString_.clear();4801indented_ = true;4802writeCommentBeforeValue(root);4803if (!indented_)4804writeIndent();4805indented_ = true;4806writeValue(root);4807writeCommentAfterValueOnSameLine(root);4808*document_ << "\n";4809document_ = nullptr; // Forget the stream, for safety.4810}48114812void StyledStreamWriter::writeValue(const Value& value) {4813switch (value.type()) {4814case nullValue:4815pushValue("null");4816break;4817case intValue:4818pushValue(valueToString(value.asLargestInt()));4819break;4820case uintValue:4821pushValue(valueToString(value.asLargestUInt()));4822break;4823case realValue:4824pushValue(valueToString(value.asDouble()));4825break;4826case stringValue: {4827// Is NULL possible for value.string_? No.4828char const* str;4829char const* end;4830bool ok = value.getString(&str, &end);4831if (ok)4832pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));4833else4834pushValue("");4835break;4836}4837case booleanValue:4838pushValue(valueToString(value.asBool()));4839break;4840case arrayValue:4841writeArrayValue(value);4842break;4843case objectValue: {4844Value::Members members(value.getMemberNames());4845if (members.empty())4846pushValue("{}");4847else {4848writeWithIndent("{");4849indent();4850auto it = members.begin();4851for (;;) {4852const String& name = *it;4853const Value& childValue = value[name];4854writeCommentBeforeValue(childValue);4855writeWithIndent(valueToQuotedString(name.c_str()));4856*document_ << " : ";4857writeValue(childValue);4858if (++it == members.end()) {4859writeCommentAfterValueOnSameLine(childValue);4860break;4861}4862*document_ << ",";4863writeCommentAfterValueOnSameLine(childValue);4864}4865unindent();4866writeWithIndent("}");4867}4868} break;4869}4870}48714872void StyledStreamWriter::writeArrayValue(const Value& value) {4873unsigned size = value.size();4874if (size == 0)4875pushValue("[]");4876else {4877bool isArrayMultiLine = isMultilineArray(value);4878if (isArrayMultiLine) {4879writeWithIndent("[");4880indent();4881bool hasChildValue = !childValues_.empty();4882unsigned index = 0;4883for (;;) {4884const Value& childValue = value[index];4885writeCommentBeforeValue(childValue);4886if (hasChildValue)4887writeWithIndent(childValues_[index]);4888else {4889if (!indented_)4890writeIndent();4891indented_ = true;4892writeValue(childValue);4893indented_ = false;4894}4895if (++index == size) {4896writeCommentAfterValueOnSameLine(childValue);4897break;4898}4899*document_ << ",";4900writeCommentAfterValueOnSameLine(childValue);4901}4902unindent();4903writeWithIndent("]");4904} else // output on a single line4905{4906assert(childValues_.size() == size);4907*document_ << "[ ";4908for (unsigned index = 0; index < size; ++index) {4909if (index > 0)4910*document_ << ", ";4911*document_ << childValues_[index];4912}4913*document_ << " ]";4914}4915}4916}49174918bool StyledStreamWriter::isMultilineArray(const Value& value) {4919ArrayIndex const size = value.size();4920bool isMultiLine = size * 3 >= rightMargin_;4921childValues_.clear();4922for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {4923const Value& childValue = value[index];4924isMultiLine = ((childValue.isArray() || childValue.isObject()) &&4925!childValue.empty());4926}4927if (!isMultiLine) // check if line length > max line length4928{4929childValues_.reserve(size);4930addChildValues_ = true;4931ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'4932for (ArrayIndex index = 0; index < size; ++index) {4933if (hasCommentForValue(value[index])) {4934isMultiLine = true;4935}4936writeValue(value[index]);4937lineLength += static_cast<ArrayIndex>(childValues_[index].length());4938}4939addChildValues_ = false;4940isMultiLine = isMultiLine || lineLength >= rightMargin_;4941}4942return isMultiLine;4943}49444945void StyledStreamWriter::pushValue(const String& value) {4946if (addChildValues_)4947childValues_.push_back(value);4948else4949*document_ << value;4950}49514952void StyledStreamWriter::writeIndent() {4953// blep intended this to look at the so-far-written string4954// to determine whether we are already indented, but4955// with a stream we cannot do that. So we rely on some saved state.4956// The caller checks indented_.4957*document_ << '\n' << indentString_;4958}49594960void StyledStreamWriter::writeWithIndent(const String& value) {4961if (!indented_)4962writeIndent();4963*document_ << value;4964indented_ = false;4965}49664967void StyledStreamWriter::indent() { indentString_ += indentation_; }49684969void StyledStreamWriter::unindent() {4970assert(indentString_.size() >= indentation_.size());4971indentString_.resize(indentString_.size() - indentation_.size());4972}49734974void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {4975if (!root.hasComment(commentBefore))4976return;49774978if (!indented_)4979writeIndent();4980const String& comment = root.getComment(commentBefore);4981String::const_iterator iter = comment.begin();4982while (iter != comment.end()) {4983*document_ << *iter;4984if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))4985// writeIndent(); // would include newline4986*document_ << indentString_;4987++iter;4988}4989indented_ = false;4990}49914992void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {4993if (root.hasComment(commentAfterOnSameLine))4994*document_ << ' ' << root.getComment(commentAfterOnSameLine);49954996if (root.hasComment(commentAfter)) {4997writeIndent();4998*document_ << root.getComment(commentAfter);4999}5000indented_ = false;5001}50025003bool StyledStreamWriter::hasCommentForValue(const Value& value) {5004return value.hasComment(commentBefore) ||5005value.hasComment(commentAfterOnSameLine) ||5006value.hasComment(commentAfter);5007}50085009//////////////////////////5010// BuiltStyledStreamWriter50115012/// Scoped enums are not available until C++11.5013struct CommentStyle {5014/// Decide whether to write comments.5015enum Enum {5016None, ///< Drop all comments.5017Most, ///< Recover odd behavior of previous versions (not implemented yet).5018All ///< Keep all comments.5019};5020};50215022struct BuiltStyledStreamWriter : public StreamWriter {5023BuiltStyledStreamWriter(String indentation,5024CommentStyle::Enum cs,5025String colonSymbol,5026String nullSymbol,5027String endingLineFeedSymbol,5028bool useSpecialFloats,5029unsigned int precision,5030PrecisionType precisionType);5031int write(Value const& root, OStream* sout) override;50325033private:5034void writeValue(Value const& value);5035void writeArrayValue(Value const& value);5036bool isMultilineArray(Value const& value);5037void pushValue(String const& value);5038void writeIndent();5039void writeWithIndent(String const& value);5040void indent();5041void unindent();5042void writeCommentBeforeValue(Value const& root);5043void writeCommentAfterValueOnSameLine(Value const& root);5044static bool hasCommentForValue(const Value& value);50455046typedef std::vector<String> ChildValues;50475048ChildValues childValues_;5049String indentString_;5050unsigned int rightMargin_;5051String indentation_;5052CommentStyle::Enum cs_;5053String colonSymbol_;5054String nullSymbol_;5055String endingLineFeedSymbol_;5056bool addChildValues_ : 1;5057bool indented_ : 1;5058bool useSpecialFloats_ : 1;5059unsigned int precision_;5060PrecisionType precisionType_;5061};5062BuiltStyledStreamWriter::BuiltStyledStreamWriter(String indentation,5063CommentStyle::Enum cs,5064String colonSymbol,5065String nullSymbol,5066String endingLineFeedSymbol,5067bool useSpecialFloats,5068unsigned int precision,5069PrecisionType precisionType)5070: rightMargin_(74), indentation_(std::move(indentation)), cs_(cs),5071colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)),5072endingLineFeedSymbol_(std::move(endingLineFeedSymbol)),5073addChildValues_(false), indented_(false),5074useSpecialFloats_(useSpecialFloats), precision_(precision),5075precisionType_(precisionType) {}5076int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) {5077sout_ = sout;5078addChildValues_ = false;5079indented_ = true;5080indentString_.clear();5081writeCommentBeforeValue(root);5082if (!indented_)5083writeIndent();5084indented_ = true;5085writeValue(root);5086writeCommentAfterValueOnSameLine(root);5087*sout_ << endingLineFeedSymbol_;5088sout_ = nullptr;5089return 0;5090}5091void BuiltStyledStreamWriter::writeValue(Value const& value) {5092switch (value.type()) {5093case nullValue:5094pushValue(nullSymbol_);5095break;5096case intValue:5097pushValue(valueToString(value.asLargestInt()));5098break;5099case uintValue:5100pushValue(valueToString(value.asLargestUInt()));5101break;5102case realValue:5103pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_,5104precisionType_));5105break;5106case stringValue: {5107// Is NULL is possible for value.string_? No.5108char const* str;5109char const* end;5110bool ok = value.getString(&str, &end);5111if (ok)5112pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));5113else5114pushValue("");5115break;5116}5117case booleanValue:5118pushValue(valueToString(value.asBool()));5119break;5120case arrayValue:5121writeArrayValue(value);5122break;5123case objectValue: {5124Value::Members members(value.getMemberNames());5125if (members.empty())5126pushValue("{}");5127else {5128writeWithIndent("{");5129indent();5130auto it = members.begin();5131for (;;) {5132String const& name = *it;5133Value const& childValue = value[name];5134writeCommentBeforeValue(childValue);5135writeWithIndent(valueToQuotedStringN(5136name.data(), static_cast<unsigned>(name.length())));5137*sout_ << colonSymbol_;5138writeValue(childValue);5139if (++it == members.end()) {5140writeCommentAfterValueOnSameLine(childValue);5141break;5142}5143*sout_ << ",";5144writeCommentAfterValueOnSameLine(childValue);5145}5146unindent();5147writeWithIndent("}");5148}5149} break;5150}5151}51525153void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {5154unsigned size = value.size();5155if (size == 0)5156pushValue("[]");5157else {5158bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value);5159if (isMultiLine) {5160writeWithIndent("[");5161indent();5162bool hasChildValue = !childValues_.empty();5163unsigned index = 0;5164for (;;) {5165Value const& childValue = value[index];5166writeCommentBeforeValue(childValue);5167if (hasChildValue)5168writeWithIndent(childValues_[index]);5169else {5170if (!indented_)5171writeIndent();5172indented_ = true;5173writeValue(childValue);5174indented_ = false;5175}5176if (++index == size) {5177writeCommentAfterValueOnSameLine(childValue);5178break;5179}5180*sout_ << ",";5181writeCommentAfterValueOnSameLine(childValue);5182}5183unindent();5184writeWithIndent("]");5185} else // output on a single line5186{5187assert(childValues_.size() == size);5188*sout_ << "[";5189if (!indentation_.empty())5190*sout_ << " ";5191for (unsigned index = 0; index < size; ++index) {5192if (index > 0)5193*sout_ << ((!indentation_.empty()) ? ", " : ",");5194*sout_ << childValues_[index];5195}5196if (!indentation_.empty())5197*sout_ << " ";5198*sout_ << "]";5199}5200}5201}52025203bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) {5204ArrayIndex const size = value.size();5205bool isMultiLine = size * 3 >= rightMargin_;5206childValues_.clear();5207for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {5208Value const& childValue = value[index];5209isMultiLine = ((childValue.isArray() || childValue.isObject()) &&5210!childValue.empty());5211}5212if (!isMultiLine) // check if line length > max line length5213{5214childValues_.reserve(size);5215addChildValues_ = true;5216ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'5217for (ArrayIndex index = 0; index < size; ++index) {5218if (hasCommentForValue(value[index])) {5219isMultiLine = true;5220}5221writeValue(value[index]);5222lineLength += static_cast<ArrayIndex>(childValues_[index].length());5223}5224addChildValues_ = false;5225isMultiLine = isMultiLine || lineLength >= rightMargin_;5226}5227return isMultiLine;5228}52295230void BuiltStyledStreamWriter::pushValue(String const& value) {5231if (addChildValues_)5232childValues_.push_back(value);5233else5234*sout_ << value;5235}52365237void BuiltStyledStreamWriter::writeIndent() {5238// blep intended this to look at the so-far-written string5239// to determine whether we are already indented, but5240// with a stream we cannot do that. So we rely on some saved state.5241// The caller checks indented_.52425243if (!indentation_.empty()) {5244// In this case, drop newlines too.5245*sout_ << '\n' << indentString_;5246}5247}52485249void BuiltStyledStreamWriter::writeWithIndent(String const& value) {5250if (!indented_)5251writeIndent();5252*sout_ << value;5253indented_ = false;5254}52555256void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }52575258void BuiltStyledStreamWriter::unindent() {5259assert(indentString_.size() >= indentation_.size());5260indentString_.resize(indentString_.size() - indentation_.size());5261}52625263void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {5264if (cs_ == CommentStyle::None)5265return;5266if (!root.hasComment(commentBefore))5267return;52685269if (!indented_)5270writeIndent();5271const String& comment = root.getComment(commentBefore);5272String::const_iterator iter = comment.begin();5273while (iter != comment.end()) {5274*sout_ << *iter;5275if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))5276// writeIndent(); // would write extra newline5277*sout_ << indentString_;5278++iter;5279}5280indented_ = false;5281}52825283void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(5284Value const& root) {5285if (cs_ == CommentStyle::None)5286return;5287if (root.hasComment(commentAfterOnSameLine))5288*sout_ << " " + root.getComment(commentAfterOnSameLine);52895290if (root.hasComment(commentAfter)) {5291writeIndent();5292*sout_ << root.getComment(commentAfter);5293}5294}52955296// static5297bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {5298return value.hasComment(commentBefore) ||5299value.hasComment(commentAfterOnSameLine) ||5300value.hasComment(commentAfter);5301}53025303///////////////5304// StreamWriter53055306StreamWriter::StreamWriter() : sout_(nullptr) {}5307StreamWriter::~StreamWriter() = default;5308StreamWriter::Factory::~Factory() = default;5309StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); }5310StreamWriterBuilder::~StreamWriterBuilder() = default;5311StreamWriter* StreamWriterBuilder::newStreamWriter() const {5312String indentation = settings_["indentation"].asString();5313String cs_str = settings_["commentStyle"].asString();5314String pt_str = settings_["precisionType"].asString();5315bool eyc = settings_["enableYAMLCompatibility"].asBool();5316bool dnp = settings_["dropNullPlaceholders"].asBool();5317bool usf = settings_["useSpecialFloats"].asBool();5318unsigned int pre = settings_["precision"].asUInt();5319CommentStyle::Enum cs = CommentStyle::All;5320if (cs_str == "All") {5321cs = CommentStyle::All;5322} else if (cs_str == "None") {5323cs = CommentStyle::None;5324} else {5325throwRuntimeError("commentStyle must be 'All' or 'None'");5326}5327PrecisionType precisionType(significantDigits);5328if (pt_str == "significant") {5329precisionType = PrecisionType::significantDigits;5330} else if (pt_str == "decimal") {5331precisionType = PrecisionType::decimalPlaces;5332} else {5333throwRuntimeError("precisionType must be 'significant' or 'decimal'");5334}5335String colonSymbol = " : ";5336if (eyc) {5337colonSymbol = ": ";5338} else if (indentation.empty()) {5339colonSymbol = ":";5340}5341String nullSymbol = "null";5342if (dnp) {5343nullSymbol.clear();5344}5345if (pre > 17)5346pre = 17;5347String endingLineFeedSymbol;5348return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol,5349endingLineFeedSymbol, usf, pre,5350precisionType);5351}5352static void getValidWriterKeys(std::set<String>* valid_keys) {5353valid_keys->clear();5354valid_keys->insert("indentation");5355valid_keys->insert("commentStyle");5356valid_keys->insert("enableYAMLCompatibility");5357valid_keys->insert("dropNullPlaceholders");5358valid_keys->insert("useSpecialFloats");5359valid_keys->insert("precision");5360valid_keys->insert("precisionType");5361}5362bool StreamWriterBuilder::validate(Json::Value* invalid) const {5363Json::Value my_invalid;5364if (!invalid)5365invalid = &my_invalid; // so we do not need to test for NULL5366Json::Value& inv = *invalid;5367std::set<String> valid_keys;5368getValidWriterKeys(&valid_keys);5369Value::Members keys = settings_.getMemberNames();5370size_t n = keys.size();5371for (size_t i = 0; i < n; ++i) {5372String const& key = keys[i];5373if (valid_keys.find(key) == valid_keys.end()) {5374inv[key] = settings_[key];5375}5376}5377return inv.empty();5378}5379Value& StreamWriterBuilder::operator[](const String& key) {5380return settings_[key];5381}5382// static5383void StreamWriterBuilder::setDefaults(Json::Value* settings) {5384//! [StreamWriterBuilderDefaults]5385(*settings)["commentStyle"] = "All";5386(*settings)["indentation"] = "\t";5387(*settings)["enableYAMLCompatibility"] = false;5388(*settings)["dropNullPlaceholders"] = false;5389(*settings)["useSpecialFloats"] = false;5390(*settings)["precision"] = 17;5391(*settings)["precisionType"] = "significant";5392//! [StreamWriterBuilderDefaults]5393}53945395String writeString(StreamWriter::Factory const& factory, Value const& root) {5396OStringStream sout;5397StreamWriterPtr const writer(factory.newStreamWriter());5398writer->write(root, &sout);5399return sout.str();5400}54015402OStream& operator<<(OStream& sout, Value const& root) {5403StreamWriterBuilder builder;5404StreamWriterPtr const writer(builder.newStreamWriter());5405writer->write(root, &sout);5406return sout;5407}54085409} // namespace Json54105411// //////////////////////////////////////////////////////////////////////5412// End of content of file: src/lib_json/json_writer.cpp5413// //////////////////////////////////////////////////////////////////////54145415541654175418541954205421