1 /// PanelCopy.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../Common/MyException.h"
6 
7 #include "../GUI/HashGUI.h"
8 
9 #include "ExtractCallback.h"
10 #include "LangUtils.h"
11 #include "Panel.h"
12 #include "resource.h"
13 #include "UpdateCallback100.h"
14 
15 using namespace NWindows;
16 
17 class CPanelCopyThread: public CProgressThreadVirt
18 {
19   HRESULT ProcessVirt();
20 public:
21   const CCopyToOptions *options;
22   CMyComPtr<IFolderOperations> FolderOperations;
23   CRecordVector<UInt32> Indices;
24   CExtractCallbackImp *ExtractCallbackSpec;
25   CMyComPtr<IFolderOperationsExtractCallback> ExtractCallback;
26 
27   CHashBundle Hash;
28   UString FirstFilePath;
29 
30   HRESULT Result;
31 
32 
CPanelCopyThread()33   CPanelCopyThread(): Result(E_FAIL) {}
34 };
35 
ProcessVirt()36 HRESULT CPanelCopyThread::ProcessVirt()
37 {
38   /*
39   CMyComPtr<IFolderSetReplaceAltStreamCharsMode> iReplace;
40   FolderOperations.QueryInterface(IID_IFolderSetReplaceAltStreamCharsMode, &iReplace);
41   if (iReplace)
42   {
43     RINOK(iReplace->SetReplaceAltStreamCharsMode(ReplaceAltStreamChars ? 1 : 0));
44   }
45   */
46 
47   if (options->testMode)
48   {
49     CMyComPtr<IArchiveFolder> archiveFolder;
50     FolderOperations.QueryInterface(IID_IArchiveFolder, &archiveFolder);
51     if (!archiveFolder)
52       return E_NOTIMPL;
53     CMyComPtr<IFolderArchiveExtractCallback> extractCallback2;
54     RINOK(ExtractCallback.QueryInterface(IID_IFolderArchiveExtractCallback, &extractCallback2));
55     NExtract::NPathMode::EEnum pathMode =
56         NExtract::NPathMode::kCurPaths;
57         // NExtract::NPathMode::kFullPathnames;
58     Result = archiveFolder->Extract(&Indices.Front(), Indices.Size(),
59         BoolToInt(options->includeAltStreams),
60         BoolToInt(options->replaceAltStreamChars),
61         pathMode, NExtract::NOverwriteMode::kAsk,
62         options->folder, BoolToInt(true), extractCallback2);
63   }
64   else
65     Result = FolderOperations->CopyTo(
66       BoolToInt(options->moveMode),
67       &Indices.Front(), Indices.Size(),
68       BoolToInt(options->includeAltStreams),
69       BoolToInt(options->replaceAltStreamChars),
70       options->folder, ExtractCallback);
71 
72   if (Result == S_OK && !ExtractCallbackSpec->ThereAreMessageErrors &&
73       (!options->hashMethods.IsEmpty() || options->testMode))
74   {
75     CProgressMessageBoxPair &pair = GetMessagePair(false); // GetMessagePair(ExtractCallbackSpec->Hash.NumErrors != 0);
76     AddHashBundleRes(pair.Message, Hash, FirstFilePath);
77   }
78 
79   return Result;
80 }
81 
82 
83 /*
84 #ifdef EXTERNAL_CODECS
85 
86 static void ThrowException_if_Error(HRESULT res)
87 {
88   if (res != S_OK)
89     throw CSystemException(res);
90 }
91 
92 #endif
93 */
94 
95 
CopyTo(CCopyToOptions & options,const CRecordVector<UInt32> & indices,UStringVector * messages,bool & usePassword,UString & password)96 HRESULT CPanel::CopyTo(CCopyToOptions &options, const CRecordVector<UInt32> &indices,
97     UStringVector *messages,
98     bool &usePassword, UString &password)
99 {
100   if (!_folderOperations)
101   {
102     UString errorMessage = LangString(IDS_OPERATION_IS_NOT_SUPPORTED);
103     if (options.showErrorMessages)
104       MessageBox_Error(errorMessage);
105     else if (messages != 0)
106       messages->Add(errorMessage);
107     return E_FAIL;
108   }
109 
110   HRESULT res = S_OK;
111 
112   {
113   /*
114   #ifdef EXTERNAL_CODECS
115   CExternalCodecs g_ExternalCodecs;
116   #endif
117   */
118   /* extracter.Hash uses g_ExternalCodecs
119      extracter must be declared after g_ExternalCodecs for correct destructor order !!! */
120 
121   CPanelCopyThread extracter;
122 
123   extracter.ExtractCallbackSpec = new CExtractCallbackImp;
124   extracter.ExtractCallback = extracter.ExtractCallbackSpec;
125 
126   extracter.options = &options;
127   extracter.ExtractCallbackSpec->ProgressDialog = &extracter.ProgressDialog;
128   extracter.ProgressDialog.CompressingMode = false;
129 
130   extracter.ExtractCallbackSpec->StreamMode = options.streamMode;
131 
132 
133   if (indices.Size() == 1)
134     extracter.FirstFilePath = GetItemRelPath(indices[0]);
135 
136   if (options.VirtFileSystem)
137   {
138     extracter.ExtractCallbackSpec->VirtFileSystem = options.VirtFileSystem;
139     extracter.ExtractCallbackSpec->VirtFileSystemSpec = options.VirtFileSystemSpec;
140   }
141   extracter.ExtractCallbackSpec->ProcessAltStreams = options.includeAltStreams;
142 
143   if (!options.hashMethods.IsEmpty())
144   {
145     /* this code is used when we call CRC calculation for files in side archive
146        But new code uses global codecs so we don't need to call LoadGlobalCodecs again */
147 
148     /*
149     #ifdef EXTERNAL_CODECS
150     ThrowException_if_Error(LoadGlobalCodecs());
151     #endif
152     */
153 
154     extracter.Hash.SetMethods(EXTERNAL_CODECS_VARS_G options.hashMethods);
155     extracter.ExtractCallbackSpec->SetHashMethods(&extracter.Hash);
156   }
157   else if (options.testMode)
158   {
159     extracter.ExtractCallbackSpec->SetHashCalc(&extracter.Hash);
160   }
161 
162   extracter.Hash.Init();
163 
164   UString title;
165   {
166     UInt32 titleID = IDS_COPYING;
167     if (options.moveMode)
168       titleID = IDS_MOVING;
169     else if (!options.hashMethods.IsEmpty() && options.streamMode)
170     {
171       titleID = IDS_CHECKSUM_CALCULATING;
172       if (options.hashMethods.Size() == 1)
173       {
174         const UString &s = options.hashMethods[0];
175         if (s != L"*")
176           title = s;
177       }
178     }
179     else if (options.testMode)
180       titleID = IDS_PROGRESS_TESTING;
181 
182     if (title.IsEmpty())
183       title = LangString(titleID);
184   }
185 
186   UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE);
187 
188   extracter.ProgressDialog.MainWindow = GetParent();
189   extracter.ProgressDialog.MainTitle = progressWindowTitle;
190   extracter.ProgressDialog.MainAddTitle = title + L' ';
191 
192   extracter.ExtractCallbackSpec->OverwriteMode = NExtract::NOverwriteMode::kAsk;
193   extracter.ExtractCallbackSpec->Init();
194   extracter.Indices = indices;
195   extracter.FolderOperations = _folderOperations;
196 
197   extracter.ExtractCallbackSpec->PasswordIsDefined = usePassword;
198   extracter.ExtractCallbackSpec->Password = password;
199 
200   RINOK(extracter.Create(title, GetParent()));
201 
202   if (messages != 0)
203     *messages = extracter.ProgressDialog.Sync.Messages;
204   res = extracter.Result;
205 
206   if (res == S_OK && extracter.ExtractCallbackSpec->IsOK())
207   {
208     usePassword = extracter.ExtractCallbackSpec->PasswordIsDefined;
209     password = extracter.ExtractCallbackSpec->Password;
210   }
211   }
212 
213   RefreshTitleAlways();
214   return res;
215 }
216 
217 
218 struct CThreadUpdate
219 {
220   CMyComPtr<IFolderOperations> FolderOperations;
221   UString FolderPrefix;
222   UStringVector FileNames;
223   CRecordVector<const wchar_t *> FileNamePointers;
224   CProgressDialog ProgressDialog;
225   CMyComPtr<IFolderArchiveUpdateCallback> UpdateCallback;
226   CUpdateCallback100Imp *UpdateCallbackSpec;
227   HRESULT Result;
228   bool MoveMode;
229 
ProcessCThreadUpdate230   void Process()
231   {
232     try
233     {
234       CProgressCloser closer(ProgressDialog);
235       Result = FolderOperations->CopyFrom(
236         MoveMode,
237         FolderPrefix,
238         &FileNamePointers.Front(),
239         FileNamePointers.Size(),
240         UpdateCallback);
241     }
242     catch(...) { Result = E_FAIL; }
243   }
MyThreadFunctionCThreadUpdate244   static THREAD_FUNC_DECL MyThreadFunction(void *param)
245   {
246     ((CThreadUpdate *)param)->Process();
247     return 0;
248   }
249 };
250 
251 
CopyFrom(bool moveMode,const UString & folderPrefix,const UStringVector & filePaths,bool showErrorMessages,UStringVector * messages)252 HRESULT CPanel::CopyFrom(bool moveMode, const UString &folderPrefix, const UStringVector &filePaths,
253     bool showErrorMessages, UStringVector *messages)
254 {
255   // CDisableNotify disableNotify(*this);
256 
257   HRESULT res;
258   if (!_folderOperations)
259     res = E_NOINTERFACE;
260   else
261   {
262   CThreadUpdate updater;
263   updater.MoveMode = moveMode;
264   updater.UpdateCallbackSpec = new CUpdateCallback100Imp;
265   updater.UpdateCallback = updater.UpdateCallbackSpec;
266   updater.UpdateCallbackSpec->Init();
267 
268   updater.UpdateCallbackSpec->ProgressDialog = &updater.ProgressDialog;
269 
270   UString title = LangString(IDS_COPYING);
271   UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE);
272 
273   updater.ProgressDialog.MainWindow = GetParent();
274   updater.ProgressDialog.MainTitle = progressWindowTitle;
275   updater.ProgressDialog.MainAddTitle = title + L' ';
276 
277   {
278     if (!_parentFolders.IsEmpty())
279     {
280       const CFolderLink &fl = _parentFolders.Back();
281       updater.UpdateCallbackSpec->PasswordIsDefined = fl.UsePassword;
282       updater.UpdateCallbackSpec->Password = fl.Password;
283     }
284   }
285 
286   updater.FolderOperations = _folderOperations;
287   updater.FolderPrefix = folderPrefix;
288   updater.FileNames.ClearAndReserve(filePaths.Size());
289   unsigned i;
290   for (i = 0; i < filePaths.Size(); i++)
291     updater.FileNames.AddInReserved(filePaths[i]);
292   updater.FileNamePointers.ClearAndReserve(updater.FileNames.Size());
293   for (i = 0; i < updater.FileNames.Size(); i++)
294     updater.FileNamePointers.AddInReserved(updater.FileNames[i]);
295 
296   NWindows::CThread thread;
297   RINOK(thread.Create(CThreadUpdate::MyThreadFunction, &updater));
298   updater.ProgressDialog.Create(title, thread, GetParent());
299 
300   if (messages != 0)
301     *messages = updater.ProgressDialog.Sync.Messages;
302 
303   res = updater.Result;
304   }
305 
306   if (res == E_NOINTERFACE)
307   {
308     UString errorMessage = LangString(IDS_OPERATION_IS_NOT_SUPPORTED);
309     if (showErrorMessages)
310       MessageBox_Error(errorMessage);
311     else if (messages != 0)
312       messages->Add(errorMessage);
313     return E_ABORT;
314   }
315 
316   RefreshTitleAlways();
317   return res;
318 }
319 
CopyFromNoAsk(const UStringVector & filePaths)320 void CPanel::CopyFromNoAsk(const UStringVector &filePaths)
321 {
322   CDisableTimerProcessing disableTimerProcessing(*this);
323 
324   CSelectedState srcSelState;
325   SaveSelectedState(srcSelState);
326 
327   CDisableNotify disableNotify(*this);
328 
329   HRESULT result = CopyFrom(false, L"", filePaths, true, 0);
330 
331   if (result != S_OK)
332   {
333     disableNotify.Restore();
334     // For Password:
335     SetFocusToList();
336     if (result != E_ABORT)
337       MessageBox_Error_HRESULT(result);
338     return;
339   }
340 
341   RefreshListCtrl(srcSelState);
342 
343   disableNotify.Restore();
344   SetFocusToList();
345 }
346 
CopyFromAsk(const UStringVector & filePaths)347 void CPanel::CopyFromAsk(const UStringVector &filePaths)
348 {
349   UString title = LangString(IDS_CONFIRM_FILE_COPY);
350   UString message = LangString(IDS_WANT_TO_COPY_FILES);
351   message += "\n\'";
352   message += _currentFolderPrefix;
353   message += "\' ?";
354   int res = ::MessageBoxW(*(this), message, title, MB_YESNOCANCEL | MB_ICONQUESTION);
355   if (res != IDYES)
356     return;
357 
358   CopyFromNoAsk(filePaths);
359 }
360