0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[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                        bool theIsPartialPayload = false)
30   : myBufferPtr(NULL),
31     myBufferEnd(NULL),
32     myDataLen  (0),
33     myDataRead (0),
34     myChunkLen (0),
35     myNbChunks (0),
36     myBufferLen(0)
37   {
38     Init (theDataLen, theChunkLen, theIsPartialPayload);
39   }
40
41   //! Initialize the buffer.
42   //! @param theDataLen  [in] the full length of input data to read from stream.
43   //! @param theChunkLen [in] the length of single chunk to read
44   //! @param theIsPartialPayload [in] when FALSE, theDataLen will be automatically aligned to the multiple of theChunkLen;
45   //!                                 when TRUE, last chunk will be read from stream exactly till theDataLen
46   //!                                 allowing portion of chunk to be uninitialized (useful for interleaved data)
47   void Init (int64_t theDataLen,
48              size_t  theChunkLen,
49              bool theIsPartialPayload = false)
50   {
51     myDataRead  = 0;
52     if (theIsPartialPayload)
53     {
54       myDataLen = theDataLen;
55     }
56     else
57     {
58       myDataLen = theDataLen - theDataLen % int64_t(theChunkLen);
59     }
60     myChunkLen  = theChunkLen;
61     myNbChunks  = sizeof(myBuffer) / theChunkLen;
62     myBufferLen = theChunkLen * myNbChunks;
63
64     myBufferEnd = myBuffer + sizeof(myBuffer);
65     myBufferPtr = myBuffer + sizeof(myBuffer);
66     memset (myBuffer, 0, sizeof(myBuffer));
67
68     if (theChunkLen > sizeof(myBuffer))
69     {
70       Standard_ProgramError::Raise ("Internal error - chunk size is greater then preallocated buffer");
71     }
72   }
73
74   //! Return TRUE if amount of read bytes is equal to requested length of entire data.
75   bool IsDone() const
76   {
77     return myDataRead == myDataLen;
78   }
79
80   //! Read next chunk.
81   //! @return pointer to the chunk or NULL on error / end of reading buffer
82   template<typename Chunk_T, typename Stream_T>
83   Chunk_T* ReadChunk (Stream_T& theStream)
84   {
85     return reinterpret_cast<Chunk_T*> (readRawDataChunk (theStream));
86   }
87
88   //! Read next chunk.
89   //! @return pointer to the chunk or NULL on error / end of reading buffer
90   template<typename Stream_T>
91   char* ReadDataChunk (Stream_T& theStream)
92   {
93     return readRawDataChunk (theStream);
94   }
95
96 private:
97
98   //! Read next chunk.
99   //! @return pointer to the chunk or NULL on error / end of reading buffer
100   template<typename Stream_T>
101   char* readRawDataChunk (Stream_T& theStream)
102   {
103     if (myBufferPtr == NULL)
104     {
105       return NULL;
106     }
107
108     myBufferPtr += myChunkLen;
109     if (myBufferPtr < myBufferEnd)
110     {
111       return myBufferPtr;
112     }
113
114     const int64_t aDataLeft = myDataLen - myDataRead;
115     if (aDataLeft <= 0) // myDataLen is normally multiple of myChunkLen, but can be smaller in interleaved data
116     {
117       myBufferPtr = NULL;
118       return NULL;
119     }
120
121     const size_t aDataToRead = int64_t(myBufferLen) > aDataLeft ? size_t(aDataLeft) : myBufferLen;
122     if (!readStream (theStream, aDataToRead))
123     {
124       myBufferPtr = NULL;
125       return NULL;
126     }
127
128     myBufferPtr = myBuffer;
129     myBufferEnd = myBuffer + aDataToRead;
130     myDataRead += aDataToRead;
131     return myBufferPtr;
132   }
133
134   //! Read from stl stream.
135   bool readStream (std::istream& theStream,
136                    size_t theLen)
137   {
138     theStream.read (myBuffer, theLen);
139     return theStream.good();
140   }
141
142   //! Read from FILE stream.
143   bool readStream (FILE* theStream,
144                    size_t theLen)
145   {
146     return ::fread (myBuffer, 1, theLen, theStream) == theLen;
147   }
148
149 private:
150
151   char        myBuffer[4096]; //!< data cache
152   char*       myBufferPtr;    //!< current position within the buffer
153   const char* myBufferEnd;    //!< end of the buffer
154   int64_t     myDataLen;      //!< length of entire data to read
155   int64_t     myDataRead;     //!< amount of data already processed
156   size_t      myChunkLen;     //!< length of single chunk that caller would like to read (e.g. iterator increment)
157   size_t      myNbChunks;     //!< number of cached chunks
158   size_t      myBufferLen;    //!< effective length of the buffer to be read at once (multiple of chunk length)
159
160 };
161
162 #endif // _Standard_ReadBuffer_HeaderFile