mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 06:58:56 +00:00
Encode characters outside the valid range for IFC SPF files and escape backslashes when writing IFC files
This commit is contained in:
@@ -67,6 +67,7 @@
|
|||||||
#define CLEAR_HEX(C) (C &= ~(HEX(1)&HEX(2)&HEX(3)&HEX(4)&HEX(5)&HEX(6)&HEX(7)&HEX(8)))
|
#define CLEAR_HEX(C) (C &= ~(HEX(1)&HEX(2)&HEX(3)&HEX(4)&HEX(5)&HEX(6)&HEX(7)&HEX(8)))
|
||||||
|
|
||||||
using namespace IfcParse;
|
using namespace IfcParse;
|
||||||
|
using namespace IfcWrite;
|
||||||
|
|
||||||
void IfcCharacterDecoder::addChar(std::stringstream& s,const UChar32& ch) {
|
void IfcCharacterDecoder::addChar(std::stringstream& s,const UChar32& ch) {
|
||||||
#ifdef HAVE_ICU
|
#ifdef HAVE_ICU
|
||||||
@@ -296,3 +297,61 @@ std::string IfcCharacterDecoder::compatibility_charset = "";
|
|||||||
#else
|
#else
|
||||||
char IfcCharacterDecoder::substitution_character = '_';
|
char IfcCharacterDecoder::substitution_character = '_';
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
IfcCharacterEncoder::IfcCharacterEncoder(const std::string& input) {
|
||||||
|
if ( !converter) converter = ucnv_open("utf-8", &status);
|
||||||
|
str = input;
|
||||||
|
}
|
||||||
|
|
||||||
|
IfcCharacterEncoder::~IfcCharacterEncoder() {
|
||||||
|
if ( !converter) ucnv_close(converter);
|
||||||
|
converter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
IfcCharacterEncoder::operator std::string() {
|
||||||
|
#ifdef HAVE_ICU
|
||||||
|
// Either 2 or 4 to uses \X2 or \X4 respectively.
|
||||||
|
// Currently hardcoded to 4, but \X2 might be
|
||||||
|
// sufficient for nearly all purposes.
|
||||||
|
const int num_bytes = 4;
|
||||||
|
const std::string num_bytes_str = std::string(1,num_bytes + 0x30);
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
UChar32 ch;
|
||||||
|
|
||||||
|
const char* source = str.c_str();
|
||||||
|
const char* limit = &*str.end();
|
||||||
|
|
||||||
|
bool in_extended = false;
|
||||||
|
|
||||||
|
while(source < limit) {
|
||||||
|
ch = ucnv_getNextUChar(converter, &source, limit, &status);
|
||||||
|
const bool within_spf_range = ch >= 0x20 && ch <= 0x7e;
|
||||||
|
if ( in_extended && within_spf_range ) {
|
||||||
|
oss << "\\X0\\";
|
||||||
|
} else if ( !in_extended && !within_spf_range ) {
|
||||||
|
oss << "\\X" << num_bytes_str << "\\";
|
||||||
|
}
|
||||||
|
if ( within_spf_range ) {
|
||||||
|
oss.put(ch);
|
||||||
|
if ( ch == '\\' ) oss.put(ch);
|
||||||
|
} else {
|
||||||
|
oss << std::hex << std::setw(num_bytes*2) << std::uppercase << std::setfill('0') << (int) ch;
|
||||||
|
}
|
||||||
|
in_extended = !within_spf_range;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( in_extended ) oss << "\\X0\\";
|
||||||
|
|
||||||
|
return oss.str();
|
||||||
|
#else
|
||||||
|
return str;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_ICU
|
||||||
|
UErrorCode IfcCharacterEncoder::status = U_ZERO_ERROR;
|
||||||
|
UConverter* IfcCharacterEncoder::converter = 0;
|
||||||
|
#endif
|
||||||
@@ -73,4 +73,21 @@ namespace IfcParse {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace IfcWrite {
|
||||||
|
|
||||||
|
class IfcCharacterEncoder {
|
||||||
|
private:
|
||||||
|
#ifdef HAVE_ICU
|
||||||
|
static UErrorCode status;
|
||||||
|
static UConverter* converter;
|
||||||
|
std::string str;
|
||||||
|
#endif
|
||||||
|
public:
|
||||||
|
IfcCharacterEncoder(const std::string& input);
|
||||||
|
~IfcCharacterEncoder();
|
||||||
|
operator std::string();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -468,7 +468,7 @@ TokenArgument::operator IfcUtil::IfcSchemaEntity() const { return token.first->f
|
|||||||
TokenArgument::operator IfcEntities() const { throw IfcException("Argument is not a list of entities"); }
|
TokenArgument::operator IfcEntities() const { throw IfcException("Argument is not a list of entities"); }
|
||||||
unsigned int TokenArgument::Size() const { return 1; }
|
unsigned int TokenArgument::Size() const { return 1; }
|
||||||
ArgumentPtr TokenArgument::operator [] (unsigned int i) const { throw IfcException("Argument is not a list of arguments"); }
|
ArgumentPtr TokenArgument::operator [] (unsigned int i) const { throw IfcException("Argument is not a list of arguments"); }
|
||||||
std::string TokenArgument::toString(bool upper) const { return TokenFunc::toString(token); }
|
std::string TokenArgument::toString(bool upper) const { if ( upper && TokenFunc::isString(token) ) return IfcWrite::IfcCharacterEncoder(TokenFunc::toString(token)); else return TokenFunc::toString(token); }
|
||||||
bool TokenArgument::isNull() const { return TokenFunc::isOperator(token,'$'); }
|
bool TokenArgument::isNull() const { return TokenFunc::isOperator(token,'$'); }
|
||||||
//
|
//
|
||||||
// Functions for casting the EntityArgument to other types
|
// Functions for casting the EntityArgument to other types
|
||||||
@@ -488,10 +488,11 @@ ArgumentPtr EntityArgument::operator [] (unsigned int i) const { throw IfcExcept
|
|||||||
std::string EntityArgument::toString(bool upper) const {
|
std::string EntityArgument::toString(bool upper) const {
|
||||||
ArgumentPtr arg = entity->wrappedValue();
|
ArgumentPtr arg = entity->wrappedValue();
|
||||||
IfcParse::TokenArgument* token_arg = dynamic_cast<IfcParse::TokenArgument*>(arg);
|
IfcParse::TokenArgument* token_arg = dynamic_cast<IfcParse::TokenArgument*>(arg);
|
||||||
std::string token_string = ( token_arg ) ? TokenFunc::toString(token_arg->token) : "";
|
std::string token_string = ( token_arg ) ? TokenFunc::toString(token_arg->token) : std::string();
|
||||||
std::string dt = Ifc2x3::Type::ToString(entity->type());
|
std::string dt = Ifc2x3::Type::ToString(entity->type());
|
||||||
if ( upper ) {
|
if ( upper ) {
|
||||||
for (std::string::iterator p = dt.begin(); p != dt.end(); ++p ) *p = toupper(*p);
|
for (std::string::iterator p = dt.begin(); p != dt.end(); ++p ) *p = toupper(*p);
|
||||||
|
token_string = IfcWrite::IfcCharacterEncoder(token_string);
|
||||||
}
|
}
|
||||||
return dt + "(" + token_string + ")";
|
return dt + "(" + token_string + ")";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "IfcParse.h"
|
#include "IfcParse.h"
|
||||||
#include "IfcWrite.h"
|
#include "IfcWrite.h"
|
||||||
#include "IfcWritableEntity.h"
|
#include "IfcWritableEntity.h"
|
||||||
|
#include "IfcCharacterDecoder.h"
|
||||||
|
|
||||||
using namespace IfcWrite;
|
using namespace IfcWrite;
|
||||||
|
|
||||||
@@ -284,10 +285,12 @@ std::string IfcWriteIntegralArgument::toString(bool upper) const {
|
|||||||
case Argument_DOUBLE:
|
case Argument_DOUBLE:
|
||||||
ss << *(double*) data;
|
ss << *(double*) data;
|
||||||
break;
|
break;
|
||||||
case Argument_STRING:
|
case Argument_STRING: {
|
||||||
ss << '\'' << *(std::string*) data << '\'';
|
std::string d = *(std::string*) data;
|
||||||
break;
|
if ( upper ) d = IfcCharacterEncoder(d);
|
||||||
case Argument_VECTOR_INT:
|
ss << '\'' << d << '\'';
|
||||||
|
break;
|
||||||
|
} case Argument_VECTOR_INT:
|
||||||
ss << "(";
|
ss << "(";
|
||||||
{const std::vector<int>& v = *(std::vector<int>*) data;
|
{const std::vector<int>& v = *(std::vector<int>*) data;
|
||||||
for ( std::vector<int>::const_iterator it = v.begin(); it != v.end(); ++ it ) {
|
for ( std::vector<int>::const_iterator it = v.begin(); it != v.end(); ++ it ) {
|
||||||
@@ -361,7 +364,7 @@ IfcSelectHelper::IfcSelectHelper(int v, Ifc2x3::Type::Enum t) {
|
|||||||
IfcWriteArgument* a = new IfcWriteIntegralArgument(v);
|
IfcWriteArgument* a = new IfcWriteIntegralArgument(v);
|
||||||
this->entity = new IfcSelectHelperEntity(t,a);
|
this->entity = new IfcSelectHelperEntity(t,a);
|
||||||
}
|
}
|
||||||
IfcSelectHelper::IfcSelectHelper(float v, Ifc2x3::Type::Enum t) {
|
IfcSelectHelper::IfcSelectHelper(double v, Ifc2x3::Type::Enum t) {
|
||||||
IfcWriteArgument* a = new IfcWriteIntegralArgument(v);
|
IfcWriteArgument* a = new IfcWriteIntegralArgument(v);
|
||||||
this->entity = new IfcSelectHelperEntity(t,a);
|
this->entity = new IfcSelectHelperEntity(t,a);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ namespace IfcWrite {
|
|||||||
IfcSelectHelper(const std::string& v, Ifc2x3::Type::Enum t=Ifc2x3::Type::IfcText);
|
IfcSelectHelper(const std::string& v, Ifc2x3::Type::Enum t=Ifc2x3::Type::IfcText);
|
||||||
IfcSelectHelper(const char* const v, Ifc2x3::Type::Enum t=Ifc2x3::Type::IfcText);
|
IfcSelectHelper(const char* const v, Ifc2x3::Type::Enum t=Ifc2x3::Type::IfcText);
|
||||||
IfcSelectHelper(int v, Ifc2x3::Type::Enum t=Ifc2x3::Type::IfcInteger);
|
IfcSelectHelper(int v, Ifc2x3::Type::Enum t=Ifc2x3::Type::IfcInteger);
|
||||||
IfcSelectHelper(float v, Ifc2x3::Type::Enum t=Ifc2x3::Type::IfcReal);
|
IfcSelectHelper(double v, Ifc2x3::Type::Enum t=Ifc2x3::Type::IfcReal);
|
||||||
IfcSelectHelper(bool v, Ifc2x3::Type::Enum t=Ifc2x3::Type::IfcBoolean);
|
IfcSelectHelper(bool v, Ifc2x3::Type::Enum t=Ifc2x3::Type::IfcBoolean);
|
||||||
bool is(Ifc2x3::Type::Enum t) const;
|
bool is(Ifc2x3::Type::Enum t) const;
|
||||||
Ifc2x3::Type::Enum type() const;
|
Ifc2x3::Type::Enum type() const;
|
||||||
|
|||||||
Reference in New Issue
Block a user