Standard_ReadLineBuffer now supports a processing of the special multi-line case with \ at the end of the line.
Standard_RedLineBuffer was used to load Stl files
#include <OSD_Timer.hxx>
#include <Precision.hxx>
#include <Standard_CLocaleSentry.hxx>
+#include <Standard_ReadLineBuffer.hxx>
#include <algorithm>
#include <limits>
namespace
{
+ // The length of buffer to read (in bytes)
+ static const size_t THE_BUFFER_SIZE = 4 * 1024;
//! Simple wrapper.
struct RWObj_ReaderFile
{
FILE* File;
- NCollection_Array1<char> Line;
- Standard_Integer LineBuffLen;
- Standard_Integer MaxLineLen;
- int64_t Position;
int64_t FileLen;
//! Constructor opening the file.
- RWObj_ReaderFile (const TCollection_AsciiString& theFile,
- const Standard_Integer theMaxLineLen = 256)
+ RWObj_ReaderFile (const TCollection_AsciiString& theFile)
: File (OSD_OpenFile (theFile.ToCString(), "rb")),
- Line (0, theMaxLineLen - 1),
- LineBuffLen (theMaxLineLen),
- MaxLineLen (theMaxLineLen),
- Position (0),
FileLen (0)
{
if (this->File != NULL)
::fclose (File);
}
}
-
- //! Read line, also considers multi-line syntax (when last line symbol is slash).
- bool ReadLine()
- {
- int64_t aPosPrev = this->Position;
- char* aLine = &Line.ChangeFirst();
- for (; ::feof (this->File) == 0 && ::fgets (aLine, MaxLineLen - 1, this->File) != NULL; )
- {
- const int64_t aPosNew = ::ftell64 (this->File);
- if (aLine[0] == '#')
- {
- Position = aPosNew;
- return true;
- }
-
- const Standard_Integer aNbRead = Standard_Integer(aPosNew - aPosPrev);
- bool toReadMore = false;
- for (int aTailIter = aNbRead - 1; aTailIter >= 0; --aTailIter)
- {
- if (aLine[aTailIter] != '\n'
- && aLine[aTailIter] != '\r'
- && aLine[aTailIter] != '\0')
- {
- if (aLine[aTailIter] == '\\')
- {
- // multi-line syntax
- aLine[aTailIter] = ' ';
- const ptrdiff_t aFullLen = aLine + aTailIter + 1 - &this->Line.First();
- if (LineBuffLen < aFullLen + MaxLineLen)
- {
- LineBuffLen += MaxLineLen;
- this->Line.Resize (0, LineBuffLen - 1, true);
- }
- aLine = &this->Line.ChangeFirst() + aFullLen;
- toReadMore = true;
- break;
- }
- break;
- }
- }
-
- if (toReadMore)
- {
- aPosPrev = aPosNew;
- continue;
- }
-
- Position = aPosNew;
- return true;
- }
- return false;
- }
-
};
//! Return TRUE if given polygon has clockwise node order.
return Standard_False;
}
+ Standard_ReadLineBuffer aBuffer (THE_BUFFER_SIZE);
+ aBuffer.SetMultilineMode (true);
+
const Standard_Integer aNbMiBTotal = Standard_Integer(aFileLen / (1024 * 1024));
Standard_Integer aNbMiBPassed = 0;
Message_ProgressSentry aPSentry (theProgress, "Reading text OBJ file", 0, aNbMiBTotal, 1);
aTimer.Start();
bool isStart = true;
- for (; aFile.ReadLine(); )
+ int64_t aPosition = 0;
+ size_t aLineLen = 0;
+ int64_t aReadBytes = 0;
+ const char* aLine = NULL;
+ for (;;)
{
+ aLine = aBuffer.ReadLine (aFile.File, aLineLen, aReadBytes);
+ if (aLine == NULL)
+ {
+ break;
+ }
++myNbLines;
- const char* aLine = &aFile.Line.First();
+ aPosition += aReadBytes;
if (aTimer.ElapsedTime() > 1.0)
{
if (!aPSentry.More())
return false;
}
- const Standard_Integer aNbMiBRead = Standard_Integer(aFile.Position / (1024 * 1024));
+ const Standard_Integer aNbMiBRead = Standard_Integer(aPosition / (1024 * 1024));
for (; aNbMiBPassed < aNbMiBRead; ++aNbMiBPassed) { aPSentry.Next(); }
aTimer.Reset();
aTimer.Start();
#include <OSD_Timer.hxx>
#include <Precision.hxx>
#include <Standard_CLocaleSentry.hxx>
+#include <Standard_ReadLineBuffer.hxx>
#include <algorithm>
#include <limits>
static const size_t THE_STL_SIZEOF_FACET = 50;
static const size_t THE_STL_MIN_FILE_SIZE = THE_STL_HEADER_SIZE + THE_STL_SIZEOF_FACET;
+ // The length of buffer to read (in bytes)
+ static const size_t THE_BUFFER_SIZE = 1024;
+
+ // Buffer to read
+ Standard_ReadLineBuffer THE_BUFFER (THE_BUFFER_SIZE);
+
//! Auxiliary tool for merging nodes during STL reading.
class MergeNodeTool
{
// 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());
- // 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<int64_t>::max());
+ size_t aLineLen = 0;
+ const char* aLine;
// skip header "solid ..."
- theStream.ignore ((std::streamsize)(aEndPos - aStartPos), '\n');
- if (!theStream)
+ aLine = THE_BUFFER.ReadLine (theStream, aLineLen);
+ if (aLine == NULL)
{
Message::DefaultMessenger()->Send ("Error: premature end of file", Message_Fail);
return false;
const int aStepB = 1024 * 1024;
const Standard_Integer aNbSteps = 1 + Standard_Integer((GETPOS(theUntilPos) - aStartPos) / aStepB);
Message_ProgressSentry aPSentry (theProgress, "Reading text STL file", 0, aNbSteps, 1);
-
int64_t aProgressPos = aStartPos + aStepB;
- const int64_t LINELEN = 1024;
int aNbLine = 1;
- char aLine1[LINELEN], aLine2[LINELEN], aLine3[LINELEN];
+
while (aPSentry.More())
{
if (GETPOS(theStream.tellg()) > aProgressPos)
aProgressPos += aStepB;
}
- char facet[LINELEN], outer[LINELEN];
- theStream.getline (facet, (std::streamsize)std::min (LINELEN, aEndPos - GETPOS(theStream.tellg()))); // "facet normal nx ny nz"
- if (str_starts_with (facet, "endsolid", 8))
+ aLine = THE_BUFFER.ReadLine (theStream, aLineLen); // "facet normal nx ny nz"
+ if (aLine == NULL)
+ {
+ Message::DefaultMessenger()->Send ("Error: premature end of file", Message_Fail);
+ return false;
+ }
+ if (str_starts_with (aLine, "endsolid", 8))
{
// end of STL code
break;
}
- theStream.getline (outer, (std::streamsize)std::min (LINELEN, aEndPos - GETPOS(theStream.tellg()))); // "outer loop"
- if (!str_starts_with (facet, "facet", 5) || !str_starts_with (outer, "outer", 5))
+ if (!str_starts_with (aLine, "facet", 5))
{
TCollection_AsciiString aStr ("Error: unexpected format of facet at line ");
aStr += aNbLine + 1;
return false;
}
- theStream.getline (aLine1, (std::streamsize)std::min (LINELEN, aEndPos - GETPOS(theStream.tellg())));
- theStream.getline (aLine2, (std::streamsize)std::min (LINELEN, aEndPos - GETPOS(theStream.tellg())));
- theStream.getline (aLine3, (std::streamsize)std::min (LINELEN, aEndPos - GETPOS(theStream.tellg())));
-
- // stop reading if end of file is reached;
- // note that well-formatted file never ends by the vertex line
- if (theStream.eof() || GETPOS(theStream.tellg()) >= aEndPos)
+ aLine = THE_BUFFER.ReadLine (theStream, aLineLen); // "outer loop"
+ if (aLine == NULL || !str_starts_with (aLine, "outer", 5))
{
- break;
+ TCollection_AsciiString aStr ("Error: unexpected format of facet at line ");
+ aStr += aNbLine + 1;
+ Message::DefaultMessenger()->Send (aStr, Message_Fail);
+ return false;
}
- if (!theStream)
+ gp_XYZ aVertex[3];
+ Standard_Boolean isEOF = false;
+ for (Standard_Integer i = 0; i < 3; i++)
{
- Message::DefaultMessenger()->Send ("Error: premature end of file", Message_Fail);
- return false;
+ aLine = THE_BUFFER.ReadLine (theStream, aLineLen);
+ if (aLine == NULL)
+ {
+ isEOF = true;
+ break;
+ }
+ gp_XYZ aReadVertex;
+ if (!ReadVertex (aLine, aReadVertex.ChangeCoord (1), aReadVertex.ChangeCoord (2), aReadVertex.ChangeCoord (3)))
+ {
+ TCollection_AsciiString aStr ("Error: cannot read vertex co-ordinates at line ");
+ aStr += aNbLine;
+ Message::DefaultMessenger()->Send (aStr, Message_Fail);
+ return false;
+ }
+ aVertex[i] = aReadVertex;
}
- aNbLine += 5;
- Standard_Real x1, y1, z1, x2, y2, z2, x3, y3, z3;
- if (! ReadVertex (aLine1, x1, y1, z1) ||
- ! ReadVertex (aLine2, x2, y2, z2) ||
- ! ReadVertex (aLine3, x3, y3, z3))
+ // stop reading if end of file is reached;
+ // note that well-formatted file never ends by the vertex line
+ if (isEOF)
{
- TCollection_AsciiString aStr ("Error: cannot read vertex co-ordinates at line ");
- aStr += aNbLine;
- Message::DefaultMessenger()->Send(aStr, Message_Fail);
- return false;
+ break;
}
+ aNbLine += 5;
+
// add triangle
- int n1 = aMergeTool.AddNode (x1, y1, z1);
- int n2 = aMergeTool.AddNode (x2, y2, z2);
- int n3 = aMergeTool.AddNode (x3, y3, z3);
+ int n1 = aMergeTool.AddNode (aVertex[0].X(), aVertex[0].Y(), aVertex[0].Z());
+ int n2 = aMergeTool.AddNode (aVertex[1].X(), aVertex[1].Y(), aVertex[1].Z());
+ int n3 = aMergeTool.AddNode (aVertex[2].X(), aVertex[2].Y(), aVertex[2].Z());
if (n1 != n2 && n2 != n3 && n3 != n1)
{
AddTriangle (n1, n2, n3);
}
- theStream.ignore ((std::streamsize)(aEndPos - GETPOS(theStream.tellg())), '\n'); // skip "endloop"
- theStream.ignore ((std::streamsize)(aEndPos - GETPOS(theStream.tellg())), '\n'); // skip "endfacet"
+ THE_BUFFER.ReadLine (theStream, aLineLen); // skip "endloop"
+ THE_BUFFER.ReadLine (theStream, aLineLen); // skip "endfacet"
aNbLine += 2;
}
//! @param theMaxBufferSizeBytes the length of buffer to read (in bytes)
Standard_ReadLineBuffer (size_t theMaxBufferSizeBytes)
: myUseReadBufferLastStr(false),
+ myIsMultilineMode (false),
myBufferPos (0),
myBytesLastRead (0)
{
{
myReadBufferLastStr.clear();
myUseReadBufferLastStr = false;
+ myIsMultilineMode = false;
myBufferPos = 0;
myBytesLastRead = 0;
}
int64_t& theReadData)
{
char* aResultLine = NULL;
+ bool isMultiline = false;
theLineLength = 0;
theReadData = 0;
if (myUseReadBufferLastStr)
{
theLineLength = myReadBufferLastStr.size();
- aResultLine = myReadBufferLastStr.data();
+ aResultLine = &myReadBufferLastStr.front();
myUseReadBufferLastStr = false;
}
break;
// read next line from myReadBuffer
while (myBufferPos < myBytesLastRead)
{
- if (myReadBuffer[myBufferPos] == '\n')
+ if (myReadBuffer[myBufferPos] == '\\' && myIsMultilineMode)
{
- isEndLineFound = true;
+ // multi-line syntax
+ if (myBufferPos + 1 == myBytesLastRead
+ ||(myBufferPos + 2 == myBytesLastRead && myReadBuffer[myBufferPos + 1] == '\r'))
+ {
+ isMultiline = true;
+ }
+ else if (myReadBuffer[myBufferPos + 1] == '\n'
+ ||(myReadBuffer[myBufferPos + 1] == '\r' && myReadBuffer[myBufferPos + 2] == '\n'))
+ {
+ if (myUseReadBufferLastStr)
+ {
+ myReadBufferLastStr.insert (myReadBufferLastStr.end(), myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
+ }
+ else
+ {
+ myReadBufferLastStr = std::vector<char>(myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
+ myUseReadBufferLastStr = true;
+ }
+
+ if (myReadBuffer[myBufferPos + 1] == '\r')
+ {
+ myBufferPos += 2;
+ }
+ else
+ {
+ myBufferPos += 1;
+ }
+
+ aStartLinePos = myBufferPos + 1;
+ }
+ }
+ else if (myReadBuffer[myBufferPos] == '\n')
+ {
+ if (!isMultiline)
+ {
+ isEndLineFound = true;
+ }
+ else if (myBufferPos == 1 && myReadBuffer[0] == '\r')
+ {
+ myReadBufferLastStr.erase (myReadBufferLastStr.end() - 1);
+ aStartLinePos += 2;
+ isMultiline = false;
+ }
+ else if (myBufferPos == 0)
+ {
+ aStartLinePos += 1;
+ if (myReadBufferLastStr[myReadBufferLastStr.size() - 1] == '\\')
+ {
+ myReadBufferLastStr.erase (myReadBufferLastStr.end() - 1);
+ }
+ else
+ {
+ myReadBufferLastStr.erase (myReadBufferLastStr.end() - 2, myReadBufferLastStr.end());
+ }
+ isMultiline = false;
+ }
}
++myBufferPos;
myReadBufferLastStr.insert (myReadBufferLastStr.end(), myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
myUseReadBufferLastStr = false;
theLineLength = myReadBufferLastStr.size();
- aResultLine = myReadBufferLastStr.data();
+ aResultLine = &myReadBufferLastStr.front();
}
else
{
myReadBufferLastStr.clear();
}
theLineLength = myBufferPos - aStartLinePos;
- aResultLine = myReadBuffer.data() + aStartLinePos;
+ aResultLine = &myReadBuffer.front() + aStartLinePos;
}
// make string null terminated by replacing '\n' or '\r' (before '\n') symbol to null character.
if (theLineLength > 1 && aResultLine[theLineLength - 2] == '\r')
// save "unfinished" part of string to additional buffer
if (aStartLinePos != myBufferPos)
{
- myReadBufferLastStr = std::vector<char>(myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
- myUseReadBufferLastStr = true;
+ if (myUseReadBufferLastStr)
+ {
+ myReadBufferLastStr.insert (myReadBufferLastStr.end(), myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
+ }
+ else
+ {
+ myReadBufferLastStr = std::vector<char>(myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
+ myUseReadBufferLastStr = true;
+ }
}
}
}
return aResultLine;
}
+ //! Returns TRUE when the Multiline Mode is on.
+ bool IsMultilineMode() const { return myIsMultilineMode; }
+
+ //! Sets or unsets the multi-line mode.
+ void SetMultilineMode (bool theMultilineMode) { myIsMultilineMode = theMultilineMode; }
+
protected:
//! Read from stl stream.
size_t theLen,
size_t& theReadLen)
{
- theReadLen = (size_t )theStream.read (myReadBuffer.data(), theLen).gcount();
+ theReadLen = (size_t )theStream.read (&myReadBuffer.front(), theLen).gcount();
return !theStream.bad();
}
size_t theLen,
size_t& theReadLen)
{
- theReadLen = ::fread (myReadBuffer.data(), 1, theLen, theStream);
+ theReadLen = ::fread (&myReadBuffer.front(), 1, theLen, theStream);
return ::ferror (theStream) == 0;
}
std::vector<char> myReadBuffer; //!< Temp read buffer
std::vector<char> myReadBufferLastStr; //!< Part of last string of myReadBuffer
bool myUseReadBufferLastStr; //!< Flag to use myReadBufferLastStr during next line reading
+ bool myIsMultilineMode; //!< Flag to process of the special multi-line case at the end of the line
size_t myBufferPos; //!< Current position in myReadBuffer
size_t myBytesLastRead; //!< The number of characters that were read last time from myReadBuffer.
};
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"
+puts "REQUIRED ALL: Error: premature end of file"
set fd [open ${imagedir}/${casename}_zero_binary.stl w]
fconfigure $fd -translation binary
puts -nonewline $fd "stl [string repeat { } 76][binary format i 0]"
puts "\n#======================================================================"
puts "# Empty file"
puts "#======================================================================"
-puts "REQUIRED ALL: Error: unexpected format of facet at line 2"
+puts "REQUIRED ALL: Error: premature end of file"
set fd [open ${imagedir}/${casename}_empty.stl w]
close $fd
readstl res_empty ${imagedir}/${casename}_empty.stl -brep