// Copyright (c) 2017-2019 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement.. #ifndef _Standard_ReadBuffer_HeaderFile #define _Standard_ReadBuffer_HeaderFile #include "Standard_ProgramError.hxx" #include //! Auxiliary tool for buffered reading from input stream within chunks of constant size. class Standard_ReadBuffer { public: //! Constructor with initialization. Standard_ReadBuffer(int64_t theDataLen, size_t theChunkLen, bool theIsPartialPayload = false) : myBufferPtr(nullptr), myBufferEnd(nullptr), myDataLen(0), myDataRead(0), myChunkLen(0), myNbChunks(0), myBufferLen(0) { Init(theDataLen, theChunkLen, theIsPartialPayload); } //! Initialize the buffer. //! @param[in] theDataLen the full length of input data to read from stream. //! @param[in] theChunkLen the length of single chunk to read //! @param[in] theIsPartialPayload when FALSE, theDataLen will be automatically aligned to the //! multiple of theChunkLen; //! when TRUE, last chunk will be read from stream exactly till //! theDataLen allowing portion of chunk to be uninitialized //! (useful for interleaved data) void Init(int64_t theDataLen, size_t theChunkLen, bool theIsPartialPayload = false) { myDataRead = 0; if (theIsPartialPayload) { myDataLen = theDataLen; } else { myDataLen = theDataLen - theDataLen % int64_t(theChunkLen); } myChunkLen = theChunkLen; myNbChunks = sizeof(myBuffer) / theChunkLen; myBufferLen = theChunkLen * myNbChunks; myBufferEnd = myBuffer + sizeof(myBuffer); myBufferPtr = myBuffer + sizeof(myBuffer); memset(myBuffer, 0, sizeof(myBuffer)); if (theChunkLen > sizeof(myBuffer)) { throw Standard_ProgramError( "Internal error - chunk size is greater then preallocated buffer"); } } //! Return TRUE if amount of read bytes is equal to requested length of entire data. bool IsDone() const { return myDataRead == myDataLen; } //! Read next chunk. //! @return pointer to the chunk or NULL on error / end of reading buffer template Chunk_T* ReadChunk(Stream_T& theStream) { return reinterpret_cast(readRawDataChunk(theStream)); } //! Read next chunk. //! @return pointer to the chunk or NULL on error / end of reading buffer template char* ReadDataChunk(Stream_T& theStream) { return readRawDataChunk(theStream); } private: //! Read next chunk. //! @return pointer to the chunk or NULL on error / end of reading buffer template char* readRawDataChunk(Stream_T& theStream) { if (myBufferPtr == nullptr) { return nullptr; } myBufferPtr += myChunkLen; if (myBufferPtr < myBufferEnd) { return myBufferPtr; } const int64_t aDataLeft = myDataLen - myDataRead; if (aDataLeft <= 0) // myDataLen is normally multiple of myChunkLen, but can be smaller in // interleaved data { myBufferPtr = nullptr; return nullptr; } const size_t aDataToRead = int64_t(myBufferLen) > aDataLeft ? size_t(aDataLeft) : myBufferLen; if (!readStream(theStream, aDataToRead)) { myBufferPtr = nullptr; return nullptr; } myBufferPtr = myBuffer; myBufferEnd = myBuffer + aDataToRead; myDataRead += aDataToRead; return myBufferPtr; } //! Read from stl stream. bool readStream(std::istream& theStream, size_t theLen) { theStream.read(myBuffer, theLen); return theStream.good(); } //! Read from FILE stream. bool readStream(FILE* theStream, size_t theLen) { return ::fread(myBuffer, 1, theLen, theStream) == theLen; } private: char myBuffer[4096]; //!< data cache char* myBufferPtr; //!< current position within the buffer const char* myBufferEnd; //!< end of the buffer int64_t myDataLen; //!< length of entire data to read int64_t myDataRead; //!< amount of data already processed // clang-format off size_t myChunkLen; //!< length of single chunk that caller would like to read (e.g. iterator increment) size_t myNbChunks; //!< number of cached chunks size_t myBufferLen; //!< effective length of the buffer to be read at once (multiple of chunk length) // clang-format on }; #endif // _Standard_ReadBuffer_HeaderFile