diff options
author | Max Horn | 2008-07-29 17:42:19 +0000 |
---|---|---|
committer | Max Horn | 2008-07-29 17:42:19 +0000 |
commit | aaa4d104f7eb4094ec6bd69ef2d44f80edd61aa4 (patch) | |
tree | f515c39e140b5ddd37f46060578d3b41759a15e3 /common | |
parent | 0a95a4814cbc9453f3af7abb46d6998409d96f53 (diff) | |
download | scummvm-rg350-aaa4d104f7eb4094ec6bd69ef2d44f80edd61aa4.tar.gz scummvm-rg350-aaa4d104f7eb4094ec6bd69ef2d44f80edd61aa4.tar.bz2 scummvm-rg350-aaa4d104f7eb4094ec6bd69ef2d44f80edd61aa4.zip |
Added two new classes, BufferedReadStream & BufferedSeekableReadStream, as proposed on scummvm-devel
svn-id: r33419
Diffstat (limited to 'common')
-rw-r--r-- | common/stream.cpp | 81 | ||||
-rw-r--r-- | common/stream.h | 47 |
2 files changed, 126 insertions, 2 deletions
diff --git a/common/stream.cpp b/common/stream.cpp index 61166fd451..d068e2fc1e 100644 --- a/common/stream.cpp +++ b/common/stream.cpp @@ -242,4 +242,85 @@ void SeekableSubReadStream::seek(int32 offset, int whence) { _parentStream->seek(_pos); } +BufferedReadStream::BufferedReadStream(ReadStream *parentStream, uint32 bufSize, bool disposeParentStream) + : _parentStream(parentStream), + _bufSize(bufSize), + _disposeParentStream(disposeParentStream) { + + assert(parentStream); + _buf = new byte[_bufSize]; + assert(_buf); + _pos = _bufSize = bufSize; +} +BufferedReadStream::~BufferedReadStream() { + if (_disposeParentStream) + delete _parentStream; + delete _buf; +} + +uint32 BufferedReadStream::read(void *dataPtr, uint32 dataSize) { + uint32 alreadyRead = 0; + const uint32 bufBytesLeft = _bufSize - _pos; + + // Check whether the data left in the buffer suffices.... + if (dataSize > bufBytesLeft) { + // Nope, we need to read more data + + // First, flush the buffer, if it is non-empty + if (0 < bufBytesLeft) { + memcpy(dataPtr, _buf + _pos, bufBytesLeft); + _pos = _bufSize; + alreadyRead += bufBytesLeft; + dataPtr = (byte *)dataPtr + bufBytesLeft; + dataSize -= bufBytesLeft; + } + + // At this point the buffer is empty. Now if the read request + // exceeds the buffer size, just satisfy it directly. + if (dataSize > _bufSize) + return alreadyRead + _parentStream->read(dataPtr, dataSize); + + // Refill the buffer. + uint32 bytesRead = _parentStream->read(_buf, _bufSize); + _pos = 0; + + // If we didn't read as many bytes as requested, the reason + // is EOF or an error. In that case we truncate the buffer + // size, as well as the number of bytes we are going to + // return to the caller. + if (_bufSize > bytesRead) { + _bufSize = bytesRead; + if (dataSize > bytesRead) + dataSize = bytesRead; + } + } + + // Satisfy the request from the buffer + memcpy(dataPtr, _buf + _pos, dataSize); + _pos += dataSize; + return alreadyRead + dataSize; +} + +BufferedSeekableReadStream::BufferedSeekableReadStream(SeekableReadStream *parentStream, uint32 bufSize, bool disposeParentStream) + : BufferedReadStream(parentStream, bufSize, disposeParentStream), + _parentStream(parentStream) { +} + +void BufferedSeekableReadStream::seek(int32 offset, int whence) { + // If it is a "local" seek, we may get away with "seeking" around + // in the buffer only. + // Note: We could try to handle SEEK_END and SEEK_SET, too, but + // since they are rarely used, it seems not worth the effort. + if (whence == SEEK_CUR && (int)_pos + offset >= 0 && _pos + offset <= _bufSize) { + _pos += offset; + } else { + // Seek was not local enough, so we reset the buffer and + // just seeks normally in the parent stream. + if (whence == SEEK_CUR) + offset -= (_bufSize - _pos); + _pos = _bufSize; + _parentStream->seek(offset, whence); + } +} + } // End of namespace Common diff --git a/common/stream.h b/common/stream.h index 4cf5fae114..9f1e091604 100644 --- a/common/stream.h +++ b/common/stream.h @@ -350,15 +350,17 @@ public: class SubReadStream : virtual public ReadStream { protected: ReadStream *_parentStream; + bool _disposeParentStream; uint32 _pos; uint32 _end; - bool _disposeParentStream; public: SubReadStream(ReadStream *parentStream, uint32 end, bool disposeParentStream = false) : _parentStream(parentStream), _pos(0), _end(end), - _disposeParentStream(disposeParentStream) {} + _disposeParentStream(disposeParentStream) { + assert(parentStream); + } ~SubReadStream() { if (_disposeParentStream) delete _parentStream; } @@ -414,6 +416,47 @@ public: } }; +/** + * Wrapper class which adds buffering to any given ReadStream. + * Users can specify how big the buffer should be, and whether the + * wrapped stream should be disposed when the wrapper is disposed. + */ +class BufferedReadStream : virtual public ReadStream { +protected: + ReadStream *_parentStream; + bool _disposeParentStream; + byte *_buf; + uint32 _pos; + uint32 _bufSize; + +public: + BufferedReadStream(ReadStream *parentStream, uint32 bufSize, bool disposeParentStream = false); + ~BufferedReadStream(); + + virtual bool eos() const { return (_pos == _bufSize) && _parentStream->eos(); } + virtual bool ioFailed() const { return _parentStream->ioFailed(); } + virtual void clearIOFailed() { _parentStream->clearIOFailed(); } + + virtual uint32 read(void *dataPtr, uint32 dataSize); +}; + +/** + * Wrapper class which adds buffering to any given SeekableReadStream. + * @see BufferedReadStream + */ +class BufferedSeekableReadStream : public BufferedReadStream, public SeekableReadStream { +protected: + SeekableReadStream *_parentStream; +public: + BufferedSeekableReadStream(SeekableReadStream *parentStream, uint32 bufSize, bool disposeParentStream = false); + + virtual uint32 pos() const { return _parentStream->pos() - (_bufSize - _pos); } + virtual uint32 size() const { return _parentStream->size(); } + + virtual void seek(int32 offset, int whence = SEEK_SET); +}; + + /** * Simple memory based 'stream', which implements the ReadStream interface for |