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:50 +01:00
parent 9c4face1ae
commit 8b0c246a7b
2 changed files with 33 additions and 24 deletions
+21 -20
View File
@@ -43,6 +43,7 @@
#include <simgear/bucket/newbucket.hxx> #include <simgear/bucket/newbucket.hxx>
#include <simgear/misc/sg_path.hxx> #include <simgear/misc/sg_path.hxx>
#include <simgear/math/SGGeometry.hxx> #include <simgear/math/SGGeometry.hxx>
#include <simgear/structure/exception.hxx>
#include "lowlevel.hxx" #include "lowlevel.hxx"
#include "sg_binobj.hxx" #include "sg_binobj.hxx"
@@ -319,15 +320,18 @@ void SGBinObject::read_object( gzFile fp,
} }
if ( sgReadError() ) { if ( sgReadError() ) {
cout << "We detected an error reading object properties" << endl; throw sg_exception("Error reading object properties");
return; }
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 ) { for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes ); sgReadUInt( fp, &nbytes );
if ( sgReadError() ) { if ( sgReadError() ) {
cout << "We detected an error reading element size for :" << j << endl; throw sg_exception("Error reading element size");
return;
} }
buf.resize( nbytes ); buf.resize( nbytes );
@@ -335,8 +339,7 @@ void SGBinObject::read_object( gzFile fp,
sgReadBytes( fp, nbytes, ptr ); sgReadBytes( fp, nbytes, ptr );
if ( sgReadError() ) { if ( sgReadError() ) {
cout << "We detected an error reading object element:" << j << "bytes="<< nbytes << endl; throw sg_exception("Error reading element bytes");
return;
} }
int_list vs; int_list vs;
@@ -405,7 +408,7 @@ bool SGBinObject::read_bin( const string& file ) {
SG_LOG( SG_EVENT, SG_ALERT, SG_LOG( SG_EVENT, SG_ALERT,
"ERROR: opening " << file << " or " << filegz << " for reading!"); "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 { } else {
// close the file before we return // close the file before we return
gzclose(fp); gzclose(fp);
SG_LOG( SG_EVENT, SG_ALERT, throw sg_io_exception("Bad BTG magic/version", sg_location(file));
"ERROR: " << file << "has bad header");
return false;
} }
// read creation time // read creation time
@@ -462,8 +463,7 @@ bool SGBinObject::read_bin( const string& file ) {
//cout << "Total objects to read = " << nobjects << endl; //cout << "Total objects to read = " << nobjects << endl;
if ( sgReadError() ) { if ( sgReadError() ) {
cout << "Error while reading header of file " << file << "(.gz)" << endl; throw sg_io_exception("Error reading BTG file header", sg_location(file));
return false;
} }
// read in objects // read in objects
@@ -613,19 +613,13 @@ bool SGBinObject::read_bin( const string& file ) {
} }
if ( sgReadError() ) { if ( sgReadError() ) {
cout << "Error while reading object:" << i << " in file " << file << "(.gz)" << endl; throw sg_io_exception("Error while reading object", sg_location(file, i));
return false;
} }
} }
// close the file // close the file
gzclose(fp); gzclose(fp);
if ( sgReadError() ) {
cout << "Error while reading file " << file << "(.gz)" << endl;
return false;
}
return true; return true;
} }
@@ -665,7 +659,7 @@ void SGBinObject::write_objects(gzFile fp, int type, const group_list& verts,
if (verts.empty()) { if (verts.empty()) {
return; return;
} }
unsigned int start = 0, end = 1; unsigned int start = 0, end = 1;
string m; string m;
int_list emptyList; 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 ( !normals.empty() && !normals.front().empty()) idx_mask |= SG_IDX_NORMALS;
if ( !colors.empty() && !colors.front().empty()) idx_mask |= SG_IDX_COLORS; if ( !colors.empty() && !colors.front().empty()) idx_mask |= SG_IDX_COLORS;
if ( !texCoords.empty() && !texCoords.front().empty()) idx_mask |= SG_IDX_TEXCOORDS; 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 sgWriteChar( fp, (char)SG_INDEX_TYPES ); // property
sgWriteUInt( fp, 1 ); // nbytes sgWriteUInt( fp, 1 ); // nbytes
sgWriteChar( fp, idx_mask ); sgWriteChar( fp, idx_mask );
+12 -4
View File
@@ -24,6 +24,7 @@
#include <simgear/scene/model/ModelRegistry.hxx> #include <simgear/scene/model/ModelRegistry.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx> #include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/structure/exception.hxx>
#include "SGReaderWriterBTG.hxx" #include "SGReaderWriterBTG.hxx"
#include "obj.hxx" #include "obj.hxx"
@@ -60,10 +61,17 @@ SGReaderWriterBTG::readNode(const std::string& fileName,
{ {
const SGReaderWriterOptions* sgOptions; const SGReaderWriterOptions* sgOptions;
sgOptions = dynamic_cast<const SGReaderWriterOptions*>(options); sgOptions = dynamic_cast<const SGReaderWriterOptions*>(options);
osg::Node* result = SGLoadBTG(fileName, sgOptions); osg::Node* result = NULL;
if (!result) try {
return ReadResult::FILE_NOT_HANDLED; 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; return result;
} }