0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[occt.git] / src / Standard / Standard_ReadLineBuffer.hxx
CommitLineData
fa1710b5 1// Copyright (c) 2019 OPEN CASCADE SAS
2//
3// This file is part of Open CASCADE Technology software library.
4//
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.
10//
11// Alternatively, this file may be used under the terms of Open CASCADE
12// commercial license or contractual agreement.
13
14#ifndef _Standard_ReadLineBuffer_HeaderFile
15#define _Standard_ReadLineBuffer_HeaderFile
16
17#include <iostream>
18#include <vector>
19
20//! Auxiliary tool for buffered reading of lines from input stream.
21class Standard_ReadLineBuffer
22{
23public:
24
25 //! Constructor with initialization.
26 //! @param theMaxBufferSizeBytes the length of buffer to read (in bytes)
27 Standard_ReadLineBuffer (size_t theMaxBufferSizeBytes)
28 : myUseReadBufferLastStr(false),
51ee6a7d 29 myIsMultilineMode (false),
3eba1c72 30 myToPutGapInMultiline (true),
fa1710b5 31 myBufferPos (0),
32 myBytesLastRead (0)
33 {
34 // allocate read buffer
35 myReadBuffer.resize (theMaxBufferSizeBytes);
36 }
37
38 //! Destructor.
39 virtual ~Standard_ReadLineBuffer() {}
40
41 //! Clear buffer and cached values.
42 void Clear()
43 {
44 myReadBufferLastStr.clear();
45 myUseReadBufferLastStr = false;
51ee6a7d 46 myIsMultilineMode = false;
3eba1c72 47 myToPutGapInMultiline = true;
fa1710b5 48 myBufferPos = 0;
49 myBytesLastRead = 0;
50 }
51
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.
64e68ea6 56 //! @param theStream [inout] - the stream to read from.
fa1710b5 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)
61 {
62 int64_t aReadData = 0;
63 return ReadLine (theStream, theLineLength, aReadData);
64 }
65
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.
64e68ea6 70 //! @param theStream [inout] - the stream to read from.
fa1710b5 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,
77 int64_t& theReadData)
78 {
79 char* aResultLine = NULL;
51ee6a7d 80 bool isMultiline = false;
fa1710b5 81 theLineLength = 0;
82 theReadData = 0;
83
84 while (aResultLine == NULL)
85 {
86 if (myBufferPos == 0 || myBufferPos >= (myBytesLastRead))
87 {
88 // read new chunk from the stream
89 if (!readStream (theStream, myReadBuffer.size(), myBytesLastRead))
90 {
91 // error during file reading
92 break;
93 }
94
95 theReadData = myBytesLastRead;
96
97 if (myBytesLastRead > 0)
98 {
99 myBufferPos = 0;
100 }
101 else
102 {
103 // end of the stream
104 if (myUseReadBufferLastStr)
105 {
106 theLineLength = myReadBufferLastStr.size();
51ee6a7d 107 aResultLine = &myReadBufferLastStr.front();
fa1710b5 108 myUseReadBufferLastStr = false;
109 }
110 break;
111 }
112 }
113
114 size_t aStartLinePos = myBufferPos;
115 bool isEndLineFound = false;
116
117 // read next line from myReadBuffer
118 while (myBufferPos < myBytesLastRead)
119 {
3eba1c72 120 if (myIsMultilineMode
121 && myReadBuffer[myBufferPos] == '\\')
fa1710b5 122 {
51ee6a7d 123 // multi-line syntax
124 if (myBufferPos + 1 == myBytesLastRead
3eba1c72 125 || (myBufferPos + 2 == myBytesLastRead
126 && myReadBuffer[myBufferPos + 1] == '\r'))
51ee6a7d 127 {
128 isMultiline = true;
3eba1c72 129 if (myToPutGapInMultiline)
130 {
131 myReadBuffer[myBufferPos] = ' ';
132 if (myBufferPos + 1 != myBytesLastRead)
133 {
134 myReadBuffer[myBufferPos + 1] = ' ';
135 }
136 }
51ee6a7d 137 }
138 else if (myReadBuffer[myBufferPos + 1] == '\n'
3eba1c72 139 ||(myReadBuffer[myBufferPos + 1] == '\r'
140 && myReadBuffer[myBufferPos + 2] == '\n'))
51ee6a7d 141 {
3eba1c72 142 size_t aBufferPos = myBufferPos;
143 myBufferPos = aBufferPos + (myReadBuffer[aBufferPos + 1] == '\r' ? 2 : 1);
144 if (myToPutGapInMultiline)
51ee6a7d 145 {
3eba1c72 146 myReadBuffer[aBufferPos] = ' ';
147 ++aBufferPos;
51ee6a7d 148 }
149
3eba1c72 150 if (myUseReadBufferLastStr)
51ee6a7d 151 {
3eba1c72 152 myReadBufferLastStr.insert (myReadBufferLastStr.end(), myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + aBufferPos);
51ee6a7d 153 }
154 else
155 {
3eba1c72 156 myReadBufferLastStr = std::vector<char>(myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + aBufferPos);
157 myUseReadBufferLastStr = true;
51ee6a7d 158 }
159
160 aStartLinePos = myBufferPos + 1;
161 }
162 }
163 else if (myReadBuffer[myBufferPos] == '\n')
164 {
165 if (!isMultiline)
166 {
167 isEndLineFound = true;
168 }
169 else if (myBufferPos == 1 && myReadBuffer[0] == '\r')
170 {
171 myReadBufferLastStr.erase (myReadBufferLastStr.end() - 1);
172 aStartLinePos += 2;
173 isMultiline = false;
174 }
175 else if (myBufferPos == 0)
176 {
177 aStartLinePos += 1;
178 if (myReadBufferLastStr[myReadBufferLastStr.size() - 1] == '\\')
179 {
180 myReadBufferLastStr.erase (myReadBufferLastStr.end() - 1);
181 }
182 else
183 {
184 myReadBufferLastStr.erase (myReadBufferLastStr.end() - 2, myReadBufferLastStr.end());
185 }
186 isMultiline = false;
187 }
fa1710b5 188 }
189
190 ++myBufferPos;
191
192 if (isEndLineFound) break;
193 }
194
195 if (isEndLineFound)
196 {
197 if (myUseReadBufferLastStr)
198 {
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();
51ee6a7d 203 aResultLine = &myReadBufferLastStr.front();
fa1710b5 204 }
205 else
206 {
207 if (myReadBufferLastStr.size() > 0)
208 {
209 myReadBufferLastStr.clear();
210 }
211 theLineLength = myBufferPos - aStartLinePos;
51ee6a7d 212 aResultLine = &myReadBuffer.front() + aStartLinePos;
fa1710b5 213 }
214 // make string null terminated by replacing '\n' or '\r' (before '\n') symbol to null character.
215 if (theLineLength > 1 && aResultLine[theLineLength - 2] == '\r')
216 {
217 aResultLine[theLineLength - 2] = '\0';
218 theLineLength -= 2;
219 }
220 else
221 {
222 aResultLine[theLineLength - 1] = '\0';
223 theLineLength -= 1;
224 }
225 }
226 else
227 {
228 // save "unfinished" part of string to additional buffer
229 if (aStartLinePos != myBufferPos)
230 {
51ee6a7d 231 if (myUseReadBufferLastStr)
232 {
233 myReadBufferLastStr.insert (myReadBufferLastStr.end(), myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
234 }
235 else
236 {
237 myReadBufferLastStr = std::vector<char>(myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
238 myUseReadBufferLastStr = true;
239 }
fa1710b5 240 }
241 }
242 }
243 return aResultLine;
244 }
245
3eba1c72 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:
248 //! @code
249 //! Line starts here, \ // line continuation character without this comment
250 //! continues \ // line continuation character without this comment
251 //! and ends.
252 //! @endcode
51ee6a7d 253 bool IsMultilineMode() const { return myIsMultilineMode; }
254
3eba1c72 255 //! Put gap space while merging lines within multiline syntax, so that the following sample:
256 //! @code
257 //! 1/2/3\ // line continuation character without this comment
258 //! 4/5/6
259 //! @endcode
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; }
262
51ee6a7d 263 //! Sets or unsets the multi-line mode.
3eba1c72 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)
268 {
269 myIsMultilineMode = theMultilineMode;
270 myToPutGapInMultiline = theToPutGap;
271 }
51ee6a7d 272
fa1710b5 273protected:
274
275 //! Read from stl stream.
276 //! @return true if reading was finished without errors.
277 bool readStream (std::istream& theStream,
278 size_t theLen,
279 size_t& theReadLen)
280 {
51ee6a7d 281 theReadLen = (size_t )theStream.read (&myReadBuffer.front(), theLen).gcount();
fa1710b5 282 return !theStream.bad();
283 }
284
285 //! Read from FILE stream.
286 //! @return true if reading was finished without errors.
287 bool readStream (FILE* theStream,
288 size_t theLen,
289 size_t& theReadLen)
290 {
51ee6a7d 291 theReadLen = ::fread (&myReadBuffer.front(), 1, theLen, theStream);
fa1710b5 292 return ::ferror (theStream) == 0;
293 }
294
295protected:
296
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
51ee6a7d 300 bool myIsMultilineMode; //!< Flag to process of the special multi-line case at the end of the line
3eba1c72 301 bool myToPutGapInMultiline; //!< Flag to put gap space while joining lines in multi-line syntax
fa1710b5 302 size_t myBufferPos; //!< Current position in myReadBuffer
303 size_t myBytesLastRead; //!< The number of characters that were read last time from myReadBuffer.
304};
305
306#endif // _Standard_ReadLineBuffer_HeaderFile