Mercurial > vba-linux
comparison 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 |
comparison
equal
deleted
inserted
replaced
0:8ced16adf2e1 | 1:f9f4f1b99eed |
---|---|
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 | |
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 } | |
93 | |
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 | |
121 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) | |
122 { | |
123 *numItems = _refItems.Size(); | |
124 return S_OK; | |
125 } | |
126 | |
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 | |
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 | |
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: | |
231 CVolumeName(): _newStyle(true) {}; | |
232 | |
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 } | |
264 | |
265 if (!_newStyle) | |
266 { | |
267 _afterPart.Empty(); | |
268 _unchangedPart = basePart + UString(L"."); | |
269 _changedPart = L"r00"; | |
270 return true; | |
271 } | |
272 | |
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 } | |
289 | |
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 }; | |
321 | |
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; | |
330 | |
331 CVolumeName seqName; | |
332 | |
333 UInt64 totalBytes = 0; | |
334 UInt64 curBytes = 0; | |
335 | |
336 if (openArchiveCallback != NULL) | |
337 { | |
338 openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback); | |
339 openArchiveCallbackWrap.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); | |
340 } | |
341 | |
342 for (;;) | |
343 { | |
344 CMyComPtr<IInStream> inStream; | |
345 if (!_archives.IsEmpty()) | |
346 { | |
347 if (!openVolumeCallback) | |
348 break; | |
349 | |
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 } | |
364 | |
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; | |
376 | |
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 } | |
385 | |
386 NArchive::NRar::CInArchive archive; | |
387 RINOK(archive.Open(inStream, maxCheckStartPosition)); | |
388 | |
389 if (_archives.IsEmpty()) | |
390 archive.GetArchiveInfo(_archiveInfo); | |
391 | |
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; | |
401 | |
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 } | |
434 | |
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 } | |
452 | |
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 } | |
462 | |
463 struct CMethodItem | |
464 { | |
465 Byte RarUnPackVersion; | |
466 CMyComPtr<ICompressCoder> Coder; | |
467 }; | |
468 | |
469 | |
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; | |
489 | |
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]; | |
506 | |
507 // const CItemEx &item = _items[j]; | |
508 | |
509 importantTotalUnPacked += item.Size; | |
510 // importantTotalPacked += item.PackSize; | |
511 importantIndexes.Add(j); | |
512 extractStatuses.Add(j == index); | |
513 } | |
514 lastIndex = index + 1; | |
515 } | |
516 | |
517 extractCallback->SetTotal(importantTotalUnPacked); | |
518 UInt64 currentImportantTotalUnPacked = 0; | |
519 UInt64 currentImportantTotalPacked = 0; | |
520 UInt64 currentUnPackSize, currentPackSize; | |
521 | |
522 CObjectVector<CMethodItem> methodItems; | |
523 | |
524 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; | |
525 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; | |
526 | |
527 CFilterCoder *filterStreamSpec = new CFilterCoder; | |
528 CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec; | |
529 | |
530 NCrypto::NRar20::CDecoder *rar20CryptoDecoderSpec = NULL; | |
531 CMyComPtr<ICompressFilter> rar20CryptoDecoder; | |
532 NCrypto::NRar29::CDecoder *rar29CryptoDecoderSpec = NULL; | |
533 CMyComPtr<ICompressFilter> rar29CryptoDecoder; | |
534 | |
535 CFolderInStream *folderInStreamSpec = NULL; | |
536 CMyComPtr<ISequentialInStream> folderInStream; | |
537 | |
538 CLocalProgress *lps = new CLocalProgress; | |
539 CMyComPtr<ICompressProgressInfo> progress = lps; | |
540 lps->Init(extractCallback, false); | |
541 | |
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; | |
551 | |
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; | |
559 | |
560 UInt32 index = importantIndexes[i]; | |
561 | |
562 const CRefItem &refItem = _refItems[index]; | |
563 const CItemEx &item = _items[refItem.ItemIndex]; | |
564 | |
565 currentUnPackSize = item.Size; | |
566 | |
567 currentPackSize = GetPackSize(index); | |
568 | |
569 if(item.IgnoreItem()) | |
570 continue; | |
571 | |
572 RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); | |
573 | |
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 } | |
582 | |
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 } | |
591 | |
592 if (!mustBeProcessedAnywhere && !testMode && !realOutStream) | |
593 continue; | |
594 | |
595 if (!realOutStream && !testMode) | |
596 askMode = NArchive::NExtract::NAskMode::kSkip; | |
597 | |
598 RINOK(extractCallback->PrepareOperation(askMode)); | |
599 | |
600 COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; | |
601 CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); | |
602 outStreamSpec->SetStream(realOutStream); | |
603 outStreamSpec->Init(); | |
604 realOutStream.Release(); | |
605 | |
606 /* | |
607 for (int partIndex = 0; partIndex < 1; partIndex++) | |
608 { | |
609 CMyComPtr<ISequentialInStream> inStream; | |
610 | |
611 // item redefinition | |
612 const CItemEx &item = _items[refItem.ItemIndex + partIndex]; | |
613 | |
614 NArchive::NRar::CInArchive &archive = _archives[refItem.VolumeIndex + partIndex]; | |
615 | |
616 inStream.Attach(archive.CreateLimitedStream(item.GetDataPosition(), | |
617 item.PackSize)); | |
618 */ | |
619 if (!folderInStream) | |
620 { | |
621 folderInStreamSpec = new CFolderInStream; | |
622 folderInStream = folderInStreamSpec; | |
623 } | |
624 | |
625 folderInStreamSpec->Init(&_archives, &_items, refItem); | |
626 | |
627 UInt64 packSize = currentPackSize; | |
628 | |
629 // packedPos += item.PackSize; | |
630 // unpackedPos += 0; | |
631 | |
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)); | |
669 | |
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; | |
741 | |
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 } | |
754 | |
755 if (mi.Coder == 0) | |
756 { | |
757 outStream.Release(); | |
758 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod)); | |
759 continue; | |
760 } | |
761 | |
762 m = methodItems.Add(mi); | |
763 } | |
764 CMyComPtr<ICompressCoder> decoder = methodItems[m].Coder; | |
765 | |
766 CMyComPtr<ICompressSetDecoderProperties2> compressSetDecoderProperties; | |
767 RINOK(decoder.QueryInterface(IID_ICompressSetDecoderProperties2, | |
768 &compressSetDecoderProperties)); | |
769 | |
770 Byte isSolid = (Byte)((IsSolid(index) || item.IsSplitBefore()) ? 1: 0); | |
771 if (solidStart) | |
772 { | |
773 isSolid = false; | |
774 solidStart = false; | |
775 } | |
776 | |
777 | |
778 RINOK(compressSetDecoderProperties->SetDecoderProperties2(&isSolid, 1)); | |
779 | |
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; | |
799 | |
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 } | |
832 | |
833 IMPL_ISetCompressCodecsInfo | |
834 | |
835 }} |