1 // UpdateGUI.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../Common/IntToString.h"
6 #include "../../../Common/StringConvert.h"
7 #include "../../../Common/StringToInt.h"
8
9 #include "../../../Windows/DLL.h"
10 #include "../../../Windows/FileDir.h"
11 #include "../../../Windows/FileName.h"
12 #include "../../../Windows/Thread.h"
13
14 #include "../Common/WorkDir.h"
15
16 #include "../Explorer/MyMessages.h"
17
18 #include "../FileManager/LangUtils.h"
19 #include "../FileManager/StringUtils.h"
20 #include "../FileManager/resourceGui.h"
21
22 #include "CompressDialog.h"
23 #include "UpdateGUI.h"
24
25 #include "resource2.h"
26
27 using namespace NWindows;
28 using namespace NFile;
29 using namespace NDir;
30
31 static const char * const kDefaultSfxModule = "7z.sfx";
32 static const char * const kSFXExtension = "exe";
33
34 extern void AddMessageToString(UString &dest, const UString &src);
35
36 UString HResultToMessage(HRESULT errorCode);
37
38 class CThreadUpdating: public CProgressThreadVirt
39 {
40 HRESULT ProcessVirt() Z7_override;
41 public:
42 CCodecs *codecs;
43 const CObjectVector<COpenType> *formatIndices;
44 const UString *cmdArcPath;
45 CUpdateCallbackGUI *UpdateCallbackGUI;
46 NWildcard::CCensor *WildcardCensor;
47 CUpdateOptions *Options;
48 bool needSetPath;
49 };
50
ProcessVirt()51 HRESULT CThreadUpdating::ProcessVirt()
52 {
53 CUpdateErrorInfo ei;
54 HRESULT res = UpdateArchive(codecs, *formatIndices, *cmdArcPath,
55 *WildcardCensor, *Options,
56 ei, UpdateCallbackGUI, UpdateCallbackGUI, needSetPath);
57 FinalMessage.ErrorMessage.Message = ei.Message.Ptr();
58 ErrorPaths = ei.FileNames;
59 if (res != S_OK)
60 return res;
61 return HRESULT_FROM_WIN32(ei.SystemError);
62 }
63
64
65 // parse command line properties
66
ParseProp_Time_BoolPair(const CProperty & prop,const char * name,CBoolPair & bp)67 static bool ParseProp_Time_BoolPair(const CProperty &prop, const char *name, CBoolPair &bp)
68 {
69 if (!prop.Name.IsPrefixedBy_Ascii_NoCase(name))
70 return false;
71 const UString rem = prop.Name.Ptr((unsigned)strlen(name));
72 UString val = prop.Value;
73 if (!rem.IsEmpty())
74 {
75 if (!val.IsEmpty())
76 return true;
77 val = rem;
78 }
79 bool res;
80 if (StringToBool(val, res))
81 {
82 bp.Val = res;
83 bp.Def = true;
84 }
85 return true;
86 }
87
ParseProp(const CProperty & prop,NCompressDialog::CInfo & di)88 static void ParseProp(
89 const CProperty &prop,
90 NCompressDialog::CInfo &di)
91 {
92 if (ParseProp_Time_BoolPair(prop, "tm", di.MTime)) return;
93 if (ParseProp_Time_BoolPair(prop, "tc", di.CTime)) return;
94 if (ParseProp_Time_BoolPair(prop, "ta", di.ATime)) return;
95 }
96
ParseProperties(const CObjectVector<CProperty> & properties,NCompressDialog::CInfo & di)97 static void ParseProperties(
98 const CObjectVector<CProperty> &properties,
99 NCompressDialog::CInfo &di)
100 {
101 FOR_VECTOR (i, properties)
102 {
103 ParseProp(properties[i], di);
104 }
105 }
106
107
108
109
110
AddProp_UString(CObjectVector<CProperty> & properties,const char * name,const UString & value)111 static void AddProp_UString(CObjectVector<CProperty> &properties, const char *name, const UString &value)
112 {
113 CProperty prop;
114 prop.Name = name;
115 prop.Value = value;
116 properties.Add(prop);
117 }
118
AddProp_UInt32(CObjectVector<CProperty> & properties,const char * name,UInt32 value)119 static void AddProp_UInt32(CObjectVector<CProperty> &properties, const char *name, UInt32 value)
120 {
121 UString s;
122 s.Add_UInt32(value);
123 AddProp_UString(properties, name, s);
124 }
125
AddProp_bool(CObjectVector<CProperty> & properties,const char * name,bool value)126 static void AddProp_bool(CObjectVector<CProperty> &properties, const char *name, bool value)
127 {
128 AddProp_UString(properties, name, UString(value ? "on": "off"));
129 }
130
131
AddProp_BoolPair(CObjectVector<CProperty> & properties,const char * name,const CBoolPair & bp)132 static void AddProp_BoolPair(CObjectVector<CProperty> &properties,
133 const char *name, const CBoolPair &bp)
134 {
135 if (bp.Def)
136 AddProp_bool(properties, name, bp.Val);
137 }
138
139
140
SplitOptionsToStrings(const UString & src,UStringVector & strings)141 static void SplitOptionsToStrings(const UString &src, UStringVector &strings)
142 {
143 SplitString(src, strings);
144 FOR_VECTOR (i, strings)
145 {
146 UString &s = strings[i];
147 if (s.Len() > 2
148 && s[0] == '-'
149 && MyCharLower_Ascii(s[1]) == 'm')
150 s.DeleteFrontal(2);
151 }
152 }
153
IsThereMethodOverride(bool is7z,const UStringVector & strings)154 static bool IsThereMethodOverride(bool is7z, const UStringVector &strings)
155 {
156 FOR_VECTOR (i, strings)
157 {
158 const UString &s = strings[i];
159 if (is7z)
160 {
161 const wchar_t *end;
162 UInt64 n = ConvertStringToUInt64(s, &end);
163 if (n == 0 && *end == L'=')
164 return true;
165 }
166 else
167 {
168 if (s.Len() > 0)
169 if (s[0] == L'm' && s[1] == L'=')
170 return true;
171 }
172 }
173 return false;
174 }
175
ParseAndAddPropertires(CObjectVector<CProperty> & properties,const UStringVector & strings)176 static void ParseAndAddPropertires(CObjectVector<CProperty> &properties,
177 const UStringVector &strings)
178 {
179 FOR_VECTOR (i, strings)
180 {
181 const UString &s = strings[i];
182 CProperty property;
183 const int index = s.Find(L'=');
184 if (index < 0)
185 property.Name = s;
186 else
187 {
188 property.Name.SetFrom(s, (unsigned)index);
189 property.Value = s.Ptr(index + 1);
190 }
191 properties.Add(property);
192 }
193 }
194
195
AddProp_Size(CObjectVector<CProperty> & properties,const char * name,const UInt64 size)196 static void AddProp_Size(CObjectVector<CProperty> &properties, const char *name, const UInt64 size)
197 {
198 UString s;
199 s.Add_UInt64(size);
200 s.Add_Char('b');
201 AddProp_UString(properties, name, s);
202 }
203
204
SetOutProperties(CObjectVector<CProperty> & properties,const NCompressDialog::CInfo & di,bool is7z,bool setMethod)205 static void SetOutProperties(
206 CObjectVector<CProperty> &properties,
207 const NCompressDialog::CInfo &di,
208 bool is7z,
209 bool setMethod)
210 {
211 if (di.Level != (UInt32)(Int32)-1)
212 AddProp_UInt32(properties, "x", (UInt32)di.Level);
213 if (setMethod)
214 {
215 if (!di.Method.IsEmpty())
216 AddProp_UString(properties, is7z ? "0": "m", di.Method);
217 if (di.Dict64 != (UInt64)(Int64)-1)
218 {
219 AString name;
220 if (is7z)
221 name = "0";
222 name += (di.OrderMode ? "mem" : "d");
223 AddProp_Size(properties, name, di.Dict64);
224 }
225 /*
226 if (di.Dict64_Chain != (UInt64)(Int64)-1)
227 {
228 AString name;
229 if (is7z)
230 name = "0";
231 name += "dc";
232 AddProp_Size(properties, name, di.Dict64_Chain);
233 }
234 */
235 if (di.Order != (UInt32)(Int32)-1)
236 {
237 AString name;
238 if (is7z)
239 name = "0";
240 name += (di.OrderMode ? "o" : "fb");
241 AddProp_UInt32(properties, name, (UInt32)di.Order);
242 }
243 }
244
245 if (!di.EncryptionMethod.IsEmpty())
246 AddProp_UString(properties, "em", di.EncryptionMethod);
247
248 if (di.EncryptHeadersIsAllowed)
249 AddProp_bool(properties, "he", di.EncryptHeaders);
250
251 if (di.SolidIsSpecified)
252 AddProp_Size(properties, "s", di.SolidBlockSize);
253
254 if (
255 // di.MultiThreadIsAllowed &&
256 di.NumThreads != (UInt32)(Int32)-1)
257 AddProp_UInt32(properties, "mt", di.NumThreads);
258
259 const NCompression::CMemUse &memUse = di.MemUsage;
260 if (memUse.IsDefined)
261 {
262 const char *kMemUse = "memuse";
263 if (memUse.IsPercent)
264 {
265 UString s;
266 // s += 'p'; // for debug: alternate percent method
267 s.Add_UInt64(memUse.Val);
268 s.Add_Char('%');
269 AddProp_UString(properties, kMemUse, s);
270 }
271 else
272 AddProp_Size(properties, kMemUse, memUse.Val);
273 }
274
275 AddProp_BoolPair(properties, "tm", di.MTime);
276 AddProp_BoolPair(properties, "tc", di.CTime);
277 AddProp_BoolPair(properties, "ta", di.ATime);
278
279 if (di.TimePrec != (UInt32)(Int32)-1)
280 AddProp_UInt32(properties, "tp", di.TimePrec);
281 }
282
283
284 struct C_UpdateMode_ToAction_Pair
285 {
286 NCompressDialog::NUpdateMode::EEnum UpdateMode;
287 const NUpdateArchive::CActionSet *ActionSet;
288 };
289
290 static const C_UpdateMode_ToAction_Pair g_UpdateMode_Pairs[] =
291 {
292 { NCompressDialog::NUpdateMode::kAdd, &NUpdateArchive::k_ActionSet_Add },
293 { NCompressDialog::NUpdateMode::kUpdate, &NUpdateArchive::k_ActionSet_Update },
294 { NCompressDialog::NUpdateMode::kFresh, &NUpdateArchive::k_ActionSet_Fresh },
295 { NCompressDialog::NUpdateMode::kSync, &NUpdateArchive::k_ActionSet_Sync }
296 };
297
FindActionSet(const NUpdateArchive::CActionSet & actionSet)298 static int FindActionSet(const NUpdateArchive::CActionSet &actionSet)
299 {
300 for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_UpdateMode_Pairs); i++)
301 if (actionSet.IsEqualTo(*g_UpdateMode_Pairs[i].ActionSet))
302 return (int)i;
303 return -1;
304 }
305
FindUpdateMode(NCompressDialog::NUpdateMode::EEnum mode)306 static int FindUpdateMode(NCompressDialog::NUpdateMode::EEnum mode)
307 {
308 for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_UpdateMode_Pairs); i++)
309 if (mode == g_UpdateMode_Pairs[i].UpdateMode)
310 return (int)i;
311 return -1;
312 }
313
314
ShowDialog(CCodecs * codecs,const CObjectVector<NWildcard::CCensorPath> & censor,CUpdateOptions & options,CUpdateCallbackGUI * callback,HWND hwndParent)315 static HRESULT ShowDialog(
316 CCodecs *codecs,
317 const CObjectVector<NWildcard::CCensorPath> &censor,
318 CUpdateOptions &options,
319 CUpdateCallbackGUI *callback, HWND hwndParent)
320 {
321 if (options.Commands.Size() != 1)
322 throw "It must be one command";
323 /*
324 FString currentDirPrefix;
325 #ifndef UNDER_CE
326 {
327 if (!MyGetCurrentDirectory(currentDirPrefix))
328 return E_FAIL;
329 NName::NormalizeDirPathPrefix(currentDirPrefix);
330 }
331 #endif
332 */
333
334 bool oneFile = false;
335 NFind::CFileInfo fileInfo;
336 UString name;
337
338 /*
339 if (censor.Pairs.Size() > 0)
340 {
341 const NWildcard::CPair &pair = censor.Pairs[0];
342 if (pair.Head.IncludeItems.Size() > 0)
343 {
344 const NWildcard::CItem &item = pair.Head.IncludeItems[0];
345 if (item.ForFile)
346 {
347 name = pair.Prefix;
348 FOR_VECTOR (i, item.PathParts)
349 {
350 if (i > 0)
351 name.Add_PathSepar();
352 name += item.PathParts[i];
353 }
354 if (fileInfo.Find(us2fs(name)))
355 {
356 if (censor.Pairs.Size() == 1 && pair.Head.IncludeItems.Size() == 1)
357 oneFile = !fileInfo.IsDir();
358 }
359 }
360 }
361 }
362 */
363 if (censor.Size() > 0)
364 {
365 const NWildcard::CCensorPath &cp = censor[0];
366 if (cp.Include)
367 {
368 {
369 if (fileInfo.Find(us2fs(cp.Path)))
370 {
371 if (censor.Size() == 1)
372 oneFile = !fileInfo.IsDir();
373 }
374 }
375 }
376 }
377
378
379 /*
380 // v23: we restore current dir in dialog code
381 #if defined(_WIN32) && !defined(UNDER_CE)
382 CCurrentDirRestorer curDirRestorer;
383 #endif
384 */
385
386 CCompressDialog dialog;
387 NCompressDialog::CInfo &di = dialog.Info;
388 dialog.ArcFormats = &codecs->Formats;
389 {
390 CObjectVector<CCodecInfoUser> userCodecs;
391 codecs->Get_CodecsInfoUser_Vector(userCodecs);
392 dialog.SetMethods(userCodecs);
393 }
394
395 if (options.MethodMode.Type_Defined)
396 di.FormatIndex = options.MethodMode.Type.FormatIndex;
397
398 FOR_VECTOR (i, codecs->Formats)
399 {
400 const CArcInfoEx &ai = codecs->Formats[i];
401 if (!ai.UpdateEnabled)
402 continue;
403 if (!oneFile && ai.Flags_KeepName())
404 continue;
405 if ((int)i != di.FormatIndex)
406 {
407 if (ai.Flags_HashHandler())
408 continue;
409 if (ai.Name.IsEqualTo_Ascii_NoCase("swfc"))
410 if (!oneFile || name.Len() < 4 || !StringsAreEqualNoCase_Ascii(name.RightPtr(4), ".swf"))
411 continue;
412 }
413 dialog.ArcIndices.Add(i);
414 }
415 if (dialog.ArcIndices.IsEmpty())
416 {
417 ShowErrorMessage(L"No Update Engines");
418 return E_FAIL;
419 }
420
421 // di.ArchiveName = options.ArchivePath.GetFinalPath();
422 di.ArcPath = options.ArchivePath.GetPathWithoutExt();
423 dialog.OriginalFileName = fs2us(fileInfo.Name);
424
425 di.PathMode = options.PathMode;
426
427 // di.CurrentDirPrefix = currentDirPrefix;
428 di.SFXMode = options.SfxMode;
429 di.OpenShareForWrite = options.OpenShareForWrite;
430 di.DeleteAfterCompressing = options.DeleteAfterCompressing;
431
432 di.SymLinks = options.SymLinks;
433 di.HardLinks = options.HardLinks;
434 di.AltStreams = options.AltStreams;
435 di.NtSecurity = options.NtSecurity;
436 if (options.SetArcMTime)
437 di.SetArcMTime.SetTrueTrue();
438 if (options.PreserveATime)
439 di.PreserveATime.SetTrueTrue();
440
441 if (callback->PasswordIsDefined)
442 di.Password = callback->Password;
443
444 di.KeepName = !oneFile;
445
446 NUpdateArchive::CActionSet &actionSet = options.Commands.Front().ActionSet;
447
448 {
449 int index = FindActionSet(actionSet);
450 if (index < 0)
451 return E_NOTIMPL;
452 di.UpdateMode = g_UpdateMode_Pairs[(unsigned)index].UpdateMode;
453 }
454
455 ParseProperties(options.MethodMode.Properties, di);
456
457 if (dialog.Create(hwndParent) != IDOK)
458 return E_ABORT;
459
460 options.DeleteAfterCompressing = di.DeleteAfterCompressing;
461
462 options.SymLinks = di.SymLinks;
463 options.HardLinks = di.HardLinks;
464 options.AltStreams = di.AltStreams;
465 options.NtSecurity = di.NtSecurity;
466 options.SetArcMTime = di.SetArcMTime.Val;
467 if (di.PreserveATime.Def)
468 options.PreserveATime = di.PreserveATime.Val;
469
470 /*
471 #if defined(_WIN32) && !defined(UNDER_CE)
472 curDirRestorer.NeedRestore = dialog.CurrentDirWasChanged;
473 #endif
474 */
475
476 options.VolumesSizes = di.VolumeSizes;
477 /*
478 if (di.VolumeSizeIsDefined)
479 {
480 MyMessageBox(L"Splitting to volumes is not supported");
481 return E_FAIL;
482 }
483 */
484
485
486 {
487 int index = FindUpdateMode(di.UpdateMode);
488 if (index < 0)
489 return E_FAIL;
490 actionSet = *g_UpdateMode_Pairs[index].ActionSet;
491 }
492
493 options.PathMode = di.PathMode;
494
495 const CArcInfoEx &archiverInfo = codecs->Formats[di.FormatIndex];
496 callback->PasswordIsDefined = (!di.Password.IsEmpty());
497 if (callback->PasswordIsDefined)
498 callback->Password = di.Password;
499
500 // we clear command line options, and fill options form Dialog
501 options.MethodMode.Properties.Clear();
502
503 const bool is7z = archiverInfo.Is_7z();
504
505 UStringVector optionStrings;
506 SplitOptionsToStrings(di.Options, optionStrings);
507 const bool methodOverride = IsThereMethodOverride(is7z, optionStrings);
508
509 SetOutProperties(options.MethodMode.Properties, di,
510 is7z,
511 !methodOverride); // setMethod
512
513 options.OpenShareForWrite = di.OpenShareForWrite;
514 ParseAndAddPropertires(options.MethodMode.Properties, optionStrings);
515
516 if (di.SFXMode)
517 options.SfxMode = true;
518 options.MethodMode.Type = COpenType();
519 options.MethodMode.Type_Defined = true;
520 options.MethodMode.Type.FormatIndex = di.FormatIndex;
521
522 options.ArchivePath.VolExtension = archiverInfo.GetMainExt();
523 if (di.SFXMode)
524 options.ArchivePath.BaseExtension = kSFXExtension;
525 else
526 options.ArchivePath.BaseExtension = options.ArchivePath.VolExtension;
527 options.ArchivePath.ParseFromPath(di.ArcPath, k_ArcNameMode_Smart);
528
529 NWorkDir::CInfo workDirInfo;
530 workDirInfo.Load();
531 options.WorkingDir.Empty();
532 if (workDirInfo.Mode != NWorkDir::NMode::kCurrent)
533 {
534 FString fullPath;
535 MyGetFullPathName(us2fs(di.ArcPath), fullPath);
536 FString namePart;
537 options.WorkingDir = GetWorkDir(workDirInfo, fullPath, namePart);
538 CreateComplexDir(options.WorkingDir);
539 }
540 return S_OK;
541 }
542
UpdateGUI(CCodecs * codecs,const CObjectVector<COpenType> & formatIndices,const UString & cmdArcPath,NWildcard::CCensor & censor,CUpdateOptions & options,bool showDialog,bool & messageWasDisplayed,CUpdateCallbackGUI * callback,HWND hwndParent)543 HRESULT UpdateGUI(
544 CCodecs *codecs,
545 const CObjectVector<COpenType> &formatIndices,
546 const UString &cmdArcPath,
547 NWildcard::CCensor &censor,
548 CUpdateOptions &options,
549 bool showDialog,
550 bool &messageWasDisplayed,
551 CUpdateCallbackGUI *callback,
552 HWND hwndParent)
553 {
554 messageWasDisplayed = false;
555 bool needSetPath = true;
556 if (showDialog)
557 {
558 RINOK(ShowDialog(codecs, censor.CensorPaths, options, callback, hwndParent))
559 needSetPath = false;
560 }
561 if (options.SfxMode && options.SfxModule.IsEmpty())
562 {
563 options.SfxModule = NWindows::NDLL::GetModuleDirPrefix();
564 options.SfxModule += kDefaultSfxModule;
565 }
566
567 CThreadUpdating tu;
568
569 tu.needSetPath = needSetPath;
570
571 tu.codecs = codecs;
572 tu.formatIndices = &formatIndices;
573 tu.cmdArcPath = &cmdArcPath;
574
575 tu.UpdateCallbackGUI = callback;
576 tu.UpdateCallbackGUI->ProgressDialog = &tu;
577 tu.UpdateCallbackGUI->Init();
578
579 UString title = LangString(IDS_PROGRESS_COMPRESSING);
580 if (!formatIndices.IsEmpty())
581 {
582 const int fin = formatIndices[0].FormatIndex;
583 if (fin >= 0)
584 if (codecs->Formats[fin].Flags_HashHandler())
585 title = LangString(IDS_CHECKSUM_CALCULATING);
586 }
587
588 /*
589 if (hwndParent != 0)
590 {
591 tu.ProgressDialog.MainWindow = hwndParent;
592 // tu.ProgressDialog.MainTitle = fileName;
593 tu.ProgressDialog.MainAddTitle = title + L' ';
594 }
595 */
596
597 tu.WildcardCensor = &censor;
598 tu.Options = &options;
599 tu.IconID = IDI_ICON;
600
601 RINOK(tu.Create(title, hwndParent))
602
603 messageWasDisplayed = tu.ThreadFinishedOK && tu.MessagesDisplayed;
604 return tu.Result;
605 }
606