careful handling of long numbers
This commit is contained in:
parent
18dc444caf
commit
c48253682f
@ -1440,12 +1440,14 @@ bool OurReader::readNumber(bool checkInf) {
|
|||||||
|
|
||||||
bool OurReader::readHexadecimal(void) {
|
bool OurReader::readHexadecimal(void) {
|
||||||
Location p = current_;
|
Location p = current_;
|
||||||
char c = '0'; // stopgap for already consumed character
|
for (; p < end_; ++p)
|
||||||
// integral part
|
{
|
||||||
while ((c >= '0' && c <= '9')
|
char c = *p;
|
||||||
|| (c >= 'a' && c <= 'f')
|
if ( (c < '0' || c > '9')
|
||||||
|| (c >= 'A' && c <= 'F'))
|
&& (c < 'a' || c > 'f')
|
||||||
c = (current_ = p) < end_ ? *p++ : '\0';
|
&& (c < 'A' || c > 'F') ) break;
|
||||||
|
}
|
||||||
|
current_ = p;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1680,23 +1682,24 @@ bool OurReader::decodeHexadecimal(Token& token) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool OurReader::decodeHexadecimal(Token& token, Value& decoded) {
|
bool OurReader::decodeHexadecimal(Token& token, Value& decoded) {
|
||||||
|
Location current = token.start_;
|
||||||
|
if (current < token.end_ && *current == '0') ++current;
|
||||||
|
if (current < token.end_ && *current == 'x') ++current;
|
||||||
Json::LargestUInt value = 0;
|
Json::LargestUInt value = 0;
|
||||||
constexpr Json::LargestUInt top =
|
if (current >= token.end_)
|
||||||
Json::LargestUInt(0xF) << ((sizeof(top) * 8) - 4);
|
return addError("Zero hexadecimal digits.", token);
|
||||||
|
if (current + (sizeof(value) * 2) < token.end_)
|
||||||
Location current = token.start_ + 2;
|
return addError("Token too long to be unsigned integer.", token, current);
|
||||||
while (current < token.end_) {
|
for (; current < token.end_; ++current) {
|
||||||
Char c = *current++;
|
Char c = *current;
|
||||||
if (c >= 'a')
|
if (c >= 'a')
|
||||||
c -= 'a' - 10;
|
c -= 'a' - 10;
|
||||||
else if (c >= 'A')
|
else if (c >= 'A')
|
||||||
c -= 'A' - 10;
|
c -= 'A' - 10;
|
||||||
else if (c >= '0')
|
else if (c >= '0')
|
||||||
c -= '0';
|
c -= '0';
|
||||||
else return addError(
|
else
|
||||||
"Contains non-hexadecimal digits.", token, current);
|
return addError("Contains non-hexadecimal digits.", token, current);
|
||||||
if (value & top) return addError(
|
|
||||||
"Number is too large for unsigned integer.", token, current);
|
|
||||||
value = value << 4 | static_cast<Value::UInt>(c);
|
value = value << 4 | static_cast<Value::UInt>(c);
|
||||||
}
|
}
|
||||||
decoded = value;
|
decoded = value;
|
||||||
|
@ -3564,7 +3564,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowHexadecimal, disallowHex) {
|
|||||||
Json::Value root;
|
Json::Value root;
|
||||||
Json::String errs;
|
Json::String errs;
|
||||||
{
|
{
|
||||||
char const doc[] = R"({"a": 0x01})";
|
char const doc[] = R"({ "a":0x9, "b":0xf, "c":0xF })";
|
||||||
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
|
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
|
||||||
JSONTEST_ASSERT(!ok);
|
JSONTEST_ASSERT(!ok);
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(
|
JSONTEST_ASSERT_STRING_EQUAL(
|
||||||
@ -3583,11 +3583,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowHexadecimal, hexObject) {
|
|||||||
{
|
{
|
||||||
Json::Value root;
|
Json::Value root;
|
||||||
Json::String errs;
|
Json::String errs;
|
||||||
char const doc[] = R"({
|
char const doc[] = R"({ "a":0x9, "b":0xf, "c":0xF })";
|
||||||
"a":0x9,
|
|
||||||
"b":0xf,
|
|
||||||
"c":0xF
|
|
||||||
})";
|
|
||||||
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
|
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
|
||||||
JSONTEST_ASSERT(ok);
|
JSONTEST_ASSERT(ok);
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
||||||
@ -3605,18 +3601,31 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowHexadecimal, hexNumbers) {
|
|||||||
|
|
||||||
struct TestData {
|
struct TestData {
|
||||||
bool ok;
|
bool ok;
|
||||||
Json::String in;
|
|
||||||
Json::LargestUInt out;
|
Json::LargestUInt out;
|
||||||
|
Json::String in;
|
||||||
};
|
};
|
||||||
|
constexpr int _ = 0; // ignored
|
||||||
const TestData test_data[] = {
|
const TestData test_data[] = {
|
||||||
{true, "9", 9}, // regular number
|
{true, 99, "99"}, // regular number
|
||||||
{true, "0x00", 0x00}, // zero
|
{true, 0x99, "0x99"}, // hexadecimal number
|
||||||
{true, "0x0123456789", 0x0123456789}, // numeric hex
|
{false, _, "AA"}, // missing prefix
|
||||||
{true, "0xABCDEF", 0xABCDEF}, // uppercase-letter hex
|
{false, _, "xAA"}, // partial prefix
|
||||||
{true, "0xabcdef", 0xabcdef}, // lowercase-letter hex
|
{true, 0xAA, "0xAA"}, // with prefix
|
||||||
{false, "x", 0 }, // leading x
|
{true, 0x00, "0x00"}, // zero
|
||||||
{false, "0xx", 0 }, // extra x
|
{true, 0x0123456789, "0x0123456789"}, // numeric hex
|
||||||
{false, "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0} // too long
|
{true, 0xABCDEF, "0xABCDEF"}, // uppercase-letter hex
|
||||||
|
{true, 0xabcdef, "0xabcdef"}, // lowercase-letter hex
|
||||||
|
#ifdef JSON_HAS_INT64
|
||||||
|
{true, 0xFfffFfffFfffFfff, "0xFfffFfffFfffFfff"}, // max
|
||||||
|
{false, _, "0x1FfffFfffFfffFfff"}, // too long
|
||||||
|
#else
|
||||||
|
{true, 0xFfffFfff, "0xFfffFfff"}, // max
|
||||||
|
{false, _, "0x1FfffFfff"}, // too long
|
||||||
|
#endif
|
||||||
|
{false, _, "0x000000000000000000000000000000000000000"}, // too long
|
||||||
|
{false, _, "x"}, // leading x
|
||||||
|
{false, _, "0x"}, // empty number
|
||||||
|
{false, _, "0xx"} // extra x
|
||||||
};
|
};
|
||||||
for (const auto& td : test_data) {
|
for (const auto& td : test_data) {
|
||||||
Json::Value root;
|
Json::Value root;
|
||||||
@ -3627,10 +3636,10 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowHexadecimal, hexNumbers) {
|
|||||||
JSONTEST_ASSERT(td.ok == ok) << "in: " << td.in;
|
JSONTEST_ASSERT(td.ok == ok) << "in: " << td.in;
|
||||||
if (td.ok)
|
if (td.ok)
|
||||||
{
|
{
|
||||||
JSONTEST_ASSERT_EQUAL(0u, errs.size());
|
JSONTEST_ASSERT_STRING_EQUAL("", errs);
|
||||||
JSONTEST_ASSERT(root.isConvertibleTo(Json::ValueType::uintValue));
|
JSONTEST_ASSERT(root.isUInt64());
|
||||||
if (root.isConvertibleTo(Json::ValueType::uintValue))
|
if (root.isUInt64())
|
||||||
JSONTEST_ASSERT_EQUAL(root.asLargestUInt(), td.out);
|
JSONTEST_ASSERT_EQUAL(td.out, root.asLargestUInt());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user