Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / UI / Common / Extract.cpp
1 // Extract.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include <stdio.h>\r
6 \r
7 #include "Windows/FileDir.h"\r
8 #include "Windows/PropVariant.h"\r
9 #include "Windows/PropVariantConversions.h"\r
10 \r
11 #include "../Common/ExtractingFilePath.h"\r
12 \r
13 #include "Extract.h"\r
14 #include "SetProperties.h"\r
15 \r
16 using namespace NWindows;\r
17 \r
18 static HRESULT DecompressArchive(\r
19     const CArc &arc,\r
20     UInt64 packSize,\r
21     const NWildcard::CCensorNode &wildcardCensor,\r
22     const CExtractOptions &options,\r
23     IExtractCallbackUI *callback,\r
24     CArchiveExtractCallback *extractCallbackSpec,\r
25     UString &errorMessage,\r
26     UInt64 &stdInProcessed)\r
27 {\r
28   stdInProcessed = 0;\r
29   IInArchive *archive = arc.Archive;\r
30   CRecordVector<UInt32> realIndices;\r
31   if (!options.StdInMode)\r
32   {\r
33     UInt32 numItems;\r
34     RINOK(archive->GetNumberOfItems(&numItems));\r
35     \r
36     for (UInt32 i = 0; i < numItems; i++)\r
37     {\r
38       UString filePath;\r
39       RINOK(arc.GetItemPath(i, filePath));\r
40       bool isFolder;\r
41       RINOK(IsArchiveItemFolder(archive, i, isFolder));\r
42       if (!wildcardCensor.CheckPath(filePath, !isFolder))\r
43         continue;\r
44       realIndices.Add(i);\r
45     }\r
46     if (realIndices.Size() == 0)\r
47     {\r
48       callback->ThereAreNoFiles();\r
49       return S_OK;\r
50     }\r
51   }\r
52 \r
53   UStringVector removePathParts;\r
54 \r
55   UString outDir = options.OutputDir;\r
56   outDir.Replace(L"*", GetCorrectFsPath(arc.DefaultName));\r
57   #ifdef _WIN32\r
58   // GetCorrectFullFsPath doesn't like "..".\r
59   // outDir.TrimRight();\r
60   // outDir = GetCorrectFullFsPath(outDir);\r
61   #endif\r
62 \r
63   if (!outDir.IsEmpty())\r
64     if (!NFile::NDirectory::CreateComplexDirectory(outDir))\r
65     {\r
66       HRESULT res = ::GetLastError();\r
67       if (res == S_OK)\r
68         res = E_FAIL;\r
69       errorMessage = ((UString)L"Can not create output directory ") + outDir;\r
70       return res;\r
71     }\r
72 \r
73   extractCallbackSpec->Init(\r
74       options.StdInMode ? &wildcardCensor : NULL,\r
75       &arc,\r
76       callback,\r
77       options.StdOutMode, options.TestMode, options.CalcCrc,\r
78       outDir,\r
79       removePathParts,\r
80       packSize);\r
81 \r
82   #if !defined(_7ZIP_ST) && !defined(_SFX)\r
83   RINOK(SetProperties(archive, options.Properties));\r
84   #endif\r
85 \r
86   HRESULT result;\r
87   Int32 testMode = (options.TestMode && !options.CalcCrc) ? 1: 0;\r
88   if (options.StdInMode)\r
89   {\r
90     result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, extractCallbackSpec);\r
91     NCOM::CPropVariant prop;\r
92     if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK)\r
93       if (prop.vt == VT_UI8 || prop.vt == VT_UI4)\r
94         stdInProcessed = ConvertPropVariantToUInt64(prop);\r
95   }\r
96   else\r
97     result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, extractCallbackSpec);\r
98 \r
99   return callback->ExtractResult(result);\r
100 }\r
101 \r
102 HRESULT DecompressArchives(\r
103     CCodecs *codecs, const CIntVector &formatIndices,\r
104     UStringVector &arcPaths, UStringVector &arcPathsFull,\r
105     const NWildcard::CCensorNode &wildcardCensor,\r
106     const CExtractOptions &options,\r
107     IOpenCallbackUI *openCallback,\r
108     IExtractCallbackUI *extractCallback,\r
109     UString &errorMessage,\r
110     CDecompressStat &stat)\r
111 {\r
112   stat.Clear();\r
113   int i;\r
114   UInt64 totalPackSize = 0;\r
115   CRecordVector<UInt64> archiveSizes;\r
116 \r
117   int numArcs = options.StdInMode ? 1 : arcPaths.Size();\r
118 \r
119   for (i = 0; i < numArcs; i++)\r
120   {\r
121     NFile::NFind::CFileInfoW fi;\r
122     fi.Size = 0;\r
123     if (!options.StdInMode)\r
124     {\r
125       const UString &arcPath = arcPaths[i];\r
126       if (!fi.Find(arcPath))\r
127         throw "there is no such archive";\r
128       if (fi.IsDir())\r
129         throw "can't decompress folder";\r
130     }\r
131     archiveSizes.Add(fi.Size);\r
132     totalPackSize += fi.Size;\r
133   }\r
134   CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;\r
135   CMyComPtr<IArchiveExtractCallback> ec(extractCallbackSpec);\r
136   bool multi = (numArcs > 1);\r
137   extractCallbackSpec->InitForMulti(multi, options.PathMode, options.OverwriteMode);\r
138   if (multi)\r
139   {\r
140     RINOK(extractCallback->SetTotal(totalPackSize));\r
141   }\r
142   for (i = 0; i < numArcs; i++)\r
143   {\r
144     const UString &arcPath = arcPaths[i];\r
145     NFile::NFind::CFileInfoW fi;\r
146     if (options.StdInMode)\r
147     {\r
148       fi.Size = 0;\r
149       fi.Attrib = 0;\r
150     }\r
151     else\r
152     {\r
153       if (!fi.Find(arcPath) || fi.IsDir())\r
154         throw "there is no such archive";\r
155     }\r
156 \r
157     #ifndef _NO_CRYPTO\r
158     openCallback->Open_ClearPasswordWasAskedFlag();\r
159     #endif\r
160 \r
161     RINOK(extractCallback->BeforeOpen(arcPath));\r
162     CArchiveLink archiveLink;\r
163 \r
164     CIntVector formatIndices2 = formatIndices;\r
165     #ifndef _SFX\r
166     if (formatIndices.IsEmpty())\r
167     {\r
168       int pos = arcPath.ReverseFind(L'.');\r
169       if (pos >= 0)\r
170       {\r
171         UString s = arcPath.Mid(pos + 1);\r
172         int index = codecs->FindFormatForExtension(s);\r
173         if (index >= 0 && s == L"001")\r
174         {\r
175           s = arcPath.Left(pos);\r
176           pos = s.ReverseFind(L'.');\r
177           if (pos >= 0)\r
178           {\r
179             int index2 = codecs->FindFormatForExtension(s.Mid(pos + 1));\r
180             if (index2 >= 0 && s.CompareNoCase(L"rar") != 0)\r
181             {\r
182               formatIndices2.Add(index2);\r
183               formatIndices2.Add(index);\r
184             }\r
185           }\r
186         }\r
187       }\r
188     }\r
189     #endif\r
190     HRESULT result = archiveLink.Open2(codecs, formatIndices2, options.StdInMode, NULL, arcPath, openCallback);\r
191     if (result == E_ABORT)\r
192       return result;\r
193 \r
194     bool crypted = false;\r
195     #ifndef _NO_CRYPTO\r
196     crypted = openCallback->Open_WasPasswordAsked();\r
197     #endif\r
198 \r
199     RINOK(extractCallback->OpenResult(arcPath, result, crypted));\r
200     if (result != S_OK)\r
201       continue;\r
202 \r
203     if (!options.StdInMode)\r
204     for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)\r
205     {\r
206       int index = arcPathsFull.FindInSorted(archiveLink.VolumePaths[v]);\r
207       if (index >= 0 && index > i)\r
208       {\r
209         arcPaths.Delete(index);\r
210         arcPathsFull.Delete(index);\r
211         totalPackSize -= archiveSizes[index];\r
212         archiveSizes.Delete(index);\r
213         numArcs = arcPaths.Size();\r
214       }\r
215     }\r
216     if (archiveLink.VolumePaths.Size() != 0)\r
217     {\r
218       totalPackSize += archiveLink.VolumesSize;\r
219       RINOK(extractCallback->SetTotal(totalPackSize));\r
220     }\r
221 \r
222     #ifndef _NO_CRYPTO\r
223     UString password;\r
224     RINOK(openCallback->Open_GetPasswordIfAny(password));\r
225     if (!password.IsEmpty())\r
226     {\r
227       RINOK(extractCallback->SetPassword(password));\r
228     }\r
229     #endif\r
230 \r
231     for (int v = 0; v < archiveLink.Arcs.Size(); v++)\r
232     {\r
233       const UString &s = archiveLink.Arcs[v].ErrorMessage;\r
234       if (!s.IsEmpty())\r
235       {\r
236         RINOK(extractCallback->MessageError(s));\r
237       }\r
238     }\r
239 \r
240     CArc &arc = archiveLink.Arcs.Back();\r
241     arc.MTimeDefined = (!options.StdInMode && !fi.IsDevice);\r
242     arc.MTime = fi.MTime;\r
243 \r
244     UInt64 packProcessed;\r
245     RINOK(DecompressArchive(arc,\r
246         fi.Size + archiveLink.VolumesSize,\r
247         wildcardCensor, options, extractCallback, extractCallbackSpec, errorMessage, packProcessed));\r
248     if (!options.StdInMode)\r
249       packProcessed = fi.Size + archiveLink.VolumesSize;\r
250     extractCallbackSpec->LocalProgressSpec->InSize += packProcessed;\r
251     extractCallbackSpec->LocalProgressSpec->OutSize = extractCallbackSpec->UnpackSize;\r
252     if (!errorMessage.IsEmpty())\r
253       return E_FAIL;\r
254   }\r
255   stat.NumFolders = extractCallbackSpec->NumFolders;\r
256   stat.NumFiles = extractCallbackSpec->NumFiles;\r
257   stat.UnpackSize = extractCallbackSpec->UnpackSize;\r
258   stat.CrcSum = extractCallbackSpec->CrcSum;\r
259 \r
260   stat.NumArchives = arcPaths.Size();\r
261   stat.PackSize = extractCallbackSpec->LocalProgressSpec->InSize;\r
262   return S_OK;\r
263 }\r