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