Compare commits

...

9 Commits

Author SHA1 Message Date
Christopher Dunn
656ac5272c partially revert 'Added features that allow the reader to accept common non-standard JSON.'
revert '642befc836ac5093b528e7d8b4fd66b66735a98c',
but keep the *added* methods for `decodedNumber()` and `decodedDouble()`.
2015-02-18 09:26:28 -06:00
Christopher Dunn
bfb149a1c9 partially revert 'fix bug for static init'
re: 28836b8acc2c002b0488c13dba28fd5be864970a

A global instance of a Value (viz. 'null') was a mistake,
but dropping it breaks binary-compatibility. So we will keep it
everywhere except the one platform where it was crashing, ARM.
2015-02-18 09:26:28 -06:00
Christopher Dunn
09fcd0acb2 revert 'Made it possible to drop null placeholders from array output.'
revert ae3c7a7aabfb345968a65001ea9bc25f1e2bb405
2015-02-18 09:26:27 -06:00
Christopher Dunn
eac41ec412 Revert "added option to FastWriter which omits the trailing new line character"
This reverts commit 5bf16105b5a90f9fa7d5d4d43452feee46603a52.
2015-02-18 09:26:27 -06:00
Christopher Dunn
8719073307 revert 'Added structured error reporting to Reader.'
revert 68db6553471bb9cb050b1bb888b5933ee758b82d
issue #147
2015-02-18 09:26:27 -06:00
Christopher Dunn
1b09a82fdd revert 'Add public semantic error reporting'
for binary-compatibility with 0.6.0
issue #147
was #57
2015-02-18 09:26:27 -06:00
Christopher Dunn
096c81de85 Revert "Switch to copy-and-swap idiom for operator=."
This reverts commit 45cd9490cd261da31cef84a44d2c587be7e26e99.

Ignored ValueInternal* changes, since those did not produce symbols for
Debian build. (They must not have used the INTERNAL stuff.)

  https://github.com/open-source-parsers/jsoncpp/issues/78

Conflicts:
	include/json/value.h
	src/lib_json/json_internalarray.inl
	src/lib_json/json_internalmap.inl
	src/lib_json/json_value.cpp
2015-02-18 09:26:27 -06:00
Christopher Dunn
2c1f9195d6 NOT C++11 2015-02-18 09:26:26 -06:00
Christopher Dunn
1416f58707 0.8.z 2015-02-18 09:26:26 -06:00
11 changed files with 46 additions and 372 deletions

View File

@ -85,10 +85,10 @@ endif( MSVC )
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# using regular Clang or AppleClang # using regular Clang or AppleClang
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# using GCC # using GCC
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -Wextra -pedantic") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic")
endif() endif()
IF(JSONCPP_WITH_WARNING_AS_ERROR) IF(JSONCPP_WITH_WARNING_AS_ERROR)

View File

@ -44,12 +44,6 @@ public:
/// \c true if root must be either an array or an object value. Default: \c /// \c true if root must be either an array or an object value. Default: \c
/// false. /// false.
bool strictRoot_; bool strictRoot_;
/// \c true if dropped null placeholders are allowed. Default: \c false.
bool allowDroppedNullPlaceholders_;
/// \c true if numeric object key are allowed. Default: \c false.
bool allowNumericKeys_;
}; };
} // namespace Json } // namespace Json

View File

