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. */