Browse Source

DynamicAny conversion limits

Aleksandar Fabijanic 19 years ago
parent
commit
f29f7cda53

+ 23 - 8
Foundation/include/Poco/DynamicAny.h

@@ -49,15 +49,30 @@ namespace Poco {
 
 
 class Foundation_API DynamicAny
-	/// A DynamicAny allows to store data of different types and to convert between these types transparently.
-	/// It's the reponsibility of the programmer to ensure that conversions are meaningful.
-	/// For example: it is possible to convert between string and character. An empty string gets converted to 
-	/// the char '\0', a non-empty string gets truncated to the very first character. Numeric values are truncated,
-	/// no overflow/underflow errors are checked. A string value "false" can be converted to a boolean value false,
-	/// any other string not "false" (not case sensitive) or "0" to true (e.g: "hi" -> true).
+	/// DynamicAny allows to store data of different types and to convert between these types transparently.
+	/// DynamicAny puts forth the best effort to provide intuitive and reasonable conversion semantics and prevent 
+	/// unexpected data loss, particularly when performing narrowing or signedness conversions of numeric data types.
 	///
-	/// A DynamicAny can be created from a value of any type for which a
-	/// specialization of DynamicAnyHolderImpl is available.
+	/// Loss of signedness is not allowed for numeric values. This means that if an attempt is made to convert 
+	/// the internal value which is a negative signed integer to an unsigned integer type storage, a RangeException is thrown. 
+	/// Overflow is not allowed, so if the internal value is a larger number than the target numeric type size can accomodate, 
+	/// a RangeException is thrown.
+	///
+	/// Precision loss, such as in conversion from floating-point types to integers or from double to float on platforms
+	/// where they differ in size (provided internal actual value fits in float min/max range), is allowed.
+	/// 
+	/// String truncation is allowed - it is possible to convert between string and character when string length is 
+	/// greater than 1. An empty string gets converted to the char '\0', a non-empty string is truncated to the first character. 
+	///
+	/// Bolean conversion are performed as follows:
+	///
+	/// A string value "false" (not case sensitive) or "0" can be converted to a boolean value false, any other string 
+	/// not being false by the above criteria evaluates to true (e.g: "hi" -> true).
+	/// Integer 0 values are false, everything else is true.
+	/// Floating point values equal to the minimal FP representation on a given platform are false, everything else is true.
+	///
+	/// A DynamicAny can be created from and converted to a value of any type for which a specialization of 
+	/// DynamicAnyHolderImpl is available. For supported types, see DynamicAnyHolder documentation.
 {
 public:
 	DynamicAny();

+ 228 - 94
Foundation/include/Poco/DynamicAnyHolder.h

@@ -46,15 +46,46 @@
 #include "Poco/String.h"
 #include "Poco/Exception.h"
 #include <typeinfo>
+#include <limits>
+
+///BEGIN ported from boost
+/// following macros were ported from boost to help the DynamicAnyHolder development
+/// for complete multi-platform code, see static_assert.hpp in boost libraries
+
+// Helper macro POCO_JOIN:
+// The following piece of macro magic joins the two
+// arguments together, even when one of the arguments is
+// itself a macro (see 16.3.1 in C++ standard).  The key
+// is that macro expansion of macro arguments does not
+// occur in POCO_DO_JOIN2 but does in POCO_DO_JOIN.
+//
+#define POCO_JOIN(X, Y) POCO_DO_JOIN( X, Y )
+#define POCO_DO_JOIN(X, Y) POCO_DO_JOIN2(X,Y)
+#define POCO_DO_JOIN2(X, Y) X##Y
+
+template <bool x> struct STATIC_ASSERTION_FAILURE;
+template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
+template<int x> struct static_assert_test{};
+
+#if defined(__GNUC__) && (__GNUC__ == 3) && ((__GNUC_MINOR__ == 3) || (__GNUC_MINOR__ == 4))
+# define poco_static_assert( B ) \
+    typedef char POCO_JOIN(poco_static_assert_typedef_, __LINE__) \
+        [ STATIC_ASSERTION_FAILURE< (bool)(B) >::value ]
+#else
+# define poco_static_assert(B) \
+   typedef static_assert_test<sizeof(STATIC_ASSERTION_FAILURE<(bool)(B)>)> poco_static_assert_typedef_
+#endif
+///END ported from boost
 
 
 namespace Poco {
 
 
 class Foundation_API DynamicAnyHolder
-	/// Interface for a data holder used by the DynamicAny class. Provides methods to convert between data types.
+	/// Interface for a data holder used by the DynamicAny class. 
+	/// Provides methods to convert between data types.
 	/// Only data types for which a convert method exists are supported, which are
-	/// all C++ built-in types, along with std::string.
+	/// all C++ built-in types with addition of std::string.
 {
 public:
 	DynamicAnyHolder();
@@ -88,6 +119,91 @@ public:
 	virtual void convert(double& val) const = 0;
 	virtual void convert(char& val) const = 0;
 	virtual void convert(std::string& val) const = 0;
+
+protected:
+	template <typename F, typename T>
+	void convertToSmaller(const F& from, T& to) const
+		/// This function is meant to convert signed integral values from
+		/// larger to smaller type. It checks the upper and lower bound and
+		/// if from value is within limits of type T (i.e. check calls do not throw), 
+		/// it is converted.
+	{
+		poco_static_assert (std::numeric_limits<F>::is_specialized);
+		poco_static_assert (std::numeric_limits<T>::is_specialized);
+		poco_static_assert (std::numeric_limits<F>::is_signed);
+		poco_static_assert (std::numeric_limits<T>::is_signed);
+
+		checkUpperLimit(from, to); 
+		checkLowerLimit(from, to);
+		to = static_cast<T>(from);
+	}
+
+	template <typename F, typename T>
+	void convertToSmallerUnsigned(const F& from, T& to) const
+		/// This function is meant for converting unsigned integral data types,
+		/// from larger to smaller type. Since lower limit is always 0 for unigned types, 
+		/// only the upper limit is checked, thus saving some cycles compared to the signed 
+		/// version of the function. If the value to be converted is smaller than
+		/// the maximum value for the target type, the conversion is performed.
+	{
+		poco_static_assert (std::numeric_limits<F>::is_specialized);
+		poco_static_assert (std::numeric_limits<T>::is_specialized);
+		poco_static_assert (!std::numeric_limits<F>::is_signed);
+		poco_static_assert (!std::numeric_limits<T>::is_signed);
+
+		checkUpperLimit(from, to); 
+		to = static_cast<T>(from);
+	}
+
+	template <typename F, typename T>
+	void convertSignedToUnsigned(const F& from, T& to) const
+		/// This function is meant for converting signed integral data types to
+		/// unsigned data types. Negative values can not be converted and if one is 
+		/// encountered, RangeException is thrown. 
+		/// If uper limit is within the target data type limits, the converiosn is performed.
+	{
+		poco_static_assert (std::numeric_limits<F>::is_specialized);
+		poco_static_assert (std::numeric_limits<T>::is_specialized);
+		poco_static_assert (std::numeric_limits<F>::is_signed);
+		poco_static_assert (!std::numeric_limits<T>::is_signed);
+
+		if (from < 0)
+			throw RangeException("Value too small.");
+		checkUpperLimit(from, to); 
+		to = static_cast<T>(from);
+	}
+
+	template <typename F, typename T>
+	void convertUnsignedToSigned(const F& from, T& to) const
+		/// This function is meant for converting unsigned integral data types to
+		/// unsigned data types. Negative values can not be converted and if one is 
+		/// encountered, RangeException is thrown. 
+		/// If uper limit is within the target data type limits, the converiosn is performed.
+	{
+		poco_static_assert (std::numeric_limits<F>::is_specialized);
+		poco_static_assert (std::numeric_limits<T>::is_specialized);
+		poco_static_assert (!std::numeric_limits<F>::is_signed);
+		poco_static_assert (std::numeric_limits<T>::is_signed);
+
+		checkUpperLimit(from, to); 
+		to = static_cast<T>(from);
+	}
+
+private:
+	template <typename F, typename T>
+	void checkUpperLimit(const F& from, T& to) const
+	{
+		if (from > std::numeric_limits<T>::max()) 
+			throw RangeException("Value too large.");
+	}
+
+	template <typename F, typename T>
+	void checkLowerLimit(const F& from, T& to) const
+	{
+		if (from < std::numeric_limits<T>::min()) 
+			throw RangeException("Value too small.");
+	}
+
 };
 
 
@@ -119,6 +235,11 @@ class DynamicAnyHolderImpl: public DynamicAnyHolder
 	///
 	/// DynamicAny can be used for any type for which a specialization for
 	/// DynamicAnyHolderImpl is available.
+	///
+	/// DynamicAnyHolderImpl throws following exceptions:
+	///		NotImplementedException (if the specialization for a type does not exist)
+	///		RangeException (if an attempt is made to assign a numeric value outside of the target min/max limits
+	///		SyntaxException (if an attempt is made to convert a string containing non-numeric characters to number)
 {
 	DynamicAnyHolderImpl()
 	{
@@ -245,22 +366,22 @@ public:
 
 	void convert(UInt8& val) const
 	{
-		val = static_cast<UInt8>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt16& val) const
 	{
-		val = static_cast<UInt16>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 	
 	void convert(UInt32& val) const
 	{
-		val = static_cast<UInt32>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt64& val) const
 	{
-		val = static_cast<UInt64>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(bool& val) const
@@ -318,7 +439,7 @@ public:
 
 	void convert(Int8& val) const
 	{
-		val = static_cast<Int8>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(Int16& val) const
@@ -338,22 +459,22 @@ public:
 
 	void convert(UInt8& val) const
 	{
-		val = static_cast<UInt8>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt16& val) const
 	{
-		val = static_cast<UInt16>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 	
 	void convert(UInt32& val) const
 	{
-		val = static_cast<UInt32>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt64& val) const
 	{
-		val = static_cast<UInt64>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(bool& val) const
@@ -373,7 +494,7 @@ public:
 
 	void convert(char& val) const
 	{
-		val = static_cast<char>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(std::string& val) const
@@ -410,12 +531,12 @@ public:
 
 	void convert(Int8& val) const
 	{
-		val = static_cast<Int8>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(Int16& val) const
 	{
-		val = static_cast<Int16>(_val);
+		convertToSmaller(_val, val);
 	}
 	
 	void convert(Int32& val) const
@@ -430,22 +551,22 @@ public:
 
 	void convert(UInt8& val) const
 	{
-		val = static_cast<UInt8>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt16& val) const
 	{
-		val = static_cast<UInt16>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 	
 	void convert(UInt32& val) const
 	{
-		val = static_cast<UInt32>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt64& val) const
 	{
-		val = static_cast<UInt64>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(bool& val) const
@@ -465,7 +586,7 @@ public:
 
 	void convert(char& val) const
 	{
-		val = static_cast<char>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(std::string& val) const
@@ -502,17 +623,17 @@ public:
 
 	void convert(Int8& val) const
 	{
-		val = static_cast<Int8>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(Int16& val) const
 	{
-		val = static_cast<Int16>(_val);
+		convertToSmaller(_val, val);
 	}
 	
 	void convert(Int32& val) const
 	{
-		val = static_cast<Int32>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(Int64& val) const
@@ -522,22 +643,22 @@ public:
 
 	void convert(UInt8& val) const
 	{
-		val = static_cast<UInt8>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt16& val) const
 	{
-		val = static_cast<UInt16>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 	
 	void convert(UInt32& val) const
 	{
-		val = static_cast<UInt32>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt64& val) const
 	{
-		val = static_cast<UInt64>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(bool& val) const
@@ -557,7 +678,7 @@ public:
 
 	void convert(char& val) const
 	{
-		val = static_cast<char>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(std::string& val) const
@@ -594,12 +715,12 @@ public:
 
 	void convert(Int8& val) const
 	{
-		val = static_cast<Int8>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(Int16& val) const
 	{
-		val = static_cast<Int16>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 	
 	void convert(Int32& val) const
@@ -649,7 +770,7 @@ public:
 
 	void convert(char& val) const
 	{
-		val = static_cast<char>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(std::string& val) const
@@ -686,17 +807,17 @@ public:
 
 	void convert(Int8& val) const
 	{
-		val = static_cast<Int8>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(Int16& val) const
 	{
-		val = static_cast<Int16>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 	
 	void convert(Int32& val) const
 	{
-		val = static_cast<Int32>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(Int64& val) const
@@ -706,7 +827,7 @@ public:
 
 	void convert(UInt8& val) const
 	{
-		val = static_cast<UInt8>(_val);
+		convertToSmallerUnsigned(_val, val);
 	}
 
 	void convert(UInt16& val) const
@@ -741,7 +862,7 @@ public:
 
 	void convert(char& val) const
 	{
-		val = static_cast<char>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(std::string& val) const
@@ -778,32 +899,32 @@ public:
 
 	void convert(Int8& val) const
 	{
-		val = static_cast<Int8>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(Int16& val) const
 	{
-		val = static_cast<Int16>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 	
 	void convert(Int32& val) const
 	{
-		val = static_cast<Int32>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(Int64& val) const
 	{
-		val = static_cast<Int64>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(UInt8& val) const
 	{
-		val = static_cast<UInt8>(_val);
+		convertToSmallerUnsigned(_val, val);
 	}
 
 	void convert(UInt16& val) const
 	{
-		val = static_cast<UInt16>(_val);
+		convertToSmallerUnsigned(_val, val);
 	}
 	
 	void convert(UInt32& val) const
@@ -833,7 +954,7 @@ public:
 
 	void convert(char& val) const
 	{
-		val = static_cast<char>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(std::string& val) const
@@ -870,37 +991,37 @@ public:
 
 	void convert(Int8& val) const
 	{
-		val = static_cast<Int8>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(Int16& val) const
 	{
-		val = static_cast<Int16>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 	
 	void convert(Int32& val) const
 	{
-		val = static_cast<Int32>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(Int64& val) const
 	{
-		val = static_cast<Int64>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(UInt8& val) const
 	{
-		val = static_cast<UInt8>(_val);
+		convertToSmallerUnsigned(_val, val);
 	}
 
 	void convert(UInt16& val) const
 	{
-		val = static_cast<UInt16>(_val);
+		convertToSmallerUnsigned(_val, val);
 	}
 	
 	void convert(UInt32& val) const
 	{
-		val = static_cast<UInt32>(_val);
+		convertToSmallerUnsigned(_val, val);
 	}
 
 	void convert(UInt64& val) const
@@ -925,7 +1046,7 @@ public:
 
 	void convert(char& val) const
 	{
-		val = static_cast<char>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(std::string& val) const
@@ -1054,47 +1175,48 @@ public:
 
 	void convert(Int8& val) const
 	{
-		val = static_cast<Int8>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(Int16& val) const
 	{
-		val = static_cast<Int16>(_val);
+		convertToSmaller(_val, val);
 	}
 	
 	void convert(Int32& val) const
 	{
-		val = static_cast<Int32>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(Int64& val) const
 	{
-		val = static_cast<Int64>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(UInt8& val) const
 	{
-		val = static_cast<UInt8>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt16& val) const
 	{
-		val = static_cast<UInt16>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 	
 	void convert(UInt32& val) const
 	{
-		val = static_cast<UInt32>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt64& val) const
 	{
-		val = static_cast<UInt64>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(bool& val) const
 	{
-		val = !(_val < 0.0001f && _val > -0.0001f);
+		val = !(_val <= std::numeric_limits<float>::min() && 
+			_val >= -1 * std::numeric_limits<float>::min());
 	}
 
 	void convert(float& val) const
@@ -1109,7 +1231,7 @@ public:
 
 	void convert(char& val) const
 	{
-		val = static_cast<char>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(std::string& val) const
@@ -1146,51 +1268,58 @@ public:
 
 	void convert(Int8& val) const
 	{
-		val = static_cast<Int8>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(Int16& val) const
 	{
-		val = static_cast<Int16>(_val);
+		convertToSmaller(_val, val);
 	}
 	
 	void convert(Int32& val) const
 	{
-		val = static_cast<Int32>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(Int64& val) const
 	{
-		val = static_cast<Int64>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(UInt8& val) const
 	{
-		val = static_cast<UInt8>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt16& val) const
 	{
-		val = static_cast<UInt16>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 	
 	void convert(UInt32& val) const
 	{
-		val = static_cast<UInt32>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt64& val) const
 	{
-		val = static_cast<UInt64>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(bool& val) const
 	{
-		val = !(_val < 0.0001 && _val > -0.0001);
+		val = !(_val <= std::numeric_limits<double>::min() && 
+			_val >= -1 * std::numeric_limits<double>::min());
 	}
 
 	void convert(float& val) const
 	{
+		double fMin = -1 * std::numeric_limits<float>::max();
+		double fMax = std::numeric_limits<float>::max();
+
+		if (_val < fMin) throw RangeException("Value too small.");
+		if (_val > fMax) throw RangeException("Value too large.");
+
 		val = static_cast<float>(_val);
 	}
 
@@ -1201,7 +1330,7 @@ public:
 
 	void convert(char& val) const
 	{
-		val = static_cast<char>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(std::string& val) const
@@ -1258,22 +1387,22 @@ public:
 
 	void convert(UInt8& val) const
 	{
-		val = static_cast<UInt8>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt16& val) const
 	{
-		val = static_cast<UInt16>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 	
 	void convert(UInt32& val) const
 	{
-		val = static_cast<UInt32>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt64& val) const
 	{
-		val = static_cast<UInt64>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(bool& val) const
@@ -1334,12 +1463,14 @@ public:
 
 	void convert(Int8& val) const
 	{
-		val = static_cast<Int8>(NumberParser::parse(_val));
+		int v = NumberParser::parse(_val);
+		convertToSmaller(v, val);
 	}
 
 	void convert(Int16& val) const
 	{
-		val = static_cast<Int16>(NumberParser::parse(_val));
+		int v = NumberParser::parse(_val);
+		convertToSmaller(v, val);
 	}
 	
 	void convert(Int32& val) const
@@ -1354,12 +1485,14 @@ public:
 
 	void convert(UInt8& val) const
 	{
-		val = static_cast<UInt8>(NumberParser::parseUnsigned(_val));
+		unsigned int v = NumberParser::parseUnsigned(_val);
+		convertToSmallerUnsigned(v, val);
 	}
 
 	void convert(UInt16& val) const
 	{
-		val = static_cast<UInt16>(NumberParser::parseUnsigned(_val));
+		unsigned int v = NumberParser::parseUnsigned(_val);
+		convertToSmallerUnsigned(v, val);
 	}
 	
 	void convert(UInt32& val) const
@@ -1385,7 +1518,8 @@ public:
 
 	void convert(float& val) const
 	{
-		val = static_cast<float>(NumberParser::parseFloat(_val));
+		double v = NumberParser::parseFloat(_val);
+		convertToSmaller(v, val);
 	}
 
 	void convert(double& val) const
@@ -1438,12 +1572,12 @@ public:
 
 	void convert(Int8& val) const
 	{
-		val = static_cast<Int8>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(Int16& val) const
 	{
-		val = static_cast<Int16>(_val);
+		convertToSmaller(_val, val);
 	}
 	
 	void convert(Int32& val) const
@@ -1458,22 +1592,22 @@ public:
 
 	void convert(UInt8& val) const
 	{
-		val = static_cast<UInt8>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt16& val) const
 	{
-		val = static_cast<UInt16>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 	
 	void convert(UInt32& val) const
 	{
-		val = static_cast<UInt32>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(UInt64& val) const
 	{
-		val = static_cast<UInt64>(_val);
+		convertSignedToUnsigned(_val, val);
 	}
 
 	void convert(bool& val) const
@@ -1493,7 +1627,7 @@ public:
 
 	void convert(char& val) const
 	{
-		val = static_cast<char>(_val);
+		convertToSmaller(_val, val);
 	}
 
 	void convert(std::string& val) const
@@ -1530,37 +1664,37 @@ public:
 
 	void convert(Int8& val) const
 	{
-		val = static_cast<Int8>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(Int16& val) const
 	{
-		val = static_cast<Int16>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 	
 	void convert(Int32& val) const
 	{
-		val = static_cast<Int32>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(Int64& val) const
 	{
-		val = static_cast<Int64>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(UInt8& val) const
 	{
-		val = static_cast<UInt8>(_val);
+		convertToSmallerUnsigned(_val, val);
 	}
 
 	void convert(UInt16& val) const
 	{
-		val = static_cast<UInt16>(_val);
+		convertToSmallerUnsigned(_val, val);
 	}
 	
 	void convert(UInt32& val) const
 	{
-		val = static_cast<UInt32>(_val);
+		convertToSmallerUnsigned(_val, val);
 	}
 
 	void convert(UInt64& val) const
@@ -1585,7 +1719,7 @@ public:
 
 	void convert(char& val) const
 	{
-		val = static_cast<char>(_val);
+		convertUnsignedToSigned(_val, val);
 	}
 
 	void convert(std::string& val) const

+ 83 - 2
Foundation/testsuite/src/DynamicAnyTest.cpp

@@ -38,7 +38,6 @@
 #include "Poco/Bugcheck.h"
 
 
-
 using namespace Poco;
 
 
@@ -940,11 +939,91 @@ void DynamicAnyTest::testConversionOperator()
 	assert (i == 42);
 	
 	any = 123;
-	std::string s(any);
+	std::string s = any;//'s(any)' bombs on gcc 3.4.4
 	assert (s == "123");
 }
 
 
+void DynamicAnyTest::testLimitsInt()
+{
+	testLimitsSigned<Int16, Int8>();
+	testLimitsSigned<Int32, Int8>();
+	testLimitsSigned<Int64, Int8>();
+	testLimitsFloatToInt<float, Int8>();
+	testLimitsFloatToInt<double, Int8>();
+
+	testLimitsSigned<Int16, char>();
+	testLimitsSigned<Int32, char>();
+	testLimitsSigned<Int64, char>();
+	testLimitsFloatToInt<float, char>();
+	testLimitsFloatToInt<double, char>();
+
+	testLimitsSigned<Int32, Int16>();
+	testLimitsSigned<Int64, Int16>();
+	testLimitsFloatToInt<float, Int16>();
+	testLimitsFloatToInt<double, Int16>();
+
+	testLimitsSigned<Int64, Int32>();
+	testLimitsFloatToInt<float, Int32>();
+	testLimitsFloatToInt<double, Int32>();
+
+	testLimitsSignedUnsigned<Int8, UInt8>();
+	testLimitsSignedUnsigned<Int16, UInt8>();
+	testLimitsSignedUnsigned<Int32, UInt8>();
+	testLimitsSignedUnsigned<Int64, UInt8>();
+	testLimitsFloatToInt<float, UInt8>();
+	testLimitsFloatToInt<double, UInt8>();
+
+	testLimitsSignedUnsigned<Int8, UInt16>();
+	testLimitsSignedUnsigned<Int16, UInt16>();
+	testLimitsSignedUnsigned<Int32, UInt16>();
+	testLimitsSignedUnsigned<Int64, UInt16>();
+	testLimitsFloatToInt<float, UInt16>();
+	testLimitsFloatToInt<double, UInt16>();
+
+	testLimitsSignedUnsigned<Int8, UInt32>();
+	testLimitsSignedUnsigned<Int16, UInt32>();
+	testLimitsSignedUnsigned<Int32, UInt32>();
+	testLimitsSignedUnsigned<Int64, UInt32>();
+	testLimitsFloatToInt<float, UInt32>();
+	testLimitsFloatToInt<double, UInt32>();
+
+	testLimitsSignedUnsigned<Int8, UInt64>();
+	testLimitsSignedUnsigned<Int16, UInt64>();
+	testLimitsSignedUnsigned<Int32, UInt64>();
+	testLimitsSignedUnsigned<Int64, UInt64>();
+	testLimitsFloatToInt<float, UInt64>();
+	testLimitsFloatToInt<double, UInt64>();
+
+
+	testLimitsUnsigned<UInt16, UInt8>();
+	testLimitsUnsigned<UInt32, UInt8>();
+	testLimitsUnsigned<UInt64, UInt8>();
+
+	testLimitsUnsigned<UInt32, UInt16>();
+	testLimitsUnsigned<UInt64, UInt16>();
+
+	testLimitsUnsigned<UInt64, UInt32>();
+}
+
+
+void DynamicAnyTest::testLimitsFloat()
+{
+	if (std::numeric_limits<double>::max() != std::numeric_limits<float>::max())
+	{
+		double iMin = -1 * std::numeric_limits<float>::max();
+		DynamicAny da = iMin * 10;
+		try { float f; f = da; fail("must fail"); }
+		catch (RangeException&) {}
+
+		double iMax = std::numeric_limits<float>::max();
+		da = iMax * 10;
+		try { float f; f = da; fail("must fail"); }
+		catch (RangeException&) {}
+	}
+}
+
+
 void DynamicAnyTest::setUp()
 {
 }
@@ -975,6 +1054,8 @@ CppUnit::Test* DynamicAnyTest::suite()
 	CppUnit_addTest(pSuite, DynamicAnyTest, testLong);
 	CppUnit_addTest(pSuite, DynamicAnyTest, testULong);
 	CppUnit_addTest(pSuite, DynamicAnyTest, testConversionOperator);
+	CppUnit_addTest(pSuite, DynamicAnyTest, testLimitsInt);
+	CppUnit_addTest(pSuite, DynamicAnyTest, testLimitsFloat);
 
 	return pSuite;
 }

+ 60 - 1
Foundation/testsuite/src/DynamicAnyTest.h

@@ -36,6 +36,8 @@
 
 
 #include "Poco/Foundation.h"
+#include "Poco/DynamicAny.h"
+#include "Poco/Exception.h"
 #include "CppUnit/TestCase.h"
 
 
@@ -61,10 +63,67 @@ public:
 	void testULong();
 	void testString();
 	void testConversionOperator();
-	
+	void testLimitsInt();
+	void testLimitsFloat();
+
 	void setUp();
 	void tearDown();
 	static CppUnit::Test* suite();
+
+private:
+	template<typename TL, typename TS>
+	void testLimitsSigned()
+	{
+		TL iMin = std::numeric_limits<TS>::min();
+		Poco::DynamicAny da = iMin - 1;
+		try { TS i; i = da; fail("must fail"); }
+		catch (Poco::RangeException&) {}
+
+		TL iMax = std::numeric_limits<TS>::max();
+		da = iMax + 1;
+		try { TS i; i = da; fail("must fail"); }
+		catch (Poco::RangeException&) {}
+	}
+
+	template<typename TL, typename TS>
+	void testLimitsFloatToInt()
+	{
+		Poco::DynamicAny da;
+
+		if (std::numeric_limits<TS>::is_signed)
+		{
+			TL iMin = static_cast<TL>(std::numeric_limits<TS>::min());
+			da = iMin * 10;
+			try { TS i; i = da; fail("must fail"); }
+			catch (Poco::RangeException&) {}
+		}
+
+		TL iMax = static_cast<TL>(std::numeric_limits<TS>::max());
+		da = iMax * 10;
+		try { TS i; i = da; fail("must fail"); }
+		catch (Poco::RangeException&) {}
+	}
+
+	template<typename TS, typename TU>
+	void testLimitsSignedUnsigned()
+	{
+		assert (std::numeric_limits<TS>::is_signed);
+		assert (!std::numeric_limits<TU>::is_signed);
+
+		TS iMin = std::numeric_limits<TS>::min();
+		Poco::DynamicAny da = iMin;
+		try { TU i; i = da; fail("must fail"); }
+		catch (Poco::RangeException&) {}
+	}
+
+	template<typename TL, typename TS>
+	void testLimitsUnsigned()
+	{
+		TL iMax = std::numeric_limits<TS>::max();
+		Poco::DynamicAny da = iMax + 1;
+		try { TS i; i = da; fail("must fail"); }
+		catch (Poco::RangeException&) {}
+	}
 };