1 // OutMemStream.cpp
2 
3 #include "StdAfx.h"
4 
5 // #include <stdio.h>
6 
7 #include "OutMemStream.h"
8 
Free()9 void COutMemStream::Free()
10 {
11   Blocks.Free(_memManager);
12   Blocks.LockMode = true;
13 }
14 
Init()15 void COutMemStream::Init()
16 {
17   WriteToRealStreamEvent.Reset();
18   _unlockEventWasSent = false;
19   _realStreamMode = false;
20   Free();
21   _curBlockPos = 0;
22   _curBlockIndex = 0;
23 }
24 
DetachData(CMemLockBlocks & blocks)25 void COutMemStream::DetachData(CMemLockBlocks &blocks)
26 {
27   Blocks.Detach(blocks, _memManager);
28   Free();
29 }
30 
31 
WriteToRealStream()32 HRESULT COutMemStream::WriteToRealStream()
33 {
34   RINOK(Blocks.WriteToStream(_memManager->GetBlockSize(), OutSeqStream));
35   Blocks.Free(_memManager);
36   return S_OK;
37 }
38 
39 
Write(const void * data,UInt32 size,UInt32 * processedSize)40 STDMETHODIMP COutMemStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
41 {
42   if (_realStreamMode)
43     return OutSeqStream->Write(data, size, processedSize);
44   if (processedSize)
45     *processedSize = 0;
46   while (size != 0)
47   {
48     if (_curBlockIndex < Blocks.Blocks.Size())
49     {
50       Byte *p = (Byte *)Blocks.Blocks[_curBlockIndex] + _curBlockPos;
51       size_t curSize = _memManager->GetBlockSize() - _curBlockPos;
52       if (size < curSize)
53         curSize = size;
54       memcpy(p, data, curSize);
55       if (processedSize)
56         *processedSize += (UInt32)curSize;
57       data = (const void *)((const Byte *)data + curSize);
58       size -= (UInt32)curSize;
59       _curBlockPos += curSize;
60 
61       UInt64 pos64 = GetPos();
62       if (pos64 > Blocks.TotalSize)
63         Blocks.TotalSize = pos64;
64       if (_curBlockPos == _memManager->GetBlockSize())
65       {
66         _curBlockIndex++;
67         _curBlockPos = 0;
68       }
69       continue;
70     }
71 
72     const NWindows::NSynchronization::CHandle_WFMO events[3] =
73       { StopWritingEvent, WriteToRealStreamEvent, /* NoLockEvent, */ _memManager->Semaphore };
74     const DWORD waitResult = NWindows::NSynchronization::WaitForMultiObj_Any_Infinite(
75         ((Blocks.LockMode /* && _memManager->Semaphore.IsCreated() */) ? 3 : 2), events);
76 
77     // printf("\n 1- outMemStream %d\n", waitResult - WAIT_OBJECT_0);
78 
79     switch (waitResult)
80     {
81       case (WAIT_OBJECT_0 + 0):
82         return StopWriteResult;
83       case (WAIT_OBJECT_0 + 1):
84       {
85         _realStreamMode = true;
86         RINOK(WriteToRealStream());
87         UInt32 processedSize2;
88         HRESULT res = OutSeqStream->Write(data, size, &processedSize2);
89         if (processedSize)
90           *processedSize += processedSize2;
91         return res;
92       }
93       case (WAIT_OBJECT_0 + 2):
94       {
95         // it has bug: no write.
96         /*
97         if (!Blocks.SwitchToNoLockMode(_memManager))
98           return E_FAIL;
99         */
100         break;
101       }
102       default:
103       {
104         if (waitResult == WAIT_FAILED)
105         {
106           DWORD res = ::GetLastError();
107           if (res != 0)
108             return HRESULT_FROM_WIN32(res);
109         }
110         return E_FAIL;
111       }
112     }
113     void *p = _memManager->AllocateBlock();
114     if (!p)
115       return E_FAIL;
116     Blocks.Blocks.Add(p);
117   }
118   return S_OK;
119 }
120 
Seek(Int64 offset,UInt32 seekOrigin,UInt64 * newPosition)121 STDMETHODIMP COutMemStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
122 {
123   if (_realStreamMode)
124   {
125     if (!OutStream)
126       return E_FAIL;
127     return OutStream->Seek(offset, seekOrigin, newPosition);
128   }
129   if (seekOrigin == STREAM_SEEK_CUR)
130   {
131     if (offset != 0)
132       return E_NOTIMPL;
133   }
134   else if (seekOrigin == STREAM_SEEK_SET)
135   {
136     if (offset != 0)
137       return E_NOTIMPL;
138     _curBlockIndex = 0;
139     _curBlockPos = 0;
140   }
141   else
142     return E_NOTIMPL;
143   if (newPosition)
144     *newPosition = GetPos();
145   return S_OK;
146 }
147 
SetSize(UInt64 newSize)148 STDMETHODIMP COutMemStream::SetSize(UInt64 newSize)
149 {
150   if (_realStreamMode)
151   {
152     if (!OutStream)
153       return E_FAIL;
154     return OutStream->SetSize(newSize);
155   }
156   Blocks.TotalSize = newSize;
157   return S_OK;
158 }
159