Avoid a divide-by-zero on malformed BTG files.

Encountered while testing v850 airports; some airports
generate materials with no tris, and hence no indices.
This causes a divide-by-zero when computing the index stride.

Detect this, and convert the BTG reader to throw exceptions
in error conditions, and to catch this and report the
appropriate result code.
This commit is contained in:
James Turner
2013-10-17 20:13:36 +01:00
parent 9c4face1ae
commit 8b0c246a7b
2 changed files with 33 additions and 24 deletions

View File

@@ -43,6 +43,7 @@
#include <simgear/bucket/newbucket.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/math/SGGeometry.hxx>
#include <simgear/structure/exception.hxx>
#include "lowlevel.hxx"
#include "sg_binobj.hxx"
@@ -319,15 +320,18 @@ void SGBinObject::read_object( gzFile fp,
}
if ( sgReadError() ) {
cout << "We detected an error reading object properties" << endl;
return;
throw sg_exception("Error reading object properties");
}
size_t indexCount = std::bitset<32>(idx_mask).count();
if (indexCount == 0) {
throw sg_exception("object index mask has no bits set");
}
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
if ( sgReadError() ) {
cout << "We detected an error reading element size for :" << j << endl;
return;
throw sg_exception("Error reading element size");
}
buf.resize( nbytes );
@@ -335,8 +339,7 @@ void SGBinObject::read_object( gzFile fp,
sgReadBytes( fp, nbytes, ptr );
if ( sgReadError() ) {
cout << "We detected an error reading object element:" << j << "bytes="<< nbytes << endl;
return;
throw sg_exception("Error reading element bytes");
}
int_list vs;
@@ -405,7 +408,7 @@ bool SGBinObject::read_bin( const string& file ) {
SG_LOG( SG_EVENT, SG_ALERT,
"ERROR: opening " << file << " or " << filegz << " for reading!");
return false;
throw sg_io_exception("Error opening for reading (and .gz)", sg_location(file));
}
}
@@ -423,9 +426,7 @@ bool SGBinObject::read_bin( const string& file ) {
} else {
// close the file before we return
gzclose(fp);
SG_LOG( SG_EVENT, SG_ALERT,
"ERROR: " << file << "has bad header");
return false;
throw sg_io_exception("Bad BTG magic/version", sg_location(file));
}
// read creation time
@@ -462,8 +463,7 @@ bool SGBinObject::read_bin( const string& file ) {
//cout << "Total objects to read = " << nobjects << endl;
if ( sgReadError() ) {
cout << "Error while reading header of file " << file << "(.gz)" << endl;
return false;
throw sg_io_exception("Error reading BTG file header", sg_location(file));
}
// read in objects
@@ -613,19 +613,13 @@ bool SGBinObject::read_bin( const string& file ) {
}
if ( sgReadError() ) {
cout << "Error while reading object:" << i << " in file " << file << "(.gz)" << endl;
return false;
throw sg_io_exception("Error while reading object", sg_location(file, i));
}
}
// close the file
gzclose(fp);
if ( sgReadError() ) {
cout << "Error while reading file " << file << "(.gz)" << endl;
return false;
}
return true;
}
@@ -665,7 +659,7 @@ void SGBinObject::write_objects(gzFile fp, int type, const group_list& verts,
if (verts.empty()) {
return;
}
unsigned int start = 0, end = 1;
string m;
int_list emptyList;
@@ -688,6 +682,13 @@ void SGBinObject::write_objects(gzFile fp, int type, const group_list& verts,
if ( !normals.empty() && !normals.front().empty()) idx_mask |= SG_IDX_NORMALS;
if ( !colors.empty() && !colors.front().empty()) idx_mask |= SG_IDX_COLORS;
if ( !texCoords.empty() && !texCoords.front().empty()) idx_mask |= SG_IDX_TEXCOORDS;
if (idx_mask == 0) {
SG_LOG(SG_IO, SG_ALERT, "SGBinObject::write_objects: object with material:"
<< m << "has no indices set");
}
sgWriteChar( fp, (char)SG_INDEX_TYPES ); // property
sgWriteUInt( fp, 1 ); // nbytes
sgWriteChar( fp, idx_mask );

View File

@@ -24,6 +24,7 @@
#include <simgear/scene/model/ModelRegistry.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/structure/exception.hxx>
#include "SGReaderWriterBTG.hxx"
#include "obj.hxx"
@@ -60,10 +61,17 @@ SGReaderWriterBTG::readNode(const std::string& fileName,
{
const SGReaderWriterOptions* sgOptions;
sgOptions = dynamic_cast<const SGReaderWriterOptions*>(options);
osg::Node* result = SGLoadBTG(fileName, sgOptions);
if (!result)
return ReadResult::FILE_NOT_HANDLED;
osg::Node* result = NULL;
try {
result = SGLoadBTG(fileName, sgOptions);
if (!result)
return ReadResult::FILE_NOT_HANDLED;
} catch (sg_exception& e) {
SG_LOG(SG_IO, SG_WARN, "error reading:" << fileName << ":" <<
e.getFormattedMessage());
return ReadResult::ERROR_IN_READING_FILE;
}
return result;
}