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