diff --git a/src/ifcopenshell-python/ifcopenshell/__init__.py b/src/ifcopenshell-python/ifcopenshell/__init__.py index 0e79c4f913..827c6c3324 100644 --- a/src/ifcopenshell-python/ifcopenshell/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/__init__.py @@ -54,16 +54,36 @@ from . import guid from .file import file from .entity_instance import entity_instance +READ_ERROR = ifcopenshell_wrapper.file_open_status.READ_ERROR +NO_HEADER = ifcopenshell_wrapper.file_open_status.NO_HEADER +UNSUPPORTED_SCHEMA = ifcopenshell_wrapper.file_open_status.UNSUPPORTED_SCHEMA + + +class Error(Exception): + pass + + +class SchemaError(Error): + pass + def open(fn): f = ifcopenshell_wrapper.open(os.path.abspath(fn)) if f.good(): return file(f) else: - raise IOError("Unable to open file for reading") + exc, msg = { + READ_ERROR: (IOError, "Unable to open file for reading"), + NO_HEADER: (Error, "Unable to parse IFC SPF header"), + UNSUPPORTED_SCHEMA: ( + SchemaError, + "Unsupported schema: %s" % ",".join(f.header.file_schema.schema_identifiers), + ), + }[f.good().value()] + raise exc(msg) -def create_entity(type, schema='IFC4', *args, **kwargs): +def create_entity(type, schema="IFC4", *args, **kwargs): e = entity_instance((schema, type)) attrs = list(enumerate(args)) + [(e.wrapped_data.get_argument_index(name), arg) for name, arg in kwargs.items()] for idx, arg in attrs: diff --git a/src/ifcparse/IfcFile.h b/src/ifcparse/IfcFile.h index f8b03de407..7b679ff7ba 100644 --- a/src/ifcparse/IfcFile.h +++ b/src/ifcparse/IfcFile.h @@ -33,6 +33,36 @@ namespace IfcParse { +class IFC_PARSE_API file_open_status { +public: + enum file_open_enum { + SUCCESS, + READ_ERROR, + NO_HEADER, + UNSUPPORTED_SCHEMA + }; + +private: + file_open_enum error_; + +public: + file_open_status(file_open_enum error) + : error_(error) + {} + + operator file_open_enum() const { + return error_; + } + + file_open_enum value() const { + return error_; + } + + operator bool() const { + return error_ == SUCCESS; + } +}; + /// This class provides several static convenience functions and variables /// and provide access to the entities in an IFC file class IFC_PARSE_API IfcFile { @@ -78,7 +108,8 @@ public: private: typedef std::map entity_entity_map_t; - bool parsing_complete_, good_; + bool parsing_complete_; + file_open_status good_ = file_open_status::SUCCESS; const IfcParse::schema_definition* schema_; const IfcParse::declaration* ifcroot_type_; @@ -116,7 +147,7 @@ public: virtual ~IfcFile(); - bool good() const { return good_; } + file_open_status good() const { return good_; } /// Returns the first entity in the file, this probably is the entity /// with the lowest id (EXPRESS ENTITY_INSTANCE_NAME) diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index 5d2093faee..96d1ed6edc 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -1326,7 +1326,6 @@ IfcFile::IfcFile(IfcParse::IfcSpfStream* s) { IfcFile::IfcFile(const IfcParse::schema_definition* schema) : parsing_complete_(true) - , good_(true) , schema_(schema) , ifcroot_type_(schema_->declaration_by_name("IfcRoot")) , MaxId(0) @@ -1341,8 +1340,6 @@ void IfcFile::initialize_(IfcParse::IfcSpfStream* s) { // number parsing. See comment above on line 41. init_locale(); - good_ = false; - parsing_complete_ = false; MaxId = 0; tokens = 0; @@ -1353,24 +1350,30 @@ void IfcFile::initialize_(IfcParse::IfcSpfStream* s) { stream = s; if (!stream->valid) { + good_ = file_open_status::READ_ERROR; return; } tokens = new IfcSpfLexer(stream, this); - _header.file(this); - _header.tryRead(); - + std::vector schemas; - try { - schemas = _header.file_schema().schema_identifiers(); - } catch (...) { - // Purposely empty catch block + + _header.file(this); + if (_header.tryRead()) { + try { + schemas = _header.file_schema().schema_identifiers(); + } catch (...) { + // Purposely empty catch block + } + } else { + good_ = file_open_status::NO_HEADER; } if (schemas.size() == 1) { try { schema_ = IfcParse::schema_by_name(schemas.front()); } catch (const IfcParse::IfcException& e) { + good_ = file_open_status::UNSUPPORTED_SCHEMA; Logger::Error(e); } } @@ -1381,8 +1384,6 @@ void IfcFile::initialize_(IfcParse::IfcSpfStream* s) { return; } - good_ = true; - ifcroot_type_ = schema_->declaration_by_name("IfcRoot"); boost::circular_buffer token_stream(3, Token());