xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Nsis/NsisDecode.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // NsisDecode.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../../C/CpuArch.h"
6 
7 #include "NsisDecode.h"
8 
9 #include "../../Common/CreateCoder.h"
10 #include "../../Common/LimitedStreams.h"
11 #include "../../Common/MethodId.h"
12 
13 #include "../../Compress/BcjCoder.h"
14 
15 #define Get32(p) GetUi32(p)
16 
17 namespace NArchive {
18 namespace NNsis {
19 
GetInputProcessedSize() const20 UInt64 CDecoder::GetInputProcessedSize() const
21 {
22   if (_lzmaDecoder)
23     return _lzmaDecoder->GetInputProcessedSize();
24   if (_deflateDecoder)
25     return _deflateDecoder->GetInputProcessedSize();
26   if (_bzDecoder)
27     return _bzDecoder->GetInputProcessedSize();
28   return 0;
29 }
30 
31 
Init(ISequentialInStream * inStream,bool & useFilter)32 HRESULT CDecoder::Init(ISequentialInStream *inStream, bool &useFilter)
33 {
34   useFilter = false;
35 
36   if (_decoderInStream)
37     if (Method != _curMethod)
38       Release();
39   _curMethod = Method;
40 
41   if (!_codecInStream)
42   {
43     switch ((int)Method)
44     {
45       // case NMethodType::kCopy: return E_NOTIMPL;
46       case NMethodType::kDeflate:
47         _deflateDecoder = new NCompress::NDeflate::NDecoder::CCOMCoder();
48         _codecInStream = _deflateDecoder;
49         break;
50       case NMethodType::kBZip2:
51         _bzDecoder = new NCompress::NBZip2::CNsisDecoder();
52         _codecInStream = _bzDecoder;
53         break;
54       case NMethodType::kLZMA:
55         _lzmaDecoder = new NCompress::NLzma::CDecoder();
56         _codecInStream = _lzmaDecoder;
57         break;
58       default: return E_NOTIMPL;
59     }
60   }
61 
62   if (Method == NMethodType::kDeflate)
63     _deflateDecoder->SetNsisMode(IsNsisDeflate);
64 
65   if (FilterFlag)
66   {
67     Byte flag;
68     RINOK(ReadStream_FALSE(inStream, &flag, 1))
69     if (flag > 1)
70       return E_NOTIMPL;
71     useFilter = (flag != 0);
72   }
73 
74   if (!useFilter)
75     _decoderInStream = _codecInStream;
76   else
77   {
78     if (!_filterInStream)
79     {
80       _filter = new CFilterCoder(false);
81       _filterInStream = _filter;
82       _filter->Filter = new NCompress::NBcj::CCoder2(z7_BranchConvSt_X86_Dec);
83     }
84     RINOK(_filter->SetInStream(_codecInStream))
85     _decoderInStream = _filterInStream;
86   }
87 
88   if (Method == NMethodType::kLZMA)
89   {
90     const unsigned kPropsSize = LZMA_PROPS_SIZE;
91     Byte props[kPropsSize];
92     RINOK(ReadStream_FALSE(inStream, props, kPropsSize))
93     RINOK(_lzmaDecoder->SetDecoderProperties2((const Byte *)props, kPropsSize))
94   }
95 
96   {
97     CMyComPtr<ICompressSetInStream> setInStream;
98     _codecInStream.QueryInterface(IID_ICompressSetInStream, &setInStream);
99     if (!setInStream)
100       return E_NOTIMPL;
101     RINOK(setInStream->SetInStream(inStream))
102   }
103 
104   {
105     CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
106     _codecInStream.QueryInterface(IID_ICompressSetOutStreamSize, &setOutStreamSize);
107     if (!setOutStreamSize)
108       return E_NOTIMPL;
109     RINOK(setOutStreamSize->SetOutStreamSize(NULL))
110   }
111 
112   if (useFilter)
113   {
114     RINOK(_filter->SetOutStreamSize(NULL))
115   }
116 
117   return S_OK;
118 }
119 
120 
121 static const UInt32 kMask_IsCompressed = (UInt32)1 << 31;
122 
123 
SetToPos(UInt64 pos,ICompressProgressInfo * progress)124 HRESULT CDecoder::SetToPos(UInt64 pos, ICompressProgressInfo *progress)
125 {
126   if (StreamPos > pos)
127     return E_FAIL;
128   const UInt64 inSizeStart = GetInputProcessedSize();
129   UInt64 offset = 0;
130   while (StreamPos < pos)
131   {
132     size_t size = (size_t)MyMin(pos - StreamPos, (UInt64)Buffer.Size());
133     RINOK(Read(Buffer, &size))
134     if (size == 0)
135       return S_FALSE;
136     StreamPos += size;
137     offset += size;
138 
139     const UInt64 inSize = GetInputProcessedSize() - inSizeStart;
140     RINOK(progress->SetRatioInfo(&inSize, &offset))
141   }
142   return S_OK;
143 }
144 
145 
Decode(CByteBuffer * outBuf,bool unpackSizeDefined,UInt32 unpackSize,ISequentialOutStream * realOutStream,ICompressProgressInfo * progress,UInt32 & packSizeRes,UInt32 & unpackSizeRes)146 HRESULT CDecoder::Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unpackSize,
147     ISequentialOutStream *realOutStream, ICompressProgressInfo *progress,
148     UInt32 &packSizeRes, UInt32 &unpackSizeRes)
149 {
150   CLimitedSequentialInStream *limitedStreamSpec = NULL;
151   CMyComPtr<ISequentialInStream> limitedStream;
152   packSizeRes = 0;
153   unpackSizeRes = 0;
154 
155   if (Solid)
156   {
157     Byte temp[4];
158     size_t processedSize = 4;
159     RINOK(Read(temp, &processedSize))
160     StreamPos += processedSize;
161     if (processedSize != 4)
162       return S_FALSE;
163     UInt32 size = Get32(temp);
164     if (unpackSizeDefined && size != unpackSize)
165       return S_FALSE;
166     unpackSize = size;
167     unpackSizeDefined = true;
168   }
169   else
170   {
171     Byte temp[4];
172     {
173       size_t processedSize = 4;
174       RINOK(ReadStream(InputStream, temp, &processedSize))
175       StreamPos += processedSize;
176       if (processedSize != 4)
177         return S_FALSE;
178     }
179     UInt32 size = Get32(temp);
180 
181     if ((size & kMask_IsCompressed) == 0)
182     {
183       if (unpackSizeDefined && size != unpackSize)
184         return S_FALSE;
185       packSizeRes = size;
186       if (outBuf)
187         outBuf->Alloc(size);
188 
189       UInt64 offset = 0;
190 
191       while (size > 0)
192       {
193         UInt32 curSize = (UInt32)MyMin((size_t)size, Buffer.Size());
194         UInt32 processedSize;
195         RINOK(InputStream->Read(Buffer, curSize, &processedSize))
196         if (processedSize == 0)
197           return S_FALSE;
198         if (outBuf)
199           memcpy((Byte *)*outBuf + (size_t)offset, Buffer, processedSize);
200         offset += processedSize;
201         size -= processedSize;
202         StreamPos += processedSize;
203         unpackSizeRes += processedSize;
204         if (realOutStream)
205           RINOK(WriteStream(realOutStream, Buffer, processedSize))
206         RINOK(progress->SetRatioInfo(&offset, &offset))
207       }
208 
209       return S_OK;
210     }
211 
212     size &= ~kMask_IsCompressed;
213     packSizeRes = size;
214     limitedStreamSpec = new CLimitedSequentialInStream;
215     limitedStream = limitedStreamSpec;
216     limitedStreamSpec->SetStream(InputStream);
217     limitedStreamSpec->Init(size);
218     {
219       bool useFilter;
220       RINOK(Init(limitedStream, useFilter))
221     }
222   }
223 
224   if (outBuf)
225   {
226     if (unpackSizeDefined)
227       outBuf->Alloc(unpackSize);
228   }
229 
230   const UInt64 inSizeStart = GetInputProcessedSize();
231 
232   // we don't allow files larger than 4 GB;
233   if (!unpackSizeDefined)
234     unpackSize = 0xFFFFFFFF;
235   UInt32 offset = 0;
236 
237   HRESULT res = S_OK;
238 
239   for (;;)
240   {
241     size_t rem = unpackSize - offset;
242     if (rem == 0)
243       break;
244     size_t size = Buffer.Size();
245     if (size > rem)
246       size = rem;
247     RINOK(Read(Buffer, &size))
248     if (size == 0)
249     {
250       if (unpackSizeDefined)
251         res = S_FALSE;
252       break;
253     }
254 
255     if (outBuf)
256     {
257       size_t nextSize = offset + size;
258       if (outBuf->Size() < nextSize)
259       {
260         {
261           const size_t nextSize2 = outBuf->Size() * 2;
262           if (nextSize < nextSize2)
263             nextSize = nextSize2;
264         }
265         outBuf->ChangeSize_KeepData(nextSize, offset);
266       }
267       memcpy((Byte *)*outBuf + (size_t)offset, Buffer, size);
268     }
269 
270     StreamPos += size;
271     offset += (UInt32)size;
272 
273     const UInt64 inSize = GetInputProcessedSize() - inSizeStart;
274 
275     if (Solid)
276       packSizeRes = (UInt32)inSize;
277     unpackSizeRes += (UInt32)size;
278 
279     UInt64 outSize = offset;
280     RINOK(progress->SetRatioInfo(&inSize, &outSize))
281     if (realOutStream)
282     {
283       res = WriteStream(realOutStream, Buffer, size);
284       if (res != S_OK)
285         break;
286     }
287   }
288 
289   if (outBuf && offset != outBuf->Size())
290     outBuf->ChangeSize_KeepData(offset, offset);
291 
292   return res;
293 }
294 
295 }}
296