diff --git a/src/RWStl/RWStl.cxx b/src/RWStl/RWStl.cxx index 9672109f5c..0d053347b1 100644 --- a/src/RWStl/RWStl.cxx +++ b/src/RWStl/RWStl.cxx @@ -80,6 +80,9 @@ namespace //! Creates Poly_Triangulation from collected data Handle(Poly_Triangulation) GetTriangulation() { + if (myTriangles.IsEmpty()) + return Handle(Poly_Triangulation)(); + Handle(Poly_Triangulation) aPoly = new Poly_Triangulation (myNodes.Length(), myTriangles.Length(), Standard_False); for (Standard_Integer aNodeIter = 0; aNodeIter < myNodes.Size(); ++aNodeIter) { @@ -109,10 +112,9 @@ Handle(Poly_Triangulation) RWStl::ReadFile (const Standard_CString theFile, const Handle(Message_ProgressIndicator)& theProgress) { Reader aReader; - if (!aReader.Read (theFile, theProgress)) - { - return Handle(Poly_Triangulation)(); - } + aReader.Read (theFile, theProgress); + // note that returned bool value is ignored intentionally -- even if something went wrong, + // but some data have been read, we at least will return these data return aReader.GetTriangulation(); } @@ -209,10 +211,15 @@ Handle(Poly_Triangulation) RWStl::ReadAscii (const OSD_Path& theFile, //function : Write //purpose : //============================================================================= -Standard_Boolean RWStl::WriteBinary (const Handle(Poly_Triangulation)& aMesh, +Standard_Boolean RWStl::WriteBinary (const Handle(Poly_Triangulation)& theMesh, const OSD_Path& thePath, const Handle(Message_ProgressIndicator)& theProgInd) { + if (theMesh.IsNull() || theMesh->NbTriangles() <= 0) + { + return Standard_False; + } + TCollection_AsciiString aPath; thePath.SystemName (aPath); @@ -222,7 +229,7 @@ Standard_Boolean RWStl::WriteBinary (const Handle(Poly_Triangulation)& aMesh, return Standard_False; } - Standard_Boolean isOK = writeBinary (aMesh, aFile, theProgInd); + Standard_Boolean isOK = writeBinary (theMesh, aFile, theProgInd); fclose (aFile); return isOK; @@ -236,6 +243,11 @@ Standard_Boolean RWStl::WriteAscii (const Handle(Poly_Triangulation)& theMesh, const OSD_Path& thePath, const Handle(Message_ProgressIndicator)& theProgInd) { + if (theMesh.IsNull() || theMesh->NbTriangles() <= 0) + { + return Standard_False; + } + TCollection_AsciiString aPath; thePath.SystemName (aPath); diff --git a/src/RWStl/RWStl_Reader.cxx b/src/RWStl/RWStl_Reader.cxx index ca2e28dcee..df2dfb92b5 100644 --- a/src/RWStl/RWStl_Reader.cxx +++ b/src/RWStl/RWStl_Reader.cxx @@ -138,9 +138,15 @@ Standard_Boolean RWStl_Reader::Read (const char* theFile, std::streampos theEnd = aStream.tellg(); aStream.seekg (0, aStream.beg); - while (!aStream.eof() && !aStream.bad()) + // binary STL files cannot be shorter than 134 bytes + // (80 bytes header + 4 bytes facet count + 50 bytes for one facet); + // thus assume files shorter than 134 as Ascii without probing + // (probing may bring stream to fail state if EOF is reached) + bool isAscii = ((size_t)theEnd < THE_STL_MIN_FILE_SIZE || IsAscii (aStream)); + + while (aStream.good()) { - if (IsAscii (aStream)) + if (isAscii) { if (!ReadAscii (aStream, theEnd, theProgress)) { @@ -156,7 +162,7 @@ Standard_Boolean RWStl_Reader::Read (const char* theFile, } aStream >> std::ws; // skip any white spaces } - return !aStream.bad(); + return ! aStream.fail(); } //============================================================================== @@ -169,10 +175,10 @@ Standard_Boolean RWStl_Reader::IsAscii (Standard_IStream& theStream) // read first 134 bytes to detect file format char aBuffer[THE_STL_MIN_FILE_SIZE]; std::streamsize aNbRead = theStream.read (aBuffer, THE_STL_MIN_FILE_SIZE).gcount(); - if (!theStream) + if (! theStream) { Message::DefaultMessenger()->Send ("Error: Cannot read file", Message_Fail); - return false; + return true; } // put back the read symbols @@ -240,7 +246,8 @@ Standard_Boolean RWStl_Reader::ReadAscii (Standard_IStream& theStream, // use method seekpos() to get true 64-bit offset to enable // handling of large files (VS 2010 64-bit) const int64_t aStartPos = GETPOS(theStream.tellg()); - const int64_t aEndPos = (theUntilPos > 0 ? GETPOS(theUntilPos) : std::numeric_limits::max()); + // Note: 1 is added to theUntilPos to be sure to read the last symbol (relevant for files without EOL at the end) + const int64_t aEndPos = (theUntilPos > 0 ? 1 + GETPOS(theUntilPos) : std::numeric_limits::max()); // skip header "solid ..." theStream.ignore (aEndPos - aStartPos, '\n'); diff --git a/src/StlAPI/StlAPI_Writer.cxx b/src/StlAPI/StlAPI_Writer.cxx index 5defbc452b..57ac659561 100644 --- a/src/StlAPI/StlAPI_Writer.cxx +++ b/src/StlAPI/StlAPI_Writer.cxx @@ -49,8 +49,11 @@ Standard_Boolean StlAPI_Writer::Write (const TopoDS_Shape& theShape, { TopLoc_Location aLoc; Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (TopoDS::Face (anExpSF.Current()), aLoc); - aNbNodes += aTriangulation->NbNodes(); - aNbTriangles += aTriangulation->NbTriangles(); + if (! aTriangulation.IsNull()) + { + aNbNodes += aTriangulation->NbNodes (); + aNbTriangles += aTriangulation->NbTriangles (); + } } // create temporary triangulation diff --git a/tests/de_mesh/stl_read/D1 b/tests/de_mesh/stl_read/D1 new file mode 100644 index 0000000000..2161e54e2b --- /dev/null +++ b/tests/de_mesh/stl_read/D1 @@ -0,0 +1,91 @@ +puts "\n#======================================================================" +puts "# Check reading empty or small STL files" +puts "#======================================================================\n" + +set minimal_ascii_stl {solid +facet normal 0 0 1 +outer loop +vertex 0 0 0 +vertex 1 0 0 +vertex 0 1 0 +endloop +endfacet +endsolid} + +puts "\n#======================================================================" +puts "# Ascii file with single facet, CRLF" +puts "#======================================================================" +set fd [open ${imagedir}/${casename}_one_ascii_dos.stl w] +fconfigure $fd -translation crlf +puts $fd $minimal_ascii_stl +close $fd +readstl res_one_ascii_dos ${imagedir}/${casename}_one_ascii_dos.stl +checknbshapes res_one_ascii_dos -face 1 + +puts "\n#======================================================================" +puts "# Ascii file with single facet, LF" +puts "#======================================================================" +set fd [open ${imagedir}/${casename}_one_ascii_unix.stl w] +fconfigure $fd -translation lf +puts $fd $minimal_ascii_stl +close $fd +readstl res_one_ascii_unix ${imagedir}/${casename}_one_ascii_unix.stl +checknbshapes res_one_ascii_unix -face 1 + +puts "\n#======================================================================" +puts "# Ascii file with single facet, LF, no EOL at the last line" +puts "#======================================================================" +set fd [open ${imagedir}/${casename}_one_ascii_noeol.stl w] +fconfigure $fd -translation lf +puts -nonewline $fd $minimal_ascii_stl +close $fd +readstl res_one_ascii_noeol ${imagedir}/${casename}_one_ascii_noeol.stl +checknbshapes res_one_ascii_noeol -face 1 + +puts "\n#======================================================================" +puts "# Ascii file with no facets, CRLF" +puts "#======================================================================" +set fd [open ${imagedir}/${casename}_zero_ascii_dos.stl w] +fconfigure $fd -translation crlf +puts $fd "solid \nendsolid" +close $fd +readstl res_zero_ascii_dos ${imagedir}/${casename}_zero_ascii_dos.stl + +puts "\n#======================================================================" +puts "# Ascii file with no facets, LF" +puts "#======================================================================" +set fd [open ${imagedir}/${casename}_zero_ascii_unix.stl w] +fconfigure $fd -translation lf +puts $fd "solid \nendsolid" +close $fd +readstl res_zero_ascii_unix ${imagedir}/${casename}_zero_ascii_unix.stl + +puts "\n#======================================================================" +puts "# Binary file with single facet" +puts "#======================================================================" +set fd [open ${imagedir}/${casename}_one_binary.stl w] +fconfigure $fd -translation binary +puts -nonewline $fd "stl [string repeat { } 76]" +puts -nonewline $fd [binary format if3f3f3f3t 1 {0 0 1} {0 0 0} {1 0 0} {0 1 0} 0] +close $fd +readstl res_one_binary ${imagedir}/${casename}_one_binary.stl +checknbshapes res_one_binary -face 1 + +puts "\n#======================================================================" +puts "# Binary file with no facets -- will be treated as Ascii and generate e r r o r" +puts "#======================================================================" +puts "REQUIRED ALL: Error: unexpected format of facet at line 2" +set fd [open ${imagedir}/${casename}_zero_binary.stl w] +fconfigure $fd -translation binary +puts -nonewline $fd "stl [string repeat { } 76][binary format i 0]" +close $fd +readstl res_zero_binary ${imagedir}/${casename}_zero_binary.stl + +puts "\n#======================================================================" +puts "# Empty file" +puts "#======================================================================" +puts "REQUIRED ALL: Error: unexpected format of facet at line 2" +set fd [open ${imagedir}/${casename}_empty.stl w] +close $fd +readstl res_empty ${imagedir}/${casename}_empty.stl + diff --git a/tests/de_mesh/stl_read/end b/tests/de_mesh/stl_read/end deleted file mode 100644 index e69de29bb2..0000000000