Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/UI/Common')
-rwxr-xr-xCPP/7zip/UI/Common/ArchiveCommandLine.cpp985
-rwxr-xr-xCPP/7zip/UI/Common/ArchiveCommandLine.h95
-rwxr-xr-xCPP/7zip/UI/Common/ArchiveExtractCallback.cpp448
-rwxr-xr-xCPP/7zip/UI/Common/ArchiveExtractCallback.h111
-rwxr-xr-xCPP/7zip/UI/Common/ArchiveName.cpp46
-rwxr-xr-xCPP/7zip/UI/Common/ArchiveName.h10
-rwxr-xr-xCPP/7zip/UI/Common/ArchiveOpenCallback.cpp127
-rwxr-xr-xCPP/7zip/UI/Common/ArchiveOpenCallback.h89
-rwxr-xr-xCPP/7zip/UI/Common/ArchiverInfo.cpp372
-rwxr-xr-xCPP/7zip/UI/Common/ArchiverInfo.h66
-rwxr-xr-xCPP/7zip/UI/Common/CompressCall.cpp367
-rwxr-xr-xCPP/7zip/UI/Common/CompressCall.h28
-rwxr-xr-xCPP/7zip/UI/Common/DefaultName.cpp26
-rwxr-xr-xCPP/7zip/UI/Common/DefaultName.h11
-rwxr-xr-xCPP/7zip/UI/Common/DirItem.h34
-rwxr-xr-xCPP/7zip/UI/Common/EnumDirItems.cpp281
-rwxr-xr-xCPP/7zip/UI/Common/EnumDirItems.h39
-rwxr-xr-xCPP/7zip/UI/Common/ExitCode.h27
-rwxr-xr-xCPP/7zip/UI/Common/Extract.cpp152
-rwxr-xr-xCPP/7zip/UI/Common/Extract.h59
-rwxr-xr-xCPP/7zip/UI/Common/ExtractMode.h31
-rwxr-xr-xCPP/7zip/UI/Common/ExtractingFilePath.cpp75
-rwxr-xr-xCPP/7zip/UI/Common/ExtractingFilePath.h12
-rwxr-xr-xCPP/7zip/UI/Common/HandlerLoader.h38
-rwxr-xr-xCPP/7zip/UI/Common/IFileExtractCallback.h46
-rwxr-xr-xCPP/7zip/UI/Common/OpenArchive.cpp531
-rwxr-xr-xCPP/7zip/UI/Common/OpenArchive.h134
-rwxr-xr-xCPP/7zip/UI/Common/PropIDUtils.cpp90
-rwxr-xr-xCPP/7zip/UI/Common/PropIDUtils.h11
-rwxr-xr-xCPP/7zip/UI/Common/Property.h14
-rwxr-xr-xCPP/7zip/UI/Common/SetProperties.cpp65
-rwxr-xr-xCPP/7zip/UI/Common/SetProperties.h10
-rwxr-xr-xCPP/7zip/UI/Common/SortUtils.cpp78
-rwxr-xr-xCPP/7zip/UI/Common/SortUtils.h11
-rwxr-xr-xCPP/7zip/UI/Common/StdAfx.h9
-rwxr-xr-xCPP/7zip/UI/Common/TempFiles.cpp22
-rwxr-xr-xCPP/7zip/UI/Common/TempFiles.h16
-rwxr-xr-xCPP/7zip/UI/Common/Update.cpp818
-rwxr-xr-xCPP/7zip/UI/Common/Update.h158
-rwxr-xr-xCPP/7zip/UI/Common/UpdateAction.cpp64
-rwxr-xr-xCPP/7zip/UI/Common/UpdateAction.h57
-rwxr-xr-xCPP/7zip/UI/Common/UpdateCallback.cpp258
-rwxr-xr-xCPP/7zip/UI/Common/UpdateCallback.h70
-rwxr-xr-xCPP/7zip/UI/Common/UpdatePair.cpp175
-rwxr-xr-xCPP/7zip/UI/Common/UpdatePair.h24
-rwxr-xr-xCPP/7zip/UI/Common/UpdateProduce.cpp63
-rwxr-xr-xCPP/7zip/UI/Common/UpdateProduce.h31
-rwxr-xr-xCPP/7zip/UI/Common/WorkDir.cpp64
-rwxr-xr-xCPP/7zip/UI/Common/WorkDir.h10
-rwxr-xr-xCPP/7zip/UI/Common/ZipRegistry.cpp420
-rwxr-xr-xCPP/7zip/UI/Common/ZipRegistry.h99
51 files changed, 6877 insertions, 0 deletions
diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
new file mode 100755
index 00000000..6f951a27
--- /dev/null
+++ b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
@@ -0,0 +1,985 @@
+// ArchiveCommandLine.cpp
+
+#include "StdAfx.h"
+
+#include <io.h>
+#include <stdio.h>
+
+#include "Common/ListFileUtils.h"
+#include "Common/StringConvert.h"
+#include "Common/StringToInt.h"
+
+#include "Windows/FileName.h"
+#include "Windows/FileDir.h"
+#ifdef _WIN32
+#include "Windows/FileMapping.h"
+#include "Windows/Synchronization.h"
+#endif
+
+#include "ArchiveCommandLine.h"
+#include "UpdateAction.h"
+#include "Update.h"
+#include "ArchiverInfo.h"
+#include "SortUtils.h"
+#include "EnumDirItems.h"
+
+using namespace NCommandLineParser;
+using namespace NWindows;
+using namespace NFile;
+
+static const int kNumSwitches = 28;
+
+namespace NKey {
+enum Enum
+{
+ kHelp1 = 0,
+ kHelp2,
+ kHelp3,
+ kDisableHeaders,
+ kDisablePercents,
+ kArchiveType,
+ kYes,
+ kPassword,
+ kProperty,
+ kOutputDir,
+ kWorkingDir,
+ kInclude,
+ kExclude,
+ kArInclude,
+ kArExclude,
+ kNoArName,
+ kUpdate,
+ kVolume,
+ kRecursed,
+ kSfx,
+ kStdIn,
+ kStdOut,
+ kOverwrite,
+ kEmail,
+ kShowDialog,
+ kLargePages,
+ kCharSet,
+ kTechMode
+};
+
+}
+
+
+static const wchar_t kRecursedIDChar = 'R';
+static const wchar_t *kRecursedPostCharSet = L"0-";
+
+static const wchar_t *kDefaultArchiveType = L"7z";
+static const wchar_t *kSFXExtension =
+ #ifdef _WIN32
+ L"exe";
+ #else
+ L"";
+ #endif
+
+namespace NRecursedPostCharIndex {
+ enum EEnum
+ {
+ kWildCardRecursionOnly = 0,
+ kNoRecursion = 1
+ };
+}
+
+static const char kImmediateNameID = '!';
+static const char kMapNameID = '#';
+static const char kFileListID = '@';
+
+static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
+static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be
+
+static const wchar_t *kOverwritePostCharSet = L"asut";
+
+NExtract::NOverwriteMode::EEnum k_OverwriteModes[] =
+{
+ NExtract::NOverwriteMode::kWithoutPrompt,
+ NExtract::NOverwriteMode::kSkipExisting,
+ NExtract::NOverwriteMode::kAutoRename,
+ NExtract::NOverwriteMode::kAutoRenameExisting
+};
+
+static const CSwitchForm kSwitchForms[kNumSwitches] =
+ {
+ { L"?", NSwitchType::kSimple, false },
+ { L"H", NSwitchType::kSimple, false },
+ { L"-HELP", NSwitchType::kSimple, false },
+ { L"BA", NSwitchType::kSimple, false },
+ { L"BD", NSwitchType::kSimple, false },
+ { L"T", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"Y", NSwitchType::kSimple, false },
+ { L"P", NSwitchType::kUnLimitedPostString, false, 0 },
+ { L"M", NSwitchType::kUnLimitedPostString, true, 1 },
+ { L"O", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"W", NSwitchType::kUnLimitedPostString, false, 0 },
+ { L"I", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+ { L"X", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+ { L"AI", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+ { L"AX", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+ { L"AN", NSwitchType::kSimple, false },
+ { L"U", NSwitchType::kUnLimitedPostString, true, 1},
+ { L"V", NSwitchType::kUnLimitedPostString, true, 1},
+ { L"R", NSwitchType::kPostChar, false, 0, 0, kRecursedPostCharSet },
+ { L"SFX", NSwitchType::kUnLimitedPostString, false, 0 },
+ { L"SI", NSwitchType::kUnLimitedPostString, false, 0 },
+ { L"SO", NSwitchType::kSimple, false, 0 },
+ { L"AO", NSwitchType::kPostChar, false, 1, 1, kOverwritePostCharSet},
+ { L"SEML", NSwitchType::kUnLimitedPostString, false, 0},
+ { L"AD", NSwitchType::kSimple, false },
+ { L"SLP", NSwitchType::kUnLimitedPostString, false, 0},
+ { L"SCS", NSwitchType::kUnLimitedPostString, false, 0},
+ { L"SLT", NSwitchType::kSimple, false }
+ };
+
+static const int kNumCommandForms = 7;
+
+static const CCommandForm g_CommandForms[kNumCommandForms] =
+{
+ { L"A", false },
+ { L"U", false },
+ { L"D", false },
+ { L"T", false },
+ { L"E", false },
+ { L"X", false },
+ { L"L", false }
+};
+
+static const int kMaxCmdLineSize = 1000;
+static const wchar_t *kUniversalWildcard = L"*";
+static const int kMinNonSwitchWords = 1;
+static const int kCommandIndex = 0;
+
+// ---------------------------
+// exception messages
+
+static const char *kUserErrorMessage = "Incorrect command line";
+static const char *kIncorrectListFile = "Incorrect wildcard in listfile";
+static const char *kIncorrectWildCardInListFile = "Incorrect wildcard in listfile";
+static const char *kIncorrectWildCardInCommandLine = "Incorrect wildcard in command line";
+static const char *kTerminalOutError = "I won't write compressed data to a terminal";
+static const char *kSameTerminalError = "I won't write data and program's messages to same terminal";
+
+static void ThrowException(const char *errorMessage)
+{
+ throw CArchiveCommandLineException(errorMessage);
+};
+
+static void ThrowUserErrorException()
+{
+ ThrowException(kUserErrorMessage);
+};
+
+// ---------------------------
+
+bool CArchiveCommand::IsFromExtractGroup() const
+{
+ switch(CommandType)
+ {
+ case NCommandType::kTest:
+ case NCommandType::kExtract:
+ case NCommandType::kFullExtract:
+ return true;
+ default:
+ return false;
+ }
+}
+
+NExtract::NPathMode::EEnum CArchiveCommand::GetPathMode() const
+{
+ switch(CommandType)
+ {
+ case NCommandType::kTest:
+ case NCommandType::kFullExtract:
+ return NExtract::NPathMode::kFullPathnames;
+ default:
+ return NExtract::NPathMode::kNoPathnames;
+ }
+}
+
+bool CArchiveCommand::IsFromUpdateGroup() const
+{
+ return (CommandType == NCommandType::kAdd ||
+ CommandType == NCommandType::kUpdate ||
+ CommandType == NCommandType::kDelete);
+}
+
+static NRecursedType::EEnum GetRecursedTypeFromIndex(int index)
+{
+ switch (index)
+ {
+ case NRecursedPostCharIndex::kWildCardRecursionOnly:
+ return NRecursedType::kWildCardOnlyRecursed;
+ case NRecursedPostCharIndex::kNoRecursion:
+ return NRecursedType::kNonRecursed;
+ default:
+ return NRecursedType::kRecursed;
+ }
+}
+
+static bool ParseArchiveCommand(const UString &commandString, CArchiveCommand &command)
+{
+ UString commandStringUpper = commandString;
+ commandStringUpper.MakeUpper();
+ UString postString;
+ int commandIndex = ParseCommand(kNumCommandForms, g_CommandForms, commandStringUpper,
+ postString) ;
+ if (commandIndex < 0)
+ return false;
+ command.CommandType = (NCommandType::EEnum)commandIndex;
+ return true;
+}
+
+// ------------------------------------------------------------------
+// filenames functions
+
+static bool AddNameToCensor(NWildcard::CCensor &wildcardCensor,
+ const UString &name, bool include, NRecursedType::EEnum type)
+{
+ bool isWildCard = DoesNameContainWildCard(name);
+ bool recursed = false;
+
+ switch (type)
+ {
+ case NRecursedType::kWildCardOnlyRecursed:
+ recursed = isWildCard;
+ break;
+ case NRecursedType::kRecursed:
+ recursed = true;
+ break;
+ case NRecursedType::kNonRecursed:
+ recursed = false;
+ break;
+ }
+ wildcardCensor.AddItem(include, name, recursed);
+ return true;
+}
+
+static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; }
+
+static void AddToCensorFromListFile(NWildcard::CCensor &wildcardCensor,
+ LPCWSTR fileName, bool include, NRecursedType::EEnum type, UINT codePage)
+{
+ UStringVector names;
+ if (!ReadNamesFromListFile(GetSystemString(fileName, GetCurrentCodePage()), names, codePage))
+ throw kIncorrectListFile;
+ for (int i = 0; i < names.Size(); i++)
+ if (!AddNameToCensor(wildcardCensor, names[i], include, type))
+ throw kIncorrectWildCardInListFile;
+}
+
+static void AddCommandLineWildCardToCensr(NWildcard::CCensor &wildcardCensor,
+ const UString &name, bool include, NRecursedType::EEnum recursedType)
+{
+ if (!AddNameToCensor(wildcardCensor, name, include, recursedType))
+ throw kIncorrectWildCardInCommandLine;
+}
+
+static void AddToCensorFromNonSwitchesStrings(
+ int startIndex,
+ NWildcard::CCensor &wildcardCensor,
+ const UStringVector &nonSwitchStrings, NRecursedType::EEnum type,
+ bool thereAreSwitchIncludes, UINT codePage)
+{
+ if(nonSwitchStrings.Size() == startIndex && (!thereAreSwitchIncludes))
+ AddCommandLineWildCardToCensr(wildcardCensor, kUniversalWildcard, true, type);
+ for(int i = startIndex; i < nonSwitchStrings.Size(); i++)
+ {
+ const UString &s = nonSwitchStrings[i];
+ if (s[0] == kFileListID)
+ AddToCensorFromListFile(wildcardCensor, s.Mid(1), true, type, codePage);
+ else
+ AddCommandLineWildCardToCensr(wildcardCensor, s, true, type);
+ }
+}
+
+#ifdef _WIN32
+static void ParseMapWithPaths(NWildcard::CCensor &wildcardCensor,
+ const UString &switchParam, bool include,
+ NRecursedType::EEnum commonRecursedType)
+{
+ int splitPos = switchParam.Find(L':');
+ if (splitPos < 0)
+ ThrowUserErrorException();
+ UString mappingName = switchParam.Left(splitPos);
+
+ UString switchParam2 = switchParam.Mid(splitPos + 1);
+ splitPos = switchParam2.Find(L':');
+ if (splitPos < 0)
+ ThrowUserErrorException();
+
+ UString mappingSize = switchParam2.Left(splitPos);
+ UString eventName = switchParam2.Mid(splitPos + 1);
+
+ UInt64 dataSize64 = ConvertStringToUInt64(mappingSize, NULL);
+ UInt32 dataSize = (UInt32)dataSize64;
+ {
+ CFileMapping fileMapping;
+ if (!fileMapping.Open(FILE_MAP_READ, false, GetSystemString(mappingName)))
+ ThrowException("Can not open mapping");
+ LPVOID data = fileMapping.MapViewOfFile(FILE_MAP_READ, 0, dataSize);
+ if (data == NULL)
+ ThrowException("MapViewOfFile error");
+ try
+ {
+ const wchar_t *curData = (const wchar_t *)data;
+ if (*curData != 0)
+ ThrowException("Incorrect mapping data");
+ UInt32 numChars = dataSize / sizeof(wchar_t);
+ UString name;
+ for (UInt32 i = 1; i < numChars; i++)
+ {
+ wchar_t c = curData[i];
+ if (c == L'\0')
+ {
+ AddCommandLineWildCardToCensr(wildcardCensor,
+ name, include, commonRecursedType);
+ name.Empty();
+ }
+ else
+ name += c;
+ }
+ if (!name.IsEmpty())
+ ThrowException("data error");
+ }
+ catch(...)
+ {
+ UnmapViewOfFile(data);
+ throw;
+ }
+ UnmapViewOfFile(data);
+ }
+
+ {
+ NSynchronization::CEvent event;
+ event.Open(EVENT_MODIFY_STATE, false, GetSystemString(eventName));
+ event.Set();
+ }
+}
+#endif
+
+static void AddSwitchWildCardsToCensor(NWildcard::CCensor &wildcardCensor,
+ const UStringVector &strings, bool include,
+ NRecursedType::EEnum commonRecursedType, UINT codePage)
+{
+ for(int i = 0; i < strings.Size(); i++)
+ {
+ const UString &name = strings[i];
+ NRecursedType::EEnum recursedType;
+ int pos = 0;
+ if (name.Length() < kSomeCludePostStringMinSize)
+ ThrowUserErrorException();
+ if (::MyCharUpper(name[pos]) == kRecursedIDChar)
+ {
+ pos++;
+ int index = UString(kRecursedPostCharSet).Find(name[pos]);
+ recursedType = GetRecursedTypeFromIndex(index);
+ if (index >= 0)
+ pos++;
+ }
+ else
+ recursedType = commonRecursedType;
+ if (name.Length() < pos + kSomeCludeAfterRecursedPostStringMinSize)
+ ThrowUserErrorException();
+ UString tail = name.Mid(pos + 1);
+ if (name[pos] == kImmediateNameID)
+ AddCommandLineWildCardToCensr(wildcardCensor, tail, include, recursedType);
+ else if (name[pos] == kFileListID)
+ AddToCensorFromListFile(wildcardCensor, tail, include, recursedType, codePage);
+ #ifdef _WIN32
+ else if (name[pos] == kMapNameID)
+ ParseMapWithPaths(wildcardCensor, tail, include, recursedType);
+ #endif
+ else
+ ThrowUserErrorException();
+ }
+}
+
+#ifdef _WIN32
+
+// This code converts all short file names to long file names.
+
+static void ConvertToLongName(const UString &prefix, UString &name)
+{
+ if (name.IsEmpty() || DoesNameContainWildCard(name))
+ return;
+ NFind::CFileInfoW fileInfo;
+ if (NFind::FindFile(prefix + name, fileInfo))
+ name = fileInfo.Name;
+}
+
+static void ConvertToLongNames(const UString &prefix, CObjectVector<NWildcard::CItem> &items)
+{
+ for (int i = 0; i < items.Size(); i++)
+ {
+ NWildcard::CItem &item = items[i];
+ if (item.Recursive || item.PathParts.Size() != 1)
+ continue;
+ ConvertToLongName(prefix, item.PathParts.Front());
+ }
+}
+
+static void ConvertToLongNames(const UString &prefix, NWildcard::CCensorNode &node)
+{
+ ConvertToLongNames(prefix, node.IncludeItems);
+ ConvertToLongNames(prefix, node.ExcludeItems);
+ int i;
+ for (i = 0; i < node.SubNodes.Size(); i++)
+ ConvertToLongName(prefix, node.SubNodes[i].Name);
+ // mix folders with same name
+ for (i = 0; i < node.SubNodes.Size(); i++)
+ {
+ NWildcard::CCensorNode &nextNode1 = node.SubNodes[i];
+ for (int j = i + 1; j < node.SubNodes.Size();)
+ {
+ const NWildcard::CCensorNode &nextNode2 = node.SubNodes[j];
+ if (nextNode1.Name.CompareNoCase(nextNode2.Name) == 0)
+ {
+ nextNode1.IncludeItems += nextNode2.IncludeItems;
+ nextNode1.ExcludeItems += nextNode2.ExcludeItems;
+ node.SubNodes.Delete(j);
+ }
+ else
+ j++;
+ }
+ }
+ for (i = 0; i < node.SubNodes.Size(); i++)
+ {
+ NWildcard::CCensorNode &nextNode = node.SubNodes[i];
+ ConvertToLongNames(prefix + nextNode.Name + wchar_t(NFile::NName::kDirDelimiter), nextNode);
+ }
+}
+
+static void ConvertToLongNames(NWildcard::CCensor &censor)
+{
+ for (int i = 0; i < censor.Pairs.Size(); i++)
+ {
+ NWildcard::CPair &pair = censor.Pairs[i];
+ ConvertToLongNames(pair.Prefix, pair.Head);
+ }
+}
+
+#endif
+
+static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i)
+{
+ switch(i)
+ {
+ case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore;
+ case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy;
+ case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress;
+ case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti;
+ }
+ throw 98111603;
+}
+
+const UString kUpdatePairStateIDSet = L"PQRXYZW";
+const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1};
+
+const UString kUpdatePairActionIDSet = L"0123"; //Ignore, Copy, Compress, Create Anti
+
+const wchar_t *kUpdateIgnoreItselfPostStringID = L"-";
+const wchar_t kUpdateNewArchivePostCharID = '!';
+
+
+static bool ParseUpdateCommandString2(const UString &command,
+ NUpdateArchive::CActionSet &actionSet, UString &postString)
+{
+ for(int i = 0; i < command.Length();)
+ {
+ wchar_t c = MyCharUpper(command[i]);
+ int statePos = kUpdatePairStateIDSet.Find(c);
+ if (statePos < 0)
+ {
+ postString = command.Mid(i);
+ return true;
+ }
+ i++;
+ if (i >= command.Length())
+ return false;
+ int actionPos = kUpdatePairActionIDSet.Find(::MyCharUpper(command[i]));
+ if (actionPos < 0)
+ return false;
+ actionSet.StateActions[statePos] = GetUpdatePairActionType(actionPos);
+ if (kUpdatePairStateNotSupportedActions[statePos] == actionPos)
+ return false;
+ i++;
+ }
+ postString.Empty();
+ return true;
+}
+
+static void ParseUpdateCommandString(CUpdateOptions &options,
+ const UStringVector &updatePostStrings,
+ const NUpdateArchive::CActionSet &defaultActionSet)
+{
+ for(int i = 0; i < updatePostStrings.Size(); i++)
+ {
+ const UString &updateString = updatePostStrings[i];
+ if(updateString.CompareNoCase(kUpdateIgnoreItselfPostStringID) == 0)
+ {
+ if(options.UpdateArchiveItself)
+ {
+ options.UpdateArchiveItself = false;
+ options.Commands.Delete(0);
+ }
+ }
+ else
+ {
+ NUpdateArchive::CActionSet actionSet = defaultActionSet;
+
+ UString postString;
+ if (!ParseUpdateCommandString2(updateString, actionSet, postString))
+ ThrowUserErrorException();
+ if(postString.IsEmpty())
+ {
+ if(options.UpdateArchiveItself)
+ options.Commands[0].ActionSet = actionSet;
+ }
+ else
+ {
+ if(MyCharUpper(postString[0]) != kUpdateNewArchivePostCharID)
+ ThrowUserErrorException();
+ CUpdateArchiveCommand uc;
+ UString archivePath = postString.Mid(1);
+ if (archivePath.IsEmpty())
+ ThrowUserErrorException();
+ uc.ArchivePath.BaseExtension = options.ArchivePath.BaseExtension;
+ uc.ArchivePath.VolExtension = options.ArchivePath.VolExtension;
+ uc.ArchivePath.ParseFromPath(archivePath);
+ uc.ActionSet = actionSet;
+ options.Commands.Add(uc);
+ }
+ }
+ }
+}
+
+static const char kByteSymbol = 'B';
+static const char kKiloSymbol = 'K';
+static const char kMegaSymbol = 'M';
+static const char kGigaSymbol = 'G';
+
+static bool ParseComplexSize(const UString &src, UInt64 &result)
+{
+ UString s = src;
+ s.MakeUpper();
+
+ const wchar_t *start = s;
+ const wchar_t *end;
+ UInt64 number = ConvertStringToUInt64(start, &end);
+ int numDigits = (int)(end - start);
+ if (numDigits == 0 || s.Length() > numDigits + 1)
+ return false;
+ if (s.Length() == numDigits)
+ {
+ result = number;
+ return true;
+ }
+ int numBits;
+ switch (s[numDigits])
+ {
+ case kByteSymbol:
+ result = number;
+ return true;
+ case kKiloSymbol:
+ numBits = 10;
+ break;
+ case kMegaSymbol:
+ numBits = 20;
+ break;
+ case kGigaSymbol:
+ numBits = 30;
+ break;
+ default:
+ return false;
+ }
+ if (number >= ((UInt64)1 << (64 - numBits)))
+ return false;
+ result = number << numBits;
+ return true;
+}
+
+static void SetAddCommandOptions(
+ NCommandType::EEnum commandType,
+ const CParser &parser,
+ CUpdateOptions &options)
+{
+ NUpdateArchive::CActionSet defaultActionSet;
+ switch(commandType)
+ {
+ case NCommandType::kAdd:
+ defaultActionSet = NUpdateArchive::kAddActionSet;
+ break;
+ case NCommandType::kDelete:
+ defaultActionSet = NUpdateArchive::kDeleteActionSet;
+ break;
+ default:
+ defaultActionSet = NUpdateArchive::kUpdateActionSet;
+ }
+
+ options.UpdateArchiveItself = true;
+
+ options.Commands.Clear();
+ CUpdateArchiveCommand updateMainCommand;
+ updateMainCommand.ActionSet = defaultActionSet;
+ options.Commands.Add(updateMainCommand);
+ if(parser[NKey::kUpdate].ThereIs)
+ ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings,
+ defaultActionSet);
+ if(parser[NKey::kWorkingDir].ThereIs)
+ {
+ const UString &postString = parser[NKey::kWorkingDir].PostStrings[0];
+ if (postString.IsEmpty())
+ NDirectory::MyGetTempPath(options.WorkingDir);
+ else
+ options.WorkingDir = postString;
+ }
+ options.SfxMode = parser[NKey::kSfx].ThereIs;
+ if (options.SfxMode)
+ options.SfxModule = parser[NKey::kSfx].PostStrings[0];
+
+ if (parser[NKey::kVolume].ThereIs)
+ {
+ const UStringVector &sv = parser[NKey::kVolume].PostStrings;
+ for (int i = 0; i < sv.Size(); i++)
+ {
+ UInt64 size;
+ if (!ParseComplexSize(sv[i], size))
+ ThrowException("Incorrect volume size");
+ options.VolumesSizes.Add(size);
+ }
+ }
+}
+
+static void SetMethodOptions(const CParser &parser, CObjectVector<CProperty> &properties)
+{
+ if (parser[NKey::kProperty].ThereIs)
+ {
+ // options.MethodMode.Properties.Clear();
+ for(int i = 0; i < parser[NKey::kProperty].PostStrings.Size(); i++)
+ {
+ CProperty property;
+ const UString &postString = parser[NKey::kProperty].PostStrings[i];
+ int index = postString.Find(L'=');
+ if (index < 0)
+ property.Name = postString;
+ else
+ {
+ property.Name = postString.Left(index);
+ property.Value = postString.Mid(index + 1);
+ }
+ properties.Add(property);
+ }
+ }
+}
+
+
+static void SetArchiveType(const UString &archiveType,
+#ifndef EXCLUDE_COM
+ UString &filePath, CLSID &classID,
+#else
+ UString &formatName,
+#endif
+ UString &archiveExtension)
+{
+ CObjectVector<CArchiverInfo> archiverInfoVector;
+ ReadArchiverInfoList(archiverInfoVector);
+ if (archiverInfoVector.Size() == 0)
+ ThrowException("There are no installed archive handlers");
+ if (archiveType.IsEmpty())
+ ThrowException("Incorrect archive type was assigned");
+ for (int i = 0; i < archiverInfoVector.Size(); i++)
+ {
+ const CArchiverInfo &archiverInfo = archiverInfoVector[i];
+ if (archiverInfo.Name.CompareNoCase(archiveType) == 0)
+ {
+ #ifndef EXCLUDE_COM
+ classID = archiverInfo.ClassID;
+ filePath = archiverInfo.FilePath;
+ #else
+ formatName = archiverInfo.Name;
+
+ #endif
+
+ archiveExtension = archiverInfo.GetMainExtension();
+ return;
+ }
+ }
+ ThrowException("Incorrect archive type was assigned");
+}
+
+
+CArchiveCommandLineParser::CArchiveCommandLineParser(): parser(kNumSwitches) {}
+
+void CArchiveCommandLineParser::Parse1(const UStringVector &commandStrings,
+ CArchiveCommandLineOptions &options)
+{
+ try
+ {
+ parser.ParseStrings(kSwitchForms, commandStrings);
+ }
+ catch(...)
+ {
+ ThrowUserErrorException();
+ }
+
+ options.IsInTerminal = (_isatty(_fileno(stdin)) != 0);
+ options.IsStdOutTerminal = (_isatty(_fileno(stdout)) != 0);
+ options.IsStdErrTerminal = (_isatty(_fileno(stderr)) != 0);
+ options.StdOutMode = parser[NKey::kStdOut].ThereIs;
+ options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs;
+ options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs || parser[NKey::kHelp3].ThereIs;
+
+ #ifdef _WIN32
+ options.LargePages = false;
+ if (parser[NKey::kLargePages].ThereIs)
+ {
+ const UString &postString = parser[NKey::kLargePages].PostStrings.Front();
+ if (postString.IsEmpty())
+ options.LargePages = true;
+ }
+ #endif
+}
+
+struct CCodePagePair
+{
+ const wchar_t *Name;
+ UINT CodePage;
+};
+
+static CCodePagePair g_CodePagePairs[] =
+{
+ { L"UTF-8", CP_UTF8 },
+ { L"WIN", CP_ACP },
+ { L"DOS", CP_OEMCP }
+};
+
+static const int kNumCodePages = sizeof(g_CodePagePairs) / sizeof(g_CodePagePairs[0]);
+
+void CArchiveCommandLineParser::Parse2(CArchiveCommandLineOptions &options)
+{
+ const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
+ int numNonSwitchStrings = nonSwitchStrings.Size();
+ if(numNonSwitchStrings < kMinNonSwitchWords)
+ ThrowUserErrorException();
+
+ if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command))
+ ThrowUserErrorException();
+
+ options.TechMode = parser[NKey::kTechMode].ThereIs;
+
+ NRecursedType::EEnum recursedType;
+ if (parser[NKey::kRecursed].ThereIs)
+ recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex);
+ else
+ recursedType = NRecursedType::kNonRecursed;
+
+ UINT codePage = CP_UTF8;
+ if (parser[NKey::kCharSet].ThereIs)
+ {
+ UString name = parser[NKey::kCharSet].PostStrings.Front();
+ name.MakeUpper();
+ int i;
+ for (i = 0; i < kNumCodePages; i++)
+ {
+ const CCodePagePair &pair = g_CodePagePairs[i];
+ if (name.Compare(pair.Name) == 0)
+ {
+ codePage = pair.CodePage;
+ break;
+ }
+ }
+ if (i >= kNumCodePages)
+ ThrowUserErrorException();
+ }
+
+ bool thereAreSwitchIncludes = false;
+ if (parser[NKey::kInclude].ThereIs)
+ {
+ thereAreSwitchIncludes = true;
+ AddSwitchWildCardsToCensor(options.WildcardCensor,
+ parser[NKey::kInclude].PostStrings, true, recursedType, codePage);
+ }
+ if (parser[NKey::kExclude].ThereIs)
+ AddSwitchWildCardsToCensor(options.WildcardCensor,
+ parser[NKey::kExclude].PostStrings, false, recursedType, codePage);
+
+ int curCommandIndex = kCommandIndex + 1;
+ bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs;
+ if (thereIsArchiveName)
+ {
+ if(curCommandIndex >= numNonSwitchStrings)
+ ThrowUserErrorException();
+ options.ArchiveName = nonSwitchStrings[curCommandIndex++];
+ }
+
+ AddToCensorFromNonSwitchesStrings(
+ curCommandIndex, options.WildcardCensor,
+ nonSwitchStrings, recursedType, thereAreSwitchIncludes, codePage);
+
+ options.YesToAll = parser[NKey::kYes].ThereIs;
+
+ bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
+
+ options.PasswordEnabled = parser[NKey::kPassword].ThereIs;
+
+ if(options.PasswordEnabled)
+ options.Password = parser[NKey::kPassword].PostStrings[0];
+
+ options.StdInMode = parser[NKey::kStdIn].ThereIs;
+ options.ShowDialog = parser[NKey::kShowDialog].ThereIs;
+
+ if(isExtractGroupCommand || options.Command.CommandType == NCommandType::kList)
+ {
+ if (options.StdInMode)
+ ThrowException("Reading archives from stdin is not implemented");
+ if (!options.WildcardCensor.AllAreRelative())
+ ThrowException("Cannot use absolute pathnames for this command");
+
+ NWildcard::CCensor archiveWildcardCensor;
+
+ if (parser[NKey::kArInclude].ThereIs)
+ {
+ AddSwitchWildCardsToCensor(archiveWildcardCensor,
+ parser[NKey::kArInclude].PostStrings, true, NRecursedType::kNonRecursed, codePage);
+ }
+ if (parser[NKey::kArExclude].ThereIs)
+ AddSwitchWildCardsToCensor(archiveWildcardCensor,
+ parser[NKey::kArExclude].PostStrings, false, NRecursedType::kNonRecursed, codePage);
+
+ if (thereIsArchiveName)
+ AddCommandLineWildCardToCensr(archiveWildcardCensor, options.ArchiveName, true, NRecursedType::kNonRecursed);
+
+ #ifdef _WIN32
+ ConvertToLongNames(archiveWildcardCensor);
+ #endif
+
+ archiveWildcardCensor.ExtendExclude();
+
+ CObjectVector<CDirItem> dirItems;
+ {
+ UStringVector errorPaths;
+ CRecordVector<DWORD> errorCodes;
+ HRESULT res = EnumerateItems(archiveWildcardCensor, dirItems, NULL, errorPaths, errorCodes);
+ if (res != S_OK || errorPaths.Size() > 0)
+ throw "cannot find archive";
+ }
+ UStringVector archivePaths;
+ int i;
+ for (i = 0; i < dirItems.Size(); i++)
+ {
+ const CDirItem &dirItem = dirItems[i];
+ if (!dirItem.IsDirectory())
+ archivePaths.Add(dirItem.FullPath);
+ }
+
+ if (archivePaths.Size() == 0)
+ throw "there is no such archive";
+
+ UStringVector archivePathsFull;
+
+ for (i = 0; i < archivePaths.Size(); i++)
+ {
+ UString fullPath;
+ NFile::NDirectory::MyGetFullPathName(archivePaths[i], fullPath);
+ archivePathsFull.Add(fullPath);
+ }
+ CIntVector indices;
+ SortStringsToIndices(archivePathsFull, indices);
+ options.ArchivePathsSorted.Reserve(indices.Size());
+ options.ArchivePathsFullSorted.Reserve(indices.Size());
+ for (i = 0; i < indices.Size(); i++)
+ {
+ options.ArchivePathsSorted.Add(archivePaths[indices[i]]);
+ options.ArchivePathsFullSorted.Add(archivePathsFull[indices[i]]);
+ }
+
+ if (isExtractGroupCommand)
+ {
+ SetMethodOptions(parser, options.ExtractProperties);
+ if (options.StdOutMode && options.IsStdOutTerminal && options.IsStdErrTerminal)
+ throw kSameTerminalError;
+ if(parser[NKey::kOutputDir].ThereIs)
+ {
+ options.OutputDir = parser[NKey::kOutputDir].PostStrings[0];
+ NFile::NName::NormalizeDirPathPrefix(options.OutputDir);
+ }
+
+ options.OverwriteMode = NExtract::NOverwriteMode::kAskBefore;
+ if(parser[NKey::kOverwrite].ThereIs)
+ options.OverwriteMode =
+ k_OverwriteModes[parser[NKey::kOverwrite].PostCharIndex];
+ else if (options.YesToAll)
+ options.OverwriteMode = NExtract::NOverwriteMode::kWithoutPrompt;
+ }
+ }
+ else if(options.Command.IsFromUpdateGroup())
+ {
+ CUpdateOptions &updateOptions = options.UpdateOptions;
+
+ UString archiveType;
+ if(parser[NKey::kArchiveType].ThereIs)
+ archiveType = parser[NKey::kArchiveType].PostStrings[0];
+ else
+ archiveType = kDefaultArchiveType;
+
+ UString typeExtension;
+ if (!archiveType.IsEmpty())
+ {
+ #ifndef EXCLUDE_COM
+ SetArchiveType(archiveType, updateOptions.MethodMode.FilePath,
+ updateOptions.MethodMode.ClassID, typeExtension);
+ #else
+ SetArchiveType(archiveType, updateOptions.MethodMode.Name, typeExtension);
+ #endif
+ }
+ UString extension = typeExtension;
+ if(parser[NKey::kSfx].ThereIs)
+ extension = kSFXExtension;
+ updateOptions.ArchivePath.BaseExtension = extension;
+ updateOptions.ArchivePath.VolExtension = typeExtension;
+ updateOptions.ArchivePath.ParseFromPath(options.ArchiveName);
+ SetAddCommandOptions(options.Command.CommandType, parser, updateOptions);
+
+ SetMethodOptions(parser, updateOptions.MethodMode.Properties);
+
+ options.EnablePercents = !parser[NKey::kDisablePercents].ThereIs;
+
+ if (options.EnablePercents)
+ {
+ if ((options.StdOutMode && !options.IsStdErrTerminal) ||
+ (!options.StdOutMode && !options.IsStdOutTerminal))
+ options.EnablePercents = false;
+ }
+
+ updateOptions.EMailMode = parser[NKey::kEmail].ThereIs;
+ if (updateOptions.EMailMode)
+ {
+ updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front();
+ if (updateOptions.EMailAddress.Length() > 0)
+ if (updateOptions.EMailAddress[0] == L'.')
+ {
+ updateOptions.EMailRemoveAfter = true;
+ updateOptions.EMailAddress.Delete(0);
+ }
+ }
+
+ updateOptions.StdOutMode = options.StdOutMode;
+ updateOptions.StdInMode = options.StdInMode;
+
+ if (updateOptions.StdOutMode && updateOptions.EMailMode)
+ throw "stdout mode and email mode cannot be combined";
+ if (updateOptions.StdOutMode && options.IsStdOutTerminal)
+ throw kTerminalOutError;
+ if(updateOptions.StdInMode)
+ updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front();
+
+ #ifdef _WIN32
+ ConvertToLongNames(options.WildcardCensor);
+ #endif
+ }
+ else
+ ThrowUserErrorException();
+ options.WildcardCensor.ExtendExclude();
+}
diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.h b/CPP/7zip/UI/Common/ArchiveCommandLine.h
new file mode 100755
index 00000000..daa66fb6
--- /dev/null
+++ b/CPP/7zip/UI/Common/ArchiveCommandLine.h
@@ -0,0 +1,95 @@
+// ArchiveCommandLine.h
+
+#ifndef __ARCHIVECOMMANDLINE_H
+#define __ARCHIVECOMMANDLINE_H
+
+#include "Common/Wildcard.h"
+#include "Common/CommandLineParser.h"
+
+#include "Extract.h"
+#include "Update.h"
+
+struct CArchiveCommandLineException: public AString
+{
+ CArchiveCommandLineException(const char *errorMessage): AString(errorMessage) {}
+};
+
+namespace NCommandType { enum EEnum
+{
+ kAdd = 0,
+ kUpdate,
+ kDelete,
+ kTest,
+ kExtract,
+ kFullExtract,
+ kList
+};}
+
+namespace NRecursedType { enum EEnum
+{
+ kRecursed,
+ kWildCardOnlyRecursed,
+ kNonRecursed,
+};}
+
+struct CArchiveCommand
+{
+ NCommandType::EEnum CommandType;
+ bool IsFromExtractGroup() const;
+ bool IsFromUpdateGroup() const;
+ bool IsTestMode() const { return CommandType == NCommandType::kTest; }
+ NExtract::NPathMode::EEnum GetPathMode() const;
+};
+
+struct CArchiveCommandLineOptions
+{
+ bool HelpMode;
+
+ #ifdef _WIN32
+ bool LargePages;
+ #endif
+
+ bool IsInTerminal;
+ bool IsStdOutTerminal;
+ bool IsStdErrTerminal;
+ bool StdInMode;
+ bool StdOutMode;
+ bool EnableHeaders;
+
+ bool YesToAll;
+ bool ShowDialog;
+ // NWildcard::CCensor ArchiveWildcardCensor;
+ NWildcard::CCensor WildcardCensor;
+
+ CArchiveCommand Command;
+ UString ArchiveName;
+
+ bool PasswordEnabled;
+ UString Password;
+
+ bool TechMode;
+ // Extract
+ bool AppendName;
+ UString OutputDir;
+ NExtract::NOverwriteMode::EEnum OverwriteMode;
+ UStringVector ArchivePathsSorted;
+ UStringVector ArchivePathsFullSorted;
+ CObjectVector<CProperty> ExtractProperties;
+
+ CUpdateOptions UpdateOptions;
+ bool EnablePercents;
+
+ CArchiveCommandLineOptions(): StdInMode(false), StdOutMode(false) {};
+
+};
+
+class CArchiveCommandLineParser
+{
+ NCommandLineParser::CParser parser;
+public:
+ CArchiveCommandLineParser();
+ void Parse1(const UStringVector &commandStrings, CArchiveCommandLineOptions &options);
+ void Parse2(CArchiveCommandLineOptions &options);
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
new file mode 100755
index 00000000..05520fed
--- /dev/null
+++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
@@ -0,0 +1,448 @@
+// ArchiveExtractCallback.cpp
+
+#include "StdAfx.h"
+
+#include "ArchiveExtractCallback.h"
+
+#include "Common/Wildcard.h"
+#include "Common/StringConvert.h"
+#include "Common/ComTry.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileFind.h"
+#include "Windows/Time.h"
+#include "Windows/Defs.h"
+#include "Windows/PropVariant.h"
+
+#include "Windows/PropVariantConversions.h"
+
+#include "../../Common/FilePathAutoRename.h"
+
+#include "../Common/ExtractingFilePath.h"
+#include "OpenArchive.h"
+
+using namespace NWindows;
+
+static const wchar_t *kCantAutoRename = L"ERROR: Can not create file with auto name";
+static const wchar_t *kCantRenameFile = L"ERROR: Can not rename existing file ";
+static const wchar_t *kCantDeleteOutputFile = L"ERROR: Can not delete output file ";
+
+
+void CArchiveExtractCallback::Init(
+ IInArchive *archiveHandler,
+ IFolderArchiveExtractCallback *extractCallback2,
+ bool stdOutMode,
+ const UString &directoryPath,
+ NExtract::NPathMode::EEnum pathMode,
+ NExtract::NOverwriteMode::EEnum overwriteMode,
+ const UStringVector &removePathParts,
+ const UString &itemDefaultName,
+ const FILETIME &utcLastWriteTimeDefault,
+ UInt32 attributesDefault)
+{
+ _stdOutMode = stdOutMode;
+ _numErrors = 0;
+ _extractCallback2 = extractCallback2;
+ _itemDefaultName = itemDefaultName;
+ _utcLastWriteTimeDefault = utcLastWriteTimeDefault;
+ _attributesDefault = attributesDefault;
+ _removePathParts = removePathParts;
+ _pathMode = pathMode;
+ _overwriteMode = overwriteMode;
+ _archiveHandler = archiveHandler;
+ _directoryPath = directoryPath;
+ NFile::NName::NormalizeDirPathPrefix(_directoryPath);
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size)
+{
+ COM_TRY_BEGIN
+ return _extractCallback2->SetTotal(size);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue)
+{
+ COM_TRY_BEGIN
+ return _extractCallback2->SetCompleted(completeValue);
+ COM_TRY_END
+}
+
+void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, UString &fullPath)
+{
+ fullPath = _directoryPath;
+ for(int i = 0; i < dirPathParts.Size(); i++)
+ {
+ if (i > 0)
+ fullPath += wchar_t(NFile::NName::kDirDelimiter);
+ fullPath += dirPathParts[i];
+ NFile::NDirectory::MyCreateDirectory(fullPath);
+ }
+}
+
+static UString MakePathNameFromParts(const UStringVector &parts)
+{
+ UString result;
+ for(int i = 0; i < parts.Size(); i++)
+ {
+ if(i != 0)
+ result += wchar_t(NFile::NName::kDirDelimiter);
+ result += parts[i];
+ }
+ return result;
+}
+
+
+HRESULT CArchiveExtractCallback::GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined)
+{
+ filetimeIsDefined = false;
+ NCOM::CPropVariant prop;
+ RINOK(_archiveHandler->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_FILETIME)
+ {
+ filetime = prop.filetime;
+ filetimeIsDefined = true;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)
+{
+ COM_TRY_BEGIN
+ *outStream = 0;
+ _outFileStream.Release();
+
+ _encrypted = false;
+ _isSplit = false;
+
+ UString fullPath;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop));
+
+ if(prop.vt == VT_EMPTY)
+ fullPath = _itemDefaultName;
+ else
+ {
+ if(prop.vt != VT_BSTR)
+ return E_FAIL;
+ fullPath = prop.bstrVal;
+ }
+ }
+
+ // UString fullPathCorrect = GetCorrectPath(fullPath);
+ _filePath = fullPath;
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(_archiveHandler->GetProperty(index, kpidPosition, &prop));
+ if (prop.vt != VT_EMPTY)
+ {
+ if (prop.vt != VT_UI8)
+ return E_FAIL;
+ _position = prop.uhVal.QuadPart;
+ _isSplit = true;
+ }
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(_archiveHandler->GetProperty(index, kpidEncrypted, &prop));
+ if (prop.vt == VT_BOOL)
+ _encrypted = VARIANT_BOOLToBool(prop.boolVal);
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ }
+
+ if(askExtractMode == NArchive::NExtract::NAskMode::kExtract)
+ {
+ if (_stdOutMode)
+ {
+ CMyComPtr<ISequentialOutStream> outStreamLoc = new CStdOutFileStream;
+ *outStream = outStreamLoc.Detach();
+ return S_OK;
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(_archiveHandler->GetProperty(index, kpidAttributes, &prop));
+ if (prop.vt == VT_EMPTY)
+ {
+ _processedFileInfo.Attributes = _attributesDefault;
+ _processedFileInfo.AttributesAreDefined = false;
+ }
+ else
+ {
+ if (prop.vt != VT_UI4)
+ throw "incorrect item";
+ _processedFileInfo.Attributes = prop.ulVal;
+ _processedFileInfo.AttributesAreDefined = true;
+ }
+ }
+
+ RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.IsDirectory));
+
+ RINOK(GetTime(index, kpidCreationTime, _processedFileInfo.CreationTime,
+ _processedFileInfo.IsCreationTimeDefined));
+ RINOK(GetTime(index, kpidLastWriteTime, _processedFileInfo.LastWriteTime,
+ _processedFileInfo.IsLastWriteTimeDefined));
+ RINOK(GetTime(index, kpidLastAccessTime, _processedFileInfo.LastAccessTime,
+ _processedFileInfo.IsLastAccessTimeDefined));
+
+ bool newFileSizeDefined;
+ UInt64 newFileSize;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(_archiveHandler->GetProperty(index, kpidSize, &prop));
+ newFileSizeDefined = (prop.vt != VT_EMPTY);
+ if (newFileSizeDefined)
+ newFileSize = ConvertPropVariantToUInt64(prop);
+ }
+
+ bool isAnti = false;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(_archiveHandler->GetProperty(index, kpidIsAnti, &prop));
+ if (prop.vt == VT_BOOL)
+ isAnti = VARIANT_BOOLToBool(prop.boolVal);
+ }
+
+ UStringVector pathParts;
+ SplitPathToParts(fullPath, pathParts);
+
+ if(pathParts.IsEmpty())
+ return E_FAIL;
+ UString processedPath;
+ switch(_pathMode)
+ {
+ case NExtract::NPathMode::kFullPathnames:
+ {
+ processedPath = fullPath;
+ break;
+ }
+ case NExtract::NPathMode::kCurrentPathnames:
+ {
+ // for incorrect paths: "/dir1/dir2/file"
+ int numRemovePathParts = _removePathParts.Size();
+ if(pathParts.Size() <= numRemovePathParts)
+ return E_FAIL;
+ for(int i = 0; i < numRemovePathParts; i++)
+ if(_removePathParts[i].CompareNoCase(pathParts[i]) != 0)
+ return E_FAIL;
+ pathParts.Delete(0, numRemovePathParts);
+ processedPath = MakePathNameFromParts(pathParts);
+ break;
+ }
+ case NExtract::NPathMode::kNoPathnames:
+ {
+ processedPath = pathParts.Back();
+ pathParts.Delete(0, pathParts.Size() - 1); // Test it!!
+ break;
+ }
+ }
+ processedPath = GetCorrectPath(processedPath);
+ if(!_processedFileInfo.IsDirectory)
+ pathParts.DeleteBack();
+
+ MakeCorrectPath(pathParts);
+
+ if (!isAnti)
+ {
+ if (!pathParts.IsEmpty())
+ {
+ UString fullPathNew;
+ CreateComplexDirectory(pathParts, fullPathNew);
+ if (_processedFileInfo.IsDirectory)
+ NFile::NDirectory::SetDirTime(fullPathNew,
+ (WriteCreated && _processedFileInfo.IsCreationTimeDefined) ? &_processedFileInfo.CreationTime : NULL,
+ (WriteAccessed && _processedFileInfo.IsLastAccessTimeDefined) ? &_processedFileInfo.LastAccessTime : NULL,
+ (WriteModified && _processedFileInfo.IsLastWriteTimeDefined) ? &_processedFileInfo.LastWriteTime : &_utcLastWriteTimeDefault);
+ }
+ }
+
+
+ UString fullProcessedPath = _directoryPath + processedPath;
+
+ if(_processedFileInfo.IsDirectory)
+ {
+ _diskFilePath = fullProcessedPath;
+ if (isAnti)
+ NFile::NDirectory::MyRemoveDirectory(_diskFilePath);
+ return S_OK;
+ }
+
+ if (!_isSplit)
+ {
+ NFile::NFind::CFileInfoW fileInfo;
+ if(NFile::NFind::FindFile(fullProcessedPath, fileInfo))
+ {
+ switch(_overwriteMode)
+ {
+ case NExtract::NOverwriteMode::kSkipExisting:
+ return S_OK;
+ case NExtract::NOverwriteMode::kAskBefore:
+ {
+ Int32 overwiteResult;
+ RINOK(_extractCallback2->AskOverwrite(
+ fullProcessedPath, &fileInfo.LastWriteTime, &fileInfo.Size, fullPath,
+ _processedFileInfo.IsLastWriteTimeDefined ? &_processedFileInfo.LastWriteTime : NULL,
+ newFileSizeDefined ? &newFileSize : NULL,
+ &overwiteResult))
+
+ switch(overwiteResult)
+ {
+ case NOverwriteAnswer::kCancel:
+ return E_ABORT;
+ case NOverwriteAnswer::kNo:
+ return S_OK;
+ case NOverwriteAnswer::kNoToAll:
+ _overwriteMode = NExtract::NOverwriteMode::kSkipExisting;
+ return S_OK;
+ case NOverwriteAnswer::kYesToAll:
+ _overwriteMode = NExtract::NOverwriteMode::kWithoutPrompt;
+ break;
+ case NOverwriteAnswer::kYes:
+ break;
+ case NOverwriteAnswer::kAutoRename:
+ _overwriteMode = NExtract::NOverwriteMode::kAutoRename;
+ break;
+ default:
+ throw 20413;
+ }
+ }
+ }
+ if (_overwriteMode == NExtract::NOverwriteMode::kAutoRename)
+ {
+ if (!AutoRenamePath(fullProcessedPath))
+ {
+ UString message = UString(kCantAutoRename) + fullProcessedPath;
+ RINOK(_extractCallback2->MessageError(message));
+ return E_FAIL;
+ }
+ }
+ else if (_overwriteMode == NExtract::NOverwriteMode::kAutoRenameExisting)
+ {
+ UString existPath = fullProcessedPath;
+ if (!AutoRenamePath(existPath))
+ {
+ UString message = kCantAutoRename + fullProcessedPath;
+ RINOK(_extractCallback2->MessageError(message));
+ return E_FAIL;
+ }
+ if(!NFile::NDirectory::MyMoveFile(fullProcessedPath, existPath))
+ {
+ UString message = UString(kCantRenameFile) + fullProcessedPath;
+ RINOK(_extractCallback2->MessageError(message));
+ return E_FAIL;
+ }
+ }
+ else
+ if (!NFile::NDirectory::DeleteFileAlways(fullProcessedPath))
+ {
+ UString message = UString(kCantDeleteOutputFile) +
+ fullProcessedPath;
+ RINOK(_extractCallback2->MessageError(message));
+ return E_FAIL;
+ }
+ }
+ }
+ if (!isAnti)
+ {
+ _outFileStreamSpec = new COutFileStream;
+ CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
+ if (!_outFileStreamSpec->File.Open(fullProcessedPath,
+ _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS))
+ {
+ // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit)
+ {
+ UString message = L"can not open output file " + fullProcessedPath;
+ RINOK(_extractCallback2->MessageError(message));
+ return S_OK;
+ }
+ }
+ if (_isSplit)
+ {
+ RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL));
+ }
+ _outFileStream = outStreamLoc;
+ *outStream = outStreamLoc.Detach();
+ }
+ _diskFilePath = fullProcessedPath;
+ }
+ else
+ {
+ *outStream = NULL;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)
+{
+ COM_TRY_BEGIN
+ _extractMode = false;
+ switch (askExtractMode)
+ {
+ case NArchive::NExtract::NAskMode::kExtract:
+ _extractMode = true;
+ };
+ return _extractCallback2->PrepareOperation(_filePath, askExtractMode, _isSplit ? &_position: 0);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult)
+{
+ COM_TRY_BEGIN
+ switch(operationResult)
+ {
+ case NArchive::NExtract::NOperationResult::kOK:
+ case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
+ case NArchive::NExtract::NOperationResult::kCRCError:
+ case NArchive::NExtract::NOperationResult::kDataError:
+ break;
+ default:
+ _outFileStream.Release();
+ return E_FAIL;
+ }
+ if(_outFileStream != NULL)
+ _outFileStreamSpec->File.SetTime(
+ (WriteCreated && _processedFileInfo.IsCreationTimeDefined) ? &_processedFileInfo.CreationTime : NULL,
+ (WriteAccessed && _processedFileInfo.IsLastAccessTimeDefined) ? &_processedFileInfo.LastAccessTime : NULL,
+ (WriteModified && _processedFileInfo.IsLastWriteTimeDefined) ? &_processedFileInfo.LastWriteTime : &_utcLastWriteTimeDefault);
+ _outFileStream.Release();
+ if (_extractMode && _processedFileInfo.AttributesAreDefined)
+ NFile::NDirectory::MySetFileAttributes(_diskFilePath, _processedFileInfo.Attributes);
+ RINOK(_extractCallback2->SetOperationResult(operationResult, _encrypted));
+ return S_OK;
+ COM_TRY_END
+}
+
+/*
+STDMETHODIMP CArchiveExtractCallback::GetInStream(
+ const wchar_t *name, ISequentialInStream **inStream)
+{
+ COM_TRY_BEGIN
+ CInFileStream *inFile = new CInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamTemp = inFile;
+ if (!inFile->Open(_srcDirectoryPrefix + name))
+ return ::GetLastError();
+ *inStream = inStreamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+*/
+
+STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
+{
+ COM_TRY_BEGIN
+ if (!_cryptoGetTextPassword)
+ {
+ RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword,
+ &_cryptoGetTextPassword));
+ }
+ return _cryptoGetTextPassword->CryptoGetTextPassword(password);
+ COM_TRY_END
+}
+
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
new file mode 100755
index 00000000..4fd63a53
--- /dev/null
+++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
@@ -0,0 +1,111 @@
+// ArchiveExtractCallback.h
+
+#ifndef __ARCHIVEEXTRACTCALLBACK_H
+#define __ARCHIVEEXTRACTCALLBACK_H
+
+#include "../../Archive/IArchive.h"
+#include "IFileExtractCallback.h"
+
+#include "Common/String.h"
+#include "Common/MyCom.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../IPassword.h"
+
+#include "ExtractMode.h"
+
+class CArchiveExtractCallback:
+ public IArchiveExtractCallback,
+ // public IArchiveVolumeExtractCallback,
+ public ICryptoGetTextPassword,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP1(ICryptoGetTextPassword)
+ // COM_INTERFACE_ENTRY(IArchiveVolumeExtractCallback)
+
+ // IProgress
+ STDMETHOD(SetTotal)(UInt64 size);
+ STDMETHOD(SetCompleted)(const UInt64 *completeValue);
+
+ // IExtractCallBack
+ STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode);
+ STDMETHOD(PrepareOperation)(Int32 askExtractMode);
+ STDMETHOD(SetOperationResult)(Int32 resultEOperationResult);
+
+ // IArchiveVolumeExtractCallback
+ // STDMETHOD(GetInStream)(const wchar_t *name, ISequentialInStream **inStream);
+
+ // ICryptoGetTextPassword
+ STDMETHOD(CryptoGetTextPassword)(BSTR *aPassword);
+
+private:
+ CMyComPtr<IInArchive> _archiveHandler;
+ CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2;
+ CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
+ UString _directoryPath;
+ NExtract::NPathMode::EEnum _pathMode;
+ NExtract::NOverwriteMode::EEnum _overwriteMode;
+
+ UString _filePath;
+ UInt64 _position;
+ bool _isSplit;
+
+ UString _diskFilePath;
+
+ bool _extractMode;
+
+ bool WriteModified;
+ bool WriteCreated;
+ bool WriteAccessed;
+
+ bool _encrypted;
+
+ struct CProcessedFileInfo
+ {
+ FILETIME CreationTime;
+ FILETIME LastWriteTime;
+ FILETIME LastAccessTime;
+ UInt32 Attributes;
+
+ bool IsCreationTimeDefined;
+ bool IsLastWriteTimeDefined;
+ bool IsLastAccessTimeDefined;
+
+ bool IsDirectory;
+ bool AttributesAreDefined;
+ } _processedFileInfo;
+
+ COutFileStream *_outFileStreamSpec;
+ CMyComPtr<ISequentialOutStream> _outFileStream;
+ UStringVector _removePathParts;
+
+ UString _itemDefaultName;
+ FILETIME _utcLastWriteTimeDefault;
+ UInt32 _attributesDefault;
+ bool _stdOutMode;
+
+ void CreateComplexDirectory(const UStringVector &dirPathParts, UString &fullPath);
+ HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined);
+public:
+ CArchiveExtractCallback():
+ WriteModified(true),
+ WriteCreated(false),
+ WriteAccessed(false)
+ {}
+ void Init(
+ IInArchive *archiveHandler,
+ IFolderArchiveExtractCallback *extractCallback2,
+ bool stdOutMode,
+ const UString &directoryPath,
+ NExtract::NPathMode::EEnum pathMode,
+ NExtract::NOverwriteMode::EEnum overwriteMode,
+ const UStringVector &removePathParts,
+ const UString &itemDefaultName,
+ const FILETIME &utcLastWriteTimeDefault,
+ UInt32 attributesDefault);
+
+ UInt64 _numErrors;
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/ArchiveName.cpp b/CPP/7zip/UI/Common/ArchiveName.cpp
new file mode 100755
index 00000000..2d50ede1
--- /dev/null
+++ b/CPP/7zip/UI/Common/ArchiveName.cpp
@@ -0,0 +1,46 @@
+// ArchiveName.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/FileFind.h"
+#include "Windows/FileDir.h"
+
+using namespace NWindows;
+
+UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName)
+{
+ UString resultName = L"Archive";
+ if (fromPrev)
+ {
+ UString dirPrefix;
+ if (NFile::NDirectory::GetOnlyDirPrefix(srcName, dirPrefix))
+ {
+ if (dirPrefix.Length() > 0)
+ if (dirPrefix[dirPrefix.Length() - 1] == '\\')
+ {
+ dirPrefix.Delete(dirPrefix.Length() - 1);
+ NFile::NFind::CFileInfoW fileInfo;
+ if (NFile::NFind::FindFile(dirPrefix, fileInfo))
+ resultName = fileInfo.Name;
+ }
+ }
+ }
+ else
+ {
+ NFile::NFind::CFileInfoW fileInfo;
+ if (!NFile::NFind::FindFile(srcName, fileInfo))
+ return resultName;
+ resultName = fileInfo.Name;
+ if (!fileInfo.IsDirectory() && !keepName)
+ {
+ int dotPos = resultName.ReverseFind('.');
+ if (dotPos > 0)
+ {
+ UString archiveName2 = resultName.Left(dotPos);
+ if (archiveName2.ReverseFind('.') < 0)
+ resultName = archiveName2;
+ }
+ }
+ }
+ return resultName;
+}
diff --git a/CPP/7zip/UI/Common/ArchiveName.h b/CPP/7zip/UI/Common/ArchiveName.h
new file mode 100755
index 00000000..6b001a5a
--- /dev/null
+++ b/CPP/7zip/UI/Common/ArchiveName.h
@@ -0,0 +1,10 @@
+// ArchiveName.h
+
+#ifndef __ARCHIVENAME_H
+#define __ARCHIVENAME_H
+
+#include "Common/String.h"
+
+UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName);
+
+#endif
diff --git a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
new file mode 100755
index 00000000..1d2944d8
--- /dev/null
+++ b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
@@ -0,0 +1,127 @@
+// ArchiveOpenCallback.cpp
+
+#include "StdAfx.h"
+
+#include "ArchiveOpenCallback.h"
+
+#include "Common/StringConvert.h"
+#include "Common/ComTry.h"
+#include "Windows/PropVariant.h"
+
+#include "../../Common/FileStreams.h"
+
+using namespace NWindows;
+
+STDMETHODIMP COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes)
+{
+ COM_TRY_BEGIN
+ return Callback->SetTotal(files, bytes);
+ COM_TRY_END
+}
+
+STDMETHODIMP COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes)
+{
+ COM_TRY_BEGIN
+ return Callback->SetTotal(files, bytes);
+ COM_TRY_END
+}
+
+STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant propVariant;
+ if (_subArchiveMode)
+ {
+ switch(propID)
+ {
+ case kpidName:
+ propVariant = _subArchiveName;
+ break;
+ }
+ propVariant.Detach(value);
+ return S_OK;
+ }
+ switch(propID)
+ {
+ case kpidName:
+ propVariant = _fileInfo.Name;
+ break;
+ case kpidIsFolder:
+ propVariant = _fileInfo.IsDirectory();
+ break;
+ case kpidSize:
+ propVariant = _fileInfo.Size;
+ break;
+ case kpidAttributes:
+ propVariant = (UInt32)_fileInfo.Attributes;
+ break;
+ case kpidLastAccessTime:
+ propVariant = _fileInfo.LastAccessTime;
+ break;
+ case kpidCreationTime:
+ propVariant = _fileInfo.CreationTime;
+ break;
+ case kpidLastWriteTime:
+ propVariant = _fileInfo.LastWriteTime;
+ break;
+ }
+ propVariant.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+int COpenCallbackImp::FindName(const UString &name)
+{
+ for (int i = 0; i < FileNames.Size(); i++)
+ if (name.CompareNoCase(FileNames[i]) == 0)
+ return i;
+ return -1;
+}
+
+struct CInFileStreamVol: public CInFileStream
+{
+ UString Name;
+ COpenCallbackImp *OpenCallbackImp;
+ CMyComPtr<IArchiveOpenCallback> OpenCallbackRef;
+ ~CInFileStreamVol()
+ {
+ int index = OpenCallbackImp->FindName(Name);
+ if (index >= 0)
+ OpenCallbackImp->FileNames.Delete(index);
+ }
+};
+
+STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream)
+{
+ COM_TRY_BEGIN
+ if (_subArchiveMode)
+ return S_FALSE;
+ RINOK(Callback->CheckBreak());
+ *inStream = NULL;
+ UString fullPath = _folderPrefix + name;
+ if (!NFile::NFind::FindFile(fullPath, _fileInfo))
+ return S_FALSE;
+ if (_fileInfo.IsDirectory())
+ return S_FALSE;
+ CInFileStreamVol *inFile = new CInFileStreamVol;
+ CMyComPtr<IInStream> inStreamTemp = inFile;
+ if (!inFile->Open(fullPath))
+ return ::GetLastError();
+ *inStream = inStreamTemp.Detach();
+ inFile->Name = name;
+ inFile->OpenCallbackImp = this;
+ inFile->OpenCallbackRef = this;
+ FileNames.Add(name);
+ return S_OK;
+ COM_TRY_END
+}
+
+#ifndef _NO_CRYPTO
+STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password)
+{
+ COM_TRY_BEGIN
+ return Callback->CryptoGetTextPassword(password);
+ COM_TRY_END
+}
+#endif
+
diff --git a/CPP/7zip/UI/Common/ArchiveOpenCallback.h b/CPP/7zip/UI/Common/ArchiveOpenCallback.h
new file mode 100755
index 00000000..454873ad
--- /dev/null
+++ b/CPP/7zip/UI/Common/ArchiveOpenCallback.h
@@ -0,0 +1,89 @@
+// ArchiveOpenCallback.h
+
+#ifndef __ARCHIVE_OPEN_CALLBACK_H
+#define __ARCHIVE_OPEN_CALLBACK_H
+
+#include "Common/String.h"
+#include "Common/MyCom.h"
+#include "Windows/FileFind.h"
+
+#ifndef _NO_CRYPTO
+#include "../../IPassword.h"
+#endif
+#include "../../Archive/IArchive.h"
+
+struct IOpenCallbackUI
+{
+ virtual HRESULT CheckBreak() = 0;
+ virtual HRESULT SetTotal(const UInt64 *files, const UInt64 *bytes) = 0;
+ virtual HRESULT SetCompleted(const UInt64 *files, const UInt64 *bytes) = 0;
+ #ifndef _NO_CRYPTO
+ virtual HRESULT CryptoGetTextPassword(BSTR *password) = 0;
+ virtual HRESULT GetPasswordIfAny(UString &password) = 0;
+ virtual bool WasPasswordAsked() = 0;
+ virtual void ClearPasswordWasAskedFlag() = 0;
+ #endif
+};
+
+class COpenCallbackImp:
+ public IArchiveOpenCallback,
+ public IArchiveOpenVolumeCallback,
+ public IArchiveOpenSetSubArchiveName,
+ #ifndef _NO_CRYPTO
+ public ICryptoGetTextPassword,
+ #endif
+ public CMyUnknownImp
+{
+public:
+ #ifndef _NO_CRYPTO
+ MY_UNKNOWN_IMP3(
+ IArchiveOpenVolumeCallback,
+ ICryptoGetTextPassword,
+ IArchiveOpenSetSubArchiveName
+ )
+ #else
+ MY_UNKNOWN_IMP2(
+ IArchiveOpenVolumeCallback,
+ IArchiveOpenSetSubArchiveName
+ )
+ #endif
+
+ STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes);
+ STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes);
+
+ // IArchiveOpenVolumeCallback
+ STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value);
+ STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream);
+
+ #ifndef _NO_CRYPTO
+ // ICryptoGetTextPassword
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+ #endif
+
+ STDMETHOD(SetSubArchiveName(const wchar_t *name))
+ {
+ _subArchiveMode = true;
+ _subArchiveName = name;
+ return S_OK;
+ }
+
+private:
+ UString _folderPrefix;
+ NWindows::NFile::NFind::CFileInfoW _fileInfo;
+ bool _subArchiveMode;
+ UString _subArchiveName;
+public:
+ UStringVector FileNames;
+ IOpenCallbackUI *Callback;
+ void Init(const UString &folderPrefix, const UString &fileName)
+ {
+ _folderPrefix = folderPrefix;
+ if (!NWindows::NFile::NFind::FindFile(_folderPrefix + fileName, _fileInfo))
+ throw 1;
+ FileNames.Clear();
+ _subArchiveMode = false;
+ }
+ int FindName(const UString &name);
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/ArchiverInfo.cpp b/CPP/7zip/UI/Common/ArchiverInfo.cpp
new file mode 100755
index 00000000..7833ed3c
--- /dev/null
+++ b/CPP/7zip/UI/Common/ArchiverInfo.cpp
@@ -0,0 +1,372 @@
+// ArchiverInfo.cpp
+
+#include "StdAfx.h"
+
+#include "ArchiverInfo.h"
+
+#ifndef EXCLUDE_COM
+
+#include "Common/StringConvert.h"
+#include "Windows/FileFind.h"
+#include "Windows/FileName.h"
+#include "Windows/DLL.h"
+#ifdef _WIN32
+#include "Windows/Registry.h"
+#endif
+#include "Windows/PropVariant.h"
+#include "../../Archive/IArchive.h"
+
+using namespace NWindows;
+using namespace NFile;
+
+#endif
+
+extern HINSTANCE g_hInstance;
+
+#ifndef EXCLUDE_COM
+
+static void SplitString(const UString &srcString, UStringVector &destStrings)
+{
+ destStrings.Clear();
+ UString string;
+ int len = srcString.Length();
+ if (len == 0)
+ return;
+ for (int i = 0; i < len; i++)
+ {
+ wchar_t c = srcString[i];
+ if (c == L' ')
+ {
+ if (!string.IsEmpty())
+ {
+ destStrings.Add(string);
+ string.Empty();
+ }
+ }
+ else
+ string += c;
+ }
+ if (!string.IsEmpty())
+ destStrings.Add(string);
+}
+
+typedef UInt32 (WINAPI * GetHandlerPropertyFunc)(
+ PROPID propID, PROPVARIANT *value);
+
+static UString GetModuleFolderPrefix()
+{
+ UString path;
+ NDLL::MyGetModuleFileName(g_hInstance, path);
+ int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR);
+ return path.Left(pos + 1);
+}
+
+static wchar_t *kFormatFolderName = L"Formats";
+
+#ifdef _WIN32
+static LPCTSTR kRegistryPath = TEXT("Software\\7-zip");
+static LPCWSTR kProgramPathValue = L"Path";
+static bool ReadPathFromRegistry(HKEY baseKey, UString &path)
+{
+ NRegistry::CKey key;
+ if(key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS)
+ if (key.QueryValue(kProgramPathValue, path) == ERROR_SUCCESS)
+ {
+ NName::NormalizeDirPathPrefix(path);
+ return true;
+ }
+ return false;
+}
+#endif
+
+static UString GetBaseFolderPrefixFromRegistry()
+{
+ UString moduleFolderPrefix = GetModuleFolderPrefix();
+ NFind::CFileInfoW fileInfo;
+ if (NFind::FindFile(moduleFolderPrefix + kFormatFolderName, fileInfo))
+ if (fileInfo.IsDirectory())
+ return moduleFolderPrefix;
+ UString path;
+ #ifdef _WIN32
+ if(ReadPathFromRegistry(HKEY_CURRENT_USER, path))
+ return path;
+ if(ReadPathFromRegistry(HKEY_LOCAL_MACHINE, path))
+ return path;
+ #endif
+ return moduleFolderPrefix;
+}
+
+typedef UInt32 (WINAPI *CreateObjectPointer)(
+ const GUID *clsID,
+ const GUID *interfaceID,
+ void **outObject);
+
+#endif
+
+#ifndef _SFX
+static inline void SetBuffer(CByteBuffer &bb, const Byte *data, int size)
+{
+ bb.SetCapacity(size);
+ memmove((Byte *)bb, data, size);
+}
+#endif
+
+void ReadArchiverInfoList(CObjectVector<CArchiverInfo> &archivers)
+{
+ archivers.Clear();
+
+ #ifdef EXCLUDE_COM
+
+ #ifdef FORMAT_7Z
+ {
+ CArchiverInfo item;
+ item.UpdateEnabled = true;
+ item.Name = L"7z";
+ item.Extensions.Add(CArchiverExtInfo(L"7z"));
+ #ifndef _SFX
+ const unsigned char kSig[] = {'7' , 'z', 0xBC, 0xAF, 0x27, 0x1C};
+ SetBuffer(item.StartSignature, kSig, 6);
+ #endif
+ archivers.Add(item);
+ }
+ #endif
+
+ #ifdef FORMAT_BZIP2
+ {
+ CArchiverInfo item;
+ item.UpdateEnabled = true;
+ item.KeepName = true;
+ item.Name = L"BZip2";
+ item.Extensions.Add(CArchiverExtInfo(L"bz2"));
+ item.Extensions.Add(CArchiverExtInfo(L"tbz2", L".tar"));
+ #ifndef _SFX
+ const unsigned char sig[] = {'B' , 'Z', 'h' };
+ SetBuffer(item.StartSignature, sig, 3);
+ #endif
+ archivers.Add(item);
+ }
+ #endif
+
+ #ifdef FORMAT_CAB
+ {
+ CArchiverInfo item;
+ item.Name = L"Cab";
+ item.Extensions.Add(CArchiverExtInfo(L"cab"));
+ #ifndef _SFX
+ const unsigned char sig[] = { 0x4D, 0x53, 0x43, 0x46 };
+ SetBuffer(item.StartSignature, sig, 4);
+ #endif
+ archivers.Add(item);
+ }
+ #endif
+
+ #ifdef FORMAT_GZIP
+ {
+ CArchiverInfo item;
+ item.UpdateEnabled = true;
+ item.Name = L"GZip";
+ item.Extensions.Add(CArchiverExtInfo(L"gz"));
+ item.Extensions.Add(CArchiverExtInfo(L"tgz", L".tar"));
+ #ifndef _SFX
+ const unsigned char sig[] = { 0x1F, 0x8B };
+ SetBuffer(item.StartSignature, sig, 2);
+ #endif
+ archivers.Add(item);
+ }
+ #endif
+
+ #ifdef FORMAT_SPLIT
+ {
+ CArchiverInfo item;
+ item.UpdateEnabled = false;
+ item.KeepName = true;
+ item.Name = L"Split";
+ item.Extensions.Add(CArchiverExtInfo(L"001"));
+ archivers.Add(item);
+ }
+ #endif
+
+ #ifdef FORMAT_TAR
+ {
+ CArchiverInfo item;
+ item.UpdateEnabled = true;
+ item.Name = L"Tar";
+ item.Extensions.Add(CArchiverExtInfo(L"tar"));
+ archivers.Add(item);
+ }
+ #endif
+
+ #ifdef FORMAT_ZIP
+ {
+ CArchiverInfo item;
+ item.UpdateEnabled = true;
+ item.Name = L"Zip";
+ item.Extensions.Add(CArchiverExtInfo(L"zip"));
+ #ifndef _SFX
+ const unsigned char sig[] = { 0x50, 0x4B, 0x03, 0x04 };
+ SetBuffer(item.StartSignature, sig, 4);
+ #endif
+ archivers.Add(item);
+ }
+ #endif
+
+ #ifdef FORMAT_CPIO
+ {
+ CArchiverInfo item;
+ item.Name = L"Cpio";
+ item.Extensions.Add(CArchiverExtInfo(L"cpio"));
+ archivers.Add(item);
+ }
+ #endif
+
+ #ifdef FORMAT_RPM
+ {
+ CArchiverInfo item;
+ item.Name = L"Rpm";
+ item.Extensions.Add(CArchiverExtInfo(L"rpm", L".cpio.gz"));
+ archivers.Add(item);
+ }
+ #endif
+
+ #ifdef FORMAT_ARJ
+ {
+ CArchiverInfo item;
+ item.Name = L"Arj";
+ item.Extensions.Add(CArchiverExtInfo(L"arj"));
+ #ifndef _SFX
+ const unsigned char sig[] = { 0x60, 0xEA };
+ SetBuffer(item.StartSignature, sig, 2);
+ #endif
+ archivers.Add(item);
+ }
+ #endif
+
+ #ifdef FORMAT_Z
+ {
+ CArchiverInfo item;
+ item.Name = L"Z";
+ item.Extensions.Add(CArchiverExtInfo(L"Z"));
+ #ifndef _SFX
+ const unsigned char sig[] = { 0x1F, 0x9D };
+ SetBuffer(item.StartSignature, sig, 2);
+ #endif
+ archivers.Add(item);
+ }
+ #endif
+
+ #else
+
+ UString folderPath = GetBaseFolderPrefixFromRegistry() +
+ (UString)kFormatFolderName + (UString)WSTRING_PATH_SEPARATOR;
+ NFind::CEnumeratorW enumerator(folderPath + L"*");
+ NFind::CFileInfoW fileInfo;
+ while (enumerator.Next(fileInfo))
+ {
+ if (fileInfo.IsDirectory())
+ continue;
+ UString filePath = folderPath + fileInfo.Name;
+ {
+ NDLL::CLibrary library;
+ if (!library.LoadEx(filePath, LOAD_LIBRARY_AS_DATAFILE))
+ continue;
+ }
+
+ NDLL::CLibrary library;
+ if (!library.Load(filePath))
+ continue;
+ GetHandlerPropertyFunc getHandlerProperty = (GetHandlerPropertyFunc)
+ library.GetProcAddress("GetHandlerProperty");
+ if (getHandlerProperty == NULL)
+ continue;
+
+ CArchiverInfo item;
+ item.FilePath = filePath;
+
+ NWindows::NCOM::CPropVariant prop;
+ if (getHandlerProperty(NArchive::kName, &prop) != S_OK)
+ continue;
+ if (prop.vt != VT_BSTR)
+ continue;
+ item.Name = prop.bstrVal;
+ prop.Clear();
+
+ if (getHandlerProperty(NArchive::kClassID, &prop) != S_OK)
+ continue;
+ if (prop.vt != VT_BSTR)
+ continue;
+ item.ClassID = *(const GUID *)prop.bstrVal;
+ prop.Clear();
+
+ if (getHandlerProperty(NArchive::kExtension, &prop) != S_OK)
+ continue;
+ if (prop.vt != VT_BSTR)
+ continue;
+
+ UString ext = prop.bstrVal;
+ UString addExt;
+
+ prop.Clear();
+
+ if (getHandlerProperty(NArchive::kAddExtension, &prop) != S_OK)
+ continue;
+ if (prop.vt == VT_BSTR)
+ {
+ addExt = prop.bstrVal;
+ }
+ else if (prop.vt != VT_EMPTY)
+ continue;
+ prop.Clear();
+
+ UStringVector exts, addExts;
+ SplitString(ext, exts);
+ SplitString(addExt, addExts);
+
+ prop.Clear();
+ for (int i = 0; i < exts.Size(); i++)
+ {
+ CArchiverExtInfo extInfo;
+ extInfo.Ext = exts[i];
+ if (addExts.Size() > 0)
+ extInfo.AddExt = addExts[i];
+ if (extInfo.AddExt == L"*")
+ extInfo.AddExt.Empty();
+ item.Extensions.Add(extInfo);
+ }
+
+ if (getHandlerProperty(NArchive::kUpdate, &prop) == S_OK)
+ if (prop.vt == VT_BOOL)
+ item.UpdateEnabled = VARIANT_BOOLToBool(prop.boolVal);
+ prop.Clear();
+
+ if (item.UpdateEnabled)
+ {
+ if (getHandlerProperty(NArchive::kKeepName, &prop) == S_OK)
+ if (prop.vt == VT_BOOL)
+ item.KeepName = VARIANT_BOOLToBool(prop.boolVal);
+ prop.Clear();
+ }
+
+ if (getHandlerProperty(NArchive::kStartSignature, &prop) == S_OK)
+ {
+ if (prop.vt == VT_BSTR)
+ {
+ UINT len = ::SysStringByteLen(prop.bstrVal);
+ item.StartSignature.SetCapacity(len);
+ memmove(item.StartSignature, prop.bstrVal, len);
+ }
+ }
+ prop.Clear();
+
+ if (getHandlerProperty(NArchive::kAssociate, &prop) == S_OK)
+ if (prop.vt == VT_BOOL)
+ item.Associate = VARIANT_BOOLToBool(prop.boolVal);
+ prop.Clear();
+
+
+ archivers.Add(item);
+ }
+
+ #endif
+}
+
+
diff --git a/CPP/7zip/UI/Common/ArchiverInfo.h b/CPP/7zip/UI/Common/ArchiverInfo.h
new file mode 100755
index 00000000..3b829518
--- /dev/null
+++ b/CPP/7zip/UI/Common/ArchiverInfo.h
@@ -0,0 +1,66 @@
+// ArchiverInfo.h
+
+#ifndef __ARCHIVERINFO_H
+#define __ARCHIVERINFO_H
+
+#include "Common/String.h"
+#include "Common/Types.h"
+#include "Common/Buffer.h"
+
+struct CArchiverExtInfo
+{
+ UString Ext;
+ UString AddExt;
+ CArchiverExtInfo() {}
+ CArchiverExtInfo(const UString &ext): Ext(ext) {}
+ CArchiverExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {}
+};
+
+struct CArchiverInfo
+{
+ #ifndef EXCLUDE_COM
+ UString FilePath;
+ CLSID ClassID;
+ #endif
+ UString Name;
+ CObjectVector<CArchiverExtInfo> Extensions;
+ #ifndef _SFX
+ CByteBuffer StartSignature;
+ CByteBuffer FinishSignature;
+ bool Associate;
+ #endif
+ int FindExtension(const UString &ext) const
+ {
+ for (int i = 0; i < Extensions.Size(); i++)
+ if (ext.CompareNoCase(Extensions[i].Ext) == 0)
+ return i;
+ return -1;
+ }
+ UString GetAllExtensions() const
+ {
+ UString s;
+ for (int i = 0; i < Extensions.Size(); i++)
+ {
+ if (i > 0)
+ s += ' ';
+ s += Extensions[i].Ext;
+ }
+ return s;
+ }
+ const UString &GetMainExtension() const
+ {
+ return Extensions[0].Ext;
+ }
+ bool UpdateEnabled;
+ bool KeepName;
+
+ CArchiverInfo(): UpdateEnabled(false), KeepName(false)
+ #ifndef _SFX
+ ,Associate(true)
+ #endif
+ {}
+};
+
+void ReadArchiverInfoList(CObjectVector<CArchiverInfo> &archivers);
+
+#endif
diff --git a/CPP/7zip/UI/Common/CompressCall.cpp b/CPP/7zip/UI/Common/CompressCall.cpp
new file mode 100755
index 00000000..86bdd297
--- /dev/null
+++ b/CPP/7zip/UI/Common/CompressCall.cpp
@@ -0,0 +1,367 @@
+// CompressCall.cpp
+
+#include "StdAfx.h"
+
+#include "CompressCall.h"
+
+#include "Common/Random.h"
+#include "Common/IntToString.h"
+#include "Common/MyCom.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/Synchronization.h"
+#include "Windows/FileMapping.h"
+#include "Windows/FileDir.h"
+
+#include "../../FileManager/ProgramLocation.h"
+#include "../../FileManager/RegistryUtils.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif _UNICODE
+
+using namespace NWindows;
+
+static LPCWSTR kShowDialogSwitch = L" -ad";
+static LPCWSTR kEmailSwitch = L" -seml.";
+static LPCWSTR kMapSwitch = L" -i#";
+static LPCWSTR kArchiveNoNameSwitch = L" -an";
+static LPCWSTR kArchiveTypeSwitch = L" -t";
+static LPCWSTR kArchiveMapSwitch = L" -ai#";
+static LPCWSTR kStopSwitchParsing = L" --";
+static LPCWSTR kLargePagesDisable = L" -slp-";
+
+static void AddLagePagesSwitch(UString &params)
+{
+ if (!ReadLockMemoryEnable())
+ params += kLargePagesDisable;
+}
+
+HRESULT MyCreateProcess(const UString &params,
+ LPCWSTR curDir, bool waitFinish,
+ NWindows::NSynchronization::CEvent *event)
+{
+ const UString params2 = params;
+ PROCESS_INFORMATION processInformation;
+ BOOL result;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ STARTUPINFOA startupInfo;
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpReserved = 0;
+ startupInfo.lpDesktop = 0;
+ startupInfo.lpTitle = 0;
+ startupInfo.dwFlags = 0;
+ startupInfo.cbReserved2 = 0;
+ startupInfo.lpReserved2 = 0;
+
+ CSysString curDirA;
+ if (curDir != 0)
+ curDirA = GetSystemString(curDir);
+ result = ::CreateProcessA(NULL, (LPSTR)(LPCSTR)GetSystemString(params),
+ NULL, NULL, FALSE, 0, NULL,
+ ((curDir != 0) ? (LPCSTR)curDirA: 0),
+ &startupInfo, &processInformation);
+ }
+ else
+ #endif
+ {
+ STARTUPINFOW startupInfo;
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpReserved = 0;
+ startupInfo.lpDesktop = 0;
+ startupInfo.lpTitle = 0;
+ startupInfo.dwFlags = 0;
+ startupInfo.cbReserved2 = 0;
+ startupInfo.lpReserved2 = 0;
+
+ result = ::CreateProcessW(NULL, (LPWSTR)(LPCWSTR)params,
+ NULL, NULL, FALSE, 0, NULL,
+ curDir,
+ &startupInfo, &processInformation);
+ }
+ if (result == 0)
+ return ::GetLastError();
+ else
+ {
+ ::CloseHandle(processInformation.hThread);
+ if (waitFinish)
+ WaitForSingleObject(processInformation.hProcess, INFINITE);
+ else if (event != NULL)
+ {
+ HANDLE handles[] = {processInformation.hProcess, *event };
+ ::WaitForMultipleObjects(sizeof(handles) / sizeof(handles[0]),
+ handles, FALSE, INFINITE);
+ }
+ ::CloseHandle(processInformation.hProcess);
+ }
+ return S_OK;
+}
+
+static UString GetQuotedString(const UString &s)
+{
+ return UString(L"\"") + s + UString(L"\"");
+}
+
+static UString Get7zGuiPath()
+{
+ UString path;
+ UString folder;
+ if (GetProgramFolderPath(folder))
+ path += folder;
+ path += L"7zG.exe";
+ return GetQuotedString(path);
+}
+
+static HRESULT CreateMap(const UStringVector &names,
+ const UString &id,
+ CFileMapping &fileMapping, NSynchronization::CEvent &event,
+ UString &params)
+{
+ UInt32 extraSize = 2;
+ UInt32 dataSize = 0;
+ for (int i = 0; i < names.Size(); i++)
+ dataSize += (names[i].Length() + 1) * sizeof(wchar_t);
+ UInt32 totalSize = extraSize + dataSize;
+
+ UString mappingName;
+ UString eventName;
+
+ CRandom random;
+ random.Init(GetTickCount());
+ for (;;)
+ {
+ int number = random.Generate();
+ wchar_t temp[32];
+ ConvertUInt64ToString(UInt32(number), temp);
+ mappingName = id;
+ mappingName += L"Mapping";
+ mappingName += temp;
+ if (!fileMapping.Create(INVALID_HANDLE_VALUE, NULL,
+ PAGE_READWRITE, totalSize, GetSystemString(mappingName)))
+ return E_FAIL;
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ break;
+ fileMapping.Close();
+ }
+
+ for (;;)
+ {
+ int number = random.Generate();
+ wchar_t temp[32];
+ ConvertUInt64ToString(UInt32(number), temp);
+ eventName = id;
+ eventName += L"MappingEndEvent";
+ eventName += temp;
+ if (!event.Create(true, false, GetSystemString(eventName)))
+ return E_FAIL;
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ break;
+ event.Close();
+ }
+
+ params += mappingName;
+ params += L":";
+ wchar_t string[10];
+ ConvertUInt64ToString(totalSize, string);
+ params += string;
+
+ params += L":";
+ params += eventName;
+
+ LPVOID data = fileMapping.MapViewOfFile(FILE_MAP_WRITE, 0, totalSize);
+ if (data == NULL)
+ return E_FAIL;
+ {
+ wchar_t *curData = (wchar_t *)data;
+ *curData = 0;
+ curData++;
+ for (int i = 0; i < names.Size(); i++)
+ {
+ const UString &s = names[i];
+ memcpy(curData, (const wchar_t *)s, s.Length() * sizeof(wchar_t));
+ curData += s.Length();
+ *curData++ = L'\0';
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CompressFiles(
+ const UString &curDir,
+ const UString &archiveName,
+ const UString &archiveType,
+ const UStringVector &names,
+ // const UString &outFolder,
+ bool email,
+ bool showDialog,
+ bool waitFinish)
+{
+ /*
+ UString curDir;
+ if (names.Size() > 0)
+ {
+ NFile::NDirectory::GetOnlyDirPrefix(names[0], curDir);
+ }
+ */
+ UString params;
+ params = Get7zGuiPath();
+ params += L" a";
+ params += kMapSwitch;
+ // params += _fileNames[0];
+
+ UInt32 extraSize = 2;
+ UInt32 dataSize = 0;
+ for (int i = 0; i < names.Size(); i++)
+ dataSize += (names[i].Length() + 1) * sizeof(wchar_t);
+ UInt32 totalSize = extraSize + dataSize;
+
+ UString mappingName;
+ UString eventName;
+
+ CFileMapping fileMapping;
+ CRandom random;
+ random.Init(GetTickCount());
+ for (;;)
+ {
+ int number = random.Generate();
+ wchar_t temp[32];
+ ConvertUInt64ToString(UInt32(number), temp);
+ mappingName = L"7zCompressMapping";
+ mappingName += temp;
+ if (!fileMapping.Create(INVALID_HANDLE_VALUE, NULL,
+ PAGE_READWRITE, totalSize, GetSystemString(mappingName)))
+ {
+ // MyMessageBox(IDS_ERROR, 0x02000605);
+ return E_FAIL;
+ }
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ break;
+ fileMapping.Close();
+ }
+
+ NSynchronization::CEvent event;
+ for (;;)
+ {
+ int number = random.Generate();
+ wchar_t temp[32];
+ ConvertUInt64ToString(UInt32(number), temp);
+ eventName = L"7zCompressMappingEndEvent";
+ eventName += temp;
+ if (!event.Create(true, false, GetSystemString(eventName)))
+ {
+ // MyMessageBox(IDS_ERROR, 0x02000605);
+ return E_FAIL;
+ }
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ break;
+ event.Close();
+ }
+
+ params += mappingName;
+ params += L":";
+ wchar_t string[10];
+ ConvertUInt64ToString(totalSize, string);
+ params += string;
+
+ params += L":";
+ params += eventName;
+
+ if (!archiveType.IsEmpty())
+ {
+ params += kArchiveTypeSwitch;
+ params += archiveType;
+ }
+
+ if (email)
+ params += kEmailSwitch;
+
+ if (showDialog)
+ params += kShowDialogSwitch;
+
+ AddLagePagesSwitch(params);
+
+ params += kStopSwitchParsing;
+ params += L" ";
+
+ params += GetQuotedString(archiveName);
+
+ LPVOID data = fileMapping.MapViewOfFile(FILE_MAP_WRITE, 0, totalSize);
+ if (data == NULL)
+ {
+ // MyMessageBox(IDS_ERROR, 0x02000605);
+ return E_FAIL;
+ }
+ try
+ {
+ wchar_t *curData = (wchar_t *)data;
+ *curData = 0;
+ curData++;
+ for (int i = 0; i < names.Size(); i++)
+ {
+ const UString &unicodeString = names[i];
+ memcpy(curData, (const wchar_t *)unicodeString ,
+ unicodeString .Length() * sizeof(wchar_t));
+ curData += unicodeString.Length();
+ *curData++ = L'\0';
+ }
+ // MessageBox(0, params, 0, 0);
+ RINOK(MyCreateProcess(params,
+ (curDir.IsEmpty()? 0: (LPCWSTR)curDir),
+ waitFinish, &event));
+ }
+ catch(...)
+ {
+ UnmapViewOfFile(data);
+ throw;
+ }
+ UnmapViewOfFile(data);
+
+
+ /*
+ CThreadCompressMain *compressor = new CThreadCompressMain();;
+ compressor->FileNames = _fileNames;
+ CThread thread;
+ if (!thread.Create(CThreadCompressMain::MyThreadFunction, compressor))
+ throw 271824;
+ */
+ return S_OK;
+}
+
+static HRESULT ExtractGroupCommand(const UStringVector &archivePaths,
+ const UString &params)
+{
+ UString params2 = params;
+ AddLagePagesSwitch(params2);
+ params2 += kArchiveNoNameSwitch;
+ params2 += kArchiveMapSwitch;
+ CFileMapping fileMapping;
+ NSynchronization::CEvent event;
+ RINOK(CreateMap(archivePaths, L"7zExtract", fileMapping, event, params2));
+ return MyCreateProcess(params2, 0, false, &event);
+}
+
+HRESULT ExtractArchives(const UStringVector &archivePaths,
+ const UString &outFolder, bool showDialog)
+{
+ UString params;
+ params = Get7zGuiPath();
+ params += L" x";
+ if (!outFolder.IsEmpty())
+ {
+ params += L" -o";
+ params += GetQuotedString(outFolder);
+ }
+ if (showDialog)
+ params += kShowDialogSwitch;
+ return ExtractGroupCommand(archivePaths, params);
+}
+
+HRESULT TestArchives(const UStringVector &archivePaths)
+{
+ UString params;
+ params = Get7zGuiPath();
+ params += L" t";
+ return ExtractGroupCommand(archivePaths, params);
+}
diff --git a/CPP/7zip/UI/Common/CompressCall.h b/CPP/7zip/UI/Common/CompressCall.h
new file mode 100755
index 00000000..95be95c3
--- /dev/null
+++ b/CPP/7zip/UI/Common/CompressCall.h
@@ -0,0 +1,28 @@
+// CompressCall.h
+
+#ifndef __COMPRESSCALL_H
+#define __COMPRESSCALL_H
+
+#include "Common/String.h"
+#include "Windows/Synchronization.h"
+
+HRESULT MyCreateProcess(const UString &params,
+ LPCWSTR lpCurrentDirectory, bool waitFinish,
+ NWindows::NSynchronization::CEvent *event);
+
+HRESULT CompressFiles(
+ const UString &curDir,
+ const UString &archiveName,
+ const UString &archiveType,
+ const UStringVector &names,
+ // const UString &outFolder,
+ bool email, bool showDialog, bool waitFinish);
+
+HRESULT ExtractArchives(
+ const UStringVector &archivePaths,
+ const UString &outFolder, bool showDialog);
+
+HRESULT TestArchives(const UStringVector &archivePaths);
+
+#endif
+
diff --git a/CPP/7zip/UI/Common/DefaultName.cpp b/CPP/7zip/UI/Common/DefaultName.cpp
new file mode 100755
index 00000000..8ee7c048
--- /dev/null
+++ b/CPP/7zip/UI/Common/DefaultName.cpp
@@ -0,0 +1,26 @@
+// DefaultName.cpp
+
+#include "StdAfx.h"
+
+#include "DefaultName.h"
+
+static const wchar_t *kEmptyFileAlias = L"[Content]";
+
+UString GetDefaultName2(const UString &fileName,
+ const UString &extension, const UString &addSubExtension)
+{
+ int extLength = extension.Length();
+ int fileNameLength = fileName.Length();
+ if (fileNameLength > extLength + 1)
+ {
+ int dotPos = fileNameLength - (extLength + 1);
+ if (fileName[dotPos] == '.')
+ if (extension.CompareNoCase(fileName.Mid(dotPos + 1)) == 0)
+ return fileName.Left(dotPos) + addSubExtension;
+ }
+ int dotPos = fileName.ReverseFind(L'.');
+ if (dotPos > 0)
+ return fileName.Left(dotPos) + addSubExtension;
+ return kEmptyFileAlias;
+}
+
diff --git a/CPP/7zip/UI/Common/DefaultName.h b/CPP/7zip/UI/Common/DefaultName.h
new file mode 100755
index 00000000..ff6330fa
--- /dev/null
+++ b/CPP/7zip/UI/Common/DefaultName.h
@@ -0,0 +1,11 @@
+// DefaultName.h
+
+#ifndef __DEFAULTNAME_H
+#define __DEFAULTNAME_H
+
+#include "Common/String.h"
+
+UString GetDefaultName2(const UString &fileName,
+ const UString &extension, const UString &addSubExtension);
+
+#endif
diff --git a/CPP/7zip/UI/Common/DirItem.h b/CPP/7zip/UI/Common/DirItem.h
new file mode 100755
index 00000000..9537071c
--- /dev/null
+++ b/CPP/7zip/UI/Common/DirItem.h
@@ -0,0 +1,34 @@
+// DirItem.h
+
+#ifndef __DIR_ITEM_H
+#define __DIR_ITEM_H
+
+#include "Common/String.h"
+#include "Common/Types.h"
+
+struct CDirItem
+{
+ UInt32 Attributes;
+ FILETIME CreationTime;
+ FILETIME LastAccessTime;
+ FILETIME LastWriteTime;
+ UInt64 Size;
+ UString Name;
+ UString FullPath;
+ bool IsDirectory() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0 ; }
+};
+
+struct CArchiveItem
+{
+ bool IsDirectory;
+ // DWORD Attributes;
+ // NWindows::NCOM::CPropVariant LastWriteTime;
+ FILETIME LastWriteTime;
+ bool SizeIsDefined;
+ UInt64 Size;
+ UString Name;
+ bool Censored;
+ int IndexInServer;
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/EnumDirItems.cpp b/CPP/7zip/UI/Common/EnumDirItems.cpp
new file mode 100755
index 00000000..454092ec
--- /dev/null
+++ b/CPP/7zip/UI/Common/EnumDirItems.cpp
@@ -0,0 +1,281 @@
+// EnumDirItems.cpp
+
+#include "StdAfx.h"
+
+#include "Common/StringConvert.h"
+#include "Common/Wildcard.h"
+#include "Common/MyCom.h"
+
+#include "EnumDirItems.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+
+void AddDirFileInfo(
+ const UString &prefix, // prefix for logical path
+ const UString &fullPathName, // path on disk: can be relative to some basePrefix
+ const NFind::CFileInfoW &fileInfo,
+ CObjectVector<CDirItem> &dirItems)
+{
+ CDirItem item;
+ item.Attributes = fileInfo.Attributes;
+ item.Size = fileInfo.Size;
+ item.CreationTime = fileInfo.CreationTime;
+ item.LastAccessTime = fileInfo.LastAccessTime;
+ item.LastWriteTime = fileInfo.LastWriteTime;
+ item.Name = prefix + fileInfo.Name;
+ item.FullPath = fullPathName;
+ dirItems.Add(item);
+}
+
+static void EnumerateDirectory(
+ const UString &baseFolderPrefix, // base (disk) prefix for scanning
+ const UString &directory, // additional disk prefix starting from baseFolderPrefix
+ const UString &prefix, // logical prefix
+ CObjectVector<CDirItem> &dirItems,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes)
+{
+ NFind::CEnumeratorW enumerator(baseFolderPrefix + directory + wchar_t(kAnyStringWildcard));
+ for (;;)
+ {
+ NFind::CFileInfoW fileInfo;
+ bool found;
+ if (!enumerator.Next(fileInfo, found))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(baseFolderPrefix + directory);
+ return;
+ }
+ if (!found)
+ break;
+ AddDirFileInfo(prefix, directory + fileInfo.Name, fileInfo, dirItems);
+ if (fileInfo.IsDirectory())
+ {
+ EnumerateDirectory(baseFolderPrefix, directory + fileInfo.Name + wchar_t(kDirDelimiter),
+ prefix + fileInfo.Name + wchar_t(kDirDelimiter), dirItems, errorPaths, errorCodes);
+ }
+ }
+}
+
+void EnumerateDirItems(
+ const UString &baseFolderPrefix, // base (disk) prefix for scanning
+ const UStringVector &fileNames, // names relative to baseFolderPrefix
+ const UString &archiveNamePrefix,
+ CObjectVector<CDirItem> &dirItems,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes)
+{
+ for(int i = 0; i < fileNames.Size(); i++)
+ {
+ const UString &fileName = fileNames[i];
+ NFind::CFileInfoW fileInfo;
+ if (!NFind::FindFile(baseFolderPrefix + fileName, fileInfo))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(baseFolderPrefix + fileName);
+ continue;
+ }
+ AddDirFileInfo(archiveNamePrefix, fileName, fileInfo, dirItems);
+ if (fileInfo.IsDirectory())
+ {
+ EnumerateDirectory(baseFolderPrefix, fileName + wchar_t(kDirDelimiter),
+ archiveNamePrefix + fileInfo.Name + wchar_t(kDirDelimiter),
+ dirItems, errorPaths, errorCodes);
+ }
+ }
+}
+
+static HRESULT EnumerateDirItems(
+ const NWildcard::CCensorNode &curNode,
+ const UString &diskPrefix, // full disk path prefix
+ const UString &archivePrefix, // prefix from root
+ const UStringVector &addArchivePrefix, // prefix from curNode
+ CObjectVector<CDirItem> &dirItems,
+ bool enterToSubFolders,
+ IEnumDirItemCallback *callback,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes)
+{
+ if (!enterToSubFolders)
+ if (curNode.NeedCheckSubDirs())
+ enterToSubFolders = true;
+ if (callback)
+ RINOK(callback->CheckBreak());
+
+ // try direct_names case at first
+ if (addArchivePrefix.IsEmpty() && !enterToSubFolders)
+ {
+ // check that all names are direct
+ int i;
+ for (i = 0; i < curNode.IncludeItems.Size(); i++)
+ {
+ const NWildcard::CItem &item = curNode.IncludeItems[i];
+ if (item.Recursive || item.PathParts.Size() != 1)
+ break;
+ const UString &name = item.PathParts.Front();
+ if (name.IsEmpty() || DoesNameContainWildCard(name))
+ break;
+ }
+ if (i == curNode.IncludeItems.Size())
+ {
+ // all names are direct (no wildcards)
+ // so we don't need file_system's dir enumerator
+ CRecordVector<bool> needEnterVector;
+ for (i = 0; i < curNode.IncludeItems.Size(); i++)
+ {
+ const NWildcard::CItem &item = curNode.IncludeItems[i];
+ const UString &name = item.PathParts.Front();
+ const UString fullPath = diskPrefix + name;
+ NFind::CFileInfoW fileInfo;
+ if (!NFind::FindFile(fullPath, fileInfo))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(fullPath);
+ continue;
+ }
+ bool isDir = fileInfo.IsDirectory();
+ if (isDir && !item.ForDir || !isDir && !item.ForFile)
+ {
+ errorCodes.Add((DWORD)E_FAIL);
+ errorPaths.Add(fullPath);
+ continue;
+ }
+ const UString realName = fileInfo.Name;
+ const UString realDiskPath = diskPrefix + realName;
+ {
+ UStringVector pathParts;
+ pathParts.Add(fileInfo.Name);
+ if (curNode.CheckPathToRoot(false, pathParts, !isDir))
+ continue;
+ }
+ AddDirFileInfo(archivePrefix, realDiskPath, fileInfo, dirItems);
+ if (!isDir)
+ continue;
+
+ UStringVector addArchivePrefixNew;
+ const NWildcard::CCensorNode *nextNode = 0;
+ int index = curNode.FindSubNode(name);
+ if (index >= 0)
+ {
+ for (int t = needEnterVector.Size(); t <= index; t++)
+ needEnterVector.Add(true);
+ needEnterVector[index] = false;
+ nextNode = &curNode.SubNodes[index];
+ }
+ else
+ {
+ nextNode = &curNode;
+ addArchivePrefixNew.Add(name); // don't change it to realName. It's for shortnames support
+ }
+ RINOK(EnumerateDirItems(*nextNode,
+ realDiskPath + wchar_t(kDirDelimiter),
+ archivePrefix + realName + wchar_t(kDirDelimiter),
+ addArchivePrefixNew, dirItems, true, callback, errorPaths, errorCodes));
+ }
+ for (i = 0; i < curNode.SubNodes.Size(); i++)
+ {
+ if (i < needEnterVector.Size())
+ if (!needEnterVector[i])
+ continue;
+ const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
+ const UString fullPath = diskPrefix + nextNode.Name;
+ NFind::CFileInfoW fileInfo;
+ if (!NFind::FindFile(fullPath, fileInfo))
+ {
+ if (!nextNode.AreThereIncludeItems())
+ continue;
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(fullPath);
+ continue;
+ }
+ if (!fileInfo.IsDirectory())
+ {
+ errorCodes.Add((DWORD)E_FAIL);
+ errorPaths.Add(fullPath);
+ continue;
+ }
+ RINOK(EnumerateDirItems(nextNode,
+ diskPrefix + fileInfo.Name + wchar_t(kDirDelimiter),
+ archivePrefix + fileInfo.Name + wchar_t(kDirDelimiter),
+ UStringVector(), dirItems, false, callback, errorPaths, errorCodes));
+ }
+ return S_OK;
+ }
+ }
+
+
+ NFind::CEnumeratorW enumerator(diskPrefix + wchar_t(kAnyStringWildcard));
+ for (;;)
+ {
+ NFind::CFileInfoW fileInfo;
+ bool found;
+ if (!enumerator.Next(fileInfo, found))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(diskPrefix);
+ break;
+ }
+ if (!found)
+ break;
+
+ if (callback)
+ RINOK(callback->CheckBreak());
+ const UString &name = fileInfo.Name;
+ bool enterToSubFolders2 = enterToSubFolders;
+ UStringVector addArchivePrefixNew = addArchivePrefix;
+ addArchivePrefixNew.Add(name);
+ {
+ UStringVector addArchivePrefixNewTemp(addArchivePrefixNew);
+ if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fileInfo.IsDirectory()))
+ continue;
+ }
+ if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fileInfo.IsDirectory()))
+ {
+ AddDirFileInfo(archivePrefix, diskPrefix + name, fileInfo, dirItems);
+ if (fileInfo.IsDirectory())
+ enterToSubFolders2 = true;
+ }
+ if (!fileInfo.IsDirectory())
+ continue;
+
+ const NWildcard::CCensorNode *nextNode = 0;
+ if (addArchivePrefix.IsEmpty())
+ {
+ int index = curNode.FindSubNode(name);
+ if (index >= 0)
+ nextNode = &curNode.SubNodes[index];
+ }
+ if (!enterToSubFolders2 && nextNode == 0)
+ continue;
+
+ addArchivePrefixNew = addArchivePrefix;
+ if (nextNode == 0)
+ {
+ nextNode = &curNode;
+ addArchivePrefixNew.Add(name);
+ }
+ RINOK(EnumerateDirItems(*nextNode,
+ diskPrefix + name + wchar_t(kDirDelimiter),
+ archivePrefix + name + wchar_t(kDirDelimiter),
+ addArchivePrefixNew, dirItems, enterToSubFolders2, callback, errorPaths, errorCodes));
+ }
+ return S_OK;
+}
+
+HRESULT EnumerateItems(
+ const NWildcard::CCensor &censor,
+ CObjectVector<CDirItem> &dirItems,
+ IEnumDirItemCallback *callback,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes)
+{
+ for (int i = 0; i < censor.Pairs.Size(); i++)
+ {
+ const NWildcard::CPair &pair = censor.Pairs[i];
+ RINOK(EnumerateDirItems(pair.Head, pair.Prefix, L"", UStringVector(), dirItems, false,
+ callback, errorPaths, errorCodes));
+ }
+ return S_OK;
+}
diff --git a/CPP/7zip/UI/Common/EnumDirItems.h b/CPP/7zip/UI/Common/EnumDirItems.h
new file mode 100755
index 00000000..8d5495a8
--- /dev/null
+++ b/CPP/7zip/UI/Common/EnumDirItems.h
@@ -0,0 +1,39 @@
+// EnumDirItems.h
+
+#ifndef __ENUM_DIR_ITEMS_H
+#define __ENUM_DIR_ITEMS_H
+
+#include "Common/Wildcard.h"
+#include "DirItem.h"
+
+#include "Windows/FileFind.h"
+
+void AddDirFileInfo(
+ const UString &prefix,
+ const UString &fullPathName,
+ const NWindows::NFile::NFind::CFileInfoW &fileInfo,
+ CObjectVector<CDirItem> &dirItems);
+
+
+void EnumerateDirItems(
+ const UString &baseFolderPrefix,
+ const UStringVector &fileNames,
+ const UString &archiveNamePrefix,
+ CObjectVector<CDirItem> &dirItems,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes);
+
+struct IEnumDirItemCallback
+{
+ virtual HRESULT CheckBreak() { return S_OK; }
+};
+
+
+HRESULT EnumerateItems(
+ const NWildcard::CCensor &censor,
+ CObjectVector<CDirItem> &dirItems,
+ IEnumDirItemCallback *callback,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes);
+
+#endif
diff --git a/CPP/7zip/UI/Common/ExitCode.h b/CPP/7zip/UI/Common/ExitCode.h
new file mode 100755
index 00000000..0aac3695
--- /dev/null
+++ b/CPP/7zip/UI/Common/ExitCode.h
@@ -0,0 +1,27 @@
+// ExitCode.h
+
+#ifndef __EXIT_CODE_H
+#define __EXIT_CODE_H
+
+namespace NExitCode {
+
+enum EEnum {
+
+ kSuccess = 0, // Successful operation
+ kWarning = 1, // Non fatal error(s) occurred
+ kFatalError = 2, // A fatal error occurred
+ // kCRCError = 3, // A CRC error occurred when unpacking
+ // kLockedArchive = 4, // Attempt to modify an archive previously locked
+ // kWriteError = 5, // Write to disk error
+ // kOpenError = 6, // Open file error
+ kUserError = 7, // Command line option error
+ kMemoryError = 8, // Not enough memory for operation
+ // kCreateFileError = 9, // Create file error
+
+ kUserBreak = 255 // User stopped the process
+
+};
+
+}
+
+#endif
diff --git a/CPP/7zip/UI/Common/Extract.cpp b/CPP/7zip/UI/Common/Extract.cpp
new file mode 100755
index 00000000..34fb383b
--- /dev/null
+++ b/CPP/7zip/UI/Common/Extract.cpp
@@ -0,0 +1,152 @@
+// Extract.cpp
+
+#include "StdAfx.h"
+
+#include "Extract.h"
+
+#include "Windows/Defs.h"
+#include "Windows/FileDir.h"
+
+#include "OpenArchive.h"
+#include "SetProperties.h"
+
+#ifndef EXCLUDE_COM
+#include "Windows/DLL.h"
+#endif
+
+using namespace NWindows;
+
+HRESULT DecompressArchive(
+ IInArchive *archive,
+ const UString &defaultName,
+ const NWildcard::CCensorNode &wildcardCensor,
+ const CExtractOptions &options,
+ IExtractCallbackUI *callback,
+ UString &errorMessage)
+{
+ CRecordVector<UInt32> realIndices;
+ UInt32 numItems;
+ RINOK(archive->GetNumberOfItems(&numItems));
+
+ for(UInt32 i = 0; i < numItems; i++)
+ {
+ UString filePath;
+ RINOK(GetArchiveItemPath(archive, i, options.DefaultItemName, filePath));
+ bool isFolder;
+ RINOK(IsArchiveItemFolder(archive, i, isFolder));
+ if (!wildcardCensor.CheckPath(filePath, !isFolder))
+ continue;
+ realIndices.Add(i);
+ }
+ if (realIndices.Size() == 0)
+ {
+ callback->ThereAreNoFiles();
+ return S_OK;
+ }
+
+ CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
+ CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec);
+
+ UStringVector removePathParts;
+
+ UString outDir = options.OutputDir;
+ outDir.Replace(L"*", defaultName);
+ if(!outDir.IsEmpty())
+ if(!NFile::NDirectory::CreateComplexDirectory(outDir))
+ {
+ HRESULT res = ::GetLastError();
+ if (res == S_OK)
+ res = E_FAIL;
+ errorMessage = ((UString)L"Can not create output directory ") + outDir;
+ return res;
+ }
+
+ extractCallbackSpec->Init(
+ archive,
+ callback,
+ options.StdOutMode,
+ outDir,
+ options.PathMode,
+ options.OverwriteMode,
+ removePathParts,
+ options.DefaultItemName,
+ options.ArchiveFileInfo.LastWriteTime,
+ options.ArchiveFileInfo.Attributes);
+
+ #ifdef COMPRESS_MT
+ RINOK(SetProperties(archive, options.Properties));
+ #endif
+
+ HRESULT result = archive->Extract(&realIndices.Front(),
+ realIndices.Size(), options.TestMode? 1: 0,
+ extractCallback);
+
+ return callback->ExtractResult(result);
+}
+
+HRESULT DecompressArchives(
+ UStringVector &archivePaths, UStringVector &archivePathsFull,
+ const NWildcard::CCensorNode &wildcardCensor,
+ const CExtractOptions &optionsSpec,
+ IOpenCallbackUI *openCallback,
+ IExtractCallbackUI *extractCallback,
+ UString &errorMessage)
+{
+ CExtractOptions options = optionsSpec;
+ for (int i = 0; i < archivePaths.Size(); i++)
+ {
+ const UString &archivePath = archivePaths[i];
+ NFile::NFind::CFileInfoW archiveFileInfo;
+ if (!NFile::NFind::FindFile(archivePath, archiveFileInfo))
+ throw "there is no such archive";
+
+ if (archiveFileInfo.IsDirectory())
+ throw "there is no such archive";
+
+ options.ArchiveFileInfo = archiveFileInfo;
+
+ #ifndef _NO_CRYPTO
+ openCallback->ClearPasswordWasAskedFlag();
+ #endif
+
+ RINOK(extractCallback->BeforeOpen(archivePath));
+ CArchiveLink archiveLink;
+ HRESULT result = MyOpenArchive(archivePath, archiveLink, openCallback);
+
+ bool crypted = false;
+ #ifndef _NO_CRYPTO
+ crypted = openCallback->WasPasswordAsked();
+ #endif
+
+ RINOK(extractCallback->OpenResult(archivePath, result, crypted));
+ if (result != S_OK)
+ continue;
+
+ for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)
+ {
+ int index = archivePathsFull.FindInSorted(archiveLink.VolumePaths[v]);
+ if (index >= 0 && index > i)
+ {
+ archivePaths.Delete(index);
+ archivePathsFull.Delete(index);
+ }
+ }
+
+ #ifndef _NO_CRYPTO
+ UString password;
+ RINOK(openCallback->GetPasswordIfAny(password));
+ if (!password.IsEmpty())
+ {
+ RINOK(extractCallback->SetPassword(password));
+ }
+ #endif
+
+ options.DefaultItemName = archiveLink.GetDefaultItemName();
+ RINOK(DecompressArchive(
+ archiveLink.GetArchive(), archiveLink.GetDefaultItemName(),
+ wildcardCensor, options, extractCallback, errorMessage));
+ if (!errorMessage.IsEmpty())
+ return E_FAIL;
+ }
+ return S_OK;
+}
diff --git a/CPP/7zip/UI/Common/Extract.h b/CPP/7zip/UI/Common/Extract.h
new file mode 100755
index 00000000..c7b47c84
--- /dev/null
+++ b/CPP/7zip/UI/Common/Extract.h
@@ -0,0 +1,59 @@
+// Extract.h
+
+#ifndef __EXTRACT_H
+#define __EXTRACT_H
+
+#include "Common/Wildcard.h"
+#include "Windows/FileFind.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "ArchiveExtractCallback.h"
+#include "ArchiveOpenCallback.h"
+#include "ExtractMode.h"
+#include "Property.h"
+
+class CExtractOptions
+{
+public:
+ bool StdOutMode;
+ bool TestMode;
+ NExtract::NPathMode::EEnum PathMode;
+
+ UString OutputDir;
+ bool YesToAll;
+ UString DefaultItemName;
+ NWindows::NFile::NFind::CFileInfoW ArchiveFileInfo;
+
+ // bool ShowDialog;
+ // bool PasswordEnabled;
+ // UString Password;
+ #ifdef COMPRESS_MT
+ CObjectVector<CProperty> Properties;
+ #endif
+
+ NExtract::NOverwriteMode::EEnum OverwriteMode;
+
+ CExtractOptions():
+ StdOutMode(false),
+ YesToAll(false),
+ TestMode(false),
+ PathMode(NExtract::NPathMode::kFullPathnames),
+ OverwriteMode(NExtract::NOverwriteMode::kAskBefore)
+ {}
+
+ /*
+ bool FullPathMode() const { return (ExtractMode == NExtractMode::kTest) ||
+ (ExtractMode == NExtractMode::kFullPath); }
+ */
+};
+
+HRESULT DecompressArchives(
+ UStringVector &archivePaths, UStringVector &archivePathsFull,
+ const NWildcard::CCensorNode &wildcardCensor,
+ const CExtractOptions &options,
+ IOpenCallbackUI *openCallback,
+ IExtractCallbackUI *extractCallback,
+ UString &errorMessage);
+
+#endif
diff --git a/CPP/7zip/UI/Common/ExtractMode.h b/CPP/7zip/UI/Common/ExtractMode.h
new file mode 100755
index 00000000..96b5a8cd
--- /dev/null
+++ b/CPP/7zip/UI/Common/ExtractMode.h
@@ -0,0 +1,31 @@
+// ExtractMode.h
+
+#ifndef __EXTRACT_MODE_H
+#define __EXTRACT_MODE_H
+
+namespace NExtract {
+
+ namespace NPathMode
+ {
+ enum EEnum
+ {
+ kFullPathnames,
+ kCurrentPathnames,
+ kNoPathnames
+ };
+ }
+
+ namespace NOverwriteMode
+ {
+ enum EEnum
+ {
+ kAskBefore,
+ kWithoutPrompt,
+ kSkipExisting,
+ kAutoRename,
+ kAutoRenameExisting
+ };
+ }
+}
+
+#endif
diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/CPP/7zip/UI/Common/ExtractingFilePath.cpp
new file mode 100755
index 00000000..a0b17282
--- /dev/null
+++ b/CPP/7zip/UI/Common/ExtractingFilePath.cpp
@@ -0,0 +1,75 @@
+// ExtractingFilePath.cpp
+
+#include "StdAfx.h"
+#include "ExtractingFilePath.h"
+
+static void ReplaceDisk(UString &s)
+{
+ int i;
+ for (i = 0; i < s.Length(); i++)
+ if (s[i] != ' ')
+ break;
+ if (s.Length() > i + 1)
+ {
+ if (s[i + 1] == L':')
+ {
+ s.Delete(i + 1);
+ // s.Insert(i + 1, L'_');
+ }
+ }
+}
+
+UString GetCorrectFileName(const UString &path)
+{
+ UString result = path;
+ {
+ UString test = path;
+ test.Trim();
+ if (test == L"..")
+ result.Replace(L"..", L"");
+ }
+ ReplaceDisk(result);
+ return result;
+}
+
+UString GetCorrectPath(const UString &path)
+{
+ UString result = path;
+ int first;
+ for (first = 0; first < result.Length(); first++)
+ if (result[first] != ' ')
+ break;
+ while(result.Length() > first)
+ {
+ if (
+ #ifdef _WIN32
+ result[first] == L'\\' ||
+ #endif
+ result[first] == L'/')
+ {
+ result.Delete(first);
+ continue;
+ }
+ break;
+ }
+ #ifdef _WIN32
+ result.Replace(L"..\\", L"");
+ #endif
+ result.Replace(L"../", L"");
+
+ ReplaceDisk(result);
+ return result;
+}
+
+void MakeCorrectPath(UStringVector &pathParts)
+{
+ for (int i = 0; i < pathParts.Size();)
+ {
+ UString &s = pathParts[i];
+ s = GetCorrectFileName(s);
+ if (s.IsEmpty())
+ pathParts.Delete(i);
+ else
+ i++;
+ }
+}
diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.h b/CPP/7zip/UI/Common/ExtractingFilePath.h
new file mode 100755
index 00000000..0ae9e9b8
--- /dev/null
+++ b/CPP/7zip/UI/Common/ExtractingFilePath.h
@@ -0,0 +1,12 @@
+// ExtractingFilePath.h
+
+#ifndef __EXTRACTINGFILEPATH_H
+#define __EXTRACTINGFILEPATH_H
+
+#include "Common/String.h"
+
+UString GetCorrectFileName(const UString &path);
+UString GetCorrectPath(const UString &path);
+void MakeCorrectPath(UStringVector &pathParts);
+
+#endif
diff --git a/CPP/7zip/UI/Common/HandlerLoader.h b/CPP/7zip/UI/Common/HandlerLoader.h
new file mode 100755
index 00000000..2a878019
--- /dev/null
+++ b/CPP/7zip/UI/Common/HandlerLoader.h
@@ -0,0 +1,38 @@
+// HandlerLoader.h
+
+#ifndef __HANDLERLOADER_H
+#define __HANDLERLOADER_H
+
+#include "../../ICoder.h"
+#include "Windows/DLL.h"
+
+typedef UInt32 (WINAPI * CreateObjectFunc)(
+ const GUID *clsID,
+ const GUID *interfaceID,
+ void **outObject);
+
+class CHandlerLoader: public NWindows::NDLL::CLibrary
+{
+public:
+ HRESULT CreateHandler(LPCWSTR filepath, REFGUID clsID,
+ void **archive, bool outHandler)
+ {
+ if (!Load(filepath))
+ return GetLastError();
+ CreateObjectFunc createObject = (CreateObjectFunc)
+ GetProcAddress("CreateObject");
+ if (createObject == NULL)
+ {
+ HRESULT res = ::GetLastError();
+ Free();
+ return res;
+ }
+ HRESULT res = createObject(&clsID,
+ outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive);
+ if (res != 0)
+ Free();
+ return res;
+ }
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/IFileExtractCallback.h b/CPP/7zip/UI/Common/IFileExtractCallback.h
new file mode 100755
index 00000000..c70d7021
--- /dev/null
+++ b/CPP/7zip/UI/Common/IFileExtractCallback.h
@@ -0,0 +1,46 @@
+// IFileExtractCallback.h
+
+#ifndef __IFILEEXTRACTCALLBACK_H
+#define __IFILEEXTRACTCALLBACK_H
+
+#include "Common/String.h"
+
+namespace NOverwriteAnswer
+{
+ enum EEnum
+ {
+ kYes,
+ kYesToAll,
+ kNo,
+ kNoToAll,
+ kAutoRename,
+ kCancel,
+ };
+}
+
+// {23170F69-40C1-278A-0000-000100070000}
+DEFINE_GUID(IID_IFolderArchiveExtractCallback,
+0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00);
+MIDL_INTERFACE("23170F69-40C1-278A-0000-000100070000")
+IFolderArchiveExtractCallback: public IProgress
+{
+public:
+ STDMETHOD(AskOverwrite)(
+ const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
+ const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
+ Int32 *answer) PURE;
+ STDMETHOD(PrepareOperation)(const wchar_t *name, Int32 askExtractMode, const UInt64 *position) PURE;
+ STDMETHOD(MessageError)(const wchar_t *message) PURE;
+ STDMETHOD(SetOperationResult)(Int32 operationResult, bool encrypted) PURE;
+};
+
+struct IExtractCallbackUI: IFolderArchiveExtractCallback
+{
+ virtual HRESULT BeforeOpen(const wchar_t *name) = 0;
+ virtual HRESULT OpenResult(const wchar_t *name, HRESULT result, bool encrypted) = 0;
+ virtual HRESULT ThereAreNoFiles() = 0;
+ virtual HRESULT ExtractResult(HRESULT result) = 0;
+ virtual HRESULT SetPassword(const UString &password) = 0;
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/OpenArchive.cpp b/CPP/7zip/UI/Common/OpenArchive.cpp
new file mode 100755
index 00000000..ce1a6de3
--- /dev/null
+++ b/CPP/7zip/UI/Common/OpenArchive.cpp
@@ -0,0 +1,531 @@
+// OpenArchive.cpp
+
+#include "StdAfx.h"
+
+#include "OpenArchive.h"
+
+#include "Common/Wildcard.h"
+
+#include "Windows/FileName.h"
+#include "Windows/FileDir.h"
+#include "Windows/Defs.h"
+#include "Windows/PropVariant.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "Common/StringConvert.h"
+
+#ifdef FORMAT_7Z
+#include "../../Archive/7z/7zHandler.h"
+#endif
+
+#ifdef FORMAT_BZIP2
+#include "../../Archive/BZip2/BZip2Handler.h"
+#endif
+
+#ifdef FORMAT_CAB
+#include "../../Archive/Cab/CabHandler.h"
+#endif
+
+#ifdef FORMAT_GZIP
+#include "../../Archive/GZip/GZipHandler.h"
+#endif
+
+#ifdef FORMAT_SPLIT
+#include "../../Archive/Split/SplitHandler.h"
+#endif
+
+#ifdef FORMAT_TAR
+#include "../../Archive/Tar/TarHandler.h"
+#endif
+
+#ifdef FORMAT_ZIP
+#include "../../Archive/Zip/ZipHandler.h"
+#endif
+
+#ifdef FORMAT_Z
+#include "../../Archive/Z/ZHandler.h"
+#endif
+
+#ifndef EXCLUDE_COM
+#include "HandlerLoader.h"
+#endif
+
+#include "DefaultName.h"
+
+using namespace NWindows;
+
+HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, UString &result)
+{
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidPath, &prop));
+ if(prop.vt == VT_BSTR)
+ result = prop.bstrVal;
+ else if (prop.vt == VT_EMPTY)
+ result.Empty();
+ else
+ return E_FAIL;
+ return S_OK;
+}
+
+HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, const UString &defaultName, UString &result)
+{
+ RINOK(GetArchiveItemPath(archive, index, result));
+ if (result.IsEmpty())
+ result = defaultName;
+ return S_OK;
+}
+
+HRESULT GetArchiveItemFileTime(IInArchive *archive, UInt32 index,
+ const FILETIME &defaultFileTime, FILETIME &fileTime)
+{
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidLastWriteTime, &prop));
+ if (prop.vt == VT_FILETIME)
+ fileTime = prop.filetime;
+ else if (prop.vt == VT_EMPTY)
+ fileTime = defaultFileTime;
+ else
+ return E_FAIL;
+ return S_OK;
+}
+
+static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
+{
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, propID, &prop));
+ if(prop.vt == VT_BOOL)
+ result = VARIANT_BOOLToBool(prop.boolVal);
+ else if (prop.vt == VT_EMPTY)
+ result = false;
+ else
+ return E_FAIL;
+ return S_OK;
+}
+
+HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
+{
+ return IsArchiveItemProp(archive, index, kpidIsFolder, result);
+}
+
+HRESULT IsArchiveItemAnti(IInArchive *archive, UInt32 index, bool &result)
+{
+ return IsArchiveItemProp(archive, index, kpidIsAnti, result);
+}
+
+// Static-SFX (for Linux) can be big.
+const UInt64 kMaxCheckStartPosition = 1 << 22;
+
+HRESULT ReOpenArchive(IInArchive *archive, const UString &fileName)
+{
+ CInFileStream *inStreamSpec = new CInFileStream;
+ CMyComPtr<IInStream> inStream(inStreamSpec);
+ inStreamSpec->Open(fileName);
+ return archive->Open(inStream, &kMaxCheckStartPosition, NULL);
+}
+
+#ifndef _SFX
+static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size)
+{
+ for (size_t i = 0; i < size; i++)
+ if (p1[i] != p2[i])
+ return false;
+ return true;
+}
+#endif
+
+HRESULT OpenArchive(
+ IInStream *inStream,
+ const UString &fileName,
+ #ifndef EXCLUDE_COM
+ HMODULE *module,
+ #endif
+ IInArchive **archiveResult,
+ CArchiverInfo &archiverInfoResult,
+ UString &defaultItemName,
+ IArchiveOpenCallback *openArchiveCallback)
+{
+ *archiveResult = NULL;
+ CObjectVector<CArchiverInfo> archiverInfoList;
+ ReadArchiverInfoList(archiverInfoList);
+ UString extension;
+ {
+ int dotPos = fileName.ReverseFind(L'.');
+ if (dotPos >= 0)
+ extension = fileName.Mid(dotPos + 1);
+ }
+ CIntVector orderIndices;
+ int i;
+ bool finded = false;
+ for(i = 0; i < archiverInfoList.Size(); i++)
+ {
+ if (archiverInfoList[i].FindExtension(extension) >= 0)
+ {
+ orderIndices.Insert(0, i);
+ finded = true;
+ }
+ else
+ orderIndices.Add(i);
+ }
+
+ #ifndef _SFX
+ if (!finded)
+ {
+ CByteBuffer byteBuffer;
+ const UInt32 kBufferSize = (200 << 10);
+ byteBuffer.SetCapacity(kBufferSize);
+ Byte *buffer = byteBuffer;
+ RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ UInt32 processedSize;
+ RINOK(ReadStream(inStream, buffer, kBufferSize, &processedSize));
+ int numFinded = 0;
+ for (int pos = (int)processedSize; pos >= 0 ; pos--)
+ {
+ for(int i = numFinded; i < orderIndices.Size(); i++)
+ {
+ int index = orderIndices[i];
+ const CArchiverInfo &ai = archiverInfoList[index];
+ const CByteBuffer &sig = ai.StartSignature;
+ if (sig.GetCapacity() == 0)
+ continue;
+ if (pos + sig.GetCapacity() > processedSize)
+ continue;
+ if (TestSignature(buffer + pos, sig, sig.GetCapacity()))
+ {
+ orderIndices.Delete(i);
+ orderIndices.Insert(0, index);
+ numFinded++;
+ }
+ }
+ }
+ }
+ #endif
+
+ HRESULT badResult = S_OK;
+ for(i = 0; i < orderIndices.Size(); i++)
+ {
+ inStream->Seek(0, STREAM_SEEK_SET, NULL);
+ const CArchiverInfo &archiverInfo = archiverInfoList[orderIndices[i]];
+ #ifndef EXCLUDE_COM
+ CHandlerLoader loader;
+ #endif
+ CMyComPtr<IInArchive> archive;
+
+ #ifdef FORMAT_7Z
+ if (archiverInfo.Name.CompareNoCase(L"7z") == 0)
+ archive = new NArchive::N7z::CHandler;
+ #endif
+
+ #ifdef FORMAT_BZIP2
+ if (archiverInfo.Name.CompareNoCase(L"BZip2") == 0)
+ archive = new NArchive::NBZip2::CHandler;
+ #endif
+
+ #ifdef FORMAT_CAB
+ if (archiverInfo.Name.CompareNoCase(L"Cab") == 0)
+ archive = new NArchive::NCab::CHandler;
+ #endif
+
+ #ifdef FORMAT_GZIP
+ if (archiverInfo.Name.CompareNoCase(L"GZip") == 0)
+ archive = new NArchive::NGZip::CHandler;
+ #endif
+
+ #ifdef FORMAT_SPLIT
+ if (archiverInfo.Name.CompareNoCase(L"Split") == 0)
+ archive = new NArchive::NSplit::CHandler;
+ #endif
+
+ #ifdef FORMAT_TAR
+ if (archiverInfo.Name.CompareNoCase(L"Tar") == 0)
+ archive = new NArchive::NTar::CHandler;
+ #endif
+
+ #ifdef FORMAT_ZIP
+ if (archiverInfo.Name.CompareNoCase(L"Zip") == 0)
+ archive = new NArchive::NZip::CHandler;
+ #endif
+
+ #ifdef FORMAT_Z
+ if (archiverInfo.Name.CompareNoCase(L"Z") == 0)
+ archive = new NArchive::NZ::CHandler;
+ #endif
+
+
+ #ifndef EXCLUDE_COM
+ if (!archive)
+ {
+ HRESULT result = loader.CreateHandler(archiverInfo.FilePath,
+ archiverInfo.ClassID, (void **)&archive, false);
+ if (result != S_OK)
+ continue;
+ }
+ #endif
+
+ if (!archive)
+ return E_FAIL;
+
+ HRESULT result = archive->Open(inStream, &kMaxCheckStartPosition, openArchiveCallback);
+ if(result == S_FALSE)
+ continue;
+ if(result != S_OK)
+ {
+ badResult = result;
+ if(result == E_ABORT)
+ break;
+ continue;
+ }
+ *archiveResult = archive.Detach();
+ #ifndef EXCLUDE_COM
+ *module = loader.Detach();
+ #endif
+ archiverInfoResult = archiverInfo;
+ int subExtIndex = archiverInfo.FindExtension(extension);
+ if (subExtIndex < 0)
+ subExtIndex = 0;
+ defaultItemName = GetDefaultName2(fileName,
+ archiverInfo.Extensions[subExtIndex].Ext,
+ archiverInfo.Extensions[subExtIndex].AddExt);
+
+ return S_OK;
+ }
+ if (badResult != S_OK)
+ return badResult;
+ return S_FALSE;
+}
+
+HRESULT OpenArchive(const UString &filePath,
+ #ifndef EXCLUDE_COM
+ HMODULE *module,
+ #endif
+ IInArchive **archiveResult,
+ CArchiverInfo &archiverInfo,
+ UString &defaultItemName,
+ IArchiveOpenCallback *openArchiveCallback)
+{
+ CInFileStream *inStreamSpec = new CInFileStream;
+ CMyComPtr<IInStream> inStream(inStreamSpec);
+ if (!inStreamSpec->Open(filePath))
+ return GetLastError();
+ return OpenArchive(inStream, ExtractFileNameFromPath(filePath),
+ #ifndef EXCLUDE_COM
+ module,
+ #endif
+ archiveResult, archiverInfo,
+ defaultItemName, openArchiveCallback);
+}
+
+static void MakeDefaultName(UString &name)
+{
+ int dotPos = name.ReverseFind(L'.');
+ if (dotPos < 0)
+ return;
+ UString ext = name.Mid(dotPos + 1);
+ if (ext.IsEmpty())
+ return;
+ for (int pos = 0; pos < ext.Length(); pos++)
+ if (ext[pos] < L'0' || ext[pos] > L'9')
+ return;
+ name = name.Left(dotPos);
+}
+
+HRESULT OpenArchive(const UString &fileName,
+ #ifndef EXCLUDE_COM
+ HMODULE *module0,
+ HMODULE *module1,
+ #endif
+ IInArchive **archive0,
+ IInArchive **archive1,
+ CArchiverInfo &archiverInfo0,
+ CArchiverInfo &archiverInfo1,
+ UString &defaultItemName0,
+ UString &defaultItemName1,
+ IArchiveOpenCallback *openArchiveCallback)
+{
+ HRESULT result = OpenArchive(fileName,
+ #ifndef EXCLUDE_COM
+ module0,
+ #endif
+ archive0, archiverInfo0, defaultItemName0, openArchiveCallback);
+ RINOK(result);
+ CMyComPtr<IInArchiveGetStream> getStream;
+ result = (*archive0)->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream);
+ if (result != S_OK || getStream == 0)
+ return S_OK;
+
+ CMyComPtr<ISequentialInStream> subSeqStream;
+ result = getStream->GetStream(0, &subSeqStream);
+ if (result != S_OK)
+ return S_OK;
+
+ CMyComPtr<IInStream> subStream;
+ if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK)
+ return S_OK;
+ if (!subStream)
+ return S_OK;
+
+ UInt32 numItems;
+ RINOK((*archive0)->GetNumberOfItems(&numItems));
+ if (numItems < 1)
+ return S_OK;
+
+ UString subPath;
+ RINOK(GetArchiveItemPath(*archive0, 0, subPath))
+ if (subPath.IsEmpty())
+ {
+ MakeDefaultName(defaultItemName0);
+ subPath = defaultItemName0;
+ if (archiverInfo0.Name.CompareNoCase(L"7z") == 0)
+ {
+ if (subPath.Right(3).CompareNoCase(L".7z") != 0)
+ subPath += L".7z";
+ }
+ }
+ else
+ subPath = ExtractFileNameFromPath(subPath);
+
+ CMyComPtr<IArchiveOpenSetSubArchiveName> setSubArchiveName;
+ openArchiveCallback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName);
+ if (setSubArchiveName)
+ setSubArchiveName->SetSubArchiveName(subPath);
+
+ result = OpenArchive(subStream, subPath,
+ #ifndef EXCLUDE_COM
+ module1,
+ #endif
+ archive1, archiverInfo1, defaultItemName1, openArchiveCallback);
+ return S_OK;
+}
+
+HRESULT MyOpenArchive(const UString &archiveName,
+ #ifndef EXCLUDE_COM
+ HMODULE *module,
+ #endif
+ IInArchive **archive,
+ UString &defaultItemName,
+ IOpenCallbackUI *openCallbackUI)
+{
+ COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
+ CMyComPtr<IArchiveOpenCallback> openCallback = openCallbackSpec;
+ openCallbackSpec->Callback = openCallbackUI;
+
+ UString fullName;
+ int fileNamePartStartIndex;
+ NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex);
+ openCallbackSpec->Init(
+ fullName.Left(fileNamePartStartIndex),
+ fullName.Mid(fileNamePartStartIndex));
+
+ CArchiverInfo archiverInfo;
+ return OpenArchive(archiveName,
+ #ifndef EXCLUDE_COM
+ module,
+ #endif
+ archive,
+ archiverInfo,
+ defaultItemName,
+ openCallback);
+}
+
+HRESULT MyOpenArchive(const UString &archiveName,
+ #ifndef EXCLUDE_COM
+ HMODULE *module0,
+ HMODULE *module1,
+ #endif
+ IInArchive **archive0,
+ IInArchive **archive1,
+ UString &defaultItemName0,
+ UString &defaultItemName1,
+ UStringVector &volumePaths,
+ IOpenCallbackUI *openCallbackUI)
+{
+ COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
+ CMyComPtr<IArchiveOpenCallback> openCallback = openCallbackSpec;
+ openCallbackSpec->Callback = openCallbackUI;
+
+ UString fullName;
+ int fileNamePartStartIndex;
+ NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex);
+ UString prefix = fullName.Left(fileNamePartStartIndex);
+ UString name = fullName.Mid(fileNamePartStartIndex);
+ openCallbackSpec->Init(prefix, name);
+
+ CArchiverInfo archiverInfo0, archiverInfo1;
+ HRESULT result = OpenArchive(archiveName,
+ #ifndef EXCLUDE_COM
+ module0,
+ module1,
+ #endif
+ archive0,
+ archive1,
+ archiverInfo0,
+ archiverInfo1,
+ defaultItemName0,
+ defaultItemName1,
+ openCallback);
+ RINOK(result);
+ volumePaths.Add(prefix + name);
+ for (int i = 0; i < openCallbackSpec->FileNames.Size(); i++)
+ volumePaths.Add(prefix + openCallbackSpec->FileNames[i]);
+ return S_OK;
+}
+
+HRESULT CArchiveLink::Close()
+{
+ if (Archive1 != 0)
+ RINOK(Archive1->Close());
+ if (Archive0 != 0)
+ RINOK(Archive0->Close());
+ return S_OK;
+}
+
+void CArchiveLink::Release()
+{
+ if (Archive1 != 0)
+ Archive1.Release();
+ if (Archive0 != 0)
+ Archive0.Release();
+ #ifndef EXCLUDE_COM
+ Library1.Free();
+ Library0.Free();
+ #endif
+}
+
+HRESULT OpenArchive(const UString &archiveName,
+ CArchiveLink &archiveLink,
+ IArchiveOpenCallback *openCallback)
+{
+ return OpenArchive(archiveName,
+ #ifndef EXCLUDE_COM
+ &archiveLink.Library0, &archiveLink.Library1,
+ #endif
+ &archiveLink.Archive0, &archiveLink.Archive1,
+ archiveLink.ArchiverInfo0, archiveLink.ArchiverInfo1,
+ archiveLink.DefaultItemName0, archiveLink.DefaultItemName1,
+ openCallback);
+}
+
+HRESULT MyOpenArchive(const UString &archiveName,
+ CArchiveLink &archiveLink,
+ IOpenCallbackUI *openCallbackUI)
+{
+ return MyOpenArchive(archiveName,
+ #ifndef EXCLUDE_COM
+ &archiveLink.Library0, &archiveLink.Library1,
+ #endif
+ &archiveLink.Archive0, &archiveLink.Archive1,
+ archiveLink.DefaultItemName0, archiveLink.DefaultItemName1,
+ archiveLink.VolumePaths,
+ openCallbackUI);
+}
+
+HRESULT ReOpenArchive(CArchiveLink &archiveLink,
+ const UString &fileName)
+{
+ if (archiveLink.GetNumLevels() > 1)
+ return E_NOTIMPL;
+ if (archiveLink.GetNumLevels() == 0)
+ return MyOpenArchive(fileName, archiveLink, 0);
+ return ReOpenArchive(archiveLink.GetArchive(), fileName);
+}
diff --git a/CPP/7zip/UI/Common/OpenArchive.h b/CPP/7zip/UI/Common/OpenArchive.h
new file mode 100755
index 00000000..f96b1ebf
--- /dev/null
+++ b/CPP/7zip/UI/Common/OpenArchive.h
@@ -0,0 +1,134 @@
+// OpenArchive.h
+
+#ifndef __OPENARCHIVE_H
+#define __OPENARCHIVE_H
+
+#include "Common/String.h"
+#include "Windows/FileFind.h"
+
+#include "../../Archive/IArchive.h"
+#include "ArchiverInfo.h"
+#include "ArchiveOpenCallback.h"
+
+#ifndef EXCLUDE_COM
+#include "Windows/DLL.h"
+#endif
+
+HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, UString &result);
+HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, const UString &defaultName, UString &result);
+HRESULT GetArchiveItemFileTime(IInArchive *archive, UInt32 index,
+ const FILETIME &defaultFileTime, FILETIME &fileTime);
+HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result);
+HRESULT IsArchiveItemAnti(IInArchive *archive, UInt32 index, bool &result);
+
+struct ISetSubArchiveName
+{
+ virtual void SetSubArchiveName(const wchar_t *name) = 0;
+};
+
+HRESULT OpenArchive(
+ IInStream *inStream,
+ const UString &fileName,
+ #ifndef EXCLUDE_COM
+ HMODULE *module,
+ #endif
+ IInArchive **archiveResult,
+ CArchiverInfo &archiverInfoResult,
+ UString &defaultItemName,
+ IArchiveOpenCallback *openArchiveCallback);
+
+HRESULT OpenArchive(const UString &filePath,
+ #ifndef EXCLUDE_COM
+ HMODULE *module,
+ #endif
+ IInArchive **archive,
+ CArchiverInfo &archiverInfo,
+ UString &defaultItemName,
+ IArchiveOpenCallback *openArchiveCallback);
+
+HRESULT OpenArchive(const UString &filePath,
+ #ifndef EXCLUDE_COM
+ HMODULE *module0,
+ HMODULE *module1,
+ #endif
+ IInArchive **archive0,
+ IInArchive **archive1,
+ CArchiverInfo &archiverInfo0,
+ CArchiverInfo &archiverInfo1,
+ UString &defaultItemName0,
+ UString &defaultItemName1,
+ IArchiveOpenCallback *openArchiveCallback);
+
+
+HRESULT ReOpenArchive(IInArchive *archive,
+ const UString &fileName);
+
+HRESULT MyOpenArchive(const UString &archiveName,
+ #ifndef EXCLUDE_COM
+ HMODULE *module,
+ #endif
+ IInArchive **archive,
+ UString &defaultItemName,
+ IOpenCallbackUI *openCallbackUI);
+
+HRESULT MyOpenArchive(const UString &archiveName,
+ #ifndef EXCLUDE_COM
+ HMODULE *module0,
+ HMODULE *module1,
+ #endif
+ IInArchive **archive0,
+ IInArchive **archive1,
+ UString &defaultItemName0,
+ UString &defaultItemName1,
+ UStringVector &volumePaths,
+ IOpenCallbackUI *openCallbackUI);
+
+struct CArchiveLink
+{
+ #ifndef EXCLUDE_COM
+ NWindows::NDLL::CLibrary Library0;
+ NWindows::NDLL::CLibrary Library1;
+ #endif
+ CMyComPtr<IInArchive> Archive0;
+ CMyComPtr<IInArchive> Archive1;
+ UString DefaultItemName0;
+ UString DefaultItemName1;
+
+ CArchiverInfo ArchiverInfo0;
+ CArchiverInfo ArchiverInfo1;
+
+ UStringVector VolumePaths;
+
+ int GetNumLevels() const
+ {
+ int result = 0;
+ if (Archive0)
+ {
+ result++;
+ if (Archive1)
+ result++;
+ }
+ return result;
+ }
+
+
+ IInArchive *GetArchive() { return Archive1 != 0 ? Archive1: Archive0; }
+ UString GetDefaultItemName() { return Archive1 != 0 ? DefaultItemName1: DefaultItemName0; }
+ const CArchiverInfo &GetArchiverInfo() { return Archive1 != 0 ? ArchiverInfo1: ArchiverInfo0; }
+ HRESULT Close();
+ void Release();
+};
+
+HRESULT OpenArchive(const UString &archiveName,
+ CArchiveLink &archiveLink,
+ IArchiveOpenCallback *openCallback);
+
+HRESULT MyOpenArchive(const UString &archiveName,
+ CArchiveLink &archiveLink,
+ IOpenCallbackUI *openCallbackUI);
+
+HRESULT ReOpenArchive(CArchiveLink &archiveLink,
+ const UString &fileName);
+
+#endif
+
diff --git a/CPP/7zip/UI/Common/PropIDUtils.cpp b/CPP/7zip/UI/Common/PropIDUtils.cpp
new file mode 100755
index 00000000..8869e565
--- /dev/null
+++ b/CPP/7zip/UI/Common/PropIDUtils.cpp
@@ -0,0 +1,90 @@
+// PropIDUtils.cpp
+
+#include "StdAfx.h"
+
+#include "PropIDUtils.h"
+
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/FileFind.h"
+#include "Windows/PropVariantConversions.h"
+
+#include "../../PropID.h"
+
+using namespace NWindows;
+
+static UString ConvertUInt32ToString(UInt32 value)
+{
+ wchar_t buffer[32];
+ ConvertUInt64ToString(value, buffer);
+ return buffer;
+}
+
+static void ConvertUInt32ToHex(UInt32 value, wchar_t *s)
+{
+ for (int i = 0; i < 8; i++)
+ {
+ int t = value & 0xF;
+ value >>= 4;
+ s[7 - i] = (wchar_t)((t < 10) ? (L'0' + t) : (L'A' + (t - 10)));
+ }
+ s[8] = L'\0';
+}
+
+UString ConvertPropertyToString(const PROPVARIANT &propVariant,
+ PROPID propID, bool full)
+{
+ switch(propID)
+ {
+ case kpidCreationTime:
+ case kpidLastWriteTime:
+ case kpidLastAccessTime:
+ {
+ if (propVariant.vt != VT_FILETIME)
+ return UString(); // It is error;
+ FILETIME localFileTime;
+ if (propVariant.filetime.dwHighDateTime == 0 &&
+ propVariant.filetime.dwLowDateTime == 0)
+ return UString();
+ if (!::FileTimeToLocalFileTime(&propVariant.filetime, &localFileTime))
+ return UString(); // It is error;
+ return ConvertFileTimeToString(localFileTime, true, full);
+ }
+ case kpidCRC:
+ {
+ if(propVariant.vt != VT_UI4)
+ break;
+ wchar_t temp[12];
+ ConvertUInt32ToHex(propVariant.ulVal, temp);
+ return temp;
+ }
+ case kpidAttributes:
+ {
+ if(propVariant.vt != VT_UI4)
+ break;
+ UString result;
+ UInt32 attributes = propVariant.ulVal;
+ if (NFile::NFind::NAttributes::IsReadOnly(attributes)) result += L'R';
+ if (NFile::NFind::NAttributes::IsHidden(attributes)) result += L'H';
+ if (NFile::NFind::NAttributes::IsSystem(attributes)) result += L'S';
+ if (NFile::NFind::NAttributes::IsDirectory(attributes)) result += L'D';
+ if (NFile::NFind::NAttributes::IsArchived(attributes)) result += L'A';
+ if (NFile::NFind::NAttributes::IsCompressed(attributes)) result += L'C';
+ if (NFile::NFind::NAttributes::IsEncrypted(attributes)) result += L'E';
+ return result;
+ }
+ case kpidDictionarySize:
+ {
+ if(propVariant.vt != VT_UI4)
+ break;
+ UInt32 size = propVariant.ulVal;
+ if (size % (1 << 20) == 0)
+ return ConvertUInt32ToString(size >> 20) + L"MB";
+ if (size % (1 << 10) == 0)
+ return ConvertUInt32ToString(size >> 10) + L"KB";
+ return ConvertUInt32ToString(size);
+ }
+ }
+ return ConvertPropVariantToString(propVariant);
+}
diff --git a/CPP/7zip/UI/Common/PropIDUtils.h b/CPP/7zip/UI/Common/PropIDUtils.h
new file mode 100755
index 00000000..aa540885
--- /dev/null
+++ b/CPP/7zip/UI/Common/PropIDUtils.h
@@ -0,0 +1,11 @@
+// PropIDUtils.h
+
+#ifndef __PROPIDUTILS_H
+#define __PROPIDUTILS_H
+
+#include "Common/String.h"
+
+UString ConvertPropertyToString(const PROPVARIANT &aPropVariant,
+ PROPID aPropID, bool aFull = true);
+
+#endif
diff --git a/CPP/7zip/UI/Common/Property.h b/CPP/7zip/UI/Common/Property.h
new file mode 100755
index 00000000..57e7b452
--- /dev/null
+++ b/CPP/7zip/UI/Common/Property.h
@@ -0,0 +1,14 @@
+// Property.h
+
+#ifndef __PROPERTY_H
+#define __PROPERTY_H
+
+#include "Common/String.h"
+
+struct CProperty
+{
+ UString Name;
+ UString Value;
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/SetProperties.cpp b/CPP/7zip/UI/Common/SetProperties.cpp
new file mode 100755
index 00000000..6c92a847
--- /dev/null
+++ b/CPP/7zip/UI/Common/SetProperties.cpp
@@ -0,0 +1,65 @@
+// SetProperties.cpp
+
+#include "StdAfx.h"
+
+#include "SetProperties.h"
+
+#include "Windows/PropVariant.h"
+#include "Common/String.h"
+#include "Common/StringToInt.h"
+#include "Common/MyCom.h"
+
+#include "../../Archive/IArchive.h"
+
+using namespace NWindows;
+using namespace NCOM;
+
+static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
+{
+ const wchar_t *endPtr;
+ UInt64 result = ConvertStringToUInt64(s, &endPtr);
+ if (endPtr - (const wchar_t *)s != s.Length())
+ prop = s;
+ else if (result <= 0xFFFFFFFF)
+ prop = (UInt32)result;
+ else
+ prop = result;
+}
+
+HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties)
+{
+ if (properties.IsEmpty())
+ return S_OK;
+ CMyComPtr<ISetProperties> setProperties;
+ unknown->QueryInterface(IID_ISetProperties, (void **)&setProperties);
+ if (!setProperties)
+ return S_OK;
+
+ UStringVector realNames;
+ CPropVariant *values = new CPropVariant[properties.Size()];
+ try
+ {
+ int i;
+ for(i = 0; i < properties.Size(); i++)
+ {
+ const CProperty &property = properties[i];
+ NCOM::CPropVariant propVariant;
+ if (!property.Value.IsEmpty())
+ ParseNumberString(property.Value, propVariant);
+ realNames.Add(property.Name);
+ values[i] = propVariant;
+ }
+ CRecordVector<const wchar_t *> names;
+ for(i = 0; i < realNames.Size(); i++)
+ names.Add((const wchar_t *)realNames[i]);
+
+ RINOK(setProperties->SetProperties(&names.Front(), values, names.Size()));
+ }
+ catch(...)
+ {
+ delete []values;
+ throw;
+ }
+ delete []values;
+ return S_OK;
+}
diff --git a/CPP/7zip/UI/Common/SetProperties.h b/CPP/7zip/UI/Common/SetProperties.h
new file mode 100755
index 00000000..892f1a21
--- /dev/null
+++ b/CPP/7zip/UI/Common/SetProperties.h
@@ -0,0 +1,10 @@
+// SetProperties.h
+
+#ifndef __SETPROPERTIES_H
+#define __SETPROPERTIES_H
+
+#include "Property.h"
+
+HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties);
+
+#endif
diff --git a/CPP/7zip/UI/Common/SortUtils.cpp b/CPP/7zip/UI/Common/SortUtils.cpp
new file mode 100755
index 00000000..c0111581
--- /dev/null
+++ b/CPP/7zip/UI/Common/SortUtils.cpp
@@ -0,0 +1,78 @@
+// SortUtils.cpp
+
+#include "StdAfx.h"
+
+#include "SortUtils.h"
+#include "Common/Types.h"
+
+/*
+template <class T>
+void TSortRefDown(T *p, UInt32 k, UInt32 size, int (*compare)(const T*, const T*, void *), void *param)
+{
+ T temp = p[k];
+ for (;;)
+ {
+ UInt32 s = (k << 1);
+ if (s > size)
+ break;
+ if (s < size && compare(p + s + 1, p + s, param) > 0)
+ s++;
+ if (compare(&temp, p + s, param) >= 0)
+ break;
+ p[k] = p[s];
+ k = s;
+ }
+ p[k] = temp;
+}
+
+template <class T>
+void TSort(T* p, UInt32 size, int (*compare)(const T*, const T*, void *), void *param)
+{
+ if (size <= 1)
+ return;
+ p--;
+ {
+ UInt32 i = size / 2;
+ do
+ TSortRefDown(p, i, size, compare, param);
+ while(--i != 0);
+ }
+ do
+ {
+ T temp = p[size];
+ p[size--] = p[1];
+ p[1] = temp;
+ TSortRefDown(p, 1, size, compare, param);
+ }
+ while (size > 1);
+}
+*/
+
+static int CompareStrings(const int *p1, const int *p2, void *param)
+{
+ const UStringVector &strings = *(const UStringVector *)param;
+ const UString &s1 = strings[*p1];
+ const UString &s2 = strings[*p2];
+ return s1.CompareNoCase(s2);
+}
+
+void SortStringsToIndices(const UStringVector &strings, CIntVector &indices)
+{
+ indices.Clear();
+ int numItems = strings.Size();
+ indices.Reserve(numItems);
+ for(int i = 0; i < numItems; i++)
+ indices.Add(i);
+ indices.Sort(CompareStrings, (void *)&strings);
+ // TSort(&indices.Front(), indices.Size(), CompareStrings, (void *)&strings);
+}
+
+void SortStrings(const UStringVector &src, UStringVector &dest)
+{
+ CIntVector indices;
+ SortStringsToIndices(src, indices);
+ dest.Clear();
+ dest.Reserve(indices.Size());
+ for (int i = 0; i < indices.Size(); i++)
+ dest.Add(src[indices[i]]);
+}
diff --git a/CPP/7zip/UI/Common/SortUtils.h b/CPP/7zip/UI/Common/SortUtils.h
new file mode 100755
index 00000000..5b9af264
--- /dev/null
+++ b/CPP/7zip/UI/Common/SortUtils.h
@@ -0,0 +1,11 @@
+// SortUtils.h
+
+#ifndef __SORTUTLS_H
+#define __SORTUTLS_H
+
+#include "Common/String.h"
+
+void SortStringsToIndices(const UStringVector &strings, CIntVector &indices);
+void SortStrings(const UStringVector &src, UStringVector &dest);
+
+#endif
diff --git a/CPP/7zip/UI/Common/StdAfx.h b/CPP/7zip/UI/Common/StdAfx.h
new file mode 100755
index 00000000..100f4344
--- /dev/null
+++ b/CPP/7zip/UI/Common/StdAfx.h
@@ -0,0 +1,9 @@
+// stdafx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/NewHandler.h"
+
+#endif
diff --git a/CPP/7zip/UI/Common/TempFiles.cpp b/CPP/7zip/UI/Common/TempFiles.cpp
new file mode 100755
index 00000000..3e604aea
--- /dev/null
+++ b/CPP/7zip/UI/Common/TempFiles.cpp
@@ -0,0 +1,22 @@
+// TempFiles.cpp
+
+#include "StdAfx.h"
+
+#include "TempFiles.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileIO.h"
+
+using namespace NWindows;
+using namespace NFile;
+
+void CTempFiles::Clear()
+{
+ while(!Paths.IsEmpty())
+ {
+ NDirectory::DeleteFileAlways(Paths.Back());
+ Paths.DeleteBack();
+ }
+}
+
+
diff --git a/CPP/7zip/UI/Common/TempFiles.h b/CPP/7zip/UI/Common/TempFiles.h
new file mode 100755
index 00000000..173713a0
--- /dev/null
+++ b/CPP/7zip/UI/Common/TempFiles.h
@@ -0,0 +1,16 @@
+// TempFiles.h
+
+#ifndef __TEMPFILES_H
+#define __TEMPFILES_H
+
+#include "Common/String.h"
+
+class CTempFiles
+{
+ void Clear();
+public:
+ UStringVector Paths;
+ ~CTempFiles() { Clear(); }
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/Update.cpp b/CPP/7zip/UI/Common/Update.cpp
new file mode 100755
index 00000000..cd7975d0
--- /dev/null
+++ b/CPP/7zip/UI/Common/Update.cpp
@@ -0,0 +1,818 @@
+// Update.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#include <mapi.h>
+#endif
+
+#include "Update.h"
+
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+#include "Common/CommandLineParser.h"
+
+#ifdef _WIN32
+#include "Windows/DLL.h"
+#endif
+
+#include "Windows/Defs.h"
+#include "Windows/FileDir.h"
+#include "Windows/FileFind.h"
+#include "Windows/FileName.h"
+#include "Windows/PropVariant.h"
+#include "Windows/PropVariantConversions.h"
+// #include "Windows/Synchronization.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Compress/Copy/CopyCoder.h"
+
+#include "../Common/DirItem.h"
+#include "../Common/EnumDirItems.h"
+#include "../Common/UpdateProduce.h"
+#include "../Common/OpenArchive.h"
+
+#include "TempFiles.h"
+#include "UpdateCallback.h"
+#include "EnumDirItems.h"
+#include "SetProperties.h"
+
+#ifdef FORMAT_7Z
+#include "../../Archive/7z/7zHandler.h"
+#endif
+
+#ifdef FORMAT_BZIP2
+#include "../../Archive/BZip2/BZip2Handler.h"
+#endif
+
+#ifdef FORMAT_GZIP
+#include "../../Archive/GZip/GZipHandler.h"
+#endif
+
+#ifdef FORMAT_TAR
+#include "../../Archive/Tar/TarHandler.h"
+#endif
+
+#ifdef FORMAT_ZIP
+#include "../../Archive/Zip/ZipHandler.h"
+#endif
+
+#ifndef EXCLUDE_COM
+#include "../Common/HandlerLoader.h"
+#endif
+
+static const char *kUpdateIsNotSupoorted =
+ "update operations are not supported for this archive";
+
+using namespace NCommandLineParser;
+using namespace NWindows;
+using namespace NCOM;
+using namespace NFile;
+using namespace NName;
+
+static const wchar_t *kTempArchiveFilePrefixString = L"7zi";
+static const wchar_t *kTempFolderPrefix = L"7zE";
+
+static const char *kIllegalFileNameMessage = "Illegal file name for temp archive";
+
+using namespace NUpdateArchive;
+
+static HRESULT CopyBlock(ISequentialInStream *inStream, ISequentialOutStream *outStream)
+{
+ CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
+ return copyCoder->Code(inStream, outStream, NULL, NULL, NULL);
+}
+
+class COutMultiVolStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+ int _streamIndex; // required stream
+ UInt64 _offsetPos; // offset from start of _streamIndex index
+ UInt64 _absPos;
+ UInt64 _length;
+
+ struct CSubStreamInfo
+ {
+ CMyComPtr<IOutStream> Stream;
+ UString Name;
+ UInt64 Pos;
+ UInt64 RealSize;
+ };
+ CObjectVector<CSubStreamInfo> Streams;
+public:
+ // CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
+ CRecordVector<UInt64> Sizes;
+ UString Prefix;
+ CTempFiles *TempFiles;
+
+ void Init()
+ {
+ _streamIndex = 0;
+ _offsetPos = 0;
+ _absPos = 0;
+ _length = 0;
+ }
+
+ MY_UNKNOWN_IMP1(IOutStream)
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+ STDMETHOD(SetSize)(Int64 newSize);
+};
+
+// static NSynchronization::CCriticalSection g_TempPathsCS;
+
+STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if(processedSize != NULL)
+ *processedSize = 0;
+ while(size > 0)
+ {
+ if (_streamIndex >= Streams.Size())
+ {
+ CSubStreamInfo subStream;
+
+ wchar_t temp[32];
+ ConvertUInt64ToString(_streamIndex + 1, temp);
+ UString res = temp;
+ while (res.Length() < 3)
+ res = UString(L'0') + res;
+ UString name = Prefix + res;
+ COutFileStream *streamSpec = new COutFileStream;
+ subStream.Stream = streamSpec;
+ if(!streamSpec->Create(name, false))
+ return ::GetLastError();
+ {
+ // NSynchronization::CCriticalSectionLock lock(g_TempPathsCS);
+ TempFiles->Paths.Add(name);
+ }
+
+ subStream.Pos = 0;
+ subStream.RealSize = 0;
+ subStream.Name = name;
+ Streams.Add(subStream);
+ continue;
+ }
+ CSubStreamInfo &subStream = Streams[_streamIndex];
+
+ int index = _streamIndex;
+ if (index >= Sizes.Size())
+ index = Sizes.Size() - 1;
+ UInt64 volSize = Sizes[index];
+
+ if (_offsetPos >= volSize)
+ {
+ _offsetPos -= volSize;
+ _streamIndex++;
+ continue;
+ }
+ if (_offsetPos != subStream.Pos)
+ {
+ // CMyComPtr<IOutStream> outStream;
+ // RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));
+ RINOK(subStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));
+ subStream.Pos = _offsetPos;
+ }
+
+ UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - subStream.Pos);
+ UInt32 realProcessed;
+ RINOK(subStream.Stream->Write(data, curSize, &realProcessed));
+ data = (void *)((Byte *)data + realProcessed);
+ size -= realProcessed;
+ subStream.Pos += realProcessed;
+ _offsetPos += realProcessed;
+ _absPos += realProcessed;
+ if (_absPos > _length)
+ _length = _absPos;
+ if (_offsetPos > subStream.RealSize)
+ subStream.RealSize = _offsetPos;
+ if(processedSize != NULL)
+ *processedSize += realProcessed;
+ if (subStream.Pos == volSize)
+ {
+ _streamIndex++;
+ _offsetPos = 0;
+ }
+ if (realProcessed == 0 && curSize != 0)
+ return E_FAIL;
+ break;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP COutMultiVolStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ if(seekOrigin >= 3)
+ return STG_E_INVALIDFUNCTION;
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET:
+ _absPos = offset;
+ break;
+ case STREAM_SEEK_CUR:
+ _absPos += offset;
+ break;
+ case STREAM_SEEK_END:
+ _absPos = _length + offset;
+ break;
+ }
+ _offsetPos = _absPos;
+ if (newPosition != NULL)
+ *newPosition = _absPos;
+ _streamIndex = 0;
+ return S_OK;
+}
+
+STDMETHODIMP COutMultiVolStream::SetSize(Int64 newSize)
+{
+ if (newSize < 0)
+ return E_INVALIDARG;
+ int i = 0;
+ while (i < Streams.Size())
+ {
+ CSubStreamInfo &subStream = Streams[i++];
+ if ((UInt64)newSize < subStream.RealSize)
+ {
+ RINOK(subStream.Stream->SetSize(newSize));
+ subStream.RealSize = newSize;
+ break;
+ }
+ newSize -= subStream.RealSize;
+ }
+ while (i < Streams.Size())
+ {
+ {
+ CSubStreamInfo &subStream = Streams.Back();
+ subStream.Stream.Release();
+ NDirectory::DeleteFileAlways(subStream.Name);
+ }
+ Streams.DeleteBack();
+ }
+ _offsetPos = _absPos;
+ _streamIndex = 0;
+ _length = newSize;
+ return S_OK;
+}
+
+
+static HRESULT Compress(
+ const CActionSet &actionSet,
+ IInArchive *archive,
+ const CCompressionMethodMode &compressionMethod,
+ CArchivePath &archivePath,
+ const CObjectVector<CArchiveItem> &archiveItems,
+ bool stdInMode,
+ /* const UString & stdInFileName, */
+ bool stdOutMode,
+ const CObjectVector<CDirItem> &dirItems,
+ bool sfxMode,
+ const UString &sfxModule,
+ const CRecordVector<UInt64> &volumesSizes,
+ CTempFiles &tempFiles,
+ CUpdateErrorInfo &errorInfo,
+ IUpdateCallbackUI *callback)
+{
+ #ifndef EXCLUDE_COM
+ CHandlerLoader loader;
+ #endif
+
+ CMyComPtr<IOutArchive> outArchive;
+ if(archive != NULL)
+ {
+ CMyComPtr<IInArchive> archive2 = archive;
+ HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive);
+ if(result != S_OK)
+ throw kUpdateIsNotSupoorted;
+ }
+ else
+ {
+ #ifndef EXCLUDE_COM
+
+ if (loader.CreateHandler(compressionMethod.FilePath,
+ compressionMethod.ClassID, (void **)&outArchive, true) != S_OK)
+ throw kUpdateIsNotSupoorted;
+ #endif
+
+ #ifdef FORMAT_7Z
+ if (compressionMethod.Name.CompareNoCase(L"7z") == 0)
+ outArchive = new NArchive::N7z::CHandler;
+ #endif
+
+ #ifdef FORMAT_BZIP2
+ if (compressionMethod.Name.CompareNoCase(L"BZip2") == 0)
+ outArchive = new NArchive::NBZip2::CHandler;
+ #endif
+
+ #ifdef FORMAT_GZIP
+ if (compressionMethod.Name.CompareNoCase(L"GZip") == 0)
+ outArchive = new NArchive::NGZip::CHandler;
+ #endif
+
+ #ifdef FORMAT_TAR
+ if (compressionMethod.Name.CompareNoCase(L"Tar") == 0)
+ outArchive = new NArchive::NTar::CHandler;
+ #endif
+
+ #ifdef FORMAT_ZIP
+ if (compressionMethod.Name.CompareNoCase(L"Zip") == 0)
+ outArchive = new NArchive::NZip::CHandler;
+ #endif
+
+ }
+ if (outArchive == 0)
+ throw kUpdateIsNotSupoorted;
+
+ NFileTimeType::EEnum fileTimeType;
+ UInt32 value;
+ RINOK(outArchive->GetFileTimeType(&value));
+
+ switch(value)
+ {
+ case NFileTimeType::kWindows:
+ case NFileTimeType::kDOS:
+ case NFileTimeType::kUnix:
+ fileTimeType = NFileTimeType::EEnum(value);
+ break;
+ default:
+ return E_FAIL;
+ }
+
+ CObjectVector<CUpdatePair> updatePairs;
+ GetUpdatePairInfoList(dirItems, archiveItems, fileTimeType, updatePairs); // must be done only once!!!
+
+ CObjectVector<CUpdatePair2> updatePairs2;
+ UpdateProduce(updatePairs, actionSet, updatePairs2);
+
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec );
+
+ updateCallbackSpec->StdInMode = stdInMode;
+ updateCallbackSpec->Callback = callback;
+ updateCallbackSpec->DirItems = &dirItems;
+ updateCallbackSpec->ArchiveItems = &archiveItems;
+ updateCallbackSpec->UpdatePairs = &updatePairs2;
+
+ CMyComPtr<ISequentialOutStream> outStream;
+
+ const UString &archiveName = archivePath.GetFinalPath();
+ if (!stdOutMode)
+ {
+ UString resultPath;
+ int pos;
+ if(!NFile::NDirectory::MyGetFullPathName(archiveName, resultPath, pos))
+ throw 1417161;
+ NFile::NDirectory::CreateComplexDirectory(resultPath.Left(pos));
+ }
+ if (volumesSizes.Size() == 0)
+ {
+ if (stdOutMode)
+ outStream = new CStdOutFileStream;
+ else
+ {
+ COutFileStream *outStreamSpec = new COutFileStream;
+ outStream = outStreamSpec;
+ bool isOK = false;
+ UString realPath;
+ for (int i = 0; i < (1 << 16); i++)
+ {
+ if (archivePath.Temp)
+ {
+ if (i > 0)
+ {
+ wchar_t s[32];
+ ConvertUInt64ToString(i, s);
+ archivePath.TempPostfix = s;
+ }
+ realPath = archivePath.GetTempPath();
+ }
+ else
+ realPath = archivePath.GetFinalPath();
+ if (outStreamSpec->Create(realPath, false))
+ {
+ tempFiles.Paths.Add(realPath);
+ isOK = true;
+ break;
+ }
+ if (::GetLastError() != ERROR_FILE_EXISTS)
+ break;
+ if (!archivePath.Temp)
+ break;
+ }
+ if (!isOK)
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.FileName = realPath;
+ errorInfo.Message = L"Can not open file";
+ return E_FAIL;
+ }
+ }
+ }
+ else
+ {
+ if (stdOutMode)
+ return E_FAIL;
+ COutMultiVolStream *volStreamSpec = new COutMultiVolStream;
+ outStream = volStreamSpec;
+ volStreamSpec->Sizes = volumesSizes;
+ volStreamSpec->Prefix = archivePath.GetFinalPath() + UString(L".");
+ volStreamSpec->TempFiles = &tempFiles;
+ volStreamSpec->Init();
+
+ /*
+ updateCallbackSpec->VolumesSizes = volumesSizes;
+ updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name;
+ if (!archivePath.VolExtension.IsEmpty())
+ updateCallbackSpec->VolExt = UString(L'.') + archivePath.VolExtension;
+ */
+ }
+
+ RINOK(SetProperties(outArchive, compressionMethod.Properties));
+
+ if (sfxMode)
+ {
+ CInFileStream *sfxStreamSpec = new CInFileStream;
+ CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
+ if (!sfxStreamSpec->Open(sfxModule))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"Can't open sfx module";
+ errorInfo.FileName = sfxModule;
+ return E_FAIL;
+ }
+
+ CMyComPtr<ISequentialOutStream> sfxOutStream;
+ if (volumesSizes.Size() == 0)
+ sfxOutStream = outStream;
+ else
+ {
+ COutFileStream *outStreamSpec = new COutFileStream;
+ sfxOutStream = outStreamSpec;
+ UString realPath = archivePath.GetFinalPath();
+ if (!outStreamSpec->Create(realPath, false))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.FileName = realPath;
+ errorInfo.Message = L"Can not open file";
+ return E_FAIL;
+ }
+ }
+ RINOK(CopyBlock(sfxStream, sfxOutStream));
+ }
+
+ HRESULT result = outArchive->UpdateItems(outStream, updatePairs2.Size(),
+ updateCallback);
+ callback->Finilize();
+ return result;
+}
+
+
+
+HRESULT EnumerateInArchiveItems(const NWildcard::CCensor &censor,
+ IInArchive *archive,
+ const UString &defaultItemName,
+ const NWindows::NFile::NFind::CFileInfoW &archiveFileInfo,
+ CObjectVector<CArchiveItem> &archiveItems)
+{
+ archiveItems.Clear();
+ UInt32 numItems;
+ RINOK(archive->GetNumberOfItems(&numItems));
+ archiveItems.Reserve(numItems);
+ for(UInt32 i = 0; i < numItems; i++)
+ {
+ CArchiveItem ai;
+
+ RINOK(GetArchiveItemPath(archive, i, ai.Name));
+ RINOK(IsArchiveItemFolder(archive, i, ai.IsDirectory));
+ ai.Censored = censor.CheckPath(ai.Name.IsEmpty() ? defaultItemName : ai.Name, !ai.IsDirectory);
+ RINOK(GetArchiveItemFileTime(archive, i,
+ archiveFileInfo.LastWriteTime, ai.LastWriteTime));
+
+ CPropVariant propertySize;
+ RINOK(archive->GetProperty(i, kpidSize, &propertySize));
+ ai.SizeIsDefined = (propertySize.vt != VT_EMPTY);
+ if (ai.SizeIsDefined)
+ ai.Size = ConvertPropVariantToUInt64(propertySize);
+
+ ai.IndexInServer = i;
+ archiveItems.Add(ai);
+ }
+ return S_OK;
+}
+
+
+static HRESULT UpdateWithItemLists(
+ CUpdateOptions &options,
+ IInArchive *archive,
+ const CObjectVector<CArchiveItem> &archiveItems,
+ const CObjectVector<CDirItem> &dirItems,
+ CTempFiles &tempFiles,
+ CUpdateErrorInfo &errorInfo,
+ IUpdateCallbackUI2 *callback)
+{
+ for(int i = 0; i < options.Commands.Size(); i++)
+ {
+ CUpdateArchiveCommand &command = options.Commands[i];
+ if (options.StdOutMode)
+ {
+ RINOK(callback->StartArchive(0, archive != 0));
+ }
+ else
+ {
+ RINOK(callback->StartArchive(command.ArchivePath.GetFinalPath(),
+ i == 0 && options.UpdateArchiveItself && archive != 0));
+ }
+
+ RINOK(Compress(command.ActionSet, archive,
+ options.MethodMode,
+ command.ArchivePath,
+ archiveItems,
+ options.StdInMode,
+ /* options.StdInFileName, */
+ options.StdOutMode,
+ dirItems,
+ options.SfxMode, options.SfxModule,
+ options.VolumesSizes,
+ tempFiles,
+ errorInfo, callback));
+
+ RINOK(callback->FinishArchive());
+ }
+ return S_OK;
+}
+
+#ifdef _WIN32
+class CCurrentDirRestorer
+{
+ UString m_CurrentDirectory;
+public:
+ CCurrentDirRestorer()
+ { NFile::NDirectory::MyGetCurrentDirectory(m_CurrentDirectory); }
+ ~CCurrentDirRestorer()
+ { RestoreDirectory();}
+ bool RestoreDirectory()
+ { return BOOLToBool(NFile::NDirectory::MySetCurrentDirectory(m_CurrentDirectory)); }
+};
+#endif
+
+struct CEnumDirItemUpdateCallback: public IEnumDirItemCallback
+{
+ IUpdateCallbackUI2 *Callback;
+ HRESULT CheckBreak() { return Callback->CheckBreak(); }
+};
+
+HRESULT UpdateArchive(const NWildcard::CCensor &censor,
+ CUpdateOptions &options,
+ CUpdateErrorInfo &errorInfo,
+ IOpenCallbackUI *openCallback,
+ IUpdateCallbackUI2 *callback)
+{
+ if (options.StdOutMode && options.EMailMode)
+ return E_FAIL;
+
+ if (options.VolumesSizes.Size() > 0 && (options.EMailMode || options.SfxMode))
+ return E_NOTIMPL;
+
+ if (options.SfxMode)
+ {
+ CProperty property;
+ property.Name = L"rsfx";
+ property.Value = L"on";
+ options.MethodMode.Properties.Add(property);
+ if (options.SfxModule.IsEmpty())
+ {
+ errorInfo.Message = L"sfx file is not specified";
+ return E_FAIL;
+ }
+ UString name = options.SfxModule;
+ if (!NDirectory::MySearchPath(NULL, name, NULL, options.SfxModule))
+ {
+ errorInfo.Message = L"can't find specified sfx module";
+ return E_FAIL;
+ }
+ }
+
+ const UString archiveName = options.ArchivePath.GetFinalPath();
+
+ UString defaultItemName;
+ NFind::CFileInfoW archiveFileInfo;
+
+ CArchiveLink archiveLink;
+ IInArchive *archive = 0;
+ if (NFind::FindFile(archiveName, archiveFileInfo))
+ {
+ if (archiveFileInfo.IsDirectory())
+ throw "there is no such archive";
+ if (options.VolumesSizes.Size() > 0)
+ return E_NOTIMPL;
+ HRESULT result = MyOpenArchive(archiveName, archiveLink, openCallback);
+ RINOK(callback->OpenResult(archiveName, result));
+ RINOK(result);
+ if (archiveLink.VolumePaths.Size() > 1)
+ {
+ errorInfo.SystemError = (DWORD)E_NOTIMPL;
+ errorInfo.Message = L"Updating for multivolume archives is not implemented";
+ return E_NOTIMPL;
+ }
+ archive = archiveLink.GetArchive();
+ defaultItemName = archiveLink.GetDefaultItemName();
+ }
+ else
+ {
+ /*
+ if (archiveType.IsEmpty())
+ throw "type of archive is not specified";
+ */
+ }
+
+ CObjectVector<CDirItem> dirItems;
+ if (options.StdInMode)
+ {
+ CDirItem item;
+ item.FullPath = item.Name = options.StdInFileName;
+ item.Size = (UInt64)(Int64)-1;
+ item.Attributes = 0;
+ SYSTEMTIME st;
+ FILETIME ft;
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+ item.CreationTime = item.LastAccessTime = item.LastWriteTime = ft;
+ dirItems.Add(item);
+ }
+ else
+ {
+ bool needScanning = false;
+ for(int i = 0; i < options.Commands.Size(); i++)
+ if (options.Commands[i].ActionSet.NeedScanning())
+ needScanning = true;
+ if (needScanning)
+ {
+ CEnumDirItemUpdateCallback enumCallback;
+ enumCallback.Callback = callback;
+ RINOK(callback->StartScanning());
+ UStringVector errorPaths;
+ CRecordVector<DWORD> errorCodes;
+ HRESULT res = EnumerateItems(censor, dirItems, &enumCallback, errorPaths, errorCodes);
+ for (int i = 0; i < errorPaths.Size(); i++)
+ {
+ RINOK(callback->CanNotFindError(errorPaths[i], errorCodes[i]));
+ }
+ if(res != S_OK)
+ {
+ errorInfo.Message = L"Scanning error";
+ // errorInfo.FileName = errorPath;
+ return res;
+ }
+ RINOK(callback->FinishScanning());
+ }
+ }
+
+ UString tempDirPrefix;
+ bool usesTempDir = false;
+
+ #ifdef _WIN32
+ NDirectory::CTempDirectoryW tempDirectory;
+ if (options.EMailMode && options.EMailRemoveAfter)
+ {
+ tempDirectory.Create(kTempFolderPrefix);
+ tempDirPrefix = tempDirectory.GetPath();
+ NormalizeDirPathPrefix(tempDirPrefix);
+ usesTempDir = true;
+ }
+ #endif
+
+ CTempFiles tempFiles;
+
+ bool createTempFile = false;
+ if(!options.StdOutMode && options.UpdateArchiveItself)
+ {
+ CArchivePath &ap = options.Commands[0].ArchivePath;
+ ap = options.ArchivePath;
+ // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty())
+ if ((archive != 0 || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0)
+ {
+ createTempFile = true;
+ ap.Temp = true;
+ if (!options.WorkingDir.IsEmpty())
+ {
+ ap.TempPrefix = options.WorkingDir;
+ NormalizeDirPathPrefix(ap.TempPrefix);
+ }
+ }
+ }
+
+ for(int i = 0; i < options.Commands.Size(); i++)
+ {
+ CArchivePath &ap = options.Commands[i].ArchivePath;
+ if (usesTempDir)
+ {
+ // Check it
+ ap.Prefix = tempDirPrefix;
+ // ap.Temp = true;
+ // ap.TempPrefix = tempDirPrefix;
+ }
+ if (i > 0 || !createTempFile)
+ {
+ const UString &path = ap.GetFinalPath();
+ if (NFind::DoesFileExist(path))
+ {
+ errorInfo.SystemError = 0;
+ errorInfo.Message = L"File already exists";
+ errorInfo.FileName = path;
+ return E_FAIL;
+ }
+ }
+ }
+
+ CObjectVector<CArchiveItem> archiveItems;
+ if (archive != NULL)
+ {
+ RINOK(EnumerateInArchiveItems(censor,
+ archive, defaultItemName, archiveFileInfo, archiveItems));
+ }
+
+ RINOK(UpdateWithItemLists(options, archive, archiveItems, dirItems,
+ tempFiles, errorInfo, callback));
+
+ if (archive != NULL)
+ {
+ RINOK(archiveLink.Close());
+ archiveLink.Release();
+ }
+
+ tempFiles.Paths.Clear();
+ if(createTempFile)
+ {
+ try
+ {
+ CArchivePath &ap = options.Commands[0].ArchivePath;
+ const UString &tempPath = ap.GetTempPath();
+ if (archive != NULL)
+ if (!NDirectory::DeleteFileAlways(archiveName))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"delete file error";
+ errorInfo.FileName = archiveName;
+ return E_FAIL;
+ }
+ if (!NDirectory::MyMoveFile(tempPath, archiveName))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"move file error";
+ errorInfo.FileName = tempPath;
+ errorInfo.FileName2 = archiveName;
+ return E_FAIL;
+ }
+ }
+ catch(...)
+ {
+ throw;
+ }
+ }
+
+ #ifdef _WIN32
+ if (options.EMailMode)
+ {
+ NDLL::CLibrary mapiLib;
+ if (!mapiLib.Load(TEXT("Mapi32.dll")))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"can not load Mapi32.dll";
+ return E_FAIL;
+ }
+ LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)
+ mapiLib.GetProcAddress("MAPISendDocuments");
+ if (fnSend == 0)
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"can not find MAPISendDocuments function";
+ return E_FAIL;
+ }
+ UStringVector fullPaths;
+ int i;
+ for(i = 0; i < options.Commands.Size(); i++)
+ {
+ CArchivePath &ap = options.Commands[i].ArchivePath;
+ UString arcPath;
+ if(!NFile::NDirectory::MyGetFullPathName(ap.GetFinalPath(), arcPath))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ return E_FAIL;
+ }
+ fullPaths.Add(arcPath);
+ }
+ CCurrentDirRestorer curDirRestorer;
+ for(i = 0; i < fullPaths.Size(); i++)
+ {
+ UString arcPath = fullPaths[i];
+ UString fileName = ExtractFileNameFromPath(arcPath);
+ AString path = GetAnsiString(arcPath);
+ AString name = GetAnsiString(fileName);
+ // Warning!!! MAPISendDocuments function changes Current directory
+ fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0);
+ }
+ }
+ #endif
+ return S_OK;
+}
+
diff --git a/CPP/7zip/UI/Common/Update.h b/CPP/7zip/UI/Common/Update.h
new file mode 100755
index 00000000..465acc24
--- /dev/null
+++ b/CPP/7zip/UI/Common/Update.h
@@ -0,0 +1,158 @@
+// Update.h
+
+#ifndef __UPDATE_H
+#define __UPDATE_H
+
+#include "Common/Wildcard.h"
+#include "Windows/FileFind.h"
+#include "../../Archive/IArchive.h"
+
+#include "UpdateAction.h"
+#include "ArchiveOpenCallback.h"
+#include "UpdateCallback.h"
+#include "Property.h"
+
+struct CArchivePath
+{
+ UString Prefix; // path(folder) prefix including slash
+ UString Name; // base name
+ UString BaseExtension; // archive type extension or "exe" extension
+ UString VolExtension; // archive type extension for volumes
+
+ bool Temp;
+ UString TempPrefix; // path(folder) for temp location
+ UString TempPostfix;
+
+ CArchivePath(): Temp(false) {};
+
+ void ParseFromPath(const UString &path)
+ {
+ SplitPathToParts(path, Prefix, Name);
+ if (Name.IsEmpty())
+ return;
+ int dotPos = Name.ReverseFind(L'.');
+ if (dotPos <= 0)
+ return;
+ if (dotPos == Name.Length() - 1)
+ {
+ Name = Name.Left(dotPos);
+ BaseExtension.Empty();
+ return;
+ }
+ if (BaseExtension.CompareNoCase(Name.Mid(dotPos + 1)) == 0)
+ {
+ BaseExtension = Name.Mid(dotPos + 1);
+ Name = Name.Left(dotPos);
+ }
+ else
+ BaseExtension.Empty();
+ }
+
+ UString GetPathWithoutExt() const
+ {
+ return Prefix + Name;
+ }
+
+ UString GetFinalPath() const
+ {
+ UString path = GetPathWithoutExt();
+ if (!BaseExtension.IsEmpty())
+ path += UString(L'.') + BaseExtension;
+ return path;
+ }
+
+
+ UString GetTempPath() const
+ {
+ UString path = TempPrefix + Name;
+ if (!BaseExtension.IsEmpty())
+ path += UString(L'.') + BaseExtension;
+ path += L".tmp";
+ path += TempPostfix;
+ return path;
+ }
+};
+
+struct CUpdateArchiveCommand
+{
+ CArchivePath ArchivePath;
+ NUpdateArchive::CActionSet ActionSet;
+};
+
+struct CCompressionMethodMode
+{
+ #ifndef EXCLUDE_COM
+ UString FilePath;
+ CLSID ClassID;
+ #else
+ UString Name;
+ #endif
+ CObjectVector<CProperty> Properties;
+};
+
+struct CUpdateOptions
+{
+ CCompressionMethodMode MethodMode;
+
+ CObjectVector<CUpdateArchiveCommand> Commands;
+ bool UpdateArchiveItself;
+ CArchivePath ArchivePath;
+
+ bool SfxMode;
+ UString SfxModule;
+
+ bool StdInMode;
+ UString StdInFileName;
+ bool StdOutMode;
+
+ bool EMailMode;
+ bool EMailRemoveAfter;
+ UString EMailAddress;
+
+ UString WorkingDir;
+
+ CUpdateOptions():
+ UpdateArchiveItself(true),
+ SfxMode(false),
+ StdInMode(false),
+ StdOutMode(false),
+ EMailMode(false),
+ EMailRemoveAfter(false)
+ {};
+ CRecordVector<UInt64> VolumesSizes;
+};
+
+struct CErrorInfo
+{
+ DWORD SystemError;
+ UString FileName;
+ UString FileName2;
+ UString Message;
+ // UStringVector ErrorPaths;
+ // CRecordVector<DWORD> ErrorCodes;
+ CErrorInfo(): SystemError(0) {};
+};
+
+struct CUpdateErrorInfo: public CErrorInfo
+{
+};
+
+struct IUpdateCallbackUI2: public IUpdateCallbackUI
+{
+ virtual HRESULT OpenResult(const wchar_t *name, HRESULT result) = 0;
+
+ virtual HRESULT StartScanning() = 0;
+ virtual HRESULT CanNotFindError(const wchar_t *name, DWORD systemError) = 0;
+ virtual HRESULT FinishScanning() = 0;
+
+ virtual HRESULT StartArchive(const wchar_t *name, bool updating) = 0;
+ virtual HRESULT FinishArchive() = 0;
+};
+
+HRESULT UpdateArchive(const NWildcard::CCensor &censor,
+ CUpdateOptions &options,
+ CUpdateErrorInfo &errorInfo,
+ IOpenCallbackUI *openCallback,
+ IUpdateCallbackUI2 *callback);
+
+#endif
diff --git a/CPP/7zip/UI/Common/UpdateAction.cpp b/CPP/7zip/UI/Common/UpdateAction.cpp
new file mode 100755
index 00000000..5e3b5a10
--- /dev/null
+++ b/CPP/7zip/UI/Common/UpdateAction.cpp
@@ -0,0 +1,64 @@
+// UpdateAction.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateAction.h"
+
+namespace NUpdateArchive {
+
+const CActionSet kAddActionSet =
+{
+ NPairAction::kCopy,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCompress,
+ NPairAction::kCompress,
+ NPairAction::kCompress,
+ NPairAction::kCompress
+};
+
+const CActionSet kUpdateActionSet =
+{
+ NPairAction::kCopy,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress
+};
+
+const CActionSet kFreshActionSet =
+{
+ NPairAction::kCopy,
+ NPairAction::kCopy,
+ NPairAction::kIgnore,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress
+};
+
+const CActionSet kSynchronizeActionSet =
+{
+ NPairAction::kCopy,
+ NPairAction::kIgnore,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+};
+
+const CActionSet kDeleteActionSet =
+{
+ NPairAction::kCopy,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore
+};
+
+}
diff --git a/CPP/7zip/UI/Common/UpdateAction.h b/CPP/7zip/UI/Common/UpdateAction.h
new file mode 100755
index 00000000..aa050975
--- /dev/null
+++ b/CPP/7zip/UI/Common/UpdateAction.h
@@ -0,0 +1,57 @@
+// UpdateAction.h
+
+#ifndef __UPDATE_ACTION_H
+#define __UPDATE_ACTION_H
+
+namespace NUpdateArchive {
+
+ namespace NPairState
+ {
+ const int kNumValues = 7;
+ enum EEnum
+ {
+ kNotMasked = 0,
+ kOnlyInArchive,
+ kOnlyOnDisk,
+ kNewInArchive,
+ kOldInArchive,
+ kSameFiles,
+ kUnknowNewerFiles
+ };
+ }
+ namespace NPairAction
+ {
+ enum EEnum
+ {
+ kIgnore = 0,
+ kCopy,
+ kCompress,
+ kCompressAsAnti
+ };
+ }
+ struct CActionSet
+ {
+ NPairAction::EEnum StateActions[NPairState::kNumValues];
+ bool NeedScanning() const
+ {
+ int i;
+ for (i = 0; i < NPairState::kNumValues; i++)
+ if (StateActions[i] == NPairAction::kCompress)
+ return true;
+ for (i = 1; i < NPairState::kNumValues; i++)
+ if (StateActions[i] != NPairAction::kIgnore)
+ return true;
+ return false;
+ }
+ };
+ extern const CActionSet kAddActionSet;
+ extern const CActionSet kUpdateActionSet;
+ extern const CActionSet kFreshActionSet;
+ extern const CActionSet kSynchronizeActionSet;
+ extern const CActionSet kDeleteActionSet;
+};
+
+
+#endif
+
+
diff --git a/CPP/7zip/UI/Common/UpdateCallback.cpp b/CPP/7zip/UI/Common/UpdateCallback.cpp
new file mode 100755
index 00000000..db3bf805
--- /dev/null
+++ b/CPP/7zip/UI/Common/UpdateCallback.cpp
@@ -0,0 +1,258 @@
+// UpdateCallback.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateCallback.h"
+
+#include "Common/StringConvert.h"
+#include "Common/IntToString.h"
+#include "Common/Defs.h"
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../../Common/FileStreams.h"
+
+using namespace NWindows;
+
+CArchiveUpdateCallback::CArchiveUpdateCallback():
+ Callback(0),
+ StdInMode(false),
+ DirItems(0),
+ ArchiveItems(0),
+ UpdatePairs(0)
+ {}
+
+
+STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 size)
+{
+ COM_TRY_BEGIN
+ return Callback->SetTotal(size);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)
+{
+ COM_TRY_BEGIN
+ return Callback->SetCompleted(completeValue);
+ COM_TRY_END
+}
+
+/*
+STATPROPSTG kProperties[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsFolder, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidLastAccessTime, VT_FILETIME},
+ { NULL, kpidCreationTime, VT_FILETIME},
+ { NULL, kpidLastWriteTime, VT_FILETIME},
+ { NULL, kpidAttributes, VT_UI4},
+ { NULL, kpidIsAnti, VT_BOOL}
+};
+*/
+
+STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **)
+{
+ return E_NOTIMPL;
+ /*
+ return CStatPropEnumerator::CreateEnumerator(kProperties,
+ sizeof(kProperties) / sizeof(kProperties[0]), enumerator);
+ */
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index,
+ Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive)
+{
+ COM_TRY_BEGIN
+ RINOK(Callback->CheckBreak());
+ const CUpdatePair2 &updatePair = (*UpdatePairs)[index];
+ if(newData != NULL)
+ *newData = BoolToInt(updatePair.NewData);
+ if(newProperties != NULL)
+ *newProperties = BoolToInt(updatePair.NewProperties);
+ if(indexInArchive != NULL)
+ {
+ if (updatePair.ExistInArchive)
+ {
+ if (ArchiveItems == 0)
+ *indexInArchive = updatePair.ArchiveItemIndex;
+ else
+ *indexInArchive = (*ArchiveItems)[updatePair.ArchiveItemIndex].IndexInServer;
+ }
+ else
+ *indexInArchive = UInt32(-1);
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ const CUpdatePair2 &updatePair = (*UpdatePairs)[index];
+ NWindows::NCOM::CPropVariant propVariant;
+
+ if (propID == kpidIsAnti)
+ {
+ propVariant = updatePair.IsAnti;
+ propVariant.Detach(value);
+ return S_OK;
+ }
+
+ if (updatePair.IsAnti)
+ {
+ switch(propID)
+ {
+ case kpidIsFolder:
+ case kpidPath:
+ break;
+ case kpidSize:
+ propVariant = (UInt64)0;
+ propVariant.Detach(value);
+ return S_OK;
+ default:
+ propVariant.Detach(value);
+ return S_OK;
+ }
+ }
+
+ if(updatePair.ExistOnDisk)
+ {
+ const CDirItem &dirItem = (*DirItems)[updatePair.DirItemIndex];
+ switch(propID)
+ {
+ case kpidPath:
+ propVariant = dirItem.Name;
+ break;
+ case kpidIsFolder:
+ propVariant = dirItem.IsDirectory();
+ break;
+ case kpidSize:
+ propVariant = dirItem.Size;
+ break;
+ case kpidAttributes:
+ propVariant = dirItem.Attributes;
+ break;
+ case kpidLastAccessTime:
+ propVariant = dirItem.LastAccessTime;
+ break;
+ case kpidCreationTime:
+ propVariant = dirItem.CreationTime;
+ break;
+ case kpidLastWriteTime:
+ propVariant = dirItem.LastWriteTime;
+ break;
+ }
+ }
+ else
+ {
+ if (propID == kpidPath)
+ {
+ if (updatePair.NewNameIsDefined)
+ {
+ propVariant = updatePair.NewName;
+ propVariant.Detach(value);
+ return S_OK;
+ }
+ }
+ if (updatePair.ExistInArchive && Archive)
+ {
+ UInt32 indexInArchive;
+ if (ArchiveItems == 0)
+ indexInArchive = updatePair.ArchiveItemIndex;
+ else
+ indexInArchive = (*ArchiveItems)[updatePair.ArchiveItemIndex].IndexInServer;
+ return Archive->GetProperty(indexInArchive, propID, value);
+ }
+ }
+ propVariant.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)
+{
+ COM_TRY_BEGIN
+ const CUpdatePair2 &updatePair = (*UpdatePairs)[index];
+ if(!updatePair.NewData)
+ return E_FAIL;
+
+ RINOK(Callback->CheckBreak());
+ RINOK(Callback->Finilize());
+
+ if(updatePair.IsAnti)
+ {
+ return Callback->GetStream((*ArchiveItems)[updatePair.ArchiveItemIndex].Name, true);
+ }
+ const CDirItem &dirItem = (*DirItems)[updatePair.DirItemIndex];
+ RINOK(Callback->GetStream(dirItem.Name, false));
+
+ if(dirItem.IsDirectory())
+ return S_OK;
+
+ if (StdInMode)
+ {
+ CStdInFileStream *inStreamSpec = new CStdInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+ *inStream = inStreamLoc.Detach();
+ }
+ else
+ {
+ CInFileStream *inStreamSpec = new CInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+ UString path = DirPrefix + dirItem.FullPath;
+ if(!inStreamSpec->Open(path))
+ {
+ return Callback->OpenFileError(path, ::GetLastError());
+ }
+ *inStream = inStreamLoc.Detach();
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 operationResult)
+{
+ COM_TRY_BEGIN
+ return Callback->SetOperationResult(operationResult);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)
+{
+ if (VolumesSizes.Size() == 0)
+ return S_FALSE;
+ if (index >= (UInt32)VolumesSizes.Size())
+ index = VolumesSizes.Size() - 1;
+ *size = VolumesSizes[index];
+ return S_OK;
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)
+{
+ COM_TRY_BEGIN
+ wchar_t temp[32];
+ ConvertUInt64ToString(index + 1, temp);
+ UString res = temp;
+ while (res.Length() < 2)
+ res = UString(L'0') + res;
+ UString fileName = VolName;
+ fileName += L'.';
+ fileName += res;
+ fileName += VolExt;
+ COutFileStream *streamSpec = new COutFileStream;
+ CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
+ if(!streamSpec->Create(fileName, false))
+ return ::GetLastError();
+ *volumeStream = streamLoc.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
+{
+ COM_TRY_BEGIN
+ return Callback->CryptoGetTextPassword2(passwordIsDefined, password);
+ COM_TRY_END
+}
diff --git a/CPP/7zip/UI/Common/UpdateCallback.h b/CPP/7zip/UI/Common/UpdateCallback.h
new file mode 100755
index 00000000..8b14a9dc
--- /dev/null
+++ b/CPP/7zip/UI/Common/UpdateCallback.h
@@ -0,0 +1,70 @@
+// UpdateCallback.h
+
+#ifndef __UPDATECALLBACK_H
+#define __UPDATECALLBACK_H
+
+#include "Common/MyCom.h"
+#include "Common/String.h"
+
+#include "../../IPassword.h"
+
+#include "../Common/UpdatePair.h"
+#include "../Common/UpdateProduce.h"
+
+struct IUpdateCallbackUI
+{
+ virtual HRESULT SetTotal(UInt64 size) = 0;
+ virtual HRESULT SetCompleted(const UInt64 *completeValue) = 0;
+ virtual HRESULT CheckBreak() = 0;
+ virtual HRESULT Finilize() = 0;
+ virtual HRESULT GetStream(const wchar_t *name, bool isAnti) = 0;
+ virtual HRESULT OpenFileError(const wchar_t *name, DWORD systemError) = 0;
+ virtual HRESULT SetOperationResult(Int32 operationResult) = 0;
+ virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) = 0;
+ virtual HRESULT CloseProgress() { return S_OK; };
+};
+
+class CArchiveUpdateCallback:
+ public IArchiveUpdateCallback2,
+ public ICryptoGetTextPassword2,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP2(IArchiveUpdateCallback2,
+ ICryptoGetTextPassword2)
+
+ // IProgress
+ STDMETHOD(SetTotal)(UInt64 size);
+ STDMETHOD(SetCompleted)(const UInt64 *completeValue);
+
+ // IUpdateCallback
+ STDMETHOD(EnumProperties)(IEnumSTATPROPSTG **enumerator);
+ STDMETHOD(GetUpdateItemInfo)(UInt32 index,
+ Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive);
+ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream);
+ STDMETHOD(SetOperationResult)(Int32 operationResult);
+
+ STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size);
+ STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream);
+
+ STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password);
+
+public:
+ CRecordVector<UInt64> VolumesSizes;
+ UString VolName;
+ UString VolExt;
+
+ IUpdateCallbackUI *Callback;
+
+ UString DirPrefix;
+ bool StdInMode;
+ const CObjectVector<CDirItem> *DirItems;
+ const CObjectVector<CArchiveItem> *ArchiveItems;
+ const CObjectVector<CUpdatePair2> *UpdatePairs;
+ CMyComPtr<IInArchive> Archive;
+
+ CArchiveUpdateCallback();
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/UpdatePair.cpp b/CPP/7zip/UI/Common/UpdatePair.cpp
new file mode 100755
index 00000000..dd51646f
--- /dev/null
+++ b/CPP/7zip/UI/Common/UpdatePair.cpp
@@ -0,0 +1,175 @@
+// UpdatePair.cpp
+
+#include "StdAfx.h"
+
+#include <time.h>
+
+#include "Common/Defs.h"
+#include "Windows/Time.h"
+
+#include "UpdatePair.h"
+#include "SortUtils.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+static int MyCompareTime(NFileTimeType::EEnum fileTimeType,
+ const FILETIME &time1, const FILETIME &time2)
+{
+ switch(fileTimeType)
+ {
+ case NFileTimeType::kWindows:
+ return ::CompareFileTime(&time1, &time2);
+ case NFileTimeType::kUnix:
+ {
+ UInt32 unixTime1, unixTime2;
+ if (!FileTimeToUnixTime(time1, unixTime1))
+ {
+ unixTime1 = 0;
+ // throw 4191614;
+ }
+ if (!FileTimeToUnixTime(time2, unixTime2))
+ {
+ unixTime2 = 0;
+ // throw 4191615;
+ }
+ return MyCompare(unixTime1, unixTime2);
+ }
+ case NFileTimeType::kDOS:
+ {
+ UInt32 dosTime1, dosTime2;
+ FileTimeToDosTime(time1, dosTime1);
+ FileTimeToDosTime(time2, dosTime2);
+ /*
+ if (!FileTimeToDosTime(time1, dosTime1))
+ throw 4191616;
+ if (!FileTimeToDosTime(time2, dosTime2))
+ throw 4191617;
+ */
+ return MyCompare(dosTime1, dosTime2);
+ }
+ }
+ throw 4191618;
+}
+
+static const wchar_t *kDuplicateFileNameMessage = L"Duplicate filename:";
+
+/*
+static const char *kNotCensoredCollisionMessaged = "Internal file name collision:\n";
+static const char *kSameTimeChangedSizeCollisionMessaged =
+ "Collision between files with same date/time and different sizes:\n";
+*/
+
+static inline int MyFileNameCompare(const UString &s1, const UString &s2)
+{
+ return
+ #ifdef _WIN32
+ s1.CompareNoCase(s2);
+ #else
+ s1.Compare(s2);
+ #endif
+}
+
+static void TestDuplicateString(const UStringVector &strings, const CIntVector &indices)
+{
+ for(int i = 0; i + 1 < indices.Size(); i++)
+ if (MyFileNameCompare(strings[indices[i]], strings[indices[i + 1]]) == 0)
+ {
+ UString message = kDuplicateFileNameMessage;
+ message += L"\n";
+ message += strings[indices[i]];
+ message += L"\n";
+ message += strings[indices[i + 1]];
+ throw message;
+ }
+}
+
+void GetUpdatePairInfoList(
+ const CObjectVector<CDirItem> &dirItems,
+ const CObjectVector<CArchiveItem> &archiveItems,
+ NFileTimeType::EEnum fileTimeType,
+ CObjectVector<CUpdatePair> &updatePairs)
+{
+ CIntVector dirIndices, archiveIndices;
+ UStringVector dirNames, archiveNames;
+
+ int numDirItems = dirItems.Size();
+ int i;
+ for(i = 0; i < numDirItems; i++)
+ dirNames.Add(dirItems[i].Name);
+ SortStringsToIndices(dirNames, dirIndices);
+ TestDuplicateString(dirNames, dirIndices);
+
+ int numArchiveItems = archiveItems.Size();
+ for(i = 0; i < numArchiveItems; i++)
+ archiveNames.Add(archiveItems[i].Name);
+ SortStringsToIndices(archiveNames, archiveIndices);
+ TestDuplicateString(archiveNames, archiveIndices);
+
+ int dirItemIndex = 0, archiveItemIndex = 0;
+ CUpdatePair pair;
+ while(dirItemIndex < numDirItems && archiveItemIndex < numArchiveItems)
+ {
+ int dirItemIndex2 = dirIndices[dirItemIndex],
+ archiveItemIndex2 = archiveIndices[archiveItemIndex];
+ const CDirItem &dirItem = dirItems[dirItemIndex2];
+ const CArchiveItem &archiveItem = archiveItems[archiveItemIndex2];
+ int compareResult = MyFileNameCompare(dirItem.Name, archiveItem.Name);
+ if (compareResult < 0)
+ {
+ pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
+ pair.DirItemIndex = dirItemIndex2;
+ dirItemIndex++;
+ }
+ else if (compareResult > 0)
+ {
+ pair.State = archiveItem.Censored ?
+ NUpdateArchive::NPairState::kOnlyInArchive: NUpdateArchive::NPairState::kNotMasked;
+ pair.ArchiveItemIndex = archiveItemIndex2;
+ archiveItemIndex++;
+ }
+ else
+ {
+ if (!archiveItem.Censored)
+ throw 1082022;; // TTString(kNotCensoredCollisionMessaged + dirItem.Name);
+ pair.DirItemIndex = dirItemIndex2;
+ pair.ArchiveItemIndex = archiveItemIndex2;
+ switch (MyCompareTime(fileTimeType, dirItem.LastWriteTime, archiveItem.LastWriteTime))
+ {
+ case -1:
+ pair.State = NUpdateArchive::NPairState::kNewInArchive;
+ break;
+ case 1:
+ pair.State = NUpdateArchive::NPairState::kOldInArchive;
+ break;
+ default:
+ if (archiveItem.SizeIsDefined)
+ if (dirItem.Size != archiveItem.Size)
+ // throw 1082034; // kSameTimeChangedSizeCollisionMessaged;
+ pair.State = NUpdateArchive::NPairState::kUnknowNewerFiles;
+ else
+ pair.State = NUpdateArchive::NPairState::kSameFiles;
+ else
+ pair.State = NUpdateArchive::NPairState::kUnknowNewerFiles;
+ }
+ dirItemIndex++;
+ archiveItemIndex++;
+ }
+ updatePairs.Add(pair);
+ }
+ for(;dirItemIndex < numDirItems; dirItemIndex++)
+ {
+ pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
+ pair.DirItemIndex = dirIndices[dirItemIndex];
+ updatePairs.Add(pair);
+ }
+ for(;archiveItemIndex < numArchiveItems; archiveItemIndex++)
+ {
+ int archiveItemIndex2 = archiveIndices[archiveItemIndex];
+ const CArchiveItem &archiveItem = archiveItems[archiveItemIndex2];
+ pair.State = archiveItem.Censored ?
+ NUpdateArchive::NPairState::kOnlyInArchive: NUpdateArchive::NPairState::kNotMasked;
+ pair.ArchiveItemIndex = archiveItemIndex2;
+ updatePairs.Add(pair);
+ }
+}
diff --git a/CPP/7zip/UI/Common/UpdatePair.h b/CPP/7zip/UI/Common/UpdatePair.h
new file mode 100755
index 00000000..f50a23f8
--- /dev/null
+++ b/CPP/7zip/UI/Common/UpdatePair.h
@@ -0,0 +1,24 @@
+// UpdatePair.h
+
+#ifndef __UPDATE_PAIR_H
+#define __UPDATE_PAIR_H
+
+#include "DirItem.h"
+#include "UpdateAction.h"
+
+#include "../../Archive/IArchive.h"
+
+struct CUpdatePair
+{
+ NUpdateArchive::NPairState::EEnum State;
+ int ArchiveItemIndex;
+ int DirItemIndex;
+};
+
+void GetUpdatePairInfoList(
+ const CObjectVector<CDirItem> &dirItems,
+ const CObjectVector<CArchiveItem> &archiveItems,
+ NFileTimeType::EEnum fileTimeType,
+ CObjectVector<CUpdatePair> &updatePairs);
+
+#endif
diff --git a/CPP/7zip/UI/Common/UpdateProduce.cpp b/CPP/7zip/UI/Common/UpdateProduce.cpp
new file mode 100755
index 00000000..992bbeec
--- /dev/null
+++ b/CPP/7zip/UI/Common/UpdateProduce.cpp
@@ -0,0 +1,63 @@
+// UpdateProduce.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateProduce.h"
+
+using namespace NUpdateArchive;
+
+static const char *kUpdateActionSetCollision =
+ "Internal collision in update action set";
+
+void UpdateProduce(
+ const CObjectVector<CUpdatePair> &updatePairs,
+ const NUpdateArchive::CActionSet &actionSet,
+ CObjectVector<CUpdatePair2> &operationChain)
+{
+ for(int i = 0; i < updatePairs.Size(); i++)
+ {
+ // CUpdateArchiveRange aRange;
+ const CUpdatePair &pair = updatePairs[i];
+
+ CUpdatePair2 pair2;
+ pair2.IsAnti = false;
+ pair2.ArchiveItemIndex = pair.ArchiveItemIndex;
+ pair2.DirItemIndex = pair.DirItemIndex;
+ pair2.ExistInArchive = (pair.State != NPairState::kOnlyOnDisk);
+ pair2.ExistOnDisk = (pair.State != NPairState::kOnlyInArchive);
+ switch(actionSet.StateActions[pair.State])
+ {
+ case NPairAction::kIgnore:
+ /*
+ if (pair.State != NPairState::kOnlyOnDisk)
+ IgnoreArchiveItem(m_ArchiveItems[pair.ArchiveItemIndex]);
+ // cout << "deleting";
+ */
+ break;
+ case NPairAction::kCopy:
+ {
+ if (pair.State == NPairState::kOnlyOnDisk)
+ throw kUpdateActionSetCollision;
+ pair2.NewData = pair2.NewProperties = false;
+ operationChain.Add(pair2);
+ break;
+ }
+ case NPairAction::kCompress:
+ {
+ if (pair.State == NPairState::kOnlyInArchive ||
+ pair.State == NPairState::kNotMasked)
+ throw kUpdateActionSetCollision;
+ pair2.NewData = pair2.NewProperties = true;
+ operationChain.Add(pair2);
+ break;
+ }
+ case NPairAction::kCompressAsAnti:
+ {
+ pair2.IsAnti = true;
+ pair2.NewData = pair2.NewProperties = true;
+ operationChain.Add(pair2);
+ break;
+ }
+ }
+ }
+}
diff --git a/CPP/7zip/UI/Common/UpdateProduce.h b/CPP/7zip/UI/Common/UpdateProduce.h
new file mode 100755
index 00000000..8f58dab9
--- /dev/null
+++ b/CPP/7zip/UI/Common/UpdateProduce.h
@@ -0,0 +1,31 @@
+// UpdateProduce.h
+
+#ifndef __UPDATE_PRODUCE_H
+#define __UPDATE_PRODUCE_H
+
+#include "UpdatePair.h"
+
+struct CUpdatePair2
+{
+ // bool OperationIsCompress;
+ bool NewData;
+ bool NewProperties;
+
+ bool ExistInArchive;
+ bool ExistOnDisk;
+ bool IsAnti;
+ int ArchiveItemIndex;
+ int DirItemIndex;
+
+ bool NewNameIsDefined;
+ UString NewName;
+
+ CUpdatePair2(): NewNameIsDefined(false) {}
+};
+
+void UpdateProduce(
+ const CObjectVector<CUpdatePair> &updatePairs,
+ const NUpdateArchive::CActionSet &actionSet,
+ CObjectVector<CUpdatePair2> &operationChain);
+
+#endif
diff --git a/CPP/7zip/UI/Common/WorkDir.cpp b/CPP/7zip/UI/Common/WorkDir.cpp
new file mode 100755
index 00000000..8db6f4f1
--- /dev/null
+++ b/CPP/7zip/UI/Common/WorkDir.cpp
@@ -0,0 +1,64 @@
+// WorkDir.cpp
+
+#include "StdAfx.h"
+
+#include "WorkDir.h"
+
+#include "Common/StringConvert.h"
+#include "Common/Wildcard.h"
+
+#include "Windows/FileName.h"
+#include "Windows/FileDir.h"
+
+static inline UINT GetCurrentCodePage()
+ { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; }
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+
+UString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const UString &path)
+{
+ NWorkDir::NMode::EEnum mode = workDirInfo.Mode;
+ if (workDirInfo.ForRemovableOnly)
+ {
+ mode = NWorkDir::NMode::kCurrent;
+ UString prefix = path.Left(3);
+ if (prefix[1] == L':' && prefix[2] == L'\\')
+ {
+ UINT driveType = GetDriveType(GetSystemString(prefix, GetCurrentCodePage()));
+ if (driveType == DRIVE_CDROM || driveType == DRIVE_REMOVABLE)
+ mode = workDirInfo.Mode;
+ }
+ /*
+ CParsedPath parsedPath;
+ parsedPath.ParsePath(archiveName);
+ UINT driveType = GetDriveType(parsedPath.Prefix);
+ if ((driveType != DRIVE_CDROM) && (driveType != DRIVE_REMOVABLE))
+ mode = NZipSettings::NWorkDir::NMode::kCurrent;
+ */
+ }
+ switch(mode)
+ {
+ case NWorkDir::NMode::kCurrent:
+ {
+ return ExtractDirPrefixFromPath(path);
+ }
+ case NWorkDir::NMode::kSpecified:
+ {
+ UString tempDir = workDirInfo.Path;
+ NormalizeDirPathPrefix(tempDir);
+ return tempDir;
+ }
+ default:
+ {
+ UString tempDir;
+ if(!NFile::NDirectory::MyGetTempPath(tempDir))
+ throw 141717;
+ return tempDir;
+ }
+ }
+}
+
+
+
diff --git a/CPP/7zip/UI/Common/WorkDir.h b/CPP/7zip/UI/Common/WorkDir.h
new file mode 100755
index 00000000..0643d67a
--- /dev/null
+++ b/CPP/7zip/UI/Common/WorkDir.h
@@ -0,0 +1,10 @@
+// WorkDir.h
+
+#ifndef __WORKDIR_H
+#define __WORKDIR_H
+
+#include "ZipRegistry.h"
+
+UString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const UString &path);
+
+#endif
diff --git a/CPP/7zip/UI/Common/ZipRegistry.cpp b/CPP/7zip/UI/Common/ZipRegistry.cpp
new file mode 100755
index 00000000..e449d6b4
--- /dev/null
+++ b/CPP/7zip/UI/Common/ZipRegistry.cpp
@@ -0,0 +1,420 @@
+// ZipRegistry.cpp
+
+#include "StdAfx.h"
+
+#include "ZipRegistry.h"
+
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/Synchronization.h"
+#include "Windows/Registry.h"
+
+#include "Windows/FileDir.h"
+
+using namespace NWindows;
+using namespace NRegistry;
+
+static const TCHAR *kCUBasePath = TEXT("Software\\7-ZIP");
+
+// static const TCHAR *kArchiversKeyName = TEXT("Archivers");
+
+static NSynchronization::CCriticalSection g_RegistryOperationsCriticalSection;
+
+//////////////////////
+// ExtractionInfo
+
+static const TCHAR *kExtractionKeyName = TEXT("Extraction");
+
+static const TCHAR *kExtractionPathHistoryKeyName = TEXT("PathHistory");
+static const TCHAR *kExtractionExtractModeValueName = TEXT("ExtarctMode");
+static const TCHAR *kExtractionOverwriteModeValueName = TEXT("OverwriteMode");
+static const TCHAR *kExtractionShowPasswordValueName = TEXT("ShowPassword");
+
+static CSysString GetKeyPath(const CSysString &path)
+{
+ return CSysString(kCUBasePath) + CSysString('\\') + CSysString(path);
+}
+
+void SaveExtractionInfo(const NExtract::CInfo &info)
+{
+ NSynchronization::CCriticalSectionLock lock(g_RegistryOperationsCriticalSection);
+ CKey extractionKey;
+ extractionKey.Create(HKEY_CURRENT_USER, GetKeyPath(kExtractionKeyName));
+ extractionKey.RecurseDeleteKey(kExtractionPathHistoryKeyName);
+ {
+ CKey pathHistoryKey;
+ pathHistoryKey.Create(extractionKey, kExtractionPathHistoryKeyName);
+ for(int i = 0; i < info.Paths.Size(); i++)
+ {
+ wchar_t numberString[16];
+ ConvertUInt64ToString(i, numberString);
+ pathHistoryKey.SetValue(numberString, info.Paths[i]);
+ }
+ }
+ extractionKey.SetValue(kExtractionExtractModeValueName, UInt32(info.PathMode));
+ extractionKey.SetValue(kExtractionOverwriteModeValueName, UInt32(info.OverwriteMode));
+ extractionKey.SetValue(kExtractionShowPasswordValueName, info.ShowPassword);
+}
+
+void ReadExtractionInfo(NExtract::CInfo &info)
+{
+ info.Paths.Clear();
+ info.PathMode = NExtract::NPathMode::kCurrentPathnames;
+ info.OverwriteMode = NExtract::NOverwriteMode::kAskBefore;
+ info.ShowPassword = false;
+
+ NSynchronization::CCriticalSectionLock lock(g_RegistryOperationsCriticalSection);
+ CKey extractionKey;
+ if(extractionKey.Open(HKEY_CURRENT_USER, GetKeyPath(kExtractionKeyName), KEY_READ) != ERROR_SUCCESS)
+ return;
+
+ {
+ CKey pathHistoryKey;
+ if(pathHistoryKey.Open(extractionKey, kExtractionPathHistoryKeyName, KEY_READ) ==
+ ERROR_SUCCESS)
+ {
+ for (;;)
+ {
+ wchar_t numberString[16];
+ ConvertUInt64ToString(info.Paths.Size(), numberString);
+ UString path;
+ if (pathHistoryKey.QueryValue(numberString, path) != ERROR_SUCCESS)
+ break;
+ info.Paths.Add(path);
+ }
+ }
+ }
+ UInt32 extractModeIndex;
+ if (extractionKey.QueryValue(kExtractionExtractModeValueName, extractModeIndex) == ERROR_SUCCESS)
+ {
+ switch (extractModeIndex)
+ {
+ case NExtract::NPathMode::kFullPathnames:
+ case NExtract::NPathMode::kCurrentPathnames:
+ case NExtract::NPathMode::kNoPathnames:
+ info.PathMode = NExtract::NPathMode::EEnum(extractModeIndex);
+ break;
+ }
+ }
+ UInt32 overwriteModeIndex;
+ if (extractionKey.QueryValue(kExtractionOverwriteModeValueName, overwriteModeIndex) == ERROR_SUCCESS)
+ {
+ switch (overwriteModeIndex)
+ {
+ case NExtract::NOverwriteMode::kAskBefore:
+ case NExtract::NOverwriteMode::kWithoutPrompt:
+ case NExtract::NOverwriteMode::kSkipExisting:
+ case NExtract::NOverwriteMode::kAutoRename:
+ case NExtract::NOverwriteMode::kAutoRenameExisting:
+ info.OverwriteMode = NExtract::NOverwriteMode::EEnum(overwriteModeIndex);
+ break;
+ }
+ }
+ if (extractionKey.QueryValue(kExtractionShowPasswordValueName,
+ info.ShowPassword) != ERROR_SUCCESS)
+ info.ShowPassword = false;
+}
+
+///////////////////////////////////
+// CompressionInfo
+
+static const TCHAR *kCompressionKeyName = TEXT("Compression");
+
+static const TCHAR *kCompressionHistoryArchivesKeyName = TEXT("ArcHistory");
+static const TCHAR *kCompressionLevelValueName = TEXT("Level");
+static const TCHAR *kCompressionLastFormatValueName = TEXT("Archiver");
+static const TCHAR *kCompressionShowPasswordValueName = TEXT("ShowPassword");
+static const TCHAR *kCompressionEncryptHeadersValueName = TEXT("EncryptHeaders");
+// static const TCHAR *kCompressionMaximizeValueName = TEXT("Maximize");
+
+static const TCHAR *kCompressionOptionsKeyName = TEXT("Options");
+static const TCHAR *kSolid = TEXT("Solid");
+static const TCHAR *kMultiThread = TEXT("Multithread");
+
+static const WCHAR *kCompressionOptions = L"Options";
+static const TCHAR *kCompressionLevel = TEXT("Level");
+static const WCHAR *kCompressionMethod = L"Method";
+static const WCHAR *kEncryptionMethod = L"EncryptionMethod";
+static const TCHAR *kCompressionDictionary = TEXT("Dictionary");
+static const TCHAR *kCompressionOrder = TEXT("Order");
+
+
+static void SetRegString(CKey &key, const WCHAR *name, const UString &value)
+{
+ if (value.IsEmpty())
+ key.DeleteValue(name);
+ else
+ key.SetValue(name, value);
+}
+
+static void SetRegUInt32(CKey &key, const TCHAR *name, UInt32 value)
+{
+ if (value == (UInt32)-1)
+ key.DeleteValue(name);
+ else
+ key.SetValue(name, value);
+}
+
+static void GetRegString(CKey &key, const WCHAR *name, UString &value)
+{
+ if (key.QueryValue(name, value) != ERROR_SUCCESS)
+ value.Empty();
+}
+
+static void GetRegUInt32(CKey &key, const TCHAR *name, UInt32 &value)
+{
+ if (key.QueryValue(name, value) != ERROR_SUCCESS)
+ value = UInt32(-1);
+}
+
+void SaveCompressionInfo(const NCompression::CInfo &info)
+{
+ NSynchronization::CCriticalSectionLock lock(g_RegistryOperationsCriticalSection);
+
+ CKey compressionKey;
+ compressionKey.Create(HKEY_CURRENT_USER, GetKeyPath(kCompressionKeyName));
+ compressionKey.RecurseDeleteKey(kCompressionHistoryArchivesKeyName);
+ {
+ CKey historyArchivesKey;
+ historyArchivesKey.Create(compressionKey, kCompressionHistoryArchivesKeyName);
+ for(int i = 0; i < info.HistoryArchives.Size(); i++)
+ {
+ wchar_t numberString[16];
+ ConvertUInt64ToString(i, numberString);
+ historyArchivesKey.SetValue(numberString, info.HistoryArchives[i]);
+ }
+ }
+
+ compressionKey.SetValue(kSolid, info.Solid);
+ compressionKey.SetValue(kMultiThread, info.MultiThread);
+ compressionKey.RecurseDeleteKey(kCompressionOptionsKeyName);
+ {
+ CKey optionsKey;
+ optionsKey.Create(compressionKey, kCompressionOptionsKeyName);
+ for(int i = 0; i < info.FormatOptionsVector.Size(); i++)
+ {
+ const NCompression::CFormatOptions &fo = info.FormatOptionsVector[i];
+ CKey formatKey;
+ formatKey.Create(optionsKey, fo.FormatID);
+
+ SetRegString(formatKey, kCompressionOptions, fo.Options);
+ SetRegString(formatKey, kCompressionMethod, fo.Method);
+ SetRegString(formatKey, kEncryptionMethod, fo.EncryptionMethod);
+
+ SetRegUInt32(formatKey, kCompressionLevel, fo.Level);
+ SetRegUInt32(formatKey, kCompressionDictionary, fo.Dictionary);
+ SetRegUInt32(formatKey, kCompressionOrder, fo.Order);
+ }
+ }
+
+ compressionKey.SetValue(kCompressionLevelValueName, UInt32(info.Level));
+ compressionKey.SetValue(kCompressionLastFormatValueName,
+ GetSystemString(info.ArchiveType));
+
+ compressionKey.SetValue(kCompressionShowPasswordValueName, info.ShowPassword);
+ compressionKey.SetValue(kCompressionEncryptHeadersValueName, info.EncryptHeaders);
+ // compressionKey.SetValue(kCompressionMaximizeValueName, info.Maximize);
+}
+
+static bool IsMultiProcessor()
+{
+ SYSTEM_INFO systemInfo;
+ GetSystemInfo(&systemInfo);
+ return systemInfo.dwNumberOfProcessors > 1;
+}
+
+void ReadCompressionInfo(NCompression::CInfo &info)
+{
+ info.HistoryArchives.Clear();
+
+ info.Solid = true;
+ info.MultiThread = IsMultiProcessor();
+ info.FormatOptionsVector.Clear();
+
+ info.Level = 5;
+ info.ArchiveType = L"7z";
+ // definedStatus.Maximize = false;
+ info.ShowPassword = false;
+ info.EncryptHeaders = false;
+
+ NSynchronization::CCriticalSectionLock lock(g_RegistryOperationsCriticalSection);
+ CKey compressionKey;
+
+ if(compressionKey.Open(HKEY_CURRENT_USER,
+ GetKeyPath(kCompressionKeyName), KEY_READ) != ERROR_SUCCESS)
+ return;
+
+ {
+ CKey historyArchivesKey;
+ if(historyArchivesKey.Open(compressionKey, kCompressionHistoryArchivesKeyName, KEY_READ) ==
+ ERROR_SUCCESS)
+ {
+ for (;;)
+ {
+ wchar_t numberString[16];
+ ConvertUInt64ToString(info.HistoryArchives.Size(), numberString);
+ UString path;
+ if (historyArchivesKey.QueryValue(numberString, path) != ERROR_SUCCESS)
+ break;
+ info.HistoryArchives.Add(path);
+ }
+ }
+ }
+
+
+ bool solid = false;
+ if (compressionKey.QueryValue(kSolid, solid) == ERROR_SUCCESS)
+ info.Solid = solid;
+ bool multiThread = false;
+ if (compressionKey.QueryValue(kMultiThread, multiThread) == ERROR_SUCCESS)
+ info.MultiThread = multiThread;
+
+ {
+ CKey optionsKey;
+ if(optionsKey.Open(compressionKey, kCompressionOptionsKeyName, KEY_READ) ==
+ ERROR_SUCCESS)
+ {
+ CSysStringVector formatIDs;
+ optionsKey.EnumKeys(formatIDs);
+ for(int i = 0; i < formatIDs.Size(); i++)
+ {
+ CKey formatKey;
+ NCompression::CFormatOptions fo;
+ fo.FormatID = formatIDs[i];
+ if(formatKey.Open(optionsKey, fo.FormatID, KEY_READ) == ERROR_SUCCESS)
+ {
+ GetRegString(formatKey, kCompressionOptions, fo.Options);
+ GetRegString(formatKey, kCompressionMethod, fo.Method);
+ GetRegString(formatKey, kEncryptionMethod, fo.EncryptionMethod);
+
+ GetRegUInt32(formatKey, kCompressionLevel, fo.Level);
+ GetRegUInt32(formatKey, kCompressionDictionary, fo.Dictionary);
+ GetRegUInt32(formatKey, kCompressionOrder, fo.Order);
+
+ info.FormatOptionsVector.Add(fo);
+ }
+
+ }
+ }
+ }
+
+ UInt32 level;
+ if (compressionKey.QueryValue(kCompressionLevelValueName, level) == ERROR_SUCCESS)
+ info.Level = level;
+ CSysString archiveType;
+ if (compressionKey.QueryValue(kCompressionLastFormatValueName, archiveType) == ERROR_SUCCESS)
+ info.ArchiveType = GetUnicodeString(archiveType);
+ if (compressionKey.QueryValue(kCompressionShowPasswordValueName,
+ info.ShowPassword) != ERROR_SUCCESS)
+ info.ShowPassword = false;
+ if (compressionKey.QueryValue(kCompressionEncryptHeadersValueName,
+ info.EncryptHeaders) != ERROR_SUCCESS)
+ info.EncryptHeaders = false;
+ /*
+ if (compressionKey.QueryValue(kCompressionLevelValueName, info.Maximize) == ERROR_SUCCESS)
+ definedStatus.Maximize = true;
+ */
+}
+
+
+///////////////////////////////////
+// WorkDirInfo
+
+static const TCHAR *kOptionsInfoKeyName = TEXT("Options");
+
+static const TCHAR *kWorkDirTypeValueName = TEXT("WorkDirType");
+static const WCHAR *kWorkDirPathValueName = L"WorkDirPath";
+static const TCHAR *kTempRemovableOnlyValueName = TEXT("TempRemovableOnly");
+static const TCHAR *kCascadedMenuValueName = TEXT("CascadedMenu");
+static const TCHAR *kContextMenuValueName = TEXT("ContextMenu");
+
+void SaveWorkDirInfo(const NWorkDir::CInfo &info)
+{
+ NSynchronization::CCriticalSectionLock lock(g_RegistryOperationsCriticalSection);
+ CKey optionsKey;
+ optionsKey.Create(HKEY_CURRENT_USER, GetKeyPath(kOptionsInfoKeyName));
+ optionsKey.SetValue(kWorkDirTypeValueName, UInt32(info.Mode));
+ optionsKey.SetValue(kWorkDirPathValueName, info.Path);
+ optionsKey.SetValue(kTempRemovableOnlyValueName, info.ForRemovableOnly);
+}
+
+void ReadWorkDirInfo(NWorkDir::CInfo &info)
+{
+ info.SetDefault();
+
+ NSynchronization::CCriticalSectionLock lock(g_RegistryOperationsCriticalSection);
+ CKey optionsKey;
+ if(optionsKey.Open(HKEY_CURRENT_USER, GetKeyPath(kOptionsInfoKeyName), KEY_READ) != ERROR_SUCCESS)
+ return;
+
+ UInt32 dirType;
+ if (optionsKey.QueryValue(kWorkDirTypeValueName, dirType) != ERROR_SUCCESS)
+ return;
+ switch (dirType)
+ {
+ case NWorkDir::NMode::kSystem:
+ case NWorkDir::NMode::kCurrent:
+ case NWorkDir::NMode::kSpecified:
+ info.Mode = NWorkDir::NMode::EEnum(dirType);
+ }
+ UString sysWorkDir;
+ if (optionsKey.QueryValue(kWorkDirPathValueName, sysWorkDir) != ERROR_SUCCESS)
+ {
+ info.Path.Empty();
+ if (info.Mode == NWorkDir::NMode::kSpecified)
+ info.Mode = NWorkDir::NMode::kSystem;
+ }
+ info.Path = GetUnicodeString(sysWorkDir);
+ if (optionsKey.QueryValue(kTempRemovableOnlyValueName, info.ForRemovableOnly) != ERROR_SUCCESS)
+ info.SetForRemovableOnlyDefault();
+}
+
+static void SaveOption(const TCHAR *value, bool enabled)
+{
+ NSynchronization::CCriticalSectionLock lock(g_RegistryOperationsCriticalSection);
+ CKey optionsKey;
+ optionsKey.Create(HKEY_CURRENT_USER, GetKeyPath(kOptionsInfoKeyName));
+ optionsKey.SetValue(value, enabled);
+}
+
+static bool ReadOption(const TCHAR *value, bool defaultValue)
+{
+ NSynchronization::CCriticalSectionLock lock(g_RegistryOperationsCriticalSection);
+ CKey optionsKey;
+ if(optionsKey.Open(HKEY_CURRENT_USER, GetKeyPath(kOptionsInfoKeyName), KEY_READ) != ERROR_SUCCESS)
+ return defaultValue;
+ bool enabled;
+ if (optionsKey.QueryValue(value, enabled) != ERROR_SUCCESS)
+ return defaultValue;
+ return enabled;
+}
+
+void SaveCascadedMenu(bool show)
+ { SaveOption(kCascadedMenuValueName, show); }
+bool ReadCascadedMenu()
+ { return ReadOption(kCascadedMenuValueName, true); }
+
+
+static void SaveValue(const TCHAR *value, UInt32 valueToWrite)
+{
+ NSynchronization::CCriticalSectionLock lock(g_RegistryOperationsCriticalSection);
+ CKey optionsKey;
+ optionsKey.Create(HKEY_CURRENT_USER, GetKeyPath(kOptionsInfoKeyName));
+ optionsKey.SetValue(value, valueToWrite);
+}
+
+static bool ReadValue(const TCHAR *value, UInt32 &result)
+{
+ NSynchronization::CCriticalSectionLock lock(g_RegistryOperationsCriticalSection);
+ CKey optionsKey;
+ if(optionsKey.Open(HKEY_CURRENT_USER, GetKeyPath(kOptionsInfoKeyName), KEY_READ) != ERROR_SUCCESS)
+ return false;
+ return (optionsKey.QueryValue(value, result) == ERROR_SUCCESS);
+}
+
+void SaveContextMenuStatus(UInt32 value)
+ { SaveValue(kContextMenuValueName, value); }
+
+bool ReadContextMenuStatus(UInt32 &value)
+ { return ReadValue(kContextMenuValueName, value); }
diff --git a/CPP/7zip/UI/Common/ZipRegistry.h b/CPP/7zip/UI/Common/ZipRegistry.h
new file mode 100755
index 00000000..30e7ee44
--- /dev/null
+++ b/CPP/7zip/UI/Common/ZipRegistry.h
@@ -0,0 +1,99 @@
+// ZipRegistry.h
+
+#ifndef __ZIPREGISTRY_H
+#define __ZIPREGISTRY_H
+
+#include "Common/String.h"
+#include "Common/Types.h"
+#include "ExtractMode.h"
+
+namespace NExtract
+{
+ struct CInfo
+ {
+ NPathMode::EEnum PathMode;
+ NOverwriteMode::EEnum OverwriteMode;
+ UStringVector Paths;
+ bool ShowPassword;
+ };
+}
+
+namespace NCompression {
+
+ struct CFormatOptions
+ {
+ CSysString FormatID;
+ UString Options;
+ UString Method;
+ UString EncryptionMethod;
+ UInt32 Level;
+ UInt32 Dictionary;
+ UInt32 Order;
+ void ResetForLevelChange()
+ {
+ Level = Dictionary = Order = UInt32(-1);
+ Method.Empty();
+ // EncryptionMethod.Empty();
+ // Options.Empty();
+ }
+ CFormatOptions() { ResetForLevelChange(); }
+ };
+
+ struct CInfo
+ {
+ UStringVector HistoryArchives;
+ // bool LevelIsDefined;
+ UInt32 Level;
+ UString ArchiveType;
+
+ bool Solid;
+ bool MultiThread;
+ CObjectVector<CFormatOptions> FormatOptionsVector;
+
+ bool ShowPassword;
+ bool EncryptHeaders;
+ };
+}
+
+namespace NWorkDir{
+
+ namespace NMode
+ {
+ enum EEnum
+ {
+ kSystem,
+ kCurrent,
+ kSpecified
+ };
+ }
+ struct CInfo
+ {
+ NMode::EEnum Mode;
+ UString Path;
+ bool ForRemovableOnly;
+ void SetForRemovableOnlyDefault() { ForRemovableOnly = true; }
+ void SetDefault()
+ {
+ Mode = NMode::kSystem;
+ Path.Empty();
+ SetForRemovableOnlyDefault();
+ }
+ };
+}
+
+void SaveExtractionInfo(const NExtract::CInfo &info);
+void ReadExtractionInfo(NExtract::CInfo &info);
+
+void SaveCompressionInfo(const NCompression::CInfo &info);
+void ReadCompressionInfo(NCompression::CInfo &info);
+
+void SaveWorkDirInfo(const NWorkDir::CInfo &info);
+void ReadWorkDirInfo(NWorkDir::CInfo &info);
+
+void SaveCascadedMenu(bool enabled);
+bool ReadCascadedMenu();
+
+void SaveContextMenuStatus(UInt32 value);
+bool ReadContextMenuStatus(UInt32 &value);
+
+#endif