Commit c68c630e authored by Jan Möbius's avatar Jan Möbius

Prevent endless loop in PLY reader when unknown property types are read.

parent aa98be12
Pipeline #7218 passed with stage
in 66 minutes and 1 second
...@@ -1201,185 +1201,187 @@ bool _PLYReader_::can_u_read(std::istream& _is) const { ...@@ -1201,185 +1201,187 @@ bool _PLYReader_::can_u_read(std::istream& _is) const {
_is >> keyword; _is >> keyword;
while (keyword != "end_header") { while (keyword != "end_header") {
if (keyword == "comment") { if (keyword == "comment") {
std::getline(_is, line); std::getline(_is, line);
} else if (keyword == "element") { } else if (keyword == "element") {
_is >> elementName; _is >> elementName;
_is >> elementCount; _is >> elementCount;
ElementInfo element; ElementInfo element;
element.name_ = elementName; element.name_ = elementName;
element.count_ = elementCount; element.count_ = elementCount;
if (elementName == "vertex") { if (elementName == "vertex") {
vertexCount_ = elementCount; vertexCount_ = elementCount;
element.element_ = VERTEX; element.element_ = VERTEX;
} else if (elementName == "face") { } else if (elementName == "face") {
faceCount_ = elementCount; faceCount_ = elementCount;
element.element_ = FACE; element.element_ = FACE;
} else { } else {
omerr() << "PLY header unsupported element type: " << elementName << std::endl; omerr() << "PLY header unsupported element type: " << elementName << std::endl;
element.element_ = UNKNOWN; element.element_ = UNKNOWN;
} }
elements_.push_back(element);
} else if (keyword == "property") {
std::string tmp1;
std::string tmp2;
// Read first keyword, as it might be a list
_is >> tmp1;
if (tmp1 == "list") {
_is >> listIndexType;
_is >> listEntryType;
_is >> propertyName;
ValueType indexType = Unsupported;
ValueType entryType = Unsupported;
if (listIndexType == "uint8") {
indexType = ValueTypeUINT8;
} else if (listIndexType == "uchar") {
indexType = ValueTypeUCHAR;
} else if (listIndexType == "int") {
indexType = ValueTypeINT;
} else {
omerr() << "Unsupported Index type for property list: " << listIndexType << std::endl;
continue;
}
entryType = get_property_type(listEntryType, listEntryType);
if (entryType == Unsupported) {
omerr() << "Unsupported Entry type for property list: " << listEntryType << std::endl;
}
PropertyInfo property(CUSTOM_PROP, entryType, propertyName); elements_.push_back(element);
property.listIndexType = indexType; } else if (keyword == "property") {
std::string tmp1;
if (elementName == "face") std::string tmp2;
{
// special case for vertex indices // Read first keyword, as it might be a list
if (propertyName == "vertex_index" || propertyName == "vertex_indices") _is >> tmp1;
{
property.property = VERTEX_INDICES; if (tmp1 == "list") {
_is >> listIndexType;
if (!elements_.back().properties_.empty()) _is >> listEntryType;
{ _is >> propertyName;
omerr() << "Custom face Properties defined, before 'vertex_indices' property was defined. They will be skipped" << std::endl;
elements_.back().properties_.clear(); ValueType indexType = Unsupported;
} ValueType entryType = Unsupported;
} else {
options_ += Options::Custom; if (listIndexType == "uint8") {
} indexType = ValueTypeUINT8;
} else if (listIndexType == "uint16") {
indexType = ValueTypeUINT16;
} else if (listIndexType == "uchar") {
indexType = ValueTypeUCHAR;
} else if (listIndexType == "int") {
indexType = ValueTypeINT;
} else {
omerr() << "Unsupported Index type for property list: " << listIndexType << std::endl;
return false;
}
} entryType = get_property_type(listEntryType, listEntryType);
else
omerr() << "property " << propertyName << " belongs to unsupported element " << elementName << std::endl;
elements_.back().properties_.push_back(property); if (entryType == Unsupported) {
omerr() << "Unsupported Entry type for property list: " << listEntryType << std::endl;
}
} else { PropertyInfo property(CUSTOM_PROP, entryType, propertyName);
// as this is not a list property, read second value of property property.listIndexType = indexType;
_is >> tmp2;
// Extract name and type of property
// As the order seems to be different in some files, autodetect it.
ValueType valueType = get_property_type(tmp1, tmp2);
propertyName = get_property_name(tmp1, tmp2);
PropertyInfo entry;
//special treatment for some vertex properties.
if (elementName == "vertex") {
if (propertyName == "x") {
entry = PropertyInfo(XCOORD, valueType);
vertexDimension_++;
} else if (propertyName == "y") {
entry = PropertyInfo(YCOORD, valueType);
vertexDimension_++;
} else if (propertyName == "z") {
entry = PropertyInfo(ZCOORD, valueType);
vertexDimension_++;
} else if (propertyName == "nx") {
entry = PropertyInfo(XNORM, valueType);
options_ += Options::VertexNormal;
} else if (propertyName == "ny") {
entry = PropertyInfo(YNORM, valueType);
options_ += Options::VertexNormal;
} else if (propertyName == "nz") {
entry = PropertyInfo(ZNORM, valueType);
options_ += Options::VertexNormal;
} else if (propertyName == "u" || propertyName == "s") {
entry = PropertyInfo(TEXX, valueType);
options_ += Options::VertexTexCoord;
} else if (propertyName == "v" || propertyName == "t") {
entry = PropertyInfo(TEXY, valueType);
options_ += Options::VertexTexCoord;
} else if (propertyName == "red") {
entry = PropertyInfo(COLORRED, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "green") {
entry = PropertyInfo(COLORGREEN, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "blue") {
entry = PropertyInfo(COLORBLUE, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "diffuse_red") {
entry = PropertyInfo(COLORRED, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "diffuse_green") {
entry = PropertyInfo(COLORGREEN, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "diffuse_blue") {
entry = PropertyInfo(COLORBLUE, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "alpha") {
entry = PropertyInfo(COLORALPHA, valueType);
options_ += Options::VertexColor;
options_ += Options::ColorAlpha;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
}
}
//not a special property, load as custom if (elementName == "face")
if (entry.value == Unsupported){ {
Property prop = CUSTOM_PROP; // special case for vertex indices
options_ += Options::Custom; if (propertyName == "vertex_index" || propertyName == "vertex_indices")
entry = PropertyInfo(prop, valueType, propertyName); {
} property.property = VERTEX_INDICES;
if (entry.property != UNSUPPORTED) if (!elements_.back().properties_.empty())
{ {
elements_.back().properties_.push_back(entry); omerr() << "Custom face Properties defined, before 'vertex_indices' property was defined. They will be skipped" << std::endl;
elements_.back().properties_.clear();
} }
} else {
options_ += Options::Custom;
} }
}
else
omerr() << "property " << propertyName << " belongs to unsupported element " << elementName << std::endl;
elements_.back().properties_.push_back(property);
} else { } else {
omlog() << "Unsupported keyword : " << keyword << std::endl; // as this is not a list property, read second value of property
_is >> tmp2;
// Extract name and type of property
// As the order seems to be different in some files, autodetect it.
ValueType valueType = get_property_type(tmp1, tmp2);
propertyName = get_property_name(tmp1, tmp2);
PropertyInfo entry;
//special treatment for some vertex properties.
if (elementName == "vertex") {
if (propertyName == "x") {
entry = PropertyInfo(XCOORD, valueType);
vertexDimension_++;
} else if (propertyName == "y") {
entry = PropertyInfo(YCOORD, valueType);
vertexDimension_++;
} else if (propertyName == "z") {
entry = PropertyInfo(ZCOORD, valueType);
vertexDimension_++;
} else if (propertyName == "nx") {
entry = PropertyInfo(XNORM, valueType);
options_ += Options::VertexNormal;
} else if (propertyName == "ny") {
entry = PropertyInfo(YNORM, valueType);
options_ += Options::VertexNormal;
} else if (propertyName == "nz") {
entry = PropertyInfo(ZNORM, valueType);
options_ += Options::VertexNormal;
} else if (propertyName == "u" || propertyName == "s") {
entry = PropertyInfo(TEXX, valueType);
options_ += Options::VertexTexCoord;
} else if (propertyName == "v" || propertyName == "t") {
entry = PropertyInfo(TEXY, valueType);
options_ += Options::VertexTexCoord;
} else if (propertyName == "red") {
entry = PropertyInfo(COLORRED, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "green") {
entry = PropertyInfo(COLORGREEN, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "blue") {
entry = PropertyInfo(COLORBLUE, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "diffuse_red") {
entry = PropertyInfo(COLORRED, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "diffuse_green") {
entry = PropertyInfo(COLORGREEN, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "diffuse_blue") {
entry = PropertyInfo(COLORBLUE, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "alpha") {
entry = PropertyInfo(COLORALPHA, valueType);
options_ += Options::VertexColor;
options_ += Options::ColorAlpha;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
}
}
//not a special property, load as custom
if (entry.value == Unsupported){
Property prop = CUSTOM_PROP;
options_ += Options::Custom;
entry = PropertyInfo(prop, valueType, propertyName);
}
if (entry.property != UNSUPPORTED)
{
elements_.back().properties_.push_back(entry);
}
} }
streamPos = _is.tellg(); } else {
_is >> keyword; omlog() << "Unsupported keyword : " << keyword << std::endl;
if (_is.bad()) { }
omerr() << "Error while reading PLY file header" << std::endl;
return false; streamPos = _is.tellg();
} _is >> keyword;
if (_is.bad()) {
omerr() << "Error while reading PLY file header" << std::endl;
return false;
}
} }
// As the binary data is directy after the end_header keyword // As the binary data is directy after the end_header keyword
......
...@@ -728,4 +728,58 @@ TEST_F(OpenMeshReadWritePLY, LoadSimpleBinaryPLYWithExtraElements) { ...@@ -728,4 +728,58 @@ TEST_F(OpenMeshReadWritePLY, LoadSimpleBinaryPLYWithExtraElements) {
EXPECT_EQ(12u, mesh_.n_faces()) << "The number of loaded faces is not correct!"; EXPECT_EQ(12u, mesh_.n_faces()) << "The number of loaded faces is not correct!";
} }
/*
* Ignore a file that does not contain vertices and faces
*/
TEST_F(OpenMeshReadWritePLY, IgnoreNonMeshPlyFile) {
mesh_.clear();
std::stringstream data;
data << "ply" << "\n";
data << "format binary_little_endian 1.0" << "\n";
data << "comment Image data" << "\n";
data << "element image 0" << "\n";
data << "property list uint16 uint16 row" << "\n";
data << "end_header" << "\n";
OpenMesh::IO::Options options = OpenMesh::IO::Options::Binary;
bool ok = OpenMesh::IO::read_mesh(mesh_, data, ".ply", options);
EXPECT_TRUE(ok) << "This empty file should be readable without an error!";
EXPECT_EQ(0u, mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(0u, mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(0u, mesh_.n_faces()) << "The number of loaded faces is not correct!";
}
/*
* Ignore a file that does not contain vertices and faces
*/
TEST_F(OpenMeshReadWritePLY, FailOnUnknownPropertyTypeForLists) {
mesh_.clear();
std::stringstream data;
data << "ply" << "\n";
data << "format binary_little_endian 1.0" << "\n";
data << "comment Image data" << "\n";
data << "element image 0" << "\n";
data << "property list blibb blubb row" << "\n";
data << "end_header" << "\n";
OpenMesh::IO::Options options = OpenMesh::IO::Options::Binary;
bool ok = OpenMesh::IO::read_mesh(mesh_, data, ".ply", options);
EXPECT_FALSE(ok) << "This file should fail to read!";
EXPECT_EQ(0u, mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(0u, mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(0u, mesh_.n_faces()) << "The number of loaded faces is not correct!";
}
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment