summaryrefslogtreecommitdiffstats
path: root/CPP/7zip/UI/Common/Extract.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/UI/Common/Extract.cpp')
-rwxr-xr-xCPP/7zip/UI/Common/Extract.cpp263
1 files changed, 263 insertions, 0 deletions
diff --git a/CPP/7zip/UI/Common/Extract.cpp b/CPP/7zip/UI/Common/Extract.cpp
new file mode 100755
index 0000000..2f5a293
--- /dev/null
+++ b/CPP/7zip/UI/Common/Extract.cpp
@@ -0,0 +1,263 @@
+// Extract.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+
+#include "Windows/FileDir.h"
+#include "Windows/PropVariant.h"
+#include "Windows/PropVariantConversions.h"
+
+#include "../Common/ExtractingFilePath.h"
+
+#include "Extract.h"
+#include "SetProperties.h"
+
+using namespace NWindows;
+
+static HRESULT DecompressArchive(
+ const CArc &arc,
+ UInt64 packSize,
+ const NWildcard::CCensorNode &wildcardCensor,
+ const CExtractOptions &options,
+ IExtractCallbackUI *callback,
+ CArchiveExtractCallback *extractCallbackSpec,
+ UString &errorMessage,
+ UInt64 &stdInProcessed)
+{
+ stdInProcessed = 0;
+ IInArchive *archive = arc.Archive;
+ CRecordVector<UInt32> realIndices;
+ if (!options.StdInMode)
+ {
+ UInt32 numItems;
+ RINOK(archive->GetNumberOfItems(&numItems));
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ UString filePath;
+ RINOK(arc.GetItemPath(i, 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"*", GetCorrectFsPath(arc.DefaultName));
+ #ifdef _WIN32
+ // GetCorrectFullFsPath doesn't like "..".
+ // outDir.TrimRight();
+ // outDir = GetCorrectFullFsPath(outDir);
+ #endif
+
+ 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(
+ options.StdInMode ? &wildcardCensor : NULL,
+ &arc,
+ callback,
+ options.StdOutMode, options.TestMode, options.CalcCrc,
+ outDir,
+ removePathParts,
+ packSize);
+
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ RINOK(SetProperties(archive, options.Properties));
+ #endif
+
+ HRESULT result;
+ Int32 testMode = (options.TestMode && !options.CalcCrc) ? 1: 0;
+ if (options.StdInMode)
+ {
+ result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, extractCallbackSpec);
+ NCOM::CPropVariant prop;
+ if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK)
+ if (prop.vt == VT_UI8 || prop.vt == VT_UI4)
+ stdInProcessed = ConvertPropVariantToUInt64(prop);
+ }
+ else
+ result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, extractCallbackSpec);
+
+ return callback->ExtractResult(result);
+}
+
+HRESULT DecompressArchives(
+ CCodecs *codecs, const CIntVector &formatIndices,
+ UStringVector &arcPaths, UStringVector &arcPathsFull,
+ const NWildcard::CCensorNode &wildcardCensor,
+ const CExtractOptions &options,
+ IOpenCallbackUI *openCallback,
+ IExtractCallbackUI *extractCallback,
+ UString &errorMessage,
+ CDecompressStat &stat)
+{
+ stat.Clear();
+ int i;
+ UInt64 totalPackSize = 0;
+ CRecordVector<UInt64> archiveSizes;
+
+ int numArcs = options.StdInMode ? 1 : arcPaths.Size();
+
+ for (i = 0; i < numArcs; i++)
+ {
+ NFile::NFind::CFileInfoW fi;
+ fi.Size = 0;
+ if (!options.StdInMode)
+ {
+ const UString &arcPath = arcPaths[i];
+ if (!fi.Find(arcPath))
+ throw "there is no such archive";
+ if (fi.IsDir())
+ throw "can't decompress folder";
+ }
+ archiveSizes.Add(fi.Size);
+ totalPackSize += fi.Size;
+ }
+ CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
+ CMyComPtr<IArchiveExtractCallback> ec(extractCallbackSpec);
+ bool multi = (numArcs > 1);
+ extractCallbackSpec->InitForMulti(multi, options.PathMode, options.OverwriteMode);
+ if (multi)
+ {
+ RINOK(extractCallback->SetTotal(totalPackSize));
+ }
+ for (i = 0; i < numArcs; i++)
+ {
+ const UString &arcPath = arcPaths[i];
+ NFile::NFind::CFileInfoW fi;
+ if (options.StdInMode)
+ {
+ fi.Size = 0;
+ fi.Attrib = 0;
+ }
+ else
+ {
+ if (!fi.Find(arcPath) || fi.IsDir())
+ throw "there is no such archive";
+ }
+
+ #ifndef _NO_CRYPTO
+ openCallback->Open_ClearPasswordWasAskedFlag();
+ #endif
+
+ RINOK(extractCallback->BeforeOpen(arcPath));
+ CArchiveLink archiveLink;
+
+ CIntVector formatIndices2 = formatIndices;
+ #ifndef _SFX
+ if (formatIndices.IsEmpty())
+ {
+ int pos = arcPath.ReverseFind(L'.');
+ if (pos >= 0)
+ {
+ UString s = arcPath.Mid(pos + 1);
+ int index = codecs->FindFormatForExtension(s);
+ if (index >= 0 && s == L"001")
+ {
+ s = arcPath.Left(pos);
+ pos = s.ReverseFind(L'.');
+ if (pos >= 0)
+ {
+ int index2 = codecs->FindFormatForExtension(s.Mid(pos + 1));
+ if (index2 >= 0 && s.CompareNoCase(L"rar") != 0)
+ {
+ formatIndices2.Add(index2);
+ formatIndices2.Add(index);
+ }
+ }
+ }
+ }
+ }
+ #endif
+ HRESULT result = archiveLink.Open2(codecs, formatIndices2, options.StdInMode, NULL, arcPath, openCallback);
+ if (result == E_ABORT)
+ return result;
+
+ bool crypted = false;
+ #ifndef _NO_CRYPTO
+ crypted = openCallback->Open_WasPasswordAsked();
+ #endif
+
+ RINOK(extractCallback->OpenResult(arcPath, result, crypted));
+ if (result != S_OK)
+ continue;
+
+ if (!options.StdInMode)
+ for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)
+ {
+ int index = arcPathsFull.FindInSorted(archiveLink.VolumePaths[v]);
+ if (index >= 0 && index > i)
+ {
+ arcPaths.Delete(index);
+ arcPathsFull.Delete(index);
+ totalPackSize -= archiveSizes[index];
+ archiveSizes.Delete(index);
+ numArcs = arcPaths.Size();
+ }
+ }
+ if (archiveLink.VolumePaths.Size() != 0)
+ {
+ totalPackSize += archiveLink.VolumesSize;
+ RINOK(extractCallback->SetTotal(totalPackSize));
+ }
+
+ #ifndef _NO_CRYPTO
+ UString password;
+ RINOK(openCallback->Open_GetPasswordIfAny(password));
+ if (!password.IsEmpty())
+ {
+ RINOK(extractCallback->SetPassword(password));
+ }
+ #endif
+
+ for (int v = 0; v < archiveLink.Arcs.Size(); v++)
+ {
+ const UString &s = archiveLink.Arcs[v].ErrorMessage;
+ if (!s.IsEmpty())
+ {
+ RINOK(extractCallback->MessageError(s));
+ }
+ }
+
+ CArc &arc = archiveLink.Arcs.Back();
+ arc.MTimeDefined = (!options.StdInMode && !fi.IsDevice);
+ arc.MTime = fi.MTime;
+
+ UInt64 packProcessed;
+ RINOK(DecompressArchive(arc,
+ fi.Size + archiveLink.VolumesSize,
+ wildcardCensor, options, extractCallback, extractCallbackSpec, errorMessage, packProcessed));
+ if (!options.StdInMode)
+ packProcessed = fi.Size + archiveLink.VolumesSize;
+ extractCallbackSpec->LocalProgressSpec->InSize += packProcessed;
+ extractCallbackSpec->LocalProgressSpec->OutSize = extractCallbackSpec->UnpackSize;
+ if (!errorMessage.IsEmpty())
+ return E_FAIL;
+ }
+ stat.NumFolders = extractCallbackSpec->NumFolders;
+ stat.NumFiles = extractCallbackSpec->NumFiles;
+ stat.UnpackSize = extractCallbackSpec->UnpackSize;
+ stat.CrcSum = extractCallbackSpec->CrcSum;
+
+ stat.NumArchives = arcPaths.Size();
+ stat.PackSize = extractCallbackSpec->LocalProgressSpec->InSize;
+ return S_OK;
+}