inline const char* fast_atoreal_move(const char* c, Real& out) { Real f; bool inv = (*c == '-'); if (inv || *c == '+') { ++c; } f = static_cast<Real>(strtoul10_64(c, &c)); if (*c == '.' || (c[0] == ',' && c[1] >= '0' && c[1] <= '9')) // allow for commas, too { ++c; // NOTE: The original implementation is highly inaccurate 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. FAST_ATOF_RELAVANT_DECIMALS can be a value between // 1 and 15. unsigned int diff = FAST_ATOF_RELAVANT_DECIMALS; double pl = static_cast<double>(strtoul10_64(c, &c, &diff)); pl *= fast_atof_table[diff]; f += static_cast<Real>(pl); } // 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 (*c == 'e' || *c == 'E') { ++c; const bool einv = (*c == '-'); if (einv || *c == '+') { ++c; } // The reason float constants are used here is that we've seen cases where compilers // would perform such casts on compile-time constants at runtime, which would be // bad considering how frequently fast_atoreal_move<float> is called in Assimp. Real exp = static_cast<Real>(strtoul10_64(c, &c)); if (einv) { exp = -exp; } f *= pow(static_cast<Real>(10.0f), exp); } if (inv) { f = -f; } out = f; return c; }
// ------------------------------------------------------------------------------------------------ uint64_t ParseTokenAsID(const Token& t, const char*& err_out) { err_out = NULL; if (t.Type() != TokenType_DATA) { err_out = "expected TOK_DATA token"; return 0L; } if(t.IsBinary()) { const char* data = t.begin(); if (data[0] != 'L') { err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)"; return 0L; } BE_NCONST uint64_t id = SafeParse<uint64_t>(data+1, t.end()); AI_SWAP8(id); return id; } // XXX: should use size_t here unsigned int length = static_cast<unsigned int>(t.end() - t.begin()); ai_assert(length > 0); const char* out; const uint64_t id = strtoul10_64(t.begin(),&out,&length); if (out > t.end()) { err_out = "failed to parse ID (text)"; return 0L; } return id; }
// ------------------------------------------------------------------------------------------------ size_t ParseTokenAsDim(const Token& t, const char*& err_out) { // same as ID parsing, except there is a trailing asterisk err_out = NULL; if (t.Type() != TokenType_DATA) { err_out = "expected TOK_DATA token"; return 0; } if(t.IsBinary()) { const char* data = t.begin(); if (data[0] != 'L') { err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)"; return 0; } BE_NCONST uint64_t id = SafeParse<uint64_t>(data+1, t.end()); AI_SWAP8(id); return static_cast<size_t>(id); } if(*t.begin() != '*') { err_out = "expected asterisk before array dimension"; return 0; } // XXX: should use size_t here unsigned int length = static_cast<unsigned int>(t.end() - t.begin()); if(length == 0) { err_out = "expected valid integer number after asterisk"; return 0; } const char* out; const size_t id = static_cast<size_t>(strtoul10_64(t.begin() + 1,&out,&length)); if (out > t.end()) { err_out = "failed to parse ID"; return 0; } return id; }