diff --git a/Foundation/include/Poco/Token.h b/Foundation/include/Poco/Token.h index fa99385d9..125c241ba 100644 --- a/Foundation/include/Poco/Token.h +++ b/Foundation/include/Poco/Token.h @@ -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. diff --git a/Foundation/src/Token.cpp b/Foundation/src/Token.cpp index d8ac16047..4f1e39694 100644 --- a/Foundation/src/Token.cpp +++ b/Foundation/src/Token.cpp @@ -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); diff --git a/JSON/include/Poco/JSON/DefaultHandler.h b/JSON/include/Poco/JSON/DefaultHandler.h index 84b65e123..67a5e9e61 100644 --- a/JSON/include/Poco/JSON/DefaultHandler.h +++ b/JSON/include/Poco/JSON/DefaultHandler.h @@ -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 diff --git a/JSON/include/Poco/JSON/Handler.h b/JSON/include/Poco/JSON/Handler.h index 9bbb7d185..b8d3ed65d 100644 --- a/JSON/include/Poco/JSON/Handler.h +++ b/JSON/include/Poco/JSON/Handler.h @@ -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; diff --git a/JSON/src/Parser.cpp b/JSON/src/Parser.cpp index 97ac95e21..910aed398 100644 --- a/JSON/src/Parser.cpp +++ b/JSON/src/Parser.cpp @@ -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::max() - || value < std::numeric_limits::min()) - { - _handler->value(value); - } - else - { - _handler->value(static_cast(value)); - } + try + { + Int64 value = token->asInteger64(); + // if number is 32-bit, then handle as such + if ( value > std::numeric_limits::max() + || value < std::numeric_limits::min() ) + { + _handler->value(value); + } + else + { + _handler->value(static_cast(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::max() ) + { + _handler->value(value); + } + else + { + _handler->value(static_cast(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; diff --git a/JSON/testsuite/src/JSONTest.cpp b/JSON/testsuite/src/JSONTest.cpp index 99b03394a..65c57ef31 100644 --- a/JSON/testsuite/src/JSONTest.cpp +++ b/JSON/testsuite/src/JSONTest.cpp @@ -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(); + 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(); + 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); diff --git a/JSON/testsuite/src/JSONTest.h b/JSON/testsuite/src/JSONTest.h index 53bd8b750..2ad25e3c3 100644 --- a/JSON/testsuite/src/JSONTest.h +++ b/JSON/testsuite/src/JSONTest.h @@ -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();