mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 10:51:13 +00:00
Make real number parsing and serializing locale-independent, as suggested by Ian Clevy.
This commit is contained in:
@@ -36,6 +36,27 @@
|
|||||||
|
|
||||||
using namespace IfcParse;
|
using namespace IfcParse;
|
||||||
|
|
||||||
|
// A static locale for the real number parser. strtod() is locale-dependent, causing issues
|
||||||
|
// in locales that have ',' as a decimal separator. Therefore the non standard _strtod_l() /
|
||||||
|
// strtod_l() is used and a reference to the "C" locale is obtained here. The alternative is
|
||||||
|
// to use std::istringstream::imbue(std::locale::classic()), but there are subtleties in
|
||||||
|
// parsing in MSVC2010 and it appears to be much slower.
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
static _locale_t locale = (_locale_t) 0;
|
||||||
|
void init_locale() {
|
||||||
|
if (locale == (_locale_t) 0) {
|
||||||
|
locale = _create_locale(LC_NUMERIC, "C");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static locale_t locale = (locale_t) 0;
|
||||||
|
void init_locale() {
|
||||||
|
if (locale == (_locale_t) 0) {
|
||||||
|
locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// Opens the file, gets the filesize and reads a chunk in memory
|
// Opens the file, gets the filesize and reads a chunk in memory
|
||||||
//
|
//
|
||||||
@@ -363,7 +384,11 @@ double TokenFunc::asFloat(const Token& t) {
|
|||||||
const std::string str = asString(t);
|
const std::string str = asString(t);
|
||||||
const char* start = str.c_str();
|
const char* start = str.c_str();
|
||||||
char* end;
|
char* end;
|
||||||
double result = strtod(start,&end);
|
#ifdef _MSC_VER
|
||||||
|
double result = _strtod_l(start,&end,locale);
|
||||||
|
#else
|
||||||
|
double result = strtod_l(start,&end,locale);
|
||||||
|
#endif
|
||||||
if ( start == end ) throw IfcException("Token is not a real");
|
if ( start == end ) throw IfcException("Token is not a real");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -693,6 +718,10 @@ bool IfcFile::Init(void* data, int len) {
|
|||||||
return IfcFile::Init(new IfcSpfStream(data,len));
|
return IfcFile::Init(new IfcSpfStream(data,len));
|
||||||
}
|
}
|
||||||
bool IfcFile::Init(IfcParse::IfcSpfStream* f) {
|
bool IfcFile::Init(IfcParse::IfcSpfStream* f) {
|
||||||
|
// Initialize a "C" locale for locale-independent
|
||||||
|
// number parsing. See comment above on line 41.
|
||||||
|
init_locale();
|
||||||
|
|
||||||
Ifc2x3::InitStringMap();
|
Ifc2x3::InitStringMap();
|
||||||
file = f;
|
file = f;
|
||||||
if ( ! file->valid ) return false;
|
if ( ! file->valid ) return false;
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
* *
|
* *
|
||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <locale>
|
||||||
|
|
||||||
#include "../ifcparse/IfcParse.h"
|
#include "../ifcparse/IfcParse.h"
|
||||||
#include "../ifcparse/IfcWrite.h"
|
#include "../ifcparse/IfcWrite.h"
|
||||||
@@ -196,7 +197,8 @@ private:
|
|||||||
// REAL = [ SIGN ] DIGIT { DIGIT } "." { DIGIT } [ "E" [ SIGN ] DIGIT { DIGIT } ] .
|
// REAL = [ SIGN ] DIGIT { DIGIT } "." { DIGIT } [ "E" [ SIGN ] DIGIT { DIGIT } ] .
|
||||||
std::string format_double(const double& d) {
|
std::string format_double(const double& d) {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << std::setprecision(16) << d;
|
oss.imbue(std::locale::classic());
|
||||||
|
oss << std::setprecision(15) << d;
|
||||||
const std::string str = oss.str();
|
const std::string str = oss.str();
|
||||||
oss.str("");
|
oss.str("");
|
||||||
std::string::size_type e = str.find('e');
|
std::string::size_type e = str.find('e');
|
||||||
|
|||||||
Reference in New Issue
Block a user