0030855: Coding - New warnings within Standard_ReadLineBuffer after integration fix...
[occt.git] / src / Standard / Standard_ReadLineBuffer.hxx
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.
21 class Standard_ReadLineBuffer
22 {
23 public:
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),
29     myBufferPos           (0),
30     myBytesLastRead       (0)
31   {
32     // allocate read buffer
33     myReadBuffer.resize (theMaxBufferSizeBytes);
34   }
35
36   //! Destructor.
37   virtual ~Standard_ReadLineBuffer() {}
38
39   //! Clear buffer and cached values.
40   void Clear()
41   {
42     myReadBufferLastStr.clear();
43     myUseReadBufferLastStr = false;
44     myBufferPos = 0;
45     myBytesLastRead = 0;
46   }
47
48   //! Read next line from the stream.
49   //! @return pointer to the line or NULL on error / end of reading buffer
50   //!         (in case of NULL result theStream should be checked externally to identify the presence of errors).
51   //!          Empty lines will be returned also with zero length.
52   //! @param theLineLength [out] - output parameter defined length of returned line.
53   template<typename Stream_T>
54   const char* ReadLine (Stream_T& theStream,
55                         size_t& theLineLength)
56   {
57     int64_t aReadData = 0;
58     return ReadLine (theStream, theLineLength, aReadData);
59   }
60
61   //! Read next line from the stream.
62   //! @return pointer to the line or NULL on error / end of reading buffer
63   //!         (in case of NULL result theStream should be checked externally to identify the presence of errors).
64   //!          Empty lines will be returned also with zero length.
65   //! @param theLineLength [out] - output parameter defined length of returned line.
66   //! @param theReadData   [out] - output parameter defined the number of elements successfully read from the stream during this call,
67   //!                              it can be zero if no data was read and the line is taken from the buffer.
68   template<typename Stream_T>
69   const char* ReadLine (Stream_T& theStream,
70                         size_t& theLineLength,
71                         int64_t& theReadData)
72   {
73     char* aResultLine = NULL;
74     theLineLength = 0;
75     theReadData = 0;
76
77     while (aResultLine == NULL)
78     {
79       if (myBufferPos == 0 || myBufferPos >= (myBytesLastRead))
80       {
81         // read new chunk from the stream
82         if (!readStream (theStream, myReadBuffer.size(), myBytesLastRead))
83         {
84           // error during file reading
85           break;
86         }
87
88         theReadData = myBytesLastRead;
89
90         if (myBytesLastRead > 0)
91         {
92           myBufferPos = 0;
93         }
94         else
95         {
96           // end of the stream
97           if (myUseReadBufferLastStr)
98           {
99             theLineLength = myReadBufferLastStr.size();
100             aResultLine = myReadBufferLastStr.data();
101             myUseReadBufferLastStr = false;
102           }
103           break;
104         }
105       }
106
107       size_t aStartLinePos = myBufferPos;
108       bool isEndLineFound = false;
109
110       // read next line from myReadBuffer
111       while (myBufferPos < myBytesLastRead)
112       {
113         if (myReadBuffer[myBufferPos] == '\n')
114         {
115           isEndLineFound = true;
116         }
117
118         ++myBufferPos;
119
120         if (isEndLineFound) break;
121       }
122
123       if (isEndLineFound)
124       {
125         if (myUseReadBufferLastStr)
126         {
127           // append current string to the last "unfinished" string of the previous chunk
128           myReadBufferLastStr.insert (myReadBufferLastStr.end(), myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
129           myUseReadBufferLastStr = false;
130           theLineLength = myReadBufferLastStr.size();
131           aResultLine = myReadBufferLastStr.data();
132         }
133         else
134         {
135           if (myReadBufferLastStr.size() > 0)
136           {
137             myReadBufferLastStr.clear();
138           }
139           theLineLength = myBufferPos - aStartLinePos;
140           aResultLine = myReadBuffer.data() + aStartLinePos;
141         }
142         // make string null terminated by replacing '\n' or '\r' (before '\n') symbol to null character.
143         if (theLineLength > 1 && aResultLine[theLineLength - 2] == '\r')
144         {
145           aResultLine[theLineLength - 2] = '\0';
146           theLineLength -= 2;
147         }
148         else
149         {
150           aResultLine[theLineLength - 1] = '\0';
151           theLineLength -= 1;
152         }
153       }
154       else
155       {
156         // save "unfinished" part of string to additional buffer
157         if (aStartLinePos != myBufferPos)
158         {
159           myReadBufferLastStr = std::vector<char>(myReadBuffer.begin() + aStartLinePos, myReadBuffer.begin() + myBufferPos);
160           myUseReadBufferLastStr = true;
161         }
162       }
163     }
164     return aResultLine;
165   }
166
167 protected:
168
169   //! Read from stl stream.
170   //! @return true if reading was finished without errors.
171   bool readStream (std::istream& theStream,
172                    size_t theLen,
173                    size_t& theReadLen)
174   {
175     theReadLen = (size_t )theStream.read (myReadBuffer.data(), theLen).gcount();
176     return !theStream.bad();
177   }
178
179   //! Read from FILE stream.
180   //! @return true if reading was finished without errors.
181   bool readStream (FILE* theStream,
182                    size_t theLen,
183                    size_t& theReadLen)
184   {
185     theReadLen = ::fread (myReadBuffer.data(), 1, theLen, theStream);
186     return ::ferror (theStream) == 0;
187   }
188
189 protected:
190
191   std::vector<char> myReadBuffer;           //!< Temp read buffer
192   std::vector<char> myReadBufferLastStr;    //!< Part of last string of myReadBuffer
193   bool              myUseReadBufferLastStr; //!< Flag to use myReadBufferLastStr during next line reading
194   size_t            myBufferPos;            //!< Current position in myReadBuffer
195   size_t            myBytesLastRead;        //!< The number of characters that were read last time from myReadBuffer.
196 };
197
198 #endif // _Standard_ReadLineBuffer_HeaderFile