mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 17:15:00 -06:00
606 lines
15 KiB
C++
Executable File
606 lines
15 KiB
C++
Executable File
// UpdateGUI.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "../../../Common/IntToString.h"
|
|
#include "../../../Common/StringConvert.h"
|
|
#include "../../../Common/StringToInt.h"
|
|
|
|
#include "../../../Windows/DLL.h"
|
|
#include "../../../Windows/FileDir.h"
|
|
#include "../../../Windows/FileName.h"
|
|
#include "../../../Windows/Thread.h"
|
|
|
|
#include "../Common/WorkDir.h"
|
|
|
|
#include "../Explorer/MyMessages.h"
|
|
|
|
#include "../FileManager/LangUtils.h"
|
|
#include "../FileManager/StringUtils.h"
|
|
#include "../FileManager/resourceGui.h"
|
|
|
|
#include "CompressDialog.h"
|
|
#include "UpdateGUI.h"
|
|
|
|
#include "resource2.h"
|
|
|
|
using namespace NWindows;
|
|
using namespace NFile;
|
|
using namespace NDir;
|
|
|
|
static const char * const kDefaultSfxModule = "7z.sfx";
|
|
static const char * const kSFXExtension = "exe";
|
|
|
|
extern void AddMessageToString(UString &dest, const UString &src);
|
|
|
|
UString HResultToMessage(HRESULT errorCode);
|
|
|
|
class CThreadUpdating: public CProgressThreadVirt
|
|
{
|
|
HRESULT ProcessVirt() Z7_override;
|
|
public:
|
|
CCodecs *codecs;
|
|
const CObjectVector<COpenType> *formatIndices;
|
|
const UString *cmdArcPath;
|
|
CUpdateCallbackGUI *UpdateCallbackGUI;
|
|
NWildcard::CCensor *WildcardCensor;
|
|
CUpdateOptions *Options;
|
|
bool needSetPath;
|
|
};
|
|
|
|
HRESULT CThreadUpdating::ProcessVirt()
|
|
{
|
|
CUpdateErrorInfo ei;
|
|
HRESULT res = UpdateArchive(codecs, *formatIndices, *cmdArcPath,
|
|
*WildcardCensor, *Options,
|
|
ei, UpdateCallbackGUI, UpdateCallbackGUI, needSetPath);
|
|
FinalMessage.ErrorMessage.Message = ei.Message.Ptr();
|
|
ErrorPaths = ei.FileNames;
|
|
if (res != S_OK)
|
|
return res;
|
|
return HRESULT_FROM_WIN32(ei.SystemError);
|
|
}
|
|
|
|
|
|
// parse command line properties
|
|
|
|
static bool ParseProp_Time_BoolPair(const CProperty &prop, const char *name, CBoolPair &bp)
|
|
{
|
|
if (!prop.Name.IsPrefixedBy_Ascii_NoCase(name))
|
|
return false;
|
|
const UString rem = prop.Name.Ptr((unsigned)strlen(name));
|
|
UString val = prop.Value;
|
|
if (!rem.IsEmpty())
|
|
{
|
|
if (!val.IsEmpty())
|
|
return true;
|
|
val = rem;
|
|
}
|
|
bool res;
|
|
if (StringToBool(val, res))
|
|
{
|
|
bp.Val = res;
|
|
bp.Def = true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void ParseProp(
|
|
const CProperty &prop,
|
|
NCompressDialog::CInfo &di)
|
|
{
|
|
if (ParseProp_Time_BoolPair(prop, "tm", di.MTime)) return;
|
|
if (ParseProp_Time_BoolPair(prop, "tc", di.CTime)) return;
|
|
if (ParseProp_Time_BoolPair(prop, "ta", di.ATime)) return;
|
|
}
|
|
|
|
static void ParseProperties(
|
|
const CObjectVector<CProperty> &properties,
|
|
NCompressDialog::CInfo &di)
|
|
{
|
|
FOR_VECTOR (i, properties)
|
|
{
|
|
ParseProp(properties[i], di);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void AddProp_UString(CObjectVector<CProperty> &properties, const char *name, const UString &value)
|
|
{
|
|
CProperty prop;
|
|
prop.Name = name;
|
|
prop.Value = value;
|
|
properties.Add(prop);
|
|
}
|
|
|
|
static void AddProp_UInt32(CObjectVector<CProperty> &properties, const char *name, UInt32 value)
|
|
{
|
|
UString s;
|
|
s.Add_UInt32(value);
|
|
AddProp_UString(properties, name, s);
|
|
}
|
|
|
|
static void AddProp_bool(CObjectVector<CProperty> &properties, const char *name, bool value)
|
|
{
|
|
AddProp_UString(properties, name, UString(value ? "on": "off"));
|
|
}
|
|
|
|
|
|
static void AddProp_BoolPair(CObjectVector<CProperty> &properties,
|
|
const char *name, const CBoolPair &bp)
|
|
{
|
|
if (bp.Def)
|
|
AddProp_bool(properties, name, bp.Val);
|
|
}
|
|
|
|
|
|
|
|
static void SplitOptionsToStrings(const UString &src, UStringVector &strings)
|
|
{
|
|
SplitString(src, strings);
|
|
FOR_VECTOR (i, strings)
|
|
{
|
|
UString &s = strings[i];
|
|
if (s.Len() > 2
|
|
&& s[0] == '-'
|
|
&& MyCharLower_Ascii(s[1]) == 'm')
|
|
s.DeleteFrontal(2);
|
|
}
|
|
}
|
|
|
|
static bool IsThereMethodOverride(bool is7z, const UStringVector &strings)
|
|
{
|
|
FOR_VECTOR (i, strings)
|
|
{
|
|
const UString &s = strings[i];
|
|
if (is7z)
|
|
{
|
|
const wchar_t *end;
|
|
UInt64 n = ConvertStringToUInt64(s, &end);
|
|
if (n == 0 && *end == L'=')
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (s.Len() > 0)
|
|
if (s[0] == L'm' && s[1] == L'=')
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void ParseAndAddPropertires(CObjectVector<CProperty> &properties,
|
|
const UStringVector &strings)
|
|
{
|
|
FOR_VECTOR (i, strings)
|
|
{
|
|
const UString &s = strings[i];
|
|
CProperty property;
|
|
const int index = s.Find(L'=');
|
|
if (index < 0)
|
|
property.Name = s;
|
|
else
|
|
{
|
|
property.Name.SetFrom(s, (unsigned)index);
|
|
property.Value = s.Ptr(index + 1);
|
|
}
|
|
properties.Add(property);
|
|
}
|
|
}
|
|
|
|
|
|
static void AddProp_Size(CObjectVector<CProperty> &properties, const char *name, const UInt64 size)
|
|
{
|
|
UString s;
|
|
s.Add_UInt64(size);
|
|
s += 'b';
|
|
AddProp_UString(properties, name, s);
|
|
}
|
|
|
|
|
|
static void SetOutProperties(
|
|
CObjectVector<CProperty> &properties,
|
|
const NCompressDialog::CInfo &di,
|
|
bool is7z,
|
|
bool setMethod)
|
|
{
|
|
if (di.Level != (UInt32)(Int32)-1)
|
|
AddProp_UInt32(properties, "x", (UInt32)di.Level);
|
|
if (setMethod)
|
|
{
|
|
if (!di.Method.IsEmpty())
|
|
AddProp_UString(properties, is7z ? "0": "m", di.Method);
|
|
if (di.Dict64 != (UInt64)(Int64)-1)
|
|
{
|
|
AString name;
|
|
if (is7z)
|
|
name = "0";
|
|
name += (di.OrderMode ? "mem" : "d");
|
|
AddProp_Size(properties, name, di.Dict64);
|
|
}
|
|
/*
|
|
if (di.Dict64_Chain != (UInt64)(Int64)-1)
|
|
{
|
|
AString name;
|
|
if (is7z)
|
|
name = "0";
|
|
name += "dc";
|
|
AddProp_Size(properties, name, di.Dict64_Chain);
|
|
}
|
|
*/
|
|
if (di.Order != (UInt32)(Int32)-1)
|
|
{
|
|
AString name;
|
|
if (is7z)
|
|
name = "0";
|
|
name += (di.OrderMode ? "o" : "fb");
|
|
AddProp_UInt32(properties, name, (UInt32)di.Order);
|
|
}
|
|
}
|
|
|
|
if (!di.EncryptionMethod.IsEmpty())
|
|
AddProp_UString(properties, "em", di.EncryptionMethod);
|
|
|
|
if (di.EncryptHeadersIsAllowed)
|
|
AddProp_bool(properties, "he", di.EncryptHeaders);
|
|
|
|
if (di.SolidIsSpecified)
|
|
AddProp_Size(properties, "s", di.SolidBlockSize);
|
|
|
|
if (
|
|
// di.MultiThreadIsAllowed &&
|
|
di.NumThreads != (UInt32)(Int32)-1)
|
|
AddProp_UInt32(properties, "mt", di.NumThreads);
|
|
|
|
const NCompression::CMemUse &memUse = di.MemUsage;
|
|
if (memUse.IsDefined)
|
|
{
|
|
const char *kMemUse = "memuse";
|
|
if (memUse.IsPercent)
|
|
{
|
|
UString s;
|
|
// s += 'p'; // for debug: alternate percent method
|
|
s.Add_UInt64(memUse.Val);
|
|
s += '%';
|
|
AddProp_UString(properties, kMemUse, s);
|
|
}
|
|
else
|
|
AddProp_Size(properties, kMemUse, memUse.Val);
|
|
}
|
|
|
|
AddProp_BoolPair(properties, "tm", di.MTime);
|
|
AddProp_BoolPair(properties, "tc", di.CTime);
|
|
AddProp_BoolPair(properties, "ta", di.ATime);
|
|
|
|
if (di.TimePrec != (UInt32)(Int32)-1)
|
|
AddProp_UInt32(properties, "tp", di.TimePrec);
|
|
}
|
|
|
|
|
|
struct C_UpdateMode_ToAction_Pair
|
|
{
|
|
NCompressDialog::NUpdateMode::EEnum UpdateMode;
|
|
const NUpdateArchive::CActionSet *ActionSet;
|
|
};
|
|
|
|
static const C_UpdateMode_ToAction_Pair g_UpdateMode_Pairs[] =
|
|
{
|
|
{ NCompressDialog::NUpdateMode::kAdd, &NUpdateArchive::k_ActionSet_Add },
|
|
{ NCompressDialog::NUpdateMode::kUpdate, &NUpdateArchive::k_ActionSet_Update },
|
|
{ NCompressDialog::NUpdateMode::kFresh, &NUpdateArchive::k_ActionSet_Fresh },
|
|
{ NCompressDialog::NUpdateMode::kSync, &NUpdateArchive::k_ActionSet_Sync }
|
|
};
|
|
|
|
static int FindActionSet(const NUpdateArchive::CActionSet &actionSet)
|
|
{
|
|
for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_UpdateMode_Pairs); i++)
|
|
if (actionSet.IsEqualTo(*g_UpdateMode_Pairs[i].ActionSet))
|
|
return (int)i;
|
|
return -1;
|
|
}
|
|
|
|
static int FindUpdateMode(NCompressDialog::NUpdateMode::EEnum mode)
|
|
{
|
|
for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_UpdateMode_Pairs); i++)
|
|
if (mode == g_UpdateMode_Pairs[i].UpdateMode)
|
|
return (int)i;
|
|
return -1;
|
|
}
|
|
|
|
|
|
static HRESULT ShowDialog(
|
|
CCodecs *codecs,
|
|
const CObjectVector<NWildcard::CCensorPath> &censor,
|
|
CUpdateOptions &options,
|
|
CUpdateCallbackGUI *callback, HWND hwndParent)
|
|
{
|
|
if (options.Commands.Size() != 1)
|
|
throw "It must be one command";
|
|
/*
|
|
FString currentDirPrefix;
|
|
#ifndef UNDER_CE
|
|
{
|
|
if (!MyGetCurrentDirectory(currentDirPrefix))
|
|
return E_FAIL;
|
|
NName::NormalizeDirPathPrefix(currentDirPrefix);
|
|
}
|
|
#endif
|
|
*/
|
|
|
|
bool oneFile = false;
|
|
NFind::CFileInfo fileInfo;
|
|
UString name;
|
|
|
|
/*
|
|
if (censor.Pairs.Size() > 0)
|
|
{
|
|
const NWildcard::CPair &pair = censor.Pairs[0];
|
|
if (pair.Head.IncludeItems.Size() > 0)
|
|
{
|
|
const NWildcard::CItem &item = pair.Head.IncludeItems[0];
|
|
if (item.ForFile)
|
|
{
|
|
name = pair.Prefix;
|
|
FOR_VECTOR (i, item.PathParts)
|
|
{
|
|
if (i > 0)
|
|
name.Add_PathSepar();
|
|
name += item.PathParts[i];
|
|
}
|
|
if (fileInfo.Find(us2fs(name)))
|
|
{
|
|
if (censor.Pairs.Size() == 1 && pair.Head.IncludeItems.Size() == 1)
|
|
oneFile = !fileInfo.IsDir();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
if (censor.Size() > 0)
|
|
{
|
|
const NWildcard::CCensorPath &cp = censor[0];
|
|
if (cp.Include)
|
|
{
|
|
{
|
|
if (fileInfo.Find(us2fs(cp.Path)))
|
|
{
|
|
if (censor.Size() == 1)
|
|
oneFile = !fileInfo.IsDir();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
// v23: we restore current dir in dialog code
|
|
#if defined(_WIN32) && !defined(UNDER_CE)
|
|
CCurrentDirRestorer curDirRestorer;
|
|
#endif
|
|
*/
|
|
|
|
CCompressDialog dialog;
|
|
NCompressDialog::CInfo &di = dialog.Info;
|
|
dialog.ArcFormats = &codecs->Formats;
|
|
{
|
|
CObjectVector<CCodecInfoUser> userCodecs;
|
|
codecs->Get_CodecsInfoUser_Vector(userCodecs);
|
|
dialog.SetMethods(userCodecs);
|
|
}
|
|
|
|
if (options.MethodMode.Type_Defined)
|
|
di.FormatIndex = options.MethodMode.Type.FormatIndex;
|
|
|
|
FOR_VECTOR (i, codecs->Formats)
|
|
{
|
|
const CArcInfoEx &ai = codecs->Formats[i];
|
|
if (!ai.UpdateEnabled)
|
|
continue;
|
|
if (!oneFile && ai.Flags_KeepName())
|
|
continue;
|
|
if ((int)i != di.FormatIndex)
|
|
{
|
|
if (ai.Flags_HashHandler())
|
|
continue;
|
|
if (ai.Name.IsEqualTo_Ascii_NoCase("swfc"))
|
|
if (!oneFile || name.Len() < 4 || !StringsAreEqualNoCase_Ascii(name.RightPtr(4), ".swf"))
|
|
continue;
|
|
}
|
|
dialog.ArcIndices.Add(i);
|
|
}
|
|
if (dialog.ArcIndices.IsEmpty())
|
|
{
|
|
ShowErrorMessage(L"No Update Engines");
|
|
return E_FAIL;
|
|
}
|
|
|
|
// di.ArchiveName = options.ArchivePath.GetFinalPath();
|
|
di.ArcPath = options.ArchivePath.GetPathWithoutExt();
|
|
dialog.OriginalFileName = fs2us(fileInfo.Name);
|
|
|
|
di.PathMode = options.PathMode;
|
|
|
|
// di.CurrentDirPrefix = currentDirPrefix;
|
|
di.SFXMode = options.SfxMode;
|
|
di.OpenShareForWrite = options.OpenShareForWrite;
|
|
di.DeleteAfterCompressing = options.DeleteAfterCompressing;
|
|
|
|
di.SymLinks = options.SymLinks;
|
|
di.HardLinks = options.HardLinks;
|
|
di.AltStreams = options.AltStreams;
|
|
di.NtSecurity = options.NtSecurity;
|
|
if (options.SetArcMTime)
|
|
di.SetArcMTime.SetTrueTrue();
|
|
if (options.PreserveATime)
|
|
di.PreserveATime.SetTrueTrue();
|
|
|
|
if (callback->PasswordIsDefined)
|
|
di.Password = callback->Password;
|
|
|
|
di.KeepName = !oneFile;
|
|
|
|
NUpdateArchive::CActionSet &actionSet = options.Commands.Front().ActionSet;
|
|
|
|
{
|
|
int index = FindActionSet(actionSet);
|
|
if (index < 0)
|
|
return E_NOTIMPL;
|
|
di.UpdateMode = g_UpdateMode_Pairs[(unsigned)index].UpdateMode;
|
|
}
|
|
|
|
ParseProperties(options.MethodMode.Properties, di);
|
|
|
|
if (dialog.Create(hwndParent) != IDOK)
|
|
return E_ABORT;
|
|
|
|
options.DeleteAfterCompressing = di.DeleteAfterCompressing;
|
|
|
|
options.SymLinks = di.SymLinks;
|
|
options.HardLinks = di.HardLinks;
|
|
options.AltStreams = di.AltStreams;
|
|
options.NtSecurity = di.NtSecurity;
|
|
options.SetArcMTime = di.SetArcMTime.Val;
|
|
if (di.PreserveATime.Def)
|
|
options.PreserveATime = di.PreserveATime.Val;
|
|
|
|
/*
|
|
#if defined(_WIN32) && !defined(UNDER_CE)
|
|
curDirRestorer.NeedRestore = dialog.CurrentDirWasChanged;
|
|
#endif
|
|
*/
|
|
|
|
options.VolumesSizes = di.VolumeSizes;
|
|
/*
|
|
if (di.VolumeSizeIsDefined)
|
|
{
|
|
MyMessageBox(L"Splitting to volumes is not supported");
|
|
return E_FAIL;
|
|
}
|
|
*/
|
|
|
|
|
|
{
|
|
int index = FindUpdateMode(di.UpdateMode);
|
|
if (index < 0)
|
|
return E_FAIL;
|
|
actionSet = *g_UpdateMode_Pairs[index].ActionSet;
|
|
}
|
|
|
|
options.PathMode = di.PathMode;
|
|
|
|
const CArcInfoEx &archiverInfo = codecs->Formats[di.FormatIndex];
|
|
callback->PasswordIsDefined = (!di.Password.IsEmpty());
|
|
if (callback->PasswordIsDefined)
|
|
callback->Password = di.Password;
|
|
|
|
// we clear command line options, and fill options form Dialog
|
|
options.MethodMode.Properties.Clear();
|
|
|
|
const bool is7z = archiverInfo.Is_7z();
|
|
|
|
UStringVector optionStrings;
|
|
SplitOptionsToStrings(di.Options, optionStrings);
|
|
const bool methodOverride = IsThereMethodOverride(is7z, optionStrings);
|
|
|
|
SetOutProperties(options.MethodMode.Properties, di,
|
|
is7z,
|
|
!methodOverride); // setMethod
|
|
|
|
options.OpenShareForWrite = di.OpenShareForWrite;
|
|
ParseAndAddPropertires(options.MethodMode.Properties, optionStrings);
|
|
|
|
if (di.SFXMode)
|
|
options.SfxMode = true;
|
|
options.MethodMode.Type = COpenType();
|
|
options.MethodMode.Type_Defined = true;
|
|
options.MethodMode.Type.FormatIndex = di.FormatIndex;
|
|
|
|
options.ArchivePath.VolExtension = archiverInfo.GetMainExt();
|
|
if (di.SFXMode)
|
|
options.ArchivePath.BaseExtension = kSFXExtension;
|
|
else
|
|
options.ArchivePath.BaseExtension = options.ArchivePath.VolExtension;
|
|
options.ArchivePath.ParseFromPath(di.ArcPath, k_ArcNameMode_Smart);
|
|
|
|
NWorkDir::CInfo workDirInfo;
|
|
workDirInfo.Load();
|
|
options.WorkingDir.Empty();
|
|
if (workDirInfo.Mode != NWorkDir::NMode::kCurrent)
|
|
{
|
|
FString fullPath;
|
|
MyGetFullPathName(us2fs(di.ArcPath), fullPath);
|
|
FString namePart;
|
|
options.WorkingDir = GetWorkDir(workDirInfo, fullPath, namePart);
|
|
CreateComplexDir(options.WorkingDir);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT UpdateGUI(
|
|
CCodecs *codecs,
|
|
const CObjectVector<COpenType> &formatIndices,
|
|
const UString &cmdArcPath,
|
|
NWildcard::CCensor &censor,
|
|
CUpdateOptions &options,
|
|
bool showDialog,
|
|
bool &messageWasDisplayed,
|
|
CUpdateCallbackGUI *callback,
|
|
HWND hwndParent)
|
|
{
|
|
messageWasDisplayed = false;
|
|
bool needSetPath = true;
|
|
if (showDialog)
|
|
{
|
|
RINOK(ShowDialog(codecs, censor.CensorPaths, options, callback, hwndParent))
|
|
needSetPath = false;
|
|
}
|
|
if (options.SfxMode && options.SfxModule.IsEmpty())
|
|
{
|
|
options.SfxModule = NWindows::NDLL::GetModuleDirPrefix();
|
|
options.SfxModule += kDefaultSfxModule;
|
|
}
|
|
|
|
CThreadUpdating tu;
|
|
|
|
tu.needSetPath = needSetPath;
|
|
|
|
tu.codecs = codecs;
|
|
tu.formatIndices = &formatIndices;
|
|
tu.cmdArcPath = &cmdArcPath;
|
|
|
|
tu.UpdateCallbackGUI = callback;
|
|
tu.UpdateCallbackGUI->ProgressDialog = &tu;
|
|
tu.UpdateCallbackGUI->Init();
|
|
|
|
UString title = LangString(IDS_PROGRESS_COMPRESSING);
|
|
if (!formatIndices.IsEmpty())
|
|
{
|
|
const int fin = formatIndices[0].FormatIndex;
|
|
if (fin >= 0)
|
|
if (codecs->Formats[fin].Flags_HashHandler())
|
|
title = LangString(IDS_CHECKSUM_CALCULATING);
|
|
}
|
|
|
|
/*
|
|
if (hwndParent != 0)
|
|
{
|
|
tu.ProgressDialog.MainWindow = hwndParent;
|
|
// tu.ProgressDialog.MainTitle = fileName;
|
|
tu.ProgressDialog.MainAddTitle = title + L' ';
|
|
}
|
|
*/
|
|
|
|
tu.WildcardCensor = &censor;
|
|
tu.Options = &options;
|
|
tu.IconID = IDI_ICON;
|
|
|
|
RINOK(tu.Create(title, hwndParent))
|
|
|
|
messageWasDisplayed = tu.ThreadFinishedOK && tu.MessagesDisplayed;
|
|
return tu.Result;
|
|
}
|