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