Blob Blame History Raw
diff -up irrlicht-1.7.2/include/fast_atof.h.fastatof irrlicht-1.7.2/include/fast_atof.h
--- irrlicht-1.7.2/include/fast_atof.h.fastatof	2010-10-24 09:42:58.000000000 -0400
+++ irrlicht-1.7.2/include/fast_atof.h	2010-11-17 15:35:45.278571002 -0500
@@ -12,8 +12,8 @@ namespace irr
 namespace core
 {
 
-// we write [17] here instead of [] to work around a swig bug
-const float fast_atof_table[17] = {
+// we write [16] here instead of [] to work around a swig bug
+const float fast_atof_table[16] = {
 	0.f,
 	0.1f,
 	0.01f,
@@ -30,7 +30,6 @@ const float fast_atof_table[17] = {
 	0.0000000000001f,
 	0.00000000000001f,
 	0.000000000000001f,
-	0.0000000000000001f
 };
 
 //! Convert a simple string of base 10 digits into a signed 32 bit integer.
@@ -39,42 +38,132 @@ const float fast_atof_table[17] = {
 //!					first non-digit.
 //! \param[out] out: (optional) If provided, it will be set to point at the first
 //!					 character not used in the calculation.
-//! \return The signed integer value of the digits. If the string specifies too many
-//!			digits to encode in an s32 then +INT_MAX or -INT_MAX will be returned.
-inline s32 strtol10(const char* in, const char** out=0)
+//! \return The unsigned integer value of the digits.
+inline u32 strtol10(const char* in, const char** out=0)
 {
-	if(!in)
-		return 0;
+	unsigned int value = 0;
 
-	bool negative = false;
-	if('-' == *in)
+	bool running = true;
+	while ( running )
 	{
-		negative = true;
+		if ( *in < '0' || *in > '9' )
+			break;
+
+		value = ( value * 10 ) + ( *in - '0' );
 		++in;
 	}
-	else if('+' == *in)
+	if (out)*out = in;
+	return value;
+}
+
+//! Convert a simple string of base 10 digits into a signed 32 bit integer.
+//! \param[in] in: The string of digits to convert. Only a leading - or + followed 
+//!					by digits 0 to 9 will be considered.  Parsing stops at the
+//!					first non-digit.
+//! \param[out] out: (optional) If provided, it will be set to point at the first
+//!					 character not used in the calculation.
+//! \return The signed integer value of the digits. If the string specifies too many
+//!			digits to encode in an s32 then +INT_MAX or -INT_MAX will be returned.
+inline s32 strtol10s(const char* in, const char** out=0)
+{
+	bool inv = (*in=='-');
+	if (inv || *in=='+')
 		++in;
 
-	u32 unsignedValue = 0;
+	int value = strtol10(in,out);
+	if (inv) {
+		value = -value;
+	}
+	return value;
+}
 
-	while ( ( *in >= '0') && ( *in <= '9' ))
+//! Convert a simple string of base 8 (octal) digits into an unsigned 32 bit integer.
+//! \param[in] in: The string of digits to convert. Only digits 0 to 7 will be considered.  
+//!                               Parsing stops at the first non-digit.
+//! \param[out] out: (optional) If provided, it will be set to point at the first
+//!					 character not used in the calculation.
+//! \return The unsigned integer value of the digits.
+inline u32 strtol8(const char* in, const char** out=0)
+{
+	unsigned int value = 0;
+
+	bool running = true;
+	while ( running )
 	{
-		unsignedValue = ( unsignedValue * 10 ) + ( *in - '0' );
+		if ( *in < '0' || *in > '7' )
+			break;
+
+		value = ( value << 3 ) + ( *in - '0' );
 		++in;
+	}
+	if (out)*out = in;
+	return value;
+}
 
-		if(unsignedValue > (u32)INT_MAX)
+//! Convert a simple string of base 16 (hex) digits into an unsigned 32 bit integer.
+//! \param[in] in: The string of digits to convert. Only digits 0 to 9, A to F will be considered.  
+//!                               Parsing stops at the first non-digit. Letters can be in either case.
+//! \param[out] out: (optional) If provided, it will be set to point at the first
+//!					 character not used in the calculation.
+//! \return The unsigned integer value of the digits.
+inline u32 strtol16( const char* in, const char** out=0)
+{
+	unsigned int value = 0;
+
+	bool running = true;
+	while ( running )
+	{
+		if ( *in >= '0' && *in <= '9' )
 		{
-			unsignedValue = (u32)INT_MAX;
-			break;
+			value = ( value << 4u ) + ( *in - '0' );
 		}
+		else if (*in >= 'A' && *in <= 'F')
+		{
+			value = ( value << 4u ) + ( *in - 'A' ) + 10;
+		}
+		else if (*in >= 'a' && *in <= 'f')
+		{
+			value = ( value << 4u ) + ( *in - 'a' ) + 10;
+		}
+		else break;
+		++in;
 	}
 	if (out)
 		*out = in;
+	return value;
+}
+
+//! Convert a hex-encoded digi (1 character) to an 8 bit unsigned integer.
+//! \param[in] in: The string of digits to convert. Only digits 0 to 9, A to F will be considered.  
+//!                               Parsing stops at the first non-digit. Letters can be in either case.
+//! \param[out] out: (optional) If provided, it will be set to point at the first
+//!					 character not used in the calculation.
+//! \return The unsigned integer value of the digits. 0xffffffff if the input is not hex
+inline u32 HexDigitToDecimal(char in)
+{
+	unsigned int out = 0xffffffff;
+	if (in >= '0' && in <= '9')
+		out = in - '0';
+
+	else if (in >= 'a' && in <= 'f')
+		out = 10u + in - 'a';
 
-	if(negative)
-		return -((s32)unsignedValue);
-	else
-		return (s32)unsignedValue;
+	else if (in >= 'A' && in <= 'F')
+		out = 10u + in - 'A';
+
+	// return value is 0xffffffff if the input is not a hex digit
+	return out;
+}
+
+//! Convert a hex-encoded octet (2 characters) to an 8 bit unsigned integer.
+//! \param[in] in: The string of digits to convert. Only digits 0 to 9, A to F will be considered.  
+//!                               Parsing stops at the first non-digit. Letters can be in either case.
+//! \param[out] out: (optional) If provided, it will be set to point at the first
+//!					 character not used in the calculation.
+//! \return The unsigned integer value of the digits. 0xffffffff if the input is not hex
+inline u8 HexOctetToDecimal(const char* in)
+{
+	return ((u8)HexDigitToDecimal(in[0])<<4)+(u8)HexDigitToDecimal(in[1]);
 }
 
 //! Converts a sequence of digits into a whole positive floating point value.
@@ -126,6 +215,56 @@ inline f32 strtof10(const char* in, cons
 	return floatValue;
 }
 
+//! Convert a simple string of base 10 digits into an unsigned 64 bit integer.
+//! \param[in] in: The string of digits to convert. Only a leading - or + followed 
+//!					by digits 0 to 9 will be considered.  Parsing stops at the
+//!					first non-digit.
+//! \param[out] out: (optional) If provided, it will be set to point at the first
+//!					 character not used in the calculation.
+//! \return The unsigned 64 bit integer value of the digits.
+inline u64 strtol10_64( const char* in, const char** out=0, unsigned int* max_inout=0)
+{
+	unsigned int cur = 0;
+	u64 value = 0;
+
+	bool running = true;
+	while ( running )
+	{
+		if ( *in < '0' || *in > '9' )
+			break;
+
+		const u64 new_value = ( value * 10 ) + ( *in - '0' );
+		
+		if (new_value < value) /* numeric overflow, we rely on you */
+			return value;
+
+		value = new_value;
+
+		++in;
+		++cur;
+
+		if (max_inout && *max_inout == cur) {
+					
+			if (out) { /* skip to end */
+				while (*in >= '0' && *in <= '9')
+					++in;
+				*out = in;
+			}
+
+			return value;
+		}
+	}
+	if (out)
+		*out = in;
+
+	if (max_inout)
+		*max_inout = cur;
+
+	return value;
+}
+// Number of relevant decimals for floating-point parsing.
+#define AI_FAST_ATOF_RELAVANT_DECIMALS 10
+
 //! Provides a fast function for converting a string into a float.
 //! This is not guaranteed to be as accurate as atof(), but is 
 //! approximately 6 to 8 times as fast.
@@ -138,46 +277,51 @@ inline const char* fast_atof_move( const
 	// Please run this regression test when making any modifications to this function:
 	// https://sourceforge.net/tracker/download.php?group_id=74339&atid=540676&file_id=298968&aid=1865300
 
-	out = 0.f;
-	if(!in)
-		return 0;
+	float f;
 
-	bool negative = false;
-	if(*in == '-')
-	{
-		negative = true;
+	bool inv = (*in=='-');
+	if (inv || *in=='+')
 		++in;
-	}
 
-	f32 value = strtof10 ( in, &in );
-
-	if (*in == '.')
+	f = (float) strtol10_64 ( in, &in);
+	if (*in == '.' || (in[0] == ',' && (in[1] >= '0' || in[1] <= '9'))) // allow for commas, too
 	{
 		++in;
 
-		const char * afterDecimal = in;
-		f32 decimal = strtof10 ( in, &afterDecimal );
-		decimal *= fast_atof_table[afterDecimal - in];
-
-		value += decimal;
+		// NOTE: The original implementation is highly unaccurate here. The precision of a single
+		// IEEE 754 float is not high enough, everything behind the 6th digit tends to be more 
+		// inaccurate than it would need to be. Casting to double seems to solve the problem.
+		// strtol_64 is used to prevent integer overflow.
+
+		// Another fix: this tends to become 0 for long numbers if we don't limit the maximum 
+		// number of digits to be read. AI_FAST_ATOF_RELAVANT_DECIMALS can be a value between
+		// 1 and 15.
+		unsigned int diff = AI_FAST_ATOF_RELAVANT_DECIMALS;
+		double pl = (double) strtol10_64 ( in, &in, &diff );
 
-		in = afterDecimal;
+		pl *= fast_atof_table[diff];
+		f += (float)pl;
 	}
 
-	if ('e' == *in || 'E' == *in)
+	// A major 'E' must be allowed. Necessary for proper reading of some DXF files.
+	// Thanks to Zhao Lei to point out that this if() must be outside the if (*c == '.' ..)
+	if (*in == 'e' || *in == 'E')
 	{
 		++in;
-		// Assume that the exponent is a whole number.
-		// strtol10() will deal with both + and - signs,
-		// but cast to (f32) to prevent overflow at FLT_MAX
-		value *= (f32)pow(10.0f, (f32)strtol10(in, &in));
-	}
-
-	if(negative)
-		out = -value;
-	else
-		out = value;
+		bool einv = (*in=='-');
+		if (einv || *in=='+')
+			++in;
+
+		float exp = (float)strtol10_64(in, &in);
+		if (einv)
+			exp *= -1.0f;
 
+		f *= pow(10.0f, exp);
+	}
+	if (inv)
+		f *= -1.0f;
+	
+	out = f;
 	return in;
 }
 
@@ -190,6 +334,47 @@ inline float fast_atof(const char* float
 	return ret;
 }
 
+//! Convert a string to a floating point number
+//! \param c: The string to convert.
+//! \param cout: A pointer to the first character in the string that wasn't
+//!         use to create the float value.
+inline float fast_atof( const char* c, const char** cout)
+{
+	float ret;
+	*cout = fast_atof_move(c, ret);
+
+	return ret;
+}
+
+//! Convert a string to a floating point number
+//! \param inout: The string to convert, returned 
+//!         as the pointer to the first character 
+//!         in the string that wasn't
+//!         use to create the float value.
+inline float fast_atof( const char** inout)
+{
+	float ret;
+	*inout = fast_atof_move(*inout, ret);
+
+	return ret;
+}
+
+//! Parse a C++-like integer literal - hex and oct prefixes - to an unsigned int
+//! 0xNNNN - hex
+//! 0NNN   - oct
+//! NNN    - dec
+//! \param[in] in: The string to convert. 
+//! \param cout: A pointer to the first character in the string that wasn't
+//!         use to create the float value.
+inline u32 strtol_cppstyle( const char* in, const char** out=0)
+{
+	if ('0' == in[0])
+	{
+		return 'x' == in[1] ? strtol16(in+2,out) : strtol8(in+1,out);
+	}
+	return strtol10(in, out);
+}
+
 } // end namespace core
 } // end namespace irr
 
diff -up irrlicht-1.7.2/include/irrTypes.h.fastatof irrlicht-1.7.2/include/irrTypes.h
--- irrlicht-1.7.2/include/irrTypes.h.fastatof	2010-10-24 09:43:00.000000000 -0400
+++ irrlicht-1.7.2/include/irrTypes.h	2010-11-17 15:35:17.651571001 -0500
@@ -67,14 +67,21 @@ typedef signed int		s32;
 #endif
 
 
+//! 64 bit unsigned variable.
+/** This is a typedef for unsigned long, it ensures portability of the engine */
+#ifdef _MSC_VER
+typedef unsigned __int64		u64;
+#else
+typedef unsigned long			u64;
+#endif
 
-// 64 bit signed variable.
-// This is a typedef for __int64, it ensures portability of the engine.
-// This type is currently not used by the engine and not supported by compilers
-// other than Microsoft Compilers, so it is outcommented.
-//typedef __int64				s64;
-
-
+//! 64 bit signed variable.
+/** This is a typedef for signed long, it ensures portability of the engine. */
+#ifdef _MSC_VER
+typedef __int64				s64;
+#else
+typedef signed long			s64;
+#endif
 
 //! 32 bit floating point variable.
 /** This is a typedef for float, it ensures portability of the engine. */