Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / UI / FileManager / ExtractCallback.cpp
1 // ExtractCallback.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include "Windows/Error.h"\r
6 #include "Windows/FileDir.h"\r
7 #include "Windows/FileFind.h"\r
8 \r
9 #include "../../Common/FilePathAutoRename.h"\r
10 \r
11 #include "../GUI/ExtractRes.h"\r
12 \r
13 #include "ExtractCallback.h"\r
14 #include "FormatUtils.h"\r
15 #include "OverwriteDialog.h"\r
16 #ifndef _NO_CRYPTO\r
17 #include "PasswordDialog.h"\r
18 #endif\r
19 \r
20 using namespace NWindows;\r
21 using namespace NFile;\r
22 using namespace NFind;\r
23 \r
24 CExtractCallbackImp::~CExtractCallbackImp() {}\r
25 \r
26 void CExtractCallbackImp::Init()\r
27 {\r
28   NumArchiveErrors = 0;\r
29   ThereAreMessageErrors = false;\r
30   #ifndef _SFX\r
31   NumFolders = NumFiles = 0;\r
32   NeedAddFile = false;\r
33   #endif\r
34 }\r
35 \r
36 void CExtractCallbackImp::AddErrorMessage(LPCWSTR message)\r
37 {\r
38   ThereAreMessageErrors = true;\r
39   ProgressDialog->Sync.AddErrorMessage(message);\r
40 }\r
41 \r
42 STDMETHODIMP CExtractCallbackImp::SetNumFiles(UInt64\r
43   #ifndef _SFX\r
44   numFiles\r
45   #endif\r
46   )\r
47 {\r
48   #ifndef _SFX\r
49   ProgressDialog->Sync.SetNumFilesTotal(numFiles);\r
50   #endif\r
51   return S_OK;\r
52 }\r
53 \r
54 STDMETHODIMP CExtractCallbackImp::SetTotal(UInt64 total)\r
55 {\r
56   ProgressDialog->Sync.SetProgress(total, 0);\r
57   return S_OK;\r
58 }\r
59 \r
60 STDMETHODIMP CExtractCallbackImp::SetCompleted(const UInt64 *value)\r
61 {\r
62   RINOK(ProgressDialog->Sync.ProcessStopAndPause());\r
63   if (value != NULL)\r
64     ProgressDialog->Sync.SetPos(*value);\r
65   return S_OK;\r
66 }\r
67 \r
68 HRESULT CExtractCallbackImp::Open_CheckBreak()\r
69 {\r
70   return ProgressDialog->Sync.ProcessStopAndPause();\r
71 }\r
72 \r
73 HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */)\r
74 {\r
75   // if (numFiles != NULL) ProgressDialog->Sync.SetNumFilesTotal(*numFiles);\r
76   return S_OK;\r
77 }\r
78 \r
79 HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */)\r
80 {\r
81   RINOK(ProgressDialog->Sync.ProcessStopAndPause());\r
82   // if (numFiles != NULL) ProgressDialog->Sync.SetNumFilesCur(*numFiles);\r
83   return S_OK;\r
84 }\r
85 \r
86 #ifndef _NO_CRYPTO\r
87 \r
88 HRESULT CExtractCallbackImp::Open_CryptoGetTextPassword(BSTR *password)\r
89 {\r
90   return CryptoGetTextPassword(password);\r
91 }\r
92 \r
93 HRESULT CExtractCallbackImp::Open_GetPasswordIfAny(UString &password)\r
94 {\r
95   if (PasswordIsDefined)\r
96     password = Password;\r
97   return S_OK;\r
98 }\r
99 \r
100 bool CExtractCallbackImp::Open_WasPasswordAsked()\r
101 {\r
102   return PasswordWasAsked;\r
103 }\r
104 \r
105 void CExtractCallbackImp::Open_ClearPasswordWasAskedFlag()\r
106 {\r
107   PasswordWasAsked = false;\r
108 }\r
109 \r
110 #endif\r
111 \r
112 \r
113 #ifndef _SFX\r
114 STDMETHODIMP CExtractCallbackImp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)\r
115 {\r
116   ProgressDialog->Sync.SetRatioInfo(inSize, outSize);\r
117   return S_OK;\r
118 }\r
119 #endif\r
120 \r
121 /*\r
122 STDMETHODIMP CExtractCallbackImp::SetTotalFiles(UInt64 total)\r
123 {\r
124   ProgressDialog->Sync.SetNumFilesTotal(total);\r
125   return S_OK;\r
126 }\r
127 \r
128 STDMETHODIMP CExtractCallbackImp::SetCompletedFiles(const UInt64 *value)\r
129 {\r
130   if (value != NULL)\r
131     ProgressDialog->Sync.SetNumFilesCur(*value);\r
132   return S_OK;\r
133 }\r
134 */\r
135 \r
136 STDMETHODIMP CExtractCallbackImp::AskOverwrite(\r
137     const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,\r
138     const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,\r
139     Int32 *answer)\r
140 {\r
141   COverwriteDialog dialog;\r
142 \r
143   dialog.OldFileInfo.SetTime(existTime);\r
144   dialog.OldFileInfo.SetSize(existSize);\r
145   dialog.OldFileInfo.Name = existName;\r
146 \r
147   dialog.NewFileInfo.SetTime(newTime);\r
148   dialog.NewFileInfo.SetSize(newSize);\r
149   dialog.NewFileInfo.Name = newName;\r
150   \r
151   ProgressDialog->WaitCreating();\r
152   INT_PTR writeAnswer = dialog.Create(*ProgressDialog);\r
153   \r
154   switch(writeAnswer)\r
155   {\r
156     case IDCANCEL: *answer = NOverwriteAnswer::kCancel; return E_ABORT;\r
157     case IDYES: *answer = NOverwriteAnswer::kYes; break;\r
158     case IDNO: *answer = NOverwriteAnswer::kNo; break;\r
159     case IDC_BUTTON_OVERWRITE_YES_TO_ALL: *answer = NOverwriteAnswer::kYesToAll; break;\r
160     case IDC_BUTTON_OVERWRITE_NO_TO_ALL: *answer = NOverwriteAnswer::kNoToAll; break;\r
161     case IDC_BUTTON_OVERWRITE_AUTO_RENAME: *answer = NOverwriteAnswer::kAutoRename; break;\r
162     default: return E_FAIL;\r
163   }\r
164   return S_OK;\r
165 }\r
166 \r
167 \r
168 STDMETHODIMP CExtractCallbackImp::PrepareOperation(const wchar_t *name, bool isFolder, Int32 /* askExtractMode */, const UInt64 * /* position */)\r
169 {\r
170   _isFolder = isFolder;\r
171   return SetCurrentFilePath2(name);\r
172 }\r
173 \r
174 STDMETHODIMP CExtractCallbackImp::MessageError(const wchar_t *message)\r
175 {\r
176   AddErrorMessage(message);\r
177   return S_OK;\r
178 }\r
179 \r
180 STDMETHODIMP CExtractCallbackImp::ShowMessage(const wchar_t *message)\r
181 {\r
182   AddErrorMessage(message);\r
183   return S_OK;\r
184 }\r
185 \r
186 STDMETHODIMP CExtractCallbackImp::SetOperationResult(Int32 operationResult, bool encrypted)\r
187 {\r
188   switch(operationResult)\r
189   {\r
190     case NArchive::NExtract::NOperationResult::kOK:\r
191       break;\r
192     default:\r
193     {\r
194       UINT messageID;\r
195       UInt32 langID;\r
196       switch(operationResult)\r
197       {\r
198         case NArchive::NExtract::NOperationResult::kUnSupportedMethod:\r
199           messageID = IDS_MESSAGES_DIALOG_EXTRACT_MESSAGE_UNSUPPORTED_METHOD;\r
200           langID = 0x02000A91;\r
201           break;\r
202         case NArchive::NExtract::NOperationResult::kDataError:\r
203           messageID = encrypted ?\r
204               IDS_MESSAGES_DIALOG_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED:\r
205               IDS_MESSAGES_DIALOG_EXTRACT_MESSAGE_DATA_ERROR;\r
206           langID = encrypted ? 0x02000A94 : 0x02000A92;\r
207           break;\r
208         case NArchive::NExtract::NOperationResult::kCRCError:\r
209           messageID = encrypted ?\r
210               IDS_MESSAGES_DIALOG_EXTRACT_MESSAGE_CRC_ENCRYPTED:\r
211               IDS_MESSAGES_DIALOG_EXTRACT_MESSAGE_CRC;\r
212           langID = encrypted ? 0x02000A95 : 0x02000A93;\r
213           break;\r
214         default:\r
215           return E_FAIL;\r
216       }\r
217       if (_needWriteArchivePath)\r
218       {\r
219         if (!_currentArchivePath.IsEmpty())\r
220           AddErrorMessage(_currentArchivePath);\r
221         _needWriteArchivePath = false;\r
222       }\r
223       AddErrorMessage(\r
224         MyFormatNew(messageID,\r
225           #ifdef LANG\r
226           langID,\r
227           #endif\r
228           _currentFilePath));\r
229     }\r
230   }\r
231   #ifndef _SFX\r
232   if (_isFolder)\r
233     NumFolders++;\r
234   else\r
235     NumFiles++;\r
236   ProgressDialog->Sync.SetNumFilesCur(NumFiles);\r
237   #endif\r
238   return S_OK;\r
239 }\r
240 \r
241 ////////////////////////////////////////\r
242 // IExtractCallbackUI\r
243 \r
244 HRESULT CExtractCallbackImp::BeforeOpen(const wchar_t *name)\r
245 {\r
246   #ifndef _SFX\r
247   ProgressDialog->Sync.SetTitleFileName(name);\r
248   #endif\r
249   _currentArchivePath = name;\r
250   return S_OK;\r
251 }\r
252 \r
253 HRESULT CExtractCallbackImp::SetCurrentFilePath2(const wchar_t *path)\r
254 {\r
255   _currentFilePath = path;\r
256   #ifndef _SFX\r
257   ProgressDialog->Sync.SetCurrentFileName(path);\r
258   #endif\r
259   return S_OK;\r
260 }\r
261 \r
262 HRESULT CExtractCallbackImp::SetCurrentFilePath(const wchar_t *path)\r
263 {\r
264   #ifndef _SFX\r
265   if (NeedAddFile)\r
266     NumFiles++;\r
267   NeedAddFile = true;\r
268   ProgressDialog->Sync.SetNumFilesCur(NumFiles);\r
269   #endif\r
270   return SetCurrentFilePath2(path);\r
271 }\r
272 \r
273 HRESULT CExtractCallbackImp::OpenResult(const wchar_t *name, HRESULT result, bool encrypted)\r
274 {\r
275   if (result != S_OK)\r
276   {\r
277     UString message;\r
278     if (result == S_FALSE)\r
279     {\r
280       message = MyFormatNew(encrypted ? IDS_CANT_OPEN_ENCRYPTED_ARCHIVE : IDS_CANT_OPEN_ARCHIVE,\r
281         #ifdef LANG\r
282         (encrypted ? 0x0200060A : 0x02000609),\r
283         #endif\r
284         name);\r
285     }\r
286     else\r
287     {\r
288       message = name;\r
289       message += L": ";\r
290       UString message2;\r
291       if (result == E_OUTOFMEMORY)\r
292         message2 =\r
293         #ifdef LANG\r
294         LangString(IDS_MEM_ERROR, 0x0200060B);\r
295         #else\r
296         MyLoadStringW(IDS_MEM_ERROR);\r
297         #endif\r
298       else\r
299         NError::MyFormatMessage(result, message2);\r
300       message += message2;\r
301     }\r
302     MessageError(message);\r
303     NumArchiveErrors++;\r
304   }\r
305   _currentArchivePath = name;\r
306   _needWriteArchivePath = true;\r
307   return S_OK;\r
308 }\r
309   \r
310 HRESULT CExtractCallbackImp::ThereAreNoFiles()\r
311 {\r
312   return S_OK;\r
313 }\r
314 \r
315 HRESULT CExtractCallbackImp::ExtractResult(HRESULT result)\r
316 {\r
317   if (result == S_OK)\r
318     return result;\r
319   NumArchiveErrors++;\r
320   if (result == E_ABORT || result == ERROR_DISK_FULL)\r
321     return result;\r
322   MessageError(_currentFilePath);\r
323   MessageError(NError::MyFormatMessageW(result));\r
324   return S_OK;\r
325 }\r
326 \r
327 #ifndef _NO_CRYPTO\r
328 \r
329 HRESULT CExtractCallbackImp::SetPassword(const UString &password)\r
330 {\r
331   PasswordIsDefined = true;\r
332   Password = password;\r
333   return S_OK;\r
334 }\r
335 \r
336 STDMETHODIMP CExtractCallbackImp::CryptoGetTextPassword(BSTR *password)\r
337 {\r
338   PasswordWasAsked = true;\r
339   if (!PasswordIsDefined)\r
340   {\r
341     CPasswordDialog dialog;\r
342     ProgressDialog->WaitCreating();\r
343     if (dialog.Create(*ProgressDialog) == IDCANCEL)\r
344       return E_ABORT;\r
345     Password = dialog.Password;\r
346     PasswordIsDefined = true;\r
347   }\r
348   return StringToBstr(Password, password);\r
349 }\r
350 \r
351 #endif\r
352 \r
353 // IExtractCallBack3\r
354 STDMETHODIMP CExtractCallbackImp::AskWrite(\r
355     const wchar_t *srcPath, Int32 srcIsFolder,\r
356     const FILETIME *srcTime, const UInt64 *srcSize,\r
357     const wchar_t *destPath,\r
358     BSTR *destPathResult,\r
359     Int32 *writeAnswer)\r
360 {\r
361   UString destPathResultTemp = destPath;\r
362 \r
363   // RINOK(StringToBstr(destPath, destPathResult));\r
364 \r
365   *destPathResult = 0;\r
366   *writeAnswer = BoolToInt(false);\r
367 \r
368   UString destPathSpec = destPath;\r
369   UString destPathSys = destPathSpec;\r
370   bool srcIsFolderSpec = IntToBool(srcIsFolder);\r
371   CFileInfoW destFileInfo;\r
372   if (destFileInfo.Find(destPathSys))\r
373   {\r
374     if (srcIsFolderSpec)\r
375     {\r
376       if (!destFileInfo.IsDir())\r
377       {\r
378         UString message = UString(L"can not replace file \'")\r
379           + destPathSpec +\r
380           UString(L"\' with folder with same name");\r
381         RINOK(MessageError(message));\r
382         return E_ABORT;\r
383       }\r
384       *writeAnswer = BoolToInt(false);\r
385       return S_OK;\r
386     }\r
387     if (destFileInfo.IsDir())\r
388     {\r
389       UString message = UString(L"can not replace folder \'")\r
390           + destPathSpec +\r
391           UString(L"\' with file with same name");\r
392       RINOK(MessageError(message));\r
393       return E_FAIL;\r
394     }\r
395 \r
396     switch(OverwriteMode)\r
397     {\r
398       case NExtract::NOverwriteMode::kSkipExisting:\r
399         return S_OK;\r
400       case NExtract::NOverwriteMode::kAskBefore:\r
401       {\r
402         Int32 overwiteResult;\r
403         RINOK(AskOverwrite(\r
404             destPathSpec,\r
405             &destFileInfo.MTime, &destFileInfo.Size,\r
406             srcPath,\r
407             srcTime, srcSize,\r
408             &overwiteResult));\r
409           switch(overwiteResult)\r
410         {\r
411           case NOverwriteAnswer::kCancel:\r
412             return E_ABORT;\r
413           case NOverwriteAnswer::kNo:\r
414             return S_OK;\r
415           case NOverwriteAnswer::kNoToAll:\r
416             OverwriteMode = NExtract::NOverwriteMode::kSkipExisting;\r
417             return S_OK;\r
418           case NOverwriteAnswer::kYesToAll:\r
419             OverwriteMode = NExtract::NOverwriteMode::kWithoutPrompt;\r
420             break;\r
421           case NOverwriteAnswer::kYes:\r
422             break;\r
423           case NOverwriteAnswer::kAutoRename:\r
424             OverwriteMode = NExtract::NOverwriteMode::kAutoRename;\r
425             break;\r
426           default:\r
427             return E_FAIL;\r
428         }\r
429       }\r
430     }\r
431     if (OverwriteMode == NExtract::NOverwriteMode::kAutoRename)\r
432     {\r
433       if (!AutoRenamePath(destPathSys))\r
434       {\r
435         UString message = UString(L"can not create name of file ")\r
436             + destPathSys;\r
437         RINOK(MessageError(message));\r
438         return E_ABORT;\r
439       }\r
440       destPathResultTemp = destPathSys;\r
441     }\r
442     else\r
443       if (!NFile::NDirectory::DeleteFileAlways(destPathSys))\r
444       {\r
445         UString message = UString(L"can not delete output file ")\r
446             + destPathSys;\r
447         RINOK(MessageError(message));\r
448         return E_ABORT;\r
449       }\r
450   }\r
451   *writeAnswer = BoolToInt(true);\r
452   return StringToBstr(destPathResultTemp, destPathResult);\r
453 }\r