xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/HandlerCont.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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