diff options
Diffstat (limited to 'CPP/7zip/Common/InMemStream.cpp')
-rwxr-xr-x | CPP/7zip/Common/InMemStream.cpp | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/CPP/7zip/Common/InMemStream.cpp b/CPP/7zip/Common/InMemStream.cpp new file mode 100755 index 00000000..036ef3bd --- /dev/null +++ b/CPP/7zip/Common/InMemStream.cpp @@ -0,0 +1,222 @@ +// InMemStream.cpp + +#include "StdAfx.h" + +#include <stdio.h> + +#include "Windows/Thread.h" + +#include "InMemStream.h" +#include "../../Common/Defs.h" + +void CStreamInfo::Free(IInMemStreamMtCallback *callback) +{ + for (int i = 0; i < Blocks.Size(); i++) + { + callback->FreeBlock(Blocks[i]); + Blocks[i] = 0; + } +} + +bool CInMemStreamMt::Create(int numSubStreams, UInt64 subStreamSize) +{ + Free(); + _subStreamSize = subStreamSize; + size_t blockSize = Callback->GetBlockSize(); + for (int i = 0; i < numSubStreams; i++) + { + _streams.Add(CStreamInfo()); + CStreamInfo &blocks = _streams.Back(); + blocks.Create(); + for (UInt64 j = 0; (UInt64)j * blockSize < _subStreamSize; j++) + blocks.Blocks.Add(0); + } + if (!_streamIndexAllocator.AllocateList(numSubStreams)) + return false; + return true; +} + +void CInMemStreamMt::Free() +{ + while(_streams.Size() > 0) + { + _streams.Back().Free(Callback); + _streams.DeleteBack(); + } +} + +HRESULT CInMemStreamMt::Read() +{ + for (;;) + { + // printf("\n_streamIndexAllocator.AllocateItem\n"); + int index = _streamIndexAllocator.AllocateItem(); + /* + if (_stopReading) + return E_ABORT; + */ + // printf("\nread Index = %d\n", index); + CStreamInfo &blocks = _streams[index]; + blocks.Init(); + Callback->AddStreamIndexToQueue(index); + + for (;;) + { + const Byte *p = (const Byte *)blocks.Blocks[blocks.LastBlockIndex]; + if (p == 0) + { + void **pp = &blocks.Blocks[blocks.LastBlockIndex]; + HRESULT res = Callback->AllocateBlock(pp); + p = (const Byte *)*pp; + RINOK(res); + if (p == 0) + return E_FAIL; + } + size_t blockSize = Callback->GetBlockSize(); + UInt32 curSize = (UInt32)(blockSize - blocks.LastBlockPos); + UInt32 realProcessedSize; + UInt64 pos64 = (UInt64)blocks.LastBlockIndex * blockSize + blocks.LastBlockPos; + if (curSize > _subStreamSize - pos64) + curSize = (UInt32)(_subStreamSize - pos64); + RINOK(_stream->Read((void *)(p + blocks.LastBlockPos), curSize, &realProcessedSize)); + + blocks.Cs->Enter(); + if (realProcessedSize == 0) + { + blocks.StreamWasFinished = true; + blocks.CanReadEvent->Set(); + blocks.Cs->Leave(); + + Callback->AddStreamIndexToQueue(-1); + return S_OK; + } + + blocks.LastBlockPos += realProcessedSize; + if (blocks.LastBlockPos == blockSize) + { + blocks.LastBlockPos = 0; + blocks.LastBlockIndex++; + } + pos64 += realProcessedSize; + if (pos64 >= _subStreamSize) + blocks.StreamWasFinished = true; + blocks.CanReadEvent->Set(); + blocks.Cs->Leave(); + if (pos64 >= _subStreamSize) + break; + } + } +} + +static DWORD WINAPI CoderThread(void *threadCoderInfo) +{ + ((CInMemStreamMt *)threadCoderInfo)->ReadResult = ((CInMemStreamMt *)threadCoderInfo)->Read(); + return 0; +} + +bool CInMemStreamMt::StartReadThread() +{ + // _stopReading = false; + NWindows::CThread Thread; + return Thread.Create(CoderThread, this); +} + +void CInMemStreamMt::FreeSubStream(int subStreamIndex) +{ + // printf("\nFreeSubStream\n"); + _streams[subStreamIndex].Free(Callback); + _streamIndexAllocator.FreeItem(subStreamIndex); + // printf("\nFreeSubStream end\n"); +} + +HRESULT CInMemStreamMt::ReadSubStream(int subStreamIndex, void *data, UInt32 size, UInt32 *processedSize, bool keepData) +{ + if (processedSize != NULL) + *processedSize = 0; + CStreamInfo &blocks = _streams[subStreamIndex]; + while (size > 0) + { + if (blocks.CurBlockPos == Callback->GetBlockSize()) + { + blocks.CurBlockPos = 0; + blocks.CurBlockIndex++; + } + UInt32 curSize; + UInt32 curPos = blocks.CurBlockPos; + + blocks.Cs->Enter(); + if (blocks.CurBlockIndex == blocks.LastBlockIndex) + { + curSize = blocks.LastBlockPos - curPos; + if (curSize == 0) + { + if (blocks.StreamWasFinished) + { + blocks.Cs->Leave(); + void *p = blocks.Blocks[blocks.CurBlockIndex]; + if (p != 0 && !keepData) + { + Callback->FreeBlock(p); + blocks.Blocks[blocks.CurBlockIndex] = 0; + } + return S_OK; + } + blocks.CanReadEvent->Reset(); + blocks.Cs->Leave(); + // printf("\nBlock Lock\n"); + blocks.CanReadEvent->Lock(); + // printf("\nAfter Lock\n"); + if (blocks.ExitResult != S_OK) + return blocks.ExitResult; + continue; + } + } + else + curSize = Callback->GetBlockSize() - curPos; + blocks.Cs->Leave(); + + if (curSize > size) + curSize = size; + void *p = blocks.Blocks[blocks.CurBlockIndex]; + memmove(data, (const Byte *)p + curPos, curSize); + data = (void *)((Byte *)data + curSize); + size -= curSize; + if (processedSize != NULL) + *processedSize += curSize; + curPos += curSize; + + bool needFree = false; + blocks.CurBlockPos = curPos; + + if (curPos == Callback->GetBlockSize()) + needFree = true; + blocks.Cs->Enter(); + if (blocks.CurBlockIndex == blocks.LastBlockIndex && + blocks.CurBlockPos == blocks.LastBlockPos && + blocks.StreamWasFinished) + needFree = true; + blocks.Cs->Leave(); + + if (needFree && !keepData) + { + Callback->FreeBlock(p); + blocks.Blocks[blocks.CurBlockIndex] = 0; + } + return S_OK; + } + return S_OK; +} + +STDMETHODIMP CInMemStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 realProcessedSize; + HRESULT result = mtStream->ReadSubStream(Index, data, size, &realProcessedSize, _keepData); + if (processedSize != NULL) + *processedSize = realProcessedSize; + if (realProcessedSize != 0) + { + // printf("\ns = %d\n", Index); + } + _size += realProcessedSize; + return result; +} |