Extract.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // Extract.cpp
  2. #include "StdAfx.h"
  3. #include "Extract.h"
  4. #include "Windows/Defs.h"
  5. #include "Windows/FileDir.h"
  6. #include "OpenArchive.h"
  7. #include "SetProperties.h"
  8. using namespace NWindows;
  9. HRESULT DecompressArchive(
  10. IInArchive *archive,
  11. UInt64 packSize,
  12. const UString &defaultName,
  13. const NWildcard::CCensorNode &wildcardCensor,
  14. const CExtractOptions &options,
  15. IExtractCallbackUI *callback,
  16. CArchiveExtractCallback *extractCallbackSpec,
  17. UString &errorMessage)
  18. {
  19. CRecordVector<UInt32> realIndices;
  20. UInt32 numItems;
  21. RINOK(archive->GetNumberOfItems(&numItems));
  22. for(UInt32 i = 0; i < numItems; i++)
  23. {
  24. UString filePath;
  25. RINOK(GetArchiveItemPath(archive, i, options.DefaultItemName, filePath));
  26. bool isFolder;
  27. RINOK(IsArchiveItemFolder(archive, i, isFolder));
  28. if (!wildcardCensor.CheckPath(filePath, !isFolder))
  29. continue;
  30. realIndices.Add(i);
  31. }
  32. if (realIndices.Size() == 0)
  33. {
  34. callback->ThereAreNoFiles();
  35. return S_OK;
  36. }
  37. UStringVector removePathParts;
  38. UString outDir = options.OutputDir;
  39. outDir.Replace(L"*", defaultName);
  40. if(!outDir.IsEmpty())
  41. if(!NFile::NDirectory::CreateComplexDirectory(outDir))
  42. {
  43. HRESULT res = ::GetLastError();
  44. if (res == S_OK)
  45. res = E_FAIL;
  46. errorMessage = ((UString)L"Can not create output directory ") + outDir;
  47. return res;
  48. }
  49. extractCallbackSpec->Init(
  50. archive,
  51. callback,
  52. options.StdOutMode,
  53. outDir,
  54. removePathParts,
  55. options.DefaultItemName,
  56. options.ArchiveFileInfo.LastWriteTime,
  57. options.ArchiveFileInfo.Attributes,
  58. packSize);
  59. #ifdef COMPRESS_MT
  60. RINOK(SetProperties(archive, options.Properties));
  61. #endif
  62. HRESULT result = archive->Extract(&realIndices.Front(),
  63. realIndices.Size(), options.TestMode? 1: 0, extractCallbackSpec);
  64. return callback->ExtractResult(result);
  65. }
  66. HRESULT DecompressArchives(
  67. CCodecs *codecs,
  68. UStringVector &archivePaths, UStringVector &archivePathsFull,
  69. const NWildcard::CCensorNode &wildcardCensor,
  70. const CExtractOptions &optionsSpec,
  71. IOpenCallbackUI *openCallback,
  72. IExtractCallbackUI *extractCallback,
  73. UString &errorMessage,
  74. CDecompressStat &stat)
  75. {
  76. stat.Clear();
  77. CExtractOptions options = optionsSpec;
  78. int i;
  79. UInt64 totalPackSize = 0;
  80. CRecordVector<UInt64> archiveSizes;
  81. for (i = 0; i < archivePaths.Size(); i++)
  82. {
  83. const UString &archivePath = archivePaths[i];
  84. NFile::NFind::CFileInfoW archiveFileInfo;
  85. if (!NFile::NFind::FindFile(archivePath, archiveFileInfo))
  86. throw "there is no such archive";
  87. if (archiveFileInfo.IsDirectory())
  88. throw "can't decompress folder";
  89. archiveSizes.Add(archiveFileInfo.Size);
  90. totalPackSize += archiveFileInfo.Size;
  91. }
  92. CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
  93. CMyComPtr<IArchiveExtractCallback> ec(extractCallbackSpec);
  94. bool multi = (archivePaths.Size() > 1);
  95. extractCallbackSpec->InitForMulti(multi, options.PathMode, options.OverwriteMode);
  96. if (multi)
  97. {
  98. RINOK(extractCallback->SetTotal(totalPackSize));
  99. }
  100. for (i = 0; i < archivePaths.Size(); i++)
  101. {
  102. const UString &archivePath = archivePaths[i];
  103. NFile::NFind::CFileInfoW archiveFileInfo;
  104. if (!NFile::NFind::FindFile(archivePath, archiveFileInfo))
  105. throw "there is no such archive";
  106. if (archiveFileInfo.IsDirectory())
  107. throw "there is no such archive";
  108. options.ArchiveFileInfo = archiveFileInfo;
  109. #ifndef _NO_CRYPTO
  110. openCallback->ClearPasswordWasAskedFlag();
  111. #endif
  112. RINOK(extractCallback->BeforeOpen(archivePath));
  113. CArchiveLink archiveLink;
  114. HRESULT result = MyOpenArchive(codecs, archivePath, archiveLink, openCallback);
  115. bool crypted = false;
  116. #ifndef _NO_CRYPTO
  117. crypted = openCallback->WasPasswordAsked();
  118. #endif
  119. RINOK(extractCallback->OpenResult(archivePath, result, crypted));
  120. if (result != S_OK)
  121. continue;
  122. for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)
  123. {
  124. int index = archivePathsFull.FindInSorted(archiveLink.VolumePaths[v]);
  125. if (index >= 0 && index > i)
  126. {
  127. archivePaths.Delete(index);
  128. archivePathsFull.Delete(index);
  129. totalPackSize -= archiveSizes[index];
  130. archiveSizes.Delete(index);
  131. }
  132. }
  133. if (archiveLink.VolumePaths.Size() != 0)
  134. {
  135. totalPackSize += archiveLink.VolumesSize;
  136. RINOK(extractCallback->SetTotal(totalPackSize));
  137. }
  138. #ifndef _NO_CRYPTO
  139. UString password;
  140. RINOK(openCallback->GetPasswordIfAny(password));
  141. if (!password.IsEmpty())
  142. {
  143. RINOK(extractCallback->SetPassword(password));
  144. }
  145. #endif
  146. options.DefaultItemName = archiveLink.GetDefaultItemName();
  147. RINOK(DecompressArchive(
  148. archiveLink.GetArchive(),
  149. archiveFileInfo.Size + archiveLink.VolumesSize,
  150. archiveLink.GetDefaultItemName(),
  151. wildcardCensor, options, extractCallback, extractCallbackSpec, errorMessage));
  152. extractCallbackSpec->LocalProgressSpec->InSize += archiveFileInfo.Size +
  153. archiveLink.VolumesSize;
  154. extractCallbackSpec->LocalProgressSpec->OutSize = extractCallbackSpec->UnpackSize;
  155. if (!errorMessage.IsEmpty())
  156. return E_FAIL;
  157. }
  158. stat.NumFolders = extractCallbackSpec->NumFolders;
  159. stat.NumFiles = extractCallbackSpec->NumFiles;
  160. stat.UnpackSize = extractCallbackSpec->UnpackSize;
  161. stat.NumArchives = archivePaths.Size();
  162. stat.PackSize = extractCallbackSpec->LocalProgressSpec->InSize;
  163. return S_OK;
  164. }