Parse the spf header and check schema_identifiers against compiled schema

This commit is contained in:
Thomas Krijnen
2015-01-05 17:46:23 +00:00
parent 4d5d749255
commit f3c26c372d
14 changed files with 334 additions and 32 deletions
+2
View File
@@ -133,6 +133,7 @@ ADD_LIBRARY(IfcParse STATIC
../src/ifcparse/IfcHierarchyHelper.cpp
../src/ifcparse/IfcLateBoundEntity.cpp
../src/ifcparse/IfcParse.cpp
../src/ifcparse/IfcSpfHeader.cpp
../src/ifcparse/IfcUtil.cpp
../src/ifcparse/IfcWrite.cpp
)
@@ -220,6 +221,7 @@ SET(include_files_parse
../src/ifcparse/IfcHierarchyHelper.h
../src/ifcparse/IfcLateBoundEntity.h
../src/ifcparse/IfcParse.h
../src/ifcparse/IfcSpfHeader.h
../src/ifcparse/IfcSpfStream.h
../src/ifcparse/IfcUtil.h
../src/ifcparse/IfcWritableEntity.h
+2
View File
@@ -35,6 +35,8 @@ header = """
namespace %(schema_name)s {
const char* const Identifier = "%(schema_name_upper)s";
// Forward definitions
%(forward_definitions)s
@@ -80,8 +80,9 @@ class file(object):
self.wrapped_data.add(e.wrapped_data)
self.instances.append(e)
return e
def __getattr__(self,attr):
def __getattr__(self, attr):
if attr[0:6] == 'create': return functools.partial(self.create_entity,attr[6:])
else: return getattr(self.wrapped_data, attr)
def __getitem__(self, key):
if isinstance(key, int):
return entity_instance(self.wrapped_data.by_id(key))
@@ -89,8 +90,6 @@ class file(object):
return entity_instance(self.wrapped_data.by_guid(key))
def by_type(self, type):
return [entity_instance(e) for e in self.wrapped_data.by_type(type)]
def write(self, fn):
self.wrapped_data.write(fn)
def __iter__(self):
return iter(self[id] for id in self.wrapped_data.entity_names())
+4
View File
@@ -24,6 +24,8 @@
* *
********************************************************************************/
#ifndef USE_IFC4
#include <set>
#include "../ifcparse/Ifc2x3.h"
@@ -4253,3 +4255,5 @@ void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) {
}
}
}
#endif
File diff suppressed because one or more lines are too long
+4
View File
@@ -24,6 +24,8 @@
* *
********************************************************************************/
#ifdef USE_IFC4
#include <set>
#include "../ifcparse/Ifc4.h"
@@ -4943,3 +4945,5 @@ void Type::PopulateDerivedFields(IfcWrite::IfcWritableEntity* e) {
}
}
}
#endif
File diff suppressed because one or more lines are too long
+6 -1
View File
@@ -23,6 +23,7 @@
#include <map>
#include "../ifcparse/IfcParse.h"
#include "../ifcparse/IfcSpfHeader.h"
namespace IfcParse {
@@ -48,6 +49,8 @@ private:
unsigned int lastId;
unsigned int MaxId;
IfcSpfHeader _header;
std::string _filename;
std::string _timestamp;
std::string _author;
@@ -56,7 +59,7 @@ private:
void initTimestamp();
public:
IfcParse::Tokens* tokens;
IfcParse::IfcSpfLexer* tokens;
IfcParse::IfcSpfStream* stream;
IfcFile(bool create_latebound_entities = false);
@@ -116,6 +119,8 @@ public:
std::string authorEmail() const;
std::string authorOrganisation() const;
const IfcSpfHeader& header() const { return _header; }
bool create_latebound_entities() const { return _create_latebound_entities; }
};
+35 -20
View File
@@ -210,17 +210,17 @@ void IfcSpfStream::Inc() {
if ( current == '\n' || current == '\r' ) IfcSpfStream::Inc();
}
Tokens::Tokens(IfcParse::IfcSpfStream *s, IfcParse::IfcFile* f) {
IfcSpfLexer::IfcSpfLexer(IfcParse::IfcSpfStream *s, IfcParse::IfcFile* f) {
file = f;
stream = s;
decoder = new IfcCharacterDecoder(s);
}
Tokens::~Tokens() {
IfcSpfLexer::~IfcSpfLexer() {
delete decoder;
}
unsigned int Tokens::skipWhitespace() {
unsigned int IfcSpfLexer::skipWhitespace() {
unsigned int n = 0;
while ( !stream->eof ) {
char c = stream->Peek();
@@ -233,7 +233,7 @@ unsigned int Tokens::skipWhitespace() {
return n;
}
unsigned int Tokens::skipComment() {
unsigned int IfcSpfLexer::skipComment() {
char c = stream->Peek();
if (c != '/') return 0;
stream->Inc();
@@ -257,7 +257,7 @@ unsigned int Tokens::skipComment() {
//
// Returns the offset of the current Token and moves cursor to next
//
Token Tokens::Next() {
Token IfcSpfLexer::Next() {
if ( stream->eof ) return TokenPtr();
@@ -298,7 +298,7 @@ Token Tokens::Next() {
// Reads a std::string from the file at specified offset
// Omits whitespace and comments
//
std::string Tokens::TokenString(unsigned int offset) {
std::string IfcSpfLexer::TokenString(unsigned int offset) {
const bool was_eof = stream->eof;
unsigned int old_offset = stream->Tell();
stream->Seek(offset);
@@ -323,9 +323,9 @@ std::string Tokens::TokenString(unsigned int offset) {
// Functions for creating Tokens from an arbitary file offset.
// The first 4 bits are reserved for Tokens of type ()=,;$*
//
Token IfcParse::TokenPtr(Tokens* tokens, unsigned int offset) { return Token(tokens,offset); }
Token IfcParse::TokenPtr(char c) { return Token((Tokens*)0,(unsigned) c); }
Token IfcParse::TokenPtr() { return Token((Tokens*)0,0); }
Token IfcParse::TokenPtr(IfcSpfLexer* tokens, unsigned int offset) { return Token(tokens,offset); }
Token IfcParse::TokenPtr(char c) { return Token((IfcSpfLexer*)0,(unsigned) c); }
Token IfcParse::TokenPtr() { return Token((IfcSpfLexer*)0,0); }
//
// Functions to convert Tokens to binary data
@@ -345,8 +345,9 @@ bool TokenFunc::isString(const Token& t) {
bool TokenFunc::isEnumeration(const Token& t) {
return ! isOperator(t) && startsWith(t, '.');
}
bool TokenFunc::isDatatype(const Token& t) {
return ! isOperator(t) && startsWith(t, 'I');
bool TokenFunc::isKeyword(const Token& t) {
// bool is a subtype of enumeration, no need to test for that
return !isOperator(t) && !isIdentifier(t) && !isString(t) && !isEnumeration(t) && !isInt(t) && !isFloat(t);
}
bool TokenFunc::isInt(const Token& t) {
if (isOperator(t)) return false;
@@ -419,7 +420,7 @@ EntityArgument::EntityArgument(const Token& t) {
// Reads the arguments from a list of token
// Aditionally, stores the ids (i.e. #[\d]+) in a vector
//
ArgumentList::ArgumentList(Tokens* t, std::vector<unsigned int>& ids) {
ArgumentList::ArgumentList(IfcSpfLexer* t, std::vector<unsigned int>& ids) {
IfcParse::IfcFile* file = t->file;
Token next = t->Next();
@@ -429,7 +430,7 @@ ArgumentList::ArgumentList(Tokens* t, std::vector<unsigned int>& ids) {
else if ( TokenFunc::isOperator(next,'(') ) Push( new ArgumentList(t,ids) );
else {
if ( TokenFunc::isIdentifier(next) ) ids.push_back(TokenFunc::asInt(next));
if ( TokenFunc::isDatatype(next) ) {
if ( TokenFunc::isKeyword(next) ) {
t->Next();
try {
Push ( new EntityArgument(next) );
@@ -619,7 +620,7 @@ EntityArgument::~EntityArgument() { delete entity; }
Entity::Entity(unsigned int i, IfcFile* f) : _id(i), args(0) {
file = f;
Token datatype = f->tokens->Next();
if ( ! TokenFunc::isDatatype(datatype)) throw IfcException("Unexpected token while parsing entity");
if ( ! TokenFunc::isKeyword(datatype)) throw IfcException("Unexpected token while parsing entity");
_type = IfcSchema::Type::FromString(TokenFunc::asString(datatype));
offset = datatype.second;
}
@@ -661,7 +662,7 @@ void Entity::Load(std::vector<unsigned int>& ids, bool seek) const {
if ( seek ) {
file->tokens->stream->Seek(offset);
Token datatype = file->tokens->Next();
if ( ! TokenFunc::isDatatype(datatype)) throw IfcException("Unexpected token while parsing entity");
if ( ! TokenFunc::isKeyword(datatype)) throw IfcException("Unexpected token while parsing entity");
_type = IfcSchema::Type::FromString(TokenFunc::asString(datatype));
}
Token open = file->tokens->Next();
@@ -760,13 +761,27 @@ bool IfcFile::Init(std::istream& f, int len) {
bool IfcFile::Init(void* data, int len) {
return IfcFile::Init(new IfcSpfStream(data,len));
}
bool IfcFile::Init(IfcParse::IfcSpfStream* f) {
IfcSchema::InitStringMap();
stream = f;
if ( ! stream->valid ) return false;
tokens = new Tokens (stream,this);
bool IfcFile::Init(IfcParse::IfcSpfStream* s) {
stream = s;
if (!stream->valid) {
return false;
}
tokens = new IfcSpfLexer(stream, this);
_header.lexer(tokens);
_header.tryRead();
std::vector<std::string> schemas;
try {
schemas = _header.file_schema().schema_identifiers();
} catch (...) {}
if (schemas.size() != 1 || schemas[0] != IfcSchema::Identifier) {
Logger::Message(Logger::LOG_WARNING, std::string("File schema encountered that is different from expected value of '") + IfcSchema::Identifier + "'");
}
Token token = TokenPtr();
Token previous = TokenPtr();
unsigned int currentId = 0;
lastId = 0;
int x = 0;
+8 -8
View File
@@ -53,9 +53,9 @@ namespace IfcParse {
class Entity;
class IfcFile;
class Tokens;
class IfcSpfLexer;
typedef std::pair<Tokens*,unsigned> Token;
typedef std::pair<IfcSpfLexer*, unsigned> Token;
/// Provides functions to convert Tokens to binary data
/// Tokens are merely offsets to where they can be read in the file
@@ -74,7 +74,7 @@ namespace IfcParse {
/// Returns whether the token can be interpreted as an enumerated value
static bool isEnumeration(const Token& t);
/// Returns whether the token can be interpreted as a datatype name
static bool isDatatype(const Token& t);
static bool isKeyword(const Token& t);
/// Returns whether the token can be interpreted as an integer
static bool isInt(const Token& t);
/// Returns whether the token can be interpreted as a boolean
@@ -97,12 +97,12 @@ namespace IfcParse {
// Functions for creating Tokens from an arbitary file offset
// The first 4 bits are reserved for Tokens of type ()=,;$*
//
Token TokenPtr(Tokens* tokens, unsigned int offset);
Token TokenPtr(IfcSpfLexer* tokens, unsigned int offset);
Token TokenPtr(char c);
Token TokenPtr();
/// A stream of tokens to be read from a IfcSpfStream.
class Tokens {
class IfcSpfLexer {
private:
IfcCharacterDecoder* decoder;
unsigned int skipWhitespace();
@@ -110,9 +110,9 @@ namespace IfcParse {
public:
IfcSpfStream* stream;
IfcFile* file;
Tokens(IfcSpfStream* s, IfcFile* f);
IfcSpfLexer(IfcSpfStream* s, IfcFile* f);
Token Next();
~Tokens();
~IfcSpfLexer();
std::string TokenString(unsigned int offset);
};
@@ -124,7 +124,7 @@ namespace IfcParse {
std::vector<Argument*> list;
void Push(Argument* l);
public:
ArgumentList(Tokens* t, std::vector<unsigned int>& ids);
ArgumentList(IfcSpfLexer* t, std::vector<unsigned int>& ids);
~ArgumentList();
IfcUtil::ArgumentType type() const;
+108
View File
@@ -0,0 +1,108 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
#include "../ifcparse/IfcParse.h"
#include "IfcSpfHeader.h"
static const char * const ISO_10303_21 = "ISO-10303-21";
static const char * const HEADER = "HEADER";
static const char * const FILE_DESCRIPTION = "FILE_DESCRIPTION";
static const char * const FILE_NAME = "FILE_NAME";
static const char * const FILE_SCHEMA = "FILE_SCHEMA";
static const char * const FILE_POPULATION = "FILE_POPULATION";
static const char * const SECTION_LANGUAGE = "SECTION_LANGUAGE";
static const char * const SECTION_CONTEXT = "SECTION_CONTEXT";
static const char * const ENDSEC = "ENDSEC";
static const char * const DATA = "DATA";
using namespace IfcParse;
void IfcSpfHeader::readSemicolon() {
if (!TokenFunc::isOperator(_lexer->Next(), ';')) {
throw IfcException(std::string("Expected ;"));
}
}
void IfcSpfHeader::readParen() {
if (!TokenFunc::isOperator(_lexer->Next(), '(')) {
throw IfcException(std::string("Expected ("));
}
}
void IfcSpfHeader::readTerminal(const std::string& term, Trail trail) {
if (TokenFunc::asString(_lexer->Next()) != term) {
throw IfcException(std::string("Expected " + term));
}
if (trail == TRAILING_SEMICOLON) {
readSemicolon();
} else if (trail == TRAILING_PAREN) {
readParen();
}
}
void IfcSpfHeader::read() {
readTerminal(ISO_10303_21, TRAILING_SEMICOLON);
readTerminal(HEADER, TRAILING_SEMICOLON);
readTerminal(FILE_DESCRIPTION, TRAILING_PAREN);
_file_description = new FileDescription(_lexer);
readSemicolon();
readTerminal(FILE_NAME, TRAILING_PAREN);
_file_name = new FileName(_lexer);
readSemicolon();
readTerminal(FILE_SCHEMA, TRAILING_PAREN);
_file_schema = new FileSchema(_lexer);
readSemicolon();
}
bool IfcSpfHeader::tryRead() {
try {
read();
return true;
} catch(const IfcException&) {
return false;
}
}
const FileDescription& IfcSpfHeader::file_description() {
if (_file_description) {
return *_file_description;
} else {
throw IfcException("File description not read");
}
}
const FileName& IfcSpfHeader::file_name() {
if (_file_name) {
return *_file_name;
} else {
throw IfcException("File name not read");
}
}
const FileSchema& IfcSpfHeader::file_schema() {
if (_file_schema) {
return *_file_schema;
} else {
throw IfcException("File schema not read");
}
}
+96
View File
@@ -0,0 +1,96 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
#ifndef IFCSPFHEADER_H
#define IFCSPFHEADER_H
#include "../ifcparse/IfcSpfStream.h"
namespace IfcParse {
class HeaderEntity {
private:
ArgumentList* list;
protected:
HeaderEntity(IfcSpfLexer* lexer) {
std::vector<unsigned int> ids;
list = new ArgumentList(lexer, ids);
};
Argument* getArgument(unsigned int i) const {
return (*list)[i];
}
};
class FileDescription : private HeaderEntity {
public:
FileDescription(IfcSpfLexer* lexer) : HeaderEntity(lexer) {}
std::vector<std::string> description() const { return *getArgument(0); }
std::string implementation_level() const { return *getArgument(1); }
};
class FileName : private HeaderEntity {
public:
FileName(IfcSpfLexer* lexer) : HeaderEntity(lexer) {}
std::string name() const { return *getArgument(0); }
std::string time_stamp() const { return *getArgument(1); }
std::vector<std::string> author() const { return *getArgument(2); }
std::vector<std::string> organization() const { return *getArgument(3); }
std::string preprocessor_version() const { return *getArgument(4); }
std::string originating_system() const { return *getArgument(5); }
std::string authorization()const { return *getArgument(6); }
};
class FileSchema : private HeaderEntity {
public:
FileSchema(IfcSpfLexer* lexer) : HeaderEntity(lexer) {}
std::vector<std::string> schema_identifiers() const { return *getArgument(0); }
};
class IfcSpfHeader {
private:
IfcSpfLexer* _lexer;
FileDescription* _file_description;
FileName* _file_name;
FileSchema* _file_schema;
void readParen();
void readSemicolon();\
enum Trail {
TRAILING_SEMICOLON,
TRAILING_PAREN,
NONE
};
void readTerminal(const std::string& term, Trail trail);
public:
IfcSpfHeader() : _lexer(0), _file_description(0), _file_name(0), _file_schema(0) {}
explicit IfcSpfHeader(IfcSpfLexer* lexer) : _lexer(lexer) {}
IfcSpfLexer* lexer() { return _lexer; }
void lexer(IfcSpfLexer* l) { _lexer = l; }
void read();
bool tryRead();
const FileDescription& file_description();
const FileName& file_name();
const FileSchema& file_schema();
};
}
#endif
+55
View File
@@ -28,6 +28,14 @@
%ignore IfcParse::IfcFile::AddEntity;
%ignore operator<<;
%ignore IfcParse::FileDescription::FileDescription;
%ignore IfcParse::FileName::FileName;
%ignore IfcParse::FileSchema::FileSchema;
%ignore IfcParse::IfcFile::tokens;
%ignore IfcParse::IfcSpfHeader::IfcSpfHeader(IfcSpfLexer*);
%ignore IfcParse::IfcSpfHeader::lexer;
%ignore IfcParse::IfcSpfHeader::stream;
%rename("by_type") EntitiesByType;
%rename("__len__") getArgumentCount;
%rename("get_argument_type") getArgumentType;
@@ -156,6 +164,11 @@
std::ofstream f(fn.c_str());
f << (*$self);
}
%pythoncode %{
if _newclass:
# Hide the getters with read-only property implementations
header = property(header)
%}
}
%extend IfcParse::IfcLateBoundEntity {
@@ -164,6 +177,48 @@
%}
}
%extend IfcParse::IfcSpfHeader {
%pythoncode %{
if _newclass:
# Hide the getters with read-only property implementations
file_description = property(file_description)
file_name = property(file_name)
file_schema = property(file_schema)
%}
};
%extend IfcParse::FileDescription {
%pythoncode %{
if _newclass:
# Hide the getters with read-only property implementations
description = property(description)
implementation_level = property(implementation_level)
%}
};
%extend IfcParse::FileName {
%pythoncode %{
if _newclass:
# Hide the getters with read-only property implementations
name = property(name)
time_stamp = property(time_stamp)
author = property(author)
organization = property(organization)
preprocessor_version = property(preprocessor_version)
originating_system = property(originating_system)
authorization = property(authorization)
%}
};
%extend IfcParse::FileSchema {
%pythoncode %{
if _newclass:
# Hide the getters with read-only property implementations
schema_identifiers = property(schema_identifiers)
%}
};
%include "../ifcparse/IfcSpfHeader.h"
%include "../ifcparse/IfcFile.h"
%include "../ifcparse/IfcLateBoundEntity.h"
+8
View File
@@ -213,6 +213,10 @@
RelativePath="..\src\ifcparse\IfcWrite.cpp"
>
</File>
<File
RelativePath="..\src\ifcparse\IfcSpfHeader.cpp"
>
</File>
<File
RelativePath="..\src\ifcparse\IfcGuidHelper.cpp"
>
@@ -283,6 +287,10 @@
RelativePath="..\src\ifcparse\IfcParse.h"
>
</File>
<File
RelativePath="..\src\ifcparse\IfcSpfHeader.h"
>
</File>
<File
RelativePath="..\src\ifcparse\IfcSpfStream.h"
>