1 // Copyright (c) 2019 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
14 #ifndef _Standard_ReadLineBuffer_HeaderFile
15 #define _Standard_ReadLineBuffer_HeaderFile
20 //! Auxiliary tool for buffered reading of lines from input stream.
21 class Standard_ReadLineBuffer
25 //! Constructor with initialization.
26 //! @param theMaxBufferSizeBytes the length of buffer to read (in bytes)
27 Standard_ReadLineBuffer (size_t theMaxBufferSizeBytes)
28 : myUseReadBufferLastStr(false),
29 myIsMultilineMode (false),
33 // allocate read buffer
34 myReadBuffer.resize (theMaxBufferSizeBytes);
38 virtual ~Standard_ReadLineBuffer() {}
40 //! Clear buffer and cached values.
43 myReadBufferLastStr.clear();
44 myUseReadBufferLastStr = false;
45 myIsMultilineMode = false;
50 //! Read next line from the stream.
51 //! @return pointer to the line or NULL on error / end of reading buffer
52 //! (in case of NULL result theStream should be checked externally to identify the presence of errors).
53 //! Empty lines will be returned also with zero length.
54 //! @param theLineLength [out] - output parameter defined length of returned line.
55 template<typename Stream_T>
56 const char* ReadLine (Stream_T& theStream,
57 size_t& theLineLength)
59 int64_t aReadData = 0;
60 return ReadLine (theStream, theLineLength, aReadData);
63 //! Read next line from the stream.
64 //! @return pointer to the line or NULL on error / end of reading buffer
65 //! (in case of NULL result theStream should be checked externally to identify the presence of errors).
66 //! Empty lines will be returned also with zero length.
67 //! @param theLineLength [out] - output parameter defined length of returned line.
68 //! @param theReadData [out] - output parameter defined the number of elements successfully read from the stream during this call,
69 //! it can be zero if no data was read and the line is taken from the buffer.
70 template<typename Stream_T>
71 const char* ReadLine (Stream_T& theStream,
72 size_t& theLineLength,
75 char* aResultLine = NULL;
76 bool isMultiline = false;
80 while (aResultLine == NULL)
82 if (myBufferPos == 0 || myBufferPos >= (myBytesLastRead))
84 // read new chunk from the stream
85 if (!readStream (theStream, myReadBuffer.size(), myBytesLastRead))
87 // error during file reading
91 theReadData = myBytesLastRead;
93 if (myBytesLastRead > 0)
100 if (myUseReadBufferLastStr)
102 theLineLength = myReadBufferLastStr.size();
103 aResultLine = &myReadBufferLastStr.front();
104 myUseReadBufferLastStr = false;
110 size_t aStartLinePos = myBufferPos;
111 bool isEndLineFound = false;
113 // read next line from myReadBuffer
114 while (myBufferPos < myBytesLastRead)
116 if (myReadBuffer[myBufferPos] == '\\' && myIsMultilineMode)
119 if (myBufferPos + 1 == myBytesLastRead
120 ||(myBufferPos + 2 == myBytesLastRead && myReadBuffer[myBufferPos + 1] == '\r'))
124 else if (myReadBuffer[myBufferPos + 1] == '\n'
125 ||(myReadBuffer[myBufferPos + 1] == '\r' && myReadBuffer[myBufferPos + 2] == '\n'))
127 if (myUseReadBufferLastStr)
129 myReadBufferLastStr.insert (myReadBufferLastStr.end(), myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
133 myReadBufferLastStr = std::vector<char>(myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
134 myUseReadBufferLastStr = true;
137 if (myReadBuffer[myBufferPos + 1] == '\r')
146 aStartLinePos = myBufferPos + 1;
149 else if (myReadBuffer[myBufferPos] == '\n')
153 isEndLineFound = true;
155 else if (myBufferPos == 1 && myReadBuffer[0] == '\r')
157 myReadBufferLastStr.erase (myReadBufferLastStr.end() - 1);
161 else if (myBufferPos == 0)
164 if (myReadBufferLastStr[myReadBufferLastStr.size() - 1] == '\\')
166 myReadBufferLastStr.erase (myReadBufferLastStr.end() - 1);
170 myReadBufferLastStr.erase (myReadBufferLastStr.end() - 2, myReadBufferLastStr.end());
178 if (isEndLineFound) break;
183 if (myUseReadBufferLastStr)
185 // append current string to the last "unfinished" string of the previous chunk
186 myReadBufferLastStr.insert (myReadBufferLastStr.end(), myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
187 myUseReadBufferLastStr = false;
188 theLineLength = myReadBufferLastStr.size();
189 aResultLine = &myReadBufferLastStr.front();
193 if (myReadBufferLastStr.size() > 0)
195 myReadBufferLastStr.clear();
197 theLineLength = myBufferPos - aStartLinePos;
198 aResultLine = &myReadBuffer.front() + aStartLinePos;
200 // make string null terminated by replacing '\n' or '\r' (before '\n') symbol to null character.
201 if (theLineLength > 1 && aResultLine[theLineLength - 2] == '\r')
203 aResultLine[theLineLength - 2] = '\0';
208 aResultLine[theLineLength - 1] = '\0';
214 // save "unfinished" part of string to additional buffer
215 if (aStartLinePos != myBufferPos)
217 if (myUseReadBufferLastStr)
219 myReadBufferLastStr.insert (myReadBufferLastStr.end(), myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
223 myReadBufferLastStr = std::vector<char>(myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
224 myUseReadBufferLastStr = true;
232 //! Returns TRUE when the Multiline Mode is on.
233 bool IsMultilineMode() const { return myIsMultilineMode; }
235 //! Sets or unsets the multi-line mode.
236 void SetMultilineMode (bool theMultilineMode) { myIsMultilineMode = theMultilineMode; }
240 //! Read from stl stream.
241 //! @return true if reading was finished without errors.
242 bool readStream (std::istream& theStream,
246 theReadLen = (size_t )theStream.read (&myReadBuffer.front(), theLen).gcount();
247 return !theStream.bad();
250 //! Read from FILE stream.
251 //! @return true if reading was finished without errors.
252 bool readStream (FILE* theStream,
256 theReadLen = ::fread (&myReadBuffer.front(), 1, theLen, theStream);
257 return ::ferror (theStream) == 0;
262 std::vector<char> myReadBuffer; //!< Temp read buffer
263 std::vector<char> myReadBufferLastStr; //!< Part of last string of myReadBuffer
264 bool myUseReadBufferLastStr; //!< Flag to use myReadBufferLastStr during next line reading
265 bool myIsMultilineMode; //!< Flag to process of the special multi-line case at the end of the line
266 size_t myBufferPos; //!< Current position in myReadBuffer
267 size_t myBytesLastRead; //!< The number of characters that were read last time from myReadBuffer.
270 #endif // _Standard_ReadLineBuffer_HeaderFile