xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/GUI/UpdateGUI.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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