view src/win32/7zip/7z/CPP/7zip/Archive/Rar/RarHandler.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
line wrap: on
line source
1 // RarHandler.cpp
3 #include "StdAfx.h"
5 #include "Common/ComTry.h"
6 #include "Common/IntToString.h"
7 #include "Common/StringConvert.h"
9 #include "Windows/PropVariant.h"
10 #include "Windows/Time.h"
12 #include "../../IPassword.h"
14 #include "../../Common/CreateCoder.h"
15 #include "../../Common/FilterCoder.h"
16 #include "../../Common/MethodId.h"
17 #include "../../Common/ProgressUtils.h"
19 #include "../../Compress/CopyCoder.h"
21 #include "../../Crypto/Rar20Crypto.h"
22 #include "../../Crypto/RarAes.h"
24 #include "../Common/ItemNameUtils.h"
25 #include "../Common/OutStreamWithCRC.h"
27 #include "RarHandler.h"
29 using namespace NWindows;
30 using namespace NTime;
32 namespace NArchive {
33 namespace NRar {
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 };
45 static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);
47 static const wchar_t *kUnknownOS = L"Unknown";
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},
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 };
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 };
82 IMP_IInArchive_Props
83 IMP_IInArchive_ArcProps
85 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 }
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 }
121 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
122 {
123 *numItems = _refItems.Size();
124 return S_OK;
125 }
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 }
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 }
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 }
223 class CVolumeName
224 {
225 bool _first;
226 bool _newStyle;
227 UString _unchangedPart;
228 UString _changedPart;
229 UString _afterPart;
230 public:
231 CVolumeName(): _newStyle(true) {};
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 || ext.CompareNoCase(L"001") == 0)
255 {
256 _afterPart.Empty();
257 _first = false;
258 _changedPart = ext;
259 _unchangedPart = name.Left(dotPos + 1);
260 return true;
261 }
262 }
263 }
265 if (!_newStyle)
266 {
267 _afterPart.Empty();
268 _unchangedPart = basePart + UString(L".");
269 _changedPart = L"r00";
270 return true;
271 }
273 int numLetters = 1;
274 if (basePart.Right(numLetters) == L"1" || basePart.Right(numLetters) == L"0")
275 {
276 while (numLetters < basePart.Length())
277 {
278 if (basePart[basePart.Length() - numLetters - 1] != '0')
279 break;
280 numLetters++;
281 }
282 }
283 else
284 return false;
285 _unchangedPart = basePart.Left(basePart.Length() - numLetters);
286 _changedPart = basePart.Right(numLetters);
287 return true;
288 }
290 UString GetNextName()
291 {
292 UString newName;
293 if (_newStyle || !_first)
294 {
295 int i;
296 int numLetters = _changedPart.Length();
297 for (i = numLetters - 1; i >= 0; i--)
298 {
299 wchar_t c = _changedPart[i];
300 if (c == L'9')
301 {
302 c = L'0';
303 newName = c + newName;
304 if (i == 0)
305 newName = UString(L'1') + newName;
306 continue;
307 }
308 c++;
309 newName = UString(c) + newName;
310 i--;
311 for (; i >= 0; i--)
312 newName = _changedPart[i] + newName;
313 break;
314 }
315 _changedPart = newName;
316 }
317 _first = false;
318 return _unchangedPart + _changedPart + _afterPart;
319 }
320 };
322 HRESULT CHandler::Open2(IInStream *stream,
323 const UInt64 *maxCheckStartPosition,
324 IArchiveOpenCallback *openArchiveCallback)
325 {
326 {
327 CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
328 CMyComPtr<ICryptoGetTextPassword> getTextPassword;
329 CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openArchiveCallback;
331 CVolumeName seqName;
333 UInt64 totalBytes = 0;
334 UInt64 curBytes = 0;
336 if (openArchiveCallback != NULL)
337 {
338 openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
339 openArchiveCallbackWrap.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
340 }
342 for (;;)
343 {
344 CMyComPtr<IInStream> inStream;
345 if (!_archives.IsEmpty())
346 {
347 if (!openVolumeCallback)
348 break;
350 if(_archives.Size() == 1)
351 {
352 if (!_archiveInfo.IsVolume())
353 break;
354 UString baseName;
355 {
356 NCOM::CPropVariant prop;
357 RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
358 if (prop.vt != VT_BSTR)
359 break;
360 baseName = prop.bstrVal;
361 }
362 seqName.InitName(baseName, _archiveInfo.HaveNewVolumeName());
363 }
365 UString fullName = seqName.GetNextName();
366 HRESULT result = openVolumeCallback->GetStream(fullName, &inStream);
367 if (result == S_FALSE)
368 break;
369 if (result != S_OK)
370 return result;
371 if (!stream)
372 break;
373 }
374 else
375 inStream = stream;
377 UInt64 endPos = 0;
378 if (openArchiveCallback != NULL)
379 {
380 RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
381 RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
382 totalBytes += endPos;
383 RINOK(openArchiveCallback->SetTotal(NULL, &totalBytes));
384 }
386 NArchive::NRar::CInArchive archive;
387 RINOK(archive.Open(inStream, maxCheckStartPosition));
389 if (_archives.IsEmpty())
390 archive.GetArchiveInfo(_archiveInfo);
392 CItemEx item;
393 for (;;)
394 {
395 HRESULT result = archive.GetNextItem(item, getTextPassword);
396 if (result == S_FALSE)
397 break;
398 RINOK(result);
399 if (item.IgnoreItem())
400 continue;
402 bool needAdd = true;
403 if (item.IsSplitBefore())
404 {
405 if (!_refItems.IsEmpty())
406 {
407 CRefItem &refItem = _refItems.Back();
408 refItem.NumItems++;
409 needAdd = false;
410 }
411 }
412 if (needAdd)
413 {
414 CRefItem refItem;
415 refItem.ItemIndex = _items.Size();
416 refItem.NumItems = 1;
417 refItem.VolumeIndex = _archives.Size();
418 _refItems.Add(refItem);
419 }
420 _items.Add(item);
421 if (openArchiveCallback != NULL && _items.Size() % 100 == 0)
422 {
423 UInt64 numFiles = _items.Size();
424 UInt64 numBytes = curBytes + item.Position;
425 RINOK(openArchiveCallback->SetCompleted(&numFiles, &numBytes));
426 }
427 }
428 curBytes += endPos;
429 _archives.Add(archive);
430 }
431 }
432 return S_OK;
433 }
435 STDMETHODIMP CHandler::Open(IInStream *stream,
436 const UInt64 *maxCheckStartPosition,
437 IArchiveOpenCallback *openArchiveCallback)
438 {
439 COM_TRY_BEGIN
440 Close();
441 try
442 {
443 HRESULT res = Open2(stream, maxCheckStartPosition, openArchiveCallback);
444 if (res != S_OK)
445 Close();
446 return res;
447 }
448 catch(const CInArchiveException &) { Close(); return S_FALSE; }
449 catch(...) { Close(); throw; }
450 COM_TRY_END
451 }
453 STDMETHODIMP CHandler::Close()
454 {
455 COM_TRY_BEGIN
456 _refItems.Clear();
457 _items.Clear();
458 _archives.Clear();
459 return S_OK;
460 COM_TRY_END
461 }
463 struct CMethodItem
464 {
465 Byte RarUnPackVersion;
466 CMyComPtr<ICompressCoder> Coder;
467 };
470 STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
471 Int32 _aTestMode, IArchiveExtractCallback *_anExtractCallback)
472 {
473 COM_TRY_BEGIN
474 CMyComPtr<ICryptoGetTextPassword> getTextPassword;
475 bool testMode = (_aTestMode != 0);
476 CMyComPtr<IArchiveExtractCallback> extractCallback = _anExtractCallback;
477 UInt64 censoredTotalUnPacked = 0,
478 // censoredTotalPacked = 0,
479 importantTotalUnPacked = 0;
480 // importantTotalPacked = 0;
481 bool allFilesMode = (numItems == UInt32(-1));
482 if (allFilesMode)
483 numItems = _refItems.Size();
484 if(numItems == 0)
485 return S_OK;
486 int lastIndex = 0;
487 CRecordVector<int> importantIndexes;
488 CRecordVector<bool> extractStatuses;
490 for(UInt32 t = 0; t < numItems; t++)
491 {
492 int index = allFilesMode ? t : indices[t];
493 const CRefItem &refItem = _refItems[index];
494 const CItemEx &item = _items[refItem.ItemIndex];
495 censoredTotalUnPacked += item.Size;
496 // censoredTotalPacked += item.PackSize;
497 int j;
498 for(j = lastIndex; j <= index; j++)
499 // if(!_items[_refItems[j].ItemIndex].IsSolid())
500 if(!IsSolid(j))
501 lastIndex = j;
502 for(j = lastIndex; j <= index; j++)
503 {
504 const CRefItem &refItem = _refItems[j];
505 const CItemEx &item = _items[refItem.ItemIndex];
507 // const CItemEx &item = _items[j];
509 importantTotalUnPacked += item.Size;
510 // importantTotalPacked += item.PackSize;
511 importantIndexes.Add(j);
512 extractStatuses.Add(j == index);
513 }
514 lastIndex = index + 1;
515 }
517 extractCallback->SetTotal(importantTotalUnPacked);
518 UInt64 currentImportantTotalUnPacked = 0;
519 UInt64 currentImportantTotalPacked = 0;
520 UInt64 currentUnPackSize, currentPackSize;
522 CObjectVector<CMethodItem> methodItems;
524 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
525 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
527 CFilterCoder *filterStreamSpec = new CFilterCoder;
528 CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec;
530 NCrypto::NRar20::CDecoder *rar20CryptoDecoderSpec = NULL;
531 CMyComPtr<ICompressFilter> rar20CryptoDecoder;
532 NCrypto::NRar29::CDecoder *rar29CryptoDecoderSpec = NULL;
533 CMyComPtr<ICompressFilter> rar29CryptoDecoder;
535 CFolderInStream *folderInStreamSpec = NULL;
536 CMyComPtr<ISequentialInStream> folderInStream;
538 CLocalProgress *lps = new CLocalProgress;
539 CMyComPtr<ICompressProgressInfo> progress = lps;
540 lps->Init(extractCallback, false);
542 bool solidStart = true;
543 for(int i = 0; i < importantIndexes.Size(); i++,
544 currentImportantTotalUnPacked += currentUnPackSize,
545 currentImportantTotalPacked += currentPackSize)
546 {
547 lps->InSize = currentImportantTotalPacked;
548 lps->OutSize = currentImportantTotalUnPacked;
549 RINOK(lps->SetCur());
550 CMyComPtr<ISequentialOutStream> realOutStream;
552 Int32 askMode;
553 if(extractStatuses[i])
554 askMode = testMode ?
555 NArchive::NExtract::NAskMode::kTest :
556 NArchive::NExtract::NAskMode::kExtract;
557 else
558 askMode = NArchive::NExtract::NAskMode::kSkip;
560 UInt32 index = importantIndexes[i];
562 const CRefItem &refItem = _refItems[index];
563 const CItemEx &item = _items[refItem.ItemIndex];
565 currentUnPackSize = item.Size;
567 currentPackSize = GetPackSize(index);
569 if(item.IgnoreItem())
570 continue;
572 RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
574 if (!IsSolid(index))
575 solidStart = true;
576 if(item.IsDir())
577 {
578 RINOK(extractCallback->PrepareOperation(askMode));
579 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
580 continue;
581 }
583 bool mustBeProcessedAnywhere = false;
584 if(i < importantIndexes.Size() - 1)
585 {
586 // const CRefItem &nextRefItem = _refItems[importantIndexes[i + 1]];
587 // const CItemEx &nextItemInfo = _items[nextRefItem.ItemIndex];
588 // mustBeProcessedAnywhere = nextItemInfo.IsSolid();
589 mustBeProcessedAnywhere = IsSolid(importantIndexes[i + 1]);
590 }
592 if (!mustBeProcessedAnywhere && !testMode && !realOutStream)
593 continue;
595 if (!realOutStream && !testMode)
596 askMode = NArchive::NExtract::NAskMode::kSkip;
598 RINOK(extractCallback->PrepareOperation(askMode));
600 COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
601 CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
602 outStreamSpec->SetStream(realOutStream);
603 outStreamSpec->Init();
604 realOutStream.Release();
606 /*
607 for (int partIndex = 0; partIndex < 1; partIndex++)
608 {
609 CMyComPtr<ISequentialInStream> inStream;
611 // item redefinition
612 const CItemEx &item = _items[refItem.ItemIndex + partIndex];
614 NArchive::NRar::CInArchive &archive = _archives[refItem.VolumeIndex + partIndex];
616 inStream.Attach(archive.CreateLimitedStream(item.GetDataPosition(),
617 item.PackSize));
618 */
619 if (!folderInStream)
620 {
621 folderInStreamSpec = new CFolderInStream;
622 folderInStream = folderInStreamSpec;
623 }
625 folderInStreamSpec->Init(&_archives, &_items, refItem);
627 UInt64 packSize = currentPackSize;
629 // packedPos += item.PackSize;
630 // unpackedPos += 0;
632 CMyComPtr<ISequentialInStream> inStream;
633 if (item.IsEncrypted())
634 {
635 CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
636 if (item.UnPackVersion >= 29)
637 {
638 if (!rar29CryptoDecoder)
639 {
640 rar29CryptoDecoderSpec = new NCrypto::NRar29::CDecoder;
641 rar29CryptoDecoder = rar29CryptoDecoderSpec;
642 // RINOK(rar29CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar29Decoder));
643 }
644 rar29CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36);
645 CMyComPtr<ICompressSetDecoderProperties2> cryptoProperties;
646 RINOK(rar29CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2,
647 &cryptoProperties));
648 RINOK(cryptoProperties->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0));
649 filterStreamSpec->Filter = rar29CryptoDecoder;
650 }
651 else if (item.UnPackVersion >= 20)
652 {
653 if (!rar20CryptoDecoder)
654 {
655 rar20CryptoDecoderSpec = new NCrypto::NRar20::CDecoder;
656 rar20CryptoDecoder = rar20CryptoDecoderSpec;
657 // RINOK(rar20CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar20Decoder));
658 }
659 filterStreamSpec->Filter = rar20CryptoDecoder;
660 }
661 else
662 {
663 outStream.Release();
664 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
665 continue;
666 }
667 RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword,
668 &cryptoSetPassword));
670 if (!getTextPassword)
671 extractCallback.QueryInterface(IID_ICryptoGetTextPassword,
672 &getTextPassword);
673 if (getTextPassword)
674 {
675 CMyComBSTR password;
676 RINOK(getTextPassword->CryptoGetTextPassword(&password));
677 if (item.UnPackVersion >= 29)
678 {
679 CByteBuffer buffer;
680 UString unicodePassword(password);
681 const UInt32 sizeInBytes = unicodePassword.Length() * 2;
682 buffer.SetCapacity(sizeInBytes);
683 for (int i = 0; i < unicodePassword.Length(); i++)
684 {
685 wchar_t c = unicodePassword[i];
686 ((Byte *)buffer)[i * 2] = (Byte)c;
687 ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
688 }
689 RINOK(cryptoSetPassword->CryptoSetPassword(
690 (const Byte *)buffer, sizeInBytes));
691 }
692 else
693 {
694 AString oemPassword = UnicodeStringToMultiByte(
695 (const wchar_t *)password, CP_OEMCP);
696 RINOK(cryptoSetPassword->CryptoSetPassword(
697 (const Byte *)(const char *)oemPassword, oemPassword.Length()));
698 }
699 }
700 else
701 {
702 RINOK(cryptoSetPassword->CryptoSetPassword(0, 0));
703 }
704 filterStreamSpec->SetInStream(folderInStream);
705 inStream = filterStream;
706 }
707 else
708 {
709 inStream = folderInStream;
710 }
711 CMyComPtr<ICompressCoder> commonCoder;
712 switch(item.Method)
713 {
714 case '0':
715 {
716 commonCoder = copyCoder;
717 break;
718 }
719 case '1':
720 case '2':
721 case '3':
722 case '4':
723 case '5':
724 {
725 /*
726 if (item.UnPackVersion >= 29)
727 {
728 outStream.Release();
729 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
730 continue;
731 }
732 */
733 int m;
734 for (m = 0; m < methodItems.Size(); m++)
735 if (methodItems[m].RarUnPackVersion == item.UnPackVersion)
736 break;
737 if (m == methodItems.Size())
738 {
739 CMethodItem mi;
740 mi.RarUnPackVersion = item.UnPackVersion;
742 mi.Coder.Release();
743 if (item.UnPackVersion <= 30)
744 {
745 UInt32 methodID = 0x040300;
746 if (item.UnPackVersion < 20)
747 methodID += 1;
748 else if (item.UnPackVersion < 29)
749 methodID += 2;
750 else
751 methodID += 3;
752 RINOK(CreateCoder(EXTERNAL_CODECS_VARS methodID, mi.Coder, false));
753 }
755 if (mi.Coder == 0)
756 {
757 outStream.Release();
758 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
759 continue;
760 }
762 m = methodItems.Add(mi);
763 }
764 CMyComPtr<ICompressCoder> decoder = methodItems[m].Coder;
766 CMyComPtr<ICompressSetDecoderProperties2> compressSetDecoderProperties;
767 RINOK(decoder.QueryInterface(IID_ICompressSetDecoderProperties2,
768 &compressSetDecoderProperties));
770 Byte isSolid = (Byte)((IsSolid(index) || item.IsSplitBefore()) ? 1: 0);
771 if (solidStart)
772 {
773 isSolid = false;
774 solidStart = false;
775 }
778 RINOK(compressSetDecoderProperties->SetDecoderProperties2(&isSolid, 1));
780 commonCoder = decoder;
781 break;
782 }
783 default:
784 outStream.Release();
785 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
786 continue;
787 }
788 HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &item.Size, progress);
789 if (item.IsEncrypted())
790 filterStreamSpec->ReleaseInStream();
791 if (result == S_FALSE)
792 {
793 outStream.Release();
794 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kDataError));
795 continue;
796 }
797 if (result != S_OK)
798 return result;
800 /*
801 if (refItem.NumItems == 1 &&
802 !item.IsSplitBefore() && !item.IsSplitAfter())
803 */
804 {
805 const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
806 bool crcOK = outStreamSpec->GetCRC() == lastItem.FileCRC;
807 outStream.Release();
808 RINOK(extractCallback->SetOperationResult(crcOK ? NArchive::NExtract::NOperationResult::kOK:
809 NArchive::NExtract::NOperationResult::kCRCError));
810 }
811 /*
812 else
813 {
814 bool crcOK = true;
815 for (int partIndex = 0; partIndex < refItem.NumItems; partIndex++)
816 {
817 const CItemEx &item = _items[refItem.ItemIndex + partIndex];
818 if (item.FileCRC != folderInStreamSpec->CRCs[partIndex])
819 {
820 crcOK = false;
821 break;
822 }
823 }
824 RINOK(extractCallback->SetOperationResult(crcOK ? NArchive::NExtract::NOperationResult::kOK:
825 NArchive::NExtract::NOperationResult::kCRCError));
826 }
827 */
828 }
829 return S_OK;
830 COM_TRY_END
831 }
833 IMPL_ISetCompressCodecsInfo
835 }}