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