188 lines
5.4 KiB
C++
188 lines
5.4 KiB
C++
// 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;
|
|
}
|