diff options
Diffstat (limited to 'CPP/7zip/Archive/Nsis/NsisHandler.cpp')
-rw-r--r-- | CPP/7zip/Archive/Nsis/NsisHandler.cpp | 688 |
1 files changed, 688 insertions, 0 deletions
diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.cpp b/CPP/7zip/Archive/Nsis/NsisHandler.cpp new file mode 100644 index 0000000..aa0a917 --- /dev/null +++ b/CPP/7zip/Archive/Nsis/NsisHandler.cpp | |||
@@ -0,0 +1,688 @@ | |||
1 | // NSisHandler.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../../../C/CpuArch.h" | ||
6 | |||
7 | #include "../../../Common/ComTry.h" | ||
8 | #include "../../../Common/IntToString.h" | ||
9 | |||
10 | #include "../../../Windows/PropVariant.h" | ||
11 | |||
12 | #include "../../Common/ProgressUtils.h" | ||
13 | #include "../../Common/StreamUtils.h" | ||
14 | |||
15 | #include "../Common/ItemNameUtils.h" | ||
16 | |||
17 | #include "NsisHandler.h" | ||
18 | |||
19 | #define Get32(p) GetUi32(p) | ||
20 | |||
21 | using namespace NWindows; | ||
22 | |||
23 | namespace NArchive { | ||
24 | namespace NNsis { | ||
25 | |||
26 | #define kBcjMethod "BCJ" | ||
27 | #define kUnknownMethod "Unknown" | ||
28 | |||
29 | static const char * const kMethods[] = | ||
30 | { | ||
31 | "Copy" | ||
32 | , "Deflate" | ||
33 | , "BZip2" | ||
34 | , "LZMA" | ||
35 | }; | ||
36 | |||
37 | static const Byte kProps[] = | ||
38 | { | ||
39 | kpidPath, | ||
40 | kpidSize, | ||
41 | kpidPackSize, | ||
42 | kpidMTime, | ||
43 | kpidAttrib, | ||
44 | kpidMethod, | ||
45 | kpidSolid, | ||
46 | kpidOffset | ||
47 | }; | ||
48 | |||
49 | static const Byte kArcProps[] = | ||
50 | { | ||
51 | kpidMethod, | ||
52 | kpidSolid, | ||
53 | kpidBit64, | ||
54 | kpidHeadersSize, | ||
55 | kpidEmbeddedStubSize, | ||
56 | kpidSubType | ||
57 | // kpidCodePage | ||
58 | }; | ||
59 | |||
60 | IMP_IInArchive_Props | ||
61 | IMP_IInArchive_ArcProps | ||
62 | |||
63 | |||
64 | static AString UInt32ToString(UInt32 val) | ||
65 | { | ||
66 | char s[16]; | ||
67 | ConvertUInt32ToString(val, s); | ||
68 | return (AString)s; | ||
69 | } | ||
70 | |||
71 | static AString GetStringForSizeValue(UInt32 val) | ||
72 | { | ||
73 | for (int i = 31; i >= 0; i--) | ||
74 | if (((UInt32)1 << i) == val) | ||
75 | return UInt32ToString(i); | ||
76 | char c = 'b'; | ||
77 | if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } | ||
78 | else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } | ||
79 | return UInt32ToString(val) + c; | ||
80 | } | ||
81 | |||
82 | static AString GetMethod(bool useFilter, NMethodType::EEnum method, UInt32 dict) | ||
83 | { | ||
84 | AString s; | ||
85 | if (useFilter) | ||
86 | { | ||
87 | s += kBcjMethod; | ||
88 | s.Add_Space(); | ||
89 | } | ||
90 | s += ((unsigned)method < ARRAY_SIZE(kMethods)) ? kMethods[(unsigned)method] : kUnknownMethod; | ||
91 | if (method == NMethodType::kLZMA) | ||
92 | { | ||
93 | s += ':'; | ||
94 | s += GetStringForSizeValue(dict); | ||
95 | } | ||
96 | return s; | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | AString CHandler::GetMethod(NMethodType::EEnum method, bool useItemFilter, UInt32 dictionary) const | ||
101 | { | ||
102 | AString s; | ||
103 | if (_archive.IsSolid && _archive.UseFilter || !_archive.IsSolid && useItemFilter) | ||
104 | { | ||
105 | s += kBcjMethod; | ||
106 | s.Add_Space(); | ||
107 | } | ||
108 | s += (method < ARRAY_SIZE(kMethods)) ? kMethods[method] : kUnknownMethod; | ||
109 | if (method == NMethodType::kLZMA) | ||
110 | { | ||
111 | s += ':'; | ||
112 | s += GetStringForSizeValue(_archive.IsSolid ? _archive.DictionarySize: dictionary); | ||
113 | } | ||
114 | return s; | ||
115 | } | ||
116 | */ | ||
117 | |||
118 | STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) | ||
119 | { | ||
120 | COM_TRY_BEGIN | ||
121 | NCOM::CPropVariant prop; | ||
122 | switch (propID) | ||
123 | { | ||
124 | // case kpidCodePage: if (_archive.IsUnicode) prop = "UTF-16"; break; | ||
125 | case kpidSubType: | ||
126 | { | ||
127 | AString s (_archive.GetFormatDescription()); | ||
128 | if (!_archive.IsInstaller) | ||
129 | { | ||
130 | s.Add_Space_if_NotEmpty(); | ||
131 | s += "(Uninstall)"; | ||
132 | } | ||
133 | if (!s.IsEmpty()) | ||
134 | prop = s; | ||
135 | break; | ||
136 | } | ||
137 | |||
138 | case kpidBit64: if (_archive.Is64Bit) prop = true; break; | ||
139 | case kpidMethod: prop = _methodString; break; | ||
140 | case kpidSolid: prop = _archive.IsSolid; break; | ||
141 | case kpidOffset: prop = _archive.StartOffset; break; | ||
142 | case kpidPhySize: prop = (UInt64)((UInt64)_archive.ExeStub.Size() + _archive.FirstHeader.ArcSize); break; | ||
143 | case kpidEmbeddedStubSize: prop = (UInt64)_archive.ExeStub.Size(); break; | ||
144 | case kpidHeadersSize: prop = _archive.FirstHeader.HeaderSize; break; | ||
145 | |||
146 | case kpidErrorFlags: | ||
147 | { | ||
148 | UInt32 v = 0; | ||
149 | if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc; | ||
150 | if (_archive.IsTruncated()) v |= kpv_ErrorFlags_UnexpectedEnd; | ||
151 | prop = v; | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | case kpidName: | ||
156 | { | ||
157 | AString s; | ||
158 | |||
159 | #ifdef NSIS_SCRIPT | ||
160 | if (!_archive.Name.IsEmpty()) | ||
161 | s = _archive.Name; | ||
162 | if (!_archive.IsInstaller) | ||
163 | { | ||
164 | if (!s.IsEmpty()) | ||
165 | s += '.'; | ||
166 | s += "Uninstall"; | ||
167 | } | ||
168 | #endif | ||
169 | |||
170 | if (s.IsEmpty()) | ||
171 | s = _archive.IsInstaller ? "Install" : "Uninstall"; | ||
172 | s += (_archive.ExeStub.Size() == 0) ? ".nsis" : ".exe"; | ||
173 | |||
174 | prop = _archive.ConvertToUnicode(s); | ||
175 | break; | ||
176 | } | ||
177 | |||
178 | #ifdef NSIS_SCRIPT | ||
179 | case kpidShortComment: | ||
180 | { | ||
181 | if (!_archive.BrandingText.IsEmpty()) | ||
182 | prop = _archive.ConvertToUnicode(_archive.BrandingText); | ||
183 | break; | ||
184 | } | ||
185 | #endif | ||
186 | } | ||
187 | prop.Detach(value); | ||
188 | return S_OK; | ||
189 | COM_TRY_END | ||
190 | } | ||
191 | |||
192 | |||
193 | STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback * /* openArchiveCallback */) | ||
194 | { | ||
195 | COM_TRY_BEGIN | ||
196 | Close(); | ||
197 | { | ||
198 | if (_archive.Open(stream, maxCheckStartPosition) != S_OK) | ||
199 | return S_FALSE; | ||
200 | { | ||
201 | UInt32 dict = _archive.DictionarySize; | ||
202 | if (!_archive.IsSolid) | ||
203 | { | ||
204 | FOR_VECTOR (i, _archive.Items) | ||
205 | { | ||
206 | const CItem &item = _archive.Items[i]; | ||
207 | if (item.DictionarySize > dict) | ||
208 | dict = item.DictionarySize; | ||
209 | } | ||
210 | } | ||
211 | _methodString = GetMethod(_archive.UseFilter, _archive.Method, dict); | ||
212 | } | ||
213 | } | ||
214 | return S_OK; | ||
215 | COM_TRY_END | ||
216 | } | ||
217 | |||
218 | STDMETHODIMP CHandler::Close() | ||
219 | { | ||
220 | _archive.Clear(); | ||
221 | _archive.Release(); | ||
222 | return S_OK; | ||
223 | } | ||
224 | |||
225 | STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) | ||
226 | { | ||
227 | *numItems = _archive.Items.Size() | ||
228 | #ifdef NSIS_SCRIPT | ||
229 | + 1 + _archive.LicenseFiles.Size(); | ||
230 | #endif | ||
231 | ; | ||
232 | return S_OK; | ||
233 | } | ||
234 | |||
235 | bool CHandler::GetUncompressedSize(unsigned index, UInt32 &size) const | ||
236 | { | ||
237 | size = 0; | ||
238 | const CItem &item = _archive.Items[index]; | ||
239 | if (item.Size_Defined) | ||
240 | size = item.Size; | ||
241 | else if (_archive.IsSolid && item.EstimatedSize_Defined) | ||
242 | size = item.EstimatedSize; | ||
243 | else | ||
244 | return false; | ||
245 | return true; | ||
246 | } | ||
247 | |||
248 | bool CHandler::GetCompressedSize(unsigned index, UInt32 &size) const | ||
249 | { | ||
250 | size = 0; | ||
251 | const CItem &item = _archive.Items[index]; | ||
252 | if (item.CompressedSize_Defined) | ||
253 | size = item.CompressedSize; | ||
254 | else | ||
255 | { | ||
256 | if (_archive.IsSolid) | ||
257 | { | ||
258 | if (index == 0) | ||
259 | size = _archive.FirstHeader.GetDataSize(); | ||
260 | else | ||
261 | return false; | ||
262 | } | ||
263 | else | ||
264 | { | ||
265 | if (!item.IsCompressed) | ||
266 | size = item.Size; | ||
267 | else | ||
268 | return false; | ||
269 | } | ||
270 | } | ||
271 | return true; | ||
272 | } | ||
273 | |||
274 | |||
275 | STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) | ||
276 | { | ||
277 | COM_TRY_BEGIN | ||
278 | NCOM::CPropVariant prop; | ||
279 | #ifdef NSIS_SCRIPT | ||
280 | if (index >= (UInt32)_archive.Items.Size()) | ||
281 | { | ||
282 | if (index == (UInt32)_archive.Items.Size()) | ||
283 | { | ||
284 | switch (propID) | ||
285 | { | ||
286 | case kpidPath: prop = "[NSIS].nsi"; break; | ||
287 | case kpidSize: | ||
288 | case kpidPackSize: prop = (UInt64)_archive.Script.Len(); break; | ||
289 | case kpidSolid: prop = false; break; | ||
290 | } | ||
291 | } | ||
292 | else | ||
293 | { | ||
294 | const CLicenseFile &lic = _archive.LicenseFiles[index - (_archive.Items.Size() + 1)]; | ||
295 | switch (propID) | ||
296 | { | ||
297 | case kpidPath: prop = lic.Name; break; | ||
298 | case kpidSize: | ||
299 | case kpidPackSize: prop = (UInt64)lic.Size; break; | ||
300 | case kpidSolid: prop = false; break; | ||
301 | } | ||
302 | } | ||
303 | } | ||
304 | else | ||
305 | #endif | ||
306 | { | ||
307 | const CItem &item = _archive.Items[index]; | ||
308 | switch (propID) | ||
309 | { | ||
310 | case kpidOffset: prop = item.Pos; break; | ||
311 | case kpidPath: | ||
312 | { | ||
313 | UString s = NItemName::WinPathToOsPath(_archive.GetReducedName(index)); | ||
314 | if (!s.IsEmpty()) | ||
315 | prop = (const wchar_t *)s; | ||
316 | break; | ||
317 | } | ||
318 | case kpidSize: | ||
319 | { | ||
320 | UInt32 size; | ||
321 | if (GetUncompressedSize(index, size)) | ||
322 | prop = (UInt64)size; | ||
323 | break; | ||
324 | } | ||
325 | case kpidPackSize: | ||
326 | { | ||
327 | UInt32 size; | ||
328 | if (GetCompressedSize(index, size)) | ||
329 | prop = (UInt64)size; | ||
330 | break; | ||
331 | } | ||
332 | case kpidMTime: | ||
333 | { | ||
334 | if (item.MTime.dwHighDateTime > 0x01000000 && | ||
335 | item.MTime.dwHighDateTime < 0xFF000000) | ||
336 | prop = item.MTime; | ||
337 | break; | ||
338 | } | ||
339 | case kpidAttrib: | ||
340 | { | ||
341 | if (item.Attrib_Defined) | ||
342 | prop = item.Attrib; | ||
343 | break; | ||
344 | } | ||
345 | |||
346 | case kpidMethod: | ||
347 | if (_archive.IsSolid) | ||
348 | prop = _methodString; | ||
349 | else | ||
350 | prop = GetMethod(_archive.UseFilter, item.IsCompressed ? _archive.Method : | ||
351 | NMethodType::kCopy, item.DictionarySize); | ||
352 | break; | ||
353 | |||
354 | case kpidSolid: prop = _archive.IsSolid; break; | ||
355 | } | ||
356 | } | ||
357 | prop.Detach(value); | ||
358 | return S_OK; | ||
359 | COM_TRY_END | ||
360 | } | ||
361 | |||
362 | |||
363 | static bool UninstallerPatch(const Byte *p, size_t size, CByteBuffer &dest) | ||
364 | { | ||
365 | for (;;) | ||
366 | { | ||
367 | if (size < 4) | ||
368 | return false; | ||
369 | UInt32 len = Get32(p); | ||
370 | if (len == 0) | ||
371 | return size == 4; | ||
372 | if (size < 8) | ||
373 | return false; | ||
374 | UInt32 offs = Get32(p + 4); | ||
375 | p += 8; | ||
376 | size -= 8; | ||
377 | if (size < len || offs > dest.Size() || len > dest.Size() - offs) | ||
378 | return false; | ||
379 | memcpy(dest + offs, p, len); | ||
380 | p += len; | ||
381 | size -= len; | ||
382 | } | ||
383 | } | ||
384 | |||
385 | |||
386 | STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, | ||
387 | Int32 testMode, IArchiveExtractCallback *extractCallback) | ||
388 | { | ||
389 | COM_TRY_BEGIN | ||
390 | bool allFilesMode = (numItems == (UInt32)(Int32)-1); | ||
391 | if (allFilesMode) | ||
392 | GetNumberOfItems(&numItems); | ||
393 | if (numItems == 0) | ||
394 | return S_OK; | ||
395 | |||
396 | UInt64 totalSize = 0; | ||
397 | UInt64 solidPosMax = 0; | ||
398 | |||
399 | UInt32 i; | ||
400 | for (i = 0; i < numItems; i++) | ||
401 | { | ||
402 | UInt32 index = (allFilesMode ? i : indices[i]); | ||
403 | |||
404 | #ifdef NSIS_SCRIPT | ||
405 | if (index >= _archive.Items.Size()) | ||
406 | { | ||
407 | if (index == _archive.Items.Size()) | ||
408 | totalSize += _archive.Script.Len(); | ||
409 | else | ||
410 | totalSize += _archive.LicenseFiles[index - (_archive.Items.Size() + 1)].Size; | ||
411 | } | ||
412 | else | ||
413 | #endif | ||
414 | { | ||
415 | UInt32 size; | ||
416 | if (_archive.IsSolid) | ||
417 | { | ||
418 | GetUncompressedSize(index, size); | ||
419 | UInt64 pos = (UInt64)_archive.GetPosOfSolidItem(index) + size; | ||
420 | if (solidPosMax < pos) | ||
421 | solidPosMax = pos; | ||
422 | } | ||
423 | else | ||
424 | { | ||
425 | GetCompressedSize(index, size); | ||
426 | totalSize += size; | ||
427 | } | ||
428 | } | ||
429 | } | ||
430 | |||
431 | extractCallback->SetTotal(totalSize + solidPosMax); | ||
432 | |||
433 | CLocalProgress *lps = new CLocalProgress; | ||
434 | CMyComPtr<ICompressProgressInfo> progress = lps; | ||
435 | lps->Init(extractCallback, !_archive.IsSolid); | ||
436 | |||
437 | if (_archive.IsSolid) | ||
438 | { | ||
439 | RINOK(_archive.SeekTo_DataStreamOffset()); | ||
440 | RINOK(_archive.InitDecoder()); | ||
441 | _archive.Decoder.StreamPos = 0; | ||
442 | } | ||
443 | |||
444 | /* We use tempBuf for solid archives, if there is duplicate item. | ||
445 | We don't know uncompressed size for non-solid archives, so we can't | ||
446 | allocate exact buffer. | ||
447 | We use tempBuf also for first part (EXE stub) of unistall.exe | ||
448 | and tempBuf2 is used for second part (NSIS script). */ | ||
449 | |||
450 | CByteBuffer tempBuf; | ||
451 | CByteBuffer tempBuf2; | ||
452 | |||
453 | /* tempPos is pos in uncompressed stream of previous item for solid archive, that | ||
454 | was written to tempBuf */ | ||
455 | UInt64 tempPos = (UInt64)(Int64)-1; | ||
456 | |||
457 | /* prevPos is pos in uncompressed stream of previous item for solid archive. | ||
458 | It's used for test mode (where we don't need to test same file second time */ | ||
459 | UInt64 prevPos = (UInt64)(Int64)-1; | ||
460 | |||
461 | // if there is error in solid archive, we show error for all subsequent files | ||
462 | bool solidDataError = false; | ||
463 | |||
464 | UInt64 curTotalPacked = 0, curTotalUnpacked = 0; | ||
465 | UInt32 curPacked = 0; | ||
466 | UInt64 curUnpacked = 0; | ||
467 | |||
468 | for (i = 0; i < numItems; i++, | ||
469 | curTotalPacked += curPacked, | ||
470 | curTotalUnpacked += curUnpacked) | ||
471 | { | ||
472 | lps->InSize = curTotalPacked; | ||
473 | lps->OutSize = curTotalUnpacked; | ||
474 | if (_archive.IsSolid) | ||
475 | lps->OutSize += _archive.Decoder.StreamPos; | ||
476 | |||
477 | curPacked = 0; | ||
478 | curUnpacked = 0; | ||
479 | RINOK(lps->SetCur()); | ||
480 | |||
481 | // RINOK(extractCallback->SetCompleted(¤tTotalSize)); | ||
482 | CMyComPtr<ISequentialOutStream> realOutStream; | ||
483 | Int32 askMode = testMode ? | ||
484 | NExtract::NAskMode::kTest : | ||
485 | NExtract::NAskMode::kExtract; | ||
486 | const UInt32 index = allFilesMode ? i : indices[i]; | ||
487 | |||
488 | RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); | ||
489 | |||
490 | bool dataError = false; | ||
491 | |||
492 | #ifdef NSIS_SCRIPT | ||
493 | if (index >= (UInt32)_archive.Items.Size()) | ||
494 | { | ||
495 | const void *data; | ||
496 | size_t size; | ||
497 | if (index == (UInt32)_archive.Items.Size()) | ||
498 | { | ||
499 | data = (const Byte *)_archive.Script; | ||
500 | size = _archive.Script.Len(); | ||
501 | } | ||
502 | else | ||
503 | { | ||
504 | CLicenseFile &lic = _archive.LicenseFiles[index - (_archive.Items.Size() + 1)]; | ||
505 | if (lic.Text.Size() != 0) | ||
506 | data = lic.Text; | ||
507 | else | ||
508 | data = _archive._data + lic.Offset; | ||
509 | size = lic.Size; | ||
510 | } | ||
511 | curUnpacked = size; | ||
512 | if (!testMode && !realOutStream) | ||
513 | continue; | ||
514 | RINOK(extractCallback->PrepareOperation(askMode)); | ||
515 | if (realOutStream) | ||
516 | RINOK(WriteStream(realOutStream, data, size)); | ||
517 | } | ||
518 | else | ||
519 | #endif | ||
520 | { | ||
521 | const CItem &item = _archive.Items[index]; | ||
522 | |||
523 | if (!_archive.IsSolid) | ||
524 | GetCompressedSize(index, curPacked); | ||
525 | |||
526 | if (!testMode && !realOutStream) | ||
527 | continue; | ||
528 | |||
529 | RINOK(extractCallback->PrepareOperation(askMode)); | ||
530 | |||
531 | dataError = solidDataError; | ||
532 | |||
533 | bool needDecompress = !solidDataError; | ||
534 | if (needDecompress) | ||
535 | { | ||
536 | if (testMode && _archive.IsSolid && _archive.GetPosOfSolidItem(index) == prevPos) | ||
537 | needDecompress = false; | ||
538 | } | ||
539 | |||
540 | if (needDecompress) | ||
541 | { | ||
542 | bool writeToTemp = false; | ||
543 | bool readFromTemp = false; | ||
544 | |||
545 | if (!_archive.IsSolid) | ||
546 | { | ||
547 | RINOK(_archive.SeekToNonSolidItem(index)); | ||
548 | } | ||
549 | else | ||
550 | { | ||
551 | UInt64 pos = _archive.GetPosOfSolidItem(index); | ||
552 | if (pos < _archive.Decoder.StreamPos) | ||
553 | { | ||
554 | if (pos != tempPos) | ||
555 | solidDataError = dataError = true; | ||
556 | readFromTemp = true; | ||
557 | } | ||
558 | else | ||
559 | { | ||
560 | HRESULT res = _archive.Decoder.SetToPos(pos, progress); | ||
561 | if (res != S_OK) | ||
562 | { | ||
563 | if (res != S_FALSE) | ||
564 | return res; | ||
565 | solidDataError = dataError = true; | ||
566 | } | ||
567 | else if (!testMode && i + 1 < numItems) | ||
568 | { | ||
569 | UInt32 next = allFilesMode ? i + 1 : indices[i + 1]; | ||
570 | if (next < _archive.Items.Size()) | ||
571 | { | ||
572 | UInt64 nextPos = _archive.GetPosOfSolidItem(next); | ||
573 | if (nextPos == pos) | ||
574 | { | ||
575 | writeToTemp = true; | ||
576 | tempPos = pos; | ||
577 | } | ||
578 | } | ||
579 | } | ||
580 | } | ||
581 | prevPos = pos; | ||
582 | } | ||
583 | |||
584 | if (!dataError) | ||
585 | { | ||
586 | // UInt32 unpackSize = 0; | ||
587 | // bool unpackSize_Defined = false; | ||
588 | bool writeToTemp1 = writeToTemp; | ||
589 | if (item.IsUninstaller) | ||
590 | { | ||
591 | // unpackSize = item.PatchSize; | ||
592 | // unpackSize_Defined = true; | ||
593 | if (!readFromTemp) | ||
594 | writeToTemp = true; | ||
595 | writeToTemp1 = writeToTemp; | ||
596 | if (_archive.ExeStub.Size() == 0) | ||
597 | { | ||
598 | if (writeToTemp1 && !readFromTemp) | ||
599 | tempBuf.Free(); | ||
600 | writeToTemp1 = false; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | if (readFromTemp) | ||
605 | { | ||
606 | if (realOutStream && !item.IsUninstaller) | ||
607 | RINOK(WriteStream(realOutStream, tempBuf, tempBuf.Size())); | ||
608 | } | ||
609 | else | ||
610 | { | ||
611 | UInt32 curUnpacked32 = 0; | ||
612 | HRESULT res = _archive.Decoder.Decode( | ||
613 | writeToTemp1 ? &tempBuf : NULL, | ||
614 | item.IsUninstaller, item.PatchSize, | ||
615 | item.IsUninstaller ? NULL : (ISequentialOutStream *)realOutStream, | ||
616 | progress, | ||
617 | curPacked, curUnpacked32); | ||
618 | curUnpacked = curUnpacked32; | ||
619 | if (_archive.IsSolid) | ||
620 | curUnpacked = 0; | ||
621 | if (res != S_OK) | ||
622 | { | ||
623 | if (res != S_FALSE) | ||
624 | return res; | ||
625 | dataError = true; | ||
626 | if (_archive.IsSolid) | ||
627 | solidDataError = true; | ||
628 | } | ||
629 | } | ||
630 | } | ||
631 | |||
632 | if (!dataError && item.IsUninstaller) | ||
633 | { | ||
634 | if (_archive.ExeStub.Size() != 0) | ||
635 | { | ||
636 | CByteBuffer destBuf = _archive.ExeStub; | ||
637 | dataError = !UninstallerPatch(tempBuf, tempBuf.Size(), destBuf); | ||
638 | |||
639 | if (realOutStream) | ||
640 | RINOK(WriteStream(realOutStream, destBuf, destBuf.Size())); | ||
641 | } | ||
642 | |||
643 | if (readFromTemp) | ||
644 | { | ||
645 | if (realOutStream) | ||
646 | RINOK(WriteStream(realOutStream, tempBuf2, tempBuf2.Size())); | ||
647 | } | ||
648 | else | ||
649 | { | ||
650 | UInt32 curPacked2 = 0; | ||
651 | UInt32 curUnpacked2 = 0; | ||
652 | |||
653 | if (!_archive.IsSolid) | ||
654 | { | ||
655 | RINOK(_archive.SeekTo(_archive.GetPosOfNonSolidItem(index) + 4 + curPacked )); | ||
656 | } | ||
657 | |||
658 | HRESULT res = _archive.Decoder.Decode( | ||
659 | writeToTemp ? &tempBuf2 : NULL, | ||
660 | false, 0, | ||
661 | realOutStream, | ||
662 | progress, | ||
663 | curPacked2, curUnpacked2); | ||
664 | curPacked += curPacked2; | ||
665 | if (!_archive.IsSolid) | ||
666 | curUnpacked += curUnpacked2; | ||
667 | if (res != S_OK) | ||
668 | { | ||
669 | if (res != S_FALSE) | ||
670 | return res; | ||
671 | dataError = true; | ||
672 | if (_archive.IsSolid) | ||
673 | solidDataError = true; | ||
674 | } | ||
675 | } | ||
676 | } | ||
677 | } | ||
678 | } | ||
679 | realOutStream.Release(); | ||
680 | RINOK(extractCallback->SetOperationResult(dataError ? | ||
681 | NExtract::NOperationResult::kDataError : | ||
682 | NExtract::NOperationResult::kOK)); | ||
683 | } | ||
684 | return S_OK; | ||
685 | COM_TRY_END | ||
686 | } | ||
687 | |||
688 | }} | ||