diff options
Diffstat (limited to 'lib/common/ReadGatherStream.cpp')
-rwxr-xr-x | lib/common/ReadGatherStream.cpp | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/lib/common/ReadGatherStream.cpp b/lib/common/ReadGatherStream.cpp new file mode 100755 index 00000000..9ccc3a54 --- /dev/null +++ b/lib/common/ReadGatherStream.cpp @@ -0,0 +1,262 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: ReadGatherStream.cpp +// Purpose: Build a stream (for reading only) out of a number of other streams. +// Created: 10/12/03 +// +// -------------------------------------------------------------------------- + +#include "Box.h" + +#include "ReadGatherStream.h" +#include "CommonException.h" + +#include "MemLeakFindOn.h" + +// -------------------------------------------------------------------------- +// +// Function +// Name: ReadGatherStream::ReadGatherStream(bool) +// Purpose: Constructor. Args says whether or not all the component streams will be deleted when this +// object is deleted. +// Created: 10/12/03 +// +// -------------------------------------------------------------------------- +ReadGatherStream::ReadGatherStream(bool DeleteComponentStreamsOnDestruction) + : mDeleteComponentStreamsOnDestruction(DeleteComponentStreamsOnDestruction), + mCurrentPosition(0), + mTotalSize(0), + mCurrentBlock(0), + mPositionInCurrentBlock(0), + mSeekDoneForCurrent(false) +{ +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: ReadGatherStream::~ReadGatherStream() +// Purpose: Destructor. Will delete all the stream objects, if required. +// Created: 10/12/03 +// +// -------------------------------------------------------------------------- +ReadGatherStream::~ReadGatherStream() +{ + // Delete compoenent streams? + if(mDeleteComponentStreamsOnDestruction) + { + for(unsigned int l = 0; l < mComponents.size(); ++l) + { + delete mComponents[l]; + } + } +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: ReadGatherStream::AddComponent(IOStream *) +// Purpose: Add a component to this stream, returning the index of this component +// in the internal list. Use this with AddBlock() +// Created: 10/12/03 +// +// -------------------------------------------------------------------------- +int ReadGatherStream::AddComponent(IOStream *pStream) +{ + ASSERT(pStream != 0); + + // Just add the component to the list, returning it's index. + int index = mComponents.size(); + mComponents.push_back(pStream); + return index; +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: ReadGatherStream::AddBlock(int, pos_type, bool, pos_type) +// Purpose: Add a block to the list of blocks being gathered into one stream. +// Length is length of block to read from this component, Seek == true +// if a seek is required, and if true, SeekTo is the position (absolute) +// in the stream to be seeked to when this block is required. +// Created: 10/12/03 +// +// -------------------------------------------------------------------------- +void ReadGatherStream::AddBlock(int Component, pos_type Length, bool Seek, pos_type SeekTo) +{ + // Check block + if(Component < 0 || Component >= (int)mComponents.size() || Length < 0 || SeekTo < 0) + { + THROW_EXCEPTION(CommonException, ReadGatherStreamAddingBadBlock); + } + + // Add to list + Block b; + b.mLength = Length; + b.mSeekTo = SeekTo; + b.mComponent = Component; + b.mSeek = Seek; + + mBlocks.push_back(b); + + // And update the total size + mTotalSize += Length; +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: ReadGatherStream::Read(void *, int, int) +// Purpose: As interface. +// Created: 10/12/03 +// +// -------------------------------------------------------------------------- +int ReadGatherStream::Read(void *pBuffer, int NBytes, int Timeout) +{ + int bytesToRead = NBytes; + uint8_t *buffer = (uint8_t*)pBuffer; + + while(bytesToRead > 0) + { + // Done? + if(mCurrentBlock >= mBlocks.size()) + { + // Stop now, as have finished the last block + return NBytes - bytesToRead; + } + + // Seek? + if(mPositionInCurrentBlock == 0 && mBlocks[mCurrentBlock].mSeek && !mSeekDoneForCurrent) + { + // Do seeks in this manner so that seeks are done regardless of whether the block + // has length > 0, and it will only be done once, and at as late a stage as possible. + + mComponents[mBlocks[mCurrentBlock].mComponent]->Seek(mBlocks[mCurrentBlock].mSeekTo, IOStream::SeekType_Absolute); + + mSeekDoneForCurrent = true; + } + + // Anything in the current block? + if(mPositionInCurrentBlock < mBlocks[mCurrentBlock].mLength) + { + // Read! + int s = mBlocks[mCurrentBlock].mLength - mPositionInCurrentBlock; + if(s > bytesToRead) s = bytesToRead; + + int r = mComponents[mBlocks[mCurrentBlock].mComponent]->Read(buffer, s, Timeout); + + // update variables + mPositionInCurrentBlock += r; + buffer += r; + bytesToRead -= r; + mCurrentPosition += r; + + if(r != s) + { + // Stream returned less than requested. To avoid blocking when not necessary, + // return now. + return NBytes - bytesToRead; + } + } + else + { + // Move to next block + ++mCurrentBlock; + mPositionInCurrentBlock = 0; + mSeekDoneForCurrent = false; + } + } + + return NBytes - bytesToRead; +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: ReadGatherStream::GetPosition() +// Purpose: As interface +// Created: 10/12/03 +// +// -------------------------------------------------------------------------- +IOStream::pos_type ReadGatherStream::GetPosition() const +{ + return mCurrentPosition; +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: ReadGatherStream::BytesLeftToRead() +// Purpose: As interface +// Created: 10/12/03 +// +// -------------------------------------------------------------------------- +IOStream::pos_type ReadGatherStream::BytesLeftToRead() +{ + return mTotalSize - mCurrentPosition; +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: ReadGatherStream::Write(const void *, int) +// Purpose: As interface. +// Created: 10/12/03 +// +// -------------------------------------------------------------------------- +void ReadGatherStream::Write(const void *pBuffer, int NBytes) +{ + THROW_EXCEPTION(CommonException, CannotWriteToReadGatherStream); +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: ReadGatherStream::StreamDataLeft() +// Purpose: As interface. +// Created: 10/12/03 +// +// -------------------------------------------------------------------------- +bool ReadGatherStream::StreamDataLeft() +{ + if(mCurrentBlock >= mBlocks.size()) + { + // Done all the blocks + return false; + } + + if(mCurrentBlock == (mBlocks.size() - 1) + && mPositionInCurrentBlock >= mBlocks[mCurrentBlock].mLength) + { + // Are on the last block, and have got all the data from it. + return false; + } + + // Otherwise, there's more data to be read + return true; +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: ReadGatherStream::StreamClosed() +// Purpose: As interface. But the stream is always closed. +// Created: 10/12/03 +// +// -------------------------------------------------------------------------- +bool ReadGatherStream::StreamClosed() +{ + return true; +} + + |