Floating-point NaN or Infinity values should be allowed as a feature #209

Introduce 'allowSpecialFloats' for readers and 'useSpecialFloats' for writers, use consistent macro snprintf definition for writers and readers, provide new unit tests for #209
This commit is contained in:
drgler
2015-09-03 22:19:22 +02:00
parent 6329975e6d
commit 2084563efb
5 changed files with 167 additions and 44 deletions

View File

@@ -17,10 +17,21 @@
#include <sstream>
#include <memory>
#include <set>
#include <limits>
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
#if defined(_MSC_VER)
#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
#define snprintf sprintf_s
#elif _MSC_VER >= 1900 // VC++ 14.0 and above
#define snprintf std::snprintf
#else
#define snprintf _snprintf
#endif
#elif defined(__ANDROID__)
#define snprintf snprintf
#elif __cplusplus >= 201103L
#define snprintf std::snprintf
#endif
#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
// Disable warning about strdup being deprecated.
@@ -795,15 +806,7 @@ std::string Reader::getLocationLineAndColumn(Location location) const {
int line, column;
getLocationLineAndColumn(location, line, column);
char buffer[18 + 16 + 16 + 1];
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
#if defined(WINCE)
_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
#else
sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
#endif
#else
snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
#endif
return buffer;
}
@@ -894,6 +897,7 @@ public:
bool allowSingleQuotes_;
bool failIfExtra_;
bool rejectDupKeys_;
bool allowSpecialFloats_;
int stackLimit_;
}; // OurFeatures
@@ -905,6 +909,7 @@ OurFeatures::OurFeatures()
, allowDroppedNullPlaceholders_(false), allowNumericKeys_(false)
, allowSingleQuotes_(false)
, failIfExtra_(false)
, allowSpecialFloats_(false)
{
}
@@ -950,6 +955,9 @@ private:
tokenTrue,
tokenFalse,
tokenNull,
tokenNaN,
tokenPosInf,
tokenNegInf,
tokenArraySeparator,
tokenMemberSeparator,
tokenComment,
@@ -980,7 +988,7 @@ private:
bool readCppStyleComment();
bool readString();
bool readStringSingleQuote();
void readNumber();
bool readNumber();
bool readValue();
bool readObject(Token& token);
bool readArray(Token& token);
@@ -1134,6 +1142,30 @@ bool OurReader::readValue() {
currentValue().setOffsetLimit(token.end_ - begin_);
}
break;
case tokenNaN:
{
Value v(std::numeric_limits<double>::quiet_NaN());
currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
}
break;
case tokenPosInf:
{
Value v(std::numeric_limits<double>::infinity());
currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
}
break;
case tokenNegInf:
{
Value v(-std::numeric_limits<double>::infinity());
currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
}
break;
case tokenArraySeparator:
case tokenObjectEnd:
case tokenArrayEnd:
@@ -1215,8 +1247,12 @@ bool OurReader::readToken(Token& token) {
case '8':
case '9':
case '-':
token.type_ = tokenNumber;
readNumber();
if (readNumber()) {
token.type_ = tokenNumber;
} else {
token.type_ = tokenNegInf;
ok = features_.allowSpecialFloats_ && match("nfinity", 7);
}
break;
case 't':
token.type_ = tokenTrue;
@@ -1230,6 +1266,22 @@ bool OurReader::readToken(Token& token) {
token.type_ = tokenNull;
ok = match("ull", 3);
break;
case 'N':
if (features_.allowSpecialFloats_) {
token.type_ = tokenNaN;
ok = match("aN", 2);
} else {
ok = false;
}
break;
case 'I':
if (features_.allowSpecialFloats_) {
token.type_ = tokenPosInf;
ok = match("nfinity", 7);
} else {
ok = false;
}
break;
case ',':
token.type_ = tokenArraySeparator;
break;
@@ -1330,8 +1382,12 @@ bool OurReader::readCppStyleComment() {
return true;
}
void OurReader::readNumber() {
bool OurReader::readNumber() {
const char *p = current_;
if (p != end_ && *p == 'I') {
current_ = ++p;
return false;
}
char c = '0'; // stopgap for already consumed character
// integral part
while (c >= '0' && c <= '9')
@@ -1350,6 +1406,7 @@ void OurReader::readNumber() {
while (c >= '0' && c <= '9')
c = (current_ = p) < end_ ? *p++ : 0;
}
return true;
}
bool OurReader::readString() {
Char c = 0;
@@ -1758,15 +1815,7 @@ std::string OurReader::getLocationLineAndColumn(Location location) const {
int line, column;
getLocationLineAndColumn(location, line, column);
char buffer[18 + 16 + 16 + 1];
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
#if defined(WINCE)
_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
#else
sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
#endif
#else
snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
#endif
return buffer;
}
@@ -1880,6 +1929,7 @@ CharReader* CharReaderBuilder::newCharReader() const
features.stackLimit_ = settings_["stackLimit"].asInt();
features.failIfExtra_ = settings_["failIfExtra"].asBool();
features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
return new OurCharReader(collectComments, features);
}
static void getValidReaderKeys(std::set<std::string>* valid_keys)
@@ -1894,6 +1944,7 @@ static void getValidReaderKeys(std::set<std::string>* valid_keys)
valid_keys->insert("stackLimit");
valid_keys->insert("failIfExtra");
valid_keys->insert("rejectDupKeys");
valid_keys->insert("allowSpecialFloats");
}
bool CharReaderBuilder::validate(Json::Value* invalid) const
{
@@ -1927,6 +1978,7 @@ void CharReaderBuilder::strictMode(Json::Value* settings)
(*settings)["allowSingleQuotes"] = false;
(*settings)["failIfExtra"] = true;
(*settings)["rejectDupKeys"] = true;
(*settings)["allowSpecialFloats"] = false;
//! [CharReaderBuilderStrictMode]
}
// static
@@ -1942,6 +1994,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings)
(*settings)["stackLimit"] = 1000;
(*settings)["failIfExtra"] = false;
(*settings)["rejectDupKeys"] = false;
(*settings)["allowSpecialFloats"] = false;
//! [CharReaderBuilderDefaults]
}