xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/GUI/CompressDialog.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // CompressDialog.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../../C/CpuArch.h"
6 
7 #include "../../../Common/IntToString.h"
8 #include "../../../Common/StringConvert.h"
9 
10 #include "../../../Windows/FileDir.h"
11 #include "../../../Windows/FileName.h"
12 #include "../../../Windows/System.h"
13 
14 #include "../../Common/MethodProps.h"
15 
16 #include "../FileManager/BrowseDialog.h"
17 #include "../FileManager/FormatUtils.h"
18 #include "../FileManager/HelpUtils.h"
19 #include "../FileManager/PropertyName.h"
20 #include "../FileManager/SplitUtils.h"
21 #include "../FileManager/resourceGui.h"
22 
23 #include "../Explorer/MyMessages.h"
24 
25 #include "../Common/ZipRegistry.h"
26 
27 #include "CompressDialog.h"
28 
29 #ifndef _UNICODE
30 extern bool g_IsNT;
31 #endif
32 
33 #include "../FileManager/LangUtils.h"
34 
35 #include "CompressDialogRes.h"
36 #include "ExtractRes.h"
37 #include "resource2.h"
38 
39 // #define PRINT_PARAMS
40 
41 #ifdef Z7_LANG
42 
43 // #define IDS_OPTIONS 2100
44 
45 static const UInt32 kLangIDs[] =
46 {
47   IDT_COMPRESS_ARCHIVE,
48   IDT_COMPRESS_UPDATE_MODE,
49   IDT_COMPRESS_FORMAT,
50   IDT_COMPRESS_LEVEL,
51   IDT_COMPRESS_METHOD,
52   IDT_COMPRESS_DICTIONARY,
53   IDT_COMPRESS_ORDER,
54   IDT_COMPRESS_SOLID,
55   IDT_COMPRESS_THREADS,
56   IDT_COMPRESS_PARAMETERS,
57 
58   IDB_COMPRESS_OPTIONS, // IDS_OPTIONS
59 
60   IDG_COMPRESS_OPTIONS,
61   IDX_COMPRESS_SFX,
62   IDX_COMPRESS_SHARED,
63   IDX_COMPRESS_DEL,
64 
65   IDT_COMPRESS_MEMORY,
66   IDT_COMPRESS_MEMORY_DE,
67 
68   IDG_COMPRESS_ENCRYPTION,
69   IDT_COMPRESS_ENCRYPTION_METHOD,
70   IDX_COMPRESS_ENCRYPT_FILE_NAMES,
71 
72   IDT_PASSWORD_ENTER,
73   IDT_PASSWORD_REENTER,
74   IDX_PASSWORD_SHOW,
75 
76   IDT_SPLIT_TO_VOLUMES,
77   IDT_COMPRESS_PATH_MODE,
78 };
79 #endif
80 
81 using namespace NWindows;
82 using namespace NFile;
83 using namespace NName;
84 using namespace NDir;
85 
86 static const unsigned kHistorySize = 20;
87 
88 static const UInt32 kSolidLog_NoSolid = 0;
89 static const UInt32 kSolidLog_FullSolid = 64;
90 
91 static const UInt32 kLzmaMaxDictSize = (UInt32)15 << 28;
92 
93 static const UINT k_Message_ArcChanged = WM_APP + 1;
94 
95 /*
96 static const UInt32 kZstd_MAX_DictSize = (UInt32)1 << MY_ZSTD_WINDOWLOG_MAX;
97 */
98 
99 /* The top value for windowLog_Chain:
100    (MY_ZSTD_CHAINLOG_MAX - 1): in BT mode
101    (MY_ZSTD_CHAINLOG_MAX)    : in non-BT mode. But such big value is useless in most cases.
102    So we always reduce top value to (MY_ZSTD_CHAINLOG_MAX - 1) */
103 /*
104 static const unsigned kMaxDictChain = MY_ZSTD_CHAINLOG_MAX - 1;
105 static const UInt32 kZstd_MAX_DictSize_Chain = (UInt32)1 << kMaxDictChain;
106 */
107 
108 static LPCSTR const kExeExt = ".exe";
109 
110 static const UInt32 g_Levels[] =
111 {
112   IDS_METHOD_STORE,
113   IDS_METHOD_FASTEST,
114   0,
115   IDS_METHOD_FAST,
116   0,
117   IDS_METHOD_NORMAL,
118   0,
119   IDS_METHOD_MAXIMUM,
120   0,
121   IDS_METHOD_ULTRA
122 };
123 
124 enum EMethodID
125 {
126   kCopy,
127   kLZMA,
128   kLZMA2,
129   kPPMd,
130   kBZip2,
131   kDeflate,
132   kDeflate64,
133   kPPMdZip,
134   // kZSTD,
135   kSha256,
136   kSha1,
137   kCrc32,
138   kCrc64,
139   kGnu,
140   kPosix
141 };
142 
143 static LPCSTR const kMethodsNames[] =
144 {
145     "Copy"
146   , "LZMA"
147   , "LZMA2"
148   , "PPMd"
149   , "BZip2"
150   , "Deflate"
151   , "Deflate64"
152   , "PPMd"
153   // , "ZSTD"
154   , "SHA256"
155   , "SHA1"
156   , "CRC32"
157   , "CRC64"
158   , "GNU"
159   , "POSIX"
160 };
161 
162 static const EMethodID g_7zMethods[] =
163 {
164   kLZMA2,
165   kLZMA,
166   kPPMd,
167   kBZip2
168   , kDeflate
169   , kDeflate64
170   // , kZSTD
171   , kCopy
172 };
173 
174 static const EMethodID g_7zSfxMethods[] =
175 {
176   kCopy,
177   kLZMA,
178   kLZMA2,
179   kPPMd
180 };
181 
182 static const EMethodID g_ZipMethods[] =
183 {
184   kDeflate,
185   kDeflate64,
186   kBZip2,
187   kLZMA,
188   kPPMdZip
189   // , kZSTD
190 };
191 
192 static const EMethodID g_GZipMethods[] =
193 {
194   kDeflate
195 };
196 
197 static const EMethodID g_BZip2Methods[] =
198 {
199   kBZip2
200 };
201 
202 static const EMethodID g_XzMethods[] =
203 {
204   kLZMA2
205 };
206 
207 /*
208 static const EMethodID g_ZstdMethods[] =
209 {
210   kZSTD
211 };
212 */
213 
214 /*
215 static const EMethodID g_SwfcMethods[] =
216 {
217   kDeflate
218   // kLZMA
219 };
220 */
221 
222 static const EMethodID g_TarMethods[] =
223 {
224   kGnu,
225   kPosix
226 };
227 
228 static const EMethodID g_HashMethods[] =
229 {
230     kSha256
231   , kSha1
232   // , kCrc32
233   // , kCrc64
234 };
235 
236 static const UInt32 kFF_Filter      = 1 << 0;
237 static const UInt32 kFF_Solid       = 1 << 1;
238 static const UInt32 kFF_MultiThread = 1 << 2;
239 static const UInt32 kFF_Encrypt     = 1 << 3;
240 static const UInt32 kFF_EncryptFileNames  = 1 << 4;
241 static const UInt32 kFF_MemUse      = 1 << 5;
242 static const UInt32 kFF_SFX         = 1 << 6;
243 
244 /*
245 static const UInt32 kFF_Time_Win  = 1 << 10;
246 static const UInt32 kFF_Time_Unix = 1 << 11;
247 static const UInt32 kFF_Time_DOS  = 1 << 12;
248 static const UInt32 kFF_Time_1ns  = 1 << 13;
249 */
250 
251 struct CFormatInfo
252 {
253   LPCSTR Name;
254   UInt32 LevelsMask;
255   unsigned NumMethods;
256   const EMethodID *MethodIDs;
257 
258   UInt32 Flags;
259 
Filter_CFormatInfo260   bool Filter_() const { return (Flags & kFF_Filter) != 0; }
Solid_CFormatInfo261   bool Solid_() const { return (Flags & kFF_Solid) != 0; }
MultiThread_CFormatInfo262   bool MultiThread_() const { return (Flags & kFF_MultiThread) != 0; }
Encrypt_CFormatInfo263   bool Encrypt_() const { return (Flags & kFF_Encrypt) != 0; }
EncryptFileNames_CFormatInfo264   bool EncryptFileNames_() const { return (Flags & kFF_EncryptFileNames) != 0; }
MemUse_CFormatInfo265   bool MemUse_() const { return (Flags & kFF_MemUse) != 0; }
SFX_CFormatInfo266   bool SFX_() const { return (Flags & kFF_SFX) != 0; }
267 };
268 
269 #define METHODS_PAIR(x) Z7_ARRAY_SIZE(x), x
270 
271 static const CFormatInfo g_Formats[] =
272 {
273   {
274     "",
275     // (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
276     ((UInt32)1 << 10) - 1,
277     // (UInt32)(Int32)-1,
278     0, NULL,
279     kFF_MultiThread | kFF_MemUse
280   },
281   {
282     "7z",
283     // (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
284     (1 << 10) - 1,
285     METHODS_PAIR(g_7zMethods),
286     kFF_Filter | kFF_Solid | kFF_MultiThread | kFF_Encrypt |
287     kFF_EncryptFileNames | kFF_MemUse | kFF_SFX
288     // | kFF_Time_Win
289   },
290   {
291     "Zip",
292     (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
293     METHODS_PAIR(g_ZipMethods),
294     kFF_MultiThread | kFF_Encrypt | kFF_MemUse
295     // | kFF_Time_Win | kFF_Time_Unix | kFF_Time_DOS
296   },
297   {
298     "GZip",
299     (1 << 1) | (1 << 5) | (1 << 7) | (1 << 9),
300     METHODS_PAIR(g_GZipMethods),
301     kFF_MemUse
302     // | kFF_Time_Unix
303   },
304   {
305     "BZip2",
306     (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
307     METHODS_PAIR(g_BZip2Methods),
308     kFF_MultiThread | kFF_MemUse
309   },
310   {
311     "xz",
312     // (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
313     (1 << 10) - 1 - (1 << 0), // store (1 << 0) is not supported
314     METHODS_PAIR(g_XzMethods),
315     kFF_Solid | kFF_MultiThread | kFF_MemUse
316   },
317   /*
318   {
319     "zstd",
320     // (1 << (MY_ZSTD_LEVEL_MAX + 1)) - 1,
321     (1 << (9 + 1)) - 1,
322     METHODS_PAIR(g_ZstdMethods),
323     // kFF_Solid |
324     kFF_MultiThread
325     | kFF_MemUse
326   },
327   */
328 /*
329   {
330     "Swfc",
331     (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
332     METHODS_PAIR(g_SwfcMethods),
333     0
334   },
335 */
336   {
337     "Tar",
338     (1 << 0),
339     METHODS_PAIR(g_TarMethods),
340     0
341     // kFF_Time_Unix | kFF_Time_Win // | kFF_Time_1ns
342   },
343   {
344     "wim",
345     (1 << 0),
346     0, NULL,
347     0
348     // | kFF_Time_Win
349   },
350   {
351     "Hash",
352     (0 << 0),
353     METHODS_PAIR(g_HashMethods),
354     0
355   }
356 };
357 
IsMethodSupportedBySfx(int methodID)358 static bool IsMethodSupportedBySfx(int methodID)
359 {
360   for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_7zSfxMethods); i++)
361     if (methodID == g_7zSfxMethods[i])
362       return true;
363   return false;
364 }
365 
366 
367 static const
368   // NCompressDialog::NUpdateMode::EEnum
369   int
370   k_UpdateMode_Vals[] =
371 {
372   NCompressDialog::NUpdateMode::kAdd,
373   NCompressDialog::NUpdateMode::kUpdate,
374   NCompressDialog::NUpdateMode::kFresh,
375   NCompressDialog::NUpdateMode::kSync
376 };
377 
378 static const UInt32 k_UpdateMode_IDs[] =
379 {
380   IDS_COMPRESS_UPDATE_MODE_ADD,
381   IDS_COMPRESS_UPDATE_MODE_UPDATE,
382   IDS_COMPRESS_UPDATE_MODE_FRESH,
383   IDS_COMPRESS_UPDATE_MODE_SYNC
384 };
385 
386 static const
387   // NWildcard::ECensorPathMode
388   int
389   k_PathMode_Vals[] =
390 {
391   NWildcard::k_RelatPath,
392   NWildcard::k_FullPath,
393   NWildcard::k_AbsPath,
394 };
395 
396 static const UInt32 k_PathMode_IDs[] =
397 {
398   IDS_PATH_MODE_RELAT,
399   IDS_EXTRACT_PATHS_FULL,
400   IDS_EXTRACT_PATHS_ABS
401 };
402 
403 void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned numItems, const int *values, int curVal);
404 
SetMethods(const CObjectVector<CCodecInfoUser> & userCodecs)405 void CCompressDialog::SetMethods(const CObjectVector<CCodecInfoUser> &userCodecs)
406 {
407   ExternalMethods.Clear();
408   {
409     FOR_VECTOR (i, userCodecs)
410     {
411       const CCodecInfoUser &c = userCodecs[i];
412       if (!c.EncoderIsAssigned
413           || !c.IsFilter_Assigned
414           || c.IsFilter
415           || c.NumStreams != 1)
416         continue;
417       unsigned k;
418       for (k = 0; k < Z7_ARRAY_SIZE(g_7zMethods); k++)
419         if (c.Name.IsEqualTo_Ascii_NoCase(kMethodsNames[g_7zMethods[k]]))
420           break;
421       if (k != Z7_ARRAY_SIZE(g_7zMethods))
422         continue;
423       ExternalMethods.Add(c.Name);
424     }
425   }
426 }
427 
428 
OnInit()429 bool CCompressDialog::OnInit()
430 {
431   #ifdef Z7_LANG
432   LangSetWindowText(*this, IDD_COMPRESS);
433   LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
434   // LangSetDlgItemText(*this, IDB_COMPRESS_OPTIONS, IDS_OPTIONS); // IDG_COMPRESS_OPTIONS
435   #endif
436 
437   {
438     size_t size = (size_t)sizeof(size_t) << 29;
439     _ramSize_Defined = NSystem::GetRamSize(size);
440     // size = (UInt64)3 << 62; // for debug only;
441     {
442       // we use reduced limit for 32-bit version:
443       unsigned bits = sizeof(size_t) * 8;
444       if (bits == 32)
445       {
446         const UInt32 limit2 = (UInt32)7 << 28;
447         if (size > limit2)
448             size = limit2;
449       }
450     }
451     _ramSize = size;
452     const size_t kMinUseSize = 1 << 26;
453     if (size < kMinUseSize)
454         size = kMinUseSize;
455     _ramSize_Reduced = size;
456 
457     // 80% - is auto usage limit in handlers
458     _ramUsage_Auto = Calc_From_Val_Percents(size, 80);
459   }
460 
461   _password1Control.Attach(GetItem(IDE_COMPRESS_PASSWORD1));
462   _password2Control.Attach(GetItem(IDE_COMPRESS_PASSWORD2));
463   _password1Control.SetText(Info.Password);
464   _password2Control.SetText(Info.Password);
465   _encryptionMethod.Attach(GetItem(IDC_COMPRESS_ENCRYPTION_METHOD));
466   _default_encryptionMethod_Index = -1;
467 
468   m_ArchivePath.Attach(GetItem(IDC_COMPRESS_ARCHIVE));
469   m_Format.Attach(GetItem(IDC_COMPRESS_FORMAT)); // that combo has CBS_SORT style in resources
470   m_Level.Attach(GetItem(IDC_COMPRESS_LEVEL));
471   m_Method.Attach(GetItem(IDC_COMPRESS_METHOD));
472   m_Dictionary.Attach(GetItem(IDC_COMPRESS_DICTIONARY));
473 
474   /*
475   {
476     RECT r;
477     GetClientRectOfItem(IDC_COMPRESS_DICTIONARY, r);
478     _dictionaryCombo_left = r.left;
479   }
480   */
481   _dictionaryCombo_left = 0; // 230;
482 
483   // m_Dictionary_Chain.Attach(GetItem(IDC_COMPRESS_DICTIONARY2));
484   m_Order.Attach(GetItem(IDC_COMPRESS_ORDER));
485   m_Solid.Attach(GetItem(IDC_COMPRESS_SOLID));
486   m_NumThreads.Attach(GetItem(IDC_COMPRESS_THREADS));
487   m_MemUse.Attach(GetItem(IDC_COMPRESS_MEM_USE));
488 
489   m_UpdateMode.Attach(GetItem(IDC_COMPRESS_UPDATE_MODE));
490   m_PathMode.Attach(GetItem(IDC_COMPRESS_PATH_MODE));
491 
492   m_Volume.Attach(GetItem(IDC_COMPRESS_VOLUME));
493   m_Params.Attach(GetItem(IDE_COMPRESS_PARAMETERS));
494 
495   AddVolumeItems(m_Volume);
496 
497   m_RegistryInfo.Load();
498   CheckButton(IDX_PASSWORD_SHOW, m_RegistryInfo.ShowPassword);
499   CheckButton(IDX_COMPRESS_ENCRYPT_FILE_NAMES, m_RegistryInfo.EncryptHeaders);
500 
501   UpdatePasswordControl();
502 
503   {
504     const bool needSetMain = (Info.FormatIndex < 0);
505     FOR_VECTOR(i, ArcIndices)
506     {
507       const unsigned arcIndex = ArcIndices[i];
508       const CArcInfoEx &ai = (*ArcFormats)[arcIndex];
509       const int index = (int)m_Format.AddString(ai.Name);
510       m_Format.SetItemData(index, (LPARAM)arcIndex);
511       if (!needSetMain)
512       {
513         if (Info.FormatIndex == (int)arcIndex)
514           m_Format.SetCurSel(index);
515         continue;
516       }
517       if (i == 0 || ai.Name.IsEqualTo_NoCase(m_RegistryInfo.ArcType))
518       {
519         m_Format.SetCurSel(index);
520         Info.FormatIndex = (int)arcIndex;
521       }
522     }
523   }
524 
525   CheckButton(IDX_COMPRESS_SFX, Info.SFXMode);
526 
527   {
528     UString fileName;
529     SetArcPathFields(Info.ArcPath, fileName, true);
530     StartDirPrefix = DirPrefix;
531     SetArchiveName(fileName);
532   }
533 
534   for (unsigned i = 0; i < m_RegistryInfo.ArcPaths.Size() && i < kHistorySize; i++)
535     m_ArchivePath.AddString(m_RegistryInfo.ArcPaths[i]);
536 
537   AddComboItems(m_UpdateMode, k_UpdateMode_IDs, Z7_ARRAY_SIZE(k_UpdateMode_IDs),
538       k_UpdateMode_Vals, Info.UpdateMode);
539 
540   AddComboItems(m_PathMode, k_PathMode_IDs, Z7_ARRAY_SIZE(k_PathMode_IDs),
541       k_PathMode_Vals, Info.PathMode);
542 
543 
544   TCHAR s[32] = { TEXT('/'), TEXT(' '), 0 };
545   ConvertUInt32ToString(NSystem::GetNumberOfProcessors(), s + 2);
546   SetItemText(IDT_COMPRESS_HARDWARE_THREADS, s);
547 
548   CheckButton(IDX_COMPRESS_SHARED, Info.OpenShareForWrite);
549   CheckButton(IDX_COMPRESS_DEL, Info.DeleteAfterCompressing);
550 
551   FormatChanged(false); // isChanged
552 
553   // OnButtonSFX();
554 
555   NormalizePosition();
556 
557   return CModalDialog::OnInit();
558 }
559 
560 /*
561 namespace NCompressDialog
562 {
563   bool CInfo::GetFullPathName(UString &result) const
564   {
565     #ifndef UNDER_CE
566     // NDirectory::MySetCurrentDirectory(CurrentDirPrefix);
567     #endif
568     FString resultF;
569     bool res = MyGetFullPathName(us2fs(ArchiveName), resultF);
570     result = fs2us(resultF);
571     return res;
572   }
573 }
574 */
575 
UpdatePasswordControl()576 void CCompressDialog::UpdatePasswordControl()
577 {
578   const bool showPassword = IsShowPasswordChecked();
579   const TCHAR c = showPassword ? (TCHAR)0: TEXT('*');
580   _password1Control.SetPasswordChar((WPARAM)c);
581   _password2Control.SetPasswordChar((WPARAM)c);
582   UString password;
583   _password1Control.GetText(password);
584   _password1Control.SetText(password);
585   _password2Control.GetText(password);
586   _password2Control.SetText(password);
587 
588   ShowItem_Bool(IDT_PASSWORD_REENTER, !showPassword);
589   _password2Control.Show_Bool(!showPassword);
590 }
591 
OnButtonClicked(unsigned buttonID,HWND buttonHWND)592 bool CCompressDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
593 {
594   switch (buttonID)
595   {
596     case IDB_COMPRESS_SET_ARCHIVE:
597     {
598       OnButtonSetArchive();
599       return true;
600     }
601     case IDX_COMPRESS_SFX:
602     {
603       SetMethod(GetMethodID());
604       OnButtonSFX();
605       SetMemoryUsage();
606       return true;
607     }
608     case IDX_PASSWORD_SHOW:
609     {
610       UpdatePasswordControl();
611       return true;
612     }
613     case IDB_COMPRESS_OPTIONS:
614     {
615       COptionsDialog dialog(this);
616       if (dialog.Create(*this) == IDOK)
617         ShowOptionsString();
618       return true;
619     }
620   }
621   return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
622 }
623 
CheckSFXControlsEnable()624 void CCompressDialog::CheckSFXControlsEnable()
625 {
626   const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
627   bool enable = fi.SFX_();
628   if (enable)
629   {
630     const int methodID = GetMethodID();
631     enable = (methodID == -1 || IsMethodSupportedBySfx(methodID));
632   }
633   if (!enable)
634     CheckButton(IDX_COMPRESS_SFX, false);
635   EnableItem(IDX_COMPRESS_SFX, enable);
636 }
637 
638 /*
639 void CCompressDialog::CheckVolumeEnable()
640 {
641   bool isSFX = IsSFX();
642   m_Volume.Enable(!isSFX);
643   if (isSFX)
644     m_Volume.SetText(TEXT(""));
645 }
646 */
647 
EnableMultiCombo(unsigned id)648 void CCompressDialog::EnableMultiCombo(unsigned id)
649 {
650   NWindows::NControl::CComboBox combo;
651   combo.Attach(GetItem(id));
652   const bool enable = (combo.GetCount() > 1);
653   EnableItem(id, enable);
654 }
655 
656 static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s);
657 
Combine_Two_BoolPairs(const CBoolPair & b1,const CBoolPair & b2,CBool1 & res)658 static void Combine_Two_BoolPairs(const CBoolPair &b1, const CBoolPair &b2, CBool1 &res)
659 {
660   if (!b1.Def && b2.Def)
661     res.Val = b2.Val;
662   else
663     res.Val = b1.Val;
664 }
665 
666 #define SET_GUI_BOOL(name) \
667       Combine_Two_BoolPairs(Info. name, m_RegistryInfo. name, name)
668 
669 
Set_Final_BoolPairs(const CBool1 & gui,CBoolPair & cmd,CBoolPair & reg)670 static void Set_Final_BoolPairs(
671     const CBool1 &gui,
672     CBoolPair &cmd,
673     CBoolPair &reg)
674 {
675   if (!cmd.Def)
676   {
677     reg.Val = gui.Val;
678     reg.Def = gui.Val;
679   }
680   if (gui.Supported)
681   {
682     cmd.Val = gui.Val;
683     cmd.Def = gui.Val;
684   }
685   else
686     cmd.Init();
687 }
688 
689 #define SET_FINAL_BOOL_PAIRS(name) \
690     Set_Final_BoolPairs(name, Info. name, m_RegistryInfo. name)
691 
FormatChanged(bool isChanged)692 void CCompressDialog::FormatChanged(bool isChanged)
693 {
694   SetLevel();
695   SetSolidBlockSize();
696   SetParams();
697   SetMemUseCombo();
698   SetNumThreads();
699 
700   const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
701   Info.SolidIsSpecified = fi.Solid_();
702   Info.EncryptHeadersIsAllowed = fi.EncryptFileNames_();
703 
704   /*
705   const bool multiThreadEnable = fi.MultiThread;
706   Info.MultiThreadIsAllowed = multiThreadEnable;
707   EnableItem(IDC_COMPRESS_SOLID, fi.Solid);
708   EnableItem(IDC_COMPRESS_THREADS, multiThreadEnable);
709   const bool methodEnable = (fi.MethodIDs != NULL);
710   EnableItem(IDC_COMPRESS_METHOD, methodEnable);
711   EnableMultiCombo(IDC_COMPRESS_DICTIONARY, methodEnable);
712   EnableItem(IDC_COMPRESS_ORDER, methodEnable);
713   */
714 
715   CheckSFXControlsEnable();
716 
717   {
718     if (!isChanged)
719     {
720       SET_GUI_BOOL (SymLinks);
721       SET_GUI_BOOL (HardLinks);
722       SET_GUI_BOOL (AltStreams);
723       SET_GUI_BOOL (NtSecurity);
724       SET_GUI_BOOL (PreserveATime);
725     }
726 
727     PreserveATime.Supported = true;
728 
729     {
730       const CArcInfoEx &ai = Get_ArcInfoEx();
731       SymLinks.Supported   = ai.Flags_SymLinks();
732       HardLinks.Supported  = ai.Flags_HardLinks();
733       AltStreams.Supported = ai.Flags_AltStreams();
734       NtSecurity.Supported = ai.Flags_NtSecurity();
735     }
736 
737     ShowOptionsString();
738   }
739   // CheckVolumeEnable();
740 
741   const bool encrypt = fi.Encrypt_();
742   EnableItem(IDG_COMPRESS_ENCRYPTION, encrypt);
743 
744   EnableItem(IDT_PASSWORD_ENTER, encrypt);
745   EnableItem(IDT_PASSWORD_REENTER, encrypt);
746   EnableItem(IDE_COMPRESS_PASSWORD1, encrypt);
747   EnableItem(IDE_COMPRESS_PASSWORD2, encrypt);
748   EnableItem(IDX_PASSWORD_SHOW, encrypt);
749 
750   EnableItem(IDT_COMPRESS_ENCRYPTION_METHOD, encrypt);
751   EnableItem(IDC_COMPRESS_ENCRYPTION_METHOD, encrypt);
752   EnableItem(IDX_COMPRESS_ENCRYPT_FILE_NAMES, fi.EncryptFileNames_());
753 
754   ShowItem_Bool(IDX_COMPRESS_ENCRYPT_FILE_NAMES, fi.EncryptFileNames_());
755 
756   SetEncryptionMethod();
757   SetMemoryUsage();
758 }
759 
760 
IsSFX()761 bool CCompressDialog::IsSFX()
762 {
763   return IsWindowEnabled(GetItem(IDX_COMPRESS_SFX))
764       && IsButtonCheckedBool(IDX_COMPRESS_SFX);
765 }
766 
GetExtDotPos(const UString & s)767 static int GetExtDotPos(const UString &s)
768 {
769   const int dotPos = s.ReverseFind_Dot();
770   if (dotPos > s.ReverseFind_PathSepar() + 1)
771     return dotPos;
772   return -1;
773 }
774 
OnButtonSFX()775 void CCompressDialog::OnButtonSFX()
776 {
777   UString fileName;
778   m_ArchivePath.GetText(fileName);
779   const int dotPos = GetExtDotPos(fileName);
780   if (IsSFX())
781   {
782     if (dotPos >= 0)
783       fileName.DeleteFrom(dotPos);
784     fileName += kExeExt;
785     m_ArchivePath.SetText(fileName);
786   }
787   else
788   {
789     if (dotPos >= 0)
790     {
791       const UString ext = fileName.Ptr(dotPos);
792       if (ext.IsEqualTo_Ascii_NoCase(kExeExt))
793       {
794         fileName.DeleteFrom(dotPos);
795         m_ArchivePath.SetText(fileName);
796       }
797     }
798     SetArchiveName2(false); // it's for OnInit
799   }
800 
801   // CheckVolumeEnable();
802 }
803 
804 
GetFinalPath_Smart(UString & resPath) const805 bool CCompressDialog::GetFinalPath_Smart(UString &resPath) const
806 {
807   resPath.Empty();
808   UString name;
809   m_ArchivePath.GetText(name);
810   name.Trim();
811   FString fullPath;
812   UString dirPrefx = DirPrefix;
813   if (dirPrefx.IsEmpty())
814     dirPrefx = StartDirPrefix;
815   const bool res = !dirPrefx.IsEmpty() ?
816       NName::GetFullPath(us2fs(dirPrefx), us2fs(name), fullPath):
817       NName::GetFullPath(                 us2fs(name), fullPath);
818   if (res)
819     resPath = fs2us(fullPath);
820   return res;
821 }
822 
823 
SetArcPathFields(const UString & path)824 bool CCompressDialog::SetArcPathFields(const UString &path)
825 {
826   UString name;
827   return SetArcPathFields(path, name, true); // always
828 }
829 
830 
SetArcPathFields(const UString & path,UString & name,bool always)831 bool CCompressDialog::SetArcPathFields(const UString &path, UString &name, bool always)
832 {
833   FString resDirPrefix;
834   FString resFileName;
835   const bool res = GetFullPathAndSplit(us2fs(path), resDirPrefix, resFileName);
836   if (res)
837   {
838     DirPrefix = fs2us(resDirPrefix);
839     name = fs2us(resFileName);
840   }
841   else
842   {
843     if (!always)
844       return false;
845     DirPrefix.Empty();
846     name = path;
847   }
848   SetItemText(IDT_COMPRESS_ARCHIVE_FOLDER, DirPrefix);
849   m_ArchivePath.SetText(name);
850   return res;
851 }
852 
853 
854 static const wchar_t * const k_IncorrectPathMessage = L"Incorrect archive path";
855 
AddFilter(CObjectVector<CBrowseFilterInfo> & filters,const UString & description,const UString & ext)856 static void AddFilter(CObjectVector<CBrowseFilterInfo> &filters,
857     const UString &description, const UString &ext)
858 {
859   CBrowseFilterInfo &f = filters.AddNew();
860   UString mask ("*.");
861   mask += ext;
862   f.Masks.Add(mask);
863   f.Description = description;
864   f.Description += " (";
865   f.Description += mask;
866   f.Description += ")";
867 }
868 
869 
870 static const char * const k_DontSave_Exts =
871   "xpi odt ods docx xlsx ";
872 
OnButtonSetArchive()873 void CCompressDialog::OnButtonSetArchive()
874 {
875   UString path;
876   if (!GetFinalPath_Smart(path))
877   {
878     ShowErrorMessage(*this, k_IncorrectPathMessage);
879     return;
880   }
881 
882   int filterIndex;
883   CObjectVector<CBrowseFilterInfo> filters;
884   unsigned numFormats = 0;
885 
886   const bool isSFX = IsSFX();
887   if (isSFX)
888   {
889     filterIndex = 0;
890     const UString ext ("exe");
891     AddFilter(filters, ext, ext);
892   }
893   else
894   {
895     filterIndex = m_Format.GetCurSel();
896     numFormats = (unsigned)m_Format.GetCount();
897 
898     // filters [0, ... numFormats - 1] corresponds to items in m_Format combo
899     UString desc;
900     UStringVector masks;
901     CStringFinder finder;
902 
903     for (unsigned i = 0; i < numFormats; i++)
904     {
905       const CArcInfoEx &ai = (*ArcFormats)[(unsigned)m_Format.GetItemData(i)];
906       CBrowseFilterInfo &f = filters.AddNew();
907       f.Description = ai.Name;
908       f.Description += " (";
909       bool needSpace_desc = false;
910 
911       FOR_VECTOR (k, ai.Exts)
912       {
913         const UString &ext = ai.Exts[k].Ext;
914         UString mask ("*.");
915         mask += ext;
916 
917         if (finder.FindWord_In_LowCaseAsciiList_NoCase(k_DontSave_Exts, ext))
918           continue;
919 
920         f.Masks.Add(mask);
921         masks.Add(mask);
922         if (needSpace_desc)
923           f.Description.Add_Space();
924         needSpace_desc = true;
925         f.Description += ext;
926       }
927       f.Description += ")";
928       // we use only main ext in desc to reduce the size of list
929       if (i != 0)
930         desc.Add_Space();
931       desc += ai.GetMainExt();
932     }
933 
934     CBrowseFilterInfo &f = filters.AddNew();
935     f.Description = LangString(IDT_COMPRESS_ARCHIVE); // IDS_ARCHIVES_COLON;
936     if (f.Description.IsEmpty())
937       GetItemText(IDT_COMPRESS_ARCHIVE, f.Description);
938     f.Description.RemoveChar(L'&');
939     // f.Description = "archive";
940     f.Description += " (";
941     f.Description += desc;
942     f.Description += ")";
943     f.Masks = masks;
944   }
945 
946   AddFilter(filters, LangString(IDS_OPEN_TYPE_ALL_FILES), UString("*"));
947   if (filterIndex < 0)
948     filterIndex = (int)filters.Size() - 1;
949 
950   const UString title = LangString(IDS_COMPRESS_SET_ARCHIVE_BROWSE);
951   CBrowseInfo bi;
952   bi.lpstrTitle = title;
953   bi.SaveMode = true;
954   bi.FilterIndex = filterIndex;
955   bi.hwndOwner = *this;
956   bi.FilePath = path;
957 
958   if (!bi.BrowseForFile(filters))
959     return;
960 
961   path = bi.FilePath;
962 
963   if (isSFX)
964   {
965     const int dotPos = GetExtDotPos(path);
966     if (dotPos >= 0)
967       path.DeleteFrom(dotPos);
968     path += kExeExt;
969   }
970   else
971   // if (bi.FilterIndex >= 0)
972   // if (bi.FilterIndex != filterIndex)
973   if ((unsigned)bi.FilterIndex < numFormats)
974   {
975     // archive format was confirmed. So we try to set format extension
976     bool needAddExt = true;
977     const CArcInfoEx &ai = (*ArcFormats)[(unsigned)m_Format.GetItemData((unsigned)bi.FilterIndex)];
978     const int dotPos = GetExtDotPos(path);
979     if (dotPos >= 0)
980     {
981       const UString ext = path.Ptr(dotPos + 1);
982       if (ai.FindExtension(ext) >= 0)
983         needAddExt = false;
984     }
985     if (needAddExt)
986     {
987       if (path.IsEmpty() || path.Back() != '.')
988         path.Add_Dot();
989       path += ai.GetMainExt();
990     }
991   }
992 
993   SetArcPathFields(path);
994 
995   if (!isSFX)
996   if ((unsigned)bi.FilterIndex < numFormats)
997   if (bi.FilterIndex != m_Format.GetCurSel())
998   {
999     m_Format.SetCurSel(bi.FilterIndex);
1000     SaveOptionsInMem();
1001     FormatChanged(true); // isChanged
1002     return;
1003   }
1004 
1005   ArcPath_WasChanged(path);
1006 }
1007 
1008 
1009 // in ExtractDialog.cpp
1010 extern void AddUniqueString(UStringVector &strings, const UString &srcString);
1011 
IsAsciiString(const UString & s)1012 static bool IsAsciiString(const UString &s)
1013 {
1014   for (unsigned i = 0; i < s.Len(); i++)
1015   {
1016     const wchar_t c = s[i];
1017     if (c < 0x20 || c > 0x7F)
1018       return false;
1019   }
1020   return true;
1021 }
1022 
1023 
AddSize_MB(UString & s,UInt64 size)1024 static void AddSize_MB(UString &s, UInt64 size)
1025 {
1026   s.Add_LF();
1027   const UInt64 v2 = size + ((UInt32)1 << 20) - 1;
1028   if (size < v2)
1029       size = v2;
1030   s.Add_UInt64(size >> 20);
1031   s += " MB : ";
1032 }
1033 
AddSize_MB_id(UString & s,UInt64 size,UInt32 id)1034 static void AddSize_MB_id(UString &s, UInt64 size, UInt32 id)
1035 {
1036   AddSize_MB(s, size);
1037   AddLangString(s, id);
1038 }
1039 
1040 void SetErrorMessage_MemUsage(UString &s, UInt64 reqSize, UInt64 ramSize, UInt64 ramLimit, const UString &usageString);
SetErrorMessage_MemUsage(UString & s,UInt64 reqSize,UInt64 ramSize,UInt64 ramLimit,const UString & usageString)1041 void SetErrorMessage_MemUsage(UString &s, UInt64 reqSize, UInt64 ramSize, UInt64 ramLimit, const UString &usageString)
1042 {
1043   AddLangString(s, IDS_MEM_OPERATION_BLOCKED);
1044   s.Add_LF();
1045   AddLangString(s, IDS_MEM_REQUIRES_BIG_MEM);
1046   s.Add_LF();
1047   AddSize_MB(s, reqSize);
1048   s += usageString;
1049   AddSize_MB_id(s, ramSize, IDS_MEM_RAM_SIZE);
1050   // if (ramLimit != 0)
1051   {
1052     AddSize_MB_id(s, ramLimit, IDS_MEM_USAGE_LIMIT_SET_BY_7ZIP);
1053   }
1054   s.Add_LF();
1055   s.Add_LF();
1056   AddLangString(s, IDS_MEM_ERROR);
1057 }
1058 
1059 
OnOK()1060 void CCompressDialog::OnOK()
1061 {
1062   _password1Control.GetText(Info.Password);
1063   if (IsZipFormat())
1064   {
1065     if (!IsAsciiString(Info.Password))
1066     {
1067       ShowErrorMessageHwndRes(*this, IDS_PASSWORD_USE_ASCII);
1068       return;
1069     }
1070     UString method = GetEncryptionMethodSpec();
1071     if (method.IsPrefixedBy_Ascii_NoCase("aes"))
1072     {
1073       if (Info.Password.Len() > 99)
1074       {
1075         ShowErrorMessageHwndRes(*this, IDS_PASSWORD_TOO_LONG);
1076         return;
1077       }
1078     }
1079   }
1080   if (!IsShowPasswordChecked())
1081   {
1082     UString password2;
1083     _password2Control.GetText(password2);
1084     if (password2 != Info.Password)
1085     {
1086       ShowErrorMessageHwndRes(*this, IDS_PASSWORD_NOT_MATCH);
1087       return;
1088     }
1089   }
1090 
1091   {
1092     UInt64 decompressMem;
1093     const UInt64 memUsage = GetMemoryUsage_DecompMem(decompressMem);
1094     if (memUsage != (UInt64)(Int64)-1)
1095     {
1096       const UInt64 limit = Get_MemUse_Bytes();
1097       if (memUsage > limit)
1098       {
1099         UString s2;
1100         LangString_OnlyFromLangFile(IDS_MEM_REQUIRED_MEM_SIZE, s2);
1101         if (s2.IsEmpty())
1102         {
1103           s2 = LangString(IDT_COMPRESS_MEMORY);
1104           if (s2.IsEmpty())
1105             GetItemText(IDT_COMPRESS_MEMORY, s2);
1106           s2.RemoveChar(L':');
1107         }
1108         UString s;
1109         SetErrorMessage_MemUsage(s, memUsage, _ramSize, limit, s2);
1110         MessageBoxError(s);
1111         return;
1112       }
1113     }
1114   }
1115 
1116   SaveOptionsInMem();
1117 
1118   UStringVector arcPaths;
1119   {
1120     UString s;
1121     if (!GetFinalPath_Smart(s))
1122     {
1123       ShowErrorMessage(*this, k_IncorrectPathMessage);
1124       return;
1125     }
1126     Info.ArcPath = s;
1127     AddUniqueString(arcPaths, s);
1128   }
1129 
1130   Info.UpdateMode = (NCompressDialog::NUpdateMode::EEnum)k_UpdateMode_Vals[m_UpdateMode.GetCurSel()];
1131   Info.PathMode = (NWildcard::ECensorPathMode)k_PathMode_Vals[m_PathMode.GetCurSel()];
1132 
1133   Info.Level = GetLevelSpec();
1134   Info.Dict64 = GetDictSpec();
1135   // Info.Dict64_Chain = GetDictChainSpec();
1136   Info.Order = GetOrderSpec();
1137   Info.OrderMode = GetOrderMode();
1138   Info.NumThreads = GetNumThreadsSpec();
1139 
1140   Info.MemUsage.Clear();
1141   {
1142     const UString mus = Get_MemUse_Spec();
1143     if (!mus.IsEmpty())
1144     {
1145       NCompression::CMemUse mu;
1146       mu.Parse(mus);
1147       if (mu.IsDefined)
1148         Info.MemUsage = mu;
1149     }
1150   }
1151 
1152   {
1153     // Info.SolidIsSpecified = g_Formats[GetStaticFormatIndex()].Solid;
1154     const UInt32 solidLogSize = GetBlockSizeSpec();
1155     Info.SolidBlockSize = 0;
1156     if (solidLogSize == (UInt32)(Int32)-1)
1157       Info.SolidIsSpecified = false;
1158     else if (solidLogSize > 0)
1159       Info.SolidBlockSize = (solidLogSize >= 64) ?
1160           (UInt64)(Int64)-1 :
1161           ((UInt64)1 << solidLogSize);
1162   }
1163 
1164   Info.Method = GetMethodSpec();
1165   Info.EncryptionMethod = GetEncryptionMethodSpec();
1166   Info.FormatIndex = (int)GetFormatIndex();
1167   Info.SFXMode = IsSFX();
1168   Info.OpenShareForWrite = IsButtonCheckedBool(IDX_COMPRESS_SHARED);
1169   Info.DeleteAfterCompressing = IsButtonCheckedBool(IDX_COMPRESS_DEL);
1170 
1171   m_RegistryInfo.EncryptHeaders =
1172     Info.EncryptHeaders = IsButtonCheckedBool(IDX_COMPRESS_ENCRYPT_FILE_NAMES);
1173 
1174 
1175   /* (Info) is for saving to registry:
1176      (CBoolPair::Val) will be set as (false), if it was (false)
1177        in registry at dialog creation, and user didn't click checkbox.
1178      in another case (CBoolPair::Val) will be set as (true) */
1179 
1180   {
1181     /* Info properties could be for another archive types.
1182        so we disable unsupported properties in Info */
1183     // const CArcInfoEx &ai = Get_ArcInfoEx();
1184 
1185     SET_FINAL_BOOL_PAIRS (SymLinks);
1186     SET_FINAL_BOOL_PAIRS (HardLinks);
1187     SET_FINAL_BOOL_PAIRS (AltStreams);
1188     SET_FINAL_BOOL_PAIRS (NtSecurity);
1189 
1190     SET_FINAL_BOOL_PAIRS (PreserveATime);
1191   }
1192 
1193   {
1194     const NCompression::CFormatOptions &fo = Get_FormatOptions();
1195 
1196     Info.TimePrec = fo.TimePrec;
1197     Info.MTime = fo.MTime;
1198     Info.CTime = fo.CTime;
1199     Info.ATime = fo.ATime;
1200     Info.SetArcMTime = fo.SetArcMTime;
1201   }
1202 
1203   m_Params.GetText(Info.Options);
1204 
1205   UString volumeString;
1206   m_Volume.GetText(volumeString);
1207   volumeString.Trim();
1208   Info.VolumeSizes.Clear();
1209 
1210   if (!volumeString.IsEmpty())
1211   {
1212     if (!ParseVolumeSizes(volumeString, Info.VolumeSizes))
1213     {
1214       ShowErrorMessageHwndRes(*this, IDS_INCORRECT_VOLUME_SIZE);
1215       return;
1216     }
1217     if (!Info.VolumeSizes.IsEmpty())
1218     {
1219       const UInt64 volumeSize = Info.VolumeSizes.Back();
1220       if (volumeSize < (100 << 10))
1221       {
1222         wchar_t s[32];
1223         ConvertUInt64ToString(volumeSize, s);
1224         if (::MessageBoxW(*this, MyFormatNew(IDS_SPLIT_CONFIRM, s),
1225             L"7-Zip", MB_YESNOCANCEL | MB_ICONQUESTION) != IDYES)
1226           return;
1227       }
1228     }
1229   }
1230 
1231   if (Info.FormatIndex >= 0)
1232     m_RegistryInfo.ArcType = (*ArcFormats)[Info.FormatIndex].Name;
1233   m_RegistryInfo.ShowPassword = IsShowPasswordChecked();
1234 
1235   FOR_VECTOR (i, m_RegistryInfo.ArcPaths)
1236   {
1237     if (arcPaths.Size() >= kHistorySize)
1238       break;
1239     AddUniqueString(arcPaths, m_RegistryInfo.ArcPaths[i]);
1240   }
1241   m_RegistryInfo.ArcPaths = arcPaths;
1242 
1243   m_RegistryInfo.Save();
1244 
1245   CModalDialog::OnOK();
1246 }
1247 
1248 #define kHelpTopic         "fm/plugins/7-zip/add.htm"
1249 #define kHelpTopic_Options "fm/plugins/7-zip/add.htm#options"
1250 
OnHelp()1251 void CCompressDialog::OnHelp()
1252 {
1253   ShowHelpWindow(kHelpTopic);
1254 }
1255 
1256 
ArcPath_WasChanged(const UString & path)1257 void CCompressDialog::ArcPath_WasChanged(const UString &path)
1258 {
1259   const int dotPos = GetExtDotPos(path);
1260   if (dotPos < 0)
1261     return;
1262   const UString ext = path.Ptr(dotPos + 1);
1263   {
1264     const CArcInfoEx &ai = Get_ArcInfoEx();
1265     if (ai.FindExtension(ext) >= 0)
1266       return;
1267   }
1268 
1269   const unsigned count = (unsigned)m_Format.GetCount();
1270   for (unsigned i = 0; i < count; i++)
1271   {
1272     const CArcInfoEx &ai = (*ArcFormats)[(unsigned)m_Format.GetItemData(i)];
1273     if (ai.FindExtension(ext) >= 0)
1274     {
1275       m_Format.SetCurSel(i);
1276       SaveOptionsInMem();
1277       FormatChanged(true); // isChanged
1278       return;
1279     }
1280   }
1281 }
1282 
1283 
OnMessage(UINT message,WPARAM wParam,LPARAM lParam)1284 bool CCompressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
1285 {
1286   switch (message)
1287   {
1288     case k_Message_ArcChanged:
1289     {
1290       // UString path;
1291       // m_ArchivePath.GetText(path);
1292       const int select = m_ArchivePath.GetCurSel();
1293       if ((unsigned)select < m_RegistryInfo.ArcPaths.Size())
1294       // if (path == m_RegistryInfo.ArcPaths[select])
1295       {
1296         const UString &path = m_RegistryInfo.ArcPaths[select];
1297         SetArcPathFields(path);
1298         // ArcPath_WasChanged(path);
1299       }
1300       return 0;
1301     }
1302   }
1303   return CModalDialog::OnMessage(message, wParam, lParam);
1304 }
1305 
1306 
OnCommand(unsigned code,unsigned itemID,LPARAM lParam)1307 bool CCompressDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam)
1308 {
1309   if (code == CBN_SELCHANGE)
1310   {
1311     switch (itemID)
1312     {
1313       case IDC_COMPRESS_ARCHIVE:
1314       {
1315         /* CBN_SELCHANGE is called before actual value of combo text will be changed.
1316            So GetText() here returns old value (before change) of combo text.
1317            So here we can change all controls except of m_ArchivePath.
1318         */
1319         const int select = m_ArchivePath.GetCurSel();
1320         if ((unsigned)select < m_RegistryInfo.ArcPaths.Size())
1321         {
1322           // DirPrefix.Empty();
1323           // SetItemText(IDT_COMPRESS_ARCHIVE_FOLDER, DirPrefix);
1324           const UString &path = m_RegistryInfo.ArcPaths[select];
1325           // SetArcPathFields(path);
1326           ArcPath_WasChanged(path);
1327           // we use PostMessage(k_Message_ArcChanged) here that later will change m_ArchivePath control
1328           PostMsg(k_Message_ArcChanged);
1329         }
1330         return true;
1331       }
1332 
1333       case IDC_COMPRESS_FORMAT:
1334       {
1335         const bool isSFX = IsSFX();
1336         SaveOptionsInMem();
1337         FormatChanged(true); // isChanged
1338         SetArchiveName2(isSFX);
1339         return true;
1340       }
1341 
1342       case IDC_COMPRESS_LEVEL:
1343       {
1344         Get_FormatOptions().ResetForLevelChange();
1345 
1346         SetMethod(); // call it if level changes method
1347 
1348         // call the following if level change keeps old method
1349         /*
1350         {
1351           // try to keep old method
1352           SetMethod(GetMethodID());
1353           MethodChanged();
1354         }
1355         */
1356 
1357         SetSolidBlockSize();
1358         SetNumThreads();
1359         CheckSFXNameChange();
1360         SetMemoryUsage();
1361         return true;
1362       }
1363 
1364       case IDC_COMPRESS_METHOD:
1365       {
1366         MethodChanged();
1367         SetSolidBlockSize();
1368         SetNumThreads();
1369         CheckSFXNameChange();
1370         SetMemoryUsage();
1371         if (Get_ArcInfoEx().Flags_HashHandler())
1372           SetArchiveName2(false);
1373 
1374         return true;
1375       }
1376 
1377       case IDC_COMPRESS_DICTIONARY:
1378       // case IDC_COMPRESS_DICTIONARY2:
1379       {
1380         /* we want to change the reported threads for Auto line
1381            and keep selected NumThreads option
1382            So we save selected NumThreads option in memory */
1383         SaveOptionsInMem();
1384         const UInt32 blockSizeLog = GetBlockSizeSpec();
1385         if (// blockSizeLog != (UInt32)(Int32)-1 &&
1386                blockSizeLog != kSolidLog_NoSolid
1387             && blockSizeLog != kSolidLog_FullSolid)
1388         {
1389           Get_FormatOptions().Reset_BlockLogSize();
1390           // SetSolidBlockSize(true);
1391         }
1392 
1393         SetDictionary2();
1394         SetSolidBlockSize();
1395         SetNumThreads(); // we want to change the reported threads for Auto line only
1396         SetMemoryUsage();
1397         return true;
1398       }
1399 
1400       case IDC_COMPRESS_ORDER:
1401       {
1402        #ifdef PRINT_PARAMS
1403         Print_Params();
1404        #endif
1405         return true;
1406       }
1407 
1408       case IDC_COMPRESS_SOLID:
1409       {
1410         SetMemoryUsage();
1411         return true;
1412       }
1413 
1414       case IDC_COMPRESS_THREADS:
1415       {
1416         SetMemoryUsage();
1417         return true;
1418       }
1419 
1420       case IDC_COMPRESS_MEM_USE:
1421       {
1422         /* we want to change the reported threads for Auto line
1423            and keep selected NumThreads option
1424            So we save selected NumThreads option in memory */
1425         SaveOptionsInMem();
1426 
1427         SetNumThreads(); // we want to change the reported threads for Auto line only
1428         SetMemoryUsage();
1429         return true;
1430       }
1431     }
1432   }
1433   return CModalDialog::OnCommand(code, itemID, lParam);
1434 }
1435 
CheckSFXNameChange()1436 void CCompressDialog::CheckSFXNameChange()
1437 {
1438   const bool isSFX = IsSFX();
1439   CheckSFXControlsEnable();
1440   if (isSFX != IsSFX())
1441     SetArchiveName2(isSFX);
1442 }
1443 
SetArchiveName2(bool prevWasSFX)1444 void CCompressDialog::SetArchiveName2(bool prevWasSFX)
1445 {
1446   UString fileName;
1447   m_ArchivePath.GetText(fileName);
1448   const CArcInfoEx &prevArchiverInfo = (*ArcFormats)[m_PrevFormat];
1449   if (prevArchiverInfo.Flags_KeepName() || Info.KeepName)
1450   {
1451     UString prevExtension;
1452     if (prevWasSFX)
1453       prevExtension = kExeExt;
1454     else
1455     {
1456       prevExtension.Add_Dot();
1457       prevExtension += prevArchiverInfo.GetMainExt();
1458     }
1459     const unsigned prevExtensionLen = prevExtension.Len();
1460     if (fileName.Len() >= prevExtensionLen)
1461       if (StringsAreEqualNoCase(fileName.RightPtr(prevExtensionLen), prevExtension))
1462         fileName.DeleteFrom(fileName.Len() - prevExtensionLen);
1463   }
1464   SetArchiveName(fileName);
1465 }
1466 
1467 // if type.KeepName then use OriginalFileName
1468 // else if !KeepName remove extension
1469 // add new extension
1470 
SetArchiveName(const UString & name)1471 void CCompressDialog::SetArchiveName(const UString &name)
1472 {
1473   UString fileName = name;
1474   Info.FormatIndex = (int)GetFormatIndex();
1475   const CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex];
1476   m_PrevFormat = Info.FormatIndex;
1477   if (ai.Flags_KeepName())
1478   {
1479     fileName = OriginalFileName;
1480   }
1481   else
1482   {
1483     if (!Info.KeepName)
1484     {
1485       int dotPos = GetExtDotPos(fileName);
1486       if (dotPos >= 0)
1487         fileName.DeleteFrom(dotPos);
1488     }
1489   }
1490 
1491   if (IsSFX())
1492     fileName += kExeExt;
1493   else
1494   {
1495     fileName.Add_Dot();
1496     UString ext = ai.GetMainExt();
1497     if (ai.Flags_HashHandler())
1498     {
1499       UString estimatedName;
1500       GetMethodSpec(estimatedName);
1501       if (!estimatedName.IsEmpty())
1502       {
1503         ext = estimatedName;
1504         ext.MakeLower_Ascii();
1505       }
1506     }
1507     fileName += ext;
1508   }
1509   m_ArchivePath.SetText(fileName);
1510 }
1511 
1512 
FindRegistryFormat(const UString & name)1513 int CCompressDialog::FindRegistryFormat(const UString &name)
1514 {
1515   FOR_VECTOR (i, m_RegistryInfo.Formats)
1516   {
1517     const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[i];
1518     if (name.IsEqualTo_NoCase(GetUnicodeString(fo.FormatID)))
1519       return (int)i;
1520   }
1521   return -1;
1522 }
1523 
1524 
FindRegistryFormat_Always(const UString & name)1525 unsigned CCompressDialog::FindRegistryFormat_Always(const UString &name)
1526 {
1527   const int index = FindRegistryFormat(name);
1528   if (index >= 0)
1529     return (unsigned)index;
1530   {
1531     NCompression::CFormatOptions fo;
1532     fo.FormatID = GetSystemString(name);
1533     return m_RegistryInfo.Formats.Add(fo);
1534   }
1535 }
1536 
1537 
Get_FormatOptions()1538 NCompression::CFormatOptions &CCompressDialog::Get_FormatOptions()
1539 {
1540   const CArcInfoEx &ai = Get_ArcInfoEx();
1541   return m_RegistryInfo.Formats[FindRegistryFormat_Always(ai.Name)];
1542 }
1543 
1544 
GetStaticFormatIndex()1545 unsigned CCompressDialog::GetStaticFormatIndex()
1546 {
1547   const CArcInfoEx &ai = Get_ArcInfoEx();
1548   for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Formats); i++)
1549     if (ai.Name.IsEqualTo_Ascii_NoCase(g_Formats[i].Name))
1550       return i;
1551   return 0; // -1;
1552 }
1553 
SetNearestSelectComboBox(NControl::CComboBox & comboBox,UInt32 value)1554 void CCompressDialog::SetNearestSelectComboBox(NControl::CComboBox &comboBox, UInt32 value)
1555 {
1556   for (int i = comboBox.GetCount() - 1; i >= 0; i--)
1557     if ((UInt32)comboBox.GetItemData(i) <= value)
1558     {
1559       comboBox.SetCurSel(i);
1560       return;
1561     }
1562   if (comboBox.GetCount() > 0)
1563     comboBox.SetCurSel(0);
1564 }
1565 
SetLevel2()1566 void CCompressDialog::SetLevel2()
1567 {
1568   m_Level.ResetContent();
1569   const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
1570   const CArcInfoEx &ai = Get_ArcInfoEx();
1571   UInt32 level = 5;
1572   {
1573     int index = FindRegistryFormat(ai.Name);
1574     if (index >= 0)
1575     {
1576       const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
1577       if (fo.Level <= 9)
1578         level = fo.Level;
1579       else if (fo.Level == (UInt32)(Int32)-1)
1580         level = 5;
1581       else
1582         level = 9;
1583     }
1584   }
1585 
1586   const bool isZstd = ai.Is_Zstd();
1587 
1588   for (unsigned i = 0; i < sizeof(UInt32) * 8; i++)
1589   {
1590     const UInt32 mask = fi.LevelsMask >> i;
1591     // if (mask == 0) break;
1592     if (mask & 1)
1593     {
1594       UString s;
1595       s.Add_UInt32(i);
1596       if (i < Z7_ARRAY_SIZE(g_Levels))
1597       {
1598         const UInt32 langID = g_Levels[i];
1599         // if (fi.LevelsMask < (1 << (MY_ZSTD_LEVEL_MAX + 1)) - 1)
1600         if (langID)
1601           if (i != 0 || !isZstd)
1602           {
1603             s += " - ";
1604             AddLangString(s, langID);
1605           }
1606       }
1607       const int index = (int)m_Level.AddString(s);
1608       m_Level.SetItemData(index, (LPARAM)i);
1609     }
1610   }
1611   SetNearestSelectComboBox(m_Level, level);
1612 }
1613 
1614 
ComboBox_AddStringAscii(NControl::CComboBox & cb,const char * s)1615 static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s)
1616 {
1617   return cb.AddString((CSysString)s);
1618 }
1619 
1620 static const char *k_Auto_Prefix = "*  ";
1621 
Modify_Auto(AString & s)1622 static void Modify_Auto(AString &s)
1623 {
1624   s.Insert(0, k_Auto_Prefix);
1625 }
1626 
SetMethod2(int keepMethodId)1627 void CCompressDialog::SetMethod2(int keepMethodId)
1628 {
1629   m_Method.ResetContent();
1630   _auto_MethodId = -1;
1631   const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
1632   const CArcInfoEx &ai = Get_ArcInfoEx();
1633   if (GetLevel() == 0 && !ai.Flags_HashHandler())
1634   {
1635     if (!ai.Is_Tar() &&
1636         !ai.Is_Zstd())
1637     {
1638       MethodChanged();
1639       return;
1640     }
1641   }
1642   UString defaultMethod;
1643   {
1644     const int index = FindRegistryFormat(ai.Name);
1645     if (index >= 0)
1646     {
1647       const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
1648       defaultMethod = fo.Method;
1649     }
1650   }
1651   const bool isSfx = IsSFX();
1652   bool weUseSameMethod = false;
1653 
1654   const bool is7z = ai.Is_7z();
1655 
1656   for (unsigned m = 0;; m++)
1657   {
1658     int methodID;
1659     const char *method;
1660     if (m < fi.NumMethods)
1661     {
1662       methodID = fi.MethodIDs[m];
1663       method = kMethodsNames[methodID];
1664       if (is7z)
1665       if (methodID == kCopy
1666           || methodID == kDeflate
1667           || methodID == kDeflate64
1668           )
1669         continue;
1670     }
1671     else
1672     {
1673       if (!is7z)
1674         break;
1675       const unsigned extIndex = m - fi.NumMethods;
1676       if (extIndex >= ExternalMethods.Size())
1677         break;
1678       methodID = (int)(Z7_ARRAY_SIZE(kMethodsNames) + extIndex);
1679       method = ExternalMethods[extIndex].Ptr();
1680     }
1681     if (isSfx)
1682       if (!IsMethodSupportedBySfx(methodID))
1683         continue;
1684 
1685     AString s (method);
1686     int writtenMethodId = methodID;
1687     if (m == 0)
1688     {
1689       _auto_MethodId = methodID;
1690       writtenMethodId = -1;
1691       Modify_Auto(s);
1692     }
1693     const int itemIndex = (int)ComboBox_AddStringAscii(m_Method, s);
1694     m_Method.SetItemData(itemIndex, writtenMethodId);
1695     if (keepMethodId == methodID)
1696     {
1697       m_Method.SetCurSel(itemIndex);
1698       weUseSameMethod = true;
1699       continue;
1700     }
1701     if ((defaultMethod.IsEqualTo_Ascii_NoCase(method) || m == 0) && !weUseSameMethod)
1702       m_Method.SetCurSel(itemIndex);
1703   }
1704 
1705   if (!weUseSameMethod)
1706     MethodChanged();
1707 }
1708 
1709 
1710 
IsZipFormat()1711 bool CCompressDialog::IsZipFormat()
1712 {
1713   return Get_ArcInfoEx().Is_Zip();
1714 }
1715 
IsXzFormat()1716 bool CCompressDialog::IsXzFormat()
1717 {
1718   return Get_ArcInfoEx().Is_Xz();
1719 }
1720 
SetEncryptionMethod()1721 void CCompressDialog::SetEncryptionMethod()
1722 {
1723   _encryptionMethod.ResetContent();
1724   _default_encryptionMethod_Index = -1;
1725   const CArcInfoEx &ai = Get_ArcInfoEx();
1726   if (ai.Is_7z())
1727   {
1728     ComboBox_AddStringAscii(_encryptionMethod, "AES-256");
1729     _encryptionMethod.SetCurSel(0);
1730     _default_encryptionMethod_Index = 0;
1731   }
1732   else if (ai.Is_Zip())
1733   {
1734     int index = FindRegistryFormat(ai.Name);
1735     UString encryptionMethod;
1736     if (index >= 0)
1737     {
1738       const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
1739       encryptionMethod = fo.EncryptionMethod;
1740     }
1741     int sel = 0;
1742     // if (ZipCryptoIsAllowed)
1743     {
1744       ComboBox_AddStringAscii(_encryptionMethod, "ZipCrypto");
1745       sel = (encryptionMethod.IsPrefixedBy_Ascii_NoCase("aes") ? 1 : 0);
1746       _default_encryptionMethod_Index = 0;
1747     }
1748     ComboBox_AddStringAscii(_encryptionMethod, "AES-256");
1749     _encryptionMethod.SetCurSel(sel);
1750   }
1751 }
1752 
1753 
GetMethodID_RAW()1754 int CCompressDialog::GetMethodID_RAW()
1755 {
1756   if (m_Method.GetCount() <= 0)
1757     return -1;
1758   return (int)(Int32)(UInt32)m_Method.GetItemData_of_CurSel();
1759 }
1760 
GetMethodID()1761 int CCompressDialog::GetMethodID()
1762 {
1763   int raw = GetMethodID_RAW();
1764   if (raw < 0)
1765     return _auto_MethodId;
1766   return raw;
1767 }
1768 
1769 
GetMethodSpec(UString & estimatedName)1770 UString CCompressDialog::GetMethodSpec(UString &estimatedName)
1771 {
1772   estimatedName.Empty();
1773   if (m_Method.GetCount() < 1)
1774     return estimatedName;
1775   const int methodIdRaw = GetMethodID_RAW();
1776   int methodId = methodIdRaw;
1777   if (methodIdRaw < 0)
1778     methodId = _auto_MethodId;
1779   UString s;
1780   if (methodId >= 0)
1781   {
1782     if ((unsigned)methodId < Z7_ARRAY_SIZE(kMethodsNames))
1783       estimatedName = kMethodsNames[methodId];
1784     else
1785       estimatedName = ExternalMethods[(unsigned)methodId - (unsigned)Z7_ARRAY_SIZE(kMethodsNames)];
1786     if (methodIdRaw >= 0)
1787       s = estimatedName;
1788   }
1789   return s;
1790 }
1791 
1792 
GetMethodSpec()1793 UString CCompressDialog::GetMethodSpec()
1794 {
1795   UString estimatedName;
1796   UString s = GetMethodSpec(estimatedName);
1797   return s;
1798 }
1799 
IsMethodEqualTo(const UString & s)1800 bool CCompressDialog::IsMethodEqualTo(const UString &s)
1801 {
1802   UString estimatedName;
1803   const UString shortName = GetMethodSpec(estimatedName);
1804   if (s.IsEmpty())
1805     return shortName.IsEmpty();
1806   return s.IsEqualTo_NoCase(estimatedName);
1807 }
1808 
1809 
GetEncryptionMethodSpec()1810 UString CCompressDialog::GetEncryptionMethodSpec()
1811 {
1812   UString s;
1813   if (_encryptionMethod.GetCount() > 0
1814       && _encryptionMethod.GetCurSel() != _default_encryptionMethod_Index)
1815   {
1816     _encryptionMethod.GetText(s);
1817     s.RemoveChar(L'-');
1818   }
1819   return s;
1820 }
1821 
1822 
1823 static const size_t k_Auto_Dict = (size_t)0 - 1;
1824 
Combo_AddDict2(NWindows::NControl::CComboBox & cb,size_t sizeReal,size_t sizeShow)1825 static int Combo_AddDict2(NWindows::NControl::CComboBox &cb, size_t sizeReal, size_t sizeShow)
1826 {
1827   char c = 0;
1828   unsigned moveBits = 0;
1829        if ((sizeShow & 0xFFFFF) == 0) { moveBits = 20; c = 'M'; }
1830   else if ((sizeShow &   0x3FF) == 0) { moveBits = 10; c = 'K'; }
1831   AString s;
1832   s.Add_UInt64(sizeShow >> moveBits);
1833   s.Add_Space();
1834   if (c != 0)
1835     s.Add_Char(c);
1836   s.Add_Char('B');
1837   if (sizeReal == k_Auto_Dict)
1838     Modify_Auto(s);
1839   const int index = (int)ComboBox_AddStringAscii(cb, s);
1840   cb.SetItemData(index, (LPARAM)sizeReal);
1841   return index;
1842 }
1843 
AddDict2(size_t sizeReal,size_t sizeShow)1844 int CCompressDialog::AddDict2(size_t sizeReal, size_t sizeShow)
1845 {
1846   return Combo_AddDict2(m_Dictionary, sizeReal, sizeShow);
1847 }
1848 
AddDict(size_t size)1849 int CCompressDialog::AddDict(size_t size)
1850 {
1851   return AddDict2(size, size);
1852 }
1853 
1854 /*
1855 int CCompressDialog::AddDict_Chain(size_t size)
1856 {
1857   return Combo_AddDict2(m_Dictionary_Chain, size, size);
1858 }
1859 */
1860 
SetDictionary2()1861 void CCompressDialog::SetDictionary2()
1862 {
1863   m_Dictionary.ResetContent();
1864   // m_Dictionary_Chain.ResetContent();
1865 
1866   // _auto_Dict = (UInt32)1 << 24; // we can use this dictSize to calculate _auto_Solid for unknown method for 7z
1867   _auto_Dict = (UInt32)(Int32)-1; // for debug
1868   // _auto_Dict_Chain = (UInt32)(Int32)-1; // for debug
1869 
1870   const CArcInfoEx &ai = Get_ArcInfoEx();
1871   UInt32 defaultDict = (UInt32)(Int32)-1;
1872   // UInt32 defaultDict_Chain = (UInt32)(Int32)-1;
1873   {
1874     const int index = FindRegistryFormat(ai.Name);
1875     if (index >= 0)
1876     {
1877       const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
1878       if (IsMethodEqualTo(fo.Method))
1879       {
1880         defaultDict = fo.Dictionary;
1881         // defaultDict_Chain = fo.DictionaryChain;
1882       }
1883     }
1884   }
1885 
1886   const int methodID = GetMethodID();
1887   const UInt32 level = GetLevel2();
1888 
1889   {
1890     RECT r, rLabel;
1891     GetClientRectOfItem(IDT_COMPRESS_DICTIONARY, rLabel);
1892     GetClientRectOfItem(IDC_COMPRESS_DICTIONARY, r);
1893     if (_dictionaryCombo_left == 0)
1894       _dictionaryCombo_left = r.left;
1895 
1896     // bool showDict2;
1897     int newLableRight;
1898     int newDictLeft;
1899 
1900     /*
1901     if (methodID == kZSTD)
1902     {
1903       showDict2 = true;
1904       newDictLeft = _dictionaryCombo_left;
1905       RECT r2;
1906       GetClientRectOfItem(IDC_COMPRESS_DICTIONARY2, r2);
1907       newLableRight = r2.left;
1908     }
1909     else
1910     */
1911     {
1912       // showDict2 = false;
1913       RECT rBig;
1914       GetClientRectOfItem(IDC_COMPRESS_METHOD, rBig);
1915       newDictLeft= rBig.left;
1916       newLableRight = newDictLeft;
1917     }
1918 
1919     if (newLableRight != rLabel.right)
1920     {
1921       rLabel.right = newLableRight;
1922       MoveItem_RECT(IDT_COMPRESS_DICTIONARY, rLabel);
1923       InvalidateRect(&rLabel);
1924     }
1925     if (newDictLeft != r.left)
1926     {
1927       r.left = newDictLeft;
1928       MoveItem_RECT(IDC_COMPRESS_DICTIONARY, r);
1929       // InvalidateRect(&r);
1930     }
1931     // ShowItem_Bool(IDC_COMPRESS_DICTIONARY2, showDict2);
1932   }
1933 
1934   if (methodID < 0)
1935     return;
1936 
1937   switch (methodID)
1938   {
1939     case kLZMA:
1940     case kLZMA2:
1941     {
1942       {
1943         _auto_Dict = level <= 4 ?
1944             (UInt32)1 << (level * 2 + 16) :
1945             level <= sizeof(size_t) / 2 + 4 ?
1946               (UInt32)1 << (level + 20) :
1947               (UInt32)1 << (sizeof(size_t) / 2 + 24);
1948       }
1949 
1950       // we use threshold 3.75 GiB to switch to kLzmaMaxDictSize.
1951       if (defaultDict != (UInt32)(Int32)-1
1952           && defaultDict >= ((UInt32)15 << 28))
1953         defaultDict = kLzmaMaxDictSize;
1954 
1955       const size_t kLzmaMaxDictSize_Up = (size_t)1 << (20 + sizeof(size_t) / 4 * 6);
1956 
1957       int curSel = AddDict2(k_Auto_Dict, _auto_Dict);
1958 
1959       for (unsigned i = (16 - 1) * 2; i <= (32 - 1) * 2; i++)
1960       {
1961         if (i < (20 - 1) * 2
1962             && i != (16 - 1) * 2
1963             && i != (18 - 1) * 2)
1964           continue;
1965         if (i == (20 - 1) * 2 + 1)
1966           continue;
1967         const size_t dict_up = (size_t)(2 + (i & 1)) << (i / 2);
1968         size_t dict = dict_up;
1969         if (dict_up >= kLzmaMaxDictSize)
1970           dict = kLzmaMaxDictSize; // we reduce dictionary
1971 
1972         const int index = AddDict(dict);
1973         // AddDict2(dict, dict_up); // for debug : we show 4 GB
1974 
1975         // const UInt32 numThreads = 2;
1976         // const UInt64 memUsage = GetMemoryUsageComp_Threads_Dict(numThreads, dict);
1977         if (defaultDict != (UInt32)(Int32)-1)
1978           if (dict <= defaultDict || curSel <= 0)
1979           // if (!maxRamSize_Defined || memUsage <= maxRamSize)
1980             curSel = index;
1981         if (dict_up >= kLzmaMaxDictSize_Up)
1982           break;
1983       }
1984 
1985       m_Dictionary.SetCurSel(curSel);
1986       break;
1987     }
1988 
1989     /*
1990     case kZSTD:
1991     {
1992       if (defaultDict != (UInt32)(Int32)-1 &&
1993           defaultDict > kZstd_MAX_DictSize)
1994         defaultDict = kZstd_MAX_DictSize;
1995 
1996       if (defaultDict_Chain != (UInt32)(Int32)-1 &&
1997           defaultDict_Chain > kZstd_MAX_DictSize_Chain)
1998         defaultDict_Chain = kZstd_MAX_DictSize_Chain;
1999 
2000       {
2001         CZstdEncProps props;
2002         ZstdEncProps_Init(&props);
2003         // props.level_zstd = level;
2004         props.level_7z = level;
2005         ZstdEncProps_Set_WindowSize(&props, defaultDict != (UInt32)(Int32)-1 ? defaultDict: 0);
2006         ZstdEncProps_NormalizeFull(&props);
2007         _auto_Dict_Chain = (UInt32)1 << props.windowLog_Chain;
2008       }
2009       {
2010         CZstdEncProps props;
2011         ZstdEncProps_Init(&props);
2012         // props.level_zstd = level;
2013         props.level_7z = level;
2014         ZstdEncProps_Set_WindowChainSize(&props, defaultDict_Chain != (UInt32)(Int32)-1 ? defaultDict_Chain: 0);
2015         ZstdEncProps_NormalizeFull(&props);
2016         _auto_Dict = (UInt32)1 << props.windowLog;
2017       }
2018 
2019       // if there is collision of two window sizes, we reduce dict_Chain
2020       if (defaultDict != (UInt32)(Int32)-1 &&
2021           defaultDict_Chain != (UInt32)(Int32)-1 &&
2022           defaultDict < defaultDict_Chain)
2023         defaultDict_Chain = defaultDict;
2024 
2025       {
2026         int curSel = AddDict2(k_Auto_Dict, _auto_Dict);
2027 
2028         // defaultDict = 12 << 10; // for debug
2029         const UInt32 kWinStart = 18;
2030         if (defaultDict != 0 && defaultDict < ((UInt32)1 << kWinStart))
2031           curSel = AddDict(defaultDict);
2032 
2033         for (unsigned i = kWinStart; i <= MY_ZSTD_WINDOWLOG_MAX; i++)
2034         {
2035           const size_t dict = (size_t)1 << i;
2036           const int index = AddDict(dict);
2037           if (defaultDict != (UInt32)(Int32)-1)
2038             if (dict <= defaultDict || curSel <= 0)
2039               curSel = index;
2040         }
2041         m_Dictionary.SetCurSel(curSel);
2042       }
2043 
2044       {
2045         int curSel = Combo_AddDict2(m_Dictionary_Chain, k_Auto_Dict, _auto_Dict_Chain);
2046 
2047         // defaultDict_Chain = 10 << 10; // for debug
2048         const UInt32 kWinChainStart = 15;
2049         if (defaultDict_Chain != 0 && defaultDict_Chain < ((UInt32)1 << kWinChainStart))
2050           curSel = AddDict_Chain(defaultDict_Chain);
2051 
2052         for (unsigned i = kWinChainStart; i <= kMaxDictChain; i++)
2053         {
2054           const size_t dict = (size_t)1 << i;
2055           if (defaultDict != (UInt32)(Int32)-1 && dict > defaultDict)
2056             break;
2057           const int index = AddDict_Chain(dict);
2058           if (defaultDict_Chain != (UInt32)(Int32)-1)
2059             if (dict <= defaultDict_Chain || curSel <= 0)
2060               curSel = index;
2061         }
2062         m_Dictionary_Chain.SetCurSel(curSel);
2063       }
2064 
2065       break;
2066     }
2067     */
2068 
2069     case kPPMd:
2070     {
2071       _auto_Dict = (UInt32)1 << (level + 19);
2072 
2073       const UInt32 kPpmd_Default_4g = (UInt32)0 - ((UInt32)1 << 10);
2074       const size_t kPpmd_MaxDictSize_Up = (size_t)1 << (29 + sizeof(size_t) / 8);
2075 
2076       if (defaultDict != (UInt32)(Int32)-1
2077           && defaultDict >= ((UInt32)15 << 28)) // threshold
2078         defaultDict = kPpmd_Default_4g;
2079 
2080       int curSel = AddDict2(k_Auto_Dict, _auto_Dict);
2081 
2082       for (unsigned i = (20 - 1) * 2; i <= (32 - 1) * 2; i++)
2083       {
2084         if (i == (20 - 1) * 2 + 1)
2085           continue;
2086 
2087         const size_t dict_up = (size_t)(2 + (i & 1)) << (i / 2);
2088         size_t dict = dict_up;
2089         if (dict_up >= kPpmd_Default_4g)
2090           dict = kPpmd_Default_4g;
2091 
2092         const int index = AddDict2(dict, dict_up);
2093         // AddDict2((UInt32)((UInt32)0 - 2), dict_up); // for debug
2094         // AddDict(dict_up); // for debug
2095         // const UInt64 memUsage = GetMemoryUsageComp_Threads_Dict(1, dict);
2096         if (defaultDict != (UInt32)(Int32)-1)
2097           if (dict <= defaultDict || curSel <= 0)
2098             // if (!maxRamSize_Defined || memUsage <= maxRamSize)
2099             curSel = index;
2100         if (dict_up >= kPpmd_MaxDictSize_Up)
2101           break;
2102       }
2103       m_Dictionary.SetCurSel(curSel);
2104       break;
2105     }
2106 
2107     case kPPMdZip:
2108     {
2109       _auto_Dict = (UInt32)1 << (level + 19);
2110 
2111       int curSel = AddDict2(k_Auto_Dict, _auto_Dict);
2112 
2113       for (unsigned i = 20; i <= 28; i++)
2114       {
2115         const UInt32 dict = (UInt32)1 << i;
2116         const int index = AddDict(dict);
2117         // const UInt64 memUsage = GetMemoryUsageComp_Threads_Dict(1, dict);
2118         if (defaultDict != (UInt32)(Int32)-1)
2119           if (dict <= defaultDict || curSel <= 0)
2120             // if (!maxRamSize_Defined || memUsage <= maxRamSize)
2121             curSel = index;
2122       }
2123       m_Dictionary.SetCurSel(curSel);
2124       break;
2125     }
2126 
2127     case kDeflate:
2128     case kDeflate64:
2129     {
2130       const UInt32 dict = (methodID == kDeflate ? (UInt32)(1 << 15) : (UInt32)(1 << 16));
2131       _auto_Dict = dict;
2132       AddDict2(k_Auto_Dict, _auto_Dict);
2133       m_Dictionary.SetCurSel(0);
2134       // EnableItem(IDC_COMPRESS_DICTIONARY, false);
2135       break;
2136     }
2137 
2138     case kBZip2:
2139     {
2140       {
2141              if (level >= 5) _auto_Dict = (900 << 10);
2142         else if (level >= 3) _auto_Dict = (500 << 10);
2143         else                 _auto_Dict = (100 << 10);
2144       }
2145 
2146       int curSel = AddDict2(k_Auto_Dict, _auto_Dict);
2147 
2148       for (unsigned i = 1; i <= 9; i++)
2149       {
2150         const UInt32 dict = ((UInt32)i * 100) << 10;
2151         AddDict(dict);
2152         // AddDict2(i * 100000, dict);
2153         if (defaultDict != (UInt32)(Int32)-1)
2154           if (i <= defaultDict / 100000 || curSel <= 0)
2155             curSel = m_Dictionary.GetCount() - 1;
2156       }
2157       m_Dictionary.SetCurSel(curSel);
2158       break;
2159     }
2160 
2161     case kCopy:
2162     {
2163       _auto_Dict = 0;
2164       AddDict(0);
2165       m_Dictionary.SetCurSel(0);
2166       break;
2167     }
2168   }
2169 }
2170 
2171 
GetComboValue(NWindows::NControl::CComboBox & c,int defMax)2172 UInt32 CCompressDialog::GetComboValue(NWindows::NControl::CComboBox &c, int defMax)
2173 {
2174   if (c.GetCount() <= defMax)
2175     return (UInt32)(Int32)-1;
2176   return (UInt32)c.GetItemData_of_CurSel();
2177 }
2178 
2179 
GetComboValue_64(NWindows::NControl::CComboBox & c,int defMax)2180 UInt64 CCompressDialog::GetComboValue_64(NWindows::NControl::CComboBox &c, int defMax)
2181 {
2182   if (c.GetCount() <= defMax)
2183     return (UInt64)(Int64)-1;
2184   // LRESULT is signed. so we cast it to unsigned size_t at first:
2185   LRESULT val = c.GetItemData_of_CurSel();
2186   if (val == (LPARAM)(INT_PTR)(-1))
2187     return (UInt64)(Int64)-1;
2188   return (UInt64)(size_t)c.GetItemData_of_CurSel();
2189 }
2190 
GetLevel2()2191 UInt32 CCompressDialog::GetLevel2()
2192 {
2193   UInt32 level = GetLevel();
2194   if (level == (UInt32)(Int32)-1)
2195     level = 5;
2196   return level;
2197 }
2198 
2199 
AddOrder(UInt32 size)2200 int CCompressDialog::AddOrder(UInt32 size)
2201 {
2202   char s[32];
2203   ConvertUInt32ToString(size, s);
2204   const int index = (int)ComboBox_AddStringAscii(m_Order, s);
2205   m_Order.SetItemData(index, (LPARAM)size);
2206   return index;
2207 }
2208 
AddOrder_Auto()2209 int CCompressDialog::AddOrder_Auto()
2210 {
2211   AString s;
2212   s.Add_UInt32(_auto_Order);
2213   Modify_Auto(s);
2214   int index = (int)ComboBox_AddStringAscii(m_Order, s);
2215   m_Order.SetItemData(index, (LPARAM)(INT_PTR)(-1));
2216   return index;
2217 }
2218 
SetOrder2()2219 void CCompressDialog::SetOrder2()
2220 {
2221   m_Order.ResetContent();
2222 
2223   _auto_Order = 1;
2224 
2225   const CArcInfoEx &ai = Get_ArcInfoEx();
2226   UInt32 defaultOrder = (UInt32)(Int32)-1;
2227 
2228   {
2229     const int index = FindRegistryFormat(ai.Name);
2230     if (index >= 0)
2231     {
2232       const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
2233       if (IsMethodEqualTo(fo.Method))
2234         defaultOrder = fo.Order;
2235     }
2236   }
2237 
2238   const int methodID = GetMethodID();
2239   const UInt32 level = GetLevel2();
2240   if (methodID < 0)
2241     return;
2242 
2243   switch (methodID)
2244   {
2245     case kLZMA:
2246     case kLZMA2:
2247     {
2248       _auto_Order = (level < 7 ? 32 : 64);
2249       int curSel = AddOrder_Auto();
2250       for (unsigned i = 2 * 2; i < 8 * 2; i++)
2251       {
2252         UInt32 order = ((UInt32)(2 + (i & 1)) << (i / 2));
2253         if (order > 256)
2254           order = 273;
2255         const int index = AddOrder(order);
2256         if (defaultOrder != (UInt32)(Int32)-1)
2257           if (order <= defaultOrder || curSel <= 0)
2258             curSel = index;
2259       }
2260       m_Order.SetCurSel(curSel);
2261       break;
2262     }
2263 
2264     /*
2265     case kZSTD:
2266     {
2267       {
2268         CZstdEncProps props;
2269         ZstdEncProps_Init(&props);
2270         // props.level_zstd = level;
2271         props.level_7z = level;
2272         ZstdEncProps_NormalizeFull(&props);
2273         _auto_Order = props.targetLength;
2274         if (props.strategy < ZSTD_strategy_btopt)
2275         {
2276           // ZSTD_strategy_fast uses targetLength to change fast level.
2277           // targetLength probably is used only in ZSTD_strategy_btopt and higher
2278           break;
2279         }
2280       }
2281       int curSel = AddOrder_Auto();
2282 
2283       for (unsigned i = 6; i <= 9 * 2; i++)
2284       {
2285         UInt32 order = ((UInt32)(2 + (i & 1)) << (i / 2));
2286         // if (order > 999) order = 999;
2287         const int index = AddOrder(order);
2288         if (defaultOrder != (UInt32)(Int32)-1)
2289           if (order <= defaultOrder || curSel <= 0)
2290             curSel = index;
2291       }
2292       m_Order.SetCurSel(curSel);
2293       break;
2294     }
2295     */
2296 
2297     case kDeflate:
2298     case kDeflate64:
2299     {
2300       {
2301              if (level >= 9) _auto_Order = 128;
2302         else if (level >= 7) _auto_Order = 64;
2303         else                 _auto_Order = 32;
2304       }
2305       int curSel = AddOrder_Auto();
2306       for (unsigned i = 2 * 2; i < 8 * 2; i++)
2307       {
2308         UInt32 order = ((UInt32)(2 + (i & 1)) << (i / 2));
2309         if (order > 256)
2310           order = (methodID == kDeflate64 ? 257 : 258);
2311         const int index = AddOrder(order);
2312         if (defaultOrder != (UInt32)(Int32)-1)
2313           if (order <= defaultOrder || curSel <= 0)
2314             curSel = index;
2315       }
2316 
2317       m_Order.SetCurSel(curSel);
2318       break;
2319     }
2320 
2321     case kPPMd:
2322     {
2323       {
2324              if (level >= 9) _auto_Order = 32;
2325         else if (level >= 7) _auto_Order = 16;
2326         else if (level >= 5) _auto_Order = 6;
2327         else                 _auto_Order = 4;
2328       }
2329 
2330       int curSel = AddOrder_Auto();
2331 
2332       for (unsigned i = 0;; i++)
2333       {
2334         UInt32 order = i + 2;
2335         if (i >= 2)
2336           order = (4 + ((i - 2) & 3)) << ((i - 2) / 4);
2337         const int index = AddOrder(order);
2338         if (defaultOrder != (UInt32)(Int32)-1)
2339           if (order <= defaultOrder || curSel <= 0)
2340             curSel = index;
2341         if (order >= 32)
2342           break;
2343       }
2344       m_Order.SetCurSel(curSel);
2345       break;
2346     }
2347 
2348     case kPPMdZip:
2349     {
2350       _auto_Order = level + 3;
2351       int curSel = AddOrder_Auto();
2352       for (unsigned i = 2; i <= 16; i++)
2353       {
2354         const int index = AddOrder(i);
2355         if (defaultOrder != (UInt32)(Int32)-1)
2356           if (i <= defaultOrder || curSel <= 0)
2357             curSel = index;
2358       }
2359       m_Order.SetCurSel(curSel);
2360       break;
2361     }
2362 
2363     // case kBZip2:
2364     default:
2365       break;
2366   }
2367 }
2368 
GetOrderMode()2369 bool CCompressDialog::GetOrderMode()
2370 {
2371   switch (GetMethodID())
2372   {
2373     case kPPMd:
2374     case kPPMdZip:
2375       return true;
2376   }
2377   return false;
2378 }
2379 
2380 
Get_Lzma2_ChunkSize(UInt64 dict)2381 static UInt64 Get_Lzma2_ChunkSize(UInt64 dict)
2382 {
2383   // we use same default chunk sizes as defined in 7z encoder and lzma2 encoder
2384   UInt64 cs = (UInt64)dict << 2;
2385   const UInt32 kMinSize = (UInt32)1 << 20;
2386   const UInt32 kMaxSize = (UInt32)1 << 28;
2387   if (cs < kMinSize) cs = kMinSize;
2388   if (cs > kMaxSize) cs = kMaxSize;
2389   if (cs < dict) cs = dict;
2390   cs += (kMinSize - 1);
2391   cs &= ~(UInt64)(kMinSize - 1);
2392   return cs;
2393 }
2394 
2395 
Add_Size(AString & s,UInt64 val)2396 static void Add_Size(AString &s, UInt64 val)
2397 {
2398   unsigned moveBits = 0;
2399   char c = 0;
2400        if ((val & 0x3FFFFFFF) == 0) { moveBits = 30; c = 'G'; }
2401   else if ((val &    0xFFFFF) == 0) { moveBits = 20; c = 'M'; }
2402   else if ((val &      0x3FF) == 0) { moveBits = 10; c = 'K'; }
2403   s.Add_UInt64(val >> moveBits);
2404   s.Add_Space();
2405   if (moveBits != 0)
2406     s.Add_Char(c);
2407   s.Add_Char('B');
2408 }
2409 
2410 
SetSolidBlockSize2()2411 void CCompressDialog::SetSolidBlockSize2()
2412 {
2413   m_Solid.ResetContent();
2414   _auto_Solid = 1 << 20;
2415 
2416   const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
2417   if (!fi.Solid_())
2418     return;
2419 
2420   const UInt32 level = GetLevel2();
2421   if (level == 0)
2422     return;
2423 
2424   UInt64 dict = GetDict2();
2425   if (dict == (UInt64)(Int64)-1)
2426   {
2427     dict = 1 << 25; // default dict for unknown methods
2428     // return;
2429   }
2430 
2431 
2432   UInt32 defaultBlockSize = (UInt32)(Int32)-1;
2433 
2434   const CArcInfoEx &ai = Get_ArcInfoEx();
2435 
2436   /*
2437   if (usePrevDictionary)
2438     defaultBlockSize = GetBlockSizeSpec();
2439   else
2440   */
2441   {
2442     const int index = FindRegistryFormat(ai.Name);
2443     if (index >= 0)
2444     {
2445       const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
2446       if (IsMethodEqualTo(fo.Method))
2447         defaultBlockSize = fo.BlockLogSize;
2448     }
2449   }
2450 
2451   const bool is7z = ai.Is_7z();
2452 
2453   const UInt64 cs = Get_Lzma2_ChunkSize(dict);
2454 
2455   // Solid Block Size
2456   UInt64 blockSize = cs; // for xz
2457 
2458   if (is7z)
2459   {
2460     // we use same default block sizes as defined in 7z encoder
2461     UInt64 kMaxSize = (UInt64)1 << 32;
2462     const int methodId = GetMethodID();
2463     if (methodId == kLZMA2)
2464     {
2465       blockSize = cs << 6;
2466       kMaxSize = (UInt64)1 << 34;
2467     }
2468     else
2469     {
2470       UInt64 dict2 = dict;
2471       if (methodId == kBZip2)
2472       {
2473         dict2 /= 100000;
2474         if (dict2 < 1)
2475           dict2 = 1;
2476         dict2 *= 100000;
2477       }
2478       blockSize = dict2 << 7;
2479     }
2480 
2481     const UInt32 kMinSize = (UInt32)1 << 24;
2482     if (blockSize < kMinSize) blockSize = kMinSize;
2483     if (blockSize > kMaxSize) blockSize = kMaxSize;
2484   }
2485 
2486   _auto_Solid = blockSize;
2487 
2488   int curSel;
2489   {
2490     AString s;
2491     Add_Size(s, _auto_Solid);
2492     Modify_Auto(s);
2493     const int index = (int)ComboBox_AddStringAscii(m_Solid, s);
2494     m_Solid.SetItemData(index, (LPARAM)(UInt32)(Int32)-1);
2495     curSel = index;
2496   }
2497 
2498   if (is7z)
2499   {
2500     UString s ('-');
2501     // kSolidLog_NoSolid = 0 for xz means default blockSize
2502     if (is7z)
2503       LangString(IDS_COMPRESS_NON_SOLID, s);
2504     const int index = (int)m_Solid.AddString(s);
2505     m_Solid.SetItemData(index, (LPARAM)(UInt32)kSolidLog_NoSolid);
2506     if (defaultBlockSize == kSolidLog_NoSolid)
2507       curSel = index;
2508   }
2509 
2510   for (unsigned i = 20; i <= 36; i++)
2511   {
2512     AString s;
2513     Add_Size(s, (UInt64)1 << i);
2514     const int index = (int)ComboBox_AddStringAscii(m_Solid, s);
2515     m_Solid.SetItemData(index, (LPARAM)(UInt32)i);
2516     if (defaultBlockSize != (UInt32)(Int32)-1)
2517       if (i <= defaultBlockSize || index <= 1)
2518         curSel = index;
2519   }
2520 
2521   {
2522     const int index = (int)m_Solid.AddString(LangString(IDS_COMPRESS_SOLID));
2523     m_Solid.SetItemData(index, (LPARAM)kSolidLog_FullSolid);
2524     if (defaultBlockSize == kSolidLog_FullSolid)
2525       curSel = index;
2526   }
2527 
2528   m_Solid.SetCurSel(curSel);
2529 }
2530 
2531 
2532 /*
2533 static void ZstdEncProps_SetDictProps_From_CompressDialog(CZstdEncProps *props, CCompressDialog &cd)
2534 {
2535   {
2536     const UInt64 d64 = cd.GetDictSpec();
2537     UInt32 d32 = 0; // 0 is default for ZstdEncProps::windowLog
2538     if (d64 != (UInt64)(Int64)-1)
2539     {
2540       d32 = (UInt32)d64;
2541       if (d32 != d64)
2542         d32 = (UInt32)(Int32)-2;
2543     }
2544     ZstdEncProps_Set_WindowSize(props, d32);
2545   }
2546   {
2547     const UInt64 d64 = cd.GetDictChainSpec();
2548     UInt32 d32 = 0; // 0 is default for ZstdEncProps::windowLog_Chain
2549     if (d64 != (UInt64)(Int64)-1)
2550     {
2551       d32 = (UInt32)d64;
2552       if (d32 != d64)
2553         d32 = (UInt32)(Int32)-2;
2554     }
2555     ZstdEncProps_Set_WindowChainSize(props, d32);
2556   }
2557 }
2558 
2559 static bool Is_Zstd_Mt_Supported()
2560 {
2561   if (!GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "InitializeConditionVariable"))
2562     return false;
2563   return true;
2564 }
2565 */
2566 
2567 static const char *k_ST_Threads = " (ST)";
2568 
SetNumThreads2()2569 void CCompressDialog::SetNumThreads2()
2570 {
2571   _auto_NumThreads = 1;
2572 
2573   m_NumThreads.ResetContent();
2574   const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
2575   if (!fi.MultiThread_())
2576     return;
2577 
2578   const UInt32 numHardwareThreads = NSystem::GetNumberOfProcessors();
2579     // 64; // for debug:
2580 
2581   UInt32 defaultValue = numHardwareThreads;
2582   bool useAutoThreads = true;
2583 
2584   {
2585     const CArcInfoEx &ai = Get_ArcInfoEx();
2586     int index = FindRegistryFormat(ai.Name);
2587     if (index >= 0)
2588     {
2589       const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
2590       if (IsMethodEqualTo(fo.Method) && fo.NumThreads != (UInt32)(Int32)-1)
2591       {
2592         defaultValue = fo.NumThreads;
2593         useAutoThreads = false;
2594       }
2595     }
2596   }
2597 
2598   // const UInt32 num_ZSTD_threads_MAX = Is_Zstd_Mt_Supported() ? MY_ZSTDMT_NBWORKERS_MAX : 0;
2599 
2600   UInt32 numAlgoThreadsMax = numHardwareThreads * 2;
2601   const int methodID = GetMethodID();
2602 
2603   switch (methodID)
2604   {
2605     case kLZMA: numAlgoThreadsMax = 2; break;
2606     case kLZMA2: numAlgoThreadsMax = 256; break;
2607     case kBZip2: numAlgoThreadsMax = 32; break;
2608     // case kZSTD: numAlgoThreadsMax = num_ZSTD_threads_MAX; break;
2609     case kCopy:
2610     case kPPMd:
2611     case kDeflate:
2612     case kDeflate64:
2613     case kPPMdZip:
2614       numAlgoThreadsMax = 1;
2615   }
2616   const bool isZip = IsZipFormat();
2617   if (isZip)
2618   {
2619     numAlgoThreadsMax =
2620       #ifdef _WIN32
2621         64; // _WIN32 supports only 64 threads in one group. So no need for more threads here
2622       #else
2623         128;
2624       #endif
2625   }
2626 
2627   UInt32 autoThreads = numHardwareThreads;
2628   if (autoThreads > numAlgoThreadsMax)
2629     autoThreads = numAlgoThreadsMax;
2630 
2631   const UInt64 memUse_Limit = Get_MemUse_Bytes();
2632 
2633   if (_ramSize_Defined)
2634   if (autoThreads > 1
2635       // || (autoThreads == 0 && methodID == kZSTD)
2636       )
2637   {
2638     if (isZip)
2639     {
2640       for (; autoThreads > 1; autoThreads--)
2641       {
2642         const UInt64 dict64 = GetDict2();
2643         UInt64 decompressMemory;
2644         const UInt64 usage = GetMemoryUsage_Threads_Dict_DecompMem(autoThreads, dict64, decompressMemory);
2645         if (usage <= memUse_Limit)
2646           break;
2647       }
2648     }
2649     else if (methodID == kLZMA2)
2650     {
2651       const UInt64 dict64 = GetDict2();
2652       const UInt32 numThreads1 = (GetLevel2() >= 5 ? 2 : 1);
2653       UInt32 numBlockThreads = autoThreads / numThreads1;
2654       for (; numBlockThreads > 1; numBlockThreads--)
2655       {
2656         autoThreads = numBlockThreads * numThreads1;
2657         UInt64 decompressMemory;
2658         const UInt64 usage = GetMemoryUsage_Threads_Dict_DecompMem(autoThreads, dict64, decompressMemory);
2659         if (usage <= memUse_Limit)
2660           break;
2661       }
2662       autoThreads = numBlockThreads * numThreads1;
2663     }
2664     /*
2665     else if (methodID == kZSTD)
2666     {
2667       if (num_ZSTD_threads_MAX != 0)
2668       {
2669         CZstdEncProps props;
2670         ZstdEncProps_Init(&props);
2671         // props.level_zstd = level;
2672         props.level_7z = GetLevel2();
2673         ZstdEncProps_SetDictProps_From_CompressDialog(&props, *this);
2674         autoThreads = ZstdEncProps_GetNumThreads_for_MemUsageLimit(&props, memUse_Limit, autoThreads);
2675       }
2676     }
2677     */
2678   }
2679 
2680   _auto_NumThreads = autoThreads;
2681 
2682   int curSel = -1;
2683   {
2684     AString s;
2685     s.Add_UInt32(autoThreads);
2686     if (autoThreads == 0) s += k_ST_Threads;
2687     Modify_Auto(s);
2688     const int index = (int)ComboBox_AddStringAscii(m_NumThreads, s);
2689     m_NumThreads.SetItemData(index, (LPARAM)(INT_PTR)(-1));
2690     // m_NumThreads.SetItemData(index, autoThreads);
2691     if (useAutoThreads)
2692       curSel = index;
2693   }
2694 
2695   if (numAlgoThreadsMax != autoThreads || autoThreads != 1)
2696   for (UInt32 i =
2697       // (methodID == kZSTD) ? 0 :
2698       1;
2699       i <= numHardwareThreads * 2 && i <= numAlgoThreadsMax; i++)
2700   {
2701     AString s;
2702     s.Add_UInt32(i);
2703     if (i == 0) s += k_ST_Threads;
2704     const int index = (int)ComboBox_AddStringAscii(m_NumThreads, s);
2705     m_NumThreads.SetItemData(index, (LPARAM)(UInt32)i);
2706     if (!useAutoThreads && i == defaultValue)
2707       curSel = index;
2708   }
2709 
2710   m_NumThreads.SetCurSel(curSel);
2711 }
2712 
2713 
AddMemSize(UString & res,UInt64 size)2714 static void AddMemSize(UString &res, UInt64 size)
2715 {
2716   char c;
2717   unsigned moveBits = 0;
2718   if (size >= ((UInt64)1 << 31) && (size & 0x3FFFFFFF) == 0)
2719     { moveBits = 30; c = 'G'; }
2720   else // if (size >= ((UInt32)1 << 21) && (size & 0xFFFFF) == 0)
2721     { moveBits = 20; c = 'M'; }
2722   // else { moveBits = 10; c = 'K'; }
2723   res.Add_UInt64(size >> moveBits);
2724   res.Add_Space();
2725   if (moveBits != 0)
2726     res.Add_Char(c);
2727   res.Add_Char('B');
2728 }
2729 
2730 
AddMemComboItem(UInt64 val,bool isPercent,bool isDefault)2731 int CCompressDialog::AddMemComboItem(UInt64 val, bool isPercent, bool isDefault)
2732 {
2733   UString sUser;
2734   UString sRegistry;
2735   if (isPercent)
2736   {
2737     UString s;
2738     s.Add_UInt64(val);
2739     s.Add_Char('%');
2740     if (isDefault)
2741       sUser = k_Auto_Prefix;
2742     else
2743       sRegistry = s;
2744     sUser += s;
2745   }
2746   else
2747   {
2748     AddMemSize(sUser, val);
2749     sRegistry = sUser;
2750     for (;;)
2751     {
2752       const int pos = sRegistry.Find(L' ');
2753       if (pos < 0)
2754         break;
2755       sRegistry.Delete(pos);
2756     }
2757     if (!sRegistry.IsEmpty())
2758       if (sRegistry.Back() == 'B')
2759         sRegistry.DeleteBack();
2760   }
2761   const unsigned dataIndex = _memUse_Strings.Add(sRegistry);
2762   const int index = (int)m_MemUse.AddString(sUser);
2763   m_MemUse.SetItemData(index, (LPARAM)dataIndex);
2764   return index;
2765 }
2766 
2767 
2768 
SetMemUseCombo()2769 void CCompressDialog::SetMemUseCombo()
2770 {
2771   _memUse_Strings.Clear();
2772   m_MemUse.ResetContent();
2773   const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
2774 
2775   {
2776     const bool enable = fi.MemUse_();
2777     ShowItem_Bool(IDT_COMPRESS_MEMORY, enable);
2778     ShowItem_Bool(IDT_COMPRESS_MEMORY_VALUE, enable);
2779     ShowItem_Bool(IDT_COMPRESS_MEMORY_DE, enable);
2780     ShowItem_Bool(IDT_COMPRESS_MEMORY_DE_VALUE, enable);
2781     ShowItem_Bool(IDC_COMPRESS_MEM_USE, enable);
2782     EnableItem(IDC_COMPRESS_MEM_USE, enable);
2783     if (!enable)
2784       return;
2785   }
2786 
2787   UInt64 curMem_Bytes = 0;
2788   UInt64 curMem_Percents = 0;
2789   bool needSetCur_Bytes = false;
2790   bool needSetCur_Percents = false;
2791   {
2792     const NCompression::CFormatOptions &fo = Get_FormatOptions();
2793     if (!fo.MemUse.IsEmpty())
2794     {
2795       NCompression::CMemUse mu;
2796       mu.Parse(fo.MemUse);
2797       if (mu.IsDefined)
2798       {
2799         if (mu.IsPercent)
2800         {
2801           curMem_Percents = mu.Val;
2802           needSetCur_Percents = true;
2803         }
2804         else
2805         {
2806           curMem_Bytes = mu.GetBytes(_ramSize_Reduced);
2807           needSetCur_Bytes = true;
2808         }
2809       }
2810     }
2811   }
2812 
2813 
2814   // 80% - is auto usage limit in handlers
2815   AddMemComboItem(80, true, true);
2816   m_MemUse.SetCurSel(0);
2817 
2818   {
2819     for (unsigned i = 10;; i += 10)
2820     {
2821       UInt64 size = i;
2822       if (i > 100)
2823         size = (UInt64)(Int64)-1;
2824       if (needSetCur_Percents && size >= curMem_Percents)
2825       {
2826         const int index = AddMemComboItem(curMem_Percents, true);
2827         m_MemUse.SetCurSel(index);
2828         needSetCur_Percents = false;
2829         if (size == curMem_Percents)
2830           continue;
2831       }
2832       if (size == (UInt64)(Int64)-1)
2833         break;
2834       AddMemComboItem(size, true);
2835     }
2836   }
2837   {
2838     for (unsigned i = (27) * 2;; i++)
2839     {
2840       UInt64 size = (UInt64)(2 + (i & 1)) << (i / 2);
2841       if (i > (20 + sizeof(size_t) * 3 - 1) * 2)
2842         size = (UInt64)(Int64)-1;
2843       if (needSetCur_Bytes && size >= curMem_Bytes)
2844       {
2845         const int index = AddMemComboItem(curMem_Bytes);
2846         m_MemUse.SetCurSel(index);
2847         needSetCur_Bytes = false;
2848         if (size == curMem_Bytes)
2849           continue;
2850       }
2851       if (size == (UInt64)(Int64)-1)
2852         break;
2853       AddMemComboItem(size);
2854     }
2855   }
2856 }
2857 
2858 
Get_MemUse_Spec()2859 UString CCompressDialog::Get_MemUse_Spec()
2860 {
2861   if (m_MemUse.GetCount() < 1)
2862     return UString();
2863   return _memUse_Strings[(unsigned)m_MemUse.GetItemData_of_CurSel()];
2864 }
2865 
2866 
Get_MemUse_Bytes()2867 UInt64 CCompressDialog::Get_MemUse_Bytes()
2868 {
2869   const UString mus = Get_MemUse_Spec();
2870   NCompression::CMemUse mu;
2871   if (!mus.IsEmpty())
2872   {
2873     mu.Parse(mus);
2874     if (mu.IsDefined)
2875       return mu.GetBytes(_ramSize_Reduced);
2876   }
2877   return _ramUsage_Auto; // _ramSize_Reduced; // _ramSize;;
2878 }
2879 
2880 
2881 
GetMemoryUsage_DecompMem(UInt64 & decompressMemory)2882 UInt64 CCompressDialog::GetMemoryUsage_DecompMem(UInt64 &decompressMemory)
2883 {
2884   return GetMemoryUsage_Dict_DecompMem(GetDict2(), decompressMemory);
2885 }
2886 
2887 
2888 /*
2889 we could use that function to reduce the dictionary if small RAM
2890 UInt64 CCompressDialog::GetMemoryUsageComp_Threads_Dict(UInt32 numThreads, UInt64 dict64)
2891 {
2892   UInt64 decompressMemory;
2893   return GetMemoryUsage_Threads_Dict_DecompMem(numThreads, dict64, decompressMemory);
2894 }
2895 */
2896 
2897 
GetMemoryUsage_Dict_DecompMem(UInt64 dict64,UInt64 & decompressMemory)2898 UInt64 CCompressDialog::GetMemoryUsage_Dict_DecompMem(UInt64 dict64, UInt64 &decompressMemory)
2899 {
2900   return GetMemoryUsage_Threads_Dict_DecompMem(GetNumThreads2(), dict64, decompressMemory);
2901 }
2902 
GetMemoryUsage_Threads_Dict_DecompMem(UInt32 numThreads,UInt64 dict64,UInt64 & decompressMemory)2903 UInt64 CCompressDialog::GetMemoryUsage_Threads_Dict_DecompMem(UInt32 numThreads, UInt64 dict64, UInt64 &decompressMemory)
2904 {
2905   decompressMemory = (UInt64)(Int64)-1;
2906 
2907   const UInt32 level = GetLevel2();
2908   if (level == 0 && !Get_ArcInfoEx().Is_Zstd())
2909   {
2910     decompressMemory = (1 << 20);
2911     return decompressMemory;
2912   }
2913   UInt64 size = 0;
2914 
2915   const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
2916   if (fi.Filter_() && level >= 9)
2917     size += (12 << 20) * 2 + (5 << 20);
2918   // UInt32 numThreads = GetNumThreads2();
2919 
2920   UInt32 numMainZipThreads = 1;
2921 
2922   if (IsZipFormat())
2923   {
2924     UInt32 numSubThreads = 1;
2925     if (GetMethodID() == kLZMA && numThreads > 1 && level >= 5)
2926       numSubThreads = 2;
2927     numMainZipThreads = numThreads / numSubThreads;
2928     if (numMainZipThreads > 1)
2929       size += (UInt64)numMainZipThreads * ((size_t)sizeof(size_t) << 23);
2930     else
2931       numMainZipThreads = 1;
2932   }
2933 
2934   const int methodId = GetMethodID();
2935 
2936   if (dict64 == (UInt64)(Int64)-1
2937       // && methodId != kZSTD
2938       )
2939     return (UInt64)(Int64)-1;
2940 
2941 
2942   switch (methodId)
2943   {
2944     case kLZMA:
2945     case kLZMA2:
2946     {
2947       const UInt32 dict = (dict64 >= kLzmaMaxDictSize ? kLzmaMaxDictSize : (UInt32)dict64);
2948       UInt32 hs = dict - 1;
2949       hs |= (hs >> 1);
2950       hs |= (hs >> 2);
2951       hs |= (hs >> 4);
2952       hs |= (hs >> 8);
2953       hs >>= 1;
2954       if (hs >= (1 << 24))
2955         hs >>= 1;
2956       hs |= (1 << 16) - 1;
2957       // if (numHashBytes >= 5)
2958       if (level < 5)
2959         hs |= (256 << 10) - 1;
2960       hs++;
2961       UInt64 size1 = (UInt64)hs * 4;
2962       size1 += (UInt64)dict * 4;
2963       if (level >= 5)
2964         size1 += (UInt64)dict * 4;
2965       size1 += (2 << 20);
2966 
2967       UInt32 numThreads1 = 1;
2968       if (numThreads > 1 && level >= 5)
2969       {
2970         size1 += (2 << 20) + (4 << 20);
2971         numThreads1 = 2;
2972       }
2973 
2974       UInt32 numBlockThreads = numThreads / numThreads1;
2975 
2976       UInt64 chunkSize = 0; // it's solid chunk
2977 
2978       if (methodId != kLZMA && numBlockThreads != 1)
2979       {
2980         chunkSize = Get_Lzma2_ChunkSize(dict);
2981 
2982         if (IsXzFormat())
2983         {
2984           UInt32 blockSizeLog = GetBlockSizeSpec();
2985           if (blockSizeLog != (UInt32)(Int32)-1)
2986           {
2987             if (blockSizeLog == kSolidLog_FullSolid)
2988             {
2989               numBlockThreads = 1;
2990               chunkSize = 0;
2991             }
2992             else if (blockSizeLog != kSolidLog_NoSolid)
2993               chunkSize = (UInt64)1 << blockSizeLog;
2994           }
2995         }
2996       }
2997 
2998       if (chunkSize == 0)
2999       {
3000         const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)(1 << 16);
3001         UInt64 blockSize = (UInt64)dict + (1 << 16)
3002           + (numThreads1 > 1 ? (1 << 20) : 0);
3003         blockSize += (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2));
3004         if (blockSize >= kBlockSizeMax)
3005           blockSize = kBlockSizeMax;
3006         size += numBlockThreads * (size1 + blockSize);
3007       }
3008       else
3009       {
3010         size += numBlockThreads * (size1 + chunkSize);
3011         UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1;
3012         if (chunkSize < ((UInt32)1 << 26)) numBlockThreads++;
3013         if (chunkSize < ((UInt32)1 << 24)) numBlockThreads++;
3014         if (chunkSize < ((UInt32)1 << 22)) numBlockThreads++;
3015         size += numPackChunks * chunkSize;
3016       }
3017 
3018       decompressMemory = dict + (2 << 20);
3019       return size;
3020     }
3021 
3022     /*
3023     case kZSTD:
3024     {
3025       CZstdEncProps props;
3026       ZstdEncProps_Init(&props);
3027       // props.level_zstd = level;
3028       props.level_7z = level;
3029       props.nbWorkers = numThreads;
3030       ZstdEncProps_SetDictProps_From_CompressDialog(&props, *this);
3031       ZstdEncProps_NormalizeFull(&props);
3032       size = ZstdEncProps_GetMemUsage(&props);
3033       decompressMemory = (UInt64)1 << props.windowLog;
3034       return size;
3035     }
3036     */
3037 
3038     case kPPMd:
3039     {
3040       decompressMemory = dict64 + (2 << 20);
3041       return size + decompressMemory;
3042     }
3043 
3044     case kDeflate:
3045     case kDeflate64:
3046     {
3047       UInt64 size1 = 3 << 20;
3048       // if (level >= 7)
3049         size1 += (1 << 20);
3050       size += size1 * numMainZipThreads;
3051       decompressMemory = (2 << 20);
3052       return size;
3053     }
3054 
3055     case kBZip2:
3056     {
3057       decompressMemory = (7 << 20);
3058       UInt64 memForOneThread = (10 << 20);
3059       return size + memForOneThread * numThreads;
3060     }
3061 
3062     case kPPMdZip:
3063     {
3064       decompressMemory = dict64 + (2 << 20);
3065       return size + (UInt64)decompressMemory * numThreads;
3066     }
3067   }
3068 
3069   return (UInt64)(Int64)-1;
3070 }
3071 
3072 
3073 
AddMemUsage(UString & s,UInt64 v)3074 static void AddMemUsage(UString &s, UInt64 v)
3075 {
3076   const char *post;
3077   if (v <= ((UInt64)16 << 30))
3078   {
3079     v = (v + (1 << 20) - 1) >> 20;
3080     post = "MB";
3081   }
3082   else if (v <= ((UInt64)64 << 40))
3083   {
3084     v = (v + (1 << 30) - 1) >> 30;
3085     post = "GB";
3086   }
3087   else
3088   {
3089     const UInt64 v2 = v + ((UInt64)1 << 40) - 1;
3090     if (v <= v2)
3091       v = v2;
3092     v >>= 40;
3093     post = "TB";
3094   }
3095   s.Add_UInt64(v);
3096   s.Add_Space();
3097   s += post;
3098 }
3099 
3100 
PrintMemUsage(UINT res,UInt64 value)3101 void CCompressDialog::PrintMemUsage(UINT res, UInt64 value)
3102 {
3103   if (value == (UInt64)(Int64)-1)
3104   {
3105     SetItemText(res, TEXT("?"));
3106     return;
3107   }
3108   UString s;
3109   AddMemUsage(s, value);
3110   if (res == IDT_COMPRESS_MEMORY_VALUE)
3111   {
3112     const UString mus = Get_MemUse_Spec();
3113     NCompression::CMemUse mu;
3114     if (!mus.IsEmpty())
3115       mu.Parse(mus);
3116     if (mu.IsDefined)
3117     {
3118       s += " / ";
3119       AddMemUsage(s, mu.GetBytes(_ramSize_Reduced));
3120     }
3121     else if (_ramSize_Defined)
3122     {
3123       s += " / ";
3124       AddMemUsage(s, _ramUsage_Auto);
3125     }
3126 
3127     if (_ramSize_Defined)
3128     {
3129       s += " / ";
3130       AddMemUsage(s, _ramSize);
3131     }
3132   }
3133   SetItemText(res, s);
3134 }
3135 
3136 
SetMemoryUsage()3137 void CCompressDialog::SetMemoryUsage()
3138 {
3139   UInt64 decompressMem;
3140   const UInt64 memUsage = GetMemoryUsage_DecompMem(decompressMem);
3141   PrintMemUsage(IDT_COMPRESS_MEMORY_VALUE, memUsage);
3142   PrintMemUsage(IDT_COMPRESS_MEMORY_DE_VALUE, decompressMem);
3143  #ifdef PRINT_PARAMS
3144   Print_Params();
3145  #endif
3146 }
3147 
3148 
3149 
3150 #ifdef PRINT_PARAMS
3151 
3152 static const char kPropDelimeter = ' '; // ':'
3153 
AddPropName(AString & s,const char * name)3154 static void AddPropName(AString &s, const char *name)
3155 {
3156   if (!s.IsEmpty())
3157     s += kPropDelimeter;
3158   s += name;
3159 }
3160 
AddProp(AString & s,const char * name,unsigned v)3161 static void AddProp(AString &s, const char *name, unsigned v)
3162 {
3163   AddPropName(s, name);
3164   s.Add_UInt32(v);
3165 }
3166 
AddProp_switch(AString & s,const char * name,E_ZSTD_paramSwitch_e e)3167 static void AddProp_switch(AString &s, const char *name, E_ZSTD_paramSwitch_e e)
3168 {
3169   AddPropName(s, name);
3170   s += e == k_ZSTD_ps_enable ? "" : "-";
3171 }
3172 
PrintPropAsLog(AString & s,const char * name,size_t v)3173 static void PrintPropAsLog(AString &s, const char *name, size_t v)
3174 {
3175   AddPropName(s, name);
3176   for (unsigned i = 0; i < sizeof(size_t) * 8; i++)
3177   {
3178     if (((size_t)1 << i) == v)
3179     {
3180       s.Add_UInt32(i);
3181       return;
3182     }
3183   }
3184   char c = 'b';
3185        if ((v & 0x3FFFFFFF) == 0) { v >>= 30; c = 'G'; }
3186   else if ((v &    0xFFFFF) == 0) { v >>= 20; c = 'M'; }
3187   else if ((v &      0x3FF) == 0) { v >>= 10; c = 'K'; }
3188   s.Add_UInt64(v);
3189   s += c;
3190 }
3191 
ZstdEncProps_Print(CZstdEncProps * props,AString & s)3192 static void ZstdEncProps_Print(CZstdEncProps *props, AString &s)
3193 {
3194   if (props->level_zstd >= 0)
3195     AddProp(s, "zx", props->level_zstd);
3196   else
3197     AddProp(s, "zf", -(props->level_zstd));
3198   AddProp(s, "a", props->strategy);
3199   AddProp(s, "d", props->windowLog);
3200   AddProp(s, "zclog", props->chainLog);
3201   AddProp(s, "zhb", props->hashLog);
3202   AddProp(s, "mml", props->minMatch);
3203   AddProp(s, "mcb", props->searchLog);
3204   AddProp(s, "fb", props->targetLength);
3205   AddProp(s, "mt", props->nbWorkers);
3206   PrintPropAsLog(s, "c", props->jobSize);
3207   AddProp(s, "zov", props->overlapLog);
3208   PrintPropAsLog(s, "ztps", props->targetPrefixSize);
3209   AddProp_switch(s, "zmfr", props->useRowMatchFinder);
3210   if (props->ldmParams.enableLdm == k_ZSTD_ps_enable)
3211   {
3212     AddProp_switch(s, "zle", props->ldmParams.enableLdm);
3213     AddProp(s, "zlhb", props->ldmParams.hashLog);
3214     AddProp(s, "zlbb", props->ldmParams.bucketSizeLog);
3215     AddProp(s, "zlmml", props->ldmParams.minMatchLength);
3216     AddProp(s, "zlhrb", props->ldmParams.hashRateLog);
3217   }
3218 }
3219 
Print_Params()3220 void CCompressDialog::Print_Params()
3221 {
3222   {
3223     CZstdEncProps props;
3224     ZstdEncProps_Init(&props);
3225     // props.level_zstd = level;
3226     props.level_7z = GetLevel2();
3227     ZstdEncProps_SetDictProps_From_CompressDialog(&props, *this);
3228     {
3229       UInt32 order = GetOrderSpec();
3230       if (order != (UInt32)(Int32)-1)
3231         props.targetLength = GetOrderSpec();
3232     }
3233     props.nbWorkers = GetNumThreads2();
3234     // props.windowLog = 18; // for debug
3235     ZstdEncProps_NormalizeFull(&props);
3236     AString s;
3237     ZstdEncProps_Print(&props, s);
3238     SetItemTextA(IDT_COMPRESS_PARAMS_INFO, s);
3239   }
3240 }
3241 
3242 #endif // PRINT_PARAMS
3243 
3244 
3245 
SetParams()3246 void CCompressDialog::SetParams()
3247 {
3248   const CArcInfoEx &ai = Get_ArcInfoEx();
3249   m_Params.SetText(TEXT(""));
3250   const int index = FindRegistryFormat(ai.Name);
3251   if (index >= 0)
3252   {
3253     const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
3254     m_Params.SetText(fo.Options);
3255   }
3256 }
3257 
SaveOptionsInMem()3258 void CCompressDialog::SaveOptionsInMem()
3259 {
3260   /* these options are for (Info.FormatIndex).
3261      If it's called just after format changing,
3262      then it's format that was selected before format changing
3263      So we store previous format properties */
3264 
3265   m_Params.GetText(Info.Options);
3266   Info.Options.Trim();
3267 
3268   const CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex];
3269   const unsigned index = FindRegistryFormat_Always(ai.Name);
3270   NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
3271   fo.Options = Info.Options;
3272   fo.Level = GetLevelSpec();
3273   {
3274     const UInt64 dict64 = GetDictSpec();
3275     UInt32 dict32;
3276     if (dict64 == (UInt64)(Int64)-1)
3277       dict32 = (UInt32)(Int32)-1;
3278     else
3279     {
3280       dict32 = (UInt32)dict64;
3281       if (dict64 != dict32)
3282       {
3283         /* here we must write 32-bit value for registry that indicates big_value
3284            (UInt32)(Int32)-1  : is used as marker for default size
3285            (UInt32)(Int32)-2  : it can be used to indicate big value (4 GiB)
3286            the value must be larger than threshold
3287         */
3288         dict32 = (UInt32)(Int32)-2;
3289         // dict32 = kLzmaMaxDictSize; // it must be larger than threshold
3290       }
3291     }
3292     fo.Dictionary = dict32;
3293   }
3294   /*
3295   {
3296     const UInt64 dict64 = GetDictChainSpec();
3297     UInt32 dict32;
3298     if (dict64 == (UInt64)(Int64)-1)
3299       dict32 = (UInt32)(Int32)-1;
3300     else
3301     {
3302       dict32 = (UInt32)dict64;
3303       if (dict64 != dict32)
3304       {
3305         dict32 = (UInt32)(Int32)-2;
3306         // dict32 = k_Zstd_MAX_DictSize; // it must be larger than threshold
3307       }
3308     }
3309     fo.DictionaryChain = dict32;
3310   }
3311   */
3312 
3313   fo.Order = GetOrderSpec();
3314   fo.Method = GetMethodSpec();
3315   fo.EncryptionMethod = GetEncryptionMethodSpec();
3316   fo.NumThreads = GetNumThreadsSpec();
3317   fo.BlockLogSize = GetBlockSizeSpec();
3318   fo.MemUse = Get_MemUse_Spec();
3319 }
3320 
3321 
GetFormatIndex()3322 unsigned CCompressDialog::GetFormatIndex()
3323 {
3324   return (unsigned)m_Format.GetItemData_of_CurSel();
3325 }
3326 
3327 
3328 
AddText_from_BoolPair(AString & s,const char * name,const CBoolPair & bp)3329 static void AddText_from_BoolPair(AString &s, const char *name, const CBoolPair &bp)
3330 {
3331   if (bp.Def)
3332   {
3333     s.Add_OptSpaced(name);
3334     if (!bp.Val)
3335       s += "-";
3336   }
3337   /*
3338   else if (bp.Val)
3339   {
3340     s.Add_OptSpaced("[");
3341     s += name;
3342     s += "]";
3343   }
3344   */
3345 }
3346 
3347 
AddText_from_Bool1(AString & s,const char * name,const CBool1 & b)3348 static void AddText_from_Bool1(AString &s, const char *name, const CBool1 &b)
3349 {
3350   if (b.Supported && b.Val)
3351     s.Add_OptSpaced(name);
3352 }
3353 
3354 
ShowOptionsString()3355 void CCompressDialog::ShowOptionsString()
3356 {
3357   NCompression::CFormatOptions &fo = Get_FormatOptions();
3358 
3359   AString s;
3360   if (fo.IsSet_TimePrec())
3361   {
3362     s.Add_OptSpaced("tp");
3363     s.Add_UInt32(fo.TimePrec);
3364   }
3365   AddText_from_BoolPair(s, "tm", fo.MTime);
3366   AddText_from_BoolPair(s, "tc", fo.CTime);
3367   AddText_from_BoolPair(s, "ta", fo.ATime);
3368   AddText_from_BoolPair(s, "-stl", fo.SetArcMTime);
3369 
3370   // const CArcInfoEx &ai = Get_ArcInfoEx();
3371   AddText_from_Bool1(s, "SL",  SymLinks);
3372   AddText_from_Bool1(s, "HL",  HardLinks);
3373   AddText_from_Bool1(s, "AS",  AltStreams);
3374   AddText_from_Bool1(s, "Sec", NtSecurity);
3375 
3376   // AddText_from_Bool1(s, "Preserve", PreserveATime);
3377 
3378   SetItemText(IDT_COMPRESS_OPTIONS, GetUnicodeString(s));
3379 }
3380 
3381 
3382 
3383 
3384 
3385 // ---------- OPTIONS ----------
3386 
3387 
CheckButton_Bool1(UINT id,const CBool1 & b1)3388 void COptionsDialog::CheckButton_Bool1(UINT id, const CBool1 &b1)
3389 {
3390   CheckButton(id, b1.Val);
3391 }
3392 
GetButton_Bool1(UINT id,CBool1 & b1)3393 void COptionsDialog::GetButton_Bool1(UINT id, CBool1 &b1)
3394 {
3395   b1.Val = IsButtonCheckedBool(id);
3396 }
3397 
3398 
CheckButton_BoolBox(bool supported,const CBoolPair & b2,CBoolBox & bb)3399 void COptionsDialog::CheckButton_BoolBox(
3400     bool supported, const CBoolPair &b2, CBoolBox &bb)
3401 {
3402   const bool isSet = b2.Def;
3403   const bool val = isSet ? b2.Val : bb.DefaultVal;
3404 
3405   bb.IsSupported = supported;
3406 
3407   CheckButton (bb.Set_Id, isSet);
3408   ShowItem_Bool (bb.Set_Id, supported);
3409   CheckButton (bb.Id, val);
3410   EnableItem (bb.Id, isSet);
3411   ShowItem_Bool (bb.Id, supported);
3412 }
3413 
GetButton_BoolBox(CBoolBox & bb)3414 void COptionsDialog::GetButton_BoolBox(CBoolBox &bb)
3415 {
3416   // we save value for invisible buttons too
3417   bb.BoolPair.Val = IsButtonCheckedBool (bb.Id);
3418   bb.BoolPair.Def = IsButtonCheckedBool (bb.Set_Id);
3419 }
3420 
3421 
Store_TimeBoxes()3422 void COptionsDialog::Store_TimeBoxes()
3423 {
3424   TimePrec = GetPrecSpec();
3425   GetButton_BoolBox (MTime);
3426   GetButton_BoolBox (CTime);
3427   GetButton_BoolBox (ATime);
3428   GetButton_BoolBox (ZTime);
3429 }
3430 
3431 
GetComboValue(NWindows::NControl::CComboBox & c,int defMax)3432 UInt32 COptionsDialog::GetComboValue(NWindows::NControl::CComboBox &c, int defMax)
3433 {
3434   if (c.GetCount() <= defMax)
3435     return (UInt32)(Int32)-1;
3436   return (UInt32)c.GetItemData_of_CurSel();
3437 }
3438 
3439 static const unsigned kTimePrec_Win  = 0;
3440 static const unsigned kTimePrec_Unix = 1;
3441 static const unsigned kTimePrec_DOS  = 2;
3442 static const unsigned kTimePrec_1ns  = 3;
3443 
AddTimeOption(UString & s,UInt32 val,const UString & unit,const char * sys=NULL)3444 static void AddTimeOption(UString &s, UInt32 val, const UString &unit, const char *sys = NULL)
3445 {
3446   // s += " : ";
3447   {
3448     AString s2;
3449     s2.Add_UInt32(val);
3450     s += s2;
3451   }
3452   s.Add_Space();
3453   s += unit;
3454   if (sys)
3455   {
3456     s += " : ";
3457     s += sys;
3458   }
3459 }
3460 
AddPrec(unsigned prec,bool isDefault)3461 int COptionsDialog::AddPrec(unsigned prec, bool isDefault)
3462 {
3463   UString s;
3464   UInt32 writePrec = prec;
3465   if (isDefault)
3466   {
3467     // s += "* ";
3468     // writePrec = (UInt32)(Int32)-1;
3469   }
3470        if (prec == kTimePrec_Win)  AddTimeOption(s, 100, NsString, "Windows");
3471   else if (prec == kTimePrec_Unix) AddTimeOption(s, 1, SecString, "Unix");
3472   else if (prec == kTimePrec_DOS)  AddTimeOption(s, 2, SecString, "DOS");
3473   else if (prec == kTimePrec_1ns)  AddTimeOption(s, 1, NsString, "Linux");
3474   else if (prec == k_PropVar_TimePrec_Base) AddTimeOption(s, 1, SecString);
3475   else if (prec >= k_PropVar_TimePrec_Base)
3476   {
3477     UInt32 d = 1;
3478     for (unsigned i = prec; i < k_PropVar_TimePrec_Base + 9; i++)
3479       d *= 10;
3480     AddTimeOption(s, d, NsString);
3481   }
3482   else
3483     s.Add_UInt32(prec);
3484   const int index = (int)m_Prec.AddString(s);
3485   m_Prec.SetItemData(index, (LPARAM)writePrec);
3486   return index;
3487 }
3488 
3489 
SetPrec()3490 void COptionsDialog::SetPrec()
3491 {
3492   // const CFormatInfo &fi = g_Formats[cd->GetStaticFormatIndex()];
3493   const CArcInfoEx &ai = cd->Get_ArcInfoEx();
3494 
3495   // UInt32 flags = fi.Flags;
3496 
3497   UInt32 flags = ai.Get_TimePrecFlags();
3498   UInt32 defaultPrec = ai.Get_DefaultTimePrec();
3499   if (defaultPrec != 0)
3500     flags |= ((UInt32)1 << defaultPrec);
3501 
3502   // const NCompression::CFormatOptions &fo = cd->Get_FormatOptions();
3503 
3504   // unsigned defaultPrec = kTimePrec_Win;
3505 
3506   if (ai.Is_GZip())
3507     defaultPrec = kTimePrec_Unix;
3508 
3509   {
3510     UString s;
3511     s += GetNameOfProperty(kpidType, L"type");
3512     s += ": ";
3513     s += ai.Name;
3514     if (ai.Is_Tar())
3515     {
3516       const int methodID = cd->GetMethodID();
3517 
3518       // for debug
3519       // defaultPrec = kTimePrec_Unix;
3520       // flags = (UInt32)1 << kTimePrec_Unix;
3521 
3522       s.Add_Colon();
3523       if (methodID >= 0 && (unsigned)methodID < Z7_ARRAY_SIZE(kMethodsNames))
3524         s += kMethodsNames[methodID];
3525       if (methodID == kPosix)
3526       {
3527         // for debug
3528         // flags |= (UInt32)1 << kTimePrec_Win;
3529         // flags |= (UInt32)1 << kTimePrec_1ns;
3530       }
3531     }
3532     else
3533     {
3534       // if (is_for_MethodChanging) return;
3535     }
3536 
3537     SetItemText(IDT_COMPRESS_TIME_INFO, s);
3538   }
3539 
3540   m_Prec.ResetContent();
3541   _auto_Prec = defaultPrec;
3542 
3543   unsigned selectedPrec = defaultPrec;
3544   {
3545     // if (TimePrec >= kTimePrec_Win && TimePrec <= kTimePrec_DOS)
3546     if ((Int32)TimePrec >= 0)
3547       selectedPrec = TimePrec;
3548   }
3549 
3550   int curSel = -1;
3551   int defaultPrecIndex = -1;
3552   for (unsigned prec = 0;
3553       // prec <= k_PropVar_TimePrec_HighPrec;
3554       prec <= k_PropVar_TimePrec_1ns;
3555       prec++)
3556   {
3557     if (((flags >> prec) & 1) == 0)
3558       continue;
3559     const bool isDefault = (defaultPrec == prec);
3560     const int index = AddPrec(prec, isDefault);
3561     if (isDefault)
3562       defaultPrecIndex = index;
3563     if (selectedPrec == prec)
3564       curSel = index;
3565   }
3566 
3567   if (curSel < 0 && selectedPrec > kTimePrec_DOS)
3568     curSel = AddPrec(selectedPrec, false); // isDefault
3569   if (curSel < 0)
3570     curSel = defaultPrecIndex;
3571   if (curSel >= 0)
3572     m_Prec.SetCurSel(curSel);
3573 
3574   {
3575     const bool isSet = IsSet_TimePrec();
3576     const int count = m_Prec.GetCount();
3577     const bool showPrec = (count != 0);
3578     ShowItem_Bool(IDC_COMPRESS_TIME_PREC, showPrec);
3579     ShowItem_Bool(IDT_COMPRESS_TIME_PREC, showPrec);
3580     EnableItem(IDC_COMPRESS_TIME_PREC, isSet && (count > 1));
3581 
3582     CheckButton(IDX_COMPRESS_PREC_SET, isSet);
3583     const bool setIsSupported = isSet || (count > 1);
3584     EnableItem(IDX_COMPRESS_PREC_SET, setIsSupported);
3585     ShowItem_Bool(IDX_COMPRESS_PREC_SET, setIsSupported);
3586   }
3587 
3588   SetTimeMAC();
3589 }
3590 
3591 
SetTimeMAC()3592 void COptionsDialog::SetTimeMAC()
3593 {
3594   const CArcInfoEx &ai = cd->Get_ArcInfoEx();
3595 
3596   const
3597   bool m_allow = ai.Flags_MTime();
3598   bool c_allow = ai.Flags_CTime();
3599   bool a_allow = ai.Flags_ATime();
3600 
3601   if (ai.Is_Tar())
3602   {
3603     const int methodID = cd->GetMethodID();
3604     c_allow = false;
3605     a_allow = false;
3606     if (methodID == kPosix)
3607     {
3608       // c_allow = true; // do we need it as change time ?
3609       a_allow = true;
3610     }
3611   }
3612 
3613   if (ai.Is_Zip())
3614   {
3615     // const int methodID = GetMethodID();
3616     UInt32 prec = GetPrec();
3617     if (prec == (UInt32)(Int32)-1)
3618       prec = _auto_Prec;
3619     if (prec != kTimePrec_Win)
3620     {
3621       c_allow = false;
3622       a_allow = false;
3623     }
3624   }
3625 
3626 
3627   /*
3628   MTime.DefaultVal = true;
3629   CTime.DefaultVal = false;
3630   ATime.DefaultVal = false;
3631   */
3632 
3633   MTime.DefaultVal = ai.Flags_MTime_Default();
3634   CTime.DefaultVal = ai.Flags_CTime_Default();
3635   ATime.DefaultVal = ai.Flags_ATime_Default();
3636 
3637   ZTime.DefaultVal = false;
3638 
3639   const NCompression::CFormatOptions &fo = cd->Get_FormatOptions();
3640 
3641   CheckButton_BoolBox (m_allow, fo.MTime, MTime );
3642   CheckButton_BoolBox (c_allow, fo.CTime, CTime );
3643   CheckButton_BoolBox (a_allow, fo.ATime, ATime );
3644   CheckButton_BoolBox (true, fo.SetArcMTime, ZTime);
3645 
3646   if (m_allow && !fo.MTime.Def)
3647   {
3648     const bool isSingleFile = ai.Flags_KeepName();
3649     if (!isSingleFile)
3650     {
3651       // we can hide changing checkboxes for MTime here:
3652       ShowItem_Bool (MTime.Set_Id, false);
3653       EnableItem (MTime.Id, false);
3654     }
3655   }
3656   // On_CheckBoxSet_Prec_Clicked();
3657   // const bool isSingleFile = ai.Flags_KeepName();
3658   // mtime for Gz can be
3659 }
3660 
3661 
3662 
On_CheckBoxSet_Prec_Clicked()3663 void COptionsDialog::On_CheckBoxSet_Prec_Clicked()
3664 {
3665   const bool isSet = IsButtonCheckedBool(IDX_COMPRESS_PREC_SET);
3666   if (!isSet)
3667   {
3668     // We save current MAC boxes to memory before SetPrec()
3669     Store_TimeBoxes();
3670     Reset_TimePrec();
3671     SetPrec();
3672   }
3673   EnableItem(IDC_COMPRESS_TIME_PREC, isSet);
3674 }
3675 
On_CheckBoxSet_Clicked(const CBoolBox & bb)3676 void COptionsDialog::On_CheckBoxSet_Clicked(const CBoolBox &bb)
3677 {
3678   const bool isSet = IsButtonCheckedBool(bb.Set_Id);
3679   if (!isSet)
3680     CheckButton(bb.Id, bb.DefaultVal);
3681   EnableItem(bb.Id, isSet);
3682 }
3683 
3684 
3685 
3686 
3687 #ifdef Z7_LANG
3688 static const UInt32 kLangIDs_Options[] =
3689 {
3690   IDX_COMPRESS_NT_SYM_LINKS,
3691   IDX_COMPRESS_NT_HARD_LINKS,
3692   IDX_COMPRESS_NT_ALT_STREAMS,
3693   IDX_COMPRESS_NT_SECUR,
3694 
3695   IDG_COMPRESS_TIME,
3696   IDT_COMPRESS_TIME_PREC,
3697   IDX_COMPRESS_MTIME,
3698   IDX_COMPRESS_CTIME,
3699   IDX_COMPRESS_ATIME,
3700   IDX_COMPRESS_ZTIME,
3701   IDX_COMPRESS_PRESERVE_ATIME
3702 };
3703 #endif
3704 
3705 
OnInit()3706 bool COptionsDialog::OnInit()
3707 {
3708   #ifdef Z7_LANG
3709   LangSetWindowText(*this, IDB_COMPRESS_OPTIONS); // IDS_OPTIONS
3710   LangSetDlgItems(*this, kLangIDs_Options, Z7_ARRAY_SIZE(kLangIDs_Options));
3711   // LangSetDlgItemText(*this, IDB_COMPRESS_TIME_DEFAULT, IDB_COMPRESS_TIME_DEFAULT);
3712   // LangSetDlgItemText(*this, IDX_COMPRESS_TIME_DEFAULT, IDX_COMPRESS_TIME_DEFAULT);
3713   #endif
3714 
3715   LangString(IDS_COMPRESS_SEC, SecString);
3716   if (SecString.IsEmpty())
3717     SecString = "sec";
3718   LangString(IDS_COMPRESS_NS, NsString);
3719   if (NsString.IsEmpty())
3720     NsString = "ns";
3721 
3722   {
3723     // const CArcInfoEx &ai = cd->Get_ArcInfoEx();
3724 
3725     ShowItem_Bool ( IDX_COMPRESS_NT_SYM_LINKS,    cd->SymLinks.Supported);
3726     ShowItem_Bool ( IDX_COMPRESS_NT_HARD_LINKS,   cd->HardLinks.Supported);
3727     ShowItem_Bool ( IDX_COMPRESS_NT_ALT_STREAMS,  cd->AltStreams.Supported);
3728     ShowItem_Bool ( IDX_COMPRESS_NT_SECUR,        cd->NtSecurity.Supported);
3729 
3730     ShowItem_Bool ( IDG_COMPRESS_NTFS,
3731            cd->SymLinks.Supported
3732         || cd->HardLinks.Supported
3733         || cd->AltStreams.Supported
3734         || cd->NtSecurity.Supported);
3735   }
3736 
3737    /* we read property from two sources:
3738        1) command line  : (Info)
3739        2) registry      : (m_RegistryInfo)
3740      (Info) has priority, if both are no defined */
3741 
3742   CheckButton_Bool1 ( IDX_COMPRESS_NT_SYM_LINKS,   cd->SymLinks);
3743   CheckButton_Bool1 ( IDX_COMPRESS_NT_HARD_LINKS,  cd->HardLinks);
3744   CheckButton_Bool1 ( IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams);
3745   CheckButton_Bool1 ( IDX_COMPRESS_NT_SECUR,       cd->NtSecurity);
3746 
3747   CheckButton_Bool1 (IDX_COMPRESS_PRESERVE_ATIME, cd->PreserveATime);
3748 
3749   m_Prec.Attach (GetItem(IDC_COMPRESS_TIME_PREC));
3750 
3751   MTime.SetIDs ( IDX_COMPRESS_MTIME, IDX_COMPRESS_MTIME_SET);
3752   CTime.SetIDs ( IDX_COMPRESS_CTIME, IDX_COMPRESS_CTIME_SET);
3753   ATime.SetIDs ( IDX_COMPRESS_ATIME, IDX_COMPRESS_ATIME_SET);
3754   ZTime.SetIDs ( IDX_COMPRESS_ZTIME, IDX_COMPRESS_ZTIME_SET);
3755 
3756   {
3757     const NCompression::CFormatOptions &fo = cd->Get_FormatOptions();
3758     TimePrec = fo.TimePrec;
3759     MTime.BoolPair = fo.MTime;
3760     CTime.BoolPair = fo.CTime;
3761     ATime.BoolPair = fo.ATime;
3762     ZTime.BoolPair = fo.SetArcMTime;
3763   }
3764 
3765   SetPrec();
3766 
3767   NormalizePosition();
3768 
3769   return CModalDialog::OnInit();
3770 }
3771 
3772 
OnCommand(unsigned code,unsigned itemID,LPARAM lParam)3773 bool COptionsDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam)
3774 {
3775   if (code == CBN_SELCHANGE)
3776   {
3777     switch (itemID)
3778     {
3779       case IDC_COMPRESS_TIME_PREC:
3780       {
3781         Store_TimeBoxes();
3782         SetTimeMAC(); // for zip/tar
3783         return true;
3784       }
3785     }
3786   }
3787   return CModalDialog::OnCommand(code, itemID, lParam);
3788 }
3789 
3790 
OnButtonClicked(unsigned buttonID,HWND buttonHWND)3791 bool COptionsDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
3792 {
3793   switch (buttonID)
3794   {
3795     case IDX_COMPRESS_PREC_SET:  { On_CheckBoxSet_Prec_Clicked(); return true; }
3796     case IDX_COMPRESS_MTIME_SET: { On_CheckBoxSet_Clicked (MTime); return true; }
3797     case IDX_COMPRESS_CTIME_SET: { On_CheckBoxSet_Clicked (CTime); return true; }
3798     case IDX_COMPRESS_ATIME_SET: { On_CheckBoxSet_Clicked (ATime); return true; }
3799     case IDX_COMPRESS_ZTIME_SET: { On_CheckBoxSet_Clicked (ZTime); return true; }
3800   }
3801   return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
3802 }
3803 
3804 
OnOK()3805 void COptionsDialog::OnOK()
3806 {
3807   GetButton_Bool1 (IDX_COMPRESS_NT_SYM_LINKS,   cd->SymLinks);
3808   GetButton_Bool1 (IDX_COMPRESS_NT_HARD_LINKS,  cd->HardLinks);
3809   GetButton_Bool1 (IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams);
3810   GetButton_Bool1 (IDX_COMPRESS_NT_SECUR,       cd->NtSecurity);
3811   GetButton_Bool1 (IDX_COMPRESS_PRESERVE_ATIME, cd->PreserveATime);
3812 
3813   Store_TimeBoxes();
3814   {
3815     NCompression::CFormatOptions &fo = cd->Get_FormatOptions();
3816     fo.TimePrec = TimePrec;
3817     fo.MTime = MTime.BoolPair;
3818     fo.CTime = CTime.BoolPair;
3819     fo.ATime = ATime.BoolPair;
3820     fo.SetArcMTime = ZTime.BoolPair;
3821   }
3822 
3823   CModalDialog::OnOK();
3824 }
3825 
OnHelp()3826 void COptionsDialog::OnHelp()
3827 {
3828   ShowHelpWindow(kHelpTopic_Options);
3829 }
3830