Upload 2.0.2
[physicsfs] / lzma / CPP / 7zip / UI / Common / Extract.cpp
diff --git a/lzma/CPP/7zip/UI/Common/Extract.cpp b/lzma/CPP/7zip/UI/Common/Extract.cpp
new file mode 100644 (file)
index 0000000..0e56a08
--- /dev/null
@@ -0,0 +1,187 @@
+// Extract.cpp
+
+#include "StdAfx.h"
+
+#include "Extract.h"
+
+#include "Windows/Defs.h"
+#include "Windows/FileDir.h"
+
+#include "OpenArchive.h"
+#include "SetProperties.h"
+
+using namespace NWindows;
+
+HRESULT DecompressArchive(
+    IInArchive *archive,
+    UInt64 packSize,
+    const UString &defaultName,
+    const NWildcard::CCensorNode &wildcardCensor,
+    const CExtractOptions &options,
+    IExtractCallbackUI *callback,
+    CArchiveExtractCallback *extractCallbackSpec,
+    UString &errorMessage)
+{
+  CRecordVector<UInt32> realIndices;
+  UInt32 numItems;
+  RINOK(archive->GetNumberOfItems(&numItems));
+
+  for(UInt32 i = 0; i < numItems; i++)
+  {
+    UString filePath;
+    RINOK(GetArchiveItemPath(archive, i, options.DefaultItemName, filePath));
+    bool isFolder;
+    RINOK(IsArchiveItemFolder(archive, i, isFolder));
+    if (!wildcardCensor.CheckPath(filePath, !isFolder))
+      continue;
+    realIndices.Add(i);
+  }
+  if (realIndices.Size() == 0)
+  {
+    callback->ThereAreNoFiles();
+    return S_OK;
+  }
+
+  UStringVector removePathParts;
+
+  UString outDir = options.OutputDir;
+  outDir.Replace(L"*", defaultName);
+  if(!outDir.IsEmpty())
+    if(!NFile::NDirectory::CreateComplexDirectory(outDir))
+    {
+      HRESULT res = ::GetLastError();
+      if (res == S_OK)
+        res = E_FAIL;
+      errorMessage = ((UString)L"Can not create output directory ") + outDir;
+      return res;
+    }
+
+  extractCallbackSpec->Init(
+      archive, 
+      callback,
+      options.StdOutMode,
+      outDir, 
+      removePathParts, 
+      options.DefaultItemName, 
+      options.ArchiveFileInfo.LastWriteTime,
+      options.ArchiveFileInfo.Attributes,
+      packSize);
+
+  #ifdef COMPRESS_MT
+  RINOK(SetProperties(archive, options.Properties));
+  #endif
+
+  HRESULT result = archive->Extract(&realIndices.Front(), 
+    realIndices.Size(), options.TestMode? 1: 0, extractCallbackSpec);
+
+  return callback->ExtractResult(result);
+}
+
+HRESULT DecompressArchives(
+    CCodecs *codecs,
+    UStringVector &archivePaths, UStringVector &archivePathsFull,    
+    const NWildcard::CCensorNode &wildcardCensor,
+    const CExtractOptions &optionsSpec,
+    IOpenCallbackUI *openCallback,
+    IExtractCallbackUI *extractCallback, 
+    UString &errorMessage, 
+    CDecompressStat &stat)
+{
+  stat.Clear();
+  CExtractOptions options = optionsSpec;
+  int i;
+  UInt64 totalPackSize = 0;
+  CRecordVector<UInt64> archiveSizes;
+  for (i = 0; i < archivePaths.Size(); i++)
+  {
+    const UString &archivePath = archivePaths[i];
+    NFile::NFind::CFileInfoW archiveFileInfo;
+    if (!NFile::NFind::FindFile(archivePath, archiveFileInfo))
+      throw "there is no such archive";
+    if (archiveFileInfo.IsDirectory())
+      throw "can't decompress folder";
+    archiveSizes.Add(archiveFileInfo.Size);
+    totalPackSize += archiveFileInfo.Size;
+  }
+  CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
+  CMyComPtr<IArchiveExtractCallback> ec(extractCallbackSpec);
+  bool multi = (archivePaths.Size() > 1);
+  extractCallbackSpec->InitForMulti(multi, options.PathMode, options.OverwriteMode);
+  if (multi)
+  {
+    RINOK(extractCallback->SetTotal(totalPackSize));  
+  }
+  for (i = 0; i < archivePaths.Size(); i++)
+  {
+    const UString &archivePath = archivePaths[i];
+    NFile::NFind::CFileInfoW archiveFileInfo;
+    if (!NFile::NFind::FindFile(archivePath, archiveFileInfo))
+      throw "there is no such archive";
+
+    if (archiveFileInfo.IsDirectory())
+      throw "there is no such archive";
+
+    options.ArchiveFileInfo = archiveFileInfo;
+
+    #ifndef _NO_CRYPTO
+    openCallback->ClearPasswordWasAskedFlag();
+    #endif
+
+    RINOK(extractCallback->BeforeOpen(archivePath));
+    CArchiveLink archiveLink;
+    HRESULT result = MyOpenArchive(codecs, archivePath, archiveLink, openCallback);
+
+    bool crypted = false;
+    #ifndef _NO_CRYPTO
+    crypted = openCallback->WasPasswordAsked();
+    #endif
+
+    RINOK(extractCallback->OpenResult(archivePath, result, crypted));
+    if (result != S_OK)
+      continue;
+
+    for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)
+    {
+      int index = archivePathsFull.FindInSorted(archiveLink.VolumePaths[v]);
+      if (index >= 0 && index > i)
+      {
+        archivePaths.Delete(index);
+        archivePathsFull.Delete(index);
+        totalPackSize -= archiveSizes[index];
+        archiveSizes.Delete(index);
+      }
+    }
+    if (archiveLink.VolumePaths.Size() != 0)
+    {
+      totalPackSize += archiveLink.VolumesSize;
+      RINOK(extractCallback->SetTotal(totalPackSize));  
+    }
+
+    #ifndef _NO_CRYPTO
+    UString password;
+    RINOK(openCallback->GetPasswordIfAny(password));
+    if (!password.IsEmpty())
+    {
+      RINOK(extractCallback->SetPassword(password));
+    }
+    #endif
+
+    options.DefaultItemName = archiveLink.GetDefaultItemName();
+    RINOK(DecompressArchive(
+        archiveLink.GetArchive(), 
+        archiveFileInfo.Size + archiveLink.VolumesSize,
+        archiveLink.GetDefaultItemName(),
+        wildcardCensor, options, extractCallback, extractCallbackSpec, errorMessage));
+    extractCallbackSpec->LocalProgressSpec->InSize += archiveFileInfo.Size + 
+        archiveLink.VolumesSize;
+    extractCallbackSpec->LocalProgressSpec->OutSize = extractCallbackSpec->UnpackSize;
+    if (!errorMessage.IsEmpty())
+      return E_FAIL;
+  }
+  stat.NumFolders = extractCallbackSpec->NumFolders;
+  stat.NumFiles = extractCallbackSpec->NumFiles;
+  stat.UnpackSize = extractCallbackSpec->UnpackSize;
+  stat.NumArchives = archivePaths.Size();
+  stat.PackSize = extractCallbackSpec->LocalProgressSpec->InSize;
+  return S_OK;
+}