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