1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-05-08 22:37:04 +08:00

Merge branch 'upstream-jsoncpp' into update-jsoncpp

* upstream-jsoncpp:
  jsoncpp 2024-09-09 (89e2973c)
This commit is contained in:
Brad King 2025-02-20 19:07:15 -05:00
commit af65a5d98b
8 changed files with 190 additions and 110 deletions

View File

@ -71,7 +71,9 @@ public:
// Boilerplate // Boilerplate
SecureAllocator() {} SecureAllocator() {}
template <typename U> SecureAllocator(const SecureAllocator<U>&) {} template <typename U> SecureAllocator(const SecureAllocator<U>&) {}
template <typename U> struct rebind { using other = SecureAllocator<U>; }; template <typename U> struct rebind {
using other = SecureAllocator<U>;
};
}; };
template <typename T, typename U> template <typename T, typename U>

View File

@ -53,12 +53,12 @@ public:
}; };
/** \brief Constructs a Reader allowing all features for parsing. /** \brief Constructs a Reader allowing all features for parsing.
* deprecated Use CharReader and CharReaderBuilder. * deprecated Use CharReader and CharReaderBuilder.
*/ */
Reader(); Reader();
/** \brief Constructs a Reader allowing the specified feature set for parsing. /** \brief Constructs a Reader allowing the specified feature set for parsing.
* deprecated Use CharReader and CharReaderBuilder. * deprecated Use CharReader and CharReaderBuilder.
*/ */
Reader(const Features& features); Reader(const Features& features);
@ -192,6 +192,7 @@ private:
using Errors = std::deque<ErrorInfo>; using Errors = std::deque<ErrorInfo>;
bool readToken(Token& token); bool readToken(Token& token);
bool readTokenSkippingComments(Token& token);
void skipSpaces(); void skipSpaces();
bool match(const Char* pattern, int patternLength); bool match(const Char* pattern, int patternLength);
bool readComment(); bool readComment();
@ -223,7 +224,6 @@ private:
int& column) const; int& column) const;
String getLocationLineAndColumn(Location location) const; String getLocationLineAndColumn(Location location) const;
void addComment(Location begin, Location end, CommentPlacement placement); void addComment(Location begin, Location end, CommentPlacement placement);
void skipCommentTokens(Token& token);
static bool containsNewLine(Location begin, Location end); static bool containsNewLine(Location begin, Location end);
static String normalizeEOL(Location begin, Location end); static String normalizeEOL(Location begin, Location end);
@ -246,6 +246,12 @@ private:
*/ */
class JSON_API CharReader { class JSON_API CharReader {
public: public:
struct JSON_API StructuredError {
ptrdiff_t offset_start;
ptrdiff_t offset_limit;
String message;
};
virtual ~CharReader() = default; virtual ~CharReader() = default;
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
* document. The document must be a UTF-8 encoded string containing the * document. The document must be a UTF-8 encoded string containing the
@ -264,7 +270,12 @@ public:
* error occurred. * error occurred.
*/ */
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) = 0; String* errs);
/** \brief Returns a vector of structured errors encountered while parsing.
* Each parse call resets the stored list of errors.
*/
std::vector<StructuredError> getStructuredErrors() const;
class JSON_API Factory { class JSON_API Factory {
public: public:
@ -274,7 +285,21 @@ public:
*/ */
virtual CharReader* newCharReader() const = 0; virtual CharReader* newCharReader() const = 0;
}; // Factory }; // Factory
}; // CharReader
protected:
class Impl {
public:
virtual ~Impl() = default;
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) = 0;
virtual std::vector<StructuredError> getStructuredErrors() const = 0;
};
explicit CharReader(std::unique_ptr<Impl> impl) : _impl(std::move(impl)) {}
private:
std::unique_ptr<Impl> _impl;
}; // CharReader
/** \brief Build a CharReader implementation. /** \brief Build a CharReader implementation.
* *
@ -362,6 +387,12 @@ public:
* snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode * snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
*/ */
static void strictMode(Json::Value* settings); static void strictMode(Json::Value* settings);
/** ECMA-404 mode.
* \pre 'settings' != NULL (but Json::null is fine)
* \remark Defaults:
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderECMA404Mode
*/
static void ecma404Mode(Json::Value* settings);
}; };
/** Consume entire stream and use its begin/end. /** Consume entire stream and use its begin/end.

View File

@ -3,8 +3,8 @@
// recognized in your jurisdiction. // recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_H_INCLUDED #ifndef JSON_VALUE_H_INCLUDED
#define JSON_H_INCLUDED #define JSON_VALUE_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION) #if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h" #include "forwards.h"
@ -443,7 +443,7 @@ public:
/// \post type() is arrayValue /// \post type() is arrayValue
void resize(ArrayIndex newSize); void resize(ArrayIndex newSize);
//@{ ///@{
/// Access an array element (zero based index). If the array contains less /// Access an array element (zero based index). If the array contains less
/// than index element, then null value are inserted in the array so that /// than index element, then null value are inserted in the array so that
/// its size is index+1. /// its size is index+1.
@ -451,15 +451,15 @@ public:
/// this from the operator[] which takes a string.) /// this from the operator[] which takes a string.)
Value& operator[](ArrayIndex index); Value& operator[](ArrayIndex index);
Value& operator[](int index); Value& operator[](int index);
//@} ///@}
//@{ ///@{
/// Access an array element (zero based index). /// Access an array element (zero based index).
/// (You may need to say 'value[0u]' to get your compiler to distinguish /// (You may need to say 'value[0u]' to get your compiler to distinguish
/// this from the operator[] which takes a string.) /// this from the operator[] which takes a string.)
const Value& operator[](ArrayIndex index) const; const Value& operator[](ArrayIndex index) const;
const Value& operator[](int index) const; const Value& operator[](int index) const;
//@} ///@}
/// If the array contains at least index+1 elements, returns the element /// If the array contains at least index+1 elements, returns the element
/// value, otherwise returns defaultValue. /// value, otherwise returns defaultValue.
@ -519,6 +519,9 @@ public:
/// and operator[]const /// and operator[]const
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
Value const* find(char const* begin, char const* end) const; Value const* find(char const* begin, char const* end) const;
/// Most general and efficient version of isMember()const, get()const,
/// and operator[]const
Value const* find(const String& key) const;
/// Most general and efficient version of object-mutators. /// Most general and efficient version of object-mutators.
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
/// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
@ -591,6 +594,26 @@ public:
iterator begin(); iterator begin();
iterator end(); iterator end();
/// \brief Returns a reference to the first element in the `Value`.
/// Requires that this value holds an array or json object, with at least one
/// element.
const Value& front() const;
/// \brief Returns a reference to the first element in the `Value`.
/// Requires that this value holds an array or json object, with at least one
/// element.
Value& front();
/// \brief Returns a reference to the last element in the `Value`.
/// Requires that value holds an array or json object, with at least one
/// element.
const Value& back() const;
/// \brief Returns a reference to the last element in the `Value`.
/// Requires that this value holds an array or json object, with at least one
/// element.
Value& back();
// Accessors for the [start, limit) range of bytes within the JSON text from // Accessors for the [start, limit) range of bytes within the JSON text from
// which this value was parsed, if any. // which this value was parsed, if any.
void setOffsetStart(ptrdiff_t start); void setOffsetStart(ptrdiff_t start);
@ -931,6 +954,14 @@ public:
inline void swap(Value& a, Value& b) { a.swap(b); } inline void swap(Value& a, Value& b) { a.swap(b); }
inline const Value& Value::front() const { return *begin(); }
inline Value& Value::front() { return *begin(); }
inline const Value& Value::back() const { return *(--end()); }
inline Value& Value::back() { return *(--end()); }
} // namespace Json } // namespace Json
#if !defined(__SUNPRO_CC) #if !defined(__SUNPRO_CC)

View File

@ -9,19 +9,18 @@
// 3. /CMakeLists.txt // 3. /CMakeLists.txt
// IMPORTANT: also update the SOVERSION!! // IMPORTANT: also update the SOVERSION!!
#define JSONCPP_VERSION_STRING "1.9.5" #define JSONCPP_VERSION_STRING "1.9.6"
#define JSONCPP_VERSION_MAJOR 1 #define JSONCPP_VERSION_MAJOR 1
#define JSONCPP_VERSION_MINOR 9 #define JSONCPP_VERSION_MINOR 9
#define JSONCPP_VERSION_PATCH 5 #define JSONCPP_VERSION_PATCH 6
#define JSONCPP_VERSION_QUALIFIER #define JSONCPP_VERSION_QUALIFIER
#define JSONCPP_VERSION_HEXA \ #define JSONCPP_VERSION_HEXA \
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
(JSONCPP_VERSION_PATCH << 8)) (JSONCPP_VERSION_PATCH << 8))
#ifdef JSONCPP_USING_SECURE_MEMORY #if !defined(JSONCPP_USE_SECURE_MEMORY)
#undef JSONCPP_USING_SECURE_MEMORY
#endif
#define JSONCPP_USING_SECURE_MEMORY 0 #define JSONCPP_USING_SECURE_MEMORY 0
#endif
// If non-zero, the library zeroes any memory that it has allocated before // If non-zero, the library zeroes any memory that it has allocated before
// it frees its memory. // it frees its memory.

View File

@ -66,7 +66,7 @@ public:
*/ */
virtual StreamWriter* newStreamWriter() const = 0; virtual StreamWriter* newStreamWriter() const = 0;
}; // Factory }; // Factory
}; // StreamWriter }; // StreamWriter
/** \brief Write into stringstream, then return string, for convenience. /** \brief Write into stringstream, then return string, for convenience.
* A StreamWriter will be created from the factory, used, and then deleted. * A StreamWriter will be created from the factory, used, and then deleted.
@ -170,8 +170,7 @@ public:
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4996) // Deriving from deprecated class #pragma warning(disable : 4996) // Deriving from deprecated class
#endif #endif
class JSON_API FastWriter class JSON_API FastWriter : public Writer {
: public Writer {
public: public:
FastWriter(); FastWriter();
~FastWriter() override = default; ~FastWriter() override = default;
@ -230,8 +229,7 @@ private:
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4996) // Deriving from deprecated class #pragma warning(disable : 4996) // Deriving from deprecated class
#endif #endif
class JSON_API class JSON_API StyledWriter : public Writer {
StyledWriter : public Writer {
public: public:
StyledWriter(); StyledWriter();
~StyledWriter() override = default; ~StyledWriter() override = default;
@ -299,8 +297,7 @@ private:
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4996) // Deriving from deprecated class #pragma warning(disable : 4996) // Deriving from deprecated class
#endif #endif
class JSON_API class JSON_API StyledStreamWriter {
StyledStreamWriter {
public: public:
/** /**
* \param indentation Each level will be indented by this amount extra. * \param indentation Each level will be indented by this amount extra.
@ -356,6 +353,7 @@ String JSON_API valueToString(
PrecisionType precisionType = PrecisionType::significantDigits); PrecisionType precisionType = PrecisionType::significantDigits);
String JSON_API valueToString(bool value); String JSON_API valueToString(bool value);
String JSON_API valueToQuotedString(const char* value); String JSON_API valueToQuotedString(const char* value);
String JSON_API valueToQuotedString(const char* value, size_t length);
/// \brief Output using the StyledStreamWriter. /// \brief Output using the StyledStreamWriter.
/// \see Json::operator>>() /// \see Json::operator>>()

View File

@ -129,7 +129,7 @@ bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,
bool successful = readValue(); bool successful = readValue();
Token token; Token token;
skipCommentTokens(token); readTokenSkippingComments(token);
if (collectComments_ && !commentsBefore_.empty()) if (collectComments_ && !commentsBefore_.empty())
root.setComment(commentsBefore_, commentAfter); root.setComment(commentsBefore_, commentAfter);
if (features_.strictRoot_) { if (features_.strictRoot_) {
@ -157,7 +157,7 @@ bool Reader::readValue() {
throwRuntimeError("Exceeded stackLimit in readValue()."); throwRuntimeError("Exceeded stackLimit in readValue().");
Token token; Token token;
skipCommentTokens(token); readTokenSkippingComments(token);
bool successful = true; bool successful = true;
if (collectComments_ && !commentsBefore_.empty()) { if (collectComments_ && !commentsBefore_.empty()) {
@ -225,14 +225,14 @@ bool Reader::readValue() {
return successful; return successful;
} }
void Reader::skipCommentTokens(Token& token) { bool Reader::readTokenSkippingComments(Token& token) {
bool success = readToken(token);
if (features_.allowComments_) { if (features_.allowComments_) {
do { while (success && token.type_ == tokenComment) {
readToken(token); success = readToken(token);
} while (token.type_ == tokenComment); }
} else {
readToken(token);
} }
return success;
} }
bool Reader::readToken(Token& token) { bool Reader::readToken(Token& token) {
@ -446,12 +446,7 @@ bool Reader::readObject(Token& token) {
Value init(objectValue); Value init(objectValue);
currentValue().swapPayload(init); currentValue().swapPayload(init);
currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetStart(token.start_ - begin_);
while (readToken(tokenName)) { while (readTokenSkippingComments(tokenName)) {
bool initialTokenOk = true;
while (tokenName.type_ == tokenComment && initialTokenOk)
initialTokenOk = readToken(tokenName);
if (!initialTokenOk)
break;
if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
return true; return true;
name.clear(); name.clear();
@ -480,15 +475,11 @@ bool Reader::readObject(Token& token) {
return recoverFromError(tokenObjectEnd); return recoverFromError(tokenObjectEnd);
Token comma; Token comma;
if (!readToken(comma) || if (!readTokenSkippingComments(comma) ||
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {
comma.type_ != tokenComment)) {
return addErrorAndRecover("Missing ',' or '}' in object declaration", return addErrorAndRecover("Missing ',' or '}' in object declaration",
comma, tokenObjectEnd); comma, tokenObjectEnd);
} }
bool finalizeTokenOk = true;
while (comma.type_ == tokenComment && finalizeTokenOk)
finalizeTokenOk = readToken(comma);
if (comma.type_ == tokenObjectEnd) if (comma.type_ == tokenObjectEnd)
return true; return true;
} }
@ -518,10 +509,7 @@ bool Reader::readArray(Token& token) {
Token currentToken; Token currentToken;
// Accept Comment after last item in the array. // Accept Comment after last item in the array.
ok = readToken(currentToken); ok = readTokenSkippingComments(currentToken);
while (currentToken.type_ == tokenComment && ok) {
ok = readToken(currentToken);
}
bool badTokenType = (currentToken.type_ != tokenArraySeparator && bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
currentToken.type_ != tokenArrayEnd); currentToken.type_ != tokenArrayEnd);
if (!ok || badTokenType) { if (!ok || badTokenType) {
@ -599,8 +587,7 @@ bool Reader::decodeDouble(Token& token) {
bool Reader::decodeDouble(Token& token, Value& decoded) { bool Reader::decodeDouble(Token& token, Value& decoded) {
double value = 0; double value = 0;
String buffer(token.start_, token.end_); IStringStream is(String(token.start_, token.end_));
IStringStream is(buffer);
if (!(is >> value)) { if (!(is >> value)) {
if (value == std::numeric_limits<double>::max()) if (value == std::numeric_limits<double>::max())
value = std::numeric_limits<double>::infinity(); value = std::numeric_limits<double>::infinity();
@ -608,7 +595,7 @@ bool Reader::decodeDouble(Token& token, Value& decoded) {
value = -std::numeric_limits<double>::infinity(); value = -std::numeric_limits<double>::infinity();
else if (!std::isinf(value)) else if (!std::isinf(value))
return addError( return addError(
"'" + String(token.start_, token.end_) + "' is not a number.", token); "'" + String(token.start_, token.end_) + "' is not a number.", token);
} }
decoded = value; decoded = value;
return true; return true;
@ -773,7 +760,7 @@ void Reader::getLocationLineAndColumn(Location location, int& line,
while (current < location && current != end_) { while (current < location && current != end_) {
Char c = *current++; Char c = *current++;
if (c == '\r') { if (c == '\r') {
if (*current == '\n') if (current != end_ && *current == '\n')
++current; ++current;
lastLineStart = current; lastLineStart = current;
++line; ++line;
@ -890,17 +877,12 @@ class OurReader {
public: public:
using Char = char; using Char = char;
using Location = const Char*; using Location = const Char*;
struct StructuredError {
ptrdiff_t offset_start;
ptrdiff_t offset_limit;
String message;
};
explicit OurReader(OurFeatures const& features); explicit OurReader(OurFeatures const& features);
bool parse(const char* beginDoc, const char* endDoc, Value& root, bool parse(const char* beginDoc, const char* endDoc, Value& root,
bool collectComments = true); bool collectComments = true);
String getFormattedErrorMessages() const; String getFormattedErrorMessages() const;
std::vector<StructuredError> getStructuredErrors() const; std::vector<CharReader::StructuredError> getStructuredErrors() const;
private: private:
OurReader(OurReader const&); // no impl OurReader(OurReader const&); // no impl
@ -943,6 +925,7 @@ private:
using Errors = std::deque<ErrorInfo>; using Errors = std::deque<ErrorInfo>;
bool readToken(Token& token); bool readToken(Token& token);
bool readTokenSkippingComments(Token& token);
void skipSpaces(); void skipSpaces();
void skipBom(bool skipBom); void skipBom(bool skipBom);
bool match(const Char* pattern, int patternLength); bool match(const Char* pattern, int patternLength);
@ -976,7 +959,6 @@ private:
int& column) const; int& column) const;
String getLocationLineAndColumn(Location location) const; String getLocationLineAndColumn(Location location) const;
void addComment(Location begin, Location end, CommentPlacement placement); void addComment(Location begin, Location end, CommentPlacement placement);
void skipCommentTokens(Token& token);
static String normalizeEOL(Location begin, Location end); static String normalizeEOL(Location begin, Location end);
static bool containsNewLine(Location begin, Location end); static bool containsNewLine(Location begin, Location end);
@ -1030,7 +1012,7 @@ bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
bool successful = readValue(); bool successful = readValue();
nodes_.pop(); nodes_.pop();
Token token; Token token;
skipCommentTokens(token); readTokenSkippingComments(token);
if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) { if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
addError("Extra non-whitespace after JSON value.", token); addError("Extra non-whitespace after JSON value.", token);
return false; return false;
@ -1058,7 +1040,7 @@ bool OurReader::readValue() {
if (nodes_.size() > features_.stackLimit_) if (nodes_.size() > features_.stackLimit_)
throwRuntimeError("Exceeded stackLimit in readValue()."); throwRuntimeError("Exceeded stackLimit in readValue().");
Token token; Token token;
skipCommentTokens(token); readTokenSkippingComments(token);
bool successful = true; bool successful = true;
if (collectComments_ && !commentsBefore_.empty()) { if (collectComments_ && !commentsBefore_.empty()) {
@ -1145,14 +1127,14 @@ bool OurReader::readValue() {
return successful; return successful;
} }
void OurReader::skipCommentTokens(Token& token) { bool OurReader::readTokenSkippingComments(Token& token) {
bool success = readToken(token);
if (features_.allowComments_) { if (features_.allowComments_) {
do { while (success && token.type_ == tokenComment) {
readToken(token); success = readToken(token);
} while (token.type_ == tokenComment); }
} else {
readToken(token);
} }
return success;
} }
bool OurReader::readToken(Token& token) { bool OurReader::readToken(Token& token) {
@ -1449,12 +1431,7 @@ bool OurReader::readObject(Token& token) {
Value init(objectValue); Value init(objectValue);
currentValue().swapPayload(init); currentValue().swapPayload(init);
currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetStart(token.start_ - begin_);
while (readToken(tokenName)) { while (readTokenSkippingComments(tokenName)) {
bool initialTokenOk = true;
while (tokenName.type_ == tokenComment && initialTokenOk)
initialTokenOk = readToken(tokenName);
if (!initialTokenOk)
break;
if (tokenName.type_ == tokenObjectEnd && if (tokenName.type_ == tokenObjectEnd &&
(name.empty() || (name.empty() ||
features_.allowTrailingCommas_)) // empty object or trailing comma features_.allowTrailingCommas_)) // empty object or trailing comma
@ -1491,15 +1468,11 @@ bool OurReader::readObject(Token& token) {
return recoverFromError(tokenObjectEnd); return recoverFromError(tokenObjectEnd);
Token comma; Token comma;
if (!readToken(comma) || if (!readTokenSkippingComments(comma) ||
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {
comma.type_ != tokenComment)) {
return addErrorAndRecover("Missing ',' or '}' in object declaration", return addErrorAndRecover("Missing ',' or '}' in object declaration",
comma, tokenObjectEnd); comma, tokenObjectEnd);
} }
bool finalizeTokenOk = true;
while (comma.type_ == tokenComment && finalizeTokenOk)
finalizeTokenOk = readToken(comma);
if (comma.type_ == tokenObjectEnd) if (comma.type_ == tokenObjectEnd)
return true; return true;
} }
@ -1533,10 +1506,7 @@ bool OurReader::readArray(Token& token) {
Token currentToken; Token currentToken;
// Accept Comment after last item in the array. // Accept Comment after last item in the array.
ok = readToken(currentToken); ok = readTokenSkippingComments(currentToken);
while (currentToken.type_ == tokenComment && ok) {
ok = readToken(currentToken);
}
bool badTokenType = (currentToken.type_ != tokenArraySeparator && bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
currentToken.type_ != tokenArrayEnd); currentToken.type_ != tokenArrayEnd);
if (!ok || badTokenType) { if (!ok || badTokenType) {
@ -1651,8 +1621,7 @@ bool OurReader::decodeDouble(Token& token) {
bool OurReader::decodeDouble(Token& token, Value& decoded) { bool OurReader::decodeDouble(Token& token, Value& decoded) {
double value = 0; double value = 0;
const String buffer(token.start_, token.end_); IStringStream is(String(token.start_, token.end_));
IStringStream is(buffer);
if (!(is >> value)) { if (!(is >> value)) {
if (value == std::numeric_limits<double>::max()) if (value == std::numeric_limits<double>::max())
value = std::numeric_limits<double>::infinity(); value = std::numeric_limits<double>::infinity();
@ -1660,7 +1629,7 @@ bool OurReader::decodeDouble(Token& token, Value& decoded) {
value = -std::numeric_limits<double>::infinity(); value = -std::numeric_limits<double>::infinity();
else if (!std::isinf(value)) else if (!std::isinf(value))
return addError( return addError(
"'" + String(token.start_, token.end_) + "' is not a number.", token); "'" + String(token.start_, token.end_) + "' is not a number.", token);
} }
decoded = value; decoded = value;
return true; return true;
@ -1826,7 +1795,7 @@ void OurReader::getLocationLineAndColumn(Location location, int& line,
while (current < location && current != end_) { while (current < location && current != end_) {
Char c = *current++; Char c = *current++;
if (c == '\r') { if (c == '\r') {
if (*current == '\n') if (current != end_ && *current == '\n')
++current; ++current;
lastLineStart = current; lastLineStart = current;
++line; ++line;
@ -1861,10 +1830,11 @@ String OurReader::getFormattedErrorMessages() const {
return formattedMessage; return formattedMessage;
} }
std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const { std::vector<CharReader::StructuredError>
std::vector<OurReader::StructuredError> allErrors; OurReader::getStructuredErrors() const {
std::vector<CharReader::StructuredError> allErrors;
for (const auto& error : errors_) { for (const auto& error : errors_) {
OurReader::StructuredError structured; CharReader::StructuredError structured;
structured.offset_start = error.token_.start_ - begin_; structured.offset_start = error.token_.start_ - begin_;
structured.offset_limit = error.token_.end_ - begin_; structured.offset_limit = error.token_.end_ - begin_;
structured.message = error.message_; structured.message = error.message_;
@ -1874,20 +1844,36 @@ std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
} }
class OurCharReader : public CharReader { class OurCharReader : public CharReader {
bool const collectComments_;
OurReader reader_;
public: public:
OurCharReader(bool collectComments, OurFeatures const& features) OurCharReader(bool collectComments, OurFeatures const& features)
: collectComments_(collectComments), reader_(features) {} : CharReader(
bool parse(char const* beginDoc, char const* endDoc, Value* root, std::unique_ptr<OurImpl>(new OurImpl(collectComments, features))) {}
String* errs) override {
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); protected:
if (errs) { class OurImpl : public Impl {
*errs = reader_.getFormattedErrorMessages(); public:
OurImpl(bool collectComments, OurFeatures const& features)
: collectComments_(collectComments), reader_(features) {}
bool parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) override {
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
if (errs) {
*errs = reader_.getFormattedErrorMessages();
}
return ok;
} }
return ok;
} std::vector<CharReader::StructuredError>
getStructuredErrors() const override {
return reader_.getStructuredErrors();
}
private:
bool const collectComments_;
OurReader reader_;
};
}; };
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
@ -1976,6 +1962,32 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) {
(*settings)["skipBom"] = true; (*settings)["skipBom"] = true;
//! [CharReaderBuilderDefaults] //! [CharReaderBuilderDefaults]
} }
// static
void CharReaderBuilder::ecma404Mode(Json::Value* settings) {
//! [CharReaderBuilderECMA404Mode]
(*settings)["allowComments"] = false;
(*settings)["allowTrailingCommas"] = false;
(*settings)["strictRoot"] = false;
(*settings)["allowDroppedNullPlaceholders"] = false;
(*settings)["allowNumericKeys"] = false;
(*settings)["allowSingleQuotes"] = false;
(*settings)["stackLimit"] = 1000;
(*settings)["failIfExtra"] = true;
(*settings)["rejectDupKeys"] = false;
(*settings)["allowSpecialFloats"] = false;
(*settings)["skipBom"] = false;
//! [CharReaderBuilderECMA404Mode]
}
std::vector<CharReader::StructuredError>
CharReader::getStructuredErrors() const {
return _impl->getStructuredErrors();
}
bool CharReader::parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) {
return _impl->parse(beginDoc, endDoc, root, errs);
}
////////////////////////////////// //////////////////////////////////
// global functions // global functions
@ -1984,7 +1996,7 @@ bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root,
String* errs) { String* errs) {
OStringStream ssin; OStringStream ssin;
ssin << sin.rdbuf(); ssin << sin.rdbuf();
String doc = ssin.str(); String doc = std::move(ssin).str();
char const* begin = doc.data(); char const* begin = doc.data();
char const* end = begin + doc.size(); char const* end = begin + doc.size();
// Note that we do not actually need a null-terminator. // Note that we do not actually need a null-terminator.

View File

@ -1092,6 +1092,9 @@ Value const* Value::find(char const* begin, char const* end) const {
return nullptr; return nullptr;
return &(*it).second; return &(*it).second;
} }
Value const* Value::find(const String& key) const {
return find(key.data(), key.data() + key.length());
}
Value* Value::demand(char const* begin, char const* end) { Value* Value::demand(char const* begin, char const* end) {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
"in Json::Value::demand(begin, end): requires " "in Json::Value::demand(begin, end): requires "
@ -1105,7 +1108,7 @@ const Value& Value::operator[](const char* key) const {
return *found; return *found;
} }
Value const& Value::operator[](const String& key) const { Value const& Value::operator[](const String& key) const {
Value const* found = find(key.data(), key.data() + key.length()); Value const* found = find(key);
if (!found) if (!found)
return nullSingleton(); return nullSingleton();
return *found; return *found;
@ -1205,7 +1208,7 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
return false; return false;
} }
if (removed) if (removed)
*removed = it->second; *removed = std::move(it->second);
ArrayIndex oldSize = size(); ArrayIndex oldSize = size();
// shift left all items left, into the place of the "removed" // shift left all items left, into the place of the "removed"
for (ArrayIndex i = index; i < (oldSize - 1); ++i) { for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
@ -1410,9 +1413,8 @@ void Value::setComment(String comment, CommentPlacement placement) {
// Always discard trailing newline, to aid indentation. // Always discard trailing newline, to aid indentation.
comment.pop_back(); comment.pop_back();
} }
JSON_ASSERT(!comment.empty());
JSON_ASSERT_MESSAGE( JSON_ASSERT_MESSAGE(
comment[0] == '\0' || comment[0] == '/', comment.empty() || comment[0] == '/',
"in Json::Value::setComment(): Comments must start with /"); "in Json::Value::setComment(): Comments must start with /");
comments_.set(placement, std::move(comment)); comments_.set(placement, std::move(comment));
} }

View File

@ -132,8 +132,9 @@ String valueToString(double value, bool useSpecialFloats,
if (!isfinite(value)) { if (!isfinite(value)) {
static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"}, static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"},
{"null", "-1e+9999", "1e+9999"}}; {"null", "-1e+9999", "1e+9999"}};
return reps[useSpecialFloats ? 0 : 1] return reps[useSpecialFloats ? 0 : 1][isnan(value) ? 0
[isnan(value) ? 0 : (value < 0) ? 1 : 2]; : (value < 0) ? 1
: 2];
} }
String buffer(size_t(36), '\0'); String buffer(size_t(36), '\0');
@ -353,6 +354,10 @@ String valueToQuotedString(const char* value) {
return valueToQuotedStringN(value, strlen(value)); return valueToQuotedStringN(value, strlen(value));
} }
String valueToQuotedString(const char* value, size_t length) {
return valueToQuotedStringN(value, length);
}
// Class Writer // Class Writer
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
Writer::~Writer() = default; Writer::~Writer() = default;
@ -490,7 +495,7 @@ void StyledWriter::writeValue(const Value& value) {
const String& name = *it; const String& name = *it;
const Value& childValue = value[name]; const Value& childValue = value[name];
writeCommentBeforeValue(childValue); writeCommentBeforeValue(childValue);
writeWithIndent(valueToQuotedString(name.c_str())); writeWithIndent(valueToQuotedString(name.c_str(), name.size()));
document_ += " : "; document_ += " : ";
writeValue(childValue); writeValue(childValue);
if (++it == members.end()) { if (++it == members.end()) {
@ -708,7 +713,7 @@ void StyledStreamWriter::writeValue(const Value& value) {
const String& name = *it; const String& name = *it;
const Value& childValue = value[name]; const Value& childValue = value[name];
writeCommentBeforeValue(childValue); writeCommentBeforeValue(childValue);
writeWithIndent(valueToQuotedString(name.c_str())); writeWithIndent(valueToQuotedString(name.c_str(), name.size()));
*document_ << " : "; *document_ << " : ";
writeValue(childValue); writeValue(childValue);
if (++it == members.end()) { if (++it == members.end()) {
@ -1246,7 +1251,7 @@ String writeString(StreamWriter::Factory const& factory, Value const& root) {
OStringStream sout; OStringStream sout;
StreamWriterPtr const writer(factory.newStreamWriter()); StreamWriterPtr const writer(factory.newStreamWriter());
writer->write(root, &sout); writer->write(root, &sout);
return sout.str(); return std::move(sout).str();
} }
OStream& operator<<(OStream& sout, Value const& root) { OStream& operator<<(OStream& sout, Value const& root) {