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.
pull/338/head
Jared Duke 2014-08-20 18:37:00 -07:00
parent 0ede630b10
commit ed124ccbab
1 changed files with 32 additions and 12 deletions

View File

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