소스 검색

Improve STL representation detection

Previously, the STL loader relied on a string check at the start of the
buffer to determine if the STL file was of ASCII representation.  This led to
certain false-positives for binary STL files with the magic string present in
their header.  This patch addresses the issue by adding a proper binary check
to the representation detection.
Jared Duke 12 년 전
부모
커밋
7db5dcb357
1개의 변경된 파일34개의 추가작업 그리고 4개의 파일을 삭제
  1. 34 4
      code/STLLoader.cpp

+ 34 - 4
code/STLLoader.cpp

@@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 using namespace Assimp;
 
+namespace {
 static const aiImporterDesc desc = {
 	"Stereolithography (STL) Importer",
 	"",
@@ -64,6 +65,34 @@ static const aiImporterDesc desc = {
 	"stl" 
 };
 
+// A valid binary STL buffer should consist of the following elements, in order:
+// 1) 80 byte header
+// 2) 4 byte face count
+// 3) 50 bytes per face
+bool IsBinarySTL(const char* buffer, unsigned int fileSize) {
+	if (fileSize < 84)
+		return false;
+
+	const uint32_t faceCount = *reinterpret_cast<const uint32_t*>(buffer + 80);
+	const uint32_t expectedBinaryFileSize = faceCount * 50 + 84;
+
+	return expectedBinaryFileSize == fileSize;
+}
+
+// An ascii STL buffer will begin with "solid NAME", where NAME is optional.
+// Note: The "solid NAME" check is necessary, but not sufficient, to determine
+// if the buffer is ASCII; a binary header could also begin with "solid NAME".
+bool IsAsciiSTL(const char* buffer, unsigned int fileSize) {
+	if (IsBinarySTL(buffer, fileSize))
+		return false;
+
+	if (fileSize < 5)
+		return false;
+
+	return strncmp(buffer, "solid", 5) == 0;
+}
+} // namespace
+
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 STLImporter::STLImporter()
@@ -136,12 +165,13 @@ void STLImporter::InternReadFile( const std::string& pFile,
 
 	bool bMatClr = false;
 
-	// check whether the file starts with 'solid' -
-	// in this case we can simply assume it IS a text file. finished.
-	if (!::strncmp(mBuffer,"solid",5)) {
+	if (IsBinarySTL(mBuffer, fileSize)) {
+		bMatClr = LoadBinaryFile();
+	} else if (IsAsciiSTL(mBuffer, fileSize)) {
 		LoadASCIIFile();
+	} else {
+		throw DeadlyImportError( "Failed to determine STL storage representation for " + pFile + ".");
 	}
-	else bMatClr = LoadBinaryFile();
 
 	// now copy faces
 	pMesh->mFaces = new aiFace[pMesh->mNumFaces];