// CompressDialog.cpp #include "StdAfx.h" #include "resource.h" #include "Common/Defs.h" #include "Common/StringConvert.h" #include "Common/IntToString.h" #include "Windows/CommonDialog.h" #include "Windows/FileDir.h" #include "Windows/FileName.h" #include "Windows/ResourceString.h" #include "Windows/System.h" #include "../FileManager/HelpUtils.h" #include "../FileManager/SplitUtils.h" #include "../FileManager/FormatUtils.h" #include "../Explorer/MyMessages.h" #include "../Common/ZipRegistry.h" #include "CompressDialog.h" #ifndef _UNICODE extern bool g_IsNT; #endif #ifdef LANG #include "../FileManager/LangUtils.h" #endif #include "CompressDialogRes.h" #define MY_SIZE_OF_ARRAY(x) (sizeof(x) / sizeof(x[0])) #ifdef LANG static CIDLangPair kIDLangPairs[] = { { IDC_STATIC_COMPRESS_ARCHIVE, 0x02000D01 }, { IDC_STATIC_COMPRESS_FORMAT, 0x02000D03 }, { IDC_STATIC_COMPRESS_LEVEL, 0x02000D0B }, { IDC_STATIC_COMPRESS_METHOD, 0x02000D04 }, { IDC_STATIC_COMPRESS_DICTIONARY, 0x02000D0C }, { IDC_STATIC_COMPRESS_ORDER, 0x02000D0D }, { IDC_STATIC_COMPRESS_MEMORY, 0x02000D0E }, { IDC_STATIC_COMPRESS_MEMORY_DE, 0x02000D0F }, { IDC_STATIC_COMPRESS_THREADS, 0x02000D12 }, { IDC_STATIC_COMPRESS_SOLID, 0x02000D13 }, { IDC_STATIC_COMPRESS_VOLUME, 0x02000D40 }, { IDC_STATIC_COMPRESS_PARAMETERS, 0x02000D06 }, { IDC_STATIC_COMPRESS_UPDATE_MODE, 0x02000D02 }, { IDC_STATIC_COMPRESS_OPTIONS, 0x02000D07 }, { IDC_COMPRESS_SFX, 0x02000D08 }, { IDC_COMPRESS_SHARED, 0x02000D16 }, { IDC_COMPRESS_ENCRYPTION, 0x02000D10 }, { IDC_STATIC_COMPRESS_PASSWORD1, 0x02000B01 }, { IDC_STATIC_COMPRESS_PASSWORD2, 0x02000B03 }, { IDC_COMPRESS_CHECK_SHOW_PASSWORD, 0x02000B02 }, { IDC_STATIC_COMPRESS_ENCRYPTION_METHOD, 0x02000D11 }, { IDC_COMPRESS_CHECK_ENCRYPT_FILE_NAMES, 0x02000D0A }, { IDOK, 0x02000702 }, { IDCANCEL, 0x02000710 }, { IDHELP, 0x02000720 } }; #endif using namespace NWindows; using namespace NFile; using namespace NName; using namespace NDirectory; static const int kHistorySize = 20; static LPCWSTR kExeExt = L".exe"; static LPCWSTR k7zFormat = L"7z"; struct CLevelInfo { UInt32 ResourceID; UInt32 LangID; }; enum ELevel { kStore = 0, kFastest = 1, kFast = 3, kNormal = 5, kMaximum = 7, kUltra = 9 }; static const CLevelInfo g_Levels[] = { { IDS_METHOD_STORE, 0x02000D81 }, { IDS_METHOD_FASTEST, 0x02000D85 }, { 0, 0 }, { IDS_METHOD_FAST, 0x02000D84 }, { 0, 0 }, { IDS_METHOD_NORMAL, 0x02000D82 }, { 0, 0 }, { IDS_METHOD_MAXIMUM, 0x02000D83 }, { 0, 0 }, { IDS_METHOD_ULTRA, 0x02000D86 } }; enum EMethodID { kCopy, kLZMA, kPPMd, kBZip2, kDeflate, kDeflate64 }; static const LPCWSTR kMethodsNames[] = { L"Copy", L"LZMA", L"PPMd", L"BZip2", L"Deflate", L"Deflate64" }; static const EMethodID g_7zMethods[] = { kLZMA, kPPMd, kBZip2 }; static const EMethodID g_7zSfxMethods[] = { kCopy, kLZMA, kPPMd }; static EMethodID g_ZipMethods[] = { kDeflate, kDeflate64, kBZip2, kLZMA }; static EMethodID g_GZipMethods[] = { kDeflate }; static EMethodID g_BZip2Methods[] = { kBZip2 }; struct CFormatInfo { LPCWSTR Name; UInt32 LevelsMask; const EMethodID *MathodIDs; int NumMethods; bool Filter; bool Solid; bool MultiThread; bool SFX; bool Encrypt; bool EncryptFileNames; }; #define METHODS_PAIR(x) x, MY_SIZE_OF_ARRAY(x) static const CFormatInfo g_Formats[] = { { L"", (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), 0, 0, false, false, false, false, false, false }, { k7zFormat, (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), METHODS_PAIR(g_7zMethods), true, true, true, true, true, true }, { L"Zip", (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), METHODS_PAIR(g_ZipMethods), false, false, true, false, true, false }, { L"GZip", (1 << 1) | (1 << 5) | (1 << 7) | (1 << 9), METHODS_PAIR(g_GZipMethods), false, false, false, false, false, false }, { L"BZip2", (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), METHODS_PAIR(g_BZip2Methods), false, false, true, false, false }, { L"Tar", (1 << 0), 0, 0, false, false, false, false, false, false } }; static bool IsMethodSupportedBySfx(int methodID) { for (int i = 0; i < MY_SIZE_OF_ARRAY(g_7zSfxMethods); i++) if (methodID == g_7zSfxMethods[i]) return true; return false; }; static UInt64 GetMaxRamSizeForProgram() { UInt64 physSize = NSystem::GetRamSize(); const UInt64 kMinSysSize = (1 << 24); if (physSize <= kMinSysSize) physSize = 0; else physSize -= kMinSysSize; const UInt64 kMinUseSize = (1 << 25); if (physSize < kMinUseSize) physSize = kMinUseSize; return physSize; } bool CCompressDialog::OnInit() { #ifdef LANG LangSetWindowText(HWND(*this), 0x02000D00); LangSetDlgItemsText(HWND(*this), kIDLangPairs, MY_SIZE_OF_ARRAY(kIDLangPairs) ); #endif _password1Control.Attach(GetItem(IDC_COMPRESS_EDIT_PASSWORD1)); _password2Control.Attach(GetItem(IDC_COMPRESS_EDIT_PASSWORD2)); _password1Control.SetText(Info.Password); _password2Control.SetText(Info.Password); _encryptionMethod.Attach(GetItem(IDC_COMPRESS_COMBO_ENCRYPTION_METHOD)); m_ArchivePath.Attach(GetItem(IDC_COMPRESS_COMBO_ARCHIVE)); m_Format.Attach(GetItem(IDC_COMPRESS_COMBO_FORMAT)); m_Level.Attach(GetItem(IDC_COMPRESS_COMBO_LEVEL)); m_Method.Attach(GetItem(IDC_COMPRESS_COMBO_METHOD)); m_Dictionary.Attach(GetItem(IDC_COMPRESS_COMBO_DICTIONARY)); m_Order.Attach(GetItem(IDC_COMPRESS_COMBO_ORDER)); m_Solid.Attach(GetItem(IDC_COMPRESS_COMBO_SOLID)); m_NumThreads.Attach(GetItem(IDC_COMPRESS_COMBO_THREADS)); m_UpdateMode.Attach(GetItem(IDC_COMPRESS_COMBO_UPDATE_MODE)); m_Volume.Attach(GetItem(IDC_COMPRESS_COMBO_VOLUME)); m_Params.Attach(GetItem(IDC_COMPRESS_EDIT_PARAMETERS)); AddVolumeItems(m_Volume); ReadCompressionInfo(m_RegistryInfo); CheckButton(IDC_COMPRESS_CHECK_SHOW_PASSWORD, m_RegistryInfo.ShowPassword); CheckButton(IDC_COMPRESS_CHECK_ENCRYPT_FILE_NAMES, m_RegistryInfo.EncryptHeaders); UpdatePasswordControl(); Info.ArchiverInfoIndex = 0; int i; for(i = 0; i < m_ArchiverInfoList.Size(); i++) { const CArcInfoEx &ai = m_ArchiverInfoList[i]; m_Format.AddString(ai.Name); if (ai.Name.CompareNoCase(m_RegistryInfo.ArchiveType) == 0) Info.ArchiverInfoIndex = i; } m_Format.SetCurSel(Info.ArchiverInfoIndex); SetArchiveName(Info.ArchiveName); SetLevel(); SetParams(); for(i = 0; i < m_RegistryInfo.HistoryArchives.Size() && i < kHistorySize; i++) m_ArchivePath.AddString(m_RegistryInfo.HistoryArchives[i]); m_UpdateMode.AddString(LangString(IDS_COMPRESS_UPDATE_MODE_ADD, 0x02000DA1)); m_UpdateMode.AddString(LangString(IDS_COMPRESS_UPDATE_MODE_UPDATE, 0x02000DA2)); m_UpdateMode.AddString(LangString(IDS_COMPRESS_UPDATE_MODE_FRESH, 0x02000DA3)); m_UpdateMode.AddString(LangString(IDS_COMPRESS_UPDATE_MODE_SYNCHRONIZE, 0x02000DA4)); m_UpdateMode.SetCurSel(0); SetSolidBlockSize(); SetNumThreads(); TCHAR s[40] = { TEXT('/'), TEXT(' '), 0 }; ConvertUInt64ToString(NSystem::GetNumberOfProcessors(), s + 2); SetItemText(IDC_COMPRESS_HARDWARE_THREADS, s); CheckButton(IDC_COMPRESS_SFX, Info.SFXMode); CheckButton(IDC_COMPRESS_SHARED, Info.OpenShareForWrite); CheckControlsEnable(); OnButtonSFX(); SetEncryptionMethod(); SetMemoryUsage(); return CModalDialog::OnInit(); } namespace NCompressDialog { bool CInfo::GetFullPathName(UString &result) const { NDirectory::MySetCurrentDirectory(CurrentDirPrefix); return MyGetFullPathName(ArchiveName, result); } } void CCompressDialog::UpdatePasswordControl() { bool showPassword = IsShowPasswordChecked(); TCHAR c = showPassword ? 0: TEXT('*'); _password1Control.SetPasswordChar(c); _password2Control.SetPasswordChar(c); UString password; _password1Control.GetText(password); _password1Control.SetText(password); _password2Control.GetText(password); _password2Control.SetText(password); int cmdShow = showPassword ? SW_HIDE : SW_SHOW; ShowItem(IDC_STATIC_COMPRESS_PASSWORD2, cmdShow); _password2Control.Show(cmdShow); } bool CCompressDialog::OnButtonClicked(int buttonID, HWND buttonHWND) { switch(buttonID) { case IDC_COMPRESS_BUTTON_SET_ARCHIVE: { OnButtonSetArchive(); return true; } case IDC_COMPRESS_SFX: { OnButtonSFX(); SetMemoryUsage(); return true; } case IDC_COMPRESS_CHECK_SHOW_PASSWORD: { UpdatePasswordControl(); return true; } } return CModalDialog::OnButtonClicked(buttonID, buttonHWND); } void CCompressDialog::CheckSFXControlsEnable() { const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; bool enable = fi.SFX; if (enable) { int methodID = GetMethodID(); enable = (methodID == -1 || IsMethodSupportedBySfx(methodID)); } if (!enable) CheckButton(IDC_COMPRESS_SFX, false); EnableItem(IDC_COMPRESS_SFX, enable); } void CCompressDialog::CheckVolumeEnable() { bool isSFX = IsSFX(); m_Volume.Enable(!isSFX); if (isSFX) m_Volume.SetText(TEXT("")); } void CCompressDialog::CheckControlsEnable() { const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; Info.SolidIsSpecified = fi.Solid; bool multiThreadEnable = fi.MultiThread; Info.MultiThreadIsAllowed = multiThreadEnable; Info.EncryptHeadersIsAllowed = fi.EncryptFileNames; EnableItem(IDC_COMPRESS_COMBO_SOLID, fi.Solid); EnableItem(IDC_COMPRESS_COMBO_THREADS, multiThreadEnable); CheckSFXControlsEnable(); CheckVolumeEnable(); EnableItem(IDC_COMPRESS_ENCRYPTION, fi.Encrypt); EnableItem(IDC_STATIC_COMPRESS_PASSWORD1, fi.Encrypt); EnableItem(IDC_STATIC_COMPRESS_PASSWORD2, fi.Encrypt); EnableItem(IDC_COMPRESS_EDIT_PASSWORD1, fi.Encrypt); EnableItem(IDC_COMPRESS_EDIT_PASSWORD2, fi.Encrypt); EnableItem(IDC_COMPRESS_CHECK_SHOW_PASSWORD, fi.Encrypt); EnableItem(IDC_STATIC_COMPRESS_ENCRYPTION_METHOD, fi.Encrypt); EnableItem(IDC_COMPRESS_COMBO_ENCRYPTION_METHOD, fi.Encrypt); EnableItem(IDC_COMPRESS_CHECK_ENCRYPT_FILE_NAMES, fi.EncryptFileNames); ShowItem(IDC_COMPRESS_CHECK_ENCRYPT_FILE_NAMES, fi.EncryptFileNames ? SW_SHOW : SW_HIDE); } bool CCompressDialog::IsSFX() { CWindow sfxButton = GetItem(IDC_COMPRESS_SFX); return sfxButton.IsEnabled() && IsButtonCheckedBool(IDC_COMPRESS_SFX); } void CCompressDialog::OnButtonSFX() { SetMethod(); UString fileName; m_ArchivePath.GetText(fileName); int dotPos = fileName.ReverseFind(L'.'); int slashPos = fileName.ReverseFind(WCHAR_PATH_SEPARATOR); if (dotPos < 0 || dotPos <= slashPos) dotPos = -1; bool isSFX = IsSFX(); if (isSFX) { if (dotPos >= 0) fileName = fileName.Left(dotPos); fileName += kExeExt; m_ArchivePath.SetText(fileName); } else { if (dotPos >= 0) { UString ext = fileName.Mid(dotPos); if (ext.CompareNoCase(kExeExt) == 0) { fileName = fileName.Left(dotPos); m_ArchivePath.SetText(fileName); } } SetArchiveName2(false); // it's for OnInit } CheckVolumeEnable(); } void CCompressDialog::OnButtonSetArchive() { UString fileName; m_ArchivePath.GetText(fileName); fileName.Trim(); Info.ArchiveName = fileName; UString fullFileName; if (!Info.GetFullPathName(fullFileName)) { fullFileName = Info.ArchiveName; return; } UString title = LangString(IDS_COMPRESS_SET_ARCHIVE_DIALOG_TITLE, 0x02000D90); UString s = LangString(IDS_OPEN_TYPE_ALL_FILES, 0x02000DB1); s += L" (*.*)"; UString resPath; if (!MyGetOpenFileName(HWND(*this), title, fullFileName, s, resPath)) return; m_ArchivePath.SetText(resPath); } // in ExtractDialog.cpp extern void AddUniqueString(UStringVector &strings, const UString &srcString); static bool IsAsciiString(const UString &s) { for (int i = 0; i < s.Length(); i++) { wchar_t c = s[i]; if (c < 0x20 || c > 0x7F) return false; } return true; } void CCompressDialog::OnOK() { _password1Control.GetText(Info.Password); if (IsZipFormat()) { if (!IsAsciiString(Info.Password)) { ShowErrorMessageHwndRes(*this, IDS_PASSWORD_USE_ASCII, 0x02000B11); return; } UString method = GetEncryptionMethodSpec(); method.MakeUpper(); if (method.Find(L"AES") == 0) { if (Info.Password.Length() > 99) { ShowErrorMessageHwndRes(*this, IDS_PASSWORD_IS_TOO_LONG, 0x02000B12); return; } } } if (!IsShowPasswordChecked()) { UString password2; _password2Control.GetText(password2); if (password2 != Info.Password) { ShowErrorMessageHwndRes(*this, IDS_PASSWORD_PASSWORDS_DO_NOT_MATCH, 0x02000B10); return; } } SaveOptionsInMem(); UString s; m_ArchivePath.GetText(s); s.Trim(); m_RegistryInfo.HistoryArchives.Clear(); AddUniqueString(m_RegistryInfo.HistoryArchives, s); Info.ArchiveName = s; Info.UpdateMode = NCompressDialog::NUpdateMode::EEnum(m_UpdateMode.GetCurSel()); Info.Level = GetLevelSpec(); Info.Dictionary = GetDictionarySpec(); Info.Order = GetOrderSpec(); Info.OrderMode = GetOrderMode(); Info.NumThreads = GetNumThreadsSpec(); UInt32 solidLogSize = GetBlockSizeSpec(); Info.SolidBlockSize = 0; if (solidLogSize > 0 && solidLogSize != (UInt32)-1) Info.SolidBlockSize = (solidLogSize >= 64) ? (UInt64)(Int64)-1 : ((UInt64)1 << solidLogSize); Info.Method = GetMethodSpec(); Info.EncryptionMethod = GetEncryptionMethodSpec(); Info.ArchiverInfoIndex = m_Format.GetCurSel(); Info.SFXMode = IsSFX(); Info.OpenShareForWrite = IsButtonCheckedBool(IDC_COMPRESS_SHARED); m_RegistryInfo.EncryptHeaders = Info.EncryptHeaders = IsButtonCheckedBool(IDC_COMPRESS_CHECK_ENCRYPT_FILE_NAMES); m_Params.GetText(Info.Options); UString volumeString; m_Volume.GetText(volumeString); volumeString.Trim(); Info.VolumeSizes.Clear(); if (!volumeString.IsEmpty()) { if (!ParseVolumeSizes(volumeString, Info.VolumeSizes)) { ShowErrorMessageHwndRes(*this, IDS_COMPRESS_INCORRECT_VOLUME_SIZE, 0x02000D41); return; } if (!Info.VolumeSizes.IsEmpty()) { const UInt64 volumeSize = Info.VolumeSizes.Back(); if (volumeSize < (100 << 10)) { wchar_t s[32]; ConvertUInt64ToString(volumeSize, s); if (::MessageBoxW(*this, MyFormatNew(IDS_COMPRESS_SPLIT_CONFIRM_MESSAGE, 0x02000D42, s), L"7-Zip", MB_YESNOCANCEL | MB_ICONQUESTION | MB_TASKMODAL) != IDYES) return; } } } for(int i = 0; i < m_ArchivePath.GetCount(); i++) { UString sTemp; m_ArchivePath.GetLBText(i, sTemp); sTemp.Trim(); AddUniqueString(m_RegistryInfo.HistoryArchives, sTemp); } if (m_RegistryInfo.HistoryArchives.Size() > kHistorySize) m_RegistryInfo.HistoryArchives.DeleteBack(); m_RegistryInfo.ArchiveType = m_ArchiverInfoList[Info.ArchiverInfoIndex].Name; m_RegistryInfo.ShowPassword = IsShowPasswordChecked(); SaveCompressionInfo(m_RegistryInfo); CModalDialog::OnOK(); } static LPCWSTR kHelpTopic = L"fm/plugins/7-zip/add.htm"; void CCompressDialog::OnHelp() { ShowHelpWindow(NULL, kHelpTopic); } bool CCompressDialog::OnCommand(int code, int itemID, LPARAM lParam) { if (code == CBN_SELCHANGE) { switch(itemID) { case IDC_COMPRESS_COMBO_FORMAT: { bool isSFX = IsSFX(); SaveOptionsInMem(); SetLevel(); SetSolidBlockSize(); SetNumThreads(); SetParams(); CheckControlsEnable(); SetArchiveName2(isSFX); SetEncryptionMethod(); SetMemoryUsage(); return true; } case IDC_COMPRESS_COMBO_LEVEL: { const CArcInfoEx &ai = m_ArchiverInfoList[m_Format.GetCurSel()]; int index = FindRegistryFormatAlways(ai.Name); NCompression::CFormatOptions &fo = m_RegistryInfo.FormatOptionsVector[index]; fo.ResetForLevelChange(); SetMethod(); SetSolidBlockSize(); SetNumThreads(); CheckSFXNameChange(); SetMemoryUsage(); return true; } case IDC_COMPRESS_COMBO_METHOD: { SetDictionary(); SetOrder(); SetSolidBlockSize(); SetNumThreads(); CheckSFXNameChange(); SetMemoryUsage(); return true; } case IDC_COMPRESS_COMBO_DICTIONARY: case IDC_COMPRESS_COMBO_ORDER: { SetSolidBlockSize(); SetMemoryUsage(); return true; } case IDC_COMPRESS_COMBO_THREADS: { SetMemoryUsage(); return true; } } } return CModalDialog::OnCommand(code, itemID, lParam); } void CCompressDialog::CheckSFXNameChange() { bool isSFX = IsSFX(); CheckSFXControlsEnable(); if (isSFX != IsSFX()) SetArchiveName2(isSFX); } void CCompressDialog::SetArchiveName2(bool prevWasSFX) { UString fileName; m_ArchivePath.GetText(fileName); const CArcInfoEx &prevArchiverInfo = m_ArchiverInfoList[m_PrevFormat]; if (prevArchiverInfo.KeepName || Info.KeepName) { UString prevExtension = prevArchiverInfo.GetMainExt(); if (prevWasSFX) prevExtension = kExeExt; else prevExtension = UString('.') + prevExtension; const int prevExtensionLen = prevExtension.Length(); if (fileName.Length() >= prevExtensionLen) if (fileName.Right(prevExtensionLen).CompareNoCase(prevExtension) == 0) fileName = fileName.Left(fileName.Length() - prevExtensionLen); } SetArchiveName(fileName); } // if type.KeepName then use OriginalFileName // else if !KeepName remove extension // add new extension void CCompressDialog::SetArchiveName(const UString &name) { UString fileName = name; Info.ArchiverInfoIndex = m_Format.GetCurSel(); const CArcInfoEx &ai = m_ArchiverInfoList[Info.ArchiverInfoIndex]; m_PrevFormat = Info.ArchiverInfoIndex; if (ai.KeepName) { fileName = OriginalFileName; } else { if (!Info.KeepName) { int dotPos = fileName.ReverseFind('.'); int slashPos = MyMax(fileName.ReverseFind(WCHAR_PATH_SEPARATOR), fileName.ReverseFind('/')); if (dotPos >= 0 && dotPos > slashPos + 1) fileName = fileName.Left(dotPos); } } if (IsSFX()) fileName += kExeExt; else { fileName += L'.'; fileName += ai.GetMainExt(); } m_ArchivePath.SetText(fileName); } int CCompressDialog::FindRegistryFormat(const UString &name) { for (int i = 0; i < m_RegistryInfo.FormatOptionsVector.Size(); i++) { const NCompression::CFormatOptions &fo = m_RegistryInfo.FormatOptionsVector[i]; if (GetUnicodeString(fo.FormatID) == name) return i; } return -1; } int CCompressDialog::FindRegistryFormatAlways(const UString &name) { int index = FindRegistryFormat(name); if (index < 0) { NCompression::CFormatOptions fo; fo.FormatID = GetSystemString(name); index = m_RegistryInfo.FormatOptionsVector.Add(fo); } return index; } int CCompressDialog::GetStaticFormatIndex() { int formatIndex = m_Format.GetCurSel(); const CArcInfoEx &ai = m_ArchiverInfoList[formatIndex]; for (int i = 0; i < MY_SIZE_OF_ARRAY(g_Formats); i++) if (ai.Name.CompareNoCase(g_Formats[i].Name) == 0) return i; return 0; // -1; } void CCompressDialog::SetNearestSelectComboBox(NControl::CComboBox &comboBox, UInt32 value) { for (int i = comboBox.GetCount() - 1; i >= 0; i--) if ((UInt32)comboBox.GetItemData(i) <= value) { comboBox.SetCurSel(i); return; } if (comboBox.GetCount() > 0) comboBox.SetCurSel(0); } void CCompressDialog::SetLevel() { m_Level.ResetContent(); const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; const CArcInfoEx &ai = m_ArchiverInfoList[m_Format.GetCurSel()]; int index = FindRegistryFormat(ai.Name); UInt32 level = kNormal; if (index >= 0) { const NCompression::CFormatOptions &fo = m_RegistryInfo.FormatOptionsVector[index]; if (fo.Level <= kUltra) level = fo.Level; else level = kUltra; } int i; for (i = 0; i <= kUltra; i++) { if ((fi.LevelsMask & (1 << i)) != 0) { const CLevelInfo &levelInfo = g_Levels[i]; int index = (int)m_Level.AddString(LangString(levelInfo.ResourceID, levelInfo.LangID)); m_Level.SetItemData(index, i); } } SetNearestSelectComboBox(m_Level, level); SetMethod(); } void CCompressDialog::SetMethod() { m_Method.ResetContent(); UInt32 level = GetLevel(); if (level == 0) { SetDictionary(); SetOrder(); return; } const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; const CArcInfoEx &ai = m_ArchiverInfoList[m_Format.GetCurSel()]; int index = FindRegistryFormat(ai.Name); UString defaultMethod; if (index >= 0) { const NCompression::CFormatOptions &fo = m_RegistryInfo.FormatOptionsVector[index]; defaultMethod = fo.Method; } bool isSfx = IsSFX(); for(int m = 0; m < fi.NumMethods; m++) { EMethodID methodID = fi.MathodIDs[m]; if (isSfx) if (!IsMethodSupportedBySfx(methodID)) continue; const LPCWSTR method = kMethodsNames[methodID]; int itemIndex = (int)m_Method.AddString(GetSystemString(method)); if (defaultMethod.CompareNoCase(method) == 0 || m == 0) m_Method.SetCurSel(itemIndex); } SetDictionary(); SetOrder(); } bool CCompressDialog::IsZipFormat() { const CArcInfoEx &ai = m_ArchiverInfoList[m_Format.GetCurSel()]; return (ai.Name.CompareNoCase(L"zip") == 0); } void CCompressDialog::SetEncryptionMethod() { _encryptionMethod.ResetContent(); const CArcInfoEx &ai = m_ArchiverInfoList[m_Format.GetCurSel()]; if (ai.Name.CompareNoCase(L"7z") == 0) { _encryptionMethod.AddString(TEXT("AES-256")); _encryptionMethod.SetCurSel(0); } else if (ai.Name.CompareNoCase(L"zip") == 0) { int index = FindRegistryFormat(ai.Name); UString encryptionMethod; if (index >= 0) { const NCompression::CFormatOptions &fo = m_RegistryInfo.FormatOptionsVector[index]; encryptionMethod = fo.EncryptionMethod; } _encryptionMethod.AddString(TEXT("ZipCrypto")); _encryptionMethod.AddString(TEXT("AES-256")); _encryptionMethod.SetCurSel(encryptionMethod.Find(L"AES") == 0 ? 1 : 0); } } int CCompressDialog::GetMethodID() { UString methodName; m_Method.GetText(methodName); for (int i = 0; i < MY_SIZE_OF_ARRAY(kMethodsNames); i++) if (methodName.CompareNoCase(kMethodsNames[i]) == 0) return i; return -1; } UString CCompressDialog::GetMethodSpec() { if (m_Method.GetCount() <= 1) return UString(); UString result; m_Method.GetText(result); return result; } UString CCompressDialog::GetEncryptionMethodSpec() { if (_encryptionMethod.GetCount() <= 1) return UString(); if (_encryptionMethod.GetCurSel() <= 0) return UString(); UString result; _encryptionMethod.GetText(result); result.Replace(L"-", L""); return result; } int CCompressDialog::AddDictionarySize(UInt32 size, bool kilo, bool maga) { UInt32 sizePrint = size; if (kilo) sizePrint >>= 10; else if (maga) sizePrint >>= 20; TCHAR s[40]; ConvertUInt64ToString(sizePrint, s); if (kilo) lstrcat(s, TEXT(" K")); else if (maga) lstrcat(s, TEXT(" M")); else lstrcat(s, TEXT(" ")); lstrcat(s, TEXT("B")); int index = (int)m_Dictionary.AddString(s); m_Dictionary.SetItemData(index, size); return index; } int CCompressDialog::AddDictionarySize(UInt32 size) { if (size > 0) { if ((size & 0xFFFFF) == 0) return AddDictionarySize(size, false, true); if ((size & 0x3FF) == 0) return AddDictionarySize(size, true, false); } return AddDictionarySize(size, false, false); } void CCompressDialog::SetDictionary() { m_Dictionary.ResetContent(); const CArcInfoEx &ai = m_ArchiverInfoList[m_Format.GetCurSel()]; int index = FindRegistryFormat(ai.Name); UInt32 defaultDictionary = UInt32(-1); if (index >= 0) { const NCompression::CFormatOptions &fo = m_RegistryInfo.FormatOptionsVector[index]; if (fo.Method.CompareNoCase(GetMethodSpec()) == 0) defaultDictionary = fo.Dictionary; } int methodID = GetMethodID(); UInt32 level = GetLevel2(); if (methodID < 0) return; const UInt64 maxRamSize = GetMaxRamSizeForProgram(); switch (methodID) { case kLZMA: { static const UInt32 kMinDicSize = (1 << 16); if (defaultDictionary == UInt32(-1)) { if (level >= 9) defaultDictionary = (1 << 26); else if (level >= 7) defaultDictionary = (1 << 25); else if (level >= 5) defaultDictionary = (1 << 24); else if (level >= 3) defaultDictionary = (1 << 20); else defaultDictionary = (kMinDicSize); } int i; AddDictionarySize(kMinDicSize); m_Dictionary.SetCurSel(0); for (i = 20; i <= 30; i++) for (int j = 0; j < 2; j++) { if (i == 20 && j > 0) continue; UInt32 dictionary = (1 << i) + (j << (i - 1)); if (dictionary > #ifdef _WIN64 (1 << 30) #else (1 << 26) #endif ) continue; AddDictionarySize(dictionary); UInt64 decomprSize; UInt64 requiredComprSize = GetMemoryUsage(dictionary, decomprSize); if (dictionary <= defaultDictionary && requiredComprSize <= maxRamSize) m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1); } // SetNearestSelectComboBox(m_Dictionary, defaultDictionary); break; } case kPPMd: { if (defaultDictionary == UInt32(-1)) { if (level >= 9) defaultDictionary = (192 << 20); else if (level >= 7) defaultDictionary = ( 64 << 20); else if (level >= 5) defaultDictionary = ( 16 << 20); else defaultDictionary = ( 4 << 20); } int i; for (i = 20; i < 31; i++) for (int j = 0; j < 2; j++) { if (i == 20 && j > 0) continue; UInt32 dictionary = (1 << i) + (j << (i - 1)); if (dictionary >= (1 << 31)) continue; AddDictionarySize(dictionary); UInt64 decomprSize; UInt64 requiredComprSize = GetMemoryUsage(dictionary, decomprSize); if (dictionary <= defaultDictionary && requiredComprSize <= maxRamSize || m_Dictionary.GetCount() == 0) m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1); } SetNearestSelectComboBox(m_Dictionary, defaultDictionary); break; } case kDeflate: { AddDictionarySize(32 << 10); m_Dictionary.SetCurSel(0); break; } case kDeflate64: { AddDictionarySize(64 << 10); m_Dictionary.SetCurSel(0); break; } case kBZip2: { // UInt32 defaultDictionary; if (defaultDictionary == UInt32(-1)) { if (level >= 5) defaultDictionary = (900 << 10); else if (level >= 3) defaultDictionary = (500 << 10); else defaultDictionary = (100 << 10); } for (int i = 1; i <= 9; i++) { UInt32 dictionary = (i * 100) << 10; AddDictionarySize(dictionary); if (dictionary <= defaultDictionary || m_Dictionary.GetCount() == 0) m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1); } break; } } } UInt32 CCompressDialog::GetComboValue(NWindows::NControl::CComboBox &c, int defMax) { if (c.GetCount() <= defMax) return (UInt32)-1; return (UInt32)c.GetItemData(c.GetCurSel()); } UInt32 CCompressDialog::GetLevel2() { UInt32 level = GetLevel(); if (level == (UInt32)-1) level = 5; return level; } int CCompressDialog::AddOrder(UInt32 size) { TCHAR s[40]; ConvertUInt64ToString(size, s); int index = (int)m_Order.AddString(s); m_Order.SetItemData(index, size); return index; } void CCompressDialog::SetOrder() { m_Order.ResetContent(); const CArcInfoEx &ai = m_ArchiverInfoList[m_Format.GetCurSel()]; int index = FindRegistryFormat(ai.Name); UInt32 defaultOrder = UInt32(-1); if (index >= 0) { const NCompression::CFormatOptions &fo = m_RegistryInfo.FormatOptionsVector[index]; if (fo.Method.CompareNoCase(GetMethodSpec()) == 0) defaultOrder = fo.Order; } int methodID = GetMethodID(); UInt32 level = GetLevel2(); if (methodID < 0) return; switch (methodID) { case kLZMA: { if (defaultOrder == UInt32(-1)) defaultOrder = (level >= 7) ? 64 : 32; for (int i = 3; i <= 8; i++) for (int j = 0; j < 2; j++) { UInt32 order = (1 << i) + (j << (i - 1)); if (order <= 256) AddOrder(order); } AddOrder(273); SetNearestSelectComboBox(m_Order, defaultOrder); break; } case kPPMd: { if (defaultOrder == UInt32(-1)) { if (level >= 9) defaultOrder = 32; else if (level >= 7) defaultOrder = 16; else if (level >= 5) defaultOrder = 6; else defaultOrder = 4; } int i; AddOrder(2); AddOrder(3); for (i = 2; i < 8; i++) for (int j = 0; j < 4; j++) { UInt32 order = (1 << i) + (j << (i - 2)); if (order < 32) AddOrder(order); } AddOrder(32); SetNearestSelectComboBox(m_Order, defaultOrder); break; } case kDeflate: case kDeflate64: { if (defaultOrder == UInt32(-1)) { if (level >= 9) defaultOrder = 128; else if (level >= 7) defaultOrder = 64; else defaultOrder = 32; } int i; for (i = 3; i <= 8; i++) for (int j = 0; j < 2; j++) { UInt32 order = (1 << i) + (j << (i - 1)); if (order <= 256) AddOrder(order); } AddOrder(methodID == kDeflate64 ? 257 : 258); SetNearestSelectComboBox(m_Order, defaultOrder); break; } case kBZip2: { break; } } } bool CCompressDialog::GetOrderMode() { switch (GetMethodID()) { case kPPMd: return true; } return false; } static const UInt32 kNoSolidBlockSize = 0; static const UInt32 kSolidBlockSize = 64; void CCompressDialog::SetSolidBlockSize() { m_Solid.ResetContent(); const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; if (!fi.Solid) return; UInt32 level = GetLevel2(); if (level == 0) return; UInt32 dictionary = GetDictionarySpec(); if (dictionary == UInt32(-1)) dictionary = 1; UInt32 defaultBlockSize = (UInt32)-1; const CArcInfoEx &ai = m_ArchiverInfoList[m_Format.GetCurSel()]; int index = FindRegistryFormat(ai.Name); if (index >= 0) { const NCompression::CFormatOptions &fo = m_RegistryInfo.FormatOptionsVector[index]; if (fo.Method.CompareNoCase(GetMethodSpec()) == 0) defaultBlockSize = fo.BlockLogSize; } index = (int)m_Solid.AddString(LangString(IDS_COMPRESS_NON_SOLID, 0x02000D14)); m_Solid.SetItemData(index, (UInt32)kNoSolidBlockSize); m_Solid.SetCurSel(0); bool needSet = defaultBlockSize == (UInt32)-1; for (int i = 20; i <= 36; i++) { if (needSet && dictionary >= (((UInt64)1 << (i - 7))) && i <= 32) defaultBlockSize = i; TCHAR s[40]; ConvertUInt64ToString(1 << (i % 10), s); if (i < 30) lstrcat(s, TEXT(" M")); else lstrcat(s, TEXT(" G")); lstrcat(s, TEXT("B")); int index = (int)m_Solid.AddString(s); m_Solid.SetItemData(index, (UInt32)i); } index = (int)m_Solid.AddString(LangString(IDS_COMPRESS_SOLID, 0x02000D15)); m_Solid.SetItemData(index, kSolidBlockSize); if (defaultBlockSize == (UInt32)-1) defaultBlockSize = kSolidBlockSize; if (defaultBlockSize != kNoSolidBlockSize) SetNearestSelectComboBox(m_Solid, defaultBlockSize); } void CCompressDialog::SetNumThreads() { m_NumThreads.ResetContent(); const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; if (!fi.MultiThread) return; UInt32 numHardwareThreads = NSystem::GetNumberOfProcessors(); UInt32 defaultValue = numHardwareThreads; const CArcInfoEx &ai = m_ArchiverInfoList[m_Format.GetCurSel()]; int index = FindRegistryFormat(ai.Name); if (index >= 0) { const NCompression::CFormatOptions &fo = m_RegistryInfo.FormatOptionsVector[index]; if (fo.Method.CompareNoCase(GetMethodSpec()) == 0) defaultValue = fo.NumThreads; } UInt32 numAlgoThreadsMax = 1; int methodID = GetMethodID(); switch (methodID) { case kLZMA: { numAlgoThreadsMax = 2; break; } case kBZip2: { numAlgoThreadsMax = 32; break; } } if (IsZipFormat()) numAlgoThreadsMax = 128; for (UInt32 i = 1; i <= numHardwareThreads * 2 && i <= numAlgoThreadsMax; i++) { TCHAR s[40]; ConvertUInt64ToString(i, s); int index = (int)m_NumThreads.AddString(s); m_NumThreads.SetItemData(index, (UInt32)i); } SetNearestSelectComboBox(m_NumThreads, defaultValue); } UInt64 CCompressDialog::GetMemoryUsage(UInt32 dictionary, UInt64 &decompressMemory) { decompressMemory = UInt64(Int64(-1)); UInt32 level = GetLevel2(); if (level == 0) { decompressMemory = (1 << 20); return decompressMemory; } UInt64 size = 0; const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; if (fi.Filter && level >= 9) size += (12 << 20) * 2 + (5 << 20); UInt32 numThreads = GetNumThreads2(); if (IsZipFormat()) { UInt32 numSubThreads = 1; if (GetMethodID() == kLZMA && numThreads > 1 && level >= 5) numSubThreads = 2; UInt32 numMainThreads = numThreads / numSubThreads; if (numMainThreads > 1) size += (UInt64)numMainThreads << 25; } switch (GetMethodID()) { case kLZMA: { UInt32 hs = dictionary - 1; hs |= (hs >> 1); hs |= (hs >> 2); hs |= (hs >> 4); hs |= (hs >> 8); hs >>= 1; hs |= 0xFFFF; if (hs > (1 << 24)) hs >>= 1; hs++; UInt64 size1 = (UInt64)hs * 4; size1 += (UInt64)dictionary * 11 / 2; if (level >= 5) size1 += (UInt64)dictionary * 4; size1 += (2 << 20); UInt32 numThreads1 = 1; if (numThreads > 1 && level >= 5) { size1 += (2 << 20) + (4 << 20); numThreads1 = 2; } size += size1 * numThreads / numThreads1; decompressMemory = dictionary + (2 << 20); return size; } case kPPMd: { decompressMemory = dictionary + (2 << 20); return size + decompressMemory; } case kDeflate: case kDeflate64: { UInt32 order = GetOrder(); if (order == UInt32(-1)) order = 32; if (level >= 7) size += (1 << 20); size += 3 << 20; decompressMemory = (2 << 20); return size; } case kBZip2: { decompressMemory = (7 << 20); UInt64 memForOneThread = (10 << 20); return size + memForOneThread * numThreads; } } return UInt64(Int64(-1)); } UInt64 CCompressDialog::GetMemoryUsage(UInt64 &decompressMemory) { return GetMemoryUsage(GetDictionary(), decompressMemory); } void CCompressDialog::PrintMemUsage(UINT res, UInt64 value) { if (value == (UInt64)Int64(-1)) { SetItemText(res, TEXT("?")); return; } value = (value + (1 << 20) - 1) >> 20; TCHAR s[40]; ConvertUInt64ToString(value, s); lstrcat(s, TEXT(" MB")); SetItemText(res, s); } void CCompressDialog::SetMemoryUsage() { UInt64 decompressMem; UInt64 memUsage = GetMemoryUsage(decompressMem); PrintMemUsage(IDC_STATIC_COMPRESS_MEMORY_VALUE, memUsage); PrintMemUsage(IDC_STATIC_COMPRESS_MEMORY_DE_VALUE, decompressMem); } void CCompressDialog::SetParams() { const CArcInfoEx &ai = m_ArchiverInfoList[m_Format.GetCurSel()]; m_Params.SetText(TEXT("")); int index = FindRegistryFormat(ai.Name); if (index >= 0) { const NCompression::CFormatOptions &fo = m_RegistryInfo.FormatOptionsVector[index]; m_Params.SetText(fo.Options); } } void CCompressDialog::SaveOptionsInMem() { const CArcInfoEx &ai = m_ArchiverInfoList[Info.ArchiverInfoIndex]; int index = FindRegistryFormatAlways(ai.Name); m_Params.GetText(Info.Options); Info.Options.Trim(); NCompression::CFormatOptions &fo = m_RegistryInfo.FormatOptionsVector[index]; fo.Options = Info.Options; fo.Level = GetLevelSpec(); fo.Dictionary = GetDictionarySpec(); fo.Order = GetOrderSpec(); fo.Method = GetMethodSpec(); fo.EncryptionMethod = GetEncryptionMethodSpec(); fo.NumThreads = GetNumThreadsSpec(); fo.BlockLogSize = GetBlockSizeSpec(); }