rlm@1: // OutMemStream.cpp rlm@1: rlm@1: #include "StdAfx.h" rlm@1: rlm@1: #include "OutMemStream.h" rlm@1: rlm@1: void COutMemStream::Free() rlm@1: { rlm@1: Blocks.Free(_memManager); rlm@1: Blocks.LockMode = true; rlm@1: } rlm@1: rlm@1: void COutMemStream::Init() rlm@1: { rlm@1: WriteToRealStreamEvent.Reset(); rlm@1: _unlockEventWasSent = false; rlm@1: _realStreamMode = false; rlm@1: Free(); rlm@1: _curBlockPos = 0; rlm@1: _curBlockIndex = 0; rlm@1: } rlm@1: rlm@1: void COutMemStream::DetachData(CMemLockBlocks &blocks) rlm@1: { rlm@1: Blocks.Detach(blocks, _memManager); rlm@1: Free(); rlm@1: } rlm@1: rlm@1: rlm@1: HRESULT COutMemStream::WriteToRealStream() rlm@1: { rlm@1: RINOK(Blocks.WriteToStream(_memManager->GetBlockSize(), OutSeqStream)); rlm@1: Blocks.Free(_memManager); rlm@1: return S_OK; rlm@1: } rlm@1: rlm@1: STDMETHODIMP COutMemStream::Write(const void *data, UInt32 size, UInt32 *processedSize) rlm@1: { rlm@1: if (_realStreamMode) rlm@1: return OutSeqStream->Write(data, size, processedSize); rlm@1: if (processedSize != 0) rlm@1: *processedSize = 0; rlm@1: while(size != 0) rlm@1: { rlm@1: if ((int)_curBlockIndex < Blocks.Blocks.Size()) rlm@1: { rlm@1: Byte *p = (Byte *)Blocks.Blocks[(int)_curBlockIndex] + _curBlockPos; rlm@1: size_t curSize = _memManager->GetBlockSize() - _curBlockPos; rlm@1: if (size < curSize) rlm@1: curSize = size; rlm@1: memmove(p, data, curSize); rlm@1: if (processedSize != 0) rlm@1: *processedSize += (UInt32)curSize; rlm@1: data = (const void *)((const Byte *)data + curSize); rlm@1: size -= (UInt32)curSize; rlm@1: _curBlockPos += curSize; rlm@1: rlm@1: UInt64 pos64 = GetPos(); rlm@1: if (pos64 > Blocks.TotalSize) rlm@1: Blocks.TotalSize = pos64; rlm@1: if (_curBlockPos == _memManager->GetBlockSize()) rlm@1: { rlm@1: _curBlockIndex++; rlm@1: _curBlockPos = 0; rlm@1: } rlm@1: continue; rlm@1: } rlm@1: HANDLE events[3] = { StopWritingEvent, WriteToRealStreamEvent, /* NoLockEvent, */ _memManager->Semaphore }; rlm@1: DWORD waitResult = ::WaitForMultipleObjects((Blocks.LockMode ? 3 : 2), events, FALSE, INFINITE); rlm@1: switch (waitResult) rlm@1: { rlm@1: case (WAIT_OBJECT_0 + 0): rlm@1: return StopWriteResult; rlm@1: case (WAIT_OBJECT_0 + 1): rlm@1: { rlm@1: _realStreamMode = true; rlm@1: RINOK(WriteToRealStream()); rlm@1: UInt32 processedSize2; rlm@1: HRESULT res = OutSeqStream->Write(data, size, &processedSize2); rlm@1: if (processedSize != 0) rlm@1: *processedSize += processedSize2; rlm@1: return res; rlm@1: } rlm@1: /* rlm@1: case (WAIT_OBJECT_0 + 2): rlm@1: { rlm@1: // it has bug: no write. rlm@1: if (!Blocks.SwitchToNoLockMode(_memManager)) rlm@1: return E_FAIL; rlm@1: break; rlm@1: } rlm@1: */ rlm@1: case (WAIT_OBJECT_0 + 2): rlm@1: break; rlm@1: default: rlm@1: return E_FAIL; rlm@1: } rlm@1: Blocks.Blocks.Add(_memManager->AllocateBlock()); rlm@1: if (Blocks.Blocks.Back() == 0) rlm@1: return E_FAIL; rlm@1: } rlm@1: return S_OK; rlm@1: } rlm@1: rlm@1: STDMETHODIMP COutMemStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) rlm@1: { rlm@1: if (_realStreamMode) rlm@1: { rlm@1: if (!OutStream) rlm@1: return E_FAIL; rlm@1: return OutStream->Seek(offset, seekOrigin, newPosition); rlm@1: } rlm@1: if (seekOrigin == STREAM_SEEK_CUR) rlm@1: { rlm@1: if (offset != 0) rlm@1: return E_NOTIMPL; rlm@1: } rlm@1: else if (seekOrigin == STREAM_SEEK_SET) rlm@1: { rlm@1: if (offset != 0) rlm@1: return E_NOTIMPL; rlm@1: _curBlockIndex = 0; rlm@1: _curBlockPos = 0; rlm@1: } rlm@1: else rlm@1: return E_NOTIMPL; rlm@1: if (newPosition != 0) rlm@1: *newPosition = GetPos(); rlm@1: return S_OK; rlm@1: } rlm@1: rlm@1: STDMETHODIMP COutMemStream::SetSize(Int64 newSize) rlm@1: { rlm@1: if (_realStreamMode) rlm@1: { rlm@1: if (!OutStream) rlm@1: return E_FAIL; rlm@1: return OutStream->SetSize(newSize); rlm@1: } rlm@1: Blocks.TotalSize = newSize; rlm@1: return S_OK; rlm@1: }