Skip to content

Commit 9c5c052

Browse files
committed
more defensive XML parsing
1 parent c9c2f76 commit 9c5c052

1 file changed

Lines changed: 41 additions & 13 deletions

File tree

src/ifcparse/parse_ifcxml.cpp

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,11 @@ static void end_element(void* user, const xmlChar* tag) {
234234

235235
// ignore uos ex:iso_10303_28 (ifc2x3) and ifc:ifcXML (ifc4)
236236
if (tagname != "uos" && tagname != "ex:iso_10303_28" && tagname != "ifc:ifcXML" && tagname != "ifcXML") {
237-
state->stack.pop_back();
237+
if (state->stack.empty()) {
238+
Logger::Error("Mismatch in parse stack due to previous errors");
239+
} else {
240+
state->stack.pop_back();
241+
}
238242
}
239243
}
240244

@@ -254,7 +258,12 @@ static void process_characters(void* user, const xmlChar* ch, int len) {
254258

255259
if (!state->stack.empty() && state->stack.back().inst() != nullptr && state->stack.back().inst()->declaration().as_type_declaration()) {
256260
auto pt = state->stack.back().inst()->declaration().as_type_declaration()->declared_type();
257-
auto val = parse_attribute_value(pt, txt);
261+
Argument* val = nullptr;
262+
try {
263+
parse_attribute_value(pt, txt);
264+
} catch (const std::exception& e) {
265+
Logger::Error(e, state->stack.back().inst());
266+
}
258267
if (val) {
259268
// type declaration always at idx 0
260269
state->stack.back().inst()->data().setArgument(0, val);
@@ -327,7 +336,13 @@ static void start_element(void* user, const xmlChar* tag, const xmlChar** attrs)
327336
#endif
328337
attributes.push_back(std::make_pair(attrname, value));
329338

330-
if ((tagname == "ifc:ifcXML" || tagname == "ifcXML") && attrname == "xsi:schemaLocation" && boost::starts_with(value, "http://www.buildingsmart-tech.org/ifcXML/IFC4")) {
339+
if ((tagname == "ifc:ifcXML" || tagname == "ifcXML") && attrname == "xsi:schemaLocation" &&
340+
(
341+
boost::starts_with(value, "http://www.buildingsmart-tech.org/ifcXML/IFC4") ||
342+
boost::starts_with(value, "http://www.buildingsmart-tech.org/ifc/IFC4")
343+
)
344+
)
345+
{
331346
// We're expecting a schemaLocation like "http://www.buildingsmart-tech.org/ifcXML/IFC4/Add2 IFC4_ADD2_TC1.xsd"
332347
// With token compression this is split into:
333348
// [0] http:
@@ -341,7 +356,8 @@ static void start_element(void* user, const xmlChar* tag, const xmlChar** attrs)
341356
decltype(it) end;
342357
for (int tok = 0; it != end && tok < 3; ++it, ++tok) {}
343358
if (it != end) {
344-
const std::string schema_name(&it->front(), it->size());
359+
std::string schema_name(&it->front(), it->size());
360+
boost::to_upper(schema_name);
345361
state->file = new IfcParse::IfcFile(IfcParse::schema_by_name(schema_name));
346362
state->file->parsing_complete() = false;
347363
state->dialect = ifcxml_dialect_ifc4;
@@ -480,13 +496,20 @@ static void start_element(void* user, const xmlChar* tag, const xmlChar** attrs)
480496
if (element_type->as_simple_type()) {
481497
state->stack.push_back(stack_node::aggregate_element(element_type, aggrpos));
482498
} else {
483-
const IfcParse::declaration* decl = state->file->schema()->declaration_by_name(tagname_copy);
484-
auto inst_or_ref = create_instance(decl);
485-
IfcUtil::IfcBaseClass* inst;
486-
Argument* attr;
487-
instance_to_attribute(inst_or_ref, attr, inst);
488-
state->stack.back().aggregate_elements.push_back(attr);
489-
state->stack.push_back(stack_node::instance(id_in_file, inst));
499+
const IfcParse::declaration* decl = nullptr;
500+
try {
501+
decl = state->file->schema()->declaration_by_name(tagname_copy);
502+
} catch (const std::exception& e) {
503+
Logger::Error(e);
504+
}
505+
if (decl) {
506+
auto inst_or_ref = create_instance(decl);
507+
IfcUtil::IfcBaseClass* inst;
508+
Argument* attr;
509+
instance_to_attribute(inst_or_ref, attr, inst);
510+
state->stack.back().aggregate_elements.push_back(attr);
511+
state->stack.push_back(stack_node::instance(id_in_file, inst));
512+
}
490513
}
491514
} else if (state_type == stack_node::node_instance) {
492515
const IfcParse::entity* current = state->stack.back().inst()->declaration().as_entity();
@@ -562,9 +585,14 @@ static void start_element(void* user, const xmlChar* tag, const xmlChar** attrs)
562585
} else if (tagname == "uos") {
563586
// intentially empty, ignored in end_element() as well
564587
} else {
565-
const IfcParse::declaration* decl = state->file->schema()->declaration_by_name(tagname);
588+
const IfcParse::declaration* decl = nullptr;
589+
try {
590+
decl = state->file->schema()->declaration_by_name(tagname);
591+
} catch (const std::exception& e) {
592+
Logger::Error(e);
593+
}
594+
566595
if (!decl) {
567-
Logger::Error("Not found in schema " + tagname);
568596
goto end;
569597
}
570598

0 commit comments

Comments
 (0)