2021-01-21 22:22:34 +01:00
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
# ifdef _MSC_VER
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# ifndef NOMINMAX
# define NOMINMAX
# endif
# ifndef NOMSG
# define NOMSG NOMSG
# endif
# ifndef NODRAWTEXT
# define NODRAWTEXT NODRAWTEXT
# endif
# ifndef NOGDI
# define NOGDI NOGDI
# endif
# ifndef NOSERVICE
2023-09-17 12:30:17 +02:00
# define NOSERVICE NOSERVICE
2021-01-21 22:22:34 +01:00
# endif
# ifndef NOKERNEL
# define NOKERNEL NOKERNEL
# endif
# ifndef NOUSER
# define NOUSER NOUSER
# endif
# ifndef NOMCX
# define NOMCX NOMCX
# endif
# ifndef NOIME
# define NOIME NOIME
# endif
# include <Windows.h>
# endif
2023-09-17 12:30:17 +02:00
# include "aggregate_of_instance.h"
# include "Argument.h"
# include "IfcBaseClass.h"
# include "IfcException.h"
# include "utils.h"
2024-08-23 20:29:07 +02:00
# include "IfcFile.h"
2021-01-21 22:22:34 +01:00
2023-09-17 12:30:17 +02:00
# include <algorithm>
2021-01-21 22:22:34 +01:00
# include <boost/algorithm/string/replace.hpp>
# include <boost/optional.hpp>
2023-11-06 20:29:00 +01:00
void aggregate_of_instance : : push ( IfcUtil : : IfcBaseClass * instance ) {
if ( instance ! = nullptr ) {
list_ . push_back ( instance ) ;
2023-09-17 12:30:17 +02:00
}
2021-01-21 22:22:34 +01:00
}
2023-11-06 20:29:00 +01:00
void aggregate_of_instance : : push ( const aggregate_of_instance : : ptr & instance ) {
if ( instance ) {
for ( it i = instance - > begin ( ) ; i ! = instance - > end ( ) ; + + i ) {
2023-10-24 14:16:26 +02:00
if ( * i ! = nullptr ) {
2023-11-06 20:38:19 +01:00
list_ . push_back ( * i ) ;
2023-09-17 12:30:17 +02:00
}
}
}
2021-01-21 22:22:34 +01:00
}
2025-10-13 20:47:43 +02:00
size_t aggregate_of_instance : : size ( ) const { return list_ . size ( ) ; }
void aggregate_of_instance : : reserve ( size_t capacity ) { list_ . reserve ( capacity ) ; }
2023-11-06 20:38:19 +01:00
aggregate_of_instance : : it aggregate_of_instance : : begin ( ) { return list_ . begin ( ) ; }
aggregate_of_instance : : it aggregate_of_instance : : end ( ) { return list_ . end ( ) ; }
2023-09-17 12:30:17 +02:00
IfcUtil : : IfcBaseClass * aggregate_of_instance : : operator [ ] ( int i ) {
2023-11-06 20:38:19 +01:00
return list_ [ i ] ;
2021-01-21 22:22:34 +01:00
}
2021-07-29 14:54:51 +02:00
bool aggregate_of_instance : : contains ( IfcUtil : : IfcBaseClass * instance ) const {
2023-11-06 20:38:19 +01:00
return std : : find ( list_ . begin ( ) , list_ . end ( ) , instance ) ! = list_ . end ( ) ;
2021-01-21 22:22:34 +01:00
}
2021-07-29 14:54:51 +02:00
void aggregate_of_instance : : remove ( IfcUtil : : IfcBaseClass * instance ) {
2023-11-06 20:29:00 +01:00
std : : vector < IfcUtil : : IfcBaseClass * > : : iterator iter ;
while ( ( iter = std : : find ( list_ . begin ( ) , list_ . end ( ) , instance ) ) ! = list_ . end ( ) ) {
list_ . erase ( iter ) ;
2023-09-17 12:30:17 +02:00
}
2021-01-21 22:22:34 +01:00
}
2021-07-29 14:54:51 +02:00
aggregate_of_instance : : ptr aggregate_of_instance : : filtered ( const std : : set < const IfcParse : : declaration * > & entities ) {
2023-09-17 12:30:17 +02:00
aggregate_of_instance : : ptr return_value ( new aggregate_of_instance ) ;
for ( it it = begin ( ) ; it ! = end ( ) ; + + it ) {
bool contained = false ;
for ( std : : set < const IfcParse : : declaration * > : : const_iterator jt = entities . begin ( ) ; jt ! = entities . end ( ) ; + + jt ) {
if ( ( * it ) - > declaration ( ) . is ( * * jt ) ) {
contained = true ;
break ;
}
}
if ( ! contained ) {
return_value - > push ( * it ) ;
}
}
return return_value ;
2021-01-21 22:22:34 +01:00
}
2021-07-29 14:54:51 +02:00
aggregate_of_instance : : ptr aggregate_of_instance : : unique ( ) {
2023-09-17 12:30:17 +02:00
std : : set < IfcUtil : : IfcBaseClass * > encountered ;
aggregate_of_instance : : ptr return_value ( new aggregate_of_instance ) ;
for ( it it = begin ( ) ; it ! = end ( ) ; + + it ) {
if ( encountered . find ( * it ) = = encountered . end ( ) ) {
return_value - > push ( * it ) ;
encountered . insert ( * it ) ;
}
}
return return_value ;
2021-01-21 22:22:34 +01:00
}
2024-08-23 20:29:07 +02:00
/*
2021-01-21 22:22:34 +01:00
//Note: some of these methods are overloaded in derived classes
Argument::operator int() const { throw IfcParse::IfcException("Argument is not an integer"); }
Argument::operator bool() const { throw IfcParse::IfcException("Argument is not a boolean"); }
2021-07-29 14:54:51 +02:00
Argument::operator boost::logic::tribool() const { throw IfcParse::IfcException("Argument is not a logical"); }
2021-01-21 22:22:34 +01:00
Argument::operator double() const { throw IfcParse::IfcException("Argument is not a number"); }
Argument::operator std::string() const { throw IfcParse::IfcException("Argument is not a string"); }
Argument::operator boost::dynamic_bitset<>() const { throw IfcParse::IfcException("Argument is not a binary"); }
Argument::operator IfcUtil::IfcBaseClass*() const { throw IfcParse::IfcException("Argument is not an entity instance"); }
Argument::operator std::vector<double>() const { throw IfcParse::IfcException("Argument is not a list of floats"); }
Argument::operator std::vector<int>() const { throw IfcParse::IfcException("Argument is not a list of ints"); }
Argument::operator std::vector<std::string>() const { throw IfcParse::IfcException("Argument is not a list of strings"); }
2023-09-17 12:30:17 +02:00
Argument::operator std::vector<boost::dynamic_bitset<>>() const { throw IfcParse::IfcException("Argument is not a list of binaries"); }
2021-07-29 14:54:51 +02:00
Argument::operator aggregate_of_instance::ptr() const { throw IfcParse::IfcException("Argument is not a list of entity instances"); }
2023-09-17 12:30:17 +02:00
Argument::operator std::vector<std::vector<int>>() const { throw IfcParse::IfcException("Argument is not a list of list of ints"); }
Argument::operator std::vector<std::vector<double>>() const { throw IfcParse::IfcException("Argument is not a list of list of floats"); }
2021-07-29 14:54:51 +02:00
Argument::operator aggregate_of_aggregate_of_instance::ptr() const { throw IfcParse::IfcException("Argument is not a list of list of entity instances"); }
2024-08-23 20:29:07 +02:00
*/
2021-01-21 22:22:34 +01:00
static const char * const argument_type_string [ ] = {
2023-09-17 12:30:17 +02:00
" NULL " ,
" DERIVED " ,
" INT " ,
" BOOL " ,
" LOGICAL " ,
" DOUBLE " ,
" STRING " ,
" BINARY " ,
" ENUMERATION " ,
" ENTITY INSTANCE " ,
" EMPTY AGGREGATE " ,
" AGGREGATE OF INT " ,
" AGGREGATE OF DOUBLE " ,
" AGGREGATE OF STRING " ,
" AGGREGATE OF BINARY " ,
" AGGREGATE OF ENTITY INSTANCE " ,
" AGGREGATE OF EMPTY AGGREGATE " ,
" AGGREGATE OF AGGREGATE OF INT " ,
" AGGREGATE OF AGGREGATE OF DOUBLE " ,
" AGGREGATE OF AGGREGATE OF ENTITY INSTANCE " ,
" UNKNOWN " } ;
2021-01-21 22:22:34 +01:00
const char * IfcUtil : : ArgumentTypeToString ( ArgumentType argument_type ) {
2023-09-17 12:30:17 +02:00
return argument_type_string [ static_cast < int > ( argument_type ) ] ;
2021-01-21 22:22:34 +01:00
}
2023-11-06 20:29:00 +01:00
bool IfcUtil : : valid_binary_string ( const std : : string & str ) {
for ( std : : string : : const_iterator it = str . begin ( ) ; it ! = str . end ( ) ; + + it ) {
2023-09-17 12:30:17 +02:00
if ( * it ! = ' 0 ' & & * it ! = ' 1 ' ) {
return false ;
}
}
return true ;
2021-01-21 22:22:34 +01:00
}
2023-09-17 12:30:17 +02:00
void IfcUtil : : sanitate_material_name ( std : : string & str ) {
2021-01-21 22:22:34 +01:00
// Spaces in material names have been observed to cause problems with obj and dae importers.
// Handle other potential problematic characters here too if observing problems.
boost : : replace_all ( str , " " , " _ " ) ;
}
2023-09-17 12:30:17 +02:00
void IfcUtil : : escape_xml ( std : : string & str ) {
boost : : replace_all ( str , " & " , " & " ) ;
2021-01-21 22:22:34 +01:00
boost : : replace_all ( str , " \" " , " " " ) ;
boost : : replace_all ( str , " ' " , " ' " ) ;
boost : : replace_all ( str , " < " , " < " ) ;
boost : : replace_all ( str , " > " , " > " ) ;
}
2023-09-17 12:30:17 +02:00
void IfcUtil : : unescape_xml ( std : : string & str ) {
boost : : replace_all ( str , " & " , " & " ) ;
2021-01-21 22:22:34 +01:00
boost : : replace_all ( str , " " " , " \" " ) ;
boost : : replace_all ( str , " ' " , " ' " ) ;
boost : : replace_all ( str , " < " , " < " ) ;
boost : : replace_all ( str , " > " , " > " ) ;
}
2024-10-07 20:41:34 +02:00
IfcUtil : : IfcBaseEntity : : IfcBaseEntity ( IfcEntityInstanceData & & data )
: IfcBaseClass ( std : : move ( data ) )
{ }
void IfcUtil : : IfcBaseEntity : : populate_derived ( ) {
2024-11-28 12:57:08 +01:00
for ( auto it = declaration ( ) . as_entity ( ) - > derived ( ) . begin ( ) ; it ! = declaration ( ) . as_entity ( ) - > derived ( ) . end ( ) ; + + it ) {
2024-10-07 20:41:34 +02:00
if ( * it ) {
2025-02-27 22:07:31 +01:00
set_attribute_value (
2024-11-28 12:57:08 +01:00
std : : distance ( declaration ( ) . as_entity ( ) - > derived ( ) . begin ( ) , it ) ,
2024-10-07 20:41:34 +02:00
Derived { }
) ;
}
}
2021-01-21 22:22:34 +01:00
}
2024-08-23 20:29:07 +02:00
AttributeValue IfcUtil : : IfcBaseEntity : : get ( const std : : string & name ) const
{
auto attrs = declaration ( ) . as_entity ( ) - > all_attributes ( ) ;
auto iter = attrs . begin ( ) ;
size_t idx = 0 ;
for ( ; iter ! = attrs . end ( ) ; + + iter , + + idx ) {
if ( ( * iter ) - > name ( ) = = name ) {
2025-02-27 22:07:31 +01:00
return get_attribute_value ( idx ) ;
2024-08-23 20:29:07 +02:00
}
}
throw IfcParse : : IfcException ( name + " not found on " + declaration ( ) . name ( ) ) ;
}
2021-01-21 22:22:34 +01:00
2021-07-29 14:54:51 +02:00
aggregate_of_instance : : ptr IfcUtil : : IfcBaseEntity : : get_inverse ( const std : : string & name ) const {
2024-12-19 10:40:59 +01:00
if ( file_ = = nullptr ) {
throw IfcParse : : IfcException ( " Instance not added to file " ) ;
}
2023-09-17 12:30:17 +02:00
const std : : vector < const IfcParse : : inverse_attribute * > attrs = declaration ( ) . as_entity ( ) - > all_inverse_attributes ( ) ;
2023-11-06 20:29:00 +01:00
std : : vector < const IfcParse : : inverse_attribute * > : : const_iterator iter = attrs . begin ( ) ;
for ( ; iter ! = attrs . end ( ) ; + + iter ) {
if ( ( * iter ) - > name ( ) = = name ) {
2024-08-23 20:29:07 +02:00
return file_ - > getInverse (
id_ ,
2023-11-06 20:29:00 +01:00
( * iter ) - > entity_reference ( ) ,
( int ) ( * iter ) - > entity_reference ( ) - > attribute_index ( ( * iter ) - > attribute_reference ( ) ) ) ;
2023-09-17 12:30:17 +02:00
}
}
throw IfcParse : : IfcException ( name + " not found on " + declaration ( ) . name ( ) ) ;
2021-01-21 22:22:34 +01:00
}
2024-08-23 20:29:07 +02:00
/*
2023-11-06 20:29:00 +01:00
void IfcUtil::IfcBaseClass::data(IfcEntityInstanceData* data) {
2023-09-17 12:30:17 +02:00
delete data_;
2023-11-06 20:29:00 +01:00
data_ = data;
2021-01-21 22:22:34 +01:00
}
2024-08-23 20:29:07 +02:00
*/
2021-01-21 22:22:34 +01:00
IfcUtil : : ArgumentType IfcUtil : : make_aggregate ( IfcUtil : : ArgumentType elem_type ) {
2023-10-24 12:21:32 +02:00
switch ( elem_type ) {
case IfcUtil : : Argument_INT :
2023-09-17 12:30:17 +02:00
return IfcUtil : : Argument_AGGREGATE_OF_INT ;
2023-10-24 12:21:32 +02:00
case IfcUtil : : Argument_DOUBLE :
2023-09-17 12:30:17 +02:00
return IfcUtil : : Argument_AGGREGATE_OF_DOUBLE ;
2023-10-24 12:21:32 +02:00
case IfcUtil : : Argument_STRING :
2023-09-17 12:30:17 +02:00
return IfcUtil : : Argument_AGGREGATE_OF_STRING ;
2023-10-24 12:21:32 +02:00
case IfcUtil : : Argument_BINARY :
2023-09-17 12:30:17 +02:00
return IfcUtil : : Argument_AGGREGATE_OF_BINARY ;
2023-10-24 12:21:32 +02:00
case IfcUtil : : Argument_ENTITY_INSTANCE :
2023-09-17 12:30:17 +02:00
return IfcUtil : : Argument_AGGREGATE_OF_ENTITY_INSTANCE ;
2023-10-24 12:21:32 +02:00
case IfcUtil : : Argument_AGGREGATE_OF_INT :
2023-09-17 12:30:17 +02:00
return IfcUtil : : Argument_AGGREGATE_OF_AGGREGATE_OF_INT ;
2023-10-24 12:21:32 +02:00
case IfcUtil : : Argument_AGGREGATE_OF_DOUBLE :
2023-09-17 12:30:17 +02:00
return IfcUtil : : Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE ;
2023-10-24 12:21:32 +02:00
case IfcUtil : : Argument_AGGREGATE_OF_ENTITY_INSTANCE :
2023-09-17 12:30:17 +02:00
return IfcUtil : : Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE ;
2023-10-24 12:21:32 +02:00
case IfcUtil : : Argument_EMPTY_AGGREGATE :
2023-09-17 12:30:17 +02:00
return IfcUtil : : Argument_AGGREGATE_OF_EMPTY_AGGREGATE ;
2023-10-24 12:21:32 +02:00
default :
2023-09-17 12:30:17 +02:00
return IfcUtil : : Argument_UNKNOWN ;
}
2021-01-21 22:22:34 +01:00
}
IfcUtil : : ArgumentType IfcUtil : : from_parameter_type ( const IfcParse : : parameter_type * pt ) {
2023-09-17 12:30:17 +02:00
// TODO: How to detect derived types here without a reference to the refering entity?
const IfcParse : : aggregation_type * at = pt - > as_aggregation_type ( ) ;
const IfcParse : : named_type * nt = pt - > as_named_type ( ) ;
const IfcParse : : simple_type * st = pt - > as_simple_type ( ) ;
2023-10-24 14:16:26 +02:00
if ( at ! = nullptr ) {
2023-09-17 12:30:17 +02:00
return make_aggregate ( from_parameter_type ( at - > type_of_element ( ) ) ) ;
2023-10-24 12:21:32 +02:00
}
2023-10-24 14:16:26 +02:00
if ( nt ! = nullptr ) {
if ( nt - > declared_type ( ) - > as_entity ( ) ! = nullptr ) {
2023-09-17 12:30:17 +02:00
return IfcUtil : : Argument_ENTITY_INSTANCE ;
2023-10-24 12:21:32 +02:00
}
2023-10-24 14:16:26 +02:00
if ( nt - > declared_type ( ) - > as_enumeration_type ( ) ! = nullptr ) {
2023-09-17 12:30:17 +02:00
return IfcUtil : : Argument_ENUMERATION ;
2023-10-24 12:21:32 +02:00
}
2023-10-24 14:16:26 +02:00
if ( nt - > declared_type ( ) - > as_select_type ( ) ! = nullptr ) {
2023-09-17 12:30:17 +02:00
return IfcUtil : : Argument_ENTITY_INSTANCE ;
2023-10-24 12:21:32 +02:00
}
2023-10-24 14:16:26 +02:00
if ( nt - > declared_type ( ) - > as_type_declaration ( ) ! = nullptr ) {
2023-09-17 12:30:17 +02:00
return from_parameter_type ( nt - > declared_type ( ) - > as_type_declaration ( ) - > declared_type ( ) ) ;
}
2023-10-24 14:16:26 +02:00
} else if ( st ! = nullptr ) {
2023-09-17 12:30:17 +02:00
switch ( st - > declared_type ( ) ) {
case IfcParse : : simple_type : : binary_type :
return IfcUtil : : Argument_BINARY ;
case IfcParse : : simple_type : : boolean_type :
return IfcUtil : : Argument_BOOL ;
case IfcParse : : simple_type : : integer_type :
return IfcUtil : : Argument_INT ;
case IfcParse : : simple_type : : logical_type :
return IfcUtil : : Argument_LOGICAL ;
case IfcParse : : simple_type : : number_type :
return IfcUtil : : Argument_DOUBLE ;
case IfcParse : : simple_type : : real_type :
return IfcUtil : : Argument_DOUBLE ;
case IfcParse : : simple_type : : string_type :
return IfcUtil : : Argument_STRING ;
case IfcParse : : simple_type : : datatype_COUNT :
throw IfcParse : : IfcException ( " Invalid simple type encountered " ) ;
}
}
return IfcUtil : : Argument_UNKNOWN ;
2021-01-21 22:22:34 +01:00
}
# ifdef _MSC_VER
std : : string IfcUtil : : path : : to_utf8 ( const std : : wstring & str ) {
2023-09-17 12:30:17 +02:00
int buffer_size = WideCharToMultiByte ( CP_UTF8 , 0 , str . c_str ( ) , - 1 , 0 , 0 , 0 , 0 ) ;
char * buffer = new char [ buffer_size ] ;
WideCharToMultiByte ( CP_UTF8 , 0 , str . c_str ( ) , - 1 , buffer , buffer_size , 0 , 0 ) ;
std : : string str_utf8 ( buffer ) ;
delete [ ] buffer ;
return str_utf8 ;
2021-01-21 22:22:34 +01:00
}
std : : wstring IfcUtil : : path : : from_utf8 ( const std : : string & str ) {
2023-09-17 12:30:17 +02:00
int buffer_size = MultiByteToWideChar ( CP_UTF8 , 0 , str . c_str ( ) , - 1 , 0 , 0 ) ;
wchar_t * buffer = new wchar_t [ buffer_size ] ;
MultiByteToWideChar ( CP_UTF8 , 0 , str . c_str ( ) , - 1 , buffer , buffer_size ) ;
std : : wstring str_wide ( buffer ) ;
delete [ ] buffer ;
return str_wide ;
2021-01-21 22:22:34 +01:00
}
IFC_PARSE_API bool IfcUtil : : path : : rename_file ( const std : : string & old_filename , const std : : string & new_filename ) {
2023-09-17 12:30:17 +02:00
std : : wstring old_filename_w = from_utf8 ( old_filename ) ;
std : : wstring new_filename_w = from_utf8 ( new_filename ) ;
delete_file ( new_filename ) ;
const bool success = ! ! MoveFileW ( old_filename_w . c_str ( ) , new_filename_w . c_str ( ) ) ;
return success ;
2021-01-21 22:22:34 +01:00
}
2026-07-07 12:49:08 +03:00
IFC_PARSE_API bool IfcUtil : : path : : atomic_rename_file ( const std : : string & old_filename , const std : : string & new_filename ) {
std : : wstring old_filename_w = from_utf8 ( old_filename ) ;
std : : wstring new_filename_w = from_utf8 ( new_filename ) ;
// MOVEFILE_REPLACE_EXISTING makes the replace atomic on NTFS (no unlink
// of the destination first). MOVEFILE_WRITE_THROUGH waits until the move
// is flushed to disk before returning.
const bool success = ! ! MoveFileExW ( old_filename_w . c_str ( ) , new_filename_w . c_str ( ) ,
MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH ) ;
return success ;
}
2021-01-21 22:22:34 +01:00
IFC_PARSE_API bool IfcUtil : : path : : delete_file ( const std : : string & filename ) {
2023-09-17 12:30:17 +02:00
std : : wstring filename_w = from_utf8 ( filename ) ;
const bool success = ! ! DeleteFileW ( filename_w . c_str ( ) ) ;
return success ;
2021-01-21 22:22:34 +01:00
}
# else
IFC_PARSE_API bool IfcUtil : : path : : rename_file ( const std : : string & old_filename , const std : : string & new_filename ) {
2023-09-17 12:30:17 +02:00
// Whether or not rename() replaces an existing file is implementation-specific,
// so remove() possible existing file always.
delete_file ( new_filename ) ;
return std : : rename ( old_filename . c_str ( ) , new_filename . c_str ( ) ) = = 0 ;
2021-01-21 22:22:34 +01:00
}
2026-07-07 12:49:08 +03:00
IFC_PARSE_API bool IfcUtil : : path : : atomic_rename_file ( const std : : string & old_filename , const std : : string & new_filename ) {
// POSIX rename() atomically replaces an existing destination on the same
// filesystem, so there is no window in which new_filename is missing.
return std : : rename ( old_filename . c_str ( ) , new_filename . c_str ( ) ) = = 0 ;
}
2021-01-21 22:22:34 +01:00
IFC_PARSE_API bool IfcUtil : : path : : delete_file ( const std : : string & filename ) {
2023-10-24 14:16:26 +02:00
return std : : remove ( filename . c_str ( ) ) ! = 0 ;
2021-01-21 22:22:34 +01:00
}
# endif