1 // RarHandler.cpp
2
3 #include "StdAfx.h"
4
5 #include "Common/ComTry.h"
6 #include "Common/IntToString.h"
7 #include "Common/StringConvert.h"
8
9 #include "Windows/PropVariant.h"
10 #include "Windows/Time.h"
11
12 #include "../../IPassword.h"
13
14 #include "../../Common/CreateCoder.h"
15 #include "../../Common/FilterCoder.h"
16 #include "../../Common/MethodId.h"
17 #include "../../Common/ProgressUtils.h"
18
19 #include "../../Compress/CopyCoder.h"
20
21 #include "../../Crypto/Rar20Crypto.h"
22 #include "../../Crypto/RarAes.h"
23
24 #include "../Common/ItemNameUtils.h"
25 #include "../Common/OutStreamWithCRC.h"
26
27 #include "RarHandler.h"
28
29 using namespace NWindows;
30 using namespace NTime;
31
32 namespace NArchive {
33 namespace NRar {
34
35 static const wchar_t *kHostOS[] =
36 {
37 L"MS DOS",
38 L"OS/2",
39 L"Win32",
40 L"Unix",
41 L"Mac OS",
42 L"BeOS"
43 };
44
45 static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);
46
47 static const wchar_t *kUnknownOS = L"Unknown";
48
49 STATPROPSTG kProps[] =
50 {
51 { NULL, kpidPath, VT_BSTR},
52 { NULL, kpidIsDir, VT_BOOL},
53 { NULL, kpidSize, VT_UI8},
54 { NULL, kpidPackSize, VT_UI8},
55 { NULL, kpidMTime, VT_FILETIME},
56 { NULL, kpidCTime, VT_FILETIME},
57 { NULL, kpidATime, VT_FILETIME},
58 { NULL, kpidAttrib, VT_UI4},
59
60 { NULL, kpidEncrypted, VT_BOOL},
61 { NULL, kpidSolid, VT_BOOL},
62 { NULL, kpidCommented, VT_BOOL},
63 { NULL, kpidSplitBefore, VT_BOOL},
64 { NULL, kpidSplitAfter, VT_BOOL},
65 { NULL, kpidCRC, VT_UI4},
66 { NULL, kpidHostOS, VT_BSTR},
67 { NULL, kpidMethod, VT_BSTR},
68 { NULL, kpidUnpackVer, VT_UI1}
69 };
70
71 STATPROPSTG kArcProps[] =
72 {
73 { NULL, kpidSolid, VT_BOOL},
74 { NULL, kpidNumBlocks, VT_UI4},
75 // { NULL, kpidEncrypted, VT_BOOL},
76 { NULL, kpidIsVolume, VT_BOOL},
77 { NULL, kpidNumVolumes, VT_UI4},
78 { NULL, kpidPhySize, VT_UI8}
79 // { NULL, kpidCommented, VT_BOOL}
80 };
81
82 IMP_IInArchive_Props
83 IMP_IInArchive_ArcProps
84
GetPackSize(int refIndex) const85 UInt64 CHandler::GetPackSize(int refIndex) const
86 {
87 const CRefItem &refItem = _refItems[refIndex];
88 UInt64 totalPackSize = 0;
89 for (int i = 0; i < refItem.NumItems; i++)
90 totalPackSize += _items[refItem.ItemIndex + i].PackSize;
91 return totalPackSize;
92 }
93
GetArchiveProperty(PROPID propID,PROPVARIANT * value)94 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
95 {
96 // COM_TRY_BEGIN
97 NWindows::NCOM::CPropVariant prop;
98 switch(propID)
99 {
100 case kpidSolid: prop = _archiveInfo.IsSolid(); break;
101 // case kpidEncrypted: prop = _archiveInfo.IsEncrypted(); break; // it's for encrypted names.
102 case kpidIsVolume: prop = _archiveInfo.IsVolume(); break;
103 case kpidNumVolumes: prop = (UInt32)_archives.Size(); break;
104 case kpidOffset: if (_archiveInfo.StartPosition != 0) prop = _archiveInfo.StartPosition; break;
105 // case kpidCommented: prop = _archiveInfo.IsCommented(); break;
106 case kpidNumBlocks:
107 {
108 UInt32 numBlocks = 0;
109 for (int i = 0; i < _refItems.Size(); i++)
110 if (!IsSolid(i))
111 numBlocks++;
112 prop = (UInt32)numBlocks;
113 break;
114 }
115 }
116 prop.Detach(value);
117 return S_OK;
118 // COM_TRY_END
119 }
120
GetNumberOfItems(UInt32 * numItems)121 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
122 {
123 *numItems = _refItems.Size();
124 return S_OK;
125 }
126
RarTimeToFileTime(const CRarTime & rarTime,FILETIME & result)127 static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result)
128 {
129 if (!DosTimeToFileTime(rarTime.DosTime, result))
130 return false;
131 UInt64 value = (((UInt64)result.dwHighDateTime) << 32) + result.dwLowDateTime;
132 value += (UInt64)rarTime.LowSecond * 10000000;
133 value += ((UInt64)rarTime.SubTime[2] << 16) +
134 ((UInt64)rarTime.SubTime[1] << 8) +
135 ((UInt64)rarTime.SubTime[0]);
136 result.dwLowDateTime = (DWORD)value;
137 result.dwHighDateTime = DWORD(value >> 32);
138 return true;
139 }
140
RarTimeToProp(const CRarTime & rarTime,NWindows::NCOM::CPropVariant & prop)141 static void RarTimeToProp(const CRarTime &rarTime, NWindows::NCOM::CPropVariant &prop)
142 {
143 FILETIME localFileTime, utcFileTime;
144 if (RarTimeToFileTime(rarTime, localFileTime))
145 {
146 if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
147 utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
148 }
149 else
150 utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
151 prop = utcFileTime;
152 }
153
GetProperty(UInt32 index,PROPID propID,PROPVARIANT * value)154 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
155 {
156 COM_TRY_BEGIN
157 NWindows::NCOM::CPropVariant prop;
158 const CRefItem &refItem = _refItems[index];
159 const CItemEx &item = _items[refItem.ItemIndex];
160 switch(propID)
161 {
162 case kpidPath:
163 {
164 UString u;
165 if (item.HasUnicodeName() && !item.UnicodeName.IsEmpty())
166 u = item.UnicodeName;
167 else
168 u = MultiByteToUnicodeString(item.Name, CP_OEMCP);
169 prop = (const wchar_t *)NItemName::WinNameToOSName(u);
170 break;
171 }
172 case kpidIsDir: prop = item.IsDir(); break;
173 case kpidSize: prop = item.Size; break;
174 case kpidPackSize: prop = GetPackSize(index); break;
175 case kpidMTime: RarTimeToProp(item.MTime, prop); break;
176 case kpidCTime: if (item.CTimeDefined) RarTimeToProp(item.CTime, prop); break;
177 case kpidATime: if (item.ATimeDefined) RarTimeToProp(item.ATime, prop); break;
178 case kpidAttrib: prop = item.GetWinAttributes(); break;
179 case kpidEncrypted: prop = item.IsEncrypted(); break;
180 case kpidSolid: prop = IsSolid(index); break;
181 case kpidCommented: prop = item.IsCommented(); break;
182 case kpidSplitBefore: prop = item.IsSplitBefore(); break;
183 case kpidSplitAfter: prop = _items[refItem.ItemIndex + refItem.NumItems - 1].IsSplitAfter(); break;
184 case kpidCRC:
185 {
186 const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
187 prop = ((lastItem.IsSplitAfter()) ? item.FileCRC : lastItem.FileCRC);
188 break;
189 }
190 case kpidUnpackVer: prop = item.UnPackVersion; break;
191 case kpidMethod:
192 {
193 UString method;
194 if (item.Method >= Byte('0') && item.Method <= Byte('5'))
195 {
196 method = L"m";
197 wchar_t temp[32];
198 ConvertUInt64ToString(item.Method - Byte('0'), temp);
199 method += temp;
200 if (!item.IsDir())
201 {
202 method += L":";
203 ConvertUInt64ToString(16 + item.GetDictSize(), temp);
204 method += temp;
205 }
206 }
207 else
208 {
209 wchar_t temp[32];
210 ConvertUInt64ToString(item.Method, temp);
211 method += temp;
212 }
213 prop = method;
214 break;
215 }
216 case kpidHostOS: prop = (item.HostOS < kNumHostOSes) ? (kHostOS[item.HostOS]) : kUnknownOS; break;
217 }
218 prop.Detach(value);
219 return S_OK;
220 COM_TRY_END
221 }
222
223 class CVolumeName
224 {
225 bool _first;
226 bool _newStyle;
227 UString _unchangedPart;
228 UString _changedPart;
229 UString _afterPart;
230 public:
CVolumeName()231 CVolumeName(): _newStyle(true) {};
232
InitName(const UString & name,bool newStyle)233 bool InitName(const UString &name, bool newStyle)
234 {
235 _first = true;
236 _newStyle = newStyle;
237 int dotPos = name.ReverseFind('.');
238 UString basePart = name;
239 if (dotPos >= 0)
240 {
241 UString ext = name.Mid(dotPos + 1);
242 if (ext.CompareNoCase(L"rar") == 0)
243 {
244 _afterPart = name.Mid(dotPos);
245 basePart = name.Left(dotPos);
246 }
247 else if (ext.CompareNoCase(L"exe") == 0)
248 {
249 _afterPart = L".rar";
250 basePart = name.Left(dotPos);
251 }
252 else if (!_newStyle)
253 {
254 if (ext.CompareNoCase(L"000") == 0 ||
255 ext.CompareNoCase(L"001") == 0 ||
256 ext.CompareNoCase(L"r00") == 0 ||
257 ext.CompareNoCase(L"r01") == 0)
258 {
259 _afterPart.Empty();
260 _first = false;
261 _changedPart = ext;
262 _unchangedPart = name.Left(dotPos + 1);
263 return true;
264 }
265 }
266 }
267
268 if (!_newStyle)
269 {
270 _afterPart.Empty();
271 _unchangedPart = basePart + UString(L".");
272 _changedPart = L"r00";
273 return true;
274 }
275
276 int numLetters = 1;
277 if (basePart.Right(numLetters) == L"1" || basePart.Right(numLetters) == L"0")
278 {
279 while (numLetters < basePart.Length())
280 {
281 if (basePart[basePart.Length() - numLetters - 1] != '0')
282 break;
283 numLetters++;
284 }
285 }
286 else
287 return false;
288 _unchangedPart = basePart.Left(basePart.Length() - numLetters);
289 _changedPart = basePart.Right(numLetters);
290 return true;
291 }
292
GetNextName()293 UString GetNextName()
294 {
295 UString newName;
296 if (_newStyle || !_first)
297 {
298 int i;
299 int numLetters = _changedPart.Length();
300 for (i = numLetters - 1; i >= 0; i--)
301 {
302 wchar_t c = _changedPart[i];
303 if (c == L'9')
304 {
305 c = L'0';
306 newName = c + newName;
307 if (i == 0)
308 newName = UString(L'1') + newName;
309 continue;
310 }
311 c++;
312 newName = UString(c) + newName;
313 i--;
314 for (; i >= 0; i--)
315 newName = _changedPart[i] + newName;
316 break;
317 }
318 _changedPart = newName;
319 }
320 _first = false;
321 return _unchangedPart + _changedPart + _afterPart;
322 }
323 };
324
Open2(IInStream * stream,const UInt64 * maxCheckStartPosition,IArchiveOpenCallback * openArchiveCallback)325 HRESULT CHandler::Open2(IInStream *stream,
326 const UInt64 *maxCheckStartPosition,
327 IArchiveOpenCallback *openArchiveCallback)
328 {
329 {
330 CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
331 CMyComPtr<ICryptoGetTextPassword> getTextPassword;
332 CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openArchiveCallback;
333
334 CVolumeName seqName;
335
336 UInt64 totalBytes = 0;
337 UInt64 curBytes = 0;
338
339 if (openArchiveCallback != NULL)
340 {
341 openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
342 openArchiveCallbackWrap.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
343 }
344
345 for (;;)
346 {
347 CMyComPtr<IInStream> inStream;
348 if (!_archives.IsEmpty())
349 {
350 if (!openVolumeCallback)
351 break;
352
353 if(_archives.Size() == 1)
354 {
355 if (!_archiveInfo.IsVolume())
356 break;
357 UString baseName;
358 {
359 NCOM::CPropVariant prop;
360 RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
361 if (prop.vt != VT_BSTR)
362 break;
363 baseName = prop.bstrVal;
364 }
365 seqName.InitName(baseName, _archiveInfo.HaveNewVolumeName());
366 }
367
368 UString fullName = seqName.GetNextName();
369 HRESULT result = openVolumeCallback->GetStream(fullName, &inStream);
370 if (result == S_FALSE)
371 break;
372 if (result != S_OK)
373 return result;
374 if (!stream)
375 break;
376 }
377 else
378 inStream = stream;
379
380 UInt64 endPos = 0;
381 if (openArchiveCallback != NULL)
382 {
383 RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
384 RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
385 totalBytes += endPos;
386 RINOK(openArchiveCallback->SetTotal(NULL, &totalBytes));
387 }
388
389 NArchive::NRar::CInArchive archive;
390 RINOK(archive.Open(inStream, maxCheckStartPosition));
391
392 if (_archives.IsEmpty())
393 archive.GetArchiveInfo(_archiveInfo);
394
395 CItemEx item;
396 for (;;)
397 {
398 HRESULT result = archive.GetNextItem(item, getTextPassword);
399 if (result == S_FALSE)
400 break;
401 RINOK(result);
402 if (item.IgnoreItem())
403 continue;
404
405 bool needAdd = true;
406 if (item.IsSplitBefore())
407 {
408 if (!_refItems.IsEmpty())
409 {
410 CRefItem &refItem = _refItems.Back();
411 refItem.NumItems++;
412 needAdd = false;
413 }
414 }
415 if (needAdd)
416 {
417 CRefItem refItem;
418 refItem.ItemIndex = _items.Size();
419 refItem.NumItems = 1;
420 refItem.VolumeIndex = _archives.Size();
421 _refItems.Add(refItem);
422 }
423 _items.Add(item);
424 if (openArchiveCallback != NULL && _items.Size() % 100 == 0)
425 {
426 UInt64 numFiles = _items.Size();
427 UInt64 numBytes = curBytes + item.Position;
428 RINOK(openArchiveCallback->SetCompleted(&numFiles, &numBytes));
429 }
430 }
431 curBytes += endPos;
432 _archives.Add(archive);
433 }
434 }
435 return S_OK;
436 }
437
Open(IInStream * stream,const UInt64 * maxCheckStartPosition,IArchiveOpenCallback * openArchiveCallback)438 STDMETHODIMP CHandler::Open(IInStream *stream,
439 const UInt64 *maxCheckStartPosition,
440 IArchiveOpenCallback *openArchiveCallback)
441 {
442 COM_TRY_BEGIN
443 Close();
444 try
445 {
446 HRESULT res = Open2(stream, maxCheckStartPosition, openArchiveCallback);
447 if (res != S_OK)
448 Close();
449 return res;
450 }
451 catch(const CInArchiveException &) { Close(); return S_FALSE; }
452 catch(...) { Close(); throw; }
453 COM_TRY_END
454 }
455
Close()456 STDMETHODIMP CHandler::Close()
457 {
458 COM_TRY_BEGIN
459 _refItems.Clear();
460 _items.Clear();
461 _archives.Clear();
462 return S_OK;
463 COM_TRY_END
464 }
465
466 struct CMethodItem
467 {
468 Byte RarUnPackVersion;
469 CMyComPtr<ICompressCoder> Coder;
470 };
471
472
Extract(const UInt32 * indices,UInt32 numItems,Int32 _aTestMode,IArchiveExtractCallback * _anExtractCallback)473 STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
474 Int32 _aTestMode, IArchiveExtractCallback *_anExtractCallback)
475 {
476 COM_TRY_BEGIN
477 CMyComPtr<ICryptoGetTextPassword> getTextPassword;
478 bool testMode = (_aTestMode != 0);
479 CMyComPtr<IArchiveExtractCallback> extractCallback = _anExtractCallback;
480 UInt64 censoredTotalUnPacked = 0,
481 // censoredTotalPacked = 0,
482 importantTotalUnPacked = 0;
483 // importantTotalPacked = 0;
484 bool allFilesMode = (numItems == UInt32(-1));
485 if (allFilesMode)
486 numItems = _refItems.Size();
487 if(numItems == 0)
488 return S_OK;
489 int lastIndex = 0;
490 CRecordVector<int> importantIndexes;
491 CRecordVector<bool> extractStatuses;
492
493 for(UInt32 t = 0; t < numItems; t++)
494 {
495 int index = allFilesMode ? t : indices[t];
496 const CRefItem &refItem = _refItems[index];
497 const CItemEx &item = _items[refItem.ItemIndex];
498 censoredTotalUnPacked += item.Size;
499 // censoredTotalPacked += item.PackSize;
500 int j;
501 for(j = lastIndex; j <= index; j++)
502 // if(!_items[_refItems[j].ItemIndex].IsSolid())
503 if(!IsSolid(j))
504 lastIndex = j;
505 for(j = lastIndex; j <= index; j++)
506 {
507 const CRefItem &refItem = _refItems[j];
508 const CItemEx &item = _items[refItem.ItemIndex];
509
510 // const CItemEx &item = _items[j];
511
512 importantTotalUnPacked += item.Size;
513 // importantTotalPacked += item.PackSize;
514 importantIndexes.Add(j);
515 extractStatuses.Add(j == index);
516 }
517 lastIndex = index + 1;
518 }
519
520 extractCallback->SetTotal(importantTotalUnPacked);
521 UInt64 currentImportantTotalUnPacked = 0;
522 UInt64 currentImportantTotalPacked = 0;
523 UInt64 currentUnPackSize, currentPackSize;
524
525 CObjectVector<CMethodItem> methodItems;
526
527 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
528 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
529
530 CFilterCoder *filterStreamSpec = new CFilterCoder;
531 CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec;
532
533 NCrypto::NRar20::CDecoder *rar20CryptoDecoderSpec = NULL;
534 CMyComPtr<ICompressFilter> rar20CryptoDecoder;
535 NCrypto::NRar29::CDecoder *rar29CryptoDecoderSpec = NULL;
536 CMyComPtr<ICompressFilter> rar29CryptoDecoder;
537
538 CFolderInStream *folderInStreamSpec = NULL;
539 CMyComPtr<ISequentialInStream> folderInStream;
540
541 CLocalProgress *lps = new CLocalProgress;
542 CMyComPtr<ICompressProgressInfo> progress = lps;
543 lps->Init(extractCallback, false);
544
545 bool solidStart = true;
546 for(int i = 0; i < importantIndexes.Size(); i++,
547 currentImportantTotalUnPacked += currentUnPackSize,
548 currentImportantTotalPacked += currentPackSize)
549 {
550 lps->InSize = currentImportantTotalPacked;
551 lps->OutSize = currentImportantTotalUnPacked;
552 RINOK(lps->SetCur());
553 CMyComPtr<ISequentialOutStream> realOutStream;
554
555 Int32 askMode;
556 if(extractStatuses[i])
557 askMode = testMode ?
558 NArchive::NExtract::NAskMode::kTest :
559 NArchive::NExtract::NAskMode::kExtract;
560 else
561 askMode = NArchive::NExtract::NAskMode::kSkip;
562
563 UInt32 index = importantIndexes[i];
564
565 const CRefItem &refItem = _refItems[index];
566 const CItemEx &item = _items[refItem.ItemIndex];
567
568 currentUnPackSize = item.Size;
569
570 currentPackSize = GetPackSize(index);
571
572 if(item.IgnoreItem())
573 continue;
574
575 RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
576
577 if (!IsSolid(index))
578 solidStart = true;
579 if(item.IsDir())
580 {
581 RINOK(extractCallback->PrepareOperation(askMode));
582 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
583 continue;
584 }
585
586 bool mustBeProcessedAnywhere = false;
587 if(i < importantIndexes.Size() - 1)
588 {
589 // const CRefItem &nextRefItem = _refItems[importantIndexes[i + 1]];
590 // const CItemEx &nextItemInfo = _items[nextRefItem.ItemIndex];
591 // mustBeProcessedAnywhere = nextItemInfo.IsSolid();
592 mustBeProcessedAnywhere = IsSolid(importantIndexes[i + 1]);
593 }
594
595 if (!mustBeProcessedAnywhere && !testMode && !realOutStream)
596 continue;
597
598 if (!realOutStream && !testMode)
599 askMode = NArchive::NExtract::NAskMode::kSkip;
600
601 RINOK(extractCallback->PrepareOperation(askMode));
602
603 COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
604 CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
605 outStreamSpec->SetStream(realOutStream);
606 outStreamSpec->Init();
607 realOutStream.Release();
608
609 /*
610 for (int partIndex = 0; partIndex < 1; partIndex++)
611 {
612 CMyComPtr<ISequentialInStream> inStream;
613
614 // item redefinition
615 const CItemEx &item = _items[refItem.ItemIndex + partIndex];
616
617 NArchive::NRar::CInArchive &archive = _archives[refItem.VolumeIndex + partIndex];
618
619 inStream.Attach(archive.CreateLimitedStream(item.GetDataPosition(),
620 item.PackSize));
621 */
622 if (!folderInStream)
623 {
624 folderInStreamSpec = new CFolderInStream;
625 folderInStream = folderInStreamSpec;
626 }
627
628 folderInStreamSpec->Init(&_archives, &_items, refItem);
629
630 UInt64 packSize = currentPackSize;
631
632 // packedPos += item.PackSize;
633 // unpackedPos += 0;
634
635 CMyComPtr<ISequentialInStream> inStream;
636 if (item.IsEncrypted())
637 {
638 CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
639 if (item.UnPackVersion >= 29)
640 {
641 if (!rar29CryptoDecoder)
642 {
643 rar29CryptoDecoderSpec = new NCrypto::NRar29::CDecoder;
644 rar29CryptoDecoder = rar29CryptoDecoderSpec;
645 // RINOK(rar29CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar29Decoder));
646 }
647 rar29CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36);
648 CMyComPtr<ICompressSetDecoderProperties2> cryptoProperties;
649 RINOK(rar29CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2,
650 &cryptoProperties));
651 RINOK(cryptoProperties->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0));
652 filterStreamSpec->Filter = rar29CryptoDecoder;
653 }
654 else if (item.UnPackVersion >= 20)
655 {
656 if (!rar20CryptoDecoder)
657 {
658 rar20CryptoDecoderSpec = new NCrypto::NRar20::CDecoder;
659 rar20CryptoDecoder = rar20CryptoDecoderSpec;
660 // RINOK(rar20CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar20Decoder));
661 }
662 filterStreamSpec->Filter = rar20CryptoDecoder;
663 }
664 else
665 {
666 outStream.Release();
667 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
668 continue;
669 }
670 RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword,
671 &cryptoSetPassword));
672
673 if (!getTextPassword)
674 extractCallback.QueryInterface(IID_ICryptoGetTextPassword,
675 &getTextPassword);
676 if (getTextPassword)
677 {
678 CMyComBSTR password;
679 RINOK(getTextPassword->CryptoGetTextPassword(&password));
680 if (item.UnPackVersion >= 29)
681 {
682 CByteBuffer buffer;
683 UString unicodePassword(password);
684 const UInt32 sizeInBytes = unicodePassword.Length() * 2;
685 buffer.SetCapacity(sizeInBytes);
686 for (int i = 0; i < unicodePassword.Length(); i++)
687 {
688 wchar_t c = unicodePassword[i];
689 ((Byte *)buffer)[i * 2] = (Byte)c;
690 ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
691 }
692 RINOK(cryptoSetPassword->CryptoSetPassword(
693 (const Byte *)buffer, sizeInBytes));
694 }
695 else
696 {
697 AString oemPassword = UnicodeStringToMultiByte(
698 (const wchar_t *)password, CP_OEMCP);
699 RINOK(cryptoSetPassword->CryptoSetPassword(
700 (const Byte *)(const char *)oemPassword, oemPassword.Length()));
701 }
702 }
703 else
704 {
705 RINOK(cryptoSetPassword->CryptoSetPassword(0, 0));
706 }
707 filterStreamSpec->SetInStream(folderInStream);
708 inStream = filterStream;
709 }
710 else
711 {
712 inStream = folderInStream;
713 }
714 CMyComPtr<ICompressCoder> commonCoder;
715 switch(item.Method)
716 {
717 case '0':
718 {
719 commonCoder = copyCoder;
720 break;
721 }
722 case '1':
723 case '2':
724 case '3':
725 case '4':
726 case '5':
727 {
728 /*
729 if (item.UnPackVersion >= 29)
730 {
731 outStream.Release();
732 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
733 continue;
734 }
735 */
736 int m;
737 for (m = 0; m < methodItems.Size(); m++)
738 if (methodItems[m].RarUnPackVersion == item.UnPackVersion)
739 break;
740 if (m == methodItems.Size())
741 {
742 CMethodItem mi;
743 mi.RarUnPackVersion = item.UnPackVersion;
744
745 mi.Coder.Release();
746 if (item.UnPackVersion <= 30)
747 {
748 UInt32 methodID = 0x040300;
749 if (item.UnPackVersion < 20)
750 methodID += 1;
751 else if (item.UnPackVersion < 29)
752 methodID += 2;
753 else
754 methodID += 3;
755 RINOK(CreateCoder(EXTERNAL_CODECS_VARS methodID, mi.Coder, false));
756 }
757
758 if (mi.Coder == 0)
759 {
760 outStream.Release();
761 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
762 continue;
763 }
764
765 m = methodItems.Add(mi);
766 }
767 CMyComPtr<ICompressCoder> decoder = methodItems[m].Coder;
768
769 CMyComPtr<ICompressSetDecoderProperties2> compressSetDecoderProperties;
770 RINOK(decoder.QueryInterface(IID_ICompressSetDecoderProperties2,
771 &compressSetDecoderProperties));
772
773 Byte isSolid = (Byte)((IsSolid(index) || item.IsSplitBefore()) ? 1: 0);
774 if (solidStart)
775 {
776 isSolid = false;
777 solidStart = false;
778 }
779
780
781 RINOK(compressSetDecoderProperties->SetDecoderProperties2(&isSolid, 1));
782
783 commonCoder = decoder;
784 break;
785 }
786 default:
787 outStream.Release();
788 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
789 continue;
790 }
791 HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &item.Size, progress);
792 if (item.IsEncrypted())
793 filterStreamSpec->ReleaseInStream();
794 if (result == S_FALSE)
795 {
796 outStream.Release();
797 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kDataError));
798 continue;
799 }
800 if (result != S_OK)
801 return result;
802
803 /*
804 if (refItem.NumItems == 1 &&
805 !item.IsSplitBefore() && !item.IsSplitAfter())
806 */
807 {
808 const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
809 bool crcOK = outStreamSpec->GetCRC() == lastItem.FileCRC;
810 outStream.Release();
811 RINOK(extractCallback->SetOperationResult(crcOK ? NArchive::NExtract::NOperationResult::kOK:
812 NArchive::NExtract::NOperationResult::kCRCError));
813 }
814 /*
815 else
816 {
817 bool crcOK = true;
818 for (int partIndex = 0; partIndex < refItem.NumItems; partIndex++)
819 {
820 const CItemEx &item = _items[refItem.ItemIndex + partIndex];
821 if (item.FileCRC != folderInStreamSpec->CRCs[partIndex])
822 {
823 crcOK = false;
824 break;
825 }
826 }
827 RINOK(extractCallback->SetOperationResult(crcOK ? NArchive::NExtract::NOperationResult::kOK:
828 NArchive::NExtract::NOperationResult::kCRCError));
829 }
830 */
831 }
832 return S_OK;
833 COM_TRY_END
834 }
835
836 IMPL_ISetCompressCodecsInfo
837
838 }}
839