Browse Source

Gracefully handle NaN/inf values in fast_atoreal_move

There are legitimate cases where inf/nan values are embeddded in a mesh.
Such values should not cause loading to fail, and indeed, previous versions of
Assimp supported their existence. Update the new fast_atoreal_move method
to gracefully parse such values, allowing case-insensitive checks for "NAN",
"INF" and "INFINITY" as per the atof guidelines found at
http://en.cppreference.com/w/cpp/string/byte/atof.

Note that the inf/nan text parsing is fairly loose, but is fast for the general
case and should handle most legitimate inf/nan values.
Jared Duke 11 năm trước cách đây
mục cha
commit
ed124ccbab
1 tập tin đã thay đổi với 33 bổ sung13 xóa
  1. 33 13
      code/fast_atof.h

+ 33 - 13
code/fast_atof.h

@@ -16,7 +16,9 @@
 #define __FAST_A_TO_F_H_INCLUDED__
 
 #include <math.h>
-#include <limits.h>
+#include <limits>
+
+#include "StringComparison.h"
 
 namespace Assimp
 {
@@ -236,18 +238,36 @@ inline const char* fast_atoreal_move( const char* c, Real& out, bool check_comma
 		++c;
 	}
 
-        if (!(c[0] >= '0' && c[0] <= '9') &&
-                !(c[0] == '.' && c[1] >= '0' && c[1] <= '9'))
-        {
-                throw std::invalid_argument("Cannot parse string "
-                        "as real number: does not start with digit "
-                        "or decimal point followed by digit.");
-        }
-
-        if (*c != '.')
-        {
-                f = static_cast<Real>( strtoul10_64 ( c, &c) );
-        }
+	if ((c[0] == 'N' || c[0] == 'n') && ASSIMP_strincmp(c, "nan", 3) == 0)
+	{
+		out = std::numeric_limits<Real>::quiet_NaN();
+		c += 3;
+		return c;
+	}
+
+	if ((c[0] == 'I' || c[0] == 'i') && ASSIMP_strincmp(c, "inf", 3) == 0)
+	{
+		out = std::numeric_limits<Real>::infinity();
+		c += 3;
+		if ((c[0] == 'I' || c[0] == 'i') && ASSIMP_strincmp(c, "inity", 5) == 0)
+		{
+			c += 5;
+		}
+		return c;
+	}
+
+	if (!(c[0] >= '0' && c[0] <= '9') &&
+	    !(c[0] == '.' && c[1] >= '0' && c[1] <= '9'))
+	{
+		throw std::invalid_argument("Cannot parse string "
+		                            "as real number: does not start with digit "
+		                            "or decimal point followed by digit.");
+	}
+
+	if (*c != '.')
+	{
+		f = static_cast<Real>( strtoul10_64 ( c, &c) );
+	}
 
 	if ((*c == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9')
 	{