3838
3939using namespace IfcParse ;
4040
41+ // A static locale for the real number parser. strtod() is locale-dependent, causing issues
42+ // in locales that have ',' as a decimal separator. Therefore the non standard _strtod_l() /
43+ // strtod_l() is used and a reference to the "C" locale is obtained here. The alternative is
44+ // to use std::istringstream::imbue(std::locale::classic()), but there are subtleties in
45+ // parsing in MSVC2010 and it appears to be much slower.
46+ #ifdef _MSC_VER
47+ static _locale_t locale = (_locale_t ) 0 ;
48+ void init_locale () {
49+ if (locale == (_locale_t ) 0 ) {
50+ locale = _create_locale (LC_NUMERIC, " C" );
51+ }
52+ }
53+ #else
54+ static locale_t locale = (locale_t ) 0 ;
55+ void init_locale () {
56+ if (locale == (_locale_t ) 0 ) {
57+ locale = newlocale (LC_NUMERIC_MASK, " C" , (locale_t ) 0 );
58+ }
59+ }
60+ #endif
61+
4162//
4263// Opens the file, gets the filesize and reads a chunk in memory
4364//
@@ -333,22 +354,28 @@ Token IfcParse::TokenPtr() { return Token((IfcSpfLexer*)0,0); }
333354bool TokenFunc::startsWith (const Token& t, char c) {
334355 return t.first ->stream ->Read (t.second ) == c;
335356}
357+
336358bool TokenFunc::isOperator (const Token& t, char op) {
337359 return (!t.first ) && (!op || op == t.second );
338360}
361+
339362bool TokenFunc::isIdentifier (const Token& t) {
340363 return ! isOperator (t) && startsWith (t, ' #' );
341364}
365+
342366bool TokenFunc::isString (const Token& t) {
343367 return ! isOperator (t) && startsWith (t, ' \' ' );
344368}
369+
345370bool TokenFunc::isEnumeration (const Token& t) {
346371 return ! isOperator (t) && startsWith (t, ' .' );
347372}
373+
348374bool TokenFunc::isKeyword (const Token& t) {
349375 // bool is a subtype of enumeration, no need to test for that
350376 return !isOperator (t) && !isIdentifier (t) && !isString (t) && !isEnumeration (t) && !isInt (t) && !isFloat (t);
351377}
378+
352379bool TokenFunc::isInt (const Token& t) {
353380 if (isOperator (t)) return false ;
354381 const std::string str = asString (t);
@@ -357,19 +384,26 @@ bool TokenFunc::isInt(const Token& t) {
357384 long result = strtol (start,&end,10 );
358385 return ((end - start) == str.length ());
359386}
387+
360388bool TokenFunc::isBool (const Token& t) {
361389 if (!isEnumeration (t)) return false ;
362390 const std::string str = asString (t);
363391 return str == " T" || str == " F" ;
364392}
393+
365394bool TokenFunc::isFloat (const Token& t) {
366395 if (isOperator (t)) return false ;
367396 const std::string str = asString (t);
368397 const char * start = str.c_str ();
369398 char * end;
370- double result = strtod (start,&end);
399+ #ifdef _MSC_VER
400+ double result = _strtod_l (start,&end,locale);
401+ #else
402+ double result = strtod_l (start,&end,locale);
403+ #endif
371404 return ((end - start) == str.length ());
372405}
406+
373407int TokenFunc::asInt (const Token& t) {
374408 const std::string str = asString (t);
375409 // In case of an ENTITY_INSTANCE_NAME skip the leading #
@@ -379,24 +413,32 @@ int TokenFunc::asInt(const Token& t) {
379413 if ( start == end ) throw IfcException (" Token is not an integer or identifier" );
380414 return (int ) result;
381415}
416+
382417bool TokenFunc::asBool (const Token& t) {
383418 const std::string str = asString (t);
384419 return str == " T" ;
385420}
421+
386422double TokenFunc::asFloat (const Token& t) {
387423 const std::string str = asString (t);
388424 const char * start = str.c_str ();
389425 char * end;
390- double result = strtod (start,&end);
426+ #ifdef _MSC_VER
427+ double result = _strtod_l (start,&end,locale);
428+ #else
429+ double result = strtod_l (start,&end,locale);
430+ #endif
391431 if ( start == end ) throw IfcException (" Token is not a real" );
392432 return result;
393433}
434+
394435std::string TokenFunc::asString (const Token& t) {
395436 if ( isOperator (t,' $' ) ) return " " ;
396437 else if ( isOperator (t) ) throw IfcException (" Token is not a string" );
397438 std::string str = t.first ->TokenString (t.second );
398439 return isString (t) || isEnumeration (t) ? str.substr (1 ,str.size ()-2 ) : str;
399440}
441+
400442std::string TokenFunc::toString (const Token& t) {
401443 if ( isOperator (t) ) return std::string ( (char *) &t.second , 1 );
402444 else return t.first ->TokenString (t.second );
@@ -769,6 +811,10 @@ bool IfcFile::Init(void* data, int len) {
769811 return IfcFile::Init (new IfcSpfStream (data,len));
770812}
771813bool IfcFile::Init (IfcParse::IfcSpfStream* s) {
814+ // Initialize a "C" locale for locale-independent
815+ // number parsing. See comment above on line 41.
816+ init_locale ();
817+
772818 stream = s;
773819 if (!stream->valid ) {
774820 return false ;
0 commit comments