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),
30 myToPutGapInMultiline (true),
34 // allocate read buffer
35 myReadBuffer.resize (theMaxBufferSizeBytes);
39 virtual ~Standard_ReadLineBuffer() {}
41 //! Clear buffer and cached values.
44 myReadBufferLastStr.clear();
45 myUseReadBufferLastStr = false;
46 myIsMultilineMode = false;
47 myToPutGapInMultiline = true;
52 //! Read next line from the stream.
53 //! @return pointer to the line or NULL on error / end of reading buffer
54 //! (in case of NULL result theStream should be checked externally to identify the presence of errors).
55 //! Empty lines will be returned also with zero length.
56 //! @param theStream [inout] - the stream to read from.
57 //! @param theLineLength [out] - output parameter defined length of returned line.
58 template<typename Stream_T>
59 const char* ReadLine (Stream_T& theStream,
60 size_t& theLineLength)
62 int64_t aReadData = 0;
63 return ReadLine (theStream, theLineLength, aReadData);
66 //! Read next line from the stream.
67 //! @return pointer to the line or NULL on error / end of reading buffer
68 //! (in case of NULL result theStream should be checked externally to identify the presence of errors).
69 //! Empty lines will be returned also with zero length.
70 //! @param theStream [inout] - the stream to read from.
71 //! @param theLineLength [out] - output parameter defined length of returned line.
72 //! @param theReadData [out] - output parameter defined the number of elements successfully read from the stream during this call,
73 //! it can be zero if no data was read and the line is taken from the buffer.
74 template<typename Stream_T>
75 const char* ReadLine (Stream_T& theStream,
76 size_t& theLineLength,
79 char* aResultLine = NULL;
80 bool isMultiline = false;
84 while (aResultLine == NULL)
86 if (myBufferPos == 0 || myBufferPos >= (myBytesLastRead))
88 // read new chunk from the stream
89 if (!readStream (theStream, myReadBuffer.size(), myBytesLastRead))
91 // error during file reading
95 theReadData = myBytesLastRead;
97 if (myBytesLastRead > 0)
104 if (myUseReadBufferLastStr)
106 theLineLength = myReadBufferLastStr.size();
107 aResultLine = &myReadBufferLastStr.front();
108 myUseReadBufferLastStr = false;
114 size_t aStartLinePos = myBufferPos;
115 bool isEndLineFound = false;
117 // read next line from myReadBuffer
118 while (myBufferPos < myBytesLastRead)
120 if (myIsMultilineMode
121 && myReadBuffer[myBufferPos] == '\\')
124 if (myBufferPos + 1 == myBytesLastRead
125 || (myBufferPos + 2 == myBytesLastRead
126 && myReadBuffer[myBufferPos + 1] == '\r'))
129 if (myToPutGapInMultiline)
131 myReadBuffer[myBufferPos] = ' ';
132 if (myBufferPos + 1 != myBytesLastRead)
134 myReadBuffer[myBufferPos + 1] = ' ';
138 else if (myReadBuffer[myBufferPos + 1] == '\n'
139 ||(myReadBuffer[myBufferPos + 1] == '\r'
140 && myReadBuffer[myBufferPos + 2] == '\n'))
142 size_t aBufferPos = myBufferPos;
143 myBufferPos = aBufferPos + (myReadBuffer[aBufferPos + 1] == '\r' ? 2 : 1);
144 if (myToPutGapInMultiline)
146 myReadBuffer[aBufferPos] = ' ';
150 if (myUseReadBufferLastStr)
152 myReadBufferLastStr.insert (myReadBufferLastStr.end(), myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + aBufferPos);
156 myReadBufferLastStr = std::vector<char>(myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + aBufferPos);
157 myUseReadBufferLastStr = true;
160 aStartLinePos = myBufferPos + 1;
163 else if (myReadBuffer[myBufferPos] == '\n')
167 isEndLineFound = true;
169 else if (myBufferPos == 1 && myReadBuffer[0] == '\r')
171 myReadBufferLastStr.erase (myReadBufferLastStr.end() - 1);
175 else if (myBufferPos == 0)
178 if (myReadBufferLastStr[myReadBufferLastStr.size() - 1] == '\\')
180 myReadBufferLastStr.erase (myReadBufferLastStr.end() - 1);
184 myReadBufferLastStr.erase (myReadBufferLastStr.end() - 2, myReadBufferLastStr.end());
192 if (isEndLineFound) break;
197 if (myUseReadBufferLastStr)
199 // append current string to the last "unfinished" string of the previous chunk
200 myReadBufferLastStr.insert (myReadBufferLastStr.end(), myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
201 myUseReadBufferLastStr = false;
202 theLineLength = myReadBufferLastStr.size();
203 aResultLine = &myReadBufferLastStr.front();
207 if (myReadBufferLastStr.size() > 0)
209 myReadBufferLastStr.clear();
211 theLineLength = myBufferPos - aStartLinePos;
212 aResultLine = &myReadBuffer.front() + aStartLinePos;
214 // make string null terminated by replacing '\n' or '\r' (before '\n') symbol to null character.
215 if (theLineLength > 1 && aResultLine[theLineLength - 2] == '\r')
217 aResultLine[theLineLength - 2] = '\0';
222 aResultLine[theLineLength - 1] = '\0';
228 // save "unfinished" part of string to additional buffer
229 if (aStartLinePos != myBufferPos)
231 if (myUseReadBufferLastStr)
233 myReadBufferLastStr.insert (myReadBufferLastStr.end(), myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
237 myReadBufferLastStr = std::vector<char>(myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
238 myUseReadBufferLastStr = true;
246 //! Returns TRUE when the Multiline Mode is on; FALSE by default.
247 //! Multiline modes joins several lines in file having \ at the end of line:
249 //! Line starts here, \ // line continuation character without this comment
250 //! continues \ // line continuation character without this comment
253 bool IsMultilineMode() const { return myIsMultilineMode; }
255 //! Put gap space while merging lines within multiline syntax, so that the following sample:
257 //! 1/2/3\ // line continuation character without this comment
260 //! Will become "1/2/3 4/5/6" when flag is TRUE, and "1/2/35/5/6" otherwise.
261 bool ToPutGapInMultiline() const { return myToPutGapInMultiline; }
263 //! Sets or unsets the multi-line mode.
264 //! @param theMultilineMode [in] multiline mode flag
265 //! @param theToPutGap [in] put gap space while connecting lines (no gap otherwise)
266 void SetMultilineMode (bool theMultilineMode,
267 bool theToPutGap = true)
269 myIsMultilineMode = theMultilineMode;
270 myToPutGapInMultiline = theToPutGap;
275 //! Read from stl stream.
276 //! @return true if reading was finished without errors.
277 bool readStream (std::istream& theStream,
281 theReadLen = (size_t )theStream.read (&myReadBuffer.front(), theLen).gcount();
282 return !theStream.bad();
285 //! Read from FILE stream.
286 //! @return true if reading was finished without errors.
287 bool readStream (FILE* theStream,
291 theReadLen = ::fread (&myReadBuffer.front(), 1, theLen, theStream);
292 return ::ferror (theStream) == 0;
297 std::vector<char> myReadBuffer; //!< Temp read buffer
298 std::vector<char> myReadBufferLastStr; //!< Part of last string of myReadBuffer
299 bool myUseReadBufferLastStr; //!< Flag to use myReadBufferLastStr during next line reading
300 bool myIsMultilineMode; //!< Flag to process of the special multi-line case at the end of the line
301 bool myToPutGapInMultiline; //!< Flag to put gap space while joining lines in multi-line syntax
302 size_t myBufferPos; //!< Current position in myReadBuffer
303 size_t myBytesLastRead; //!< The number of characters that were read last time from myReadBuffer.
306 #endif // _Standard_ReadLineBuffer_HeaderFile