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