2012-08-11 13:24:08 +00:00
/********************************************************************************
2011-07-11 09:33:18 +00: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/>. *
* *
********************************************************************************/
2011-05-08 11:04:32 +00:00
2011-09-25 09:53:22 +00:00
# include "../ifcparse/IfcCharacterDecoder.h"
2011-05-08 11:04:32 +00:00
# include "../ifcparse/IfcParse.h"
2011-09-25 09:53:22 +00:00
# include "../ifcparse/IfcException.h"
2017-06-05 17:26:58 +02:00
# include "../ifcparse/IfcBaseClass.h"
2015-01-05 14:11:42 +00:00
# include "../ifcparse/IfcSpfStream.h"
# include "../ifcparse/IfcFile.h"
2015-02-17 19:48:41 +00:00
# include "../ifcparse/IfcSIPrefix.h"
2015-09-08 20:40:54 +02:00
# include "../ifcparse/IfcSchema.h"
2019-02-08 15:18:55 +01:00
# include "../ifcparse/utils.h"
2011-05-08 11:04:32 +00:00
2017-07-23 14:52:04 +02:00
# ifdef USE_MMAP
# include <boost/filesystem/path.hpp>
# endif
2019-07-03 12:10:27 +02:00
# include <set>
# include <ctime>
# include <mutex>
# include <string>
# include <stdio.h>
# include <stdlib.h>
# include <algorithm>
# include <boost/circular_buffer.hpp>
# include <boost/algorithm/string.hpp>
# include <boost/math/special_functions/fpclassify.hpp>
2016-06-12 11:22:08 +02:00
# define PERMISSIVE_FLOAT
2011-05-08 11:04:32 +00:00
using namespace IfcParse ;
2015-02-03 13:53:36 +00:00
// 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.
2016-06-05 14:03:03 +02:00
# if defined(_MSC_VER)
2015-02-03 13:53:36 +00:00
static _locale_t locale = ( _locale_t ) 0 ;
void init_locale ( ) {
if ( locale = = ( _locale_t ) 0 ) {
locale = _create_locale ( LC_NUMERIC , " C " ) ;
}
}
2016-05-29 17:58:03 +01:00
2016-06-05 14:03:03 +02:00
# else
2015-02-03 13:53:36 +00:00
2016-06-05 14:03:03 +02:00
# if defined(__MINGW64__) || defined(__MINGW32__)
2016-05-29 17:58:03 +01:00
# include <locale>
# include <sstream>
typedef void * locale_t ;
2016-06-05 14:03:03 +02:00
static locale_t locale = ( locale_t ) 0 ;
2016-05-29 17:58:03 +01:00
void init_locale ( ) { }
double strtod_l ( const char * start , char * * end , locale_t loc ) {
2016-06-05 14:03:03 +02:00
double d ;
std : : stringstream ss ;
ss . imbue ( std : : locale : : classic ( ) ) ;
ss < < start ;
ss > > d ;
size_t nread = ss . tellg ( ) ;
* end = const_cast < char * > ( start ) + nread ;
return d ;
}
# else
# ifdef __APPLE__
# include <xlocale.h>
# endif
# include <locale.h>
static locale_t locale = ( locale_t ) 0 ;
void init_locale ( ) {
if ( locale = = ( locale_t ) 0 ) {
locale = newlocale ( LC_NUMERIC_MASK , " C " , ( locale_t ) 0 ) ;
}
2016-05-29 17:58:03 +01:00
}
2016-06-05 14:03:03 +02:00
2016-05-29 17:58:03 +01:00
# endif
2016-06-05 14:03:03 +02:00
# endif
2016-05-29 17:58:03 +01:00
2011-07-11 09:33:18 +00:00
//
2017-07-23 14:52:04 +02:00
// Opens the file and gets the filesize
2011-07-11 09:33:18 +00:00
//
2017-07-23 14:52:04 +02:00
# ifdef USE_MMAP
IfcSpfStream : : IfcSpfStream ( const std : : string & fn , bool mmap )
# else
2016-03-05 00:40:08 +02:00
IfcSpfStream : : IfcSpfStream ( const std : : string & fn )
2017-07-23 14:52:04 +02:00
# endif
: stream ( 0 )
, buffer ( 0 )
, valid ( false )
, eof ( false )
2016-03-05 00:40:08 +02:00
{
2012-12-31 11:47:46 +00:00
# ifdef _MSC_VER
2019-02-08 15:18:55 +01:00
std : : wstring fn_ws = IfcUtil : : path : : from_utf8 ( fn ) ;
const wchar_t * fn_wide = fn_ws . c_str ( ) ;
2017-07-23 14:52:04 +02:00
# ifdef USE_MMAP
if ( mmap ) {
mfs = boost : : iostreams : : mapped_file_source ( boost : : filesystem : : wpath ( fn_wide ) ) ;
} else {
# endif
stream = _wfopen ( fn_wide , L " rb " ) ;
# ifdef USE_MMAP
}
# endif
2012-12-31 11:47:46 +00:00
# else
2017-07-23 14:52:04 +02:00
# ifdef USE_MMAP
if ( mmap ) {
mfs = boost : : iostreams : : mapped_file_source ( fn ) ;
} else {
2012-12-31 11:47:46 +00:00
# endif
2017-07-23 14:52:04 +02:00
stream = fopen ( fn . c_str ( ) , " rb " ) ;
# ifdef USE_MMAP
}
# endif
# endif
# ifdef USE_MMAP
if ( mmap ) {
if ( ! mfs . is_open ( ) ) {
return ;
}
valid = true ;
buffer = mfs . data ( ) ;
ptr = 0 ;
len = mfs . size ( ) ;
} else {
# endif
if ( stream = = NULL ) {
return ;
}
valid = true ;
fseek ( stream , 0 , SEEK_END ) ;
size = ( unsigned int ) ftell ( stream ) ;
rewind ( stream ) ;
char * buffer_rw = new char [ size ] ;
len = ( unsigned int ) fread ( buffer_rw , 1 , size , stream ) ;
buffer = buffer_rw ;
eof = len = = 0 ;
ptr = 0 ;
fclose ( stream ) ;
# ifdef USE_MMAP
2011-08-07 10:21:22 +00:00
}
2012-05-26 09:00:30 +00:00
# endif
2011-07-11 09:33:18 +00:00
}
2016-03-05 00:40:08 +02:00
IfcSpfStream : : IfcSpfStream ( std : : istream & f , int l )
2017-07-23 14:52:04 +02:00
: stream ( 0 )
, buffer ( 0 )
2016-03-05 00:40:08 +02:00
{
2011-08-20 09:08:56 +00:00
eof = false ;
size = l ;
2017-07-23 14:52:04 +02:00
char * buffer_rw = new char [ size ] ;
f . read ( buffer_rw , size ) ;
buffer = buffer_rw ;
2011-08-20 09:08:56 +00:00
valid = f . gcount ( ) = = size ;
ptr = 0 ;
2012-05-26 09:00:30 +00:00
len = l ;
2011-08-20 09:08:56 +00:00
}
2016-03-05 00:40:08 +02:00
IfcSpfStream : : IfcSpfStream ( void * data , int l )
2017-07-23 14:52:04 +02:00
: stream ( 0 )
, buffer ( 0 )
2016-03-05 00:40:08 +02:00
{
2011-10-27 16:13:29 +00:00
eof = false ;
size = l ;
buffer = ( char * ) data ;
valid = true ;
ptr = 0 ;
2016-03-05 00:40:08 +02:00
len = l ;
2011-10-27 16:13:29 +00:00
}
2016-02-07 22:45:42 +02:00
IfcSpfStream : : ~ IfcSpfStream ( )
{
Close ( ) ;
}
2012-08-11 13:24:08 +00:00
void IfcSpfStream : : Close ( ) {
2017-07-23 14:52:04 +02:00
# ifdef USE_MMAP
if ( mfs . is_open ( ) ) {
mfs . close ( ) ;
return ;
2011-07-11 09:33:18 +00:00
}
2012-08-11 13:24:08 +00:00
# endif
2017-07-23 14:52:04 +02:00
delete [ ] buffer ;
2011-07-11 09:33:18 +00:00
}
//
// Seeks an arbitrary position in the file
//
2012-08-11 13:24:08 +00:00
void IfcSpfStream : : Seek ( unsigned int o ) {
2017-07-23 14:52:04 +02:00
ptr = o ;
if ( ptr > = len ) throw IfcException ( " Reading outside of file limits " ) ;
eof = false ;
2011-07-11 09:33:18 +00:00
}
//
// Returns the character at the cursor
//
2012-08-11 13:24:08 +00:00
char IfcSpfStream : : Peek ( ) {
2011-07-11 09:33:18 +00:00
return buffer [ ptr ] ;
}
//
// Returns the character at specified offset
//
2012-08-11 13:24:08 +00:00
char IfcSpfStream : : Read ( unsigned int o ) {
2017-07-23 14:52:04 +02:00
return buffer [ o ] ;
2011-07-11 09:33:18 +00:00
}
//
// Returns the cursor position
//
2012-08-11 13:24:08 +00:00
unsigned int IfcSpfStream : : Tell ( ) {
2012-05-26 09:00:30 +00:00
return ptr ;
2011-07-11 09:33:18 +00:00
}
//
// Increments cursor and reads new chunk if necessary
//
2012-08-11 13:24:08 +00:00
void IfcSpfStream : : Inc ( ) {
2011-08-20 09:08:56 +00:00
if ( + + ptr = = len ) {
2017-07-23 14:52:04 +02:00
eof = true ;
return ;
2011-08-20 09:08:56 +00:00
}
2012-08-11 13:24:08 +00:00
const char current = IfcSpfStream : : Peek ( ) ;
2019-07-03 12:10:27 +02:00
if ( current = = ' \n ' | | current = = ' \r ' ) {
// NB this is recursive. It might as well be a loop.
IfcSpfStream : : Inc ( ) ;
}
2011-07-11 09:33:18 +00:00
}
2015-01-05 17:46:23 +00:00
IfcSpfLexer : : IfcSpfLexer ( IfcParse : : IfcSpfStream * s , IfcParse : : IfcFile * f ) {
2011-07-11 09:33:18 +00:00
file = f ;
2012-08-11 13:24:08 +00:00
stream = s ;
decoder = new IfcCharacterDecoder ( s ) ;
2011-09-25 09:53:22 +00:00
}
2015-01-05 17:46:23 +00:00
IfcSpfLexer : : ~ IfcSpfLexer ( ) {
2011-09-25 09:53:22 +00:00
delete decoder ;
2011-07-11 09:33:18 +00:00
}
2015-01-05 17:46:23 +00:00
unsigned int IfcSpfLexer : : skipWhitespace ( ) {
2014-04-02 15:04:09 +00:00
unsigned int n = 0 ;
while ( ! stream - > eof ) {
char c = stream - > Peek ( ) ;
if ( ( c = = ' ' | | c = = ' \r ' | | c = = ' \n ' | | c = = ' \t ' ) ) {
stream - > Inc ( ) ;
+ + n ;
}
else break ;
}
return n ;
}
2015-01-05 17:46:23 +00:00
unsigned int IfcSpfLexer : : skipComment ( ) {
2014-04-02 15:04:09 +00:00
char c = stream - > Peek ( ) ;
if ( c ! = ' / ' ) return 0 ;
stream - > Inc ( ) ;
c = stream - > Peek ( ) ;
if ( c ! = ' * ' ) {
stream - > Seek ( stream - > Tell ( ) - 1 ) ;
return 0 ;
}
unsigned int n = 2 ;
char p = 0 ;
while ( ! stream - > eof ) {
c = stream - > Peek ( ) ;
stream - > Inc ( ) ;
+ + n ;
if ( c = = ' / ' & & p = = ' * ' ) break ;
p = c ;
}
return n ;
}
2011-07-11 09:33:18 +00:00
//
// Returns the offset of the current Token and moves cursor to next
//
2015-01-05 17:46:23 +00:00
Token IfcSpfLexer : : Next ( ) {
2011-07-11 09:33:18 +00:00
2016-06-09 22:25:50 +06:00
if ( stream - > eof ) return NoneTokenPtr ( ) ;
2011-07-11 09:33:18 +00:00
2014-04-02 15:04:09 +00:00
while ( skipWhitespace ( ) | | skipComment ( ) ) { }
2016-06-09 22:25:50 +06:00
if ( stream - > eof ) return NoneTokenPtr ( ) ;
2012-08-11 13:24:08 +00:00
unsigned int pos = stream - > Tell ( ) ;
2011-07-11 09:33:18 +00:00
2014-04-02 15:04:09 +00:00
char c = stream - > Peek ( ) ;
2011-07-11 09:33:18 +00:00
// If the cursor is at [()=,;$*] we know token consists of single char
2014-04-19 09:35:08 +00:00
if ( c = = ' ( ' | | c = = ' ) ' | | c = = ' = ' | | c = = ' , ' | | c = = ' ; ' | | c = = ' $ ' | | c = = ' * ' ) {
2012-08-11 13:24:08 +00:00
stream - > Inc ( ) ;
2016-06-09 22:25:50 +06:00
return OperatorTokenPtr ( this , pos , pos + 1 ) ;
2011-07-11 09:33:18 +00:00
}
int len = 0 ;
2012-08-11 13:24:08 +00:00
while ( ! stream - > eof ) {
2011-07-11 09:33:18 +00:00
// Read character and increment pointer if not starting a new token
2015-11-21 23:05:28 +02:00
c = stream - > Peek ( ) ;
2014-04-19 09:35:08 +00:00
if ( len & & ( c = = ' ( ' | | c = = ' ) ' | | c = = ' = ' | | c = = ' , ' | | c = = ' ; ' | | c = = ' / ' ) ) break ;
2012-08-11 13:24:08 +00:00
stream - > Inc ( ) ;
2011-07-11 09:33:18 +00:00
len + + ;
2014-04-02 15:04:09 +00:00
// If a string is encountered defer processing to the IfcCharacterDecoder
2019-07-03 12:10:27 +02:00
if ( c = = ' \' ' ) decoder - > skip ( ) ;
2011-07-11 09:33:18 +00:00
}
2016-06-09 22:25:50 +06:00
if ( len ) return GeneralTokenPtr ( this , pos , stream - > Tell ( ) ) ;
else return NoneTokenPtr ( ) ;
2011-07-11 09:33:18 +00:00
}
2019-07-03 12:10:27 +02:00
bool IfcSpfStream : : is_eof_at ( unsigned int local_ptr ) {
return local_ptr > = len ;
}
void IfcSpfStream : : increment_at ( unsigned int & local_ptr ) {
if ( + + local_ptr = = len ) {
return ;
}
const char current = IfcSpfStream : : peek_at ( local_ptr ) ;
if ( current = = ' \n ' | | current = = ' \r ' ) IfcSpfStream : : increment_at ( local_ptr ) ;
}
char IfcSpfStream : : peek_at ( unsigned int local_ptr ) {
return buffer [ local_ptr ] ;
}
2011-07-11 09:33:18 +00:00
//
// Reads a std::string from the file at specified offset
// Omits whitespace and comments
//
2016-06-09 22:25:50 +06:00
void IfcSpfLexer : : TokenString ( unsigned int offset , std : : string & buffer ) {
buffer . clear ( ) ;
2019-07-03 12:10:27 +02:00
while ( ! stream - > is_eof_at ( offset ) ) {
char c = stream - > peek_at ( offset ) ;
2014-04-19 09:35:08 +00:00
if ( buffer . size ( ) & & ( c = = ' ( ' | | c = = ' ) ' | | c = = ' = ' | | c = = ' , ' | | c = = ' ; ' | | c = = ' / ' ) ) break ;
2019-07-03 12:10:27 +02:00
stream - > increment_at ( offset ) ;
2014-04-02 15:04:09 +00:00
if ( c = = ' ' | | c = = ' \r ' | | c = = ' \n ' | | c = = ' \t ' ) continue ;
2016-06-09 22:25:50 +06:00
else if ( c = = ' \' ' ) {
2019-07-03 12:10:27 +02:00
// todo, make decoder use local offset ptr
buffer = decoder - > get ( offset ) ;
2017-06-05 17:26:58 +02:00
break ;
2016-06-09 22:25:50 +06:00
}
2014-04-02 15:04:09 +00:00
else buffer . push_back ( c ) ;
2011-05-08 11:04:32 +00:00
}
2011-07-11 09:33:18 +00:00
}
2016-06-09 22:25:50 +06:00
//Note: according to STEP standard, there may be newlines in tokens
inline void RemoveTokenSeparators ( IfcSpfStream * stream , unsigned start , unsigned end , std : : string & oDestination ) {
oDestination . clear ( ) ;
for ( unsigned i = start ; i < end ; i + + ) {
char c = stream - > Read ( i ) ;
if ( c = = ' ' | | c = = ' \r ' | | c = = ' \n ' | | c = = ' \t ' )
continue ;
oDestination + = c ;
}
}
2011-07-11 09:33:18 +00:00
2016-06-09 22:25:50 +06:00
bool ParseInt ( const char * pStart , int & val ) {
char * pEnd ;
long result = strtol ( pStart , & pEnd , 10 ) ;
if ( * pEnd ! = 0 )
return false ;
val = ( int ) result ;
return true ;
}
bool ParseFloat ( const char * pStart , double & val ) {
char * pEnd ;
# ifdef _MSC_VER
double result = _strtod_l ( pStart , & pEnd , locale ) ;
# else
double result = strtod_l ( pStart , & pEnd , locale ) ;
# endif
if ( * pEnd ! = 0 )
return false ;
val = result ;
return true ;
}
bool ParseBool ( const char * pStart , bool & val ) {
if ( strlen ( pStart ) ! = 3 | | pStart [ 0 ] ! = ' . ' | | pStart [ 2 ] ! = ' . ' )
return false ;
char mid = pStart [ 1 ] ;
2016-06-20 11:34:13 +02:00
/// @todo https://github.com/IfcOpenShell/IfcOpenShell/issues/95
if ( ! ( mid = = ' T ' | | mid = = ' F ' | | mid = = ' U ' ) )
2016-06-09 22:25:50 +06:00
return false ;
val = ( mid = = ' T ' ) ;
return true ;
}
Token IfcParse : : OperatorTokenPtr ( IfcSpfLexer * lexer , unsigned start , unsigned end ) {
char first = lexer - > stream - > Read ( start ) ;
Token token ( lexer , start , end , Token_OPERATOR ) ;
token . value_char = first ;
return token ;
}
Token IfcParse : : GeneralTokenPtr ( IfcSpfLexer * lexer , unsigned start , unsigned end ) {
Token token ( lexer , start , end , Token_NONE ) ;
//extract token into temp buffer (remove eol-s, no encoding changes)
std : : string & tokenStr = lexer - > GetTempString ( ) ;
RemoveTokenSeparators ( lexer - > stream , start , end , tokenStr ) ;
//determine type of the token
char first = lexer - > stream - > Read ( start ) ;
if ( first = = ' # ' ) {
token . type = Token_IDENTIFIER ;
if ( ! ParseInt ( tokenStr . c_str ( ) + 1 , token . value_int ) )
throw IfcException ( " Identifier token as not integer " ) ;
}
else if ( first = = ' \' ' )
token . type = Token_STRING ;
else if ( first = = ' . ' ) {
token . type = Token_ENUMERATION ;
if ( ParseBool ( tokenStr . c_str ( ) , token . value_bool ) ) //bool is also enumeration
token . type = Token_BOOL ;
}
else if ( first = = ' " ' )
token . type = Token_BINARY ;
else if ( ParseInt ( tokenStr . c_str ( ) , token . value_int ) )
token . type = Token_INT ;
else if ( ParseFloat ( tokenStr . c_str ( ) , token . value_double ) )
token . type = Token_FLOAT ;
else
token . type = Token_KEYWORD ;
return token ;
}
Token IfcParse : : NoneTokenPtr ( ) { return Token ( ) ; }
bool TokenFunc : : isOperator ( const Token & t ) {
return t . type = = Token_OPERATOR ;
2011-05-08 11:04:32 +00:00
}
2015-02-03 13:53:36 +00:00
2012-08-11 13:24:08 +00:00
bool TokenFunc : : isOperator ( const Token & t , char op ) {
2016-06-09 22:25:50 +06:00
return t . type = = Token_OPERATOR & & t . value_char = = op ;
2011-06-13 07:23:09 +00:00
}
2015-02-03 13:53:36 +00:00
2012-08-11 13:24:08 +00:00
bool TokenFunc : : isIdentifier ( const Token & t ) {
2016-06-09 22:25:50 +06:00
return t . type = = Token_IDENTIFIER ;
2011-05-08 11:04:32 +00:00
}
2015-02-03 13:53:36 +00:00
2012-08-11 13:24:08 +00:00
bool TokenFunc : : isString ( const Token & t ) {
2016-06-09 22:25:50 +06:00
return t . type = = Token_STRING ;
2011-05-08 11:04:32 +00:00
}
2015-02-03 13:53:36 +00:00
2012-08-11 13:24:08 +00:00
bool TokenFunc : : isEnumeration ( const Token & t ) {
2016-06-09 22:25:50 +06:00
return t . type = = Token_ENUMERATION | | t . type = = Token_BOOL ;
2011-05-08 11:04:32 +00:00
}
2015-02-03 13:53:36 +00:00
2015-04-07 15:06:56 +00:00
bool TokenFunc : : isBinary ( const Token & t ) {
2016-06-09 22:25:50 +06:00
return t . type = = Token_BINARY ;
2015-04-07 15:06:56 +00:00
}
2015-01-05 17:46:23 +00:00
bool TokenFunc : : isKeyword ( const Token & t ) {
2016-06-09 22:25:50 +06:00
return t . type = = Token_KEYWORD ;
2011-05-08 11:04:32 +00:00
}
2015-02-03 13:53:36 +00:00
2014-11-02 18:36:51 +00:00
bool TokenFunc : : isInt ( const Token & t ) {
2016-06-09 22:25:50 +06:00
return t . type = = Token_INT ;
2014-11-02 18:36:51 +00:00
}
2015-02-03 13:53:36 +00:00
2014-11-02 18:36:51 +00:00
bool TokenFunc : : isBool ( const Token & t ) {
2016-06-09 22:25:50 +06:00
return t . type = = Token_BOOL ;
2014-11-02 18:36:51 +00:00
}
2015-02-03 13:53:36 +00:00
2014-11-02 18:36:51 +00:00
bool TokenFunc : : isFloat ( const Token & t ) {
2016-06-12 11:22:08 +02:00
# ifdef PERMISSIVE_FLOAT
/// NB: We are being more permissive here then allowed by the standard
2016-06-09 22:25:50 +06:00
return t . type = = Token_FLOAT | | t . type = = Token_INT ;
2016-06-12 11:22:08 +02:00
# else
return t . type = = Token_FLOAT ;
# endif
2014-11-02 18:36:51 +00:00
}
2015-02-03 13:53:36 +00:00
2012-08-11 13:24:08 +00:00
int TokenFunc : : asInt ( const Token & t ) {
2016-06-12 11:22:08 +02:00
if ( t . type ! = Token_INT ) {
throw IfcInvalidTokenException ( t . startPos , toString ( t ) , " integer " ) ;
}
2016-06-09 22:25:50 +06:00
return t . value_int ;
}
int TokenFunc : : asIdentifier ( const Token & t ) {
2016-06-12 11:22:08 +02:00
if ( t . type ! = Token_IDENTIFIER ) {
throw IfcInvalidTokenException ( t . startPos , toString ( t ) , " instance name " ) ;
}
2016-06-09 22:25:50 +06:00
return t . value_int ;
2011-06-13 07:23:09 +00:00
}
2015-02-03 13:53:36 +00:00
2012-08-11 13:24:08 +00:00
bool TokenFunc : : asBool ( const Token & t ) {
2016-06-12 11:22:08 +02:00
if ( t . type ! = Token_BOOL ) {
throw IfcInvalidTokenException ( t . startPos , toString ( t ) , " boolean " ) ;
}
2016-06-09 22:25:50 +06:00
return t . value_bool ;
2011-05-08 11:04:32 +00:00
}
2015-02-03 13:53:36 +00:00
2012-08-11 13:24:08 +00:00
double TokenFunc : : asFloat ( const Token & t ) {
2016-06-12 11:22:08 +02:00
# ifdef PERMISSIVE_FLOAT
if ( t . type = = Token_INT ) {
/// NB: We are being more permissive here then allowed by the standard
return t . value_int ;
} else // ----> continues beyond preprocessor directive
# endif
if ( t . type = = Token_FLOAT ) {
return t . value_double ;
} else {
throw IfcInvalidTokenException ( t . startPos , toString ( t ) , " real " ) ;
}
2016-06-09 22:25:50 +06:00
}
const std : : string & TokenFunc : : asStringRef ( const Token & t ) {
2017-03-02 16:12:20 +02:00
if ( t . type = = Token_NONE ) {
throw IfcParse : : IfcException ( " Null token encountered, premature end of file? " ) ;
}
2016-06-09 22:25:50 +06:00
std : : string & str = t . lexer - > GetTempString ( ) ;
t . lexer - > TokenString ( t . startPos , str ) ;
2016-06-14 20:30:02 +02:00
if ( ( isString ( t ) | | isEnumeration ( t ) | | isBinary ( t ) ) & & ! str . empty ( ) ) {
2016-06-09 22:25:50 +06:00
//remove start+end characters in-place
2016-06-14 20:30:02 +02:00
str . erase ( str . end ( ) - 1 ) ;
2016-06-09 22:25:50 +06:00
str . erase ( str . begin ( ) ) ;
}
return str ;
2011-07-11 09:33:18 +00:00
}
2015-02-03 13:53:36 +00:00
2012-08-11 13:24:08 +00:00
std : : string TokenFunc : : asString ( const Token & t ) {
2016-06-12 11:22:08 +02:00
if ( isString ( t ) | | isEnumeration ( t ) | | isBinary ( t ) ) {
return asStringRef ( t ) ;
} else {
throw IfcInvalidTokenException ( t . startPos , toString ( t ) , " string " ) ;
}
2015-04-07 15:06:56 +00:00
}
boost : : dynamic_bitset < > TokenFunc : : asBinary ( const Token & t ) {
2016-06-09 22:25:50 +06:00
const std : : string & str = asStringRef ( t ) ;
2015-04-07 15:06:56 +00:00
if ( str . size ( ) < 1 ) {
throw IfcException ( " Token is not a valid binary sequence " ) ;
}
std : : string : : const_iterator it = str . begin ( ) ;
int n = * it - ' 0 ' ;
if ( ( n < 0 | | n > 3 ) | | ( str . size ( ) = = 1 & & n ! = 0 ) ) {
throw IfcException ( " Token is not a valid binary sequence " ) ;
}
+ + it ;
2015-11-03 17:58:08 +02:00
unsigned i = ( ( unsigned ) str . size ( ) - 1 ) * 4 - n ;
2015-04-07 15:06:56 +00:00
boost : : dynamic_bitset < > bitset ( i ) ;
for ( ; it ! = str . end ( ) ; + + it ) {
const std : : string : : value_type & c = * it ;
int value = ( c < ' A ' ) ? ( c - ' 0 ' ) : ( c - ' A ' + 10 ) ;
for ( unsigned j = 0 ; j < 4 ; + + j ) {
if ( i - - = = 0 ) break ;
if ( value & ( 1 < < ( 3 - j ) ) ) {
bitset . set ( i ) ;
}
}
}
return bitset ;
2011-05-08 11:04:32 +00:00
}
2015-02-03 13:53:36 +00:00
2012-08-11 13:24:08 +00:00
std : : string TokenFunc : : toString ( const Token & t ) {
2016-06-09 22:25:50 +06:00
std : : string result ;
t . lexer - > TokenString ( t . startPos , result ) ;
return result ;
2011-07-11 09:33:18 +00:00
}
2011-05-08 11:04:32 +00:00
2012-08-11 13:24:08 +00:00
TokenArgument : : TokenArgument ( const Token & t ) {
2011-07-11 09:33:18 +00:00
token = t ;
2011-05-08 11:04:32 +00:00
}
2011-07-11 09:33:18 +00:00
2015-01-05 14:11:42 +00:00
EntityArgument : : EntityArgument ( const Token & t ) {
2016-06-09 22:25:50 +06:00
IfcParse : : IfcFile * file = t . lexer - > file ;
2017-06-05 17:26:58 +02:00
IfcEntityInstanceData * data = read ( 0 , file , t . startPos ) ;
2017-06-24 21:35:38 +02:00
// Data needs to be loaded, for the tokens
// to be consumed and parsing to continue.
data - > load ( ) ;
2017-12-13 13:16:49 +01:00
entity = file - > schema ( ) - > instantiate ( data ) ;
2011-05-08 11:04:32 +00:00
}
2011-07-11 09:33:18 +00:00
2018-01-29 12:11:50 +01:00
namespace {
template < typename T >
class vector_or_array {
std : : vector < T > * vector_ ;
T * array_ ;
size_t size_ , index_ ;
public :
vector_or_array ( std : : vector < T > * vector )
: vector_ ( vector )
, array_ ( 0 )
, size_ ( 0 )
, index_ ( 0 )
{ }
vector_or_array ( Argument * * arr , size_t size )
: vector_ ( 0 )
, array_ ( arr )
, size_ ( size )
, index_ ( 0 )
{ }
void push_back ( const T & t ) {
if ( array_ & & index_ < size_ ) {
array_ [ index_ + + ] = t ;
} else if ( vector_ ) {
vector_ - > push_back ( t ) ;
}
}
} ;
}
2011-07-11 09:33:18 +00:00
//
// Reads the arguments from a list of token
2017-06-05 17:26:58 +02:00
// Aditionally, registers the ids (i.e. #[\d]+) in the inverse map
2011-07-11 09:33:18 +00:00
//
2018-01-29 12:11:50 +01:00
size_t IfcParse : : IfcFile : : load ( unsigned entity_instance_name , Argument * * & attributes , size_t num_attributes ) {
2017-06-05 17:26:58 +02:00
Token next = tokens - > Next ( ) ;
2018-01-29 12:11:50 +01:00
std : : vector < Argument * > * vector = 0 ;
vector_or_array < Argument * > filler ( attributes , num_attributes ) ;
if ( attributes = = 0 ) {
vector = new std : : vector < Argument * > ( ) ;
filler = vector_or_array < Argument * > ( vector ) ;
}
2020-10-30 09:59:01 +01:00
size_t return_value = 0 ;
2018-01-29 12:11:50 +01:00
2016-06-09 22:25:50 +06:00
while ( next . startPos | | next . lexer ) {
2015-01-16 16:26:40 +00:00
if ( TokenFunc : : isOperator ( next , ' , ' ) ) {
// do nothing
} else if ( TokenFunc : : isOperator ( next , ' ) ' ) ) {
break ;
} else if ( TokenFunc : : isOperator ( next , ' ( ' ) ) {
2020-10-30 09:59:01 +01:00
return_value + + ;
2015-11-21 23:05:28 +02:00
ArgumentList * alist = new ArgumentList ( ) ;
2018-01-29 12:11:50 +01:00
alist - > size ( ) = load ( entity_instance_name , alist - > arguments ( ) , 0 ) ;
filler . push_back ( alist ) ;
2015-01-16 16:26:40 +00:00
} else {
2020-10-30 09:59:01 +01:00
return_value + + ;
2015-01-16 16:26:40 +00:00
if ( TokenFunc : : isIdentifier ( next ) ) {
2017-06-05 17:26:58 +02:00
if ( ! parsing_complete_ ) {
register_inverse ( entity_instance_name , next ) ;
}
2015-01-16 16:26:40 +00:00
} if ( TokenFunc : : isKeyword ( next ) ) {
2012-03-31 09:54:15 +00:00
try {
2018-01-29 12:11:50 +01:00
filler . push_back ( new EntityArgument ( next ) ) ;
2012-03-31 09:54:15 +00:00
} catch ( IfcException & e ) {
2017-06-05 17:26:58 +02:00
Logger : : Message ( Logger : : LOG_ERROR , e . what ( ) ) ;
2012-03-31 09:54:15 +00:00
}
2011-07-11 09:33:18 +00:00
} else {
2018-01-29 12:11:50 +01:00
filler . push_back ( new TokenArgument ( next ) ) ;
2011-07-11 09:33:18 +00:00
}
}
2017-06-05 17:26:58 +02:00
next = tokens - > Next ( ) ;
2011-07-11 09:33:18 +00:00
}
2018-01-29 12:11:50 +01:00
if ( vector ) {
attributes = new Argument * [ vector - > size ( ) ] ;
return_value = vector - > size ( ) ;
for ( size_t i = 0 ; i < vector - > size ( ) ; + + i ) {
attributes [ i ] = vector - > at ( i ) ;
}
}
delete vector ;
return return_value ;
2011-05-08 11:04:32 +00:00
}
2011-07-11 09:33:18 +00:00
2014-11-02 18:36:51 +00:00
IfcUtil : : ArgumentType ArgumentList : : type ( ) const {
2018-01-29 12:11:50 +01:00
if ( size_ = = 0 ) {
2016-11-08 17:24:08 +01:00
return IfcUtil : : Argument_EMPTY_AGGREGATE ;
}
2018-01-29 12:11:50 +01:00
const IfcUtil : : ArgumentType elem_type = list_ [ 0 ] - > type ( ) ;
2017-12-11 15:46:57 +01:00
return IfcUtil : : make_aggregate ( elem_type ) ;
2014-11-02 18:36:51 +00:00
}
2015-04-07 15:06:56 +00:00
// templated helper function for reading arguments into a list
template < typename T >
2018-01-29 12:11:50 +01:00
std : : vector < T > read_aggregate_as_vector ( Argument * * list , size_t size ) {
2015-04-07 15:06:56 +00:00
std : : vector < T > return_value ;
2018-01-29 12:11:50 +01:00
return_value . reserve ( size ) ;
for ( size_t i = 0 ; i < size ; + + i ) {
return_value . push_back ( * list [ i ] ) ;
2015-04-07 15:06:56 +00:00
}
return return_value ;
}
2015-06-16 12:58:07 +00:00
template < typename T >
2018-01-29 12:11:50 +01:00
std : : vector < std : : vector < T > > read_aggregate_of_aggregate_as_vector2 ( Argument * * list , size_t size ) {
2015-06-16 12:58:07 +00:00
std : : vector < std : : vector < T > > return_value ;
2018-01-29 12:11:50 +01:00
return_value . reserve ( size ) ;
for ( size_t i = 0 ; i < size ; + + i ) {
return_value . push_back ( * list [ i ] ) ;
2015-06-16 12:58:07 +00:00
}
return return_value ;
}
2015-04-07 15:06:56 +00:00
2011-07-11 09:33:18 +00:00
//
// Functions for casting the ArgumentList to other types
//
2012-03-13 11:56:52 +00:00
ArgumentList : : operator std : : vector < double > ( ) const {
2018-01-29 12:11:50 +01:00
return read_aggregate_as_vector < double > ( list_ , size_ ) ;
2011-07-25 14:56:40 +00:00
}
2015-06-16 12:58:07 +00:00
2011-07-25 14:56:40 +00:00
ArgumentList : : operator std : : vector < int > ( ) const {
2018-01-29 12:11:50 +01:00
return read_aggregate_as_vector < int > ( list_ , size_ ) ;
2011-07-25 14:56:40 +00:00
}
2015-06-16 12:58:07 +00:00
2011-07-25 14:56:40 +00:00
ArgumentList : : operator std : : vector < std : : string > ( ) const {
2018-01-29 12:11:50 +01:00
return read_aggregate_as_vector < std : : string > ( list_ , size_ ) ;
2015-04-07 15:06:56 +00:00
}
2015-06-16 12:58:07 +00:00
2015-04-07 15:06:56 +00:00
ArgumentList : : operator std : : vector < boost : : dynamic_bitset < > > ( ) const {
2018-01-29 12:11:50 +01:00
return read_aggregate_as_vector < boost : : dynamic_bitset < > > ( list_ , size_ ) ;
2011-07-25 14:56:40 +00:00
}
2015-06-16 12:58:07 +00:00
2014-05-04 14:42:55 +00:00
ArgumentList : : operator IfcEntityList : : ptr ( ) const {
IfcEntityList : : ptr l ( new IfcEntityList ( ) ) ;
2018-01-29 12:11:50 +01:00
for ( size_t i = 0 ; i < size_ ; + + i ) {
2011-07-11 09:33:18 +00:00
// FIXME: account for $
2018-01-29 12:11:50 +01:00
IfcUtil : : IfcBaseClass * entity = * list_ [ i ] ;
2011-07-11 09:33:18 +00:00
l - > push ( entity ) ;
}
return l ;
}
2015-06-16 12:58:07 +00:00
ArgumentList : : operator std : : vector < std : : vector < int > > ( ) const {
2018-01-29 12:11:50 +01:00
return read_aggregate_of_aggregate_as_vector2 < int > ( list_ , size_ ) ;
2015-06-16 12:58:07 +00:00
}
ArgumentList : : operator std : : vector < std : : vector < double > > ( ) const {
2018-01-29 12:11:50 +01:00
return read_aggregate_of_aggregate_as_vector2 < double > ( list_ , size_ ) ;
2015-06-16 12:58:07 +00:00
}
2014-05-04 14:42:55 +00:00
ArgumentList : : operator IfcEntityListList : : ptr ( ) const {
IfcEntityListList : : ptr l ( new IfcEntityListList ( ) ) ;
2018-01-29 12:11:50 +01:00
for ( size_t i = 0 ; i < size_ ; + + i ) {
const Argument * arg = list_ [ i ] ;
2014-05-04 14:42:55 +00:00
const ArgumentList * arg_list ;
2015-11-21 23:05:28 +02:00
if ( ( arg_list = dynamic_cast < const ArgumentList * > ( arg ) ) ! = 0 ) {
2014-05-04 14:42:55 +00:00
IfcEntityList : : ptr e = * arg_list ;
l - > push ( e ) ;
2019-11-01 16:11:46 +01:00
} else {
auto token = dynamic_cast < const TokenArgument * > ( arg ) ;
int startpos = token ? token - > token . startPos : 0 ;
std : : string string_rep = this - > toString ( ) ;
throw IfcInvalidTokenException ( startpos , string_rep , " nested aggregate " ) ;
2014-05-04 14:42:55 +00:00
}
}
return l ;
}
2015-06-16 12:58:07 +00:00
2018-01-29 12:11:50 +01:00
unsigned int ArgumentList : : size ( ) const { return ( unsigned int ) size_ ; }
2015-06-16 12:58:07 +00:00
2014-05-04 14:42:55 +00:00
Argument * ArgumentList : : operator [ ] ( unsigned int i ) const {
2018-01-29 12:11:50 +01:00
if ( i > = size_ ) {
2015-06-17 11:04:28 +00:00
throw IfcAttributeOutOfRangeException ( " Argument index out of range " ) ;
2015-01-16 16:26:40 +00:00
}
2018-01-29 12:11:50 +01:00
return list_ [ i ] ;
2011-07-11 09:33:18 +00:00
}
2015-06-16 12:58:07 +00:00
2018-01-29 12:11:50 +01:00
/*
2015-01-16 16:26:40 +00:00
void ArgumentList::set(unsigned int i, Argument* argument) {
while (size() < i) {
2016-06-09 22:25:50 +06:00
push(new NullArgument());
2015-01-16 16:26:40 +00:00
}
if (i < size()) {
delete list[i];
list[i] = argument;
} else {
list.push_back(argument);
}
}
2018-01-29 12:11:50 +01:00
*/
2015-06-16 12:58:07 +00:00
2012-03-13 11:56:52 +00:00
std : : string ArgumentList : : toString ( bool upper ) const {
2011-07-11 09:33:18 +00:00
std : : stringstream ss ;
ss < < " ( " ;
2018-01-29 12:11:50 +01:00
for ( size_t i = 0 ; i < size_ ; + + i ) {
if ( i ! = 0 ) {
ss < < " , " ;
}
ss < < list_ [ i ] - > toString ( upper ) ;
2011-05-08 11:04:32 +00:00
}
ss < < " ) " ;
return ss . str ( ) ;
}
2015-06-16 12:58:07 +00:00
2011-07-25 14:56:40 +00:00
bool ArgumentList : : isNull ( ) const { return false ; }
2015-06-16 12:58:07 +00:00
2011-09-03 13:58:59 +00:00
ArgumentList : : ~ ArgumentList ( ) {
2018-01-29 12:11:50 +01:00
for ( size_t i = 0 ; i < size_ ; + + i ) {
delete list_ [ i ] ;
2011-09-03 13:58:59 +00:00
}
2018-01-29 12:11:50 +01:00
delete [ ] list_ ;
2011-09-03 13:58:59 +00:00
}
2011-05-08 11:04:32 +00:00
2015-06-16 12:58:07 +00:00
2014-11-02 18:36:51 +00:00
IfcUtil : : ArgumentType TokenArgument : : type ( ) const {
if ( TokenFunc : : isInt ( token ) ) {
return IfcUtil : : Argument_INT ;
} else if ( TokenFunc : : isBool ( token ) ) {
return IfcUtil : : Argument_BOOL ;
} else if ( TokenFunc : : isFloat ( token ) ) {
return IfcUtil : : Argument_DOUBLE ;
} else if ( TokenFunc : : isString ( token ) ) {
return IfcUtil : : Argument_STRING ;
} else if ( TokenFunc : : isEnumeration ( token ) ) {
return IfcUtil : : Argument_ENUMERATION ;
} else if ( TokenFunc : : isIdentifier ( token ) ) {
2015-04-07 15:06:56 +00:00
return IfcUtil : : Argument_ENTITY_INSTANCE ;
} else if ( TokenFunc : : isBinary ( token ) ) {
return IfcUtil : : Argument_BINARY ;
2015-03-12 17:54:52 +00:00
} else if ( TokenFunc : : isOperator ( token , ' $ ' ) ) {
return IfcUtil : : Argument_NULL ;
} else if ( TokenFunc : : isOperator ( token , ' * ' ) ) {
return IfcUtil : : Argument_DERIVED ;
2014-11-02 18:36:51 +00:00
} else {
return IfcUtil : : Argument_UNKNOWN ;
}
}
2011-07-11 09:33:18 +00:00
//
// Functions for casting the TokenArgument to other types
//
TokenArgument : : operator int ( ) const { return TokenFunc : : asInt ( token ) ; }
TokenArgument : : operator bool ( ) const { return TokenFunc : : asBool ( token ) ; }
2012-03-13 11:56:52 +00:00
TokenArgument : : operator double ( ) const { return TokenFunc : : asFloat ( token ) ; }
2011-07-11 09:33:18 +00:00
TokenArgument : : operator std : : string ( ) const { return TokenFunc : : asString ( token ) ; }
2015-04-07 15:06:56 +00:00
TokenArgument : : operator boost : : dynamic_bitset < > ( ) const { return TokenFunc : : asBinary ( token ) ; }
2017-12-13 13:16:49 +01:00
TokenArgument : : operator IfcUtil : : IfcBaseClass * ( ) const { return token . lexer - > file - > instance_by_id ( TokenFunc : : asIdentifier ( token ) ) ; }
2015-01-10 22:13:52 +00:00
unsigned int TokenArgument : : size ( ) const { return 1 ; }
2015-11-23 15:52:12 +02:00
Argument * TokenArgument : : operator [ ] ( unsigned int /*i*/ ) const { throw IfcException ( " Argument is not a list of attributes " ) ; }
2012-10-09 19:54:35 +00:00
std : : string TokenArgument : : toString ( bool upper ) const {
if ( upper & & TokenFunc : : isString ( token ) ) {
return IfcWrite : : IfcCharacterEncoder ( TokenFunc : : asString ( token ) ) ;
} else {
return TokenFunc : : toString ( token ) ;
}
}
2011-07-25 14:56:40 +00:00
bool TokenArgument : : isNull ( ) const { return TokenFunc : : isOperator ( token , ' $ ' ) ; }
2014-11-02 18:36:51 +00:00
IfcUtil : : ArgumentType EntityArgument : : type ( ) const {
2015-04-07 15:06:56 +00:00
return IfcUtil : : Argument_ENTITY_INSTANCE ;
2014-11-02 18:36:51 +00:00
}
2011-07-11 09:33:18 +00:00
//
// Functions for casting the EntityArgument to other types
//
2015-01-05 14:11:42 +00:00
EntityArgument : : operator IfcUtil : : IfcBaseClass * ( ) const { return entity ; }
2015-01-10 22:13:52 +00:00
unsigned int EntityArgument : : size ( ) const { return 1 ; }
2015-11-23 15:52:12 +02:00
Argument * EntityArgument : : operator [ ] ( unsigned int /*i*/ ) const { throw IfcException ( " Argument is not a list of arguments " ) ; }
2012-03-13 11:56:52 +00:00
std : : string EntityArgument : : toString ( bool upper ) const {
2017-12-11 14:47:30 +01:00
return entity - > data ( ) . toString ( upper ) ;
2012-03-13 11:56:52 +00:00
}
2011-09-03 13:58:59 +00:00
//return entity->entity->toString(); }
2011-07-25 14:56:40 +00:00
bool EntityArgument : : isNull ( ) const { return false ; }
2017-12-11 14:47:30 +01:00
EntityArgument : : ~ EntityArgument ( ) { delete entity ; }
2011-07-11 09:33:18 +00:00
//
// Reads an Entity from the list of Tokens at the specified offset in the file
//
2017-06-05 17:26:58 +02:00
IfcEntityInstanceData * IfcParse : : read ( unsigned int i , IfcFile * f , boost : : optional < unsigned > offset ) {
if ( offset ) {
f - > tokens - > stream - > Seek ( * offset ) ;
2011-05-08 11:04:32 +00:00
}
2017-06-05 17:26:58 +02:00
Token datatype = f - > tokens - > Next ( ) ;
if ( ! TokenFunc : : isKeyword ( datatype ) ) throw IfcException ( " Unexpected token while parsing entity " ) ;
2017-12-13 13:16:49 +01:00
const IfcParse : : declaration * ty = f - > schema ( ) - > declaration_by_name ( TokenFunc : : asStringRef ( datatype ) ) ;
2017-06-05 17:26:58 +02:00
IfcEntityInstanceData * e = new IfcEntityInstanceData ( ty , f , i , offset . get_value_or ( 0 ) ) ;
return e ;
2011-05-08 11:04:32 +00:00
}
2011-07-11 09:33:18 +00:00
2019-07-03 12:10:27 +02:00
void IfcParse : : IfcFile : : seek_to ( const IfcEntityInstanceData & data ) {
2017-06-05 17:26:58 +02:00
if ( tokens - > stream - > Tell ( ) ! = data . offset_in_file ( ) ) {
tokens - > stream - > Seek ( data . offset_in_file ( ) ) ;
Token datatype = tokens - > Next ( ) ;
if ( ! TokenFunc : : isKeyword ( datatype ) ) throw IfcException ( " Unexpected token while parsing entity instance " ) ;
2011-09-25 09:53:22 +00:00
}
2017-06-05 17:26:58 +02:00
tokens - > Next ( ) ;
2019-07-03 12:10:27 +02:00
}
void IfcParse : : IfcFile : : try_read_semicolon ( ) {
2017-06-05 17:26:58 +02:00
unsigned int old_offset = tokens - > stream - > Tell ( ) ;
Token semilocon = tokens - > Next ( ) ;
if ( ! TokenFunc : : isOperator ( semilocon , ' ; ' ) ) {
tokens - > stream - > Seek ( old_offset ) ;
2011-05-08 11:04:32 +00:00
}
}
2011-07-11 09:33:18 +00:00
2017-06-05 17:26:58 +02:00
void IfcParse : : IfcFile : : register_inverse ( unsigned id_from , Token t ) {
// Assume a check on token type has already been performed
byref [ t . value_int ] . push_back ( id_from ) ;
2011-05-08 11:04:32 +00:00
}
2011-07-11 09:33:18 +00:00
2017-07-03 14:18:56 +02:00
void IfcParse : : IfcFile : : register_inverse ( unsigned id_from , IfcUtil : : IfcBaseClass * inst ) {
2017-12-11 14:47:30 +01:00
byref [ inst - > data ( ) . id ( ) ] . push_back ( id_from ) ;
2017-07-03 14:18:56 +02:00
}
void IfcParse : : IfcFile : : unregister_inverse ( unsigned id_from , IfcUtil : : IfcBaseClass * inst ) {
2017-12-11 14:47:30 +01:00
std : : vector < unsigned int > & ids = byref [ inst - > data ( ) . id ( ) ] ;
2017-07-03 14:42:08 +02:00
std : : vector < unsigned int > : : iterator it = std : : find ( ids . begin ( ) , ids . end ( ) , id_from ) ;
2017-07-03 14:18:56 +02:00
if ( it = = ids . end ( ) ) {
2017-07-03 16:38:04 +02:00
// @todo inverses also need to be populated when multiple instances are added to a new file.
// throw IfcParse::IfcException("Instance not found among inverses");
2017-07-03 14:18:56 +02:00
} else {
ids . erase ( it ) ;
}
}
2011-07-11 09:33:18 +00:00
//
// Returns a string representation of the entity
// Note that this initializes the entity if it is not initialized
//
2017-06-05 17:26:58 +02:00
std : : string IfcEntityInstanceData : : toString ( bool upper ) const {
2018-01-29 12:11:50 +01:00
if ( attributes_ = = 0 ) {
2017-06-24 21:35:38 +02:00
load ( ) ;
2011-05-08 11:04:32 +00:00
}
2015-01-25 10:50:12 +00:00
2011-07-11 09:33:18 +00:00
std : : stringstream ss ;
2015-02-17 20:23:21 +00:00
ss . imbue ( std : : locale : : classic ( ) ) ;
2018-01-29 12:11:50 +01:00
std : : string dt ;
if ( type_ ) {
dt = type ( ) - > name ( ) ;
if ( upper ) {
boost : : to_upper ( dt ) ;
}
2015-01-25 10:50:12 +00:00
2018-01-29 12:11:50 +01:00
if ( type ( ) - > as_entity ( ) | | id_ ! = 0 ) {
ss < < " # " < < id_ < < " = " ;
}
2015-01-16 16:26:40 +00:00
}
2015-01-25 10:50:12 +00:00
2017-06-05 17:26:58 +02:00
ss < < dt < < " ( " ;
2018-01-29 12:11:50 +01:00
for ( size_t i = 0 ; i < getArgumentCount ( ) ; + + i ) {
if ( i ! = 0 ) {
2017-06-05 17:26:58 +02:00
ss < < " , " ;
}
2018-01-29 12:11:50 +01:00
if ( attributes_ [ i ] = = 0 ) {
ss < < " $ " ;
} else {
ss < < attributes_ [ i ] - > toString ( upper ) ;
}
2017-06-05 17:26:58 +02:00
}
ss < < " ) " ;
2015-01-25 10:50:12 +00:00
2011-05-08 11:04:32 +00:00
return ss . str ( ) ;
}
2011-07-11 09:33:18 +00:00
2017-06-05 17:26:58 +02:00
IfcEntityInstanceData : : ~ IfcEntityInstanceData ( ) {
2018-03-21 17:29:37 +01:00
if ( attributes_ ! = NULL ) {
for ( size_t i = 0 ; i < getArgumentCount ( ) ; + + i ) {
delete attributes_ [ i ] ;
}
delete [ ] attributes_ ;
2017-06-05 17:26:58 +02:00
}
}
unsigned IfcEntityInstanceData : : set_id ( boost : : optional < unsigned > i ) {
if ( i ) {
return id_ = * i ;
} else {
return id_ = file - > FreshId ( ) ;
}
2011-09-03 13:58:59 +00:00
}
2011-07-11 09:33:18 +00:00
//
2015-01-10 22:13:52 +00:00
// Returns the entities of Entity type that have this entity in their ArgumentList
2011-07-11 09:33:18 +00:00
//
2018-07-07 17:15:54 +02:00
IfcEntityList : : ptr IfcEntityInstanceData : : getInverse ( const IfcParse : : declaration * type , int attribute_index ) const {
2019-07-03 12:10:27 +02:00
static std : : mutex m ;
std : : lock_guard < std : : mutex > lk ( m ) ;
2017-06-05 17:26:58 +02:00
return file - > getInverse ( id_ , type , attribute_index ) ;
2012-07-18 19:32:58 +00:00
}
2017-06-24 21:35:38 +02:00
void IfcEntityInstanceData : : load ( ) const {
2019-07-03 12:10:27 +02:00
static std : : recursive_mutex m ;
std : : lock_guard < std : : recursive_mutex > lk ( m ) ;
2018-01-29 12:11:50 +01:00
// type_ is 0 for header entities which have their size predetermined in code
2019-07-03 12:10:27 +02:00
Argument * * tmp_data = nullptr ;
2018-01-29 12:11:50 +01:00
if ( type_ ! = 0 ) {
2020-10-30 09:59:01 +01:00
tmp_data = new Argument * [ getArgumentCount ( ) ] { } ;
2018-01-29 12:11:50 +01:00
}
2019-07-03 12:10:27 +02:00
file - > seek_to ( * this ) ;
2020-10-30 09:59:01 +01:00
size_t n = file - > load ( id ( ) , tmp_data , getArgumentCount ( ) ) ;
if ( n ! = getArgumentCount ( ) ) {
Logger : : Error ( " Wrong number of attributes on instance with id # " + boost : : lexical_cast < std : : string > ( id_ ) ) ;
}
2019-07-03 12:10:27 +02:00
file - > try_read_semicolon ( ) ;
// @todo does this need to be atomic somehow?
attributes_ = tmp_data ;
2017-06-05 17:26:58 +02:00
}
IfcEntityInstanceData : : IfcEntityInstanceData ( const IfcEntityInstanceData & e ) {
2017-08-02 16:09:01 +02:00
file = 0 ;
2017-06-05 17:26:58 +02:00
type_ = e . type_ ;
id_ = 0 ;
2018-01-29 12:11:50 +01:00
const unsigned int count = e . getArgumentCount ( ) ;
2017-08-02 16:09:01 +02:00
// In order not to have the instance read from file
2018-01-29 12:11:50 +01:00
attributes_ = new Argument * [ count ] ;
2017-08-02 16:09:01 +02:00
2017-06-05 17:26:58 +02:00
for ( unsigned int i = 0 ; i < count ; + + i ) {
2018-01-29 12:11:50 +01:00
attributes_ [ i ] = 0 ;
2017-06-05 17:26:58 +02:00
this - > setArgument ( i , e . getArgument ( i ) ) ;
}
}
2018-08-29 12:54:25 +02:00
static IfcParse : : NullArgument static_null_attribute ;
2017-06-05 17:26:58 +02:00
Argument * IfcEntityInstanceData : : getArgument ( unsigned int i ) const {
2018-01-29 12:11:50 +01:00
if ( attributes_ = = 0 ) {
2017-06-24 21:35:38 +02:00
load ( ) ;
2017-06-05 17:26:58 +02:00
}
2018-01-29 12:11:50 +01:00
if ( i < getArgumentCount ( ) ) {
2018-08-29 12:54:25 +02:00
if ( attributes_ [ i ] = = nullptr ) {
return & static_null_attribute ;
} else {
return attributes_ [ i ] ;
}
2017-06-05 17:26:58 +02:00
} else {
throw IfcParse : : IfcException ( " Attribute index out of range " ) ;
}
}
2017-07-03 14:18:56 +02:00
class unregister_inverse_visitor {
private :
IfcFile & file_ ;
const IfcEntityInstanceData & data_ ;
public :
unregister_inverse_visitor ( IfcFile & file , const IfcEntityInstanceData & data )
: file_ ( file ) , data_ ( data )
{ }
void operator ( ) ( IfcUtil : : IfcBaseClass * inst ) {
file_ . unregister_inverse ( data_ . id ( ) , inst ) ;
}
} ;
class register_inverse_visitor {
private :
IfcFile & file_ ;
const IfcEntityInstanceData & data_ ;
public :
register_inverse_visitor ( IfcFile & file , const IfcEntityInstanceData & data )
: file_ ( file ) , data_ ( data )
{ }
void operator ( ) ( IfcUtil : : IfcBaseClass * inst ) {
file_ . register_inverse ( data_ . id ( ) , inst ) ;
}
} ;
class add_to_instance_list_visitor {
private :
IfcEntityList : : ptr & list_ ;
public :
add_to_instance_list_visitor ( IfcEntityList : : ptr & list )
: list_ ( list )
{ }
void operator ( ) ( IfcUtil : : IfcBaseClass * inst ) {
list_ - > push ( inst ) ;
}
} ;
class apply_individual_instance_visitor {
private :
Argument * attribute_ ;
IfcEntityInstanceData * data_ ;
template < typename T >
void apply_attribute_ ( T & t , Argument * attr ) const {
2018-08-13 11:43:28 +02:00
if ( ! attr ) {
return ;
}
2017-07-03 14:18:56 +02:00
if ( attr - > type ( ) = = IfcUtil : : Argument_ENTITY_INSTANCE ) {
IfcUtil : : IfcBaseClass * inst = * attr ;
t ( inst ) ;
} else if ( attr - > type ( ) = = IfcUtil : : Argument_AGGREGATE_OF_ENTITY_INSTANCE ) {
IfcEntityList : : ptr entity_list_attribute = * attr ;
for ( IfcEntityList : : it it = entity_list_attribute - > begin ( ) ; it ! = entity_list_attribute - > end ( ) ; + + it ) {
t ( * it ) ;
}
} else if ( attr - > type ( ) = = IfcUtil : : Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE ) {
IfcEntityListList : : ptr entity_list_attribute = * attr ;
for ( IfcEntityListList : : outer_it it = entity_list_attribute - > begin ( ) ; it ! = entity_list_attribute - > end ( ) ; + + it ) {
for ( IfcEntityListList : : inner_it jt = it - > begin ( ) ; jt ! = it - > end ( ) ; + + jt ) {
t ( * jt ) ;
}
}
}
} ;
public :
apply_individual_instance_visitor ( Argument * attribute )
: attribute_ ( attribute ) , data_ ( 0 )
{ }
apply_individual_instance_visitor ( IfcEntityInstanceData * data )
: attribute_ ( 0 ) , data_ ( data )
{ }
template < typename T >
void apply ( T & t ) const {
if ( attribute_ ) {
apply_attribute_ ( t , attribute_ ) ;
} else {
for ( unsigned i = 0 ; i < data_ - > getArgumentCount ( ) ; + + i ) {
Argument * attr = data_ - > getArgument ( i ) ;
apply_attribute_ ( t , attr ) ;
}
}
} ;
} ;
2017-06-05 17:26:58 +02:00
void IfcEntityInstanceData : : setArgument ( unsigned int i , Argument * a , IfcUtil : : ArgumentType attr_type ) {
2018-01-29 12:11:50 +01:00
if ( attributes_ = = 0 ) {
2017-06-24 21:35:38 +02:00
load ( ) ;
2017-06-15 14:12:03 +02:00
}
2017-06-05 17:26:58 +02:00
if ( attr_type = = IfcUtil : : Argument_UNKNOWN ) {
attr_type = a - > type ( ) ;
}
IfcWrite : : IfcWriteArgument * copy = new IfcWrite : : IfcWriteArgument ( ) ;
switch ( attr_type ) {
case IfcUtil : : Argument_NULL :
copy - > set ( boost : : blank ( ) ) ;
break ;
case IfcUtil : : Argument_DERIVED :
copy - > set ( IfcWrite : : IfcWriteArgument : : Derived ( ) ) ;
break ;
case IfcUtil : : Argument_INT :
copy - > set ( static_cast < int > ( * a ) ) ;
break ;
case IfcUtil : : Argument_BOOL :
copy - > set ( static_cast < bool > ( * a ) ) ;
break ;
case IfcUtil : : Argument_DOUBLE :
copy - > set ( static_cast < double > ( * a ) ) ;
break ;
case IfcUtil : : Argument_STRING :
copy - > set ( static_cast < std : : string > ( * a ) ) ;
break ;
case IfcUtil : : Argument_BINARY : {
boost : : dynamic_bitset < > attr_value = * a ;
copy - > set ( attr_value ) ;
break ; }
case IfcUtil : : Argument_AGGREGATE_OF_INT : {
std : : vector < int > attr_value = * a ;
copy - > set ( attr_value ) ;
break ; }
case IfcUtil : : Argument_AGGREGATE_OF_DOUBLE : {
std : : vector < double > attr_value = * a ;
copy - > set ( attr_value ) ;
break ; }
case IfcUtil : : Argument_AGGREGATE_OF_STRING : {
std : : vector < std : : string > attr_value = * a ;
copy - > set ( attr_value ) ;
break ; }
case IfcUtil : : Argument_AGGREGATE_OF_BINARY : {
std : : vector < boost : : dynamic_bitset < > > attr_value = * a ;
copy - > set ( attr_value ) ;
break ; }
case IfcUtil : : Argument_ENUMERATION : {
std : : string enum_literal = a - > toString ( ) ;
// Remove leading and trailing '.'
enum_literal = enum_literal . substr ( 1 , enum_literal . size ( ) - 2 ) ;
2017-12-11 17:20:22 +01:00
2017-12-13 13:16:49 +01:00
const IfcParse : : enumeration_type * enum_type = type ( ) - > as_entity ( ) - >
2017-12-11 17:20:22 +01:00
attribute_by_index ( i ) - > type_of_attribute ( ) - > as_named_type ( ) - > declared_type ( ) - > as_enumeration_type ( ) ;
std : : vector < std : : string > : : const_iterator it = std : : find (
enum_type - > enumeration_items ( ) . begin ( ) ,
enum_type - > enumeration_items ( ) . end ( ) ,
enum_literal ) ;
2017-12-11 15:46:57 +01:00
if ( it = = enum_type - > enumeration_items ( ) . end ( ) ) {
throw IfcParse : : IfcException ( enum_literal + " does not name a valid item for " + enum_type - > name ( ) ) ;
}
copy - > set ( IfcWrite : : IfcWriteArgument : : EnumerationReference ( it - enum_type - > enumeration_items ( ) . begin ( ) , it - > c_str ( ) ) ) ;
2017-06-05 17:26:58 +02:00
break ; }
case IfcUtil : : Argument_ENTITY_INSTANCE : {
copy - > set ( static_cast < IfcUtil : : IfcBaseClass * > ( * a ) ) ;
break ; }
case IfcUtil : : Argument_AGGREGATE_OF_ENTITY_INSTANCE : {
IfcEntityList : : ptr instances = * a ;
IfcEntityList : : ptr mapped_instances ( new IfcEntityList ) ;
2020-06-07 16:44:42 +02:00
// @todo mapped_instances are not actually mapped to the file using add().
2017-06-05 17:26:58 +02:00
for ( IfcEntityList : : it it = instances - > begin ( ) ; it ! = instances - > end ( ) ; + + it ) {
mapped_instances - > push ( * it ) ;
}
copy - > set ( mapped_instances ) ;
break ; }
case IfcUtil : : Argument_AGGREGATE_OF_AGGREGATE_OF_INT : {
std : : vector < std : : vector < int > > attr_value = * a ;
copy - > set ( attr_value ) ;
break ; }
case IfcUtil : : Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE : {
std : : vector < std : : vector < double > > attr_value = * a ;
copy - > set ( attr_value ) ;
break ; }
case IfcUtil : : Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE : {
IfcEntityListList : : ptr instances = * a ;
IfcEntityListList : : ptr mapped_instances ( new IfcEntityListList ) ;
for ( IfcEntityListList : : outer_it it = instances - > begin ( ) ; it ! = instances - > end ( ) ; + + it ) {
std : : vector < IfcUtil : : IfcBaseClass * > inner ;
for ( IfcEntityListList : : inner_it jt = it - > begin ( ) ; jt ! = it - > end ( ) ; + + jt ) {
inner . push_back ( * jt ) ;
}
mapped_instances - > push ( inner ) ;
}
copy - > set ( mapped_instances ) ;
break ; }
case IfcUtil : : Argument_EMPTY_AGGREGATE :
case IfcUtil : : Argument_AGGREGATE_OF_EMPTY_AGGREGATE : {
2017-12-13 13:16:49 +01:00
IfcUtil : : ArgumentType t2 = IfcUtil : : from_parameter_type ( type ( ) - > as_entity ( ) - > attribute_by_index ( i ) - > type_of_attribute ( ) ) ;
2017-06-05 17:26:58 +02:00
delete copy ;
2017-08-02 16:09:01 +02:00
copy = 0 ;
2017-06-05 17:26:58 +02:00
setArgument ( i , a , t2 ) ;
break ; }
default :
case IfcUtil : : Argument_UNKNOWN :
throw IfcParse : : IfcException ( std : : string ( " Unknown attribute encountered: ' " ) + a - > toString ( ) + " ' at index ' " + boost : : lexical_cast < std : : string > ( i ) + " ' " ) ;
break ;
}
2017-08-02 16:09:01 +02:00
if ( ! copy ) {
return ;
}
2018-01-29 12:11:50 +01:00
if ( attributes_ [ i ] ! = 0 ) {
2017-07-03 14:18:56 +02:00
Argument * current_attribute = attributes_ [ i ] ;
if ( this - > file ) {
unregister_inverse_visitor visitor ( * this - > file , * this ) ;
apply_individual_instance_visitor ( current_attribute ) . apply ( visitor ) ;
}
delete attributes_ [ i ] ;
}
if ( this - > file ) {
register_inverse_visitor visitor ( * this - > file , * this ) ;
apply_individual_instance_visitor ( copy ) . apply ( visitor ) ;
2018-12-21 12:06:35 +02:00
this - > file - > mark_entity_as_modified ( id_ ) ;
}
2017-07-03 14:18:56 +02:00
2018-01-29 12:11:50 +01:00
attributes_ [ i ] = copy ;
2017-06-05 17:26:58 +02:00
}
2011-07-11 09:33:18 +00:00
//
// Parses the IFC file in fn
// Creates the maps
//
2017-07-23 14:52:04 +02:00
# ifdef USE_MMAP
2017-12-12 10:33:24 +01:00
IfcFile : : IfcFile ( const std : : string & fn , bool mmap ) {
2020-12-15 09:44:19 +01:00
initialize_ ( new IfcSpfStream ( fn , mmap ) ) ;
2017-07-23 14:52:04 +02:00
}
# else
2017-12-12 10:33:24 +01:00
IfcFile : : IfcFile ( const std : : string & fn ) {
initialize_ ( new IfcSpfStream ( fn ) ) ;
2011-08-20 09:08:56 +00:00
}
2017-07-23 14:52:04 +02:00
# endif
2017-08-22 10:16:07 +02:00
2017-12-12 10:33:24 +01:00
IfcFile : : IfcFile ( std : : istream & f , int len ) {
initialize_ ( new IfcSpfStream ( f , len ) ) ;
2011-08-20 09:08:56 +00:00
}
2015-02-17 19:48:41 +00:00
2017-12-12 10:33:24 +01:00
IfcFile : : IfcFile ( void * data , int len ) {
initialize_ ( new IfcSpfStream ( data , len ) ) ;
}
IfcFile : : IfcFile ( IfcParse : : IfcSpfStream * s ) {
initialize_ ( s ) ;
}
IfcFile : : IfcFile ( const IfcParse : : schema_definition * schema )
2018-08-29 12:54:25 +02:00
: parsing_complete_ ( true )
, good_ ( true )
2017-12-29 12:09:07 +01:00
, schema_ ( schema )
, ifcroot_type_ ( schema_ - > declaration_by_name ( " IfcRoot " ) )
2017-12-12 10:33:24 +01:00
, MaxId ( 0 )
, tokens ( 0 )
, stream ( 0 )
{
setDefaultHeaderValues ( ) ;
2011-10-27 16:13:29 +00:00
}
2015-02-17 19:48:41 +00:00
2017-12-12 10:33:24 +01:00
void IfcFile : : initialize_ ( IfcParse : : IfcSpfStream * s ) {
2015-02-03 13:53:36 +00:00
// Initialize a "C" locale for locale-independent
// number parsing. See comment above on line 41.
init_locale ( ) ;
2017-12-12 10:33:24 +01:00
good_ = false ;
parsing_complete_ = false ;
MaxId = 0 ;
tokens = 0 ;
stream = 0 ;
2017-12-31 12:20:13 +01:00
schema_ = 0 ;
2017-12-12 10:33:24 +01:00
setDefaultHeaderValues ( ) ;
2015-01-05 17:46:23 +00:00
stream = s ;
if ( ! stream - > valid ) {
2017-12-12 10:33:24 +01:00
return ;
2015-01-05 17:46:23 +00:00
}
tokens = new IfcSpfLexer ( stream , this ) ;
2017-06-05 17:26:58 +02:00
_header . file ( this ) ;
2015-01-05 17:46:23 +00:00
_header . tryRead ( ) ;
std : : vector < std : : string > schemas ;
try {
schemas = _header . file_schema ( ) . schema_identifiers ( ) ;
2017-08-01 16:45:11 +02:00
} catch ( . . . ) {
// Purposely empty catch block
}
2017-12-12 10:33:24 +01:00
if ( schemas . size ( ) = = 1 ) {
try {
schema_ = IfcParse : : schema_by_name ( schemas . front ( ) ) ;
} catch ( const IfcParse : : IfcException & e ) {
Logger : : Error ( e ) ;
}
}
if ( schema_ = = 0 ) {
2018-10-30 14:32:28 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " No support for file schema encountered ( "
+ boost : : algorithm : : join ( schemas , " , " ) + " ) " ) ;
return ;
2015-01-05 17:46:23 +00:00
}
2018-10-30 14:32:28 +01:00
good_ = true ;
2017-12-13 13:58:58 +01:00
ifcroot_type_ = schema_ - > declaration_by_name ( " IfcRoot " ) ;
2017-07-03 20:39:40 +02:00
boost : : circular_buffer < Token > token_stream ( 3 , Token ( ) ) ;
2015-01-05 17:46:23 +00:00
2017-06-05 17:26:58 +02:00
IfcEntityInstanceData * data ;
IfcUtil : : IfcBaseClass * instance = 0 ;
unsigned current_id = 0 ;
int progress = 0 ;
2012-08-11 13:24:08 +00:00
Logger : : Status ( " Scanning file... " ) ;
2017-06-05 17:26:58 +02:00
while ( ! stream - > eof ) {
if ( token_stream [ 0 ] . type = = IfcParse : : Token_IDENTIFIER & &
token_stream [ 1 ] . type = = IfcParse : : Token_OPERATOR & &
token_stream [ 1 ] . value_char = = ' = ' & &
token_stream [ 2 ] . type = = IfcParse : : Token_KEYWORD )
{
current_id = ( unsigned ) TokenFunc : : asIdentifier ( token_stream [ 0 ] ) ;
2017-12-13 13:16:49 +01:00
const IfcParse : : declaration * entity_type ;
2011-10-13 11:25:59 +00:00
try {
2017-12-13 13:16:49 +01:00
entity_type = schema_ - > declaration_by_name ( TokenFunc : : asStringRef ( token_stream [ 2 ] ) ) ;
2015-06-17 11:04:28 +00:00
} catch ( const IfcException & ex ) {
2017-06-05 17:26:58 +02:00
Logger : : Message ( Logger : : LOG_ERROR , ex . what ( ) ) ;
2017-06-14 12:42:38 +02:00
goto advance ;
2017-12-12 10:33:24 +01:00
}
2017-06-05 17:26:58 +02:00
data = new IfcEntityInstanceData ( entity_type , this , current_id , token_stream [ 2 ] . startPos ) ;
2017-12-13 13:16:49 +01:00
instance = schema ( ) - > instantiate ( data ) ;
2017-06-05 17:26:58 +02:00
2017-05-23 20:06:35 +03:00
/// @todo Printing to stdout in a library class feels weird. Maybe move the progress prints to the client code?
2012-08-11 13:24:08 +00:00
// Update the status after every 1000 instances parsed
2017-06-05 17:26:58 +02:00
if ( ! ( ( + + progress ) % 1000 ) ) {
std : : stringstream ss ; ss < < " \r # " < < current_id ;
2012-10-19 08:20:43 +00:00
Logger : : Status ( ss . str ( ) , false ) ;
2012-08-11 13:24:08 +00:00
}
2017-06-05 17:26:58 +02:00
2017-12-13 13:58:58 +01:00
if ( instance - > declaration ( ) . is ( * ifcroot_type_ ) ) {
2012-03-13 11:56:52 +00:00
try {
2017-12-13 13:58:58 +01:00
const std : : string guid = * instance - > data ( ) . getArgument ( 0 ) ;
2012-03-13 11:56:52 +00:00
if ( byguid . find ( guid ) ! = byguid . end ( ) ) {
std : : stringstream ss ;
2015-10-05 13:08:24 +02:00
ss < < " Instance encountered with non-unique GlobalId " < < guid ;
2012-08-11 13:24:08 +00:00
Logger : : Message ( Logger : : LOG_WARNING , ss . str ( ) ) ;
2012-03-13 11:56:52 +00:00
}
2017-12-13 13:58:58 +01:00
byguid [ guid ] = instance ;
2015-06-17 11:04:28 +00:00
} catch ( const IfcException & ex ) {
2012-08-11 13:24:08 +00:00
Logger : : Message ( Logger : : LOG_ERROR , ex . what ( ) ) ;
2012-03-13 11:56:52 +00:00
}
}
2014-11-04 12:02:28 +00:00
2017-12-13 13:16:49 +01:00
const IfcParse : : declaration * ty = & instance - > declaration ( ) ;
2017-08-16 21:46:39 +02:00
{
2017-12-13 13:16:49 +01:00
IfcEntityList : : ptr insts = instances_by_type_excl_subtypes ( ty ) ;
if ( ! insts ) {
insts = IfcEntityList : : ptr ( new IfcEntityList ( ) ) ;
bytype_excl [ ty ] = insts ;
2017-08-16 21:46:39 +02:00
}
2017-12-13 13:16:49 +01:00
insts - > push ( instance ) ;
2017-08-16 21:46:39 +02:00
}
2016-03-18 11:14:14 +01:00
for ( ; ; ) {
2017-12-13 13:16:49 +01:00
IfcEntityList : : ptr insts = instances_by_type ( ty ) ;
if ( ! insts ) {
insts = IfcEntityList : : ptr ( new IfcEntityList ( ) ) ;
bytype [ ty ] = insts ;
2011-08-24 12:21:07 +00:00
}
2017-12-13 13:16:49 +01:00
insts - > push ( instance ) ;
const IfcParse : : declaration * pt = ty - > as_entity ( ) - > supertype ( ) ;
2016-03-18 11:14:14 +01:00
if ( pt ) {
2017-12-13 13:16:49 +01:00
ty = pt ;
2016-03-18 11:14:14 +01:00
} else {
break ;
}
}
2017-08-16 21:46:39 +02:00
2017-06-05 17:26:58 +02:00
if ( byid . find ( current_id ) ! = byid . end ( ) ) {
2012-02-04 15:10:17 +00:00
std : : stringstream ss ;
2017-06-05 17:26:58 +02:00
ss < < " Overwriting instance with name # " < < current_id ;
2012-08-11 13:24:08 +00:00
Logger : : Message ( Logger : : LOG_WARNING , ss . str ( ) ) ;
2012-02-04 15:10:17 +00:00
}
2017-06-05 17:26:58 +02:00
byid [ current_id ] = instance ;
2014-11-04 12:02:28 +00:00
2017-06-05 17:26:58 +02:00
MaxId = ( std : : max ) ( MaxId , current_id ) ;
} else if ( token_stream [ 0 ] . type = = IfcParse : : Token_IDENTIFIER & & instance ) {
register_inverse ( current_id , token_stream [ 0 ] ) ;
2012-03-13 11:56:52 +00:00
}
2014-11-04 12:02:28 +00:00
2017-06-14 12:42:38 +02:00
advance :
2017-06-05 17:26:58 +02:00
Token next_token ;
try {
next_token = tokens - > Next ( ) ;
} catch ( const IfcException & e ) {
Logger : : Message ( Logger : : LOG_ERROR , std : : string ( e . what ( ) ) + " . Parsing terminated " ) ;
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_ERROR , " Parsing terminated " ) ;
2011-05-08 11:04:32 +00:00
}
2017-06-05 17:26:58 +02:00
if ( next_token . type = = Token_NONE ) break ;
token_stream . push_back ( next_token ) ;
2011-05-08 11:04:32 +00:00
}
2017-06-05 17:26:58 +02:00
2012-08-11 13:24:08 +00:00
Logger : : Status ( " \r Done scanning file " ) ;
2017-06-05 17:26:58 +02:00
parsing_complete_ = true ;
2017-12-12 10:33:24 +01:00
return ;
2011-07-11 09:33:18 +00:00
}
2015-02-17 19:48:41 +00:00
2017-08-01 19:07:46 +02:00
class traversal_visitor {
private :
std : : set < IfcUtil : : IfcBaseClass * > & visited_ ;
IfcEntityList : : ptr & list_ ;
int level_ ;
int max_level_ ;
public :
traversal_visitor ( std : : set < IfcUtil : : IfcBaseClass * > & visited , IfcEntityList : : ptr & list , int level , int max_level )
: visited_ ( visited )
, list_ ( list )
, level_ ( level )
, max_level_ ( max_level )
{ }
void operator ( ) ( IfcUtil : : IfcBaseClass * inst ) ;
} ;
2017-06-20 18:54:30 +02:00
void traverse_ ( IfcUtil : : IfcBaseClass * instance , std : : set < IfcUtil : : IfcBaseClass * > & visited , IfcEntityList : : ptr list , int level , int max_level ) {
2015-02-17 19:48:41 +00:00
if ( visited . find ( instance ) ! = visited . end ( ) ) {
return ;
}
visited . insert ( instance ) ;
list - > push ( instance ) ;
if ( level > = max_level & & max_level > 0 ) return ;
2017-08-01 19:07:46 +02:00
traversal_visitor visit ( visited , list , level + 1 , max_level ) ;
2017-12-11 14:47:30 +01:00
apply_individual_instance_visitor ( & instance - > data ( ) ) . apply ( visit ) ;
2015-02-17 19:48:41 +00:00
}
2017-08-01 19:07:46 +02:00
void traversal_visitor : : operator ( ) ( IfcUtil : : IfcBaseClass * inst ) {
traverse_ ( inst , visited_ , list_ , level_ , max_level_ ) ;
}
2017-06-20 18:54:30 +02:00
IfcEntityList : : ptr IfcParse : : traverse ( IfcUtil : : IfcBaseClass * instance , int max_level ) {
2015-02-17 19:48:41 +00:00
std : : set < IfcUtil : : IfcBaseClass * > visited ;
IfcEntityList : : ptr return_value ( new IfcEntityList ) ;
2017-06-20 18:54:30 +02:00
traverse_ ( instance , visited , return_value , 0 , max_level ) ;
2015-02-17 19:48:41 +00:00
return return_value ;
}
2017-06-20 18:54:30 +02:00
/// @note: for backwards compatibility
IfcEntityList : : ptr IfcFile : : traverse ( IfcUtil : : IfcBaseClass * instance , int max_level ) {
return IfcParse : : traverse ( instance , max_level ) ;
}
2018-12-21 12:06:35 +02:00
void IfcFile : : mark_entity_as_modified ( int /*id*/ )
{
by_ref_cached_ . clear ( ) ;
}
2015-02-17 20:07:09 +00:00
void IfcFile : : addEntities ( IfcEntityList : : ptr es ) {
2012-08-11 13:24:08 +00:00
for ( IfcEntityList : : it i = es - > begin ( ) ; i ! = es - > end ( ) ; + + i ) {
2015-02-17 19:55:27 +00:00
addEntity ( * i ) ;
2012-08-11 13:24:08 +00:00
}
}
2015-02-17 19:48:41 +00:00
2015-02-17 19:55:27 +00:00
IfcUtil : : IfcBaseClass * IfcFile : : addEntity ( IfcUtil : : IfcBaseClass * entity ) {
2018-11-04 15:16:08 +01:00
if ( entity - > declaration ( ) . schema ( ) ! = schema ( ) ) {
throw IfcParse : : IfcException ( " Unabled to add instance from " + entity - > declaration ( ) . schema ( ) - > name ( ) + " schema to file with " + schema ( ) - > name ( ) + " schema " ) ;
}
2015-02-17 19:48:41 +00:00
// If this instance has been inserted before, return
// a reference to the copy that was created from it.
2015-11-21 23:05:28 +02:00
entity_entity_map_t : : iterator mit = entity_file_map . find ( entity ) ;
if ( mit ! = entity_file_map . end ( ) ) {
return mit - > second ;
2015-02-17 19:48:41 +00:00
}
2017-08-02 16:09:01 +02:00
IfcUtil : : IfcBaseClass * new_entity = entity ;
2015-02-17 19:48:41 +00:00
// Obtain all forward references by a depth-first
// traversal and add them to the file.
2018-08-29 12:54:25 +02:00
if ( parsing_complete_ ) {
try {
IfcEntityList : : ptr entity_attributes = traverse ( entity , 1 ) ;
for ( IfcEntityList : : it it = entity_attributes - > begin ( ) ; it ! = entity_attributes - > end ( ) ; + + it ) {
if ( * it ! = entity ) {
entity_entity_map_t : : iterator mit2 = entity_file_map . find ( * it ) ;
if ( mit2 = = entity_file_map . end ( ) ) {
entity_file_map . insert ( entity_entity_map_t : : value_type ( * it , addEntity ( * it ) ) ) ;
}
2017-08-02 16:09:01 +02:00
}
2015-02-17 22:02:06 +00:00
}
2018-08-29 12:54:25 +02:00
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_ERROR , " Failed to visit forward references of " , entity ) ;
2015-02-17 19:48:41 +00:00
}
2015-03-12 17:54:52 +00:00
}
2015-02-17 19:48:41 +00:00
// See whether the instance is already part of a file
2017-12-11 14:47:30 +01:00
if ( entity - > data ( ) . file ! = 0 ) {
if ( entity - > data ( ) . file = = this ) {
2015-02-17 19:48:41 +00:00
// If it is part of this file
// nothing needs to be done.
return entity ;
}
// An instance is being added from another file. A copy of the
// container and entity is created. The attribute references
// need to be updated to point to instances in this file.
2017-12-11 14:47:30 +01:00
IfcFile * other_file = entity - > data ( ) . file ;
IfcEntityInstanceData * we = new IfcEntityInstanceData ( entity - > data ( ) ) ;
2017-12-13 13:16:49 +01:00
new_entity = schema ( ) - > instantiate ( we ) ;
2015-02-17 19:48:41 +00:00
// In case an entity is added that contains geometry, the unit
// information needs to be accounted for for IfcLengthMeasures.
2016-07-15 06:49:32 +03:00
double conversion_factor = std : : numeric_limits < double > : : quiet_NaN ( ) ;
2015-02-17 19:48:41 +00:00
for ( unsigned i = 0 ; i < we - > getArgumentCount ( ) ; + + i ) {
Argument * attr = we - > getArgument ( i ) ;
IfcUtil : : ArgumentType attr_type = attr - > type ( ) ;
2017-12-11 14:47:30 +01:00
2017-12-31 12:20:13 +01:00
IfcParse : : declaration * decl = 0 ;
if ( entity - > declaration ( ) . as_entity ( ) ) {
decl = 0 ;
const parameter_type * pt = entity - > declaration ( ) . as_entity ( ) - > attribute_by_index ( i ) - > type_of_attribute ( ) ;
while ( pt - > as_aggregation_type ( ) ) {
pt = pt - > as_aggregation_type ( ) - > type_of_element ( ) ;
}
if ( pt - > as_named_type ( ) ) {
decl = pt - > as_named_type ( ) - > declared_type ( ) ;
}
}
2017-12-11 14:47:30 +01:00
2015-04-07 15:06:56 +00:00
if ( attr_type = = IfcUtil : : Argument_ENTITY_INSTANCE ) {
2015-03-12 17:54:52 +00:00
entity_entity_map_t : : const_iterator eit = entity_file_map . find ( * attr ) ;
if ( eit = = entity_file_map . end ( ) ) throw IfcParse : : IfcException ( " Unable to map instance to file " ) ;
2017-06-05 17:26:58 +02:00
IfcWrite : : IfcWriteArgument * copy = new IfcWrite : : IfcWriteArgument ( ) ;
copy - > set ( eit - > second ) ;
we - > setArgument ( i , copy ) ;
2015-04-07 15:06:56 +00:00
} else if ( attr_type = = IfcUtil : : Argument_AGGREGATE_OF_ENTITY_INSTANCE ) {
2015-02-17 19:48:41 +00:00
IfcEntityList : : ptr instances = * attr ;
IfcEntityList : : ptr new_instances ( new IfcEntityList ) ;
for ( IfcEntityList : : it it = instances - > begin ( ) ; it ! = instances - > end ( ) ; + + it ) {
2015-03-12 17:54:52 +00:00
entity_entity_map_t : : const_iterator eit = entity_file_map . find ( * it ) ;
if ( eit = = entity_file_map . end ( ) ) throw IfcParse : : IfcException ( " Unable to map instance to file " ) ;
new_instances - > push ( eit - > second ) ;
2015-02-17 19:48:41 +00:00
}
2017-06-05 17:26:58 +02:00
IfcWrite : : IfcWriteArgument * copy = new IfcWrite : : IfcWriteArgument ( ) ;
copy - > set ( new_instances ) ;
we - > setArgument ( i , copy ) ;
2015-04-07 15:06:56 +00:00
} else if ( attr_type = = IfcUtil : : Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE ) {
2015-02-17 19:48:41 +00:00
IfcEntityListList : : ptr instances = * attr ;
IfcEntityListList : : ptr new_instances ( new IfcEntityListList ) ;
for ( IfcEntityListList : : outer_it it = instances - > begin ( ) ; it ! = instances - > end ( ) ; + + it ) {
std : : vector < IfcUtil : : IfcBaseClass * > list ;
for ( IfcEntityListList : : inner_it jt = it - > begin ( ) ; jt ! = it - > end ( ) ; + + jt ) {
2015-03-12 17:54:52 +00:00
entity_entity_map_t : : const_iterator eit = entity_file_map . find ( * jt ) ;
if ( eit = = entity_file_map . end ( ) ) throw IfcParse : : IfcException ( " Unable to map instance to file " ) ;
list . push_back ( eit - > second ) ;
2015-02-17 19:48:41 +00:00
}
new_instances - > push ( list ) ;
}
2017-06-05 17:26:58 +02:00
IfcWrite : : IfcWriteArgument * copy = new IfcWrite : : IfcWriteArgument ( ) ;
copy - > set ( new_instances ) ;
we - > setArgument ( i , copy ) ;
2017-12-13 13:16:49 +01:00
} else if ( decl & & decl - > is ( * schema ( ) - > declaration_by_name ( " IfcLengthMeasure " ) ) ) {
2016-07-15 06:49:32 +03:00
if ( boost : : math : : isnan ( conversion_factor ) ) {
2017-12-13 18:05:10 +01:00
const std : : pair < IfcUtil : : IfcBaseClass * , double > this_file_unit = getUnit ( " LENGTHUNIT " ) ;
const std : : pair < IfcUtil : : IfcBaseClass * , double > other_file_unit = other_file - > getUnit ( " LENGTHUNIT " ) ;
2017-08-04 16:31:34 +02:00
if ( this_file_unit . first & & other_file_unit . first ) {
conversion_factor = other_file_unit . second / this_file_unit . second ;
} else {
conversion_factor = 1. ;
}
2015-02-17 19:48:41 +00:00
}
if ( attr_type = = IfcUtil : : Argument_DOUBLE ) {
double v = * attr ;
2016-07-15 06:49:32 +03:00
v * = conversion_factor ;
2017-06-05 17:26:58 +02:00
IfcWrite : : IfcWriteArgument * copy = new IfcWrite : : IfcWriteArgument ( ) ;
copy - > set ( v ) ;
we - > setArgument ( i , copy ) ;
2015-04-07 15:06:56 +00:00
} else if ( attr_type = = IfcUtil : : Argument_AGGREGATE_OF_DOUBLE ) {
2015-02-17 19:48:41 +00:00
std : : vector < double > v = * attr ;
for ( std : : vector < double > : : iterator it = v . begin ( ) ; it ! = v . end ( ) ; + + it ) {
2016-07-15 06:49:32 +03:00
( * it ) * = conversion_factor ;
2015-02-17 19:48:41 +00:00
}
2017-06-05 17:26:58 +02:00
IfcWrite : : IfcWriteArgument * copy = new IfcWrite : : IfcWriteArgument ( ) ;
copy - > set ( v ) ;
we - > setArgument ( i , copy ) ;
2015-02-17 19:48:41 +00:00
}
}
}
// A new entity instance name is generated and
// the instance is pointed to this file.
we - > file = this ;
2017-12-13 13:16:49 +01:00
if ( we - > type ( ) - > as_entity ( ) ) {
2017-08-02 16:09:01 +02:00
we - > set_id ( FreshId ( ) ) ;
}
2018-08-29 12:54:25 +02:00
// @todo entity_file_map: use weak_ptr
2017-08-02 16:09:01 +02:00
entity_file_map . insert ( entity_entity_map_t : : value_type ( entity , new_entity ) ) ;
2015-02-17 19:48:41 +00:00
}
// For subtypes of IfcRoot, the GUID mapping needs to be updated.
2017-12-13 13:58:58 +01:00
if ( new_entity - > declaration ( ) . is ( * ifcroot_type_ ) ) {
2012-07-18 19:32:58 +00:00
try {
2017-12-13 13:58:58 +01:00
const std : : string guid = * new_entity - > data ( ) . getArgument ( 0 ) ;
2012-07-18 19:32:58 +00:00
if ( byguid . find ( guid ) ! = byguid . end ( ) ) {
std : : stringstream ss ;
ss < < " Overwriting entity with guid " < < guid ;
2012-08-11 13:24:08 +00:00
Logger : : Message ( Logger : : LOG_WARNING , ss . str ( ) ) ;
2012-07-18 19:32:58 +00:00
}
2017-12-13 13:58:58 +01:00
byguid [ guid ] = new_entity ;
2015-06-17 11:04:28 +00:00
} catch ( const IfcException & ex ) {
2012-08-11 13:24:08 +00:00
Logger : : Message ( Logger : : LOG_ERROR , ex . what ( ) ) ;
2012-07-18 19:32:58 +00:00
}
}
2014-11-04 12:02:28 +00:00
2015-02-17 19:48:41 +00:00
// The mapping by entity type is updated.
2017-12-13 13:16:49 +01:00
const IfcParse : : declaration * ty = & new_entity - > declaration ( ) ;
2017-08-16 21:46:39 +02:00
2017-12-31 12:20:13 +01:00
if ( ty - > as_entity ( ) ) {
2017-12-13 13:16:49 +01:00
IfcEntityList : : ptr insts = instances_by_type_excl_subtypes ( ty ) ;
if ( ! insts ) {
insts = IfcEntityList : : ptr ( new IfcEntityList ( ) ) ;
bytype_excl [ ty ] = insts ;
2017-08-16 21:46:39 +02:00
}
2017-12-13 13:16:49 +01:00
insts - > push ( new_entity ) ;
2017-08-16 21:46:39 +02:00
}
2017-12-31 12:20:13 +01:00
for ( ; ty - > as_entity ( ) ; ) {
2017-12-13 13:16:49 +01:00
IfcEntityList : : ptr insts = instances_by_type ( ty ) ;
if ( ! insts ) {
insts = IfcEntityList : : ptr ( new IfcEntityList ( ) ) ;
bytype [ ty ] = insts ;
2012-07-18 19:32:58 +00:00
}
2017-12-13 13:16:49 +01:00
insts - > push ( new_entity ) ;
const IfcParse : : declaration * pt = ty - > as_entity ( ) - > supertype ( ) ;
2016-03-18 11:14:14 +01:00
if ( pt ) {
2017-12-13 13:16:49 +01:00
ty = pt ;
} else {
2016-03-18 11:14:14 +01:00
break ;
}
}
2017-08-16 21:46:39 +02:00
2017-12-31 12:20:13 +01:00
if ( ty - > as_entity ( ) ) {
2017-08-30 14:09:07 +02:00
int new_id = - 1 ;
2017-12-11 14:47:30 +01:00
if ( ! new_entity - > data ( ) . file ) {
2017-08-30 14:09:07 +02:00
// For newly created entities ensure a valid ENTITY_INSTANCE_NAME is set
2017-12-11 14:47:30 +01:00
new_entity - > data ( ) . file = this ;
new_id = new_entity - > data ( ) . set_id ( ) ;
2017-08-30 14:09:07 +02:00
} else {
2017-12-11 14:47:30 +01:00
new_id = new_entity - > data ( ) . id ( ) ;
2017-08-30 14:09:07 +02:00
}
2015-02-17 19:48:41 +00:00
2017-08-30 14:09:07 +02:00
if ( byid . find ( new_id ) ! = byid . end ( ) ) {
// This should not happen
std : : stringstream ss ;
ss < < " Overwriting entity with id " < < new_id ;
Logger : : Message ( Logger : : LOG_WARNING , ss . str ( ) ) ;
}
2012-07-18 19:32:58 +00:00
2017-08-30 14:09:07 +02:00
// The mapping by entity instance name is updated.
byid [ new_id ] = new_entity ;
}
2014-11-02 18:36:51 +00:00
2018-08-29 12:54:25 +02:00
if ( parsing_complete_ & & ty - > as_entity ( ) ) {
build_inverses_ ( new_entity ) ;
2015-02-17 19:48:41 +00:00
}
2014-11-02 18:36:51 +00:00
2017-08-02 16:09:01 +02:00
return new_entity ;
2015-02-17 19:48:41 +00:00
}
void IfcFile : : removeEntity ( IfcUtil : : IfcBaseClass * entity ) {
2017-12-11 14:47:30 +01:00
const unsigned id = entity - > data ( ) . id ( ) ;
2017-12-13 13:16:49 +01:00
IfcUtil : : IfcBaseClass * file_entity = instance_by_id ( id ) ;
2020-09-30 09:38:01 +02:00
// Attention when running removeEntity inside a loop over a list of entities to be removed.
// This invalidates the iterator. A workaround is to reverse the loop:
// boost::shared_ptr<IfcEntityList> entities = ...;
// for (auto it = entities->end() - 1; it >= entities->begin(); --it) {
// IfcUtil::IfcBaseClass *const inst = *it;
// model->removeEntity(inst);
// }
2015-02-17 19:48:41 +00:00
// TODO: Create a set of weak relations. Inverse relations that do not dictate an
// instance to be retained. For example: when deleting an IfcRepresentation, the
// individual IfcRepresentationItems can not be deleted if an IfcStyledItem is
// related. Hence, the IfcRepresentationItem::StyledByItem relation could be
// characterized as weak.
2017-12-13 13:58:58 +01:00
// std::set<IfcSchema::Type::Enum> weak_roots;
2015-02-17 19:48:41 +00:00
if ( entity ! = file_entity ) {
throw IfcParse : : IfcException ( " Instance not part of this file " ) ;
}
2017-12-13 13:16:49 +01:00
IfcEntityList : : ptr references = instances_by_reference ( id ) ;
2015-02-17 19:48:41 +00:00
// Alter entity instances with INVERSE relations to the entity being
// deleted. This is necessary to maintain a valid IFC file, because
// dangling references to it's entities name should be removed. At this
// moment, inversely related instances affected by the removal of the
// entity being deleted are not deleted themselves.
if ( references ) {
2015-11-21 23:05:28 +02:00
for ( IfcEntityList : : it iit = references - > begin ( ) ; iit ! = references - > end ( ) ; + + iit ) {
IfcUtil : : IfcBaseEntity * related_instance = ( IfcUtil : : IfcBaseEntity * ) * iit ;
2017-12-11 14:47:30 +01:00
for ( unsigned i = 0 ; i < related_instance - > data ( ) . getArgumentCount ( ) ; + + i ) {
Argument * attr = related_instance - > data ( ) . getArgument ( i ) ;
2015-02-17 19:48:41 +00:00
if ( attr - > isNull ( ) ) continue ;
2017-12-11 14:47:30 +01:00
IfcUtil : : ArgumentType attr_type = attr - > type ( ) ;
2015-02-17 19:48:41 +00:00
switch ( attr_type ) {
2015-04-07 15:06:56 +00:00
case IfcUtil : : Argument_ENTITY_INSTANCE : {
2015-02-17 19:48:41 +00:00
IfcUtil : : IfcBaseClass * instance_attribute = * attr ;
if ( instance_attribute = = entity ) {
2017-06-05 17:26:58 +02:00
IfcWrite : : IfcWriteArgument * copy = new IfcWrite : : IfcWriteArgument ( ) ;
copy - > set ( boost : : blank ( ) ) ;
2017-12-11 14:47:30 +01:00
related_instance - > data ( ) . setArgument ( i , copy ) ;
2015-02-17 19:48:41 +00:00
} }
break ;
2015-04-07 15:06:56 +00:00
case IfcUtil : : Argument_AGGREGATE_OF_ENTITY_INSTANCE : {
2015-02-17 19:48:41 +00:00
IfcEntityList : : ptr instance_list = * attr ;
if ( instance_list - > contains ( entity ) ) {
instance_list - > remove ( entity ) ;
2017-06-05 17:26:58 +02:00
IfcWrite : : IfcWriteArgument * copy = new IfcWrite : : IfcWriteArgument ( ) ;
copy - > set ( instance_list ) ;
2017-12-11 14:47:30 +01:00
related_instance - > data ( ) . setArgument ( i , copy ) ;
2015-02-17 19:48:41 +00:00
} }
break ;
2015-04-07 15:06:56 +00:00
case IfcUtil : : Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE : {
2015-02-17 19:48:41 +00:00
IfcEntityListList : : ptr instance_list_list = * attr ;
if ( instance_list_list - > contains ( entity ) ) {
IfcEntityListList : : ptr new_list ( new IfcEntityListList ) ;
for ( IfcEntityListList : : outer_it it = instance_list_list - > begin ( ) ; it ! = instance_list_list - > end ( ) ; + + it ) {
std : : vector < IfcUtil : : IfcBaseClass * > instances = * it ;
2015-02-17 21:24:18 +00:00
std : : vector < IfcUtil : : IfcBaseClass * > : : iterator jt ;
2015-02-17 19:48:41 +00:00
while ( ( jt = std : : find ( instances . begin ( ) , instances . end ( ) , entity ) ) ! = instances . end ( ) ) {
instances . erase ( jt ) ;
}
new_list - > push ( instances ) ;
2014-11-27 09:22:58 +00:00
}
2017-06-05 17:26:58 +02:00
IfcWrite : : IfcWriteArgument * copy = new IfcWrite : : IfcWriteArgument ( ) ;
copy - > set ( new_list ) ;
2017-12-11 14:47:30 +01:00
related_instance - > data ( ) . setArgument ( i , copy ) ;
2015-02-17 19:48:41 +00:00
} }
break ;
default : break ;
2014-05-05 16:17:28 +00:00
}
2015-02-17 19:48:41 +00:00
}
2014-05-05 16:17:28 +00:00
}
2015-02-17 19:48:41 +00:00
byref . erase ( byref . find ( id ) ) ;
2014-05-05 16:17:28 +00:00
}
2015-02-17 19:48:41 +00:00
IfcEntityList : : ptr entity_attributes = traverse ( entity , 1 ) ;
for ( IfcEntityList : : it it = entity_attributes - > begin ( ) ; it ! = entity_attributes - > end ( ) ; + + it ) {
IfcUtil : : IfcBaseClass * entity_attribute = * it ;
if ( entity_attribute = = entity ) continue ;
2017-12-11 14:47:30 +01:00
const unsigned int name = entity_attribute - > data ( ) . id ( ) ;
2017-10-23 13:32:57 +02:00
// Do not update inverses for simple types (which have id()==0 in IfcOpenShell).
if ( name ! = 0 ) {
2017-10-23 13:47:37 +02:00
entities_by_ref_t : : iterator byref_it = byref . find ( name ) ;
if ( byref_it ! = byref . end ( ) ) {
std : : vector < unsigned > & ids = byref_it - > second ;
2018-07-12 12:33:35 +02:00
ids . erase ( std : : remove ( ids . begin ( ) , ids . end ( ) , id ) , ids . end ( ) ) ;
2017-04-25 16:37:50 +02:00
}
2015-02-17 19:48:41 +00:00
}
}
2017-12-13 13:58:58 +01:00
if ( entity - > declaration ( ) . is ( * ifcroot_type_ ) ) {
const std : : string global_id = * entity - > data ( ) . getArgument ( 0 ) ;
2015-02-17 19:48:41 +00:00
byguid . erase ( byguid . find ( global_id ) ) ;
}
byid . erase ( byid . find ( id ) ) ;
2017-12-13 13:16:49 +01:00
const IfcParse : : declaration * ty = & entity - > declaration ( ) ;
2017-08-16 21:46:39 +02:00
{
2017-12-13 13:16:49 +01:00
IfcEntityList : : ptr instances_of_same_type = instances_by_type_excl_subtypes ( ty ) ;
2017-08-16 21:46:39 +02:00
instances_of_same_type - > remove ( entity ) ;
if ( instances_of_same_type - > size ( ) = = 0 ) {
bytype_excl . erase ( ty ) ;
}
}
for ( ; ; ) {
2017-12-13 13:16:49 +01:00
IfcEntityList : : ptr instances_of_same_type = instances_by_type ( ty ) ;
2017-08-16 21:46:39 +02:00
if ( instances_of_same_type ) {
instances_of_same_type - > remove ( entity ) ;
}
if ( instances_of_same_type - > size ( ) = = 0 ) {
bytype . erase ( ty ) ;
}
2017-12-13 13:16:49 +01:00
const IfcParse : : declaration * pt = ty - > as_entity ( ) - > supertype ( ) ;
2017-08-16 21:46:39 +02:00
if ( pt ) {
2017-12-13 13:16:49 +01:00
ty = pt ;
2017-08-16 21:46:39 +02:00
} else {
break ;
}
}
2015-02-17 19:48:41 +00:00
delete entity ;
2012-07-18 19:32:58 +00:00
}
2015-02-17 19:48:41 +00:00
2017-12-13 13:16:49 +01:00
IfcEntityList : : ptr IfcFile : : instances_by_type ( const IfcParse : : declaration * t ) {
2015-01-05 14:11:42 +00:00
entities_by_type_t : : const_iterator it = bytype . find ( t ) ;
2014-05-04 14:42:55 +00:00
return ( it = = bytype . end ( ) ) ? IfcEntityList : : ptr ( ) : it - > second ;
2011-05-08 11:04:32 +00:00
}
2015-02-17 19:48:41 +00:00
2017-12-13 13:16:49 +01:00
IfcEntityList : : ptr IfcFile : : instances_by_type_excl_subtypes ( const IfcParse : : declaration * t ) {
2017-08-16 21:46:39 +02:00
entities_by_type_t : : const_iterator it = bytype_excl . find ( t ) ;
return ( it = = bytype_excl . end ( ) ) ? IfcEntityList : : ptr ( ) : it - > second ;
}
2017-12-13 13:16:49 +01:00
IfcEntityList : : ptr IfcFile : : instances_by_type ( const std : : string & t ) {
return instances_by_type ( schema ( ) - > declaration_by_name ( t ) ) ;
2012-07-19 00:14:01 +00:00
}
2015-02-17 19:48:41 +00:00
2020-07-11 11:55:00 +02:00
IfcEntityList : : ptr IfcFile : : instances_by_type_excl_subtypes ( const std : : string & t ) {
return instances_by_type_excl_subtypes ( schema ( ) - > declaration_by_name ( t ) ) ;
}
2017-12-13 13:16:49 +01:00
IfcEntityList : : ptr IfcFile : : instances_by_reference ( int t ) {
2015-01-05 14:11:42 +00:00
entities_by_ref_t : : const_iterator it = byref . find ( t ) ;
2018-09-28 15:00:48 +03:00
IfcEntityList : : ptr ret ;
2017-06-05 17:26:58 +02:00
if ( it ! = byref . end ( ) ) {
2018-10-01 15:11:34 +03:00
ref_map_t : : const_iterator cached_it = by_ref_cached_ . find ( t ) ;
if ( cached_it ! = by_ref_cached_ . end ( ) ) {
ret = cached_it - > second ;
}
else {
2019-02-06 13:33:38 +01:00
if ( it - > second . size ( ) ) {
ret . reset ( new IfcEntityList ) ;
ret - > reserve ( ( unsigned ) it - > second . size ( ) ) ;
const std : : vector < unsigned > & ids = it - > second ;
for ( std : : vector < unsigned > : : const_iterator jt = ids . begin ( ) ; jt ! = ids . end ( ) ; + + jt ) {
2019-02-06 15:39:43 +01:00
ret - > push ( instance_by_id ( * jt ) ) ;
2019-02-06 13:33:38 +01:00
}
2018-10-01 15:11:34 +03:00
}
by_ref_cached_ [ t ] = ret ;
}
2017-06-05 17:26:58 +02:00
}
2018-09-28 15:00:48 +03:00
return ret ;
2011-05-08 11:04:32 +00:00
}
2015-02-17 19:48:41 +00:00
2017-12-13 13:16:49 +01:00
IfcUtil : : IfcBaseClass * IfcFile : : instance_by_id ( int id ) {
2015-01-05 14:11:42 +00:00
entity_by_id_t : : const_iterator it = byid . find ( id ) ;
2015-02-17 19:48:41 +00:00
if ( it = = byid . end ( ) ) {
2018-04-23 10:51:59 +02:00
throw IfcException ( " Instance # " + boost : : lexical_cast < std : : string > ( id ) + " not found " ) ;
2011-05-08 11:04:32 +00:00
}
2011-07-11 09:33:18 +00:00
return it - > second ;
2011-05-08 11:04:32 +00:00
}
2015-02-17 19:48:41 +00:00
2017-12-13 13:58:58 +01:00
IfcUtil : : IfcBaseClass * IfcFile : : instance_by_guid ( const std : : string & guid ) {
2015-01-05 14:11:42 +00:00
entity_by_guid_t : : const_iterator it = byguid . find ( guid ) ;
2012-03-13 11:56:52 +00:00
if ( it = = byguid . end ( ) ) {
2018-04-23 10:51:59 +02:00
throw IfcException ( " Instance with GlobalId ' " + guid + " ' not found " ) ;
2012-03-13 11:56:52 +00:00
} else {
return it - > second ;
}
}
2011-07-25 14:56:40 +00:00
2012-08-11 13:24:08 +00:00
// FIXME: Test destructor to delete entity and arg allocations
IfcFile : : ~ IfcFile ( ) {
2015-01-05 14:11:42 +00:00
for ( entity_by_id_t : : const_iterator it = byid . begin ( ) ; it ! = byid . end ( ) ; + + it ) {
2011-09-03 13:58:59 +00:00
delete it - > second ;
}
2015-01-05 14:11:42 +00:00
delete stream ;
2011-09-03 13:58:59 +00:00
delete tokens ;
2012-08-11 13:24:08 +00:00
}
2015-01-05 14:11:42 +00:00
IfcFile : : entity_by_id_t : : const_iterator IfcFile : : begin ( ) const {
2012-03-16 15:21:52 +00:00
return byid . begin ( ) ;
}
2015-02-17 19:48:41 +00:00
2015-01-05 14:11:42 +00:00
IfcFile : : entity_by_id_t : : const_iterator IfcFile : : end ( ) const {
2012-03-16 15:21:52 +00:00
return byid . end ( ) ;
}
2012-08-11 13:24:08 +00:00
2017-08-16 21:46:39 +02:00
IfcFile : : type_iterator IfcFile : : types_begin ( ) const {
return bytype_excl . begin ( ) ;
}
IfcFile : : type_iterator IfcFile : : types_end ( ) const {
return bytype_excl . end ( ) ;
}
IfcFile : : type_iterator IfcFile : : types_incl_super_begin ( ) const {
return bytype . begin ( ) ;
}
IfcFile : : type_iterator IfcFile : : types_incl_super_end ( ) const {
return bytype . end ( ) ;
}
2018-11-13 14:46:15 +01:00
namespace {
struct id_instance_pair_sorter {
bool operator ( ) ( const IfcParse : : IfcFile : : entity_by_id_t : : value_type & a , const IfcParse : : IfcFile : : entity_by_id_t : : value_type & b ) const {
return a . first < b . first ;
}
} ;
}
2012-08-11 13:24:08 +00:00
std : : ostream & operator < < ( std : : ostream & os , const IfcParse : : IfcFile & f ) {
2015-01-16 16:26:40 +00:00
f . header ( ) . write ( os ) ;
2012-07-18 19:32:58 +00:00
2018-11-13 14:46:15 +01:00
typedef std : : vector < std : : pair < unsigned int , IfcUtil : : IfcBaseClass * > > vector_t ;
vector_t sorted ( f . begin ( ) , f . end ( ) ) ;
std : : sort ( sorted . begin ( ) , sorted . end ( ) , id_instance_pair_sorter ( ) ) ;
for ( vector_t : : const_iterator it = sorted . begin ( ) ; it ! = sorted . end ( ) ; + + it ) {
2014-05-04 14:42:55 +00:00
const IfcUtil : : IfcBaseClass * e = it - > second ;
2017-12-11 14:47:30 +01:00
if ( e - > declaration ( ) . as_entity ( ) ) {
os < < e - > data ( ) . toString ( true ) < < " ; " < < std : : endl ;
2015-01-25 10:50:12 +00:00
}
2012-07-18 19:32:58 +00:00
}
os < < " ENDSEC; " < < std : : endl ;
2012-08-11 13:24:08 +00:00
os < < " END-ISO-10303-21; " < < std : : endl ;
return os ;
}
2012-11-17 15:19:38 +00:00
2015-01-16 16:26:40 +00:00
std : : string IfcFile : : createTimestamp ( ) const {
2012-11-17 15:19:38 +00:00
char buf [ 255 ] ;
2015-01-16 16:26:40 +00:00
2012-11-17 15:19:38 +00:00
time_t t ;
time ( & t ) ;
2015-01-16 16:26:40 +00:00
struct tm * ti = localtime ( & t ) ;
std : : string result = " " ;
2012-11-17 15:19:38 +00:00
if ( strftime ( buf , 255 , " %Y-%m-%dT%H:%M:%S " , ti ) ) {
2015-01-16 16:26:40 +00:00
result = std : : string ( buf ) ;
2012-11-17 15:19:38 +00:00
}
2015-01-16 16:26:40 +00:00
return result ;
2015-01-10 22:13:52 +00:00
}
2017-12-13 13:58:58 +01:00
IfcEntityList : : ptr IfcFile : : getInverse ( int instance_id , const IfcParse : : declaration * type , int attribute_index ) {
2017-12-13 13:16:49 +01:00
IfcUtil : : IfcBaseClass * instance = instance_by_id ( instance_id ) ;
2015-01-10 22:13:52 +00:00
IfcEntityList : : ptr l = IfcEntityList : : ptr ( new IfcEntityList ) ;
2017-12-13 13:16:49 +01:00
IfcEntityList : : ptr all = instances_by_reference ( instance_id ) ;
2015-01-10 22:13:52 +00:00
if ( ! all ) return l ;
for ( IfcEntityList : : it it = all - > begin ( ) ; it ! = all - > end ( ) ; + + it ) {
2017-12-13 13:58:58 +01:00
bool valid = type = = 0 | | ( * it ) - > declaration ( ) . is ( * type ) ;
2015-01-10 22:13:52 +00:00
if ( valid & & attribute_index > = 0 ) {
2018-07-07 17:15:54 +02:00
try {
Argument * arg = ( * it ) - > data ( ) . getArgument ( attribute_index ) ;
if ( arg - > type ( ) = = IfcUtil : : Argument_ENTITY_INSTANCE ) {
valid = instance = = * arg ;
} else if ( arg - > type ( ) = = IfcUtil : : Argument_AGGREGATE_OF_ENTITY_INSTANCE ) {
IfcEntityList : : ptr li = * arg ;
valid = li - > contains ( instance ) ;
} else if ( arg - > type ( ) = = IfcUtil : : Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE ) {
IfcEntityListList : : ptr li = * arg ;
valid = li - > contains ( instance ) ;
}
} catch ( const IfcException & e ) {
2018-05-04 10:25:57 +02:00
valid = false ;
Logger : : Error ( e ) ;
2015-01-10 22:13:52 +00:00
}
}
if ( valid ) {
l - > push ( * it ) ;
}
}
return l ;
2015-01-16 16:26:40 +00:00
}
void IfcFile : : setDefaultHeaderValues ( ) {
const std : : string empty_string = " " ;
std : : vector < std : : string > file_description , schema_identifiers , empty_vector ;
file_description . push_back ( " ViewDefinition [CoordinationView] " ) ;
2017-12-21 14:14:04 +01:00
if ( schema ( ) ) {
schema_identifiers . push_back ( schema ( ) - > name ( ) ) ;
}
2015-01-16 16:26:40 +00:00
header ( ) . file_description ( ) . description ( file_description ) ;
header ( ) . file_description ( ) . implementation_level ( " 2;1 " ) ;
header ( ) . file_name ( ) . name ( empty_string ) ;
header ( ) . file_name ( ) . time_stamp ( createTimestamp ( ) ) ;
header ( ) . file_name ( ) . author ( empty_vector ) ;
header ( ) . file_name ( ) . organization ( empty_vector ) ;
header ( ) . file_name ( ) . preprocessor_version ( " IfcOpenShell " IFCOPENSHELL_VERSION ) ;
header ( ) . file_name ( ) . originating_system ( " IfcOpenShell " IFCOPENSHELL_VERSION ) ;
header ( ) . file_name ( ) . authorization ( empty_string ) ;
header ( ) . file_schema ( ) . schema_identifiers ( schema_identifiers ) ;
}
2017-12-13 18:05:10 +01:00
std : : pair < IfcUtil : : IfcBaseClass * , double > IfcFile : : getUnit ( const std : : string & unit_type ) {
std : : pair < IfcUtil : : IfcBaseClass * , double > return_value ( 0 , 1. ) ;
IfcEntityList : : ptr projects = instances_by_type ( schema ( ) - > declaration_by_name ( " IfcProject " ) ) ;
2018-04-04 14:40:10 +02:00
if ( projects & & projects - > size ( ) = = 1 ) {
2017-12-13 18:05:10 +01:00
IfcUtil : : IfcBaseClass * project = * projects - > begin ( ) ;
IfcUtil : : IfcBaseClass * unit_assignment = * project - > data ( ) . getArgument (
project - > declaration ( ) . as_entity ( ) - > attribute_index ( " UnitsInContext " )
) ;
IfcEntityList : : ptr units = * unit_assignment - > data ( ) . getArgument (
unit_assignment - > declaration ( ) . as_entity ( ) - > attribute_index ( " Units " )
) ;
2015-02-17 19:48:41 +00:00
for ( IfcEntityList : : it it = units - > begin ( ) ; it ! = units - > end ( ) ; + + it ) {
2017-12-18 15:25:09 +01:00
IfcUtil : : IfcBaseClass * unit = * it ;
2017-12-13 18:05:10 +01:00
if ( unit - > declaration ( ) . is ( " IfcNamedUnit " ) ) {
const std : : string file_unit_type = * unit - > data ( ) . getArgument (
unit - > declaration ( ) . as_entity ( ) - > attribute_index ( " UnitType " )
) ;
if ( file_unit_type ! = unit_type ) {
2015-02-17 19:48:41 +00:00
continue ;
}
2017-12-13 18:05:10 +01:00
IfcUtil : : IfcBaseClass * siunit = 0 ;
if ( unit - > declaration ( ) . is ( " IfcConversionBasedUnit " ) ) {
IfcUtil : : IfcBaseClass * mu = * unit - > data ( ) . getArgument (
unit - > declaration ( ) . as_entity ( ) - > attribute_index ( " ConversionFactor " )
) ;
IfcUtil : : IfcBaseClass * vlc = * mu - > data ( ) . getArgument (
mu - > declaration ( ) . as_entity ( ) - > attribute_index ( " ValueComponent " )
) ;
IfcUtil : : IfcBaseClass * unc = * mu - > data ( ) . getArgument (
mu - > declaration ( ) . as_entity ( ) - > attribute_index ( " ValueComponent " )
) ;
return_value . second * = static_cast < double > ( * vlc - > data ( ) . getArgument ( 0 ) ) ;
return_value . first = unit ;
if ( unc - > declaration ( ) . is ( " IfcSIUnit " ) ) {
siunit = unc ;
2015-02-17 19:48:41 +00:00
}
2017-12-13 18:05:10 +01:00
} else if ( unit - > declaration ( ) . is ( " IfcSIUnit " ) ) {
return_value . first = siunit = unit ;
2015-02-17 19:48:41 +00:00
}
2017-12-13 18:05:10 +01:00
2015-11-21 23:05:28 +02:00
if ( siunit ) {
2017-12-13 18:05:10 +01:00
Argument * prefix = siunit - > data ( ) . getArgument (
siunit - > declaration ( ) . as_entity ( ) - > attribute_index ( " Prefix " )
) ;
if ( ! prefix - > isNull ( ) ) {
return_value . second * = IfcSIPrefixToValue ( * prefix ) ;
2015-02-17 19:48:41 +00:00
}
}
}
}
}
2017-12-13 18:05:10 +01:00
2015-02-17 19:48:41 +00:00
return return_value ;
2016-05-15 15:47:21 +02:00
}
2018-08-29 12:54:25 +02:00
void IfcParse : : IfcFile : : build_inverses_ ( IfcUtil : : IfcBaseClass * inst ) {
IfcEntityList : : ptr entity_attributes ( new IfcEntityList ) ;
try {
entity_attributes = traverse ( inst , 1 ) ;
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
}
for ( IfcEntityList : : it it = entity_attributes - > begin ( ) ; it ! = entity_attributes - > end ( ) ; + + it ) {
IfcUtil : : IfcBaseClass * entity_attribute = * it ;
if ( * it = = inst ) continue ;
try {
if ( entity_attribute - > declaration ( ) . as_entity ( ) ) {
unsigned entity_attribute_id = entity_attribute - > data ( ) . id ( ) ;
byref [ entity_attribute_id ] . push_back ( inst - > data ( ) . id ( ) ) ;
}
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
}
}
}
void IfcParse : : IfcFile : : build_inverses ( ) {
for ( auto & pair : * this ) {
build_inverses_ ( pair . second ) ;
}
2020-09-30 09:38:01 +02:00
}