Merge pull request #103 from syvex/JSONParseLarge64

Fix JSON parsing of large unsigned 64-bit integers
This commit is contained in:
Aleksandar Fabijanic 2013-02-22 13:43:54 -08:00
Родитель 97f1f61914 13a1a0b9a2
Коммит 36122110e5
7 изменённых файлов: 152 добавлений и 17 удалений

Просмотреть файл

@ -108,11 +108,17 @@ public:
#if defined(POCO_HAVE_INT64)
virtual Int64 asInteger64() const;
/// Returns a 64-bit integer representation of the token.
virtual UInt64 asUnsignedInteger64() const;
/// Returns an unsigned 64-bit integer representation of the token.
#endif
virtual int asInteger() const;
/// Returns an integer representation of the token.
virtual unsigned asUnsignedInteger() const;
/// Returns an unsigned integer representation of the token.
virtual double asFloat() const;
/// Returns a floating-point representation of the token.

Просмотреть файл

@ -81,6 +81,12 @@ Int64 Token::asInteger64() const
{
return NumberParser::parse64(_value);
}
UInt64 Token::asUnsignedInteger64() const
{
return NumberParser::parseUnsigned64(_value);
}
#endif
@ -90,6 +96,12 @@ int Token::asInteger() const
}
unsigned Token::asUnsignedInteger() const
{
return NumberParser::parseUnsigned(_value);
}
double Token::asFloat() const
{
return NumberParser::parseFloat(_value);

Просмотреть файл

@ -82,9 +82,17 @@ public:
virtual void value(int v);
/// An integer value is read
virtual void value(unsigned v);
/// An unsigned value is read. This will only be triggered if the
/// value cannot fit into a signed int.
#if defined(POCO_HAVE_INT64)
virtual void value(Int64 v);
/// A 64-bit integer value is read
virtual void value(UInt64 v);
/// An unsigned 64-bit integer value is read. This will only be
/// triggered if the value cannot fit into a signed 64-bit integer.
#endif
virtual void value(const std::string& s);
@ -120,11 +128,23 @@ inline void DefaultHandler::value(int v)
}
inline void DefaultHandler::value(unsigned v)
{
setValue(v);
}
#if defined(POCO_HAVE_INT64)
inline void DefaultHandler::value(Int64 v)
{
setValue(v);
}
inline void DefaultHandler::value(UInt64 v)
{
setValue(v);
}
#endif

Просмотреть файл

@ -71,10 +71,18 @@ public:
virtual void value(int v) = 0;
/// An integer value is read
virtual void value(unsigned v) = 0;
/// An unsigned value is read. This will only be triggered if the
/// value cannot fit into a signed int.
#if defined(POCO_HAVE_INT64)
virtual void value(Int64 v) = 0;
/// A 64-bit integer value is read
virtual void value(UInt64 v) = 0;
/// An unsigned 64-bit integer value is read. This will only be
/// triggered if the value cannot fit into a signed 64-bit integer.
#endif
virtual void value(const std::string& value) = 0;

Просмотреть файл

@ -636,20 +636,46 @@ void Parser::readValue(const Token* token)
if (_handler != NULL)
{
#if defined(POCO_HAVE_INT64)
Int64 value = token->asInteger64();
// if number is 32-bit, then handle as such
if (value > std::numeric_limits<int>::max()
|| value < std::numeric_limits<int>::min())
{
_handler->value(value);
}
else
{
_handler->value(static_cast<int>(value));
}
try
{
Int64 value = token->asInteger64();
// if number is 32-bit, then handle as such
if ( value > std::numeric_limits<int>::max()
|| value < std::numeric_limits<int>::min() )
{
_handler->value(value);
}
else
{
_handler->value(static_cast<int>(value));
}
}
// try to handle error as unsigned in case of overflow
catch ( const SyntaxException& )
{
UInt64 value = token->asUnsignedInteger64();
// if number is 32-bit, then handle as such
if ( value > std::numeric_limits<unsigned>::max() )
{
_handler->value(value);
}
else
{
_handler->value(static_cast<unsigned>(value));
}
}
#else
int value = token->asInteger();
_handle->value(value);
try
{
int value = token->asInteger();
_handle->value(value);
}
// try to handle error as unsigned in case of overflow
catch ( const SyntaxException& )
{
unsigned value = token->asUnsignedInteger();
_handle->value(value);
}
#endif
}
break;

Просмотреть файл

@ -192,12 +192,42 @@ void JSONTest::testNumberProperty()
assert(value == 1969);
}
void JSONTest::testUnsignedNumberProperty()
{
// 4294967295 == unsigned(-1)
std::string json = "{ \"test\" : 4294967295 }";
Parser parser;
Var result;
try
{
DefaultHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
}
catch(JSONException& jsone)
{
std::cout << jsone.message() << std::endl;
assert(false);
}
assert(result.type() == typeid(Object::Ptr));
Object::Ptr object = result.extract<Object::Ptr>();
Var test = object->get("test");
assert(test.isInteger());
unsigned value = test;
assert(value == -1);
}
#if defined(POCO_HAVE_INT64)
void JSONTest::testNumber64Property()
{
std::string json = "{ \"test\" : 5000000000000000 }";
std::string json = "{ \"test\" : -5000000000000000 }";
Parser parser;
Var result;
@ -220,10 +250,39 @@ void JSONTest::testNumber64Property()
Var test = object->get("test");
assert(test.isInteger());
Poco::Int64 value = test;
assert(value == 5000000000000000);
assert(value == -5000000000000000);
}
void JSONTest::testUnsignedNumber64Property()
{
// 18446744073709551615 == UInt64(-1)
std::string json = "{ \"test\" : 18446744073709551615 }";
Parser parser;
Var result;
try
{
DefaultHandler handler;
parser.setHandler(&handler);
parser.parse(json);
result = handler.result();
}
catch(JSONException& jsone)
{
std::cout << jsone.message() << std::endl;
assert(false);
}
assert(result.type() == typeid(Object::Ptr));
Object::Ptr object = result.extract<Object::Ptr>();
Var test = object->get("test");
assert(test.isInteger());
Poco::UInt64 value = test;
assert(value == -1);
}
#endif
@ -962,8 +1021,10 @@ CppUnit::Test* JSONTest::suite()
CppUnit_addTest(pSuite, JSONTest, testTrueProperty);
CppUnit_addTest(pSuite, JSONTest, testFalseProperty);
CppUnit_addTest(pSuite, JSONTest, testNumberProperty);
CppUnit_addTest(pSuite, JSONTest, testUnsignedNumberProperty);
#if defined(POCO_HAVE_INT64)
CppUnit_addTest(pSuite, JSONTest, testNumber64Property);
CppUnit_addTest(pSuite, JSONTest, testUnsignedNumber64Property);
#endif
CppUnit_addTest(pSuite, JSONTest, testStringProperty);
CppUnit_addTest(pSuite, JSONTest, testEmptyObject);

Просмотреть файл

@ -50,8 +50,10 @@ public:
void testTrueProperty();
void testFalseProperty();
void testNumberProperty();
void testUnsignedNumberProperty();
#if defined(POCO_HAVE_INT64)
void testNumber64Property();
void testUnsignedNumber64Property();
#endif
void testStringProperty();
void testEmptyObject();