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