summaryrefslogtreecommitdiff
path: root/lib/common/ReadGatherStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/common/ReadGatherStream.cpp')
-rwxr-xr-xlib/common/ReadGatherStream.cpp262
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;
+}
+
+