1 // HandlerCont.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../Common/ComTry.h"
6
7 #include "../Common/LimitedStreams.h"
8 #include "../Common/ProgressUtils.h"
9 #include "../Common/StreamUtils.h"
10
11 #include "../Compress/CopyCoder.h"
12
13 #include "HandlerCont.h"
14
15 namespace NArchive {
16
17 namespace NExt {
18 API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size);
19 }
20
Z7_COM7F_IMF(CHandlerCont::Extract (const UInt32 * indices,UInt32 numItems,Int32 testMode,IArchiveExtractCallback * extractCallback))21 Z7_COM7F_IMF(CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems,
22 Int32 testMode, IArchiveExtractCallback *extractCallback))
23 {
24 COM_TRY_BEGIN
25 const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
26 if (allFilesMode)
27 {
28 RINOK(GetNumberOfItems(&numItems))
29 }
30 if (numItems == 0)
31 return S_OK;
32 UInt64 totalSize = 0;
33 UInt32 i;
34 for (i = 0; i < numItems; i++)
35 {
36 UInt64 pos, size;
37 GetItem_ExtractInfo(allFilesMode ? i : indices[i], pos, size);
38 totalSize += size;
39 }
40 RINOK(extractCallback->SetTotal(totalSize))
41
42 totalSize = 0;
43
44 CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
45 lps->Init(extractCallback, false);
46 CMyComPtr2_Create<ISequentialInStream, CLimitedSequentialInStream> streamSpec;
47 streamSpec->SetStream(_stream);
48 CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
49
50 for (i = 0;; i++)
51 {
52 lps->InSize = totalSize;
53 lps->OutSize = totalSize;
54 RINOK(lps->SetCur())
55 if (i >= numItems)
56 break;
57
58 CMyComPtr<ISequentialOutStream> outStream;
59 const Int32 askMode = testMode ?
60 NExtract::NAskMode::kTest :
61 NExtract::NAskMode::kExtract;
62 const UInt32 index = allFilesMode ? i : indices[i];
63
64 RINOK(extractCallback->GetStream(index, &outStream, askMode))
65
66 UInt64 pos, size;
67 int opRes = GetItem_ExtractInfo(index, pos, size);
68 totalSize += size;
69 if (!testMode && !outStream)
70 continue;
71
72 RINOK(extractCallback->PrepareOperation(askMode))
73
74 if (opRes == NExtract::NOperationResult::kOK)
75 {
76 RINOK(InStream_SeekSet(_stream, pos))
77 streamSpec->Init(size);
78
79 RINOK(copyCoder.Interface()->Code(streamSpec, outStream, NULL, NULL, lps))
80
81 opRes = NExtract::NOperationResult::kDataError;
82 if (copyCoder->TotalSize == size)
83 opRes = NExtract::NOperationResult::kOK;
84 else if (copyCoder->TotalSize < size)
85 opRes = NExtract::NOperationResult::kUnexpectedEnd;
86 }
87
88 outStream.Release();
89 RINOK(extractCallback->SetOperationResult(opRes))
90 }
91
92 return S_OK;
93 COM_TRY_END
94 }
95
Z7_COM7F_IMF(CHandlerCont::GetStream (UInt32 index,ISequentialInStream ** stream))96 Z7_COM7F_IMF(CHandlerCont::GetStream(UInt32 index, ISequentialInStream **stream))
97 {
98 COM_TRY_BEGIN
99 *stream = NULL;
100 UInt64 pos, size;
101 if (GetItem_ExtractInfo(index, pos, size) != NExtract::NOperationResult::kOK)
102 return S_FALSE;
103 return CreateLimitedInStream(_stream, pos, size, stream);
104 COM_TRY_END
105 }
106
107
108
CHandlerImg()109 CHandlerImg::CHandlerImg()
110 {
111 Clear_HandlerImg_Vars();
112 }
113
Z7_COM7F_IMF(CHandlerImg::Seek (Int64 offset,UInt32 seekOrigin,UInt64 * newPosition))114 Z7_COM7F_IMF(CHandlerImg::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
115 {
116 switch (seekOrigin)
117 {
118 case STREAM_SEEK_SET: break;
119 case STREAM_SEEK_CUR: offset += _virtPos; break;
120 case STREAM_SEEK_END: offset += _size; break;
121 default: return STG_E_INVALIDFUNCTION;
122 }
123 if (offset < 0)
124 {
125 if (newPosition)
126 *newPosition = _virtPos;
127 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
128 }
129 _virtPos = (UInt64)offset;
130 if (newPosition)
131 *newPosition = (UInt64)offset;
132 return S_OK;
133 }
134
135 static const Byte k_GDP_Signature[] =
136 { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 };
137 // static const Byte k_Ext_Signature[] = { 0x53, 0xEF };
138 // static const unsigned k_Ext_Signature_offset = 0x438;
139
GetImgExt(ISequentialInStream * stream)140 static const char *GetImgExt(ISequentialInStream *stream)
141 {
142 // const size_t kHeaderSize_for_Ext = (1 << 11); // for ext
143 const size_t kHeaderSize = 2 << 12; // for 4 KB sector GPT
144 Byte buf[kHeaderSize];
145 size_t processed = kHeaderSize;
146 if (ReadStream(stream, buf, &processed) == S_OK)
147 {
148 if (processed >= kHeaderSize)
149 if (buf[0x1FE] == 0x55 && buf[0x1FF] == 0xAA)
150 {
151 for (unsigned k = (1 << 9); k <= (1u << 12); k <<= 3)
152 if (memcmp(buf + k, k_GDP_Signature, sizeof(k_GDP_Signature)) == 0)
153 return "gpt";
154 return "mbr";
155 }
156 if (NExt::IsArc_Ext(buf, processed) == k_IsArc_Res_YES)
157 return "ext";
158 }
159 return NULL;
160 }
161
CloseAtError()162 void CHandlerImg::CloseAtError()
163 {
164 Stream.Release();
165 }
166
Clear_HandlerImg_Vars()167 void CHandlerImg::Clear_HandlerImg_Vars()
168 {
169 _imgExt = NULL;
170 _size = 0;
171 ClearStreamVars();
172 Reset_VirtPos();
173 Reset_PosInArc();
174 }
175
Z7_COM7F_IMF(CHandlerImg::Open (IInStream * stream,const UInt64 *,IArchiveOpenCallback * openCallback))176 Z7_COM7F_IMF(CHandlerImg::Open(IInStream *stream,
177 const UInt64 * /* maxCheckStartPosition */,
178 IArchiveOpenCallback * openCallback))
179 {
180 COM_TRY_BEGIN
181 {
182 Close();
183 HRESULT res;
184 try
185 {
186 res = Open2(stream, openCallback);
187 if (res == S_OK)
188 {
189 CMyComPtr<ISequentialInStream> inStream;
190 const HRESULT res2 = GetStream(0, &inStream);
191 if (res2 == S_OK && inStream)
192 _imgExt = GetImgExt(inStream);
193 // _imgExt = GetImgExt(this); // for debug
194 /* we reset (_virtPos) to support cases, if some code will
195 call Read() from Handler object instead of GetStream() object. */
196 Reset_VirtPos();
197 // optional: we reset (_posInArc). if real seek position of stream will be changed in external code
198 Reset_PosInArc();
199 // optional: here we could also reset seek positions in parent streams..
200 return S_OK;
201 }
202 }
203 catch(...)
204 {
205 CloseAtError();
206 throw;
207 }
208 CloseAtError();
209 return res;
210 }
211 COM_TRY_END
212 }
213
Z7_COM7F_IMF(CHandlerImg::GetNumberOfItems (UInt32 * numItems))214 Z7_COM7F_IMF(CHandlerImg::GetNumberOfItems(UInt32 *numItems))
215 {
216 *numItems = 1;
217 return S_OK;
218 }
219
220
221 Z7_CLASS_IMP_NOQIB_1(
222 CHandlerImgProgress
223 , ICompressProgressInfo
224 )
225 public:
226 CHandlerImg &Handler;
227 CMyComPtr<ICompressProgressInfo> _ratioProgress;
228
229 CHandlerImgProgress(CHandlerImg &handler) : Handler(handler) {}
230 };
231
232
233 Z7_COM7F_IMF(CHandlerImgProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
234 {
235 UInt64 inSize2;
236 if (Handler.Get_PackSizeProcessed(inSize2))
237 inSize = &inSize2;
238 return _ratioProgress->SetRatioInfo(inSize, outSize);
239 }
240
241
242 Z7_COM7F_IMF(CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
243 Int32 testMode, IArchiveExtractCallback *extractCallback))
244 {
245 COM_TRY_BEGIN
246 if (numItems == 0)
247 return S_OK;
248 if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
249 return E_INVALIDARG;
250
251 RINOK(extractCallback->SetTotal(_size))
252 CMyComPtr<ISequentialOutStream> outStream;
253 const Int32 askMode = testMode ?
254 NExtract::NAskMode::kTest :
255 NExtract::NAskMode::kExtract;
256 RINOK(extractCallback->GetStream(0, &outStream, askMode))
257 if (!testMode && !outStream)
258 return S_OK;
259 RINOK(extractCallback->PrepareOperation(askMode))
260
261 int opRes = NExtract::NOperationResult::kDataError;
262
263 ClearStreamVars();
264
265 CMyComPtr<ISequentialInStream> inStream;
266 HRESULT hres = GetStream(0, &inStream);
267 if (hres == S_FALSE)
268 hres = E_NOTIMPL;
269
270 if (hres == S_OK && inStream)
271 {
272 CLocalProgress *lps = new CLocalProgress;
273 CMyComPtr<ICompressProgressInfo> progress = lps;
274 lps->Init(extractCallback, false);
275
276 if (Init_PackSizeProcessed())
277 {
278 CHandlerImgProgress *imgProgressSpec = new CHandlerImgProgress(*this);
279 CMyComPtr<ICompressProgressInfo> imgProgress = imgProgressSpec;
280 imgProgressSpec->_ratioProgress = progress;
281 progress.Release();
282 progress = imgProgress;
283 }
284
285 CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
286
287 hres = copyCoder.Interface()->Code(inStream, outStream, NULL, &_size, progress);
288 if (hres == S_OK)
289 {
290 if (copyCoder->TotalSize == _size)
291 opRes = NExtract::NOperationResult::kOK;
292
293 if (_stream_unavailData)
294 opRes = NExtract::NOperationResult::kUnavailable;
295 else if (_stream_unsupportedMethod)
296 opRes = NExtract::NOperationResult::kUnsupportedMethod;
297 else if (_stream_dataError)
298 opRes = NExtract::NOperationResult::kDataError;
299 else if (copyCoder->TotalSize < _size)
300 opRes = NExtract::NOperationResult::kUnexpectedEnd;
301 }
302 }
303
304 inStream.Release();
305 outStream.Release();
306
307 if (hres != S_OK)
308 {
309 if (hres == S_FALSE)
310 opRes = NExtract::NOperationResult::kDataError;
311 else if (hres == E_NOTIMPL)
312 opRes = NExtract::NOperationResult::kUnsupportedMethod;
313 else
314 return hres;
315 }
316
317 return extractCallback->SetOperationResult(opRes);
318 COM_TRY_END
319 }
320
321 }
322