@ -35,18 +35,6 @@ public:
typedef char Char; typedef char Char;
typedef const Char* Location; typedef const Char* Location;
/** \brief An error tagged with where in the JSON text it was encountered.
*
* The offsets give the [start, limit) range of bytes within the text. Note
* that this is bytes, not codepoints.
*
*/
struct StructuredError {
size_t offset_start;
size_t offset_limit;
std::string message;
};
/** \brief Constructs a Reader allowing all features /** \brief Constructs a Reader allowing all features
* for parsing. * for parsing.
*/ */
@ -123,38 +111,6 @@ public:
*/ */
std::string getFormattedErrorMessages() const; std::string getFormattedErrorMessages() const;
/** \brief Returns a vector of structured erros encounted while parsing.
* \return A (possibly empty) vector of StructuredError objects. Currently
* only one error can be returned, but the caller should tolerate
* multiple
* errors. This can occur if the parser recovers from a non-fatal
* parse error and then encounters additional errors.
*/
std::vector<StructuredError> getStructuredErrors() const;
/** \brief Add a semantic error message.
* \param value JSON Value location associated with the error
* \param message The error message.
* \return \c true if the error was successfully added, \c false if the
* Value offset exceeds the document size.
*/
bool pushError(const Value& value, const std::string& message);
/** \brief Add a semantic error message with extra context.
* \param value JSON Value location associated with the error
* \param message The error message.
* \param extra Additional JSON Value location to contextualize the error
* \return \c true if the error was successfully added, \c false if either
* Value offset exceeds the document size.
*/
bool pushError(const Value& value, const std::string& message, const Value& extra);
/** \brief Return whether there are any errors.
* \return \c true if there are no errors to report \c false if
* errors have occurred.
*/
bool good() const;
private: private:
enum TokenType { enum TokenType {
tokenEndOfStream = 0, tokenEndOfStream = 0,

View File

@ -133,8 +133,11 @@ public:
typedef Json::LargestUInt LargestUInt; typedef Json::LargestUInt LargestUInt;
typedef Json::ArrayIndex ArrayIndex; typedef Json::ArrayIndex ArrayIndex;
static const Value& null; ///! We regret this reference to a global instance; prefer the simpler Value(). static const Value& nullRef;
static const Value& nullRef; ///! just a kludge for binary-compatibility; same as null #if !defined(__ARMEL__)
/// \deprecated This exists for binary compatibility only. Use nullRef.
static const Value null;
#endif
/// Minimum signed integer value that can be stored in a Json::Value. /// Minimum signed integer value that can be stored in a Json::Value.
static const LargestInt minLargestInt; static const LargestInt minLargestInt;
/// Maximum signed integer value that can be stored in a Json::Value. /// Maximum signed integer value that can be stored in a Json::Value.
@ -172,7 +175,7 @@ private:
CZString(const char* cstr, DuplicationPolicy allocate); CZString(const char* cstr, DuplicationPolicy allocate);
CZString(const CZString& other); CZString(const CZString& other);
~CZString(); ~CZString();
CZString& operator=(CZString other); CZString &operator=(const CZString &other);
bool operator<(const CZString& other) const; bool operator<(const CZString& other) const;
bool operator==(const CZString& other) const; bool operator==(const CZString& other) const;
ArrayIndex index() const; ArrayIndex index() const;
@ -241,7 +244,7 @@ Json::Value obj_value(Json::objectValue); // {}
~Value(); ~Value();
// Deep copy, then swap(other). // Deep copy, then swap(other).
Value& operator=(Value other); Value &operator=(const Value &other);
/// Swap everything. /// Swap everything.
void swap(Value& other); void swap(Value& other);
/// Swap values but leave comments and source offsets in place. /// Swap values but leave comments and source offsets in place.
@ -451,13 +454,6 @@ Json::Value obj_value(Json::objectValue); // {}
iterator begin(); iterator begin();
iterator end(); iterator end();
// Accessors for the [start, limit) range of bytes within the JSON text from
// which this value was parsed, if any.
void setOffsetStart(size_t start);
void setOffsetLimit(size_t limit);
size_t getOffsetStart() const;
size_t getOffsetLimit() const;
private: private:
void initBasic(ValueType type, bool allocated = false); void initBasic(ValueType type, bool allocated = false);
@ -514,11 +510,6 @@ private:
unsigned int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. unsigned int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
#endif #endif
CommentInfo* comments_; CommentInfo* comments_;
// [start, limit) byte offsets in the source JSON text from which this Value
// was extracted.
size_t start_;
size_t limit_;
}; };
/** \brief Experimental and untested: represents an element of the "path" to /** \brief Experimental and untested: represents an element of the "path" to

View File

@ -4,9 +4,9 @@
#ifndef JSON_VERSION_H_INCLUDED #ifndef JSON_VERSION_H_INCLUDED
# define JSON_VERSION_H_INCLUDED # define JSON_VERSION_H_INCLUDED
# define JSONCPP_VERSION_STRING "1.4.3" # define JSONCPP_VERSION_STRING "0.8.3"
# define JSONCPP_VERSION_MAJOR 1 # define JSONCPP_VERSION_MAJOR 0
# define JSONCPP_VERSION_MINOR 4 # define JSONCPP_VERSION_MINOR 8
# define JSONCPP_VERSION_PATCH 3 # define JSONCPP_VERSION_PATCH 3
# define JSONCPP_VERSION_QUALIFIER # define JSONCPP_VERSION_QUALIFIER
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) # define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))

View File

@ -153,15 +153,6 @@ public:
void enableYAMLCompatibility(); void enableYAMLCompatibility();
/** \brief Drop the "null" string from the writer's output for nullValues.
* Strictly speaking, this is not valid JSON. But when the output is being
* fed to a browser's Javascript, it makes for smaller output and the
* browser can handle the output just fine.
*/
void dropNullPlaceholders();
void omitEndingLineFeed();
public: // overridden from Writer public: // overridden from Writer
virtual std::string write(const Value& root); virtual std::string write(const Value& root);
@ -170,8 +161,6 @@ private:
std::string document_; std::string document_;
bool yamlCompatiblityEnabled_; bool yamlCompatiblityEnabled_;
bool dropNullPlaceholders_;
bool omitEndingLineFeed_;
}; };
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a

View File

@ -43,17 +43,14 @@ typedef std::auto_ptr<CharReader> CharReaderPtr;
// //////////////////////////////// // ////////////////////////////////
Features::Features() Features::Features()
: allowComments_(true), strictRoot_(false), : allowComments_(true), strictRoot_(false)
allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} {}
Features Features::all() { return Features(); } Features Features::all() { return Features(); }
Features Features::strictMode() { Features Features::strictMode() {
Features features; Features features;
features.allowComments_ = false; features.allowComments_ = false;
features.strictRoot_ = true; features.strictRoot_ = true;
features.allowDroppedNullPlaceholders_ = false;
features.allowNumericKeys_ = false;
return features; return features;
} }
@ -163,11 +160,9 @@ bool Reader::readValue() {
switch (token.type_) { switch (token.type_) {
case tokenObjectBegin: case tokenObjectBegin:
successful = readObject(token); successful = readObject(token);
currentValue().setOffsetLimit(current_ - begin_);
break; break;
case tokenArrayBegin: case tokenArrayBegin:
successful = readArray(token); successful = readArray(token);
currentValue().setOffsetLimit(current_ - begin_);
break; break;
case tokenNumber: case tokenNumber:
successful = decodeNumber(token); successful = decodeNumber(token);
@ -179,41 +174,22 @@ bool Reader::readValue() {
{ {
Value v(true); Value v(true);
currentValue().swapPayload(v); currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} }
break; break;
case tokenFalse: case tokenFalse:
{ {
Value v(false); Value v(false);
currentValue().swapPayload(v); currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} }
break; break;
case tokenNull: case tokenNull:
{ {
Value v; Value v;
currentValue().swapPayload(v); currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} }
break; break;
case tokenArraySeparator:
if (features_.allowDroppedNullPlaceholders_) {
// "Un-read" the current token and mark the current value as a null
// token.
current_--;
Value v;
currentValue().swapPayload(v);
currentValue().setOffsetStart(current_ - begin_ - 1);
currentValue().setOffsetLimit(current_ - begin_);
break;
}
// Else, fall through... // Else, fall through...
default: default:
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return addError("Syntax error: value, object or array expected.", token); return addError("Syntax error: value, object or array expected.", token);
} }
@ -441,12 +417,11 @@ bool Reader::readString() {
return c == '"'; return c == '"';
} }
bool Reader::readObject(Token& tokenStart) { bool Reader::readObject(Token& /*tokenStart*/) {
Token tokenName; Token tokenName;
std::string name; std::string name;
Value init(objectValue); Value init(objectValue);
currentValue().swapPayload(init); currentValue().swapPayload(init);
currentValue().setOffsetStart(tokenStart.start_ - begin_);
while (readToken(tokenName)) { while (readToken(tokenName)) {
bool initialTokenOk = true; bool initialTokenOk = true;
while (tokenName.type_ == tokenComment && initialTokenOk) while (tokenName.type_ == tokenComment && initialTokenOk)
@ -459,11 +434,6 @@ bool Reader::readObject(Token& tokenStart) {
if (tokenName.type_ == tokenString) { if (tokenName.type_ == tokenString) {
if (!decodeString(tokenName, name)) if (!decodeString(tokenName, name))
return recoverFromError(tokenObjectEnd); return recoverFromError(tokenObjectEnd);
} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
Value numberName;
if (!decodeNumber(tokenName, numberName))
return recoverFromError(tokenObjectEnd);
name = numberName.asString();
} else { } else {
break; break;
} }
@ -497,10 +467,9 @@ bool Reader::readObject(Token& tokenStart) {
"Missing '}' or object member name", tokenName, tokenObjectEnd); "Missing '}' or object member name", tokenName, tokenObjectEnd);
} }
bool Reader::readArray(Token& tokenStart) { bool Reader::readArray(Token& /*tokenStart*/) {
Value init(arrayValue); Value init(arrayValue);
currentValue().swapPayload(init); currentValue().swapPayload(init);
currentValue().setOffsetStart(tokenStart.start_ - begin_);
skipSpaces(); skipSpaces();
if (*current_ == ']') // empty array if (*current_ == ']') // empty array
{ {
@ -540,8 +509,6 @@ bool Reader::decodeNumber(Token& token) {
if (!decodeNumber(token, decoded)) if (!decodeNumber(token, decoded))
return false; return false;
currentValue().swapPayload(decoded); currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true; return true;
} }
@ -590,8 +557,6 @@ bool Reader::decodeDouble(Token& token) {
if (!decodeDouble(token, decoded)) if (!decodeDouble(token, decoded))
return false; return false;
currentValue().swapPayload(decoded); currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true; return true;
} }
@ -637,8 +602,6 @@ bool Reader::decodeString(Token& token) {
return false; return false;
Value decoded(decoded_string); Value decoded(decoded_string);
currentValue().swapPayload(decoded); currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true; return true;
} }
@ -850,59 +813,8 @@ std::string Reader::getFormattedErrorMessages() const {
return formattedMessage; return formattedMessage;
} }
std::vector<Reader::StructuredError> Reader::getStructuredErrors() const { // Reader
std::vector<Reader::StructuredError> allErrors; /////////////////////////
for (Errors::const_iterator itError = errors_.begin();
itError != errors_.end();
++itError) {
const ErrorInfo& error = *itError;
Reader::StructuredError structured;
structured.offset_start = error.token_.start_ - begin_;
structured.offset_limit = error.token_.end_ - begin_;
structured.message = error.message_;
allErrors.push_back(structured);
}
return allErrors;
}
bool Reader::pushError(const Value& value, const std::string& message) {
size_t length = end_ - begin_;
if(value.getOffsetStart() > length
|| value.getOffsetLimit() > length)
return false;
Token token;
token.type_ = tokenError;
token.start_ = begin_ + value.getOffsetStart();
token.end_ = end_ + value.getOffsetLimit();
ErrorInfo info;
info.token_ = token;
info.message_ = message;
info.extra_ = 0;
errors_.push_back(info);
return true;
}
bool Reader::pushError(const Value& value, const std::string& message, const Value& extra) {
size_t length = end_ - begin_;
if(value.getOffsetStart() > length
|| value.getOffsetLimit() > length
|| extra.getOffsetLimit() > length)
return false;
Token token;
token.type_ = tokenError;
token.start_ = begin_ + value.getOffsetStart();
token.end_ = begin_ + value.getOffsetLimit();
ErrorInfo info;
info.token_ = token;
info.message_ = message;
info.extra_ = begin_ + extra.getOffsetStart();
errors_.push_back(info);
return true;
}
bool Reader::good() const {
return !errors_.size();
}
// exact copy of Features // exact copy of Features
class OurFeatures { class OurFeatures {
@ -956,10 +868,6 @@ public:
Value& root, Value& root,
bool collectComments = true); bool collectComments = true);
std::string getFormattedErrorMessages() const; std::string getFormattedErrorMessages() const;
std::vector<StructuredError> getStructuredErrors() const;
bool pushError(const Value& value, const std::string& message);
bool pushError(const Value& value, const std::string& message, const Value& extra);
bool good() const;
private: private:
OurReader(OurReader const&); // no impl OurReader(OurReader const&); // no impl
@ -1123,11 +1031,9 @@ bool OurReader::readValue() {
switch (token.type_) { switch (token.type_) {
case tokenObjectBegin: case tokenObjectBegin:
successful = readObject(token); successful = readObject(token);
currentValue().setOffsetLimit(current_ - begin_);
break; break;
case tokenArrayBegin: case tokenArrayBegin:
successful = readArray(token); successful = readArray(token);
currentValue().setOffsetLimit(current_ - begin_);
break; break;
case tokenNumber: case tokenNumber:
successful = decodeNumber(token); successful = decodeNumber(token);
@ -1139,24 +1045,18 @@ bool OurReader::readValue() {
{ {
Value v(true); Value v(true);
currentValue().swapPayload(v); currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} }
break; break;
case tokenFalse: case tokenFalse:
{ {
Value v(false); Value v(false);
currentValue().swapPayload(v); currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} }
break; break;
case tokenNull: case tokenNull:
{ {
Value v; Value v;
currentValue().swapPayload(v); currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
} }
break; break;
case tokenArraySeparator: case tokenArraySeparator:
@ -1166,14 +1066,10 @@ bool OurReader::readValue() {
current_--; current_--;
Value v; Value v;
currentValue().swapPayload(v); currentValue().swapPayload(v);
currentValue().setOffsetStart(current_ - begin_ - 1);
currentValue().setOffsetLimit(current_ - begin_);
break; break;
} }
// Else, fall through... // Else, fall through...
default: default:
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return addError("Syntax error: value, object or array expected.", token); return addError("Syntax error: value, object or array expected.", token);
} }
@ -1387,7 +1283,6 @@ bool OurReader::readObject(Token& tokenStart) {
std::string name; std::string name;
Value init(objectValue); Value init(objectValue);
currentValue().swapPayload(init); currentValue().swapPayload(init);
currentValue().setOffsetStart(tokenStart.start_ - begin_);
while (readToken(tokenName)) { while (readToken(tokenName)) {
bool initialTokenOk = true; bool initialTokenOk = true;
while (tokenName.type_ == tokenComment && initialTokenOk) while (tokenName.type_ == tokenComment && initialTokenOk)
@ -1441,7 +1336,6 @@ bool OurReader::readObject(Token& tokenStart) {
bool OurReader::readArray(Token& tokenStart) { bool OurReader::readArray(Token& tokenStart) {
Value init(arrayValue); Value init(arrayValue);
currentValue().swapPayload(init); currentValue().swapPayload(init);
currentValue().setOffsetStart(tokenStart.start_ - begin_);
skipSpaces(); skipSpaces();
if (*current_ == ']') // empty array if (*current_ == ']') // empty array
{ {
@ -1481,8 +1375,6 @@ bool OurReader::decodeNumber(Token& token) {
if (!decodeNumber(token, decoded)) if (!decodeNumber(token, decoded))
return false; return false;
currentValue().swapPayload(decoded); currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true; return true;
} }
@ -1531,8 +1423,6 @@ bool OurReader::decodeDouble(Token& token) {
if (!decodeDouble(token, decoded)) if (!decodeDouble(token, decoded))
return false; return false;
currentValue().swapPayload(decoded); currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true; return true;
} }
@ -1578,8 +1468,6 @@ bool OurReader::decodeString(Token& token) {
return false; return false;
Value decoded(decoded_string); Value decoded(decoded_string);
currentValue().swapPayload(decoded); currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true; return true;
} }
@ -1786,60 +1674,6 @@ std::string OurReader::getFormattedErrorMessages() const {
return formattedMessage; return formattedMessage;
} }
std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
std::vector<OurReader::StructuredError> allErrors;
for (Errors::const_iterator itError = errors_.begin();
itError != errors_.end();
++itError) {
const ErrorInfo& error = *itError;
OurReader::StructuredError structured;
structured.offset_start = error.token_.start_ - begin_;
structured.offset_limit = error.token_.end_ - begin_;
structured.message = error.message_;
allErrors.push_back(structured);
}
return allErrors;
}
bool OurReader::pushError(const Value& value, const std::string& message) {
size_t length = end_ - begin_;
if(value.getOffsetStart() > length
|| value.getOffsetLimit() > length)
return false;
Token token;
token.type_ = tokenError;
token.start_ = begin_ + value.getOffsetStart();
token.end_ = end_ + value.getOffsetLimit();
ErrorInfo info;
info.token_ = token;
info.message_ = message;
info.extra_ = 0;
errors_.push_back(info);
return true;
}
bool OurReader::pushError(const Value& value, const std::string& message, const Value& extra) {
size_t length = end_ - begin_;
if(value.getOffsetStart() > length
|| value.getOffsetLimit() > length
|| extra.getOffsetLimit() > length)
return false;
Token token;
token.type_ = tokenError;
token.start_ = begin_ + value.getOffsetStart();
token.end_ = begin_ + value.getOffsetLimit();
ErrorInfo info;
info.token_ = token;
info.message_ = message;
info.extra_ = begin_ + extra.getOffsetStart();
errors_.push_back(info);
return true;
}
bool OurReader::good() const {
return !errors_.size();
}
class OurCharReader : public CharReader { class OurCharReader : public CharReader {
bool const collectComments_; bool const collectComments_;

View File

@ -31,12 +31,13 @@ namespace Json {
#if defined(__ARMEL__) #if defined(__ARMEL__)
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
#else #else
// This exists for binary compatibility only. Use nullRef.
static const Value null;
#define ALIGNAS(byte_alignment) #define ALIGNAS(byte_alignment)
#endif #endif
static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
const unsigned char& kNullRef = kNull[0]; const unsigned char& kNullRef = kNull[0];
const Value& Value::null = reinterpret_cast<const Value&>(kNullRef); const Value& Value::nullRef = reinterpret_cast<const Value&>(kNullRef);
const Value& Value::nullRef = null;
const Int Value::minInt = Int(~(UInt(-1) / 2)); const Int Value::minInt = Int(~(UInt(-1) / 2));
const Int Value::maxInt = Int(UInt(-1) / 2); const Int Value::maxInt = Int(UInt(-1) / 2);
@ -192,8 +193,9 @@ void Value::CZString::swap(CZString& other) {
std::swap(index_, other.index_); std::swap(index_, other.index_);
} }
Value::CZString& Value::CZString::operator=(CZString other) { Value::CZString &Value::CZString::operator=(const CZString &other) {
swap(other); CZString temp(other);
swap(temp);
return *this; return *this;
} }
@ -331,7 +333,7 @@ Value::Value(const Value& other)
itemIsUsed_(0) itemIsUsed_(0)
#endif #endif
, ,
comments_(0), start_(other.start_), limit_(other.limit_) { comments_(0) {
switch (type_) { switch (type_) {
case nullValue: case nullValue:
case intValue: case intValue:
@ -409,8 +411,9 @@ Value::~Value() {
delete[] comments_; delete[] comments_;
} }
Value& Value::operator=(Value other) { Value &Value::operator=(const Value &other) {
swap(other); Value temp(other);
swap(temp);
return *this; return *this;
} }
@ -427,8 +430,6 @@ void Value::swapPayload(Value& other) {
void Value::swap(Value& other) { void Value::swap(Value& other) {
swapPayload(other); swapPayload(other);
std::swap(comments_, other.comments_); std::swap(comments_, other.comments_);
std::swap(start_, other.start_);
std::swap(limit_, other.limit_);
} }
ValueType Value::type() const { return type_; } ValueType Value::type() const { return type_; }
@ -803,8 +804,6 @@ void Value::clear() {
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
type_ == objectValue, type_ == objectValue,
"in Json::Value::clear(): requires complex value"); "in Json::Value::clear(): requires complex value");
start_ = 0;
limit_ = 0;
switch (type_) { switch (type_) {
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
case arrayValue: case arrayValue:
@ -858,7 +857,7 @@ Value& Value::operator[](ArrayIndex index) {
if (it != value_.map_->end() && (*it).first == key) if (it != value_.map_->end() && (*it).first == key)
return (*it).second; return (*it).second;
ObjectValues::value_type defaultValue(key, null); ObjectValues::value_type defaultValue(key, nullRef);
it = value_.map_->insert(it, defaultValue); it = value_.map_->insert(it, defaultValue);
return (*it).second; return (*it).second;
#else #else
@ -878,16 +877,16 @@ const Value& Value::operator[](ArrayIndex index) const {
type_ == nullValue || type_ == arrayValue, type_ == nullValue || type_ == arrayValue,
"in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
if (type_ == nullValue) if (type_ == nullValue)
return null; return nullRef;
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
CZString key(index); CZString key(index);
ObjectValues::const_iterator it = value_.map_->find(key); ObjectValues::const_iterator it = value_.map_->find(key);
if (it == value_.map_->end()) if (it == value_.map_->end())
return null; return nullRef;
return (*it).second; return (*it).second;
#else #else
Value* value = value_.array_->find(index); Value* value = value_.array_->find(index);
return value ? *value : null; return value ? *value : nullRef;
#endif #endif
} }
@ -909,8 +908,6 @@ void Value::initBasic(ValueType type, bool allocated) {
itemIsUsed_ = 0; itemIsUsed_ = 0;
#endif #endif
comments_ = 0; comments_ = 0;
start_ = 0;
limit_ = 0;
} }
Value& Value::resolveReference(const char* key, bool isStatic) { Value& Value::resolveReference(const char* key, bool isStatic) {
@ -926,7 +923,7 @@ Value& Value::resolveReference(const char* key, bool isStatic) {
if (it != value_.map_->end() && (*it).first == actualKey) if (it != value_.map_->end() && (*it).first == actualKey)
return (*it).second; return (*it).second;
ObjectValues::value_type defaultValue(actualKey, null); ObjectValues::value_type defaultValue(actualKey, nullRef);
it = value_.map_->insert(it, defaultValue); it = value_.map_->insert(it, defaultValue);
Value& value = (*it).second; Value& value = (*it).second;
return value; return value;
@ -937,7 +934,7 @@ Value& Value::resolveReference(const char* key, bool isStatic) {
Value Value::get(ArrayIndex index, const Value& defaultValue) const { Value Value::get(ArrayIndex index, const Value& defaultValue) const {
const Value* value = &((*this)[index]); const Value* value = &((*this)[index]);
return value == &null ? defaultValue : *value; return value == &nullRef ? defaultValue : *value;
} }
bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
@ -947,16 +944,16 @@ const Value& Value::operator[](const char* key) const {
type_ == nullValue || type_ == objectValue, type_ == nullValue || type_ == objectValue,
"in Json::Value::operator[](char const*)const: requires objectValue"); "in Json::Value::operator[](char const*)const: requires objectValue");
if (type_ == nullValue) if (type_ == nullValue)
return null; return nullRef;
#ifndef JSON_VALUE_USE_INTERNAL_MAP #ifndef JSON_VALUE_USE_INTERNAL_MAP
CZString actualKey(key, CZString::noDuplication); CZString actualKey(key, CZString::noDuplication);
ObjectValues::const_iterator it = value_.map_->find(actualKey); ObjectValues::const_iterator it = value_.map_->find(actualKey);
if (it == value_.map_->end()) if (it == value_.map_->end())
return null; return nullRef;
return (*it).second; return (*it).second;
#else #else
const Value* value = value_.map_->find(key); const Value* value = value_.map_->find(key);
return value ? *value : null; return value ? *value : nullRef;
#endif #endif
} }
@ -986,7 +983,7 @@ Value& Value::append(const Value& value) { return (*this)[size()] = value; }
Value Value::get(const char* key, const Value& defaultValue) const { Value Value::get(const char* key, const Value& defaultValue) const {
const Value* value = &((*this)[key]); const Value* value = &((*this)[key]);
return value == &null ? defaultValue : *value; return value == &nullRef ? defaultValue : *value;
} }
Value Value::get(const std::string& key, const Value& defaultValue) const { Value Value::get(const std::string& key, const Value& defaultValue) const {
@ -1022,7 +1019,7 @@ Value Value::removeMember(const char* key) {
JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
"in Json::Value::removeMember(): requires objectValue"); "in Json::Value::removeMember(): requires objectValue");
if (type_ == nullValue) if (type_ == nullValue)
return null; return nullRef;
Value removed; // null Value removed; // null
removeMember(key, &removed); removeMember(key, &removed);
@ -1070,7 +1067,7 @@ Value Value::get(const CppTL::ConstString& key,
bool Value::isMember(const char* key) const { bool Value::isMember(const char* key) const {
const Value* value = &((*this)[key]); const Value* value = &((*this)[key]);
return value != &null; return value != &nullRef;
} }
bool Value::isMember(const std::string& key) const { bool Value::isMember(const std::string& key) const {
@ -1257,14 +1254,6 @@ std::string Value::getComment(CommentPlacement placement) const {
return ""; return "";
} }
void Value::setOffsetStart(size_t start) { start_ = start; }
void Value::setOffsetLimit(size_t limit) { limit_ = limit; }
size_t Value::getOffsetStart() const { return start_; }
size_t Value::getOffsetLimit() const { return limit_; }
std::string Value::toStyledString() const { std::string Value::toStyledString() const {
StyledWriter writer; StyledWriter writer;
return writer.write(*this); return writer.write(*this);
@ -1484,7 +1473,7 @@ const Value& Path::resolve(const Value& root) const {
// Error: unable to resolve path (object value expected at position...) // Error: unable to resolve path (object value expected at position...)
} }
node = &((*node)[arg.key_]); node = &((*node)[arg.key_]);
if (node == &Value::null) { if (node == &Value::nullRef) {
// Error: unable to resolve path (object has no member named '' at // Error: unable to resolve path (object has no member named '' at
// position...) // position...)
} }
@ -1505,7 +1494,7 @@ Value Path::resolve(const Value& root, const Value& defaultValue) const {
if (!node->isObject()) if (!node->isObject())
return defaultValue; return defaultValue;
node = &((*node)[arg.key_]); node = &((*node)[arg.key_]);
if (node == &Value::null) if (node == &Value::nullRef)
return defaultValue; return defaultValue;
} }
} }

View File

@ -192,28 +192,21 @@ Writer::~Writer() {}
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
FastWriter::FastWriter() FastWriter::FastWriter()
: yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), : yamlCompatiblityEnabled_(false) {}
omitEndingLineFeed_(false) {}
void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
std::string FastWriter::write(const Value& root) { std::string FastWriter::write(const Value& root) {
document_ = ""; document_ = "";
writeValue(root); writeValue(root);
if (!omitEndingLineFeed_) document_ += "\n";
document_ += "\n";
return document_; return document_;
} }
void FastWriter::writeValue(const Value& value) { void FastWriter::writeValue(const Value& value) {
switch (value.type()) { switch (value.type()) {
case nullValue: case nullValue:
if (!dropNullPlaceholders_) document_ += "null";
document_ += "null";
break; break;
case intValue: case intValue:
document_ += valueToString(value.asLargestInt()); document_ += valueToString(value.asLargestInt());

View File

@ -1497,36 +1497,6 @@ JSONTEST_FIXTURE(ValueTest, typeChecksThrowExceptions) {
#endif #endif
} }
JSONTEST_FIXTURE(ValueTest, offsetAccessors) {
Json::Value x;
JSONTEST_ASSERT(x.getOffsetStart() == 0);
JSONTEST_ASSERT(x.getOffsetLimit() == 0);
x.setOffsetStart(10);
x.setOffsetLimit(20);
JSONTEST_ASSERT(x.getOffsetStart() == 10);
JSONTEST_ASSERT(x.getOffsetLimit() == 20);
Json::Value y(x);
JSONTEST_ASSERT(y.getOffsetStart() == 10);
JSONTEST_ASSERT(y.getOffsetLimit() == 20);
Json::Value z;
z.swap(y);
JSONTEST_ASSERT(z.getOffsetStart() == 10);
JSONTEST_ASSERT(z.getOffsetLimit() == 20);
JSONTEST_ASSERT(y.getOffsetStart() == 0);
JSONTEST_ASSERT(y.getOffsetLimit() == 0);
}
struct WriterTest : JsonTest::TestCase {};
JSONTEST_FIXTURE(WriterTest, dropNullPlaceholders) {
Json::FastWriter writer;
Json::Value nullValue;
JSONTEST_ASSERT(writer.write(nullValue) == "null\n");
writer.dropNullPlaceholders();
JSONTEST_ASSERT(writer.write(nullValue) == "\n");
}
struct StreamWriterTest : JsonTest::TestCase {}; struct StreamWriterTest : JsonTest::TestCase {};
JSONTEST_FIXTURE(StreamWriterTest, dropNullPlaceholders) { JSONTEST_FIXTURE(StreamWriterTest, dropNullPlaceholders) {
@ -1546,7 +1516,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithNoErrors) {
bool ok = reader.parse("{ \"property\" : \"value\" }", root); bool ok = reader.parse("{ \"property\" : \"value\" }", root);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0); JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0);
JSONTEST_ASSERT(reader.getStructuredErrors().size() == 0);
} }
JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) { JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) {
@ -1558,25 +1527,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) {
root); root);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0); JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0);
JSONTEST_ASSERT(reader.getStructuredErrors().size() == 0);
JSONTEST_ASSERT(root["property"].getOffsetStart() == 15);
JSONTEST_ASSERT(root["property"].getOffsetLimit() == 34);
JSONTEST_ASSERT(root["property"][0].getOffsetStart() == 16);
JSONTEST_ASSERT(root["property"][0].getOffsetLimit() == 23);
JSONTEST_ASSERT(root["property"][1].getOffsetStart() == 25);
JSONTEST_ASSERT(root["property"][1].getOffsetLimit() == 33);
JSONTEST_ASSERT(root["obj"].getOffsetStart() == 44);
JSONTEST_ASSERT(root["obj"].getOffsetLimit() == 76);
JSONTEST_ASSERT(root["obj"]["nested"].getOffsetStart() == 57);
JSONTEST_ASSERT(root["obj"]["nested"].getOffsetLimit() == 60);
JSONTEST_ASSERT(root["obj"]["bool"].getOffsetStart() == 71);
JSONTEST_ASSERT(root["obj"]["bool"].getOffsetLimit() == 75);
JSONTEST_ASSERT(root["null"].getOffsetStart() == 87);
JSONTEST_ASSERT(root["null"].getOffsetLimit() == 91);
JSONTEST_ASSERT(root["false"].getOffsetStart() == 103);
JSONTEST_ASSERT(root["false"].getOffsetLimit() == 108);
JSONTEST_ASSERT(root.getOffsetStart() == 0);
JSONTEST_ASSERT(root.getOffsetLimit() == 110);
} }
JSONTEST_FIXTURE(ReaderTest, parseWithOneError) { JSONTEST_FIXTURE(ReaderTest, parseWithOneError) {
@ -1587,13 +1537,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithOneError) {
JSONTEST_ASSERT(reader.getFormattedErrorMessages() == JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
"* Line 1, Column 15\n Syntax error: value, object or array " "* Line 1, Column 15\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
std::vector<Json::Reader::StructuredError> errors =
reader.getStructuredErrors();
JSONTEST_ASSERT(errors.size() == 1);
JSONTEST_ASSERT(errors.at(0).offset_start == 14);
JSONTEST_ASSERT(errors.at(0).offset_limit == 15);
JSONTEST_ASSERT(errors.at(0).message ==
"Syntax error: value, object or array expected.");
} }
JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) { JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) {
@ -1604,13 +1547,6 @@ JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) {
JSONTEST_ASSERT(reader.getFormattedErrorMessages() == JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
"* Line 1, Column 19\n Syntax error: value, object or array " "* Line 1, Column 19\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
std::vector<Json::Reader::StructuredError> errors =
reader.getStructuredErrors();
JSONTEST_ASSERT(errors.size() == 1);
JSONTEST_ASSERT(errors.at(0).offset_start == 18);
JSONTEST_ASSERT(errors.at(0).offset_limit == 19);
JSONTEST_ASSERT(errors.at(0).message ==
"Syntax error: value, object or array expected.");
} }
JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) { JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) {
@ -1621,12 +1557,6 @@ JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) {
JSONTEST_ASSERT(reader.getFormattedErrorMessages() == JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
"* Line 1, Column 16\n Bad escape sequence in string\nSee " "* Line 1, Column 16\n Bad escape sequence in string\nSee "
"Line 1, Column 20 for detail.\n"); "Line 1, Column 20 for detail.\n");
std::vector<Json::Reader::StructuredError> errors =
reader.getStructuredErrors();
JSONTEST_ASSERT(errors.size() == 1);
JSONTEST_ASSERT(errors.at(0).offset_start == 15);
JSONTEST_ASSERT(errors.at(0).offset_limit == 23);
JSONTEST_ASSERT(errors.at(0).message == "Bad escape sequence in string");
} }
struct CharReaderTest : JsonTest::TestCase {}; struct CharReaderTest : JsonTest::TestCase {};
@ -1898,10 +1828,8 @@ int main(int argc, const char* argv[]) {
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareArray); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareArray);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareObject); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareObject);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareType); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareType);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, offsetAccessors);
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, typeChecksThrowExceptions); JSONTEST_REGISTER_FIXTURE(runner, ValueTest, typeChecksThrowExceptions);
JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders);
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders); JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders);
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithNoErrors); JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithNoErrors);

View File

@ -1 +1 @@
1.4.3 0.8.3