0030964: Data Exchange - use Standard_ReadLineBuffer within OBJ reader
[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),
fa1710b5 30 myBufferPos (0),
31 myBytesLastRead (0)
32 {
33 // allocate read buffer
34 myReadBuffer.resize (theMaxBufferSizeBytes);
35 }
36
37 //! Destructor.
38 virtual ~Standard_ReadLineBuffer() {}
39
40 //! Clear buffer and cached values.
41 void Clear()
42 {
43 myReadBufferLastStr.clear();
44 myUseReadBufferLastStr = false;
51ee6a7d 45 myIsMultilineMode = false;
fa1710b5 46 myBufferPos = 0;
47 myBytesLastRead = 0;
48 }
49
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)
58 {
59 int64_t aReadData = 0;
60 return ReadLine (theStream, theLineLength, aReadData);
61 }
62
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,
73 int64_t& theReadData)
74 {
75 char* aResultLine = NULL;
51ee6a7d 76 bool isMultiline = false;
fa1710b5 77 theLineLength = 0;
78 theReadData = 0;
79
80 while (aResultLine == NULL)
81 {
82 if (myBufferPos == 0 || myBufferPos >= (myBytesLastRead))
83 {
84 // read new chunk from the stream
85 if (!readStream (theStream, myReadBuffer.size(), myBytesLastRead))
86 {
87 // error during file reading
88 break;
89 }
90
91 theReadData = myBytesLastRead;
92
93 if (myBytesLastRead > 0)
94 {
95 myBufferPos = 0;
96 }
97 else
98 {
99 // end of the stream
100 if (myUseReadBufferLastStr)
101 {
102 theLineLength = myReadBufferLastStr.size();
51ee6a7d 103 aResultLine = &myReadBufferLastStr.front();
fa1710b5 104 myUseReadBufferLastStr = false;
105 }
106 break;
107 }
108 }
109
110 size_t aStartLinePos = myBufferPos;
111 bool isEndLineFound = false;
112
113 // read next line from myReadBuffer
114 while (myBufferPos < myBytesLastRead)
115 {
51ee6a7d 116 if (myReadBuffer[myBufferPos] == '\\' && myIsMultilineMode)
fa1710b5 117 {
51ee6a7d 118 // multi-line syntax
119 if (myBufferPos + 1 == myBytesLastRead
120 ||(myBufferPos + 2 == myBytesLastRead && myReadBuffer[myBufferPos + 1] == '\r'))
121 {
122 isMultiline = true;
123 }
124 else if (myReadBuffer[myBufferPos + 1] == '\n'
125 ||(myReadBuffer[myBufferPos + 1] == '\r' && myReadBuffer[myBufferPos + 2] == '\n'))
126 {
127 if (myUseReadBufferLastStr)
128 {
129 myReadBufferLastStr.insert (myReadBufferLastStr.end(), myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
130 }
131 else
132 {
133 myReadBufferLastStr = std::vector<char>(myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
134 myUseReadBufferLastStr = true;
135 }
136
137 if (myReadBuffer[myBufferPos + 1] == '\r')
138 {
139 myBufferPos += 2;
140 }
141 else
142 {
143 myBufferPos += 1;
144 }
145
146 aStartLinePos = myBufferPos + 1;
147 }
148 }
149 else if (myReadBuffer[myBufferPos] == '\n')
150 {
151 if (!isMultiline)
152 {
153 isEndLineFound = true;
154 }
155 else if (myBufferPos == 1 && myReadBuffer[0] == '\r')
156 {
157 myReadBufferLastStr.erase (myReadBufferLastStr.end() - 1);
158 aStartLinePos += 2;
159 isMultiline = false;
160 }
161 else if (myBufferPos == 0)
162 {
163 aStartLinePos += 1;
164 if (myReadBufferLastStr[myReadBufferLastStr.size() - 1] == '\\')
165 {
166 myReadBufferLastStr.erase (myReadBufferLastStr.end() - 1);
167 }
168 else
169 {
170 myReadBufferLastStr.erase (myReadBufferLastStr.end() - 2, myReadBufferLastStr.end());
171 }
172 isMultiline = false;
173 }
fa1710b5 174 }
175
176 ++myBufferPos;
177
178 if (isEndLineFound) break;
179 }
180
181 if (isEndLineFound)
182 {
183 if (myUseReadBufferLastStr)
184 {
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();
51ee6a7d 189 aResultLine = &myReadBufferLastStr.front();
fa1710b5 190 }
191 else
192 {
193 if (myReadBufferLastStr.size() > 0)
194 {
195 myReadBufferLastStr.clear();
196 }
197 theLineLength = myBufferPos - aStartLinePos;
51ee6a7d 198 aResultLine = &myReadBuffer.front() + aStartLinePos;
fa1710b5 199 }
200 // make string null terminated by replacing '\n' or '\r' (before '\n') symbol to null character.
201 if (theLineLength > 1 && aResultLine[theLineLength - 2] == '\r')
202 {
203 aResultLine[theLineLength - 2] = '\0';
204 theLineLength -= 2;
205 }
206 else
207 {
208 aResultLine[theLineLength - 1] = '\0';
209 theLineLength -= 1;
210 }
211 }
212 else
213 {
214 // save "unfinished" part of string to additional buffer
215 if (aStartLinePos != myBufferPos)
216 {
51ee6a7d 217 if (myUseReadBufferLastStr)
218 {
219 myReadBufferLastStr.insert (myReadBufferLastStr.end(), myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
220 }
221 else
222 {
223 myReadBufferLastStr = std::vector<char>(myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
224 myUseReadBufferLastStr = true;
225 }
fa1710b5 226 }
227 }
228 }
229 return aResultLine;
230 }
231
51ee6a7d 232 //! Returns TRUE when the Multiline Mode is on.
233 bool IsMultilineMode() const { return myIsMultilineMode; }
234
235 //! Sets or unsets the multi-line mode.
236 void SetMultilineMode (bool theMultilineMode) { myIsMultilineMode = theMultilineMode; }
237
fa1710b5 238protected:
239
240 //! Read from stl stream.
241 //! @return true if reading was finished without errors.
242 bool readStream (std::istream& theStream,
243 size_t theLen,
244 size_t& theReadLen)
245 {
51ee6a7d 246 theReadLen = (size_t )theStream.read (&myReadBuffer.front(), theLen).gcount();
fa1710b5 247 return !theStream.bad();
248 }
249
250 //! Read from FILE stream.
251 //! @return true if reading was finished without errors.
252 bool readStream (FILE* theStream,
253 size_t theLen,
254 size_t& theReadLen)
255 {
51ee6a7d 256 theReadLen = ::fread (&myReadBuffer.front(), 1, theLen, theStream);
fa1710b5 257 return ::ferror (theStream) == 0;
258 }
259
260protected:
261
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
51ee6a7d 265 bool myIsMultilineMode; //!< Flag to process of the special multi-line case at the end of the line
fa1710b5 266 size_t myBufferPos; //!< Current position in myReadBuffer
267 size_t myBytesLastRead; //!< The number of characters that were read last time from myReadBuffer.
268};
269
270#endif // _Standard_ReadLineBuffer_HeaderFile