blob: 2f5a293ba8789802c5a60047d41a6cf9a2b12b03 [file] [log] [blame]
// 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;
}