more defensive XML parsing

This commit is contained in:
Thomas Krijnen
2020-05-05 13:08:09 +02:00
parent c9c2f76960
commit 9c5c05202f
+41 -13
View File
@@ -234,7 +234,11 @@ static void end_element(void* user, const xmlChar* tag) {
// ignore uos ex:iso_10303_28 (ifc2x3) and ifc:ifcXML (ifc4) // ignore uos ex:iso_10303_28 (ifc2x3) and ifc:ifcXML (ifc4)
if (tagname != "uos" && tagname != "ex:iso_10303_28" && tagname != "ifc:ifcXML" && tagname != "ifcXML") { if (tagname != "uos" && tagname != "ex:iso_10303_28" && tagname != "ifc:ifcXML" && tagname != "ifcXML") {
state->stack.pop_back(); if (state->stack.empty()) {
Logger::Error("Mismatch in parse stack due to previous errors");
} else {
state->stack.pop_back();
}
} }
} }
@@ -254,7 +258,12 @@ static void process_characters(void* user, const xmlChar* ch, int len) {
if (!state->stack.empty() && state->stack.back().inst() != nullptr && state->stack.back().inst()->declaration().as_type_declaration()) { if (!state->stack.empty() && state->stack.back().inst() != nullptr && state->stack.back().inst()->declaration().as_type_declaration()) {
auto pt = state->stack.back().inst()->declaration().as_type_declaration()->declared_type(); auto pt = state->stack.back().inst()->declaration().as_type_declaration()->declared_type();
auto val = parse_attribute_value(pt, txt); Argument* val = nullptr;
try {
parse_attribute_value(pt, txt);
} catch (const std::exception& e) {
Logger::Error(e, state->stack.back().inst());
}
if (val) { if (val) {
// type declaration always at idx 0 // type declaration always at idx 0
state->stack.back().inst()->data().setArgument(0, val); state->stack.back().inst()->data().setArgument(0, val);
@@ -327,7 +336,13 @@ static void start_element(void* user, const xmlChar* tag, const xmlChar** attrs)
#endif #endif
attributes.push_back(std::make_pair(attrname, value)); attributes.push_back(std::make_pair(attrname, value));
if ((tagname == "ifc:ifcXML" || tagname == "ifcXML") && attrname == "xsi:schemaLocation" && boost::starts_with(value, "http://www.buildingsmart-tech.org/ifcXML/IFC4")) { if ((tagname == "ifc:ifcXML" || tagname == "ifcXML") && attrname == "xsi:schemaLocation" &&
(
boost::starts_with(value, "http://www.buildingsmart-tech.org/ifcXML/IFC4") ||
boost::starts_with(value, "http://www.buildingsmart-tech.org/ifc/IFC4")
)
)
{
// We're expecting a schemaLocation like "http://www.buildingsmart-tech.org/ifcXML/IFC4/Add2 IFC4_ADD2_TC1.xsd" // We're expecting a schemaLocation like "http://www.buildingsmart-tech.org/ifcXML/IFC4/Add2 IFC4_ADD2_TC1.xsd"
// With token compression this is split into: // With token compression this is split into:
// [0] http: // [0] http:
@@ -341,7 +356,8 @@ static void start_element(void* user, const xmlChar* tag, const xmlChar** attrs)
decltype(it) end; decltype(it) end;
for (int tok = 0; it != end && tok < 3; ++it, ++tok) {} for (int tok = 0; it != end && tok < 3; ++it, ++tok) {}
if (it != end) { if (it != end) {
const std::string schema_name(&it->front(), it->size()); std::string schema_name(&it->front(), it->size());
boost::to_upper(schema_name);
state->file = new IfcParse::IfcFile(IfcParse::schema_by_name(schema_name)); state->file = new IfcParse::IfcFile(IfcParse::schema_by_name(schema_name));
state->file->parsing_complete() = false; state->file->parsing_complete() = false;
state->dialect = ifcxml_dialect_ifc4; state->dialect = ifcxml_dialect_ifc4;
@@ -480,13 +496,20 @@ static void start_element(void* user, const xmlChar* tag, const xmlChar** attrs)
if (element_type->as_simple_type()) { if (element_type->as_simple_type()) {
state->stack.push_back(stack_node::aggregate_element(element_type, aggrpos)); state->stack.push_back(stack_node::aggregate_element(element_type, aggrpos));
} else { } else {
const IfcParse::declaration* decl = state->file->schema()->declaration_by_name(tagname_copy); const IfcParse::declaration* decl = nullptr;
auto inst_or_ref = create_instance(decl); try {
IfcUtil::IfcBaseClass* inst; decl = state->file->schema()->declaration_by_name(tagname_copy);
Argument* attr; } catch (const std::exception& e) {
instance_to_attribute(inst_or_ref, attr, inst); Logger::Error(e);
state->stack.back().aggregate_elements.push_back(attr); }
state->stack.push_back(stack_node::instance(id_in_file, inst)); if (decl) {
auto inst_or_ref = create_instance(decl);
IfcUtil::IfcBaseClass* inst;
Argument* attr;
instance_to_attribute(inst_or_ref, attr, inst);
state->stack.back().aggregate_elements.push_back(attr);
state->stack.push_back(stack_node::instance(id_in_file, inst));
}
} }
} else if (state_type == stack_node::node_instance) { } else if (state_type == stack_node::node_instance) {
const IfcParse::entity* current = state->stack.back().inst()->declaration().as_entity(); 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)
} else if (tagname == "uos") { } else if (tagname == "uos") {
// intentially empty, ignored in end_element() as well // intentially empty, ignored in end_element() as well
} else { } else {
const IfcParse::declaration* decl = state->file->schema()->declaration_by_name(tagname); const IfcParse::declaration* decl = nullptr;
try {
decl = state->file->schema()->declaration_by_name(tagname);
} catch (const std::exception& e) {
Logger::Error(e);
}
if (!decl) { if (!decl) {
Logger::Error("Not found in schema " + tagname);
goto end; goto end;
} }