Prevent endless loop in PLY reader when unknown property types are read.
This commit is contained in:
@@ -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);
|
elements_.push_back(element);
|
||||||
} else if (keyword == "property") {
|
} else if (keyword == "property") {
|
||||||
std::string tmp1;
|
std::string tmp1;
|
||||||
std::string tmp2;
|
std::string tmp2;
|
||||||
|
|
||||||
// Read first keyword, as it might be a list
|
// Read first keyword, as it might be a list
|
||||||
_is >> tmp1;
|
_is >> tmp1;
|
||||||
|
|
||||||
if (tmp1 == "list") {
|
if (tmp1 == "list") {
|
||||||
_is >> listIndexType;
|
_is >> listIndexType;
|
||||||
_is >> listEntryType;
|
_is >> listEntryType;
|
||||||
_is >> propertyName;
|
_is >> propertyName;
|
||||||
|
|
||||||
ValueType indexType = Unsupported;
|
ValueType indexType = Unsupported;
|
||||||
ValueType entryType = Unsupported;
|
ValueType entryType = Unsupported;
|
||||||
|
|
||||||
if (listIndexType == "uint8") {
|
if (listIndexType == "uint8") {
|
||||||
indexType = ValueTypeUINT8;
|
indexType = ValueTypeUINT8;
|
||||||
} else if (listIndexType == "uchar") {
|
} else if (listIndexType == "uint16") {
|
||||||
indexType = ValueTypeUCHAR;
|
indexType = ValueTypeUINT16;
|
||||||
} else if (listIndexType == "int") {
|
} else if (listIndexType == "uchar") {
|
||||||
indexType = ValueTypeINT;
|
indexType = ValueTypeUCHAR;
|
||||||
} else {
|
} else if (listIndexType == "int") {
|
||||||
omerr() << "Unsupported Index type for property list: " << listIndexType << std::endl;
|
indexType = ValueTypeINT;
|
||||||
continue;
|
} else {
|
||||||
}
|
omerr() << "Unsupported Index type for property list: " << listIndexType << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
entryType = get_property_type(listEntryType, listEntryType);
|
entryType = get_property_type(listEntryType, listEntryType);
|
||||||
|
|
||||||
if (entryType == Unsupported) {
|
if (entryType == Unsupported) {
|
||||||
omerr() << "Unsupported Entry type for property list: " << listEntryType << std::endl;
|
omerr() << "Unsupported Entry type for property list: " << listEntryType << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyInfo property(CUSTOM_PROP, entryType, propertyName);
|
PropertyInfo property(CUSTOM_PROP, entryType, propertyName);
|
||||||
property.listIndexType = indexType;
|
property.listIndexType = indexType;
|
||||||
|
|
||||||
if (elementName == "face")
|
if (elementName == "face")
|
||||||
{
|
{
|
||||||
// special case for vertex indices
|
// special case for vertex indices
|
||||||
if (propertyName == "vertex_index" || propertyName == "vertex_indices")
|
if (propertyName == "vertex_index" || propertyName == "vertex_indices")
|
||||||
{
|
{
|
||||||
property.property = VERTEX_INDICES;
|
property.property = VERTEX_INDICES;
|
||||||
|
|
||||||
if (!elements_.back().properties_.empty())
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
if (!elements_.back().properties_.empty())
|
||||||
else
|
|
||||||
omerr() << "property " << propertyName << " belongs to unsupported element " << elementName << std::endl;
|
|
||||||
|
|
||||||
elements_.back().properties_.push_back(property);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// 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);
|
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) {
|
|||||||
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!";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user