From ed124ccbab7471599d7528f3b93179470dfa142b Mon Sep 17 00:00:00 2001 From: Jared Duke Date: Wed, 20 Aug 2014 18:37:00 -0700 Subject: [PATCH] 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. --- code/fast_atof.h | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/code/fast_atof.h b/code/fast_atof.h index 4ff666b38..03e08f404 100644 --- a/code/fast_atof.h +++ b/code/fast_atof.h @@ -16,7 +16,9 @@ #define __FAST_A_TO_F_H_INCLUDED__ #include -#include +#include + +#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[0] == 'N' || c[0] == 'n') && ASSIMP_strincmp(c, "nan", 3) == 0) + { + out = std::numeric_limits::quiet_NaN(); + c += 3; + return c; + } - if (*c != '.') - { - f = static_cast( strtoul10_64 ( c, &c) ); - } + if ((c[0] == 'I' || c[0] == 'i') && ASSIMP_strincmp(c, "inf", 3) == 0) + { + out = std::numeric_limits::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( strtoul10_64 ( c, &c) ); + } if ((*c == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9') {