0030692: Data Exchange - introduce base framework RWMesh for importing mesh data...
[occt.git] / src / Standard / Standard_ReadBuffer.hxx
1 // Copyright (c) 2017-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_ReadBuffer_HeaderFile
15 #define _Standard_ReadBuffer_HeaderFile
16
17 #include <Standard_ProgramError.hxx>
18
19 #include <iostream>
20
21 //! Auxiliary tool for buffered reading from input stream within chunks of constant size.
22 class Standard_ReadBuffer
23 {
24 public:
25
26   //! Constructor with initialization.
27   Standard_ReadBuffer (int64_t theDataLen,
28                        size_t  theChunkLen)
29   : myBufferPtr(NULL),
30     myBufferEnd(NULL),
31     myDataLen  (0),
32     myDataRead (0),
33     myChunkLen (0),
34     myNbChunks (0),
35     myBufferLen(0)
36   {
37     Init (theDataLen, theChunkLen);
38   }
39
40   //! Initialize the buffer.
41   //! @param theDataLen  the full length of input data to read from stream.
42   //! @param theChunkLen the length of single chunk to read
43   void Init (int64_t theDataLen,
44              size_t  theChunkLen)
45   {
46     myDataRead  = 0;
47     myDataLen   = theDataLen - theDataLen % int64_t(theChunkLen);
48     myChunkLen  = theChunkLen;
49     myNbChunks  = sizeof(myBuffer) / theChunkLen;
50     myBufferLen = theChunkLen * myNbChunks;
51
52     myBufferEnd = myBuffer + sizeof(myBuffer);
53     myBufferPtr = myBuffer + sizeof(myBuffer);
54     memset (myBuffer, 0, sizeof(myBuffer));
55
56     if (theChunkLen > sizeof(myBuffer))
57     {
58       Standard_ProgramError::Raise ("Internal error - chunk size is greater then preallocated buffer");
59     }
60   }
61
62   //! Return TRUE if amount of read bytes is equal to requested length of entire data.
63   bool IsDone() const
64   {
65     return myDataRead == myDataLen;
66   }
67
68   //! Read next chunk.
69   //! @return pointer to the chunk or NULL on error / end of reading buffer
70   template<typename Chunk_T, typename Stream_T>
71   Chunk_T* ReadChunk (Stream_T& theStream)
72   {
73     return reinterpret_cast<Chunk_T*> (readRawDataChunk (theStream));
74   }
75
76   //! Read next chunk.
77   //! @return pointer to the chunk or NULL on error / end of reading buffer
78   template<typename Stream_T>
79   char* ReadDataChunk (Stream_T& theStream)
80   {
81     return readRawDataChunk (theStream);
82   }
83
84 private:
85
86   //! Read next chunk.
87   //! @return pointer to the chunk or NULL on error / end of reading buffer
88   template<typename Stream_T>
89   char* readRawDataChunk (Stream_T& theStream)
90   {
91     myBufferPtr += myChunkLen;
92     if (myBufferPtr < myBufferEnd)
93     {
94       return myBufferPtr;
95     }
96
97     const int64_t aDataLeft = myDataLen - myDataRead;
98     if (aDataLeft == 0) // myDataLen should be multiple of myChunkLen
99     {
100       myBufferPtr = NULL;
101       return NULL;
102     }
103
104     const size_t aDataToRead = int64_t(myBufferLen) > aDataLeft ? size_t(aDataLeft) : myBufferLen;
105     if (!readStream (theStream, aDataToRead))
106     {
107       myBufferPtr = NULL;
108       return NULL;
109     }
110
111     myBufferPtr = myBuffer;
112     myBufferEnd = myBuffer + aDataToRead;
113     myDataRead += aDataToRead;
114     return myBufferPtr;
115   }
116
117   //! Read from stl stream.
118   bool readStream (std::istream& theStream,
119                    size_t theLen)
120   {
121     theStream.read (myBuffer, theLen);
122     return theStream.good();
123   }
124
125   //! Read from FILE stream.
126   bool readStream (FILE* theStream,
127                    size_t theLen)
128   {
129     return ::fread (myBuffer, 1, theLen, theStream) == theLen;
130   }
131
132 private:
133
134   char        myBuffer[4096]; //!< data cache
135   char*       myBufferPtr;    //!< current position within the buffer
136   const char* myBufferEnd;    //!< end of the buffer
137   int64_t     myDataLen;      //!< length of entire data to read
138   int64_t     myDataRead;     //!< amount of data already processed
139   size_t      myChunkLen;     //!< length of single chunk that caller would like to read (e.g. iterator increment)
140   size_t      myNbChunks;     //!< number of cached chunks
141   size_t      myBufferLen;    //!< effective length of the buffer to be read at once (multiple of chunk length)
142
143 };
144
145 #endif // _Standard_ReadBuffer_HeaderFile