Skip to content

Commit f3c26c3

Browse files
committed
Parse the spf header and check schema_identifiers against compiled schema
1 parent 4d5d749 commit f3c26c3

14 files changed

Lines changed: 334 additions & 32 deletions

File tree

cmake/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ ADD_LIBRARY(IfcParse STATIC
133133
../src/ifcparse/IfcHierarchyHelper.cpp
134134
../src/ifcparse/IfcLateBoundEntity.cpp
135135
../src/ifcparse/IfcParse.cpp
136+
../src/ifcparse/IfcSpfHeader.cpp
136137
../src/ifcparse/IfcUtil.cpp
137138
../src/ifcparse/IfcWrite.cpp
138139
)
@@ -220,6 +221,7 @@ SET(include_files_parse
220221
../src/ifcparse/IfcHierarchyHelper.h
221222
../src/ifcparse/IfcLateBoundEntity.h
222223
../src/ifcparse/IfcParse.h
224+
../src/ifcparse/IfcSpfHeader.h
223225
../src/ifcparse/IfcSpfStream.h
224226
../src/ifcparse/IfcUtil.h
225227
../src/ifcparse/IfcWritableEntity.h

src/ifcexpressparser/templates.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
3636
namespace %(schema_name)s {
3737
38+
const char* const Identifier = "%(schema_name_upper)s";
39+
3840
// Forward definitions
3941
%(forward_definitions)s
4042

src/ifcopenshell-python/ifcopenshell/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,16 @@ def create_entity(self,type,*args,**kwargs):
8080
self.wrapped_data.add(e.wrapped_data)
8181
self.instances.append(e)
8282
return e
83-
def __getattr__(self,attr):
83+
def __getattr__(self, attr):
8484
if attr[0:6] == 'create': return functools.partial(self.create_entity,attr[6:])
85+
else: return getattr(self.wrapped_data, attr)
8586
def __getitem__(self, key):
8687
if isinstance(key, int):
8788
return entity_instance(self.wrapped_data.by_id(key))
8889
elif isinstance(key, str):
8990
return entity_instance(self.wrapped_data.by_guid(key))
9091
def by_type(self, type):
9192
return [entity_instance(e) for e in self.wrapped_data.by_type(type)]
92-
def write(self, fn):
93-
self.wrapped_data.write(fn)
9493
def __iter__(self):
9594
return iter(self[id] for id in self.wrapped_data.entity_names())
9695

src/ifcparse/Ifc2x3-latebound.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
* *
2525
********************************************************************************/
2626

27+
#ifndef USE_IFC4
28+
2729
#include <set>
2830

2931
#include "../ifcparse/Ifc2x3.h"
@@ -4253,3 +4255,5 @@ void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) {
42534255
}
42544256
}
42554257
}
4258+
4259+
#endif

src/ifcparse/Ifc2x3.h

Lines changed: 2 additions & 0 deletions
Large diffs are not rendered by default.

src/ifcparse/Ifc4-latebound.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
* *
2525
********************************************************************************/
2626

27+
#ifdef USE_IFC4
28+
2729
#include <set>
2830

2931
#include "../ifcparse/Ifc4.h"
@@ -4943,3 +4945,5 @@ void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) {
49434945
}
49444946
}
49454947
}
4948+
4949+
#endif

src/ifcparse/Ifc4.h

Lines changed: 2 additions & 0 deletions
Large diffs are not rendered by default.

src/ifcparse/IfcFile.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <map>
2424

2525
#include "../ifcparse/IfcParse.h"
26+
#include "../ifcparse/IfcSpfHeader.h"
2627

2728
namespace IfcParse {
2829

@@ -48,6 +49,8 @@ class IfcFile {
4849
unsigned int lastId;
4950
unsigned int MaxId;
5051

52+
IfcSpfHeader _header;
53+
5154
std::string _filename;
5255
std::string _timestamp;
5356
std::string _author;
@@ -56,7 +59,7 @@ class IfcFile {
5659

5760
void initTimestamp();
5861
public:
59-
IfcParse::Tokens* tokens;
62+
IfcParse::IfcSpfLexer* tokens;
6063
IfcParse::IfcSpfStream* stream;
6164

6265
IfcFile(bool create_latebound_entities = false);
@@ -116,6 +119,8 @@ class IfcFile {
116119
std::string authorEmail() const;
117120
std::string authorOrganisation() const;
118121

122+
const IfcSpfHeader& header() const { return _header; }
123+
119124
bool create_latebound_entities() const { return _create_latebound_entities; }
120125
};
121126

src/ifcparse/IfcParse.cpp

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -210,17 +210,17 @@ void IfcSpfStream::Inc() {
210210
if ( current == '\n' || current == '\r' ) IfcSpfStream::Inc();
211211
}
212212

213-
Tokens::Tokens(IfcParse::IfcSpfStream *s, IfcParse::IfcFile* f) {
213+
IfcSpfLexer::IfcSpfLexer(IfcParse::IfcSpfStream *s, IfcParse::IfcFile* f) {
214214
file = f;
215215
stream = s;
216216
decoder = new IfcCharacterDecoder(s);
217217
}
218218

219-
Tokens::~Tokens() {
219+
IfcSpfLexer::~IfcSpfLexer() {
220220
delete decoder;
221221
}
222222

223-
unsigned int Tokens::skipWhitespace() {
223+
unsigned int IfcSpfLexer::skipWhitespace() {
224224
unsigned int n = 0;
225225
while ( !stream->eof ) {
226226
char c = stream->Peek();
@@ -233,7 +233,7 @@ unsigned int Tokens::skipWhitespace() {
233233
return n;
234234
}
235235

236-
unsigned int Tokens::skipComment() {
236+
unsigned int IfcSpfLexer::skipComment() {
237237
char c = stream->Peek();
238238
if (c != '/') return 0;
239239
stream->Inc();
@@ -257,7 +257,7 @@ unsigned int Tokens::skipComment() {
257257
//
258258
// Returns the offset of the current Token and moves cursor to next
259259
//
260-
Token Tokens::Next() {
260+
Token IfcSpfLexer::Next() {
261261

262262
if ( stream->eof ) return TokenPtr();
263263

@@ -298,7 +298,7 @@ Token Tokens::Next() {
298298
// Reads a std::string from the file at specified offset
299299
// Omits whitespace and comments
300300
//
301-
std::string Tokens::TokenString(unsigned int offset) {
301+
std::string IfcSpfLexer::TokenString(unsigned int offset) {
302302
const bool was_eof = stream->eof;
303303
unsigned int old_offset = stream->Tell();
304304
stream->Seek(offset);
@@ -323,9 +323,9 @@ std::string Tokens::TokenString(unsigned int offset) {
323323
// Functions for creating Tokens from an arbitary file offset.
324324
// The first 4 bits are reserved for Tokens of type ()=,;$*
325325
//
326-
Token IfcParse::TokenPtr(Tokens* tokens, unsigned int offset) { return Token(tokens,offset); }
327-
Token IfcParse::TokenPtr(char c) { return Token((Tokens*)0,(unsigned) c); }
328-
Token IfcParse::TokenPtr() { return Token((Tokens*)0,0); }
326+
Token IfcParse::TokenPtr(IfcSpfLexer* tokens, unsigned int offset) { return Token(tokens,offset); }
327+
Token IfcParse::TokenPtr(char c) { return Token((IfcSpfLexer*)0,(unsigned) c); }
328+
Token IfcParse::TokenPtr() { return Token((IfcSpfLexer*)0,0); }
329329

330330
//
331331
// Functions to convert Tokens to binary data
@@ -345,8 +345,9 @@ bool TokenFunc::isString(const Token& t) {
345345
bool TokenFunc::isEnumeration(const Token& t) {
346346
return ! isOperator(t) && startsWith(t, '.');
347347
}
348-
bool TokenFunc::isDatatype(const Token& t) {
349-
return ! isOperator(t) && startsWith(t, 'I');
348+
bool TokenFunc::isKeyword(const Token& t) {
349+
// bool is a subtype of enumeration, no need to test for that
350+
return !isOperator(t) && !isIdentifier(t) && !isString(t) && !isEnumeration(t) && !isInt(t) && !isFloat(t);
350351
}
351352
bool TokenFunc::isInt(const Token& t) {
352353
if (isOperator(t)) return false;
@@ -419,7 +420,7 @@ EntityArgument::EntityArgument(const Token& t) {
419420
// Reads the arguments from a list of token
420421
// Aditionally, stores the ids (i.e. #[\d]+) in a vector
421422
//
422-
ArgumentList::ArgumentList(Tokens* t, std::vector<unsigned int>& ids) {
423+
ArgumentList::ArgumentList(IfcSpfLexer* t, std::vector<unsigned int>& ids) {
423424
IfcParse::IfcFile* file = t->file;
424425

425426
Token next = t->Next();
@@ -429,7 +430,7 @@ ArgumentList::ArgumentList(Tokens* t, std::vector<unsigned int>& ids) {
429430
else if ( TokenFunc::isOperator(next,'(') ) Push( new ArgumentList(t,ids) );
430431
else {
431432
if ( TokenFunc::isIdentifier(next) ) ids.push_back(TokenFunc::asInt(next));
432-
if ( TokenFunc::isDatatype(next) ) {
433+
if ( TokenFunc::isKeyword(next) ) {
433434
t->Next();
434435
try {
435436
Push ( new EntityArgument(next) );
@@ -619,7 +620,7 @@ EntityArgument::~EntityArgument() { delete entity; }
619620
Entity::Entity(unsigned int i, IfcFile* f) : _id(i), args(0) {
620621
file = f;
621622
Token datatype = f->tokens->Next();
622-
if ( ! TokenFunc::isDatatype(datatype)) throw IfcException("Unexpected token while parsing entity");
623+
if ( ! TokenFunc::isKeyword(datatype)) throw IfcException("Unexpected token while parsing entity");
623624
_type = IfcSchema::Type::FromString(TokenFunc::asString(datatype));
624625
offset = datatype.second;
625626
}
@@ -661,7 +662,7 @@ void Entity::Load(std::vector<unsigned int>& ids, bool seek) const {
661662
if ( seek ) {
662663
file->tokens->stream->Seek(offset);
663664
Token datatype = file->tokens->Next();
664-
if ( ! TokenFunc::isDatatype(datatype)) throw IfcException("Unexpected token while parsing entity");
665+
if ( ! TokenFunc::isKeyword(datatype)) throw IfcException("Unexpected token while parsing entity");
665666
_type = IfcSchema::Type::FromString(TokenFunc::asString(datatype));
666667
}
667668
Token open = file->tokens->Next();
@@ -760,13 +761,27 @@ bool IfcFile::Init(std::istream& f, int len) {
760761
bool IfcFile::Init(void* data, int len) {
761762
return IfcFile::Init(new IfcSpfStream(data,len));
762763
}
763-
bool IfcFile::Init(IfcParse::IfcSpfStream* f) {
764-
IfcSchema::InitStringMap();
765-
stream = f;
766-
if ( ! stream->valid ) return false;
767-
tokens = new Tokens (stream,this);
764+
bool IfcFile::Init(IfcParse::IfcSpfStream* s) {
765+
stream = s;
766+
if (!stream->valid) {
767+
return false;
768+
}
769+
770+
tokens = new IfcSpfLexer(stream, this);
771+
_header.lexer(tokens);
772+
_header.tryRead();
773+
774+
std::vector<std::string> schemas;
775+
try {
776+
schemas = _header.file_schema().schema_identifiers();
777+
} catch (...) {}
778+
if (schemas.size() != 1 || schemas[0] != IfcSchema::Identifier) {
779+
Logger::Message(Logger::LOG_WARNING, std::string("File schema encountered that is different from expected value of '") + IfcSchema::Identifier + "'");
780+
}
781+
768782
Token token = TokenPtr();
769783
Token previous = TokenPtr();
784+
770785
unsigned int currentId = 0;
771786
lastId = 0;
772787
int x = 0;

src/ifcparse/IfcParse.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ namespace IfcParse {
5353

5454
class Entity;
5555
class IfcFile;
56-
class Tokens;
56+
class IfcSpfLexer;
5757

58-
typedef std::pair<Tokens*,unsigned> Token;
58+
typedef std::pair<IfcSpfLexer*, unsigned> Token;
5959

6060
/// Provides functions to convert Tokens to binary data
6161
/// Tokens are merely offsets to where they can be read in the file
@@ -74,7 +74,7 @@ namespace IfcParse {
7474
/// Returns whether the token can be interpreted as an enumerated value
7575
static bool isEnumeration(const Token& t);
7676
/// Returns whether the token can be interpreted as a datatype name
77-
static bool isDatatype(const Token& t);
77+
static bool isKeyword(const Token& t);
7878
/// Returns whether the token can be interpreted as an integer
7979
static bool isInt(const Token& t);
8080
/// Returns whether the token can be interpreted as a boolean
@@ -97,22 +97,22 @@ namespace IfcParse {
9797
// Functions for creating Tokens from an arbitary file offset
9898
// The first 4 bits are reserved for Tokens of type ()=,;$*
9999
//
100-
Token TokenPtr(Tokens* tokens, unsigned int offset);
100+
Token TokenPtr(IfcSpfLexer* tokens, unsigned int offset);
101101
Token TokenPtr(char c);
102102
Token TokenPtr();
103103

104104
/// A stream of tokens to be read from a IfcSpfStream.
105-
class Tokens {
105+
class IfcSpfLexer {
106106
private:
107107
IfcCharacterDecoder* decoder;
108108
unsigned int skipWhitespace();
109109
unsigned int skipComment();
110110
public:
111111
IfcSpfStream* stream;
112112
IfcFile* file;
113-
Tokens(IfcSpfStream* s, IfcFile* f);
113+
IfcSpfLexer(IfcSpfStream* s, IfcFile* f);
114114
Token Next();
115-
~Tokens();
115+
~IfcSpfLexer();
116116
std::string TokenString(unsigned int offset);
117117
};
118118

@@ -124,7 +124,7 @@ namespace IfcParse {
124124
std::vector<Argument*> list;
125125
void Push(Argument* l);
126126
public:
127-
ArgumentList(Tokens* t, std::vector<unsigned int>& ids);
127+
ArgumentList(IfcSpfLexer* t, std::vector<unsigned int>& ids);
128128
~ArgumentList();
129129

130130
IfcUtil::ArgumentType type() const;

0 commit comments

Comments
 (0)