From be3b47d0d504a3409ce66bd77bb8c0acff87c4f5 Mon Sep 17 00:00:00 2001 From: kh1 Date: Thu, 15 Mar 2012 14:53:47 +0100 Subject: Reorganize the tree, have better ifw.pri. Shadow build support. Change-Id: I01fb12537f863ed0744979973c7e4153889cc5cb Reviewed-by: Tim Jenssen --- .../win/CPP/7zip/UI/Common/ArchiveCommandLine.cpp | 1042 ++++++++++++++++++++ .../win/CPP/7zip/UI/Common/ArchiveCommandLine.h | 111 +++ .../CPP/7zip/UI/Common/ArchiveExtractCallback.cpp | 488 +++++++++ .../CPP/7zip/UI/Common/ArchiveExtractCallback.h | 143 +++ .../7zip/win/CPP/7zip/UI/Common/ArchiveName.cpp | 54 + src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.h | 10 + .../win/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp | 133 +++ .../win/CPP/7zip/UI/Common/ArchiveOpenCallback.h | 103 ++ src/libs/7zip/win/CPP/7zip/UI/Common/Bench.cpp | 1028 +++++++++++++++++++ src/libs/7zip/win/CPP/7zip/UI/Common/Bench.h | 42 + .../7zip/win/CPP/7zip/UI/Common/CompressCall.cpp | 246 +++++ .../7zip/win/CPP/7zip/UI/Common/CompressCall.h | 24 + .../7zip/win/CPP/7zip/UI/Common/CompressCall2.cpp | 178 ++++ .../7zip/win/CPP/7zip/UI/Common/DefaultName.cpp | 35 + src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.h | 11 + src/libs/7zip/win/CPP/7zip/UI/Common/DirItem.h | 69 ++ .../7zip/win/CPP/7zip/UI/Common/EnumDirItems.cpp | 361 +++++++ .../7zip/win/CPP/7zip/UI/Common/EnumDirItems.h | 25 + src/libs/7zip/win/CPP/7zip/UI/Common/ExitCode.h | 27 + src/libs/7zip/win/CPP/7zip/UI/Common/Extract.cpp | 263 +++++ src/libs/7zip/win/CPP/7zip/UI/Common/Extract.h | 76 ++ src/libs/7zip/win/CPP/7zip/UI/Common/ExtractMode.h | 31 + .../win/CPP/7zip/UI/Common/ExtractingFilePath.cpp | 142 +++ .../win/CPP/7zip/UI/Common/ExtractingFilePath.h | 13 + .../win/CPP/7zip/UI/Common/IFileExtractCallback.h | 46 + .../7zip/win/CPP/7zip/UI/Common/LoadCodecs.cpp | 681 +++++++++++++ src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.h | 235 +++++ .../7zip/win/CPP/7zip/UI/Common/OpenArchive.cpp | 536 ++++++++++ src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.h | 87 ++ .../7zip/win/CPP/7zip/UI/Common/PropIDUtils.cpp | 120 +++ src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.h | 12 + src/libs/7zip/win/CPP/7zip/UI/Common/Property.h | 14 + .../7zip/win/CPP/7zip/UI/Common/SetProperties.cpp | 79 ++ .../7zip/win/CPP/7zip/UI/Common/SetProperties.h | 10 + src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.cpp | 22 + src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.h | 10 + src/libs/7zip/win/CPP/7zip/UI/Common/StdAfx.h | 9 + src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.cpp | 22 + src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.h | 16 + src/libs/7zip/win/CPP/7zip/UI/Common/Update.cpp | 910 +++++++++++++++++ src/libs/7zip/win/CPP/7zip/UI/Common/Update.h | 175 ++++ .../7zip/win/CPP/7zip/UI/Common/UpdateAction.cpp | 64 ++ .../7zip/win/CPP/7zip/UI/Common/UpdateAction.h | 57 ++ .../7zip/win/CPP/7zip/UI/Common/UpdateCallback.cpp | 249 +++++ .../7zip/win/CPP/7zip/UI/Common/UpdateCallback.h | 74 ++ .../7zip/win/CPP/7zip/UI/Common/UpdatePair.cpp | 158 +++ src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.h | 25 + .../7zip/win/CPP/7zip/UI/Common/UpdateProduce.cpp | 58 ++ .../7zip/win/CPP/7zip/UI/Common/UpdateProduce.h | 35 + src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.cpp | 59 ++ src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.h | 10 + .../7zip/win/CPP/7zip/UI/Common/ZipRegistry.cpp | 293 ++++++ src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.h | 105 ++ 53 files changed, 8826 insertions(+) create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/Bench.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/Bench.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall2.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/DirItem.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/ExitCode.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/Extract.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/Extract.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/ExtractMode.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/IFileExtractCallback.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/Property.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/StdAfx.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/Update.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/Update.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.h create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.cpp create mode 100644 src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.h (limited to 'src/libs/7zip/win/CPP/7zip/UI/Common') diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.cpp new file mode 100644 index 000000000..8ae2e15e8 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.cpp @@ -0,0 +1,1042 @@ +// ArchiveCommandLine.cpp + +#include "StdAfx.h" + +#ifdef _WIN32 +#ifndef UNDER_CE +#include +#endif +#endif +#include + +#include "Common/ListFileUtils.h" +#include "Common/StringConvert.h" +#include "Common/StringToInt.h" + +#include "Windows/FileDir.h" +#include "Windows/FileName.h" +#ifdef _WIN32 +#include "Windows/FileMapping.h" +#include "Windows/Synchronization.h" +#endif + +#include "ArchiveCommandLine.h" +#include "EnumDirItems.h" +#include "SortUtils.h" +#include "Update.h" +#include "UpdateAction.h" + +extern bool g_CaseSensitive; + +#ifdef UNDER_CE + +#define MY_IS_TERMINAL(x) false; + +#else + +#if _MSC_VER >= 1400 +#define MY_isatty_fileno(x) _isatty(_fileno(x)) +#else +#define MY_isatty_fileno(x) isatty(fileno(x)) +#endif + +#define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0); + +#endif + +using namespace NCommandLineParser; +using namespace NWindows; +using namespace NFile; + +int g_CodePage = -1; + +namespace NKey { +enum Enum +{ + kHelp1 = 0, + kHelp2, + kHelp3, + kDisableHeaders, + kDisablePercents, + kArchiveType, + kYes, + #ifndef _NO_CRYPTO + kPassword, + #endif + kProperty, + kOutputDir, + kWorkingDir, + kInclude, + kExclude, + kArInclude, + kArExclude, + kNoArName, + kUpdate, + kVolume, + kRecursed, + kSfx, + kStdIn, + kStdOut, + kOverwrite, + kEmail, + kShowDialog, + kLargePages, + kListfileCharSet, + kConsoleCharSet, + kTechMode, + kShareForWrite, + kCaseSensitive, + kCalcCrc +}; + +} + + +static const wchar_t kRecursedIDChar = 'R'; +static const wchar_t *kRecursedPostCharSet = L"0-"; + +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 <@|!>ame must be +static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!>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[] = + { + { 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 }, + #ifndef _NO_CRYPTO + { L"P", NSwitchType::kUnLimitedPostString, false, 0 }, + #endif + { 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"SCC", NSwitchType::kUnLimitedPostString, false, 0}, + { L"SLT", NSwitchType::kSimple, false }, + { L"SSW", NSwitchType::kSimple, false }, + { L"SSC", NSwitchType::kPostChar, false, 0, 0, L"-" }, + { L"SCRC", NSwitchType::kSimple, false } + }; + +static const CCommandForm g_CommandForms[] = +{ + { L"A", false }, + { L"U", false }, + { L"D", false }, + { L"T", false }, + { L"E", false }, + { L"X", false }, + { L"L", false }, + { L"B", false }, + { L"I", false } +}; + +static const int kNumCommandForms = sizeof(g_CommandForms) / sizeof(g_CommandForms[0]); + +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 *kCannotFindListFile = "Cannot find listfile"; +static const char *kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch."; +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 const char *kEmptyFilePath = "Empty file path"; + +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 void AddNameToCensor(NWildcard::CCensor &wildcardCensor, + const UString &name, bool include, NRecursedType::EEnum type) +{ + bool recursed = false; + + switch (type) + { + case NRecursedType::kWildCardOnlyRecursed: + recursed = DoesNameContainWildCard(name); + break; + case NRecursedType::kRecursed: + recursed = true; + break; + } + wildcardCensor.AddItem(include, name, recursed); +} + +static void AddToCensorFromListFile(NWildcard::CCensor &wildcardCensor, + LPCWSTR fileName, bool include, NRecursedType::EEnum type, UINT codePage) +{ + UStringVector names; + if (!NFind::DoesFileExist(fileName)) + throw kCannotFindListFile; + if (!ReadNamesFromListFile(fileName, names, codePage)) + throw kIncorrectListFile; + for (int i = 0; i < names.Size(); i++) + AddNameToCensor(wildcardCensor, names[i], include, type); +} + +static void AddToCensorFromNonSwitchesStrings( + int startIndex, + NWildcard::CCensor &wildcardCensor, + const UStringVector &nonSwitchStrings, NRecursedType::EEnum type, + bool thereAreSwitchIncludes, UINT codePage) +{ + if (nonSwitchStrings.Size() == startIndex && (!thereAreSwitchIncludes)) + AddNameToCensor(wildcardCensor, kUniversalWildcard, true, type); + for (int i = startIndex; i < nonSwitchStrings.Size(); i++) + { + const UString &s = nonSwitchStrings[i]; + if (s.IsEmpty()) + throw kEmptyFilePath; + if (s[0] == kFileListID) + AddToCensorFromListFile(wildcardCensor, s.Mid(1), true, type, codePage); + else + AddNameToCensor(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, GetSystemString(mappingName)) != 0) + ThrowException("Can not open mapping"); + LPVOID data = fileMapping.Map(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') + { + AddNameToCensor(wildcardCensor, name, include, commonRecursedType); + name.Empty(); + } + else + name += c; + } + if (!name.IsEmpty()) + ThrowException("data error"); + } + catch(...) + { + UnmapViewOfFile(data); + throw; + } + UnmapViewOfFile(data); + } + + { + NSynchronization::CManualResetEvent event; + if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(eventName)) == S_OK) + 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) + AddNameToCensor(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 fi; + if (fi.Find(prefix + name)) + name = fi.Name; +} + +static void ConvertToLongNames(const UString &prefix, CObjectVector &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.UserArchivePath = 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 &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); + } + } +} + +CArchiveCommandLineParser::CArchiveCommandLineParser(): + parser(sizeof(kSwitchForms) / sizeof(kSwitchForms[0])) {} + +void CArchiveCommandLineParser::Parse1(const UStringVector &commandStrings, + CArchiveCommandLineOptions &options) +{ + try + { + parser.ParseStrings(kSwitchForms, commandStrings); + } + catch(...) + { + ThrowUserErrorException(); + } + + options.IsInTerminal = MY_IS_TERMINAL(stdin); + options.IsStdOutTerminal = MY_IS_TERMINAL(stdout); + options.IsStdErrTerminal = MY_IS_TERMINAL(stderr); + options.StdInMode = parser[NKey::kStdIn].ThereIs; + 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 int FindCharset(const NCommandLineParser::CParser &parser, int keyIndex, int defaultVal) +{ + if (!parser[keyIndex].ThereIs) + return defaultVal; + + UString name = parser[keyIndex].PostStrings.Back(); + name.MakeUpper(); + int i; + for (i = 0; i < sizeof(g_CodePagePairs) / sizeof(g_CodePagePairs[0]); i++) + { + const CCodePagePair &pair = g_CodePagePairs[i]; + if (name.Compare(pair.Name) == 0) + return pair.CodePage; + } + if (i == sizeof(g_CodePagePairs) / sizeof(g_CodePagePairs[0])) + ThrowUserErrorException(); + return -1; +} + +static bool ConvertStringToUInt32(const wchar_t *s, UInt32 &v) +{ + const wchar_t *end; + UInt64 number = ConvertStringToUInt64(s, &end); + if (*end != 0) + return false; + if (number > (UInt32)0xFFFFFFFF) + return false; + v = (UInt32)number; + return true; +} + +void EnumerateDirItemsAndSort(NWildcard::CCensor &wildcardCensor, + UStringVector &sortedPaths, + UStringVector &sortedFullPaths) +{ + UStringVector paths; + { + CDirItems dirItems; + { + UStringVector errorPaths; + CRecordVector errorCodes; + HRESULT res = EnumerateItems(wildcardCensor, dirItems, NULL, errorPaths, errorCodes); + if (res != S_OK || errorPaths.Size() > 0) + throw "cannot find archive"; + } + for (int i = 0; i < dirItems.Items.Size(); i++) + { + const CDirItem &dirItem = dirItems.Items[i]; + if (!dirItem.IsDir()) + paths.Add(dirItems.GetPhyPath(i)); + } + } + + if (paths.Size() == 0) + throw "there is no such archive"; + + UStringVector fullPaths; + + int i; + for (i = 0; i < paths.Size(); i++) + { + UString fullPath; + NFile::NDirectory::MyGetFullPathName(paths[i], fullPath); + fullPaths.Add(fullPath); + } + CIntVector indices; + SortFileNames(fullPaths, indices); + sortedPaths.Reserve(indices.Size()); + sortedFullPaths.Reserve(indices.Size()); + for (i = 0; i < indices.Size(); i++) + { + int index = indices[i]; + sortedPaths.Add(paths[index]); + sortedFullPaths.Add(fullPaths[index]); + } +} + +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; + options.CalcCrc = parser[NKey::kCalcCrc].ThereIs; + + if (parser[NKey::kCaseSensitive].ThereIs) + g_CaseSensitive = (parser[NKey::kCaseSensitive].PostCharIndex < 0); + + NRecursedType::EEnum recursedType; + if (parser[NKey::kRecursed].ThereIs) + recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex); + else + recursedType = NRecursedType::kNonRecursed; + + g_CodePage = FindCharset(parser, NKey::kConsoleCharSet, -1); + UINT codePage = FindCharset(parser, NKey::kListfileCharSet, CP_UTF8); + + 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 && + options.Command.CommandType != NCommandType::kBenchmark && + options.Command.CommandType != NCommandType::kInfo; + + bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); + bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList; + + if (isExtractOrList && options.StdInMode) + thereIsArchiveName = false; + + if (thereIsArchiveName) + { + if (curCommandIndex >= numNonSwitchStrings) + ThrowUserErrorException(); + options.ArchiveName = nonSwitchStrings[curCommandIndex++]; + if (options.ArchiveName.IsEmpty()) + ThrowUserErrorException(); + } + + AddToCensorFromNonSwitchesStrings( + curCommandIndex, options.WildcardCensor, + nonSwitchStrings, recursedType, thereAreSwitchIncludes, codePage); + + options.YesToAll = parser[NKey::kYes].ThereIs; + + + #ifndef _NO_CRYPTO + options.PasswordEnabled = parser[NKey::kPassword].ThereIs; + if (options.PasswordEnabled) + options.Password = parser[NKey::kPassword].PostStrings[0]; + #endif + + options.ShowDialog = parser[NKey::kShowDialog].ThereIs; + + if (parser[NKey::kArchiveType].ThereIs) + options.ArcType = parser[NKey::kArchiveType].PostStrings[0]; + + if (isExtractOrList) + { + 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) + AddNameToCensor(archiveWildcardCensor, options.ArchiveName, true, NRecursedType::kNonRecursed); + + #ifdef _WIN32 + ConvertToLongNames(archiveWildcardCensor); + #endif + + archiveWildcardCensor.ExtendExclude(); + + if (options.StdInMode) + { + UString arcName = parser[NKey::kStdIn].PostStrings.Front(); + options.ArchivePathsSorted.Add(arcName); + options.ArchivePathsFullSorted.Add(arcName); + } + else + { + EnumerateDirItemsAndSort(archiveWildcardCensor, + options.ArchivePathsSorted, + options.ArchivePathsFullSorted); + } + + 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; + + SetAddCommandOptions(options.Command.CommandType, parser, updateOptions); + + SetMethodOptions(parser, updateOptions.MethodMode.Properties); + + if (parser[NKey::kShareForWrite].ThereIs) + updateOptions.OpenShareForWrite = true; + + 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 if (options.Command.CommandType == NCommandType::kBenchmark) + { + options.NumThreads = (UInt32)-1; + options.DictionarySize = (UInt32)-1; + options.NumIterations = 1; + if (curCommandIndex < numNonSwitchStrings) + { + if (!ConvertStringToUInt32(nonSwitchStrings[curCommandIndex++], options.NumIterations)) + ThrowUserErrorException(); + } + for (int i = 0; i < parser[NKey::kProperty].PostStrings.Size(); i++) + { + UString postString = parser[NKey::kProperty].PostStrings[i]; + postString.MakeUpper(); + if (postString.Length() < 2) + ThrowUserErrorException(); + if (postString[0] == 'D') + { + int pos = 1; + if (postString[pos] == '=') + pos++; + UInt32 logSize; + if (!ConvertStringToUInt32((const wchar_t *)postString + pos, logSize)) + ThrowUserErrorException(); + if (logSize > 31) + ThrowUserErrorException(); + options.DictionarySize = 1 << logSize; + } + else if (postString[0] == 'M' && postString[1] == 'T' ) + { + int pos = 2; + if (postString[pos] == '=') + pos++; + if (postString[pos] != 0) + if (!ConvertStringToUInt32((const wchar_t *)postString + pos, options.NumThreads)) + ThrowUserErrorException(); + } + else if (postString[0] == 'M' && postString[1] == '=' ) + { + int pos = 2; + if (postString[pos] != 0) + options.Method = postString.Mid(2); + } + else + ThrowUserErrorException(); + } + } + else if (options.Command.CommandType == NCommandType::kInfo) + { + } + else + ThrowUserErrorException(); + options.WildcardCensor.ExtendExclude(); +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.h new file mode 100644 index 000000000..e8f601df4 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.h @@ -0,0 +1,111 @@ +// ArchiveCommandLine.h + +#ifndef __ARCHIVE_COMMAND_LINE_H +#define __ARCHIVE_COMMAND_LINE_H + +#include "Common/CommandLineParser.h" +#include "Common/Wildcard.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, + kBenchmark, + kInfo +};} + +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; + + #ifndef _NO_CRYPTO + bool PasswordEnabled; + UString Password; + #endif + + bool TechMode; + // Extract + bool CalcCrc; + bool AppendName; + UString OutputDir; + NExtract::NOverwriteMode::EEnum OverwriteMode; + UStringVector ArchivePathsSorted; + UStringVector ArchivePathsFullSorted; + CObjectVector ExtractProperties; + + CUpdateOptions UpdateOptions; + UString ArcType; + bool EnablePercents; + + // Benchmark + UInt32 NumIterations; + UInt32 NumThreads; + UInt32 DictionarySize; + UString Method; + + + CArchiveCommandLineOptions(): StdInMode(false), StdOutMode(false) {}; +}; + +class CArchiveCommandLineParser +{ + NCommandLineParser::CParser parser; +public: + CArchiveCommandLineParser(); + void Parse1(const UStringVector &commandStrings, CArchiveCommandLineOptions &options); + void Parse2(CArchiveCommandLineOptions &options); +}; + +void EnumerateDirItemsAndSort(NWildcard::CCensor &wildcardCensor, + UStringVector &sortedPaths, + UStringVector &sortedFullPaths); + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp new file mode 100644 index 000000000..4c0cc90b5 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp @@ -0,0 +1,488 @@ +// ArchiveExtractCallback.cpp + +#include "StdAfx.h" + +#include "Common/ComTry.h" +#include "Common/Wildcard.h" + +#include "Windows/FileDir.h" +#include "Windows/FileFind.h" +#include "Windows/PropVariant.h" +#include "Windows/PropVariantConversions.h" + +#include "../../Common/FilePathAutoRename.h" + +#include "../Common/ExtractingFilePath.h" + +#include "ArchiveExtractCallback.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( + const NWildcard::CCensorNode *wildcardCensor, + const CArc *arc, + IFolderArchiveExtractCallback *extractCallback2, + bool stdOutMode, bool testMode, bool crcMode, + const UString &directoryPath, + const UStringVector &removePathParts, + UInt64 packSize) +{ + _wildcardCensor = wildcardCensor; + + _stdOutMode = stdOutMode; + _testMode = testMode; + _crcMode = crcMode; + _unpTotal = 1; + _packTotal = packSize; + + _extractCallback2 = extractCallback2; + _compressProgress.Release(); + _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress); + + LocalProgressSpec->Init(extractCallback2, true); + LocalProgressSpec->SendProgress = false; + + + _removePathParts = removePathParts; + _arc = arc; + _directoryPath = directoryPath; + NFile::NName::NormalizeDirPathPrefix(_directoryPath); +} + +STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size) +{ + COM_TRY_BEGIN + _unpTotal = size; + if (!_multiArchives && _extractCallback2) + return _extractCallback2->SetTotal(size); + return S_OK; + COM_TRY_END +} + +static void NormalizeVals(UInt64 &v1, UInt64 &v2) +{ + const UInt64 kMax = (UInt64)1 << 31; + while (v1 > kMax) + { + v1 >>= 1; + v2 >>= 1; + } +} + +static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal) +{ + NormalizeVals(packTotal, unpTotal); + NormalizeVals(unpCur, unpTotal); + if (unpTotal == 0) + unpTotal = 1; + return unpCur * packTotal / unpTotal; +} + +STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue) +{ + COM_TRY_BEGIN + if (!_extractCallback2) + return S_OK; + + if (_multiArchives) + { + if (completeValue != NULL) + { + UInt64 packCur = LocalProgressSpec->InSize + MyMultDiv64(*completeValue, _unpTotal, _packTotal); + return _extractCallback2->SetCompleted(&packCur); + } + } + return _extractCallback2->SetCompleted(completeValue); + COM_TRY_END +} + +STDMETHODIMP CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + COM_TRY_BEGIN + return _localProgress->SetRatioInfo(inSize, outSize); + 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); + } +} + +HRESULT CArchiveExtractCallback::GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined) +{ + filetimeIsDefined = false; + NCOM::CPropVariant prop; + RINOK(_arc->Archive->GetProperty(index, propID, &prop)); + if (prop.vt == VT_FILETIME) + { + filetime = prop.filetime; + filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0); + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +HRESULT CArchiveExtractCallback::GetUnpackSize() +{ + NCOM::CPropVariant prop; + RINOK(_arc->Archive->GetProperty(_index, kpidSize, &prop)); + _curSizeDefined = (prop.vt != VT_EMPTY); + if (_curSizeDefined) + _curSize = ConvertPropVariantToUInt64(prop); + return S_OK; +} + +STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) +{ + COM_TRY_BEGIN + _crcStream.Release(); + *outStream = 0; + _outFileStream.Release(); + + _encrypted = false; + _isSplit = false; + _curSize = 0; + _curSizeDefined = false; + _index = index; + + UString fullPath; + + IInArchive *archive = _arc->Archive; + RINOK(_arc->GetItemPath(index, fullPath)); + RINOK(IsArchiveItemFolder(archive, index, _fi.IsDir)); + + _filePath = fullPath; + + { + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidPosition, &prop)); + if (prop.vt != VT_EMPTY) + { + if (prop.vt != VT_UI8) + return E_FAIL; + _position = prop.uhVal.QuadPart; + _isSplit = true; + } + } + + RINOK(GetArchiveItemBoolProp(archive, index, kpidEncrypted, _encrypted)); + + RINOK(GetUnpackSize()); + + if (_wildcardCensor) + { + if (!_wildcardCensor->CheckPath(fullPath, !_fi.IsDir)) + return S_OK; + } + + if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) + { + if (_stdOutMode) + { + CMyComPtr outStreamLoc = new CStdOutFileStream; + *outStream = outStreamLoc.Detach(); + return S_OK; + } + + { + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidAttrib, &prop)); + if (prop.vt == VT_UI4) + { + _fi.Attrib = prop.ulVal; + _fi.AttribDefined = true; + } + else if (prop.vt == VT_EMPTY) + _fi.AttribDefined = false; + else + return E_FAIL; + } + + RINOK(GetTime(index, kpidCTime, _fi.CTime, _fi.CTimeDefined)); + RINOK(GetTime(index, kpidATime, _fi.ATime, _fi.ATimeDefined)); + RINOK(GetTime(index, kpidMTime, _fi.MTime, _fi.MTimeDefined)); + + bool isAnti = false; + RINOK(_arc->IsItemAnti(index, isAnti)); + + UStringVector pathParts; + SplitPathToParts(fullPath, pathParts); + + if (pathParts.IsEmpty()) + return E_FAIL; + int numRemovePathParts = 0; + switch(_pathMode) + { + case NExtract::NPathMode::kFullPathnames: + break; + case NExtract::NPathMode::kCurrentPathnames: + { + 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; + break; + } + case NExtract::NPathMode::kNoPathnames: + { + numRemovePathParts = pathParts.Size() - 1; + break; + } + } + pathParts.Delete(0, numRemovePathParts); + MakeCorrectPath(pathParts); + UString processedPath = MakePathNameFromParts(pathParts); + if (!isAnti) + { + if (!_fi.IsDir) + { + if (!pathParts.IsEmpty()) + pathParts.DeleteBack(); + } + + if (!pathParts.IsEmpty()) + { + UString fullPathNew; + CreateComplexDirectory(pathParts, fullPathNew); + if (_fi.IsDir) + NFile::NDirectory::SetDirTime(fullPathNew, + (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL, + (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL, + (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); + } + } + + + UString fullProcessedPath = _directoryPath + processedPath; + + if (_fi.IsDir) + { + _diskFilePath = fullProcessedPath; + if (isAnti) + NFile::NDirectory::MyRemoveDirectory(_diskFilePath); + return S_OK; + } + + if (!_isSplit) + { + NFile::NFind::CFileInfoW fileInfo; + if (fileInfo.Find(fullProcessedPath)) + { + switch(_overwriteMode) + { + case NExtract::NOverwriteMode::kSkipExisting: + return S_OK; + case NExtract::NOverwriteMode::kAskBefore: + { + Int32 overwiteResult; + RINOK(_extractCallback2->AskOverwrite( + fullProcessedPath, &fileInfo.MTime, &fileInfo.Size, fullPath, + _fi.MTimeDefined ? &_fi.MTime : NULL, + _curSizeDefined ? &_curSize : 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: + return E_FAIL; + } + } + } + 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 S_OK; + // return E_FAIL; + } + } + } + if (!isAnti) + { + _outFileStreamSpec = new COutFileStream; + CMyComPtr outStreamLoc(_outFileStreamSpec); + if (!_outFileStreamSpec->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; + } + if (_crcMode) + { + _crcStreamSpec = new COutStreamWithCRC; + _crcStream = _crcStreamSpec; + CMyComPtr crcStream = _crcStreamSpec; + _crcStreamSpec->SetStream(*outStream); + if (*outStream) + (*outStream)->Release(); + *outStream = crcStream.Detach(); + _crcStreamSpec->Init(true); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode) +{ + COM_TRY_BEGIN + _extractMode = false; + switch (askExtractMode) + { + case NArchive::NExtract::NAskMode::kExtract: + if (_testMode) + askExtractMode = NArchive::NExtract::NAskMode::kTest; + else + _extractMode = true; + break; + }; + return _extractCallback2->PrepareOperation(_filePath, _fi.IsDir, + 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 (_crcStream) + { + CrcSum += _crcStreamSpec->GetCRC(); + _curSize = _crcStreamSpec->GetSize(); + _curSizeDefined = true; + _crcStream.Release(); + } + if (_outFileStream) + { + _outFileStreamSpec->SetTime( + (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL, + (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL, + (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); + _curSize = _outFileStreamSpec->ProcessedSize; + _curSizeDefined = true; + RINOK(_outFileStreamSpec->Close()); + _outFileStream.Release(); + } + if (!_curSizeDefined) + GetUnpackSize(); + if (_curSizeDefined) + UnpackSize += _curSize; + if (_fi.IsDir) + NumFolders++; + else + NumFiles++; + + if (_extractMode && _fi.AttribDefined) + NFile::NDirectory::MySetFileAttributes(_diskFilePath, _fi.Attrib); + 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 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/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.h new file mode 100644 index 000000000..367e4b07d --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.h @@ -0,0 +1,143 @@ +// ArchiveExtractCallback.h + +#ifndef __ARCHIVE_EXTRACT_CALLBACK_H +#define __ARCHIVE_EXTRACT_CALLBACK_H + +#include "Common/MyCom.h" +#include "Common/Wildcard.h" + +#include "../../IPassword.h" + +#include "../../Common/FileStreams.h" +#include "../../Common/ProgressUtils.h" + +#include "../../Archive/IArchive.h" + +#include "../../Archive/Common/OutStreamWithCRC.h" + +#include "ExtractMode.h" +#include "IFileExtractCallback.h" +#include "OpenArchive.h" + +class CArchiveExtractCallback: + public IArchiveExtractCallback, + // public IArchiveVolumeExtractCallback, + public ICryptoGetTextPassword, + public ICompressProgressInfo, + public CMyUnknownImp +{ + const CArc *_arc; + const NWildcard::CCensorNode *_wildcardCensor; + CMyComPtr _extractCallback2; + CMyComPtr _compressProgress; + CMyComPtr _cryptoGetTextPassword; + UString _directoryPath; + NExtract::NPathMode::EEnum _pathMode; + NExtract::NOverwriteMode::EEnum _overwriteMode; + + UString _diskFilePath; + UString _filePath; + UInt64 _position; + bool _isSplit; + + bool _extractMode; + + bool WriteCTime; + bool WriteATime; + bool WriteMTime; + + bool _encrypted; + + struct CProcessedFileInfo + { + FILETIME CTime; + FILETIME ATime; + FILETIME MTime; + UInt32 Attrib; + + bool CTimeDefined; + bool ATimeDefined; + bool MTimeDefined; + bool AttribDefined; + + bool IsDir; + } _fi; + + UInt32 _index; + UInt64 _curSize; + bool _curSizeDefined; + COutFileStream *_outFileStreamSpec; + CMyComPtr _outFileStream; + + COutStreamWithCRC *_crcStreamSpec; + CMyComPtr _crcStream; + + UStringVector _removePathParts; + + bool _stdOutMode; + bool _testMode; + bool _crcMode; + bool _multiArchives; + + CMyComPtr _localProgress; + UInt64 _packTotal; + UInt64 _unpTotal; + + void CreateComplexDirectory(const UStringVector &dirPathParts, UString &fullPath); + HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined); + HRESULT GetUnpackSize(); + +public: + + CLocalProgress *LocalProgressSpec; + + UInt64 NumFolders; + UInt64 NumFiles; + UInt64 UnpackSize; + UInt32 CrcSum; + + MY_UNKNOWN_IMP2(ICryptoGetTextPassword, ICompressProgressInfo) + // COM_INTERFACE_ENTRY(IArchiveVolumeExtractCallback) + + INTERFACE_IArchiveExtractCallback(;) + + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); + + // IArchiveVolumeExtractCallback + // STDMETHOD(GetInStream)(const wchar_t *name, ISequentialInStream **inStream); + + STDMETHOD(CryptoGetTextPassword)(BSTR *password); + + CArchiveExtractCallback(): + WriteCTime(true), + WriteATime(true), + WriteMTime(true), + _multiArchives(false) + { + LocalProgressSpec = new CLocalProgress(); + _localProgress = LocalProgressSpec; + } + + void InitForMulti(bool multiArchives, + NExtract::NPathMode::EEnum pathMode, + NExtract::NOverwriteMode::EEnum overwriteMode) + { + _multiArchives = multiArchives; + _pathMode = pathMode; + _overwriteMode = overwriteMode; + NumFolders = NumFiles = UnpackSize = 0; + CrcSum = 0; + } + + void Init( + const NWildcard::CCensorNode *wildcardCensor, + const CArc *arc, + IFolderArchiveExtractCallback *extractCallback2, + bool stdOutMode, bool testMode, bool crcMode, + const UString &directoryPath, + const UStringVector &removePathParts, + UInt64 packSize); + +}; + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.cpp new file mode 100644 index 000000000..c3684def8 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.cpp @@ -0,0 +1,54 @@ +// ArchiveName.cpp + +#include "StdAfx.h" + +#include "Windows/FileDir.h" +#include "Windows/FileFind.h" + +#include "ExtractingFilePath.h" + +using namespace NWindows; + +static UString CreateArchiveName2(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] == WCHAR_PATH_SEPARATOR) + { + dirPrefix.Delete(dirPrefix.Length() - 1); + NFile::NFind::CFileInfoW fileInfo; + if (fileInfo.Find(dirPrefix)) + resultName = fileInfo.Name; + } + } + } + else + { + NFile::NFind::CFileInfoW fileInfo; + if (!fileInfo.Find(srcName)) + // return resultName; + return srcName; + resultName = fileInfo.Name; + if (!fileInfo.IsDir() && !keepName) + { + int dotPos = resultName.ReverseFind('.'); + if (dotPos > 0) + { + UString archiveName2 = resultName.Left(dotPos); + if (archiveName2.ReverseFind('.') < 0) + resultName = archiveName2; + } + } + } + return resultName; +} + +UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName) +{ + return GetCorrectFsPath(CreateArchiveName2(srcName, fromPrev, keepName)); +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.h new file mode 100644 index 000000000..9513fb2ba --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.h @@ -0,0 +1,10 @@ +// ArchiveName.h + +#ifndef __ARCHIVENAME_H +#define __ARCHIVENAME_H + +#include "Common/MyString.h" + +UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName); + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp new file mode 100644 index 000000000..e7e617131 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp @@ -0,0 +1,133 @@ +// ArchiveOpenCallback.cpp + +#include "StdAfx.h" + +#include "Common/StringConvert.h" +#include "Common/ComTry.h" + +#include "Windows/PropVariant.h" + +#include "../../Common/FileStreams.h" + +#include "ArchiveOpenCallback.h" + +using namespace NWindows; + +STDMETHODIMP COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes) +{ + COM_TRY_BEGIN + if (ReOpenCallback) + return ReOpenCallback->SetTotal(files, bytes); + if (!Callback) + return S_OK; + return Callback->Open_SetTotal(files, bytes); + COM_TRY_END +} + +STDMETHODIMP COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes) +{ + COM_TRY_BEGIN + if (ReOpenCallback) + return ReOpenCallback->SetCompleted(files, bytes); + if (!Callback) + return S_OK; + return Callback->Open_SetCompleted(files, bytes); + COM_TRY_END +} + +STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + if (_subArchiveMode) + switch(propID) + { + case kpidName: prop = _subArchiveName; break; + } + else + switch(propID) + { + case kpidName: prop = _fileInfo.Name; break; + case kpidIsDir: prop = _fileInfo.IsDir(); break; + case kpidSize: prop = _fileInfo.Size; break; + case kpidAttrib: prop = (UInt32)_fileInfo.Attrib; break; + case kpidCTime: prop = _fileInfo.CTime; break; + case kpidATime: prop = _fileInfo.ATime; break; + case kpidMTime: prop = _fileInfo.MTime; break; + } + prop.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 OpenCallbackRef; + ~CInFileStreamVol() + { + if (OpenCallbackRef) + { + 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; + if (Callback) + { + RINOK(Callback->Open_CheckBreak()); + } + *inStream = NULL; + UString fullPath = _folderPrefix + name; + if (!_fileInfo.Find(fullPath)) + return S_FALSE; + if (_fileInfo.IsDir()) + return S_FALSE; + CInFileStreamVol *inFile = new CInFileStreamVol; + CMyComPtr inStreamTemp = inFile; + if (!inFile->Open(fullPath)) + return ::GetLastError(); + *inStream = inStreamTemp.Detach(); + inFile->Name = name; + inFile->OpenCallbackImp = this; + inFile->OpenCallbackRef = this; + FileNames.Add(name); + TotalSize += _fileInfo.Size; + return S_OK; + COM_TRY_END +} + +#ifndef _NO_CRYPTO +STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password) +{ + COM_TRY_BEGIN + if (ReOpenCallback) + { + CMyComPtr getTextPassword; + ReOpenCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); + if (getTextPassword) + return getTextPassword->CryptoGetTextPassword(password); + } + if (!Callback) + return E_NOTIMPL; + return Callback->Open_CryptoGetTextPassword(password); + COM_TRY_END +} +#endif + diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.h new file mode 100644 index 000000000..c6651e8f9 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.h @@ -0,0 +1,103 @@ +// ArchiveOpenCallback.h + +#ifndef __ARCHIVE_OPEN_CALLBACK_H +#define __ARCHIVE_OPEN_CALLBACK_H + +#include "Common/MyCom.h" +#include "Common/MyString.h" + +#include "Windows/FileFind.h" + +#ifndef _NO_CRYPTO +#include "../../IPassword.h" +#endif +#include "../../Archive/IArchive.h" + +#ifdef _NO_CRYPTO + +#define INTERFACE_IOpenCallbackUI_Crypto(x) + +#else + +#define INTERFACE_IOpenCallbackUI_Crypto(x) \ + virtual HRESULT Open_CryptoGetTextPassword(BSTR *password) x; \ + virtual HRESULT Open_GetPasswordIfAny(UString &password) x; \ + virtual bool Open_WasPasswordAsked() x; \ + virtual void Open_ClearPasswordWasAskedFlag() x; \ + +#endif + +#define INTERFACE_IOpenCallbackUI(x) \ + virtual HRESULT Open_CheckBreak() x; \ + virtual HRESULT Open_SetTotal(const UInt64 *files, const UInt64 *bytes) x; \ + virtual HRESULT Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) x; \ + INTERFACE_IOpenCallbackUI_Crypto(x) + +struct IOpenCallbackUI +{ + INTERFACE_IOpenCallbackUI(=0) +}; + +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 + + INTERFACE_IArchiveOpenCallback(;) + INTERFACE_IArchiveOpenVolumeCallback(;) + + #ifndef _NO_CRYPTO + STDMETHOD(CryptoGetTextPassword)(BSTR *password); + #endif + + STDMETHOD(SetSubArchiveName(const wchar_t *name)) + { + _subArchiveMode = true; + _subArchiveName = name; + TotalSize = 0; + return S_OK; + } + +private: + UString _folderPrefix; + NWindows::NFile::NFind::CFileInfoW _fileInfo; + bool _subArchiveMode; + UString _subArchiveName; +public: + UStringVector FileNames; + IOpenCallbackUI *Callback; + CMyComPtr ReOpenCallback; + UInt64 TotalSize; + + COpenCallbackImp(): Callback(NULL) {} + void Init(const UString &folderPrefix, const UString &fileName) + { + _folderPrefix = folderPrefix; + if (!_fileInfo.Find(_folderPrefix + fileName)) + throw 1; + FileNames.Clear(); + _subArchiveMode = false; + TotalSize = 0; + } + int FindName(const UString &name); +}; + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/Bench.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/Bench.cpp new file mode 100644 index 000000000..282f405f1 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/Bench.cpp @@ -0,0 +1,1028 @@ +// Bench.cpp + +#include "StdAfx.h" + +#include "Bench.h" + +#ifndef _WIN32 +#define USE_POSIX_TIME +#define USE_POSIX_TIME2 +#endif + +#ifdef USE_POSIX_TIME +#include +#ifdef USE_POSIX_TIME2 +#include +#endif +#endif + +#ifdef _WIN32 +#define USE_ALLOCA +#endif + +#ifdef USE_ALLOCA +#ifdef _WIN32 +#include +#else +#include +#endif +#endif + +#include "../../../../C/7zCrc.h" +#include "../../../../C/Alloc.h" + +#ifndef _7ZIP_ST +#include "../../../Windows/Synchronization.h" +#include "../../../Windows/Thread.h" +#endif + +#include "../../../Windows/PropVariant.h" + +static const UInt32 kUncompressMinBlockSize = +#ifdef UNDER_CE +1 << 24; +#else +1 << 26; +#endif + +static const UInt32 kCrcBlockSize = +#ifdef UNDER_CE +1 << 25; +#else +1 << 30; +#endif + +static const UInt32 kAdditionalSize = (1 << 16); +static const UInt32 kCompressedAdditionalSize = (1 << 10); +static const UInt32 kMaxLzmaPropSize = 5; + +class CBaseRandomGenerator +{ + UInt32 A1; + UInt32 A2; +public: + CBaseRandomGenerator() { Init(); } + void Init() { A1 = 362436069; A2 = 521288629;} + UInt32 GetRnd() + { + return + ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) + + ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) ); + } +}; + +class CBenchBuffer +{ +public: + size_t BufferSize; + Byte *Buffer; + CBenchBuffer(): Buffer(0) {} + virtual ~CBenchBuffer() { Free(); } + void Free() + { + ::MidFree(Buffer); + Buffer = 0; + } + bool Alloc(size_t bufferSize) + { + if (Buffer != 0 && BufferSize == bufferSize) + return true; + Free(); + Buffer = (Byte *)::MidAlloc(bufferSize); + BufferSize = bufferSize; + return (Buffer != 0); + } +}; + +class CBenchRandomGenerator: public CBenchBuffer +{ + CBaseRandomGenerator *RG; +public: + void Set(CBaseRandomGenerator *rg) { RG = rg; } + UInt32 GetVal(UInt32 &res, int numBits) + { + UInt32 val = res & (((UInt32)1 << numBits) - 1); + res >>= numBits; + return val; + } + UInt32 GetLen(UInt32 &res) + { + UInt32 len = GetVal(res, 2); + return GetVal(res, 1 + len); + } + void Generate() + { + UInt32 pos = 0; + UInt32 rep0 = 1; + while (pos < BufferSize) + { + UInt32 res = RG->GetRnd(); + res >>= 1; + if (GetVal(res, 1) == 0 || pos < 1024) + Buffer[pos++] = (Byte)(res & 0xFF); + else + { + UInt32 len; + len = 1 + GetLen(res); + if (GetVal(res, 3) != 0) + { + len += GetLen(res); + do + { + UInt32 ppp = GetVal(res, 5) + 6; + res = RG->GetRnd(); + if (ppp > 30) + continue; + rep0 = /* (1 << ppp) +*/ GetVal(res, ppp); + res = RG->GetRnd(); + } + while (rep0 >= pos); + rep0++; + } + + for (UInt32 i = 0; i < len && pos < BufferSize; i++, pos++) + Buffer[pos] = Buffer[pos - rep0]; + } + } + } +}; + + +class CBenchmarkInStream: + public ISequentialInStream, + public CMyUnknownImp +{ + const Byte *Data; + size_t Pos; + size_t Size; +public: + MY_UNKNOWN_IMP + void Init(const Byte *data, size_t size) + { + Data = data; + Size = size; + Pos = 0; + } + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + size_t remain = Size - Pos; + UInt32 kMaxBlockSize = (1 << 20); + if (size > kMaxBlockSize) + size = kMaxBlockSize; + if (size > remain) + size = (UInt32)remain; + for (UInt32 i = 0; i < size; i++) + ((Byte *)data)[i] = Data[Pos + i]; + Pos += size; + if(processedSize != NULL) + *processedSize = size; + return S_OK; +} + +class CBenchmarkOutStream: + public ISequentialOutStream, + public CBenchBuffer, + public CMyUnknownImp +{ + // bool _overflow; +public: + UInt32 Pos; + // CBenchmarkOutStream(): _overflow(false) {} + void Init() + { + // _overflow = false; + Pos = 0; + } + MY_UNKNOWN_IMP + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + size_t curSize = BufferSize - Pos; + if (curSize > size) + curSize = size; + memcpy(Buffer + Pos, data, curSize); + Pos += (UInt32)curSize; + if(processedSize != NULL) + *processedSize = (UInt32)curSize; + if (curSize != size) + { + // _overflow = true; + return E_FAIL; + } + return S_OK; +} + +class CCrcOutStream: + public ISequentialOutStream, + public CMyUnknownImp +{ +public: + UInt32 Crc; + MY_UNKNOWN_IMP + void Init() { Crc = CRC_INIT_VAL; } + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + Crc = CrcUpdate(Crc, data, size); + if (processedSize != NULL) + *processedSize = size; + return S_OK; +} + +static UInt64 GetTimeCount() +{ + #ifdef USE_POSIX_TIME + #ifdef USE_POSIX_TIME2 + timeval v; + if (gettimeofday(&v, 0) == 0) + return (UInt64)(v.tv_sec) * 1000000 + v.tv_usec; + return (UInt64)time(NULL) * 1000000; + #else + return time(NULL); + #endif + #else + /* + LARGE_INTEGER value; + if (::QueryPerformanceCounter(&value)) + return value.QuadPart; + */ + return GetTickCount(); + #endif +} + +static UInt64 GetFreq() +{ + #ifdef USE_POSIX_TIME + #ifdef USE_POSIX_TIME2 + return 1000000; + #else + return 1; + #endif + #else + /* + LARGE_INTEGER value; + if (::QueryPerformanceFrequency(&value)) + return value.QuadPart; + */ + return 1000; + #endif +} + +#ifndef USE_POSIX_TIME +static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; } +#endif + +static UInt64 GetUserTime() +{ + #ifdef USE_POSIX_TIME + return clock(); + #else + FILETIME creationTime, exitTime, kernelTime, userTime; + if ( + #ifdef UNDER_CE + ::GetThreadTimes(::GetCurrentThread() + #else + ::GetProcessTimes(::GetCurrentProcess() + #endif + , &creationTime, &exitTime, &kernelTime, &userTime) != 0) + return GetTime64(userTime) + GetTime64(kernelTime); + return (UInt64)GetTickCount() * 10000; + #endif +} + +static UInt64 GetUserFreq() +{ + #ifdef USE_POSIX_TIME + return CLOCKS_PER_SEC; + #else + return 10000000; + #endif +} + +class CBenchProgressStatus +{ + #ifndef _7ZIP_ST + NWindows::NSynchronization::CCriticalSection CS; + #endif +public: + HRESULT Res; + bool EncodeMode; + void SetResult(HRESULT res) + { + #ifndef _7ZIP_ST + NWindows::NSynchronization::CCriticalSectionLock lock(CS); + #endif + Res = res; + } + HRESULT GetResult() + { + #ifndef _7ZIP_ST + NWindows::NSynchronization::CCriticalSectionLock lock(CS); + #endif + return Res; + } +}; + +class CBenchProgressInfo: + public ICompressProgressInfo, + public CMyUnknownImp +{ +public: + CBenchProgressStatus *Status; + CBenchInfo BenchInfo; + HRESULT Res; + IBenchCallback *callback; + CBenchProgressInfo(): callback(0) {} + MY_UNKNOWN_IMP + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); +}; + +static void SetStartTime(CBenchInfo &bi) +{ + bi.GlobalFreq = GetFreq(); + bi.UserFreq = GetUserFreq(); + bi.GlobalTime = ::GetTimeCount(); + bi.UserTime = ::GetUserTime(); +} + +static void SetFinishTime(const CBenchInfo &biStart, CBenchInfo &dest) +{ + dest.GlobalFreq = GetFreq(); + dest.UserFreq = GetUserFreq(); + dest.GlobalTime = ::GetTimeCount() - biStart.GlobalTime; + dest.UserTime = ::GetUserTime() - biStart.UserTime; +} + +STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + HRESULT res = Status->GetResult(); + if (res != S_OK) + return res; + if (!callback) + return res; + CBenchInfo info = BenchInfo; + SetFinishTime(BenchInfo, info); + if (Status->EncodeMode) + { + info.UnpackSize = *inSize; + info.PackSize = *outSize; + res = callback->SetEncodeResult(info, false); + } + else + { + info.PackSize = BenchInfo.PackSize + *inSize; + info.UnpackSize = BenchInfo.UnpackSize + *outSize; + res = callback->SetDecodeResult(info, false); + } + if (res != S_OK) + Status->SetResult(res); + return res; +} + +static const int kSubBits = 8; + +static UInt32 GetLogSize(UInt32 size) +{ + for (int i = kSubBits; i < 32; i++) + for (UInt32 j = 0; j < (1 << kSubBits); j++) + if (size <= (((UInt32)1) << i) + (j << (i - kSubBits))) + return (i << kSubBits) + j; + return (32 << kSubBits); +} + +static void NormalizeVals(UInt64 &v1, UInt64 &v2) +{ + while (v1 > 1000000) + { + v1 >>= 1; + v2 >>= 1; + } +} + +UInt64 GetUsage(const CBenchInfo &info) +{ + UInt64 userTime = info.UserTime; + UInt64 userFreq = info.UserFreq; + UInt64 globalTime = info.GlobalTime; + UInt64 globalFreq = info.GlobalFreq; + NormalizeVals(userTime, userFreq); + NormalizeVals(globalFreq, globalTime); + if (userFreq == 0) + userFreq = 1; + if (globalTime == 0) + globalTime = 1; + return userTime * globalFreq * 1000000 / userFreq / globalTime; +} + +UInt64 GetRatingPerUsage(const CBenchInfo &info, UInt64 rating) +{ + UInt64 userTime = info.UserTime; + UInt64 userFreq = info.UserFreq; + UInt64 globalTime = info.GlobalTime; + UInt64 globalFreq = info.GlobalFreq; + NormalizeVals(userFreq, userTime); + NormalizeVals(globalTime, globalFreq); + if (globalFreq == 0) + globalFreq = 1; + if (userTime == 0) + userTime = 1; + return userFreq * globalTime / globalFreq * rating / userTime; +} + +static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq) +{ + UInt64 elTime = elapsedTime; + NormalizeVals(freq, elTime); + if (elTime == 0) + elTime = 1; + return value * freq / elTime; +} + +UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 freq, UInt64 size) +{ + UInt64 t = GetLogSize(dictionarySize) - (kBenchMinDicLogSize << kSubBits); + UInt64 numCommandsForOne = 870 + ((t * t * 5) >> (2 * kSubBits)); + UInt64 numCommands = (UInt64)(size) * numCommandsForOne; + return MyMultDiv64(numCommands, elapsedTime, freq); +} + +UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt32 numIterations) +{ + UInt64 numCommands = (inSize * 200 + outSize * 4) * numIterations; + return MyMultDiv64(numCommands, elapsedTime, freq); +} + +struct CEncoderInfo; + +struct CEncoderInfo +{ + #ifndef _7ZIP_ST + NWindows::CThread thread[2]; + #endif + CMyComPtr encoder; + CBenchProgressInfo *progressInfoSpec[2]; + CMyComPtr progressInfo[2]; + UInt32 NumIterations; + #ifdef USE_ALLOCA + size_t AllocaSize; + #endif + + struct CDecoderInfo + { + CEncoderInfo *Encoder; + UInt32 DecoderIndex; + #ifdef USE_ALLOCA + size_t AllocaSize; + #endif + bool CallbackMode; + }; + CDecoderInfo decodersInfo[2]; + + CMyComPtr decoders[2]; + HRESULT Results[2]; + CBenchmarkOutStream *outStreamSpec; + CMyComPtr outStream; + IBenchCallback *callback; + UInt32 crc; + UInt32 kBufferSize; + UInt32 compressedSize; + CBenchRandomGenerator rg; + CBenchmarkOutStream *propStreamSpec; + CMyComPtr propStream; + HRESULT Init(UInt32 dictionarySize, UInt32 numThreads, CBaseRandomGenerator *rg); + HRESULT Encode(); + HRESULT Decode(UInt32 decoderIndex); + + CEncoderInfo(): outStreamSpec(0), callback(0), propStreamSpec(0) {} + + #ifndef _7ZIP_ST + static THREAD_FUNC_DECL EncodeThreadFunction(void *param) + { + CEncoderInfo *encoder = (CEncoderInfo *)param; + #ifdef USE_ALLOCA + alloca(encoder->AllocaSize); + #endif + HRESULT res = encoder->Encode(); + encoder->Results[0] = res; + if (res != S_OK) + encoder->progressInfoSpec[0]->Status->SetResult(res); + + return 0; + } + static THREAD_FUNC_DECL DecodeThreadFunction(void *param) + { + CDecoderInfo *decoder = (CDecoderInfo *)param; + #ifdef USE_ALLOCA + alloca(decoder->AllocaSize); + #endif + CEncoderInfo *encoder = decoder->Encoder; + encoder->Results[decoder->DecoderIndex] = encoder->Decode(decoder->DecoderIndex); + return 0; + } + + HRESULT CreateEncoderThread() + { + return thread[0].Create(EncodeThreadFunction, this); + } + + HRESULT CreateDecoderThread(int index, bool callbackMode + #ifdef USE_ALLOCA + , size_t allocaSize + #endif + ) + { + CDecoderInfo &decoder = decodersInfo[index]; + decoder.DecoderIndex = index; + decoder.Encoder = this; + #ifdef USE_ALLOCA + decoder.AllocaSize = allocaSize; + #endif + decoder.CallbackMode = callbackMode; + return thread[index].Create(DecodeThreadFunction, &decoder); + } + #endif +}; + +HRESULT CEncoderInfo::Init(UInt32 dictionarySize, UInt32 numThreads, CBaseRandomGenerator *rgLoc) +{ + rg.Set(rgLoc); + kBufferSize = dictionarySize + kAdditionalSize; + UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize; + if (!rg.Alloc(kBufferSize)) + return E_OUTOFMEMORY; + rg.Generate(); + crc = CrcCalc(rg.Buffer, rg.BufferSize); + + outStreamSpec = new CBenchmarkOutStream; + if (!outStreamSpec->Alloc(kCompressedBufferSize)) + return E_OUTOFMEMORY; + + outStream = outStreamSpec; + + propStreamSpec = 0; + if (!propStream) + { + propStreamSpec = new CBenchmarkOutStream; + propStream = propStreamSpec; + } + if (!propStreamSpec->Alloc(kMaxLzmaPropSize)) + return E_OUTOFMEMORY; + propStreamSpec->Init(); + + PROPID propIDs[] = + { + NCoderPropID::kDictionarySize, + NCoderPropID::kNumThreads + }; + const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]); + PROPVARIANT props[kNumProps]; + props[0].vt = VT_UI4; + props[0].ulVal = dictionarySize; + + props[1].vt = VT_UI4; + props[1].ulVal = numThreads; + + { + CMyComPtr setCoderProperties; + RINOK(encoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties)); + if (!setCoderProperties) + return E_FAIL; + RINOK(setCoderProperties->SetCoderProperties(propIDs, props, kNumProps)); + + CMyComPtr writeCoderProperties; + encoder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProperties); + if (writeCoderProperties) + { + RINOK(writeCoderProperties->WriteCoderProperties(propStream)); + } + } + return S_OK; +} + +HRESULT CEncoderInfo::Encode() +{ + CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; + CMyComPtr inStream = inStreamSpec; + inStreamSpec->Init(rg.Buffer, rg.BufferSize); + outStreamSpec->Init(); + + RINOK(encoder->Code(inStream, outStream, 0, 0, progressInfo[0])); + compressedSize = outStreamSpec->Pos; + encoder.Release(); + return S_OK; +} + +HRESULT CEncoderInfo::Decode(UInt32 decoderIndex) +{ + CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; + CMyComPtr inStream = inStreamSpec; + CMyComPtr &decoder = decoders[decoderIndex]; + + CMyComPtr compressSetDecoderProperties; + decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &compressSetDecoderProperties); + if (!compressSetDecoderProperties) + return E_FAIL; + + CCrcOutStream *crcOutStreamSpec = new CCrcOutStream; + CMyComPtr crcOutStream = crcOutStreamSpec; + + CBenchProgressInfo *pi = progressInfoSpec[decoderIndex]; + pi->BenchInfo.UnpackSize = 0; + pi->BenchInfo.PackSize = 0; + + for (UInt32 j = 0; j < NumIterations; j++) + { + inStreamSpec->Init(outStreamSpec->Buffer, compressedSize); + crcOutStreamSpec->Init(); + + RINOK(compressSetDecoderProperties->SetDecoderProperties2(propStreamSpec->Buffer, propStreamSpec->Pos)); + UInt64 outSize = kBufferSize; + RINOK(decoder->Code(inStream, crcOutStream, 0, &outSize, progressInfo[decoderIndex])); + if (CRC_GET_DIGEST(crcOutStreamSpec->Crc) != crc) + return S_FALSE; + pi->BenchInfo.UnpackSize += kBufferSize; + pi->BenchInfo.PackSize += compressedSize; + } + decoder.Release(); + return S_OK; +} + +static const UInt32 kNumThreadsMax = (1 << 16); + +struct CBenchEncoders +{ + CEncoderInfo *encoders; + CBenchEncoders(UInt32 num): encoders(0) { encoders = new CEncoderInfo[num]; } + ~CBenchEncoders() { delete []encoders; } +}; + +HRESULT LzmaBench( + DECL_EXTERNAL_CODECS_LOC_VARS + UInt32 numThreads, UInt32 dictionarySize, IBenchCallback *callback) +{ + UInt32 numEncoderThreads = + #ifndef _7ZIP_ST + (numThreads > 1 ? numThreads / 2 : 1); + #else + 1; + #endif + UInt32 numSubDecoderThreads = + #ifndef _7ZIP_ST + (numThreads > 1 ? 2 : 1); + #else + 1; + #endif + if (dictionarySize < (1 << kBenchMinDicLogSize) || numThreads < 1 || numEncoderThreads > kNumThreadsMax) + { + return E_INVALIDARG; + } + + CBenchEncoders encodersSpec(numEncoderThreads); + CEncoderInfo *encoders = encodersSpec.encoders; + + + UInt32 i; + for (i = 0; i < numEncoderThreads; i++) + { + CEncoderInfo &encoder = encoders[i]; + encoder.callback = (i == 0) ? callback : 0; + + const UInt32 kLzmaId = 0x030101; + RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS kLzmaId, encoder.encoder, true)); + if (!encoder.encoder) + return E_NOTIMPL; + for (UInt32 j = 0; j < numSubDecoderThreads; j++) + { + RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS kLzmaId, encoder.decoders[j], false)); + if (!encoder.decoders[j]) + return E_NOTIMPL; + } + } + + CBaseRandomGenerator rg; + rg.Init(); + for (i = 0; i < numEncoderThreads; i++) + { + RINOK(encoders[i].Init(dictionarySize, numThreads, &rg)); + } + + CBenchProgressStatus status; + status.Res = S_OK; + status.EncodeMode = true; + + for (i = 0; i < numEncoderThreads; i++) + { + CEncoderInfo &encoder = encoders[i]; + for (int j = 0; j < 2; j++) + { + encoder.progressInfo[j] = encoder.progressInfoSpec[j] = new CBenchProgressInfo; + encoder.progressInfoSpec[j]->Status = &status; + } + if (i == 0) + { + encoder.progressInfoSpec[0]->callback = callback; + encoder.progressInfoSpec[0]->BenchInfo.NumIterations = numEncoderThreads; + SetStartTime(encoder.progressInfoSpec[0]->BenchInfo); + } + + #ifndef _7ZIP_ST + if (numEncoderThreads > 1) + { + #ifdef USE_ALLOCA + encoder.AllocaSize = (i * 16 * 21) & 0x7FF; + #endif + RINOK(encoder.CreateEncoderThread()) + } + else + #endif + { + RINOK(encoder.Encode()); + } + } + #ifndef _7ZIP_ST + if (numEncoderThreads > 1) + for (i = 0; i < numEncoderThreads; i++) + encoders[i].thread[0].Wait(); + #endif + + RINOK(status.Res); + + CBenchInfo info; + + SetFinishTime(encoders[0].progressInfoSpec[0]->BenchInfo, info); + info.UnpackSize = 0; + info.PackSize = 0; + info.NumIterations = 1; // progressInfoSpec->NumIterations; + for (i = 0; i < numEncoderThreads; i++) + { + CEncoderInfo &encoder = encoders[i]; + info.UnpackSize += encoder.kBufferSize; + info.PackSize += encoder.compressedSize; + } + RINOK(callback->SetEncodeResult(info, true)); + + + status.Res = S_OK; + status.EncodeMode = false; + + UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads; + for (i = 0; i < numEncoderThreads; i++) + { + CEncoderInfo &encoder = encoders[i]; + encoder.NumIterations = 2 + kUncompressMinBlockSize / encoder.kBufferSize; + + if (i == 0) + { + encoder.progressInfoSpec[0]->callback = callback; + encoder.progressInfoSpec[0]->BenchInfo.NumIterations = numDecoderThreads; + SetStartTime(encoder.progressInfoSpec[0]->BenchInfo); + } + + #ifndef _7ZIP_ST + if (numDecoderThreads > 1) + { + for (UInt32 j = 0; j < numSubDecoderThreads; j++) + { + HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0) + #ifdef USE_ALLOCA + , ((i * numSubDecoderThreads + j) * 16 * 21) & 0x7FF + #endif + ); + RINOK(res); + } + } + else + #endif + { + RINOK(encoder.Decode(0)); + } + } + #ifndef _7ZIP_ST + HRESULT res = S_OK; + if (numDecoderThreads > 1) + for (i = 0; i < numEncoderThreads; i++) + for (UInt32 j = 0; j < numSubDecoderThreads; j++) + { + CEncoderInfo &encoder = encoders[i]; + encoder.thread[j].Wait(); + if (encoder.Results[j] != S_OK) + res = encoder.Results[j]; + } + RINOK(res); + #endif + RINOK(status.Res); + SetFinishTime(encoders[0].progressInfoSpec[0]->BenchInfo, info); + #ifndef _7ZIP_ST + #ifdef UNDER_CE + if (numDecoderThreads > 1) + for (i = 0; i < numEncoderThreads; i++) + for (UInt32 j = 0; j < numSubDecoderThreads; j++) + { + FILETIME creationTime, exitTime, kernelTime, userTime; + if (::GetThreadTimes(encoders[i].thread[j], &creationTime, &exitTime, &kernelTime, &userTime) != 0) + info.UserTime += GetTime64(userTime) + GetTime64(kernelTime); + } + #endif + #endif + info.UnpackSize = 0; + info.PackSize = 0; + info.NumIterations = numSubDecoderThreads * encoders[0].NumIterations; + for (i = 0; i < numEncoderThreads; i++) + { + CEncoderInfo &encoder = encoders[i]; + info.UnpackSize += encoder.kBufferSize; + info.PackSize += encoder.compressedSize; + } + RINOK(callback->SetDecodeResult(info, false)); + RINOK(callback->SetDecodeResult(info, true)); + return S_OK; +} + + +inline UInt64 GetLZMAUsage(bool multiThread, UInt32 dictionary) +{ + UInt32 hs = dictionary - 1; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + hs >>= 1; + hs |= 0xFFFF; + if (hs > (1 << 24)) + hs >>= 1; + hs++; + return ((hs + (1 << 16)) + (UInt64)dictionary * 2) * 4 + (UInt64)dictionary * 3 / 2 + + (1 << 20) + (multiThread ? (6 << 20) : 0); +} + +UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary) +{ + const UInt32 kBufferSize = dictionary; + const UInt32 kCompressedBufferSize = (kBufferSize / 2); + UInt32 numSubThreads = (numThreads > 1) ? 2 : 1; + UInt32 numBigThreads = numThreads / numSubThreads; + return (kBufferSize + kCompressedBufferSize + + GetLZMAUsage((numThreads > 1), dictionary) + (2 << 20)) * numBigThreads; +} + +static bool CrcBig(const void *data, UInt32 size, UInt32 numCycles, UInt32 crcBase) +{ + for (UInt32 i = 0; i < numCycles; i++) + if (CrcCalc(data, size) != crcBase) + return false; + return true; +} + +#ifndef _7ZIP_ST +struct CCrcInfo +{ + NWindows::CThread Thread; + const Byte *Data; + UInt32 Size; + UInt32 NumCycles; + UInt32 Crc; + bool Res; + void Wait() + { + Thread.Wait(); + Thread.Close(); + } +}; + +static THREAD_FUNC_DECL CrcThreadFunction(void *param) +{ + CCrcInfo *p = (CCrcInfo *)param; + p->Res = CrcBig(p->Data, p->Size, p->NumCycles, p->Crc); + return 0; +} + +struct CCrcThreads +{ + UInt32 NumThreads; + CCrcInfo *Items; + CCrcThreads(): Items(0), NumThreads(0) {} + void WaitAll() + { + for (UInt32 i = 0; i < NumThreads; i++) + Items[i].Wait(); + NumThreads = 0; + } + ~CCrcThreads() + { + WaitAll(); + delete []Items; + } +}; +#endif + +static UInt32 CrcCalc1(const Byte *buf, UInt32 size) +{ + UInt32 crc = CRC_INIT_VAL;; + for (UInt32 i = 0; i < size; i++) + crc = CRC_UPDATE_BYTE(crc, buf[i]); + return CRC_GET_DIGEST(crc); +} + +static void RandGen(Byte *buf, UInt32 size, CBaseRandomGenerator &RG) +{ + for (UInt32 i = 0; i < size; i++) + buf[i] = (Byte)RG.GetRnd(); +} + +static UInt32 RandGenCrc(Byte *buf, UInt32 size, CBaseRandomGenerator &RG) +{ + RandGen(buf, size, RG); + return CrcCalc1(buf, size); +} + +bool CrcInternalTest() +{ + CBenchBuffer buffer; + const UInt32 kBufferSize0 = (1 << 8); + const UInt32 kBufferSize1 = (1 << 10); + const UInt32 kCheckSize = (1 << 5); + if (!buffer.Alloc(kBufferSize0 + kBufferSize1)) + return false; + Byte *buf = buffer.Buffer; + UInt32 i; + for (i = 0; i < kBufferSize0; i++) + buf[i] = (Byte)i; + UInt32 crc1 = CrcCalc1(buf, kBufferSize0); + if (crc1 != 0x29058C73) + return false; + CBaseRandomGenerator RG; + RandGen(buf + kBufferSize0, kBufferSize1, RG); + for (i = 0; i < kBufferSize0 + kBufferSize1 - kCheckSize; i++) + for (UInt32 j = 0; j < kCheckSize; j++) + if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j)) + return false; + return true; +} + +HRESULT CrcBench(UInt32 numThreads, UInt32 bufferSize, UInt64 &speed) +{ + if (numThreads == 0) + numThreads = 1; + + CBenchBuffer buffer; + size_t totalSize = (size_t)bufferSize * numThreads; + if (totalSize / numThreads != bufferSize) + return E_OUTOFMEMORY; + if (!buffer.Alloc(totalSize)) + return E_OUTOFMEMORY; + + Byte *buf = buffer.Buffer; + CBaseRandomGenerator RG; + UInt32 numCycles = (kCrcBlockSize) / ((bufferSize >> 2) + 1) + 1; + + UInt64 timeVal; + #ifndef _7ZIP_ST + CCrcThreads threads; + if (numThreads > 1) + { + threads.Items = new CCrcInfo[numThreads]; + UInt32 i; + for (i = 0; i < numThreads; i++) + { + CCrcInfo &info = threads.Items[i]; + Byte *data = buf + (size_t)bufferSize * i; + info.Data = data; + info.NumCycles = numCycles; + info.Size = bufferSize; + info.Crc = RandGenCrc(data, bufferSize, RG); + } + timeVal = GetTimeCount(); + for (i = 0; i < numThreads; i++) + { + CCrcInfo &info = threads.Items[i]; + RINOK(info.Thread.Create(CrcThreadFunction, &info)); + threads.NumThreads++; + } + threads.WaitAll(); + for (i = 0; i < numThreads; i++) + if (!threads.Items[i].Res) + return S_FALSE; + } + else + #endif + { + UInt32 crc = RandGenCrc(buf, bufferSize, RG); + timeVal = GetTimeCount(); + if (!CrcBig(buf, bufferSize, numCycles, crc)) + return S_FALSE; + } + timeVal = GetTimeCount() - timeVal; + if (timeVal == 0) + timeVal = 1; + + UInt64 size = (UInt64)numCycles * totalSize; + speed = MyMultDiv64(size, timeVal, GetFreq()); + return S_OK; +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/Bench.h b/src/libs/7zip/win/CPP/7zip/UI/Common/Bench.h new file mode 100644 index 000000000..a8d02a19b --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/Bench.h @@ -0,0 +1,42 @@ +// Bench.h + +#ifndef __7ZIP_BENCH_H +#define __7ZIP_BENCH_H + +#include "../../Common/CreateCoder.h" + +struct CBenchInfo +{ + UInt64 GlobalTime; + UInt64 GlobalFreq; + UInt64 UserTime; + UInt64 UserFreq; + UInt64 UnpackSize; + UInt64 PackSize; + UInt32 NumIterations; + CBenchInfo(): NumIterations(0) {} +}; + +struct IBenchCallback +{ + virtual HRESULT SetEncodeResult(const CBenchInfo &info, bool final) = 0; + virtual HRESULT SetDecodeResult(const CBenchInfo &info, bool final) = 0; +}; + +UInt64 GetUsage(const CBenchInfo &benchOnfo); +UInt64 GetRatingPerUsage(const CBenchInfo &info, UInt64 rating); +UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 freq, UInt64 size); +UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt32 numIterations); + +HRESULT LzmaBench( + DECL_EXTERNAL_CODECS_LOC_VARS + UInt32 numThreads, UInt32 dictionarySize, IBenchCallback *callback); + +const int kBenchMinDicLogSize = 18; + +UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary); + +bool CrcInternalTest(); +HRESULT CrcBench(UInt32 numThreads, UInt32 bufferSize, UInt64 &speed); + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.cpp new file mode 100644 index 000000000..c2685f798 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.cpp @@ -0,0 +1,246 @@ +// CompressCall.cpp + +#include "StdAfx.h" + +#include "Common/IntToString.h" +#include "Common/MyCom.h" +#include "Common/Random.h" +#include "Common/StringConvert.h" + +#include "Windows/FileDir.h" +#include "Windows/FileMapping.h" +#include "Windows/Process.h" +#include "Windows/Synchronization.h" + +#include "../FileManager/ProgramLocation.h" +#include "../FileManager/RegistryUtils.h" + +#include "CompressCall.h" + +using namespace NWindows; + +#define MY_TRY_BEGIN try { +#define MY_TRY_FINISH } \ + catch(...) { ErrorMessageHRESULT(E_FAIL); return E_FAIL; } + +static LPCWSTR kShowDialogSwitch = L" -ad"; +static LPCWSTR kEmailSwitch = L" -seml."; +static LPCWSTR kIncludeSwitch = L" -i"; +static LPCWSTR kArchiveTypeSwitch = L" -t"; +static LPCWSTR kArcIncludeSwitches = L" -an -ai"; +static LPCWSTR kStopSwitchParsing = L" --"; +static LPCWSTR kLargePagesDisable = L" -slp-"; + +UString GetQuotedString(const UString &s) +{ + return UString(L'\"') + s + UString(L'\"'); +} +static void ErrorMessage(LPCWSTR message) +{ + MessageBoxW(g_HWND, message, L"7-Zip", MB_ICONERROR | MB_OK); +} + +static void ErrorMessageHRESULT(HRESULT res, LPCWSTR s = NULL) +{ + UString s2 = HResultToMessage(res); + if (s) + { + s2 += L'\n'; + s2 += s; + } + ErrorMessage(s2); +} + +static HRESULT MyCreateProcess(LPCWSTR imageName, const UString ¶ms, + LPCWSTR curDir, bool waitFinish, + NSynchronization::CBaseEvent *event) +{ + CProcess process; + WRes res = process.Create(imageName, params, curDir); + if (res != 0) + { + ErrorMessageHRESULT(res, imageName); + return res; + } + if (waitFinish) + process.Wait(); + else if (event != NULL) + { + HANDLE handles[] = { process, *event }; + ::WaitForMultipleObjects(sizeof(handles) / sizeof(handles[0]), handles, FALSE, INFINITE); + } + return S_OK; +} + +static void AddLagePagesSwitch(UString ¶ms) +{ + if (!ReadLockMemoryEnable()) + params += kLargePagesDisable; +} + +static UString Get7zGuiPath() +{ + UString path; + GetProgramFolderPath(path); + return path + L"7zG.exe"; +} + +class CRandNameGenerator +{ + CRandom _random; +public: + CRandNameGenerator() { _random.Init(); } + UString GenerateName() + { + wchar_t temp[16]; + ConvertUInt32ToString((UInt32)_random.Generate(), temp); + return temp; + } +}; + +static HRESULT CreateMap(const UStringVector &names, + CFileMapping &fileMapping, NSynchronization::CManualResetEvent &event, + UString ¶ms) +{ + UInt32 totalSize = 1; + for (int i = 0; i < names.Size(); i++) + totalSize += (names[i].Length() + 1); + totalSize *= sizeof(wchar_t); + + CRandNameGenerator random; + + UString mappingName; + for (;;) + { + mappingName = L"7zMap" + random.GenerateName(); + + WRes res = fileMapping.Create(PAGE_READWRITE, totalSize, GetSystemString(mappingName)); + if (fileMapping.IsCreated() && res == 0) + break; + if (res != ERROR_ALREADY_EXISTS) + return res; + fileMapping.Close(); + } + + UString eventName; + for (;;) + { + eventName = L"7zEvent" + random.GenerateName(); + WRes res = event.CreateWithName(false, GetSystemString(eventName)); + if (event.IsCreated() && res == 0) + break; + if (res != ERROR_ALREADY_EXISTS) + return res; + event.Close(); + } + + params += L'#'; + params += mappingName; + params += L':'; + wchar_t temp[16]; + ConvertUInt32ToString(totalSize, temp); + params += temp; + + params += L':'; + params += eventName; + + LPVOID data = fileMapping.Map(FILE_MAP_WRITE, 0, totalSize); + if (data == NULL) + return E_FAIL; + CFileUnmapper unmapper(data); + { + wchar_t *cur = (wchar_t *)data; + *cur++ = 0; + for (int i = 0; i < names.Size(); i++) + { + const UString &s = names[i]; + int len = s.Length() + 1; + memcpy(cur, (const wchar_t *)s, len * sizeof(wchar_t)); + cur += len; + } + } + return S_OK; +} + +HRESULT CompressFiles( + const UString &arcPathPrefix, + const UString &arcName, + const UString &arcType, + const UStringVector &names, + bool email, bool showDialog, bool waitFinish) +{ + MY_TRY_BEGIN + UString params = L'a'; + + CFileMapping fileMapping; + NSynchronization::CManualResetEvent event; + params += kIncludeSwitch; + RINOK(CreateMap(names, fileMapping, event, params)); + + if (!arcType.IsEmpty()) + { + params += kArchiveTypeSwitch; + params += arcType; + } + + if (email) + params += kEmailSwitch; + + if (showDialog) + params += kShowDialogSwitch; + + AddLagePagesSwitch(params); + + params += kStopSwitchParsing; + params += L' '; + + params += GetQuotedString( + #ifdef UNDER_CE + arcPathPrefix + + #endif + arcName); + + return MyCreateProcess(Get7zGuiPath(), params, + (arcPathPrefix.IsEmpty()? 0: (LPCWSTR)arcPathPrefix), waitFinish, &event); + MY_TRY_FINISH +} + +static HRESULT ExtractGroupCommand(const UStringVector &arcPaths, UString ¶ms) +{ + AddLagePagesSwitch(params); + params += kArcIncludeSwitches; + CFileMapping fileMapping; + NSynchronization::CManualResetEvent event; + RINOK(CreateMap(arcPaths, fileMapping, event, params)); + return MyCreateProcess(Get7zGuiPath(), params, 0, false, &event); +} + +HRESULT ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog) +{ + MY_TRY_BEGIN + UString params = L'x'; + if (!outFolder.IsEmpty()) + { + params += L" -o"; + params += GetQuotedString(outFolder); + } + if (showDialog) + params += kShowDialogSwitch; + return ExtractGroupCommand(arcPaths, params); + MY_TRY_FINISH +} + +HRESULT TestArchives(const UStringVector &arcPaths) +{ + MY_TRY_BEGIN + UString params = L't'; + return ExtractGroupCommand(arcPaths, params); + MY_TRY_FINISH +} + +HRESULT Benchmark() +{ + MY_TRY_BEGIN + return MyCreateProcess(Get7zGuiPath(), L'b', 0, false, NULL); + MY_TRY_FINISH +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.h b/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.h new file mode 100644 index 000000000..fc18df57c --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.h @@ -0,0 +1,24 @@ +// CompressCall.h + +#ifndef __COMPRESS_CALL_H +#define __COMPRESS_CALL_H + +#include "Common/MyString.h" + +UString GetQuotedString(const UString &s); + +extern HWND g_HWND; +UString HResultToMessage(HRESULT errorCode); + +HRESULT CompressFiles( + const UString &arcPathPrefix, + const UString &arcName, + const UString &arcType, + const UStringVector &names, + bool email, bool showDialog, bool waitFinish); + +HRESULT ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog); +HRESULT TestArchives(const UStringVector &arcPaths); +HRESULT Benchmark(); + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall2.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall2.cpp new file mode 100644 index 000000000..473f7d933 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall2.cpp @@ -0,0 +1,178 @@ +// CompressCall.cpp + +#include "StdAfx.h" + +#include "Common/MyException.h" + +#include "../../UI/common/ArchiveCommandLine.h" + +#include "../../UI/GUI/BenchmarkDialog.h" +#include "../../UI/GUI/ExtractGUI.h" +#include "../../UI/GUI/UpdateGUI.h" + +#include "../../UI/GUI/ExtractRes.h" + +#include "CompressCall.h" + +#define MY_TRY_BEGIN try { +#define MY_TRY_FINISH } \ + catch(CSystemException &e) { result = e.ErrorCode; } \ + catch(...) { result = E_FAIL; } \ + if (result != S_OK && result != E_ABORT) \ + ErrorMessageHRESULT(result); + +#define CREATE_CODECS \ + CCodecs *codecs = new CCodecs; \ + CMyComPtr compressCodecsInfo = codecs; \ + result = codecs->Load(); \ + if (result != S_OK) \ + throw CSystemException(result); + +UString GetQuotedString(const UString &s) +{ + return UString(L'\"') + s + UString(L'\"'); +} + +static void ErrorMessage(LPCWSTR message) +{ + MessageBoxW(g_HWND, message, L"7-Zip", MB_ICONERROR); +} + +static void ErrorMessageHRESULT(HRESULT res) +{ + ErrorMessage(HResultToMessage(res)); +} + +static void ErrorLangMessage(UINT resourceID, UInt32 langID) +{ + ErrorMessage(LangString(resourceID, langID)); +} + +HRESULT CompressFiles( + const UString &arcPathPrefix, + const UString &arcName, + const UString &arcType, + const UStringVector &names, + bool email, bool showDialog, bool /* waitFinish */) +{ + HRESULT result; + MY_TRY_BEGIN + CREATE_CODECS + + CUpdateCallbackGUI callback; + + callback.Init(); + + CUpdateOptions uo; + uo.EMailMode = email; + uo.SetAddActionCommand(); + + CIntVector formatIndices; + if (!codecs->FindFormatForArchiveType(arcType, formatIndices)) + { + ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE, 0x0200060D); + return E_FAIL; + } + if (!uo.Init(codecs, formatIndices, arcPathPrefix + arcName)) + { + ErrorLangMessage(IDS_UPDATE_NOT_SUPPORTED, 0x02000601); + return E_FAIL; + } + + NWildcard::CCensor censor; + for (int i = 0; i < names.Size(); i++) + censor.AddItem(true, names[i], false); + + bool messageWasDisplayed = false; + result = UpdateGUI(codecs, censor, uo, showDialog, messageWasDisplayed, &callback, g_HWND); + + if (result != S_OK) + { + if (result != E_ABORT && messageWasDisplayed) + return E_FAIL; + throw CSystemException(result); + } + if (callback.FailedFiles.Size() > 0) + { + if (!messageWasDisplayed) + throw CSystemException(E_FAIL); + return E_FAIL; + } + MY_TRY_FINISH + return S_OK; +} + +static HRESULT ExtractGroupCommand(const UStringVector &arcPaths, + bool showDialog, const UString &outFolder, bool testMode) +{ + HRESULT result; + MY_TRY_BEGIN + CREATE_CODECS + + CExtractOptions eo; + eo.OutputDir = outFolder; + eo.TestMode = testMode; + + CExtractCallbackImp *ecs = new CExtractCallbackImp; + CMyComPtr extractCallback = ecs; + + ecs->Init(); + + // eo.CalcCrc = options.CalcCrc; + + UStringVector arcPathsSorted; + UStringVector arcFullPathsSorted; + { + NWildcard::CCensor acrCensor; + for (int i = 0; i < arcPaths.Size(); i++) + acrCensor.AddItem(true, arcPaths[i], false); + EnumerateDirItemsAndSort(acrCensor, arcPathsSorted, arcFullPathsSorted); + } + + CIntVector formatIndices; + + NWildcard::CCensor censor; + censor.AddItem(true, L"*", false); + + bool messageWasDisplayed = false; + result = ExtractGUI(codecs, formatIndices, arcPathsSorted, arcFullPathsSorted, + censor.Pairs.Front().Head, eo, showDialog, messageWasDisplayed, ecs, g_HWND); + if (result != S_OK) + { + if (result != E_ABORT && messageWasDisplayed) + return E_FAIL; + throw CSystemException(result); + } + return ecs->IsOK() ? S_OK : E_FAIL; + MY_TRY_FINISH + return result; +} + +HRESULT ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog) +{ + return ExtractGroupCommand(arcPaths, showDialog, outFolder, false); +} + +HRESULT TestArchives(const UStringVector &arcPaths) +{ + return ExtractGroupCommand(arcPaths, true, UString(), true); +} + +HRESULT Benchmark() +{ + HRESULT result; + MY_TRY_BEGIN + CREATE_CODECS + + #ifdef EXTERNAL_CODECS + CObjectVector externalCodecs; + RINOK(LoadExternalCodecs(codecs, externalCodecs)); + #endif + result = Benchmark( + #ifdef EXTERNAL_CODECS + codecs, &externalCodecs, + #endif + (UInt32)-1, (UInt32)-1, g_HWND); + MY_TRY_FINISH + return result; +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.cpp new file mode 100644 index 000000000..4335e2731 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.cpp @@ -0,0 +1,35 @@ +// DefaultName.cpp + +#include "StdAfx.h" + +#include "DefaultName.h" + +static UString GetDefaultName3(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; + + if (addSubExtension.IsEmpty()) + return fileName + L"~"; + else + return fileName + addSubExtension; +} + +UString GetDefaultName2(const UString &fileName, + const UString &extension, const UString &addSubExtension) +{ + UString name = GetDefaultName3(fileName, extension, addSubExtension); + name.TrimRight(); + return name; +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.h b/src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.h new file mode 100644 index 000000000..9764ff871 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.h @@ -0,0 +1,11 @@ +// DefaultName.h + +#ifndef __DEFAULTNAME_H +#define __DEFAULTNAME_H + +#include "Common/MyString.h" + +UString GetDefaultName2(const UString &fileName, + const UString &extension, const UString &addSubExtension); + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/DirItem.h b/src/libs/7zip/win/CPP/7zip/UI/Common/DirItem.h new file mode 100644 index 000000000..29cc60d93 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/DirItem.h @@ -0,0 +1,69 @@ +// DirItem.h + +#ifndef __DIR_ITEM_H +#define __DIR_ITEM_H + +#include "Common/MyString.h" +#include "Common/Types.h" +#include "../../Archive/IArchive.h" + +struct CDirItem +{ + UInt64 Size; + FILETIME CTime; + FILETIME ATime; + FILETIME MTime; + UString Name; + UInt32 Attrib; + int PhyParent; + int LogParent; + + CDirItem(): PhyParent(-1), LogParent(-1) {} + bool IsDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ; } +}; + +class CDirItems +{ + UStringVector Prefixes; + CIntVector PhyParents; + CIntVector LogParents; + + UString GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const; +public: + CObjectVector Items; + + int GetNumFolders() const { return Prefixes.Size(); } + UString GetPhyPath(int index) const; + UString GetLogPath(int index) const; + + int AddPrefix(int phyParent, int logParent, const UString &prefix); + void DeleteLastPrefix(); + + void EnumerateDirectory(int phyParent, int logParent, const UString &phyPrefix, + UStringVector &errorPaths, CRecordVector &errorCodes); + + void EnumerateDirItems2( + const UString &phyPrefix, + const UString &logPrefix, + const UStringVector &filePaths, + UStringVector &errorPaths, CRecordVector &errorCodes); + + void ReserveDown(); +}; + +struct CArcItem +{ + UInt64 Size; + FILETIME MTime; + UString Name; + bool IsDir; + bool SizeDefined; + bool MTimeDefined; + bool Censored; + UInt32 IndexInServer; + int TimeType; + + CArcItem(): IsDir(false), SizeDefined(false), MTimeDefined(false), Censored(false), TimeType(-1) {} +}; + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.cpp new file mode 100644 index 000000000..ba03ea35c --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.cpp @@ -0,0 +1,361 @@ +// EnumDirItems.cpp + +#include "StdAfx.h" + +#include "EnumDirItems.h" + +using namespace NWindows; +using namespace NFile; +using namespace NName; + +void AddDirFileInfo(int phyParent, int logParent, + const NFind::CFileInfoW &fi, CObjectVector &dirItems) +{ + CDirItem di; + di.Size = fi.Size; + di.CTime = fi.CTime; + di.ATime = fi.ATime; + di.MTime = fi.MTime; + di.Attrib = fi.Attrib; + di.PhyParent = phyParent; + di.LogParent = logParent; + di.Name = fi.Name; + dirItems.Add(di); +} + +UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const +{ + UString path; + int len = name.Length(); + int i; + for (i = index; i >= 0; i = parents[i]) + len += Prefixes[i].Length(); + int totalLen = len; + wchar_t *p = path.GetBuffer(len); + p[len] = 0; + len -= name.Length(); + memcpy(p + len, (const wchar_t *)name, name.Length() * sizeof(wchar_t)); + for (i = index; i >= 0; i = parents[i]) + { + const UString &s = Prefixes[i]; + len -= s.Length(); + memcpy(p + len, (const wchar_t *)s, s.Length() * sizeof(wchar_t)); + } + path.ReleaseBuffer(totalLen); + return path; +} + +UString CDirItems::GetPhyPath(int index) const +{ + const CDirItem &di = Items[index]; + return GetPrefixesPath(PhyParents, di.PhyParent, di.Name); +} + +UString CDirItems::GetLogPath(int index) const +{ + const CDirItem &di = Items[index]; + return GetPrefixesPath(LogParents, di.LogParent, di.Name); +} + +void CDirItems::ReserveDown() +{ + Prefixes.ReserveDown(); + PhyParents.ReserveDown(); + LogParents.ReserveDown(); + Items.ReserveDown(); +} + +int CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix) +{ + PhyParents.Add(phyParent); + LogParents.Add(logParent); + return Prefixes.Add(prefix); +} + +void CDirItems::DeleteLastPrefix() +{ + PhyParents.DeleteBack(); + LogParents.DeleteBack(); + Prefixes.DeleteBack(); +} + +void CDirItems::EnumerateDirectory(int phyParent, int logParent, const UString &phyPrefix, + UStringVector &errorPaths, CRecordVector &errorCodes) +{ + NFind::CEnumeratorW enumerator(phyPrefix + (wchar_t)kAnyStringWildcard); + for (;;) + { + NFind::CFileInfoW fi; + bool found; + if (!enumerator.Next(fi, found)) + { + errorCodes.Add(::GetLastError()); + errorPaths.Add(phyPrefix); + return; + } + if (!found) + break; + AddDirFileInfo(phyParent, logParent, fi, Items); + if (fi.IsDir()) + { + const UString name2 = fi.Name + (wchar_t)kDirDelimiter; + int parent = AddPrefix(phyParent, logParent, name2); + EnumerateDirectory(parent, parent, phyPrefix + name2, errorPaths, errorCodes); + } + } +} + +void CDirItems::EnumerateDirItems2(const UString &phyPrefix, const UString &logPrefix, + const UStringVector &filePaths, UStringVector &errorPaths, CRecordVector &errorCodes) +{ + int phyParent = phyPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, phyPrefix); + int logParent = logPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, logPrefix); + + for (int i = 0; i < filePaths.Size(); i++) + { + const UString &filePath = filePaths[i]; + NFind::CFileInfoW fi; + const UString phyPath = phyPrefix + filePath; + if (!fi.Find(phyPath)) + { + errorCodes.Add(::GetLastError()); + errorPaths.Add(phyPath); + continue; + } + int delimiter = filePath.ReverseFind((wchar_t)kDirDelimiter); + UString phyPrefixCur; + int phyParentCur = phyParent; + if (delimiter >= 0) + { + phyPrefixCur = filePath.Left(delimiter + 1); + phyParentCur = AddPrefix(phyParent, logParent, phyPrefixCur); + } + AddDirFileInfo(phyParentCur, logParent, fi, Items); + if (fi.IsDir()) + { + const UString name2 = fi.Name + (wchar_t)kDirDelimiter; + int parent = AddPrefix(phyParentCur, logParent, name2); + EnumerateDirectory(parent, parent, phyPrefix + phyPrefixCur + name2, errorPaths, errorCodes); + } + } + ReserveDown(); +} + +static HRESULT EnumerateDirItems(const NWildcard::CCensorNode &curNode, + int phyParent, int logParent, const UString &phyPrefix, + const UStringVector &addArchivePrefix, + CDirItems &dirItems, + bool enterToSubFolders, + IEnumDirItemCallback *callback, + UStringVector &errorPaths, + CRecordVector &errorCodes); + +static HRESULT EnumerateDirItems_Spec(const NWildcard::CCensorNode &curNode, + int phyParent, int logParent, const UString &curFolderName, + const UString &phyPrefix, + const UStringVector &addArchivePrefix, + CDirItems &dirItems, + bool enterToSubFolders, + IEnumDirItemCallback *callback, + UStringVector &errorPaths, + CRecordVector &errorCodes) + +{ + const UString name2 = curFolderName + (wchar_t)kDirDelimiter; + int parent = dirItems.AddPrefix(phyParent, logParent, name2); + int numItems = dirItems.Items.Size(); + HRESULT res = EnumerateDirItems(curNode, parent, parent, phyPrefix + name2, + addArchivePrefix, dirItems, enterToSubFolders, callback, errorPaths, errorCodes); + if (numItems == dirItems.Items.Size()) + dirItems.DeleteLastPrefix(); + return res; +} + + +static HRESULT EnumerateDirItems(const NWildcard::CCensorNode &curNode, + int phyParent, int logParent, const UString &phyPrefix, + const UStringVector &addArchivePrefix, // prefix from curNode + CDirItems &dirItems, + bool enterToSubFolders, + IEnumDirItemCallback *callback, + UStringVector &errorPaths, + CRecordVector &errorCodes) +{ + if (!enterToSubFolders) + if (curNode.NeedCheckSubDirs()) + enterToSubFolders = true; + if (callback) + RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), phyPrefix)); + + // 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 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 = phyPrefix + name; + NFind::CFileInfoW fi; + if (!fi.Find(fullPath)) + { + errorCodes.Add(::GetLastError()); + errorPaths.Add(fullPath); + continue; + } + bool isDir = fi.IsDir(); + if (isDir && !item.ForDir || !isDir && !item.ForFile) + { + errorCodes.Add((DWORD)E_FAIL); + errorPaths.Add(fullPath); + continue; + } + { + UStringVector pathParts; + pathParts.Add(fi.Name); + if (curNode.CheckPathToRoot(false, pathParts, !isDir)) + continue; + } + AddDirFileInfo(phyParent, logParent, fi, dirItems.Items); + 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 fi.Name. It's for shortnames support + } + + RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix, + 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 = phyPrefix + nextNode.Name; + NFind::CFileInfoW fi; + if (!fi.Find(fullPath)) + { + if (!nextNode.AreThereIncludeItems()) + continue; + errorCodes.Add(::GetLastError()); + errorPaths.Add(fullPath); + continue; + } + if (!fi.IsDir()) + { + errorCodes.Add((DWORD)E_FAIL); + errorPaths.Add(fullPath); + continue; + } + + RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix, + UStringVector(), dirItems, false, callback, errorPaths, errorCodes)); + } + return S_OK; + } + } + + + NFind::CEnumeratorW enumerator(phyPrefix + wchar_t(kAnyStringWildcard)); + for (int ttt = 0; ; ttt++) + { + NFind::CFileInfoW fi; + bool found; + if (!enumerator.Next(fi, found)) + { + errorCodes.Add(::GetLastError()); + errorPaths.Add(phyPrefix); + break; + } + if (!found) + break; + + if (callback && (ttt & 0xFF) == 0xFF) + RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), phyPrefix)); + const UString &name = fi.Name; + bool enterToSubFolders2 = enterToSubFolders; + UStringVector addArchivePrefixNew = addArchivePrefix; + addArchivePrefixNew.Add(name); + { + UStringVector addArchivePrefixNewTemp(addArchivePrefixNew); + if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fi.IsDir())) + continue; + } + if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir())) + { + AddDirFileInfo(phyParent, logParent, fi, dirItems.Items); + if (fi.IsDir()) + enterToSubFolders2 = true; + } + if (!fi.IsDir()) + 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_Spec(*nextNode, phyParent, logParent, name, phyPrefix, + addArchivePrefixNew, dirItems, enterToSubFolders2, callback, errorPaths, errorCodes)); + } + return S_OK; +} + +HRESULT EnumerateItems( + const NWildcard::CCensor &censor, + CDirItems &dirItems, + IEnumDirItemCallback *callback, + UStringVector &errorPaths, + CRecordVector &errorCodes) +{ + for (int i = 0; i < censor.Pairs.Size(); i++) + { + const NWildcard::CPair &pair = censor.Pairs[i]; + int phyParent = pair.Prefix.IsEmpty() ? -1 : dirItems.AddPrefix(-1, -1, pair.Prefix); + RINOK(EnumerateDirItems(pair.Head, phyParent, -1, pair.Prefix, UStringVector(), dirItems, false, + callback, errorPaths, errorCodes)); + } + dirItems.ReserveDown(); + return S_OK; +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.h b/src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.h new file mode 100644 index 000000000..d0ce950e3 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.h @@ -0,0 +1,25 @@ +// EnumDirItems.h + +#ifndef __ENUM_DIR_ITEMS_H +#define __ENUM_DIR_ITEMS_H + +#include "Common/Wildcard.h" +#include "Windows/FileFind.h" +#include "DirItem.h" + +void AddDirFileInfo(int phyParent, int logParent, + const NWindows::NFile::NFind::CFileInfoW &fi, CObjectVector &dirItems); + +struct IEnumDirItemCallback +{ + virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, const wchar_t *path) = 0; +}; + +HRESULT EnumerateItems( + const NWildcard::CCensor &censor, + CDirItems &dirItems, + IEnumDirItemCallback *callback, + UStringVector &errorPaths, + CRecordVector &errorCodes); + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ExitCode.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ExitCode.h new file mode 100644 index 000000000..b6d7d4dfc --- /dev/null +++ b/src/libs/7zip/win/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/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.cpp new file mode 100644 index 000000000..ca2c8c73d --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.cpp @@ -0,0 +1,263 @@ +// Extract.cpp + +#include "StdAfx.h" + +#include + +#include "Windows/FileDir.h" +#include "Windows/PropVariant.h" +#include "Windows/PropVariantConversions.h" + +#include "../Common/ExtractingFilePath.h" + +#include "Extract.h" +#include "SetProperties.h" + +using namespace NWindows; + +static HRESULT DecompressArchive( + const CArc &arc, + UInt64 packSize, + const NWildcard::CCensorNode &wildcardCensor, + const CExtractOptions &options, + IExtractCallbackUI *callback, + CArchiveExtractCallback *extractCallbackSpec, + UString &errorMessage, + UInt64 &stdInProcessed) +{ + stdInProcessed = 0; + IInArchive *archive = arc.Archive; + CRecordVector realIndices; + if (!options.StdInMode) + { + UInt32 numItems; + RINOK(archive->GetNumberOfItems(&numItems)); + + for (UInt32 i = 0; i < numItems; i++) + { + UString filePath; + RINOK(arc.GetItemPath(i, 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; + } + } + + UStringVector removePathParts; + + UString outDir = options.OutputDir; + outDir.Replace(L"*", GetCorrectFsPath(arc.DefaultName)); + #ifdef _WIN32 + // GetCorrectFullFsPath doesn't like "..". + // outDir.TrimRight(); + // outDir = GetCorrectFullFsPath(outDir); + #endif + + 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( + options.StdInMode ? &wildcardCensor : NULL, + &arc, + callback, + options.StdOutMode, options.TestMode, options.CalcCrc, + outDir, + removePathParts, + packSize); + + #if !defined(_7ZIP_ST) && !defined(_SFX) + RINOK(SetProperties(archive, options.Properties)); + #endif + + HRESULT result; + Int32 testMode = (options.TestMode && !options.CalcCrc) ? 1: 0; + if (options.StdInMode) + { + result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, extractCallbackSpec); + NCOM::CPropVariant prop; + if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK) + if (prop.vt == VT_UI8 || prop.vt == VT_UI4) + stdInProcessed = ConvertPropVariantToUInt64(prop); + } + else + result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, extractCallbackSpec); + + return callback->ExtractResult(result); +} + +HRESULT DecompressArchives( + CCodecs *codecs, const CIntVector &formatIndices, + UStringVector &arcPaths, UStringVector &arcPathsFull, + const NWildcard::CCensorNode &wildcardCensor, + const CExtractOptions &options, + IOpenCallbackUI *openCallback, + IExtractCallbackUI *extractCallback, + UString &errorMessage, + CDecompressStat &stat) +{ + stat.Clear(); + int i; + UInt64 totalPackSize = 0; + CRecordVector archiveSizes; + + int numArcs = options.StdInMode ? 1 : arcPaths.Size(); + + for (i = 0; i < numArcs; i++) + { + NFile::NFind::CFileInfoW fi; + fi.Size = 0; + if (!options.StdInMode) + { + const UString &arcPath = arcPaths[i]; + if (!fi.Find(arcPath)) + throw "there is no such archive"; + if (fi.IsDir()) + throw "can't decompress folder"; + } + archiveSizes.Add(fi.Size); + totalPackSize += fi.Size; + } + CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; + CMyComPtr ec(extractCallbackSpec); + bool multi = (numArcs > 1); + extractCallbackSpec->InitForMulti(multi, options.PathMode, options.OverwriteMode); + if (multi) + { + RINOK(extractCallback->SetTotal(totalPackSize)); + } + for (i = 0; i < numArcs; i++) + { + const UString &arcPath = arcPaths[i]; + NFile::NFind::CFileInfoW fi; + if (options.StdInMode) + { + fi.Size = 0; + fi.Attrib = 0; + } + else + { + if (!fi.Find(arcPath) || fi.IsDir()) + throw "there is no such archive"; + } + + #ifndef _NO_CRYPTO + openCallback->Open_ClearPasswordWasAskedFlag(); + #endif + + RINOK(extractCallback->BeforeOpen(arcPath)); + CArchiveLink archiveLink; + + CIntVector formatIndices2 = formatIndices; + #ifndef _SFX + if (formatIndices.IsEmpty()) + { + int pos = arcPath.ReverseFind(L'.'); + if (pos >= 0) + { + UString s = arcPath.Mid(pos + 1); + int index = codecs->FindFormatForExtension(s); + if (index >= 0 && s == L"001") + { + s = arcPath.Left(pos); + pos = s.ReverseFind(L'.'); + if (pos >= 0) + { + int index2 = codecs->FindFormatForExtension(s.Mid(pos + 1)); + if (index2 >= 0 && s.CompareNoCase(L"rar") != 0) + { + formatIndices2.Add(index2); + formatIndices2.Add(index); + } + } + } + } + } + #endif + HRESULT result = archiveLink.Open2(codecs, formatIndices2, options.StdInMode, NULL, arcPath, openCallback); + if (result == E_ABORT) + return result; + + bool crypted = false; + #ifndef _NO_CRYPTO + crypted = openCallback->Open_WasPasswordAsked(); + #endif + + RINOK(extractCallback->OpenResult(arcPath, result, crypted)); + if (result != S_OK) + continue; + + if (!options.StdInMode) + for (int v = 0; v < archiveLink.VolumePaths.Size(); v++) + { + int index = arcPathsFull.FindInSorted(archiveLink.VolumePaths[v]); + if (index >= 0 && index > i) + { + arcPaths.Delete(index); + arcPathsFull.Delete(index); + totalPackSize -= archiveSizes[index]; + archiveSizes.Delete(index); + numArcs = arcPaths.Size(); + } + } + if (archiveLink.VolumePaths.Size() != 0) + { + totalPackSize += archiveLink.VolumesSize; + RINOK(extractCallback->SetTotal(totalPackSize)); + } + + #ifndef _NO_CRYPTO + UString password; + RINOK(openCallback->Open_GetPasswordIfAny(password)); + if (!password.IsEmpty()) + { + RINOK(extractCallback->SetPassword(password)); + } + #endif + + for (int v = 0; v < archiveLink.Arcs.Size(); v++) + { + const UString &s = archiveLink.Arcs[v].ErrorMessage; + if (!s.IsEmpty()) + { + RINOK(extractCallback->MessageError(s)); + } + } + + CArc &arc = archiveLink.Arcs.Back(); + arc.MTimeDefined = (!options.StdInMode && !fi.IsDevice); + arc.MTime = fi.MTime; + + UInt64 packProcessed; + RINOK(DecompressArchive(arc, + fi.Size + archiveLink.VolumesSize, + wildcardCensor, options, extractCallback, extractCallbackSpec, errorMessage, packProcessed)); + if (!options.StdInMode) + packProcessed = fi.Size + archiveLink.VolumesSize; + extractCallbackSpec->LocalProgressSpec->InSize += packProcessed; + extractCallbackSpec->LocalProgressSpec->OutSize = extractCallbackSpec->UnpackSize; + if (!errorMessage.IsEmpty()) + return E_FAIL; + } + stat.NumFolders = extractCallbackSpec->NumFolders; + stat.NumFiles = extractCallbackSpec->NumFiles; + stat.UnpackSize = extractCallbackSpec->UnpackSize; + stat.CrcSum = extractCallbackSpec->CrcSum; + + stat.NumArchives = arcPaths.Size(); + stat.PackSize = extractCallbackSpec->LocalProgressSpec->InSize; + return S_OK; +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.h b/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.h new file mode 100644 index 000000000..5a939ed23 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.h @@ -0,0 +1,76 @@ +// Extract.h + +#ifndef __EXTRACT_H +#define __EXTRACT_H + +#include "Windows/FileFind.h" + +#include "../../Archive/IArchive.h" + +#include "ArchiveExtractCallback.h" +#include "ArchiveOpenCallback.h" +#include "ExtractMode.h" +#include "Property.h" + +#include "../Common/LoadCodecs.h" + +struct CExtractOptions +{ + bool StdInMode; + bool StdOutMode; + bool YesToAll; + bool TestMode; + bool CalcCrc; + NExtract::NPathMode::EEnum PathMode; + NExtract::NOverwriteMode::EEnum OverwriteMode; + UString OutputDir; + + // bool ShowDialog; + // bool PasswordEnabled; + // UString Password; + #if !defined(_7ZIP_ST) && !defined(_SFX) + CObjectVector Properties; + #endif + + #ifdef EXTERNAL_CODECS + CCodecs *Codecs; + #endif + + CExtractOptions(): + StdInMode(false), + StdOutMode(false), + YesToAll(false), + TestMode(false), + CalcCrc(false), + PathMode(NExtract::NPathMode::kFullPathnames), + OverwriteMode(NExtract::NOverwriteMode::kAskBefore) + {} +}; + +struct CDecompressStat +{ + UInt64 NumArchives; + UInt64 UnpackSize; + UInt64 PackSize; + UInt64 NumFolders; + UInt64 NumFiles; + UInt32 CrcSum; + + void Clear() + { + NumArchives = UnpackSize = PackSize = NumFolders = NumFiles = 0; + CrcSum = 0; + } +}; + +HRESULT DecompressArchives( + CCodecs *codecs, const CIntVector &formatIndices, + UStringVector &archivePaths, UStringVector &archivePathsFull, + const NWildcard::CCensorNode &wildcardCensor, + const CExtractOptions &options, + IOpenCallbackUI *openCallback, + IExtractCallbackUI *extractCallback, + UString &errorMessage, + CDecompressStat &stat); + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractMode.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractMode.h new file mode 100644 index 000000000..b448fb30a --- /dev/null +++ b/src/libs/7zip/win/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/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.cpp new file mode 100644 index 000000000..8f31708b6 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.cpp @@ -0,0 +1,142 @@ +// ExtractingFilePath.cpp + +#include "StdAfx.h" + +#include "../../../../C/Types.h" + +#include "Common/Wildcard.h" + +#include "ExtractingFilePath.h" + +static UString ReplaceIncorrectChars(const UString &s) +{ + #ifdef _WIN32 + UString res; + for (int i = 0; i < s.Length(); i++) + { + wchar_t c = s[i]; + if (c < 0x20 || c == '*' || c == '?' || c == '<' || c == '>' || c == '|' || c == ':' || c == '"') + c = '_'; + res += c; + } + res.TrimRight(); + while (!res.IsEmpty() && res[res.Length() - 1] == '.') + res.Delete(res.Length() - 1); + return res; + #else + return s; + #endif +} + +#ifdef _WIN32 +static const wchar_t *g_ReservedNames[] = +{ + L"CON", L"PRN", L"AUX", L"NUL" +}; + +static bool CheckTail(const UString &name, int len) +{ + int dotPos = name.Find(L'.'); + if (dotPos < 0) + dotPos = name.Length(); + UString s = name.Left(dotPos); + s.TrimRight(); + return (s.Length() != len); +} + +static bool CheckNameNum(const UString &name, const wchar_t *reservedName) +{ + int len = MyStringLen(reservedName); + if (name.Length() <= len) + return true; + if (name.Left(len).CompareNoCase(reservedName) != 0) + return true; + wchar_t c = name[len]; + if (c < L'0' || c > L'9') + return true; + return CheckTail(name, len + 1); +} + +static bool IsSupportedName(const UString &name) +{ + for (int i = 0; i < sizeof(g_ReservedNames) / sizeof(g_ReservedNames[0]); i++) + { + const wchar_t *reservedName = g_ReservedNames[i]; + int len = MyStringLen(reservedName); + if (name.Length() < len) + continue; + if (name.Left(len).CompareNoCase(reservedName) != 0) + continue; + if (!CheckTail(name, len)) + return false; + } + if (!CheckNameNum(name, L"COM")) + return false; + return CheckNameNum(name, L"LPT"); +} +#endif + +static UString GetCorrectFileName(const UString &path) +{ + if (path == L".." || path == L".") + return UString(); + return ReplaceIncorrectChars(path); +} + +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 + { + #ifdef _WIN32 + if (!IsSupportedName(s)) + s = (UString)L"_" + s; + #endif + i++; + } + } +} + +UString MakePathNameFromParts(const UStringVector &parts) +{ + UString result; + for (int i = 0; i < parts.Size(); i++) + { + if (i != 0) + result += WCHAR_PATH_SEPARATOR; + result += parts[i]; + } + return result; +} + +UString GetCorrectFsPath(const UString &path) +{ + UString res = GetCorrectFileName(path); + #ifdef _WIN32 + if (!IsSupportedName(res)) + res = (UString)L"_" + res; + #endif + return res; +} + +UString GetCorrectFullFsPath(const UString &path) +{ + UStringVector parts; + SplitPathToParts(path, parts); + for (int i = 0; i < parts.Size(); i++) + { + UString &s = parts[i]; + #ifdef _WIN32 + while (!s.IsEmpty() && s[s.Length() - 1] == '.') + s.Delete(s.Length() - 1); + if (!IsSupportedName(s)) + s = (UString)L"_" + s; + #endif + } + return MakePathNameFromParts(parts); +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.h new file mode 100644 index 000000000..da28bfc23 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.h @@ -0,0 +1,13 @@ +// ExtractingFilePath.h + +#ifndef __EXTRACTING_FILE_PATH_H +#define __EXTRACTING_FILE_PATH_H + +#include "Common/MyString.h" + +UString MakePathNameFromParts(const UStringVector &parts); +void MakeCorrectPath(UStringVector &pathParts); +UString GetCorrectFsPath(const UString &path); +UString GetCorrectFullFsPath(const UString &path); + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/IFileExtractCallback.h b/src/libs/7zip/win/CPP/7zip/UI/Common/IFileExtractCallback.h new file mode 100644 index 000000000..e8dcdce5f --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/IFileExtractCallback.h @@ -0,0 +1,46 @@ +// IFileExtractCallback.h + +#ifndef __IFILEEXTRACTCALLBACK_H +#define __IFILEEXTRACTCALLBACK_H + +#include "Common/MyString.h" +#include "../../IDecl.h" + +namespace NOverwriteAnswer +{ + enum EEnum + { + kYes, + kYesToAll, + kNo, + kNoToAll, + kAutoRename, + kCancel + }; +} + +DECL_INTERFACE_SUB(IFolderArchiveExtractCallback, IProgress, 0x01, 0x07) +{ +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, bool isFolder, 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; + + #ifndef _NO_CRYPTO + virtual HRESULT SetPassword(const UString &password) = 0; + #endif +}; + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.cpp new file mode 100644 index 000000000..856e47fbc --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.cpp @@ -0,0 +1,681 @@ +// LoadCodecs.cpp + +#include "StdAfx.h" + +#include "LoadCodecs.h" + +#include "../../../Common/MyCom.h" +#ifdef NEW_FOLDER_INTERFACE +#include "../../../Common/StringToInt.h" +#endif +#include "../../../Windows/PropVariant.h" + +#include "../../ICoder.h" +#include "../../Common/RegisterArc.h" + +#ifdef EXTERNAL_CODECS +#include "../../../Windows/FileFind.h" +#include "../../../Windows/DLL.h" +#ifdef NEW_FOLDER_INTERFACE +#include "../../../Windows/ResourceString.h" +static const UINT kIconTypesResId = 100; +#endif + +#ifdef _WIN32 +#include "Windows/Registry.h" +#endif + +using namespace NWindows; +using namespace NFile; + +#ifdef _WIN32 +extern HINSTANCE g_hInstance; +#endif + +static CSysString GetLibraryFolderPrefix() +{ + #ifdef _WIN32 + TCHAR fullPath[MAX_PATH + 1]; + ::GetModuleFileName(g_hInstance, fullPath, MAX_PATH); + CSysString path = fullPath; + int pos = path.ReverseFind(TEXT(CHAR_PATH_SEPARATOR)); + return path.Left(pos + 1); + #else + return CSysString(); // FIX IT + #endif +} + +#define kCodecsFolderName TEXT("Codecs") +#define kFormatsFolderName TEXT("Formats") +static const TCHAR *kMainDll = TEXT("7z.dll"); + +#ifdef _WIN32 +static LPCTSTR kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip"); +static LPCTSTR kProgramPathValue = TEXT("Path"); +static bool ReadPathFromRegistry(HKEY baseKey, CSysString &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 + +CSysString GetBaseFolderPrefixFromRegistry() +{ + CSysString moduleFolderPrefix = GetLibraryFolderPrefix(); + #ifdef _WIN32 + if (!NFind::DoesFileExist(moduleFolderPrefix + kMainDll) && + !NFind::DoesDirExist(moduleFolderPrefix + kCodecsFolderName) && + !NFind::DoesDirExist(moduleFolderPrefix + kFormatsFolderName)) + { + CSysString path; + if (ReadPathFromRegistry(HKEY_CURRENT_USER, path)) + return path; + if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, path)) + return path; + } + #endif + return moduleFolderPrefix; +} + +typedef UInt32 (WINAPI *GetNumberOfMethodsFunc)(UInt32 *numMethods); +typedef UInt32 (WINAPI *GetNumberOfFormatsFunc)(UInt32 *numFormats); +typedef UInt32 (WINAPI *GetHandlerPropertyFunc)(PROPID propID, PROPVARIANT *value); +typedef UInt32 (WINAPI *GetHandlerPropertyFunc2)(UInt32 index, PROPID propID, PROPVARIANT *value); +typedef UInt32 (WINAPI *CreateObjectFunc)(const GUID *clsID, const GUID *iid, void **outObject); +typedef UInt32 (WINAPI *SetLargePageModeFunc)(); + + +static HRESULT GetCoderClass(GetMethodPropertyFunc getMethodProperty, UInt32 index, + PROPID propId, CLSID &clsId, bool &isAssigned) +{ + NWindows::NCOM::CPropVariant prop; + isAssigned = false; + RINOK(getMethodProperty(index, propId, &prop)); + if (prop.vt == VT_BSTR) + { + isAssigned = true; + clsId = *(const GUID *)prop.bstrVal; + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +HRESULT CCodecs::LoadCodecs() +{ + CCodecLib &lib = Libs.Back(); + lib.GetMethodProperty = (GetMethodPropertyFunc)lib.Lib.GetProc("GetMethodProperty"); + if (lib.GetMethodProperty == NULL) + return S_OK; + + UInt32 numMethods = 1; + GetNumberOfMethodsFunc getNumberOfMethodsFunc = (GetNumberOfMethodsFunc)lib.Lib.GetProc("GetNumberOfMethods"); + if (getNumberOfMethodsFunc != NULL) + { + RINOK(getNumberOfMethodsFunc(&numMethods)); + } + + for(UInt32 i = 0; i < numMethods; i++) + { + CDllCodecInfo info; + info.LibIndex = Libs.Size() - 1; + info.CodecIndex = i; + + RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned)); + RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned)); + + Codecs.Add(info); + } + return S_OK; +} + +static HRESULT ReadProp( + GetHandlerPropertyFunc getProp, + GetHandlerPropertyFunc2 getProp2, + UInt32 index, PROPID propID, NCOM::CPropVariant &prop) +{ + if (getProp2) + return getProp2(index, propID, &prop);; + return getProp(propID, &prop); +} + +static HRESULT ReadBoolProp( + GetHandlerPropertyFunc getProp, + GetHandlerPropertyFunc2 getProp2, + UInt32 index, PROPID propID, bool &res) +{ + NCOM::CPropVariant prop; + RINOK(ReadProp(getProp, getProp2, index, propID, prop)); + if (prop.vt == VT_BOOL) + res = VARIANT_BOOLToBool(prop.boolVal); + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +static HRESULT ReadStringProp( + GetHandlerPropertyFunc getProp, + GetHandlerPropertyFunc2 getProp2, + UInt32 index, PROPID propID, UString &res) +{ + NCOM::CPropVariant prop; + RINOK(ReadProp(getProp, getProp2, index, propID, prop)); + if (prop.vt == VT_BSTR) + res = prop.bstrVal; + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +#endif + +static const unsigned int kNumArcsMax = 48; +static unsigned int g_NumArcs = 0; +static const CArcInfo *g_Arcs[kNumArcsMax]; +void RegisterArc(const CArcInfo *arcInfo) +{ + if (g_NumArcs < kNumArcsMax) + g_Arcs[g_NumArcs++] = arcInfo; +} + +static void SplitString(const UString &srcString, UStringVector &destStrings) +{ + destStrings.Clear(); + UString s; + int len = srcString.Length(); + if (len == 0) + return; + for (int i = 0; i < len; i++) + { + wchar_t c = srcString[i]; + if (c == L' ') + { + if (!s.IsEmpty()) + { + destStrings.Add(s); + s.Empty(); + } + } + else + s += c; + } + if (!s.IsEmpty()) + destStrings.Add(s); +} + +void CArcInfoEx::AddExts(const wchar_t *ext, const wchar_t *addExt) +{ + UStringVector exts, addExts; + if (ext != 0) + SplitString(ext, exts); + if (addExt != 0) + SplitString(addExt, addExts); + for (int i = 0; i < exts.Size(); i++) + { + CArcExtInfo extInfo; + extInfo.Ext = exts[i]; + if (i < addExts.Size()) + { + extInfo.AddExt = addExts[i]; + if (extInfo.AddExt == L"*") + extInfo.AddExt.Empty(); + } + Exts.Add(extInfo); + } +} + +#ifdef EXTERNAL_CODECS + +HRESULT CCodecs::LoadFormats() +{ + const NDLL::CLibrary &lib = Libs.Back().Lib; + GetHandlerPropertyFunc getProp = 0; + GetHandlerPropertyFunc2 getProp2 = (GetHandlerPropertyFunc2)lib.GetProc("GetHandlerProperty2"); + if (getProp2 == NULL) + { + getProp = (GetHandlerPropertyFunc)lib.GetProc("GetHandlerProperty"); + if (getProp == NULL) + return S_OK; + } + + UInt32 numFormats = 1; + GetNumberOfFormatsFunc getNumberOfFormats = (GetNumberOfFormatsFunc)lib.GetProc("GetNumberOfFormats"); + if (getNumberOfFormats != NULL) + { + RINOK(getNumberOfFormats(&numFormats)); + } + if (getProp2 == NULL) + numFormats = 1; + + for(UInt32 i = 0; i < numFormats; i++) + { + CArcInfoEx item; + item.LibIndex = Libs.Size() - 1; + item.FormatIndex = i; + + RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kName, item.Name)); + + NCOM::CPropVariant prop; + if (ReadProp(getProp, getProp2, i, NArchive::kClassID, prop) != S_OK) + continue; + if (prop.vt != VT_BSTR) + continue; + item.ClassID = *(const GUID *)prop.bstrVal; + prop.Clear(); + + UString ext, addExt; + RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kExtension, ext)); + RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kAddExtension, addExt)); + item.AddExts(ext, addExt); + + ReadBoolProp(getProp, getProp2, i, NArchive::kUpdate, item.UpdateEnabled); + if (item.UpdateEnabled) + ReadBoolProp(getProp, getProp2, i, NArchive::kKeepName, item.KeepName); + + if (ReadProp(getProp, getProp2, i, 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); + } + Formats.Add(item); + } + return S_OK; +} + +#ifdef NEW_FOLDER_INTERFACE +void CCodecIcons::LoadIcons(HMODULE m) +{ + UString iconTypes = MyLoadStringW(m, kIconTypesResId); + UStringVector pairs; + SplitString(iconTypes, pairs); + for (int i = 0; i < pairs.Size(); i++) + { + const UString &s = pairs[i]; + int pos = s.Find(L':'); + CIconPair iconPair; + iconPair.IconIndex = -1; + if (pos < 0) + pos = s.Length(); + else + { + UString num = s.Mid(pos + 1); + if (!num.IsEmpty()) + { + const wchar_t *end; + iconPair.IconIndex = (UInt32)ConvertStringToUInt64(num, &end); + if (*end != L'\0') + continue; + } + } + iconPair.Ext = s.Left(pos); + IconPairs.Add(iconPair); + } +} + +bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const +{ + iconIndex = -1; + for (int i = 0; i < IconPairs.Size(); i++) + { + const CIconPair &pair = IconPairs[i]; + if (ext.CompareNoCase(pair.Ext) == 0) + { + iconIndex = pair.IconIndex; + return true; + } + } + return false; +} +#endif + +#ifdef _7ZIP_LARGE_PAGES +extern "C" +{ + extern SIZE_T g_LargePageSize; +} +#endif + +HRESULT CCodecs::LoadDll(const CSysString &dllPath, bool needCheckDll) +{ + if (needCheckDll) + { + NDLL::CLibrary library; + if (!library.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE)) + return S_OK; + } + Libs.Add(CCodecLib()); + CCodecLib &lib = Libs.Back(); + #ifdef NEW_FOLDER_INTERFACE + lib.Path = dllPath; + #endif + bool used = false; + HRESULT res = S_OK; + if (lib.Lib.Load(dllPath)) + { + #ifdef NEW_FOLDER_INTERFACE + lib.LoadIcons(); + #endif + + #ifdef _7ZIP_LARGE_PAGES + if (g_LargePageSize != 0) + { + SetLargePageModeFunc setLargePageMode = (SetLargePageModeFunc)lib.Lib.GetProc("SetLargePageMode"); + if (setLargePageMode != 0) + setLargePageMode(); + } + #endif + + lib.CreateObject = (CreateObjectFunc)lib.Lib.GetProc("CreateObject"); + if (lib.CreateObject != 0) + { + int startSize = Codecs.Size(); + res = LoadCodecs(); + used = (Codecs.Size() != startSize); + if (res == S_OK) + { + startSize = Formats.Size(); + res = LoadFormats(); + used = used || (Formats.Size() != startSize); + } + } + } + if (!used) + Libs.DeleteBack(); + return res; +} + +HRESULT CCodecs::LoadDllsFromFolder(const CSysString &folderPrefix) +{ + NFile::NFind::CEnumerator enumerator(folderPrefix + CSysString(TEXT("*"))); + NFile::NFind::CFileInfo fi; + while (enumerator.Next(fi)) + { + if (fi.IsDir()) + continue; + RINOK(LoadDll(folderPrefix + fi.Name, true)); + } + return S_OK; +} + +#endif + +#ifndef _SFX +static inline void SetBuffer(CByteBuffer &bb, const Byte *data, int size) +{ + bb.SetCapacity(size); + memmove((Byte *)bb, data, size); +} +#endif + +HRESULT CCodecs::Load() +{ + #ifdef NEW_FOLDER_INTERFACE + InternalIcons.LoadIcons(g_hInstance); + #endif + + Formats.Clear(); + #ifdef EXTERNAL_CODECS + Codecs.Clear(); + #endif + for (UInt32 i = 0; i < g_NumArcs; i++) + { + const CArcInfo &arc = *g_Arcs[i]; + CArcInfoEx item; + item.Name = arc.Name; + item.CreateInArchive = arc.CreateInArchive; + item.CreateOutArchive = arc.CreateOutArchive; + item.AddExts(arc.Ext, arc.AddExt); + item.UpdateEnabled = (arc.CreateOutArchive != 0); + item.KeepName = arc.KeepName; + + #ifndef _SFX + SetBuffer(item.StartSignature, arc.Signature, arc.SignatureSize); + #endif + Formats.Add(item); + } + #ifdef EXTERNAL_CODECS + const CSysString baseFolder = GetBaseFolderPrefixFromRegistry(); + RINOK(LoadDll(baseFolder + kMainDll, false)); + RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName TEXT(STRING_PATH_SEPARATOR))); + RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName TEXT(STRING_PATH_SEPARATOR))); + #endif + return S_OK; +} + +#ifndef _SFX + +int CCodecs::FindFormatForArchiveName(const UString &arcPath) const +{ + int slashPos1 = arcPath.ReverseFind(WCHAR_PATH_SEPARATOR); + int slashPos2 = arcPath.ReverseFind(L'.'); + int dotPos = arcPath.ReverseFind(L'.'); + if (dotPos < 0 || dotPos < slashPos1 || dotPos < slashPos2) + return -1; + UString ext = arcPath.Mid(dotPos + 1); + for (int i = 0; i < Formats.Size(); i++) + { + const CArcInfoEx &arc = Formats[i]; + if (!arc.UpdateEnabled) + continue; + if (arc.FindExtension(ext) >= 0) + return i; + } + return -1; +} + +int CCodecs::FindFormatForExtension(const UString &ext) const +{ + if (ext.IsEmpty()) + return -1; + for (int i = 0; i < Formats.Size(); i++) + if (Formats[i].FindExtension(ext) >= 0) + return i; + return -1; +} + +int CCodecs::FindFormatForArchiveType(const UString &arcType) const +{ + for (int i = 0; i < Formats.Size(); i++) + if (Formats[i].Name.CompareNoCase(arcType) == 0) + return i; + return -1; +} + +bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const +{ + formatIndices.Clear(); + for (int pos = 0; pos < arcType.Length();) + { + int pos2 = arcType.Find('.', pos); + if (pos2 < 0) + pos2 = arcType.Length(); + const UString name = arcType.Mid(pos, pos2 - pos); + int index = FindFormatForArchiveType(name); + if (index < 0 && name != L"*") + { + formatIndices.Clear(); + return false; + } + formatIndices.Add(index); + pos = pos2 + 1; + } + return true; +} + +#endif + +#ifdef EXTERNAL_CODECS + +#ifdef EXPORT_CODECS +extern unsigned int g_NumCodecs; +STDAPI CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject); +STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); +// STDAPI GetNumberOfMethods(UInt32 *numCodecs); +#endif + +STDMETHODIMP CCodecs::GetNumberOfMethods(UInt32 *numMethods) +{ + *numMethods = + #ifdef EXPORT_CODECS + g_NumCodecs + + #endif + Codecs.Size(); + return S_OK; +} + +STDMETHODIMP CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + return GetMethodProperty(index, propID, value); + #endif + + const CDllCodecInfo &ci = Codecs[index + #ifdef EXPORT_CODECS + - g_NumCodecs + #endif + ]; + + if (propID == NMethodPropID::kDecoderIsAssigned) + { + NWindows::NCOM::CPropVariant propVariant; + propVariant = ci.DecoderIsAssigned; + propVariant.Detach(value); + return S_OK; + } + if (propID == NMethodPropID::kEncoderIsAssigned) + { + NWindows::NCOM::CPropVariant propVariant; + propVariant = ci.EncoderIsAssigned; + propVariant.Detach(value); + return S_OK; + } + return Libs[ci.LibIndex].GetMethodProperty(ci.CodecIndex, propID, value); +} + +STDMETHODIMP CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder) +{ + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + return CreateCoder2(false, index, iid, coder); + #endif + const CDllCodecInfo &ci = Codecs[index + #ifdef EXPORT_CODECS + - g_NumCodecs + #endif + ]; + if (ci.DecoderIsAssigned) + return Libs[ci.LibIndex].CreateObject(&ci.Decoder, iid, (void **)coder); + return S_OK; +} + +STDMETHODIMP CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder) +{ + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + return CreateCoder2(true, index, iid, coder); + #endif + const CDllCodecInfo &ci = Codecs[index + #ifdef EXPORT_CODECS + - g_NumCodecs + #endif + ]; + if (ci.EncoderIsAssigned) + return Libs[ci.LibIndex].CreateObject(&ci.Encoder, iid, (void **)coder); + return S_OK; +} + +HRESULT CCodecs::CreateCoder(const UString &name, bool encode, CMyComPtr &coder) const +{ + for (int i = 0; i < Codecs.Size(); i++) + { + const CDllCodecInfo &codec = Codecs[i]; + if (encode && !codec.EncoderIsAssigned || !encode && !codec.DecoderIsAssigned) + continue; + const CCodecLib &lib = Libs[codec.LibIndex]; + UString res; + NWindows::NCOM::CPropVariant prop; + RINOK(lib.GetMethodProperty(codec.CodecIndex, NMethodPropID::kName, &prop)); + if (prop.vt == VT_BSTR) + res = prop.bstrVal; + else if (prop.vt != VT_EMPTY) + continue; + if (name.CompareNoCase(res) == 0) + return lib.CreateObject(encode ? &codec.Encoder : &codec.Decoder, &IID_ICompressCoder, (void **)&coder); + } + return CLASS_E_CLASSNOTAVAILABLE; +} + +int CCodecs::GetCodecLibIndex(UInt32 index) +{ + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + return -1; + #endif + #ifdef EXTERNAL_CODECS + const CDllCodecInfo &ci = Codecs[index + #ifdef EXPORT_CODECS + - g_NumCodecs + #endif + ]; + return ci.LibIndex; + #else + return -1; + #endif +} + +bool CCodecs::GetCodecEncoderIsAssigned(UInt32 index) +{ + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + { + NWindows::NCOM::CPropVariant prop; + if (GetProperty(index, NMethodPropID::kEncoder, &prop) == S_OK) + if (prop.vt != VT_EMPTY) + return true; + return false; + } + #endif + #ifdef EXTERNAL_CODECS + const CDllCodecInfo &ci = Codecs[index + #ifdef EXPORT_CODECS + - g_NumCodecs + #endif + ]; + return ci.EncoderIsAssigned; + #else + return false; + #endif +} + +HRESULT CCodecs::GetCodecId(UInt32 index, UInt64 &id) +{ + UString s; + NWindows::NCOM::CPropVariant prop; + RINOK(GetProperty(index, NMethodPropID::kID, &prop)); + if (prop.vt != VT_UI8) + return E_INVALIDARG; + id = prop.uhVal.QuadPart; + return S_OK; +} + +UString CCodecs::GetCodecName(UInt32 index) +{ + UString s; + NWindows::NCOM::CPropVariant prop; + if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK) + if (prop.vt == VT_BSTR) + s = prop.bstrVal; + return s; +} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.h b/src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.h new file mode 100644 index 000000000..a633dd2e1 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.h @@ -0,0 +1,235 @@ +// LoadCodecs.h + +#ifndef __LOADCODECS_H +#define __LOADCODECS_H + +#include "../../../Common/Types.h" +#include "../../../Common/MyCom.h" +#include "../../../Common/MyString.h" +#include "../../../Common/Buffer.h" +#include "../../ICoder.h" + +#ifdef EXTERNAL_CODECS +#include "../../../Windows/DLL.h" +#endif + +struct CDllCodecInfo +{ + CLSID Encoder; + CLSID Decoder; + bool EncoderIsAssigned; + bool DecoderIsAssigned; + int LibIndex; + UInt32 CodecIndex; +}; + +#include "../../Archive/IArchive.h" + +typedef IInArchive * (*CreateInArchiveP)(); +typedef IOutArchive * (*CreateOutArchiveP)(); + +struct CArcExtInfo +{ + UString Ext; + UString AddExt; + CArcExtInfo() {} + CArcExtInfo(const UString &ext): Ext(ext) {} + CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {} +}; + + +struct CArcInfoEx +{ + #ifdef EXTERNAL_CODECS + int LibIndex; + UInt32 FormatIndex; + CLSID ClassID; + #endif + bool UpdateEnabled; + CreateInArchiveP CreateInArchive; + CreateOutArchiveP CreateOutArchive; + UString Name; + CObjectVector Exts; + #ifndef _SFX + CByteBuffer StartSignature; + // CByteBuffer FinishSignature; + #ifdef NEW_FOLDER_INTERFACE + UStringVector AssociateExts; + #endif + #endif + bool KeepName; + UString GetMainExt() const + { + if (Exts.IsEmpty()) + return UString(); + return Exts[0].Ext; + } + int FindExtension(const UString &ext) const + { + for (int i = 0; i < Exts.Size(); i++) + if (ext.CompareNoCase(Exts[i].Ext) == 0) + return i; + return -1; + } + UString GetAllExtensions() const + { + UString s; + for (int i = 0; i < Exts.Size(); i++) + { + if (i > 0) + s += ' '; + s += Exts[i].Ext; + } + return s; + } + + void AddExts(const wchar_t* ext, const wchar_t* addExt); + + CArcInfoEx(): + #ifdef EXTERNAL_CODECS + LibIndex(-1), + #endif + UpdateEnabled(false), + CreateInArchive(0), CreateOutArchive(0), + KeepName(false) + #ifndef _SFX + #endif + {} +}; + +#ifdef EXTERNAL_CODECS +typedef UInt32 (WINAPI *GetMethodPropertyFunc)(UInt32 index, PROPID propID, PROPVARIANT *value); +typedef UInt32 (WINAPI *CreateObjectFunc)(const GUID *clsID, const GUID *interfaceID, void **outObject); + + +#ifdef NEW_FOLDER_INTERFACE +struct CCodecIcons +{ + struct CIconPair + { + UString Ext; + int IconIndex; + }; + CObjectVector IconPairs; + void LoadIcons(HMODULE m); + bool FindIconIndex(const UString &ext, int &iconIndex) const; +}; +#endif + +struct CCodecLib +#ifdef NEW_FOLDER_INTERFACE +: public CCodecIcons +#endif +{ + NWindows::NDLL::CLibrary Lib; + GetMethodPropertyFunc GetMethodProperty; + CreateObjectFunc CreateObject; + #ifdef NEW_FOLDER_INTERFACE + CSysString Path; + void LoadIcons() { CCodecIcons::LoadIcons((HMODULE)Lib); } + #endif + CCodecLib(): GetMethodProperty(0) {} +}; +#endif + +class CCodecs: + #ifdef EXTERNAL_CODECS + public ICompressCodecsInfo, + #else + public IUnknown, + #endif + public CMyUnknownImp +{ +public: + #ifdef EXTERNAL_CODECS + CObjectVector Libs; + CObjectVector Codecs; + + #ifdef NEW_FOLDER_INTERFACE + CCodecIcons InternalIcons; + #endif + + HRESULT LoadCodecs(); + HRESULT LoadFormats(); + HRESULT LoadDll(const CSysString &path, bool needCheckDll); + HRESULT LoadDllsFromFolder(const CSysString &folderPrefix); + + HRESULT CreateArchiveHandler(const CArcInfoEx &ai, void **archive, bool outHandler) const + { + return Libs[ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive); + } + #endif + +public: + CObjectVector Formats; + HRESULT Load(); + + #ifndef _SFX + int FindFormatForArchiveName(const UString &arcPath) const; + int FindFormatForExtension(const UString &ext) const; + int FindFormatForArchiveType(const UString &arcType) const; + bool FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const; + #endif + + MY_UNKNOWN_IMP + + #ifdef EXTERNAL_CODECS + STDMETHOD(GetNumberOfMethods)(UInt32 *numMethods); + STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value); + STDMETHOD(CreateDecoder)(UInt32 index, const GUID *interfaceID, void **coder); + STDMETHOD(CreateEncoder)(UInt32 index, const GUID *interfaceID, void **coder); + #endif + + int GetCodecLibIndex(UInt32 index); + bool GetCodecEncoderIsAssigned(UInt32 index); + HRESULT GetCodecId(UInt32 index, UInt64 &id); + UString GetCodecName(UInt32 index); + + HRESULT CreateInArchive(int formatIndex, CMyComPtr &archive) const + { + const CArcInfoEx &ai = Formats[formatIndex]; + #ifdef EXTERNAL_CODECS + if (ai.LibIndex < 0) + #endif + { + archive = ai.CreateInArchive(); + return S_OK; + } + #ifdef EXTERNAL_CODECS + return CreateArchiveHandler(ai, (void **)&archive, false); + #endif + } + HRESULT CreateOutArchive(int formatIndex, CMyComPtr &archive) const + { + const CArcInfoEx &ai = Formats[formatIndex]; + #ifdef EXTERNAL_CODECS + if (ai.LibIndex < 0) + #endif + { + archive = ai.CreateOutArchive(); + return S_OK; + } + #ifdef EXTERNAL_CODECS + return CreateArchiveHandler(ai, (void **)&archive, true); + #endif + } + int FindOutFormatFromName(const UString &name) const + { + for (int i = 0; i < Formats.Size(); i++) + { + const CArcInfoEx &arc = Formats[i]; + if (!arc.UpdateEnabled) + continue; + if (arc.Name.CompareNoCase(name) == 0) + return i; + } + return -1; + } + + #ifdef EXTERNAL_CODECS + HRESULT CreateCoder(const UString &name, bool encode, CMyComPtr &coder) const; + #endif + +}; + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.cpp new file mode 100644 index 000000000..56a630467 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.cpp @@ -0,0 +1,536 @@ +// OpenArchive.cpp + +#include "StdAfx.h" + +#include "Common/Wildcard.h" + +#include "Windows/FileDir.h" +#include "Windows/PropVariant.h" + +#include "../../Common/FileStreams.h" +#include "../../Common/StreamUtils.h" + +#include "DefaultName.h" +#include "OpenArchive.h" + +using namespace NWindows; + +// Static-SFX (for Linux) can be big. +const UInt64 kMaxCheckStartPosition = 1 << 22; + +HRESULT GetArchiveItemBoolProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result) +{ + NCOM::CPropVariant prop; + result = false; + RINOK(archive->GetProperty(index, propID, &prop)); + if (prop.vt == VT_BOOL) + result = VARIANT_BOOLToBool(prop.boolVal); + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result) +{ + return GetArchiveItemBoolProp(archive, index, kpidIsDir, result); +} + +HRESULT CArc::GetItemPath(UInt32 index, UString &result) const +{ + { + 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; + } + if (result.IsEmpty()) + { + result = DefaultName; + NCOM::CPropVariant prop; + RINOK(Archive->GetProperty(index, kpidExtension, &prop)); + if (prop.vt == VT_BSTR) + { + result += L'.'; + result += prop.bstrVal; + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + } + return S_OK; +} + +HRESULT CArc::GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const +{ + NCOM::CPropVariant prop; + defined = false; + ft.dwHighDateTime = ft.dwLowDateTime = 0; + RINOK(Archive->GetProperty(index, kpidMTime, &prop)); + if (prop.vt == VT_FILETIME) + { + ft = prop.filetime; + defined = true; + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + else if (MTimeDefined) + { + ft = MTime; + defined = true; + } + return S_OK; +} + +#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 + +#ifdef UNDER_CE +static const int kNumHashBytes = 1; +#define HASH_VAL(buf, pos) ((buf)[pos]) +#else +static const int kNumHashBytes = 2; +#define HASH_VAL(buf, pos) ((buf)[pos] | ((UInt32)(buf)[pos + 1] << 8)) +#endif + + +HRESULT CArc::OpenStream( + CCodecs *codecs, + int formatIndex, + IInStream *stream, + ISequentialInStream *seqStream, + IArchiveOpenCallback *callback) +{ + Archive.Release(); + ErrorMessage.Empty(); + const UString fileName = ExtractFileNameFromPath(Path); + UString extension; + { + int dotPos = fileName.ReverseFind(L'.'); + if (dotPos >= 0) + extension = fileName.Mid(dotPos + 1); + } + CIntVector orderIndices; + if (formatIndex >= 0) + orderIndices.Add(formatIndex); + else + { + + int i; + int numFinded = 0; + for (i = 0; i < codecs->Formats.Size(); i++) + if (codecs->Formats[i].FindExtension(extension) >= 0) + orderIndices.Insert(numFinded++, i); + else + orderIndices.Add(i); + + if (!stream) + { + if (numFinded != 1) + return E_NOTIMPL; + orderIndices.DeleteFrom(1); + } + + #ifndef _SFX + if (orderIndices.Size() >= 2 && (numFinded == 0 || extension.CompareNoCase(L"exe") == 0)) + { + CIntVector orderIndices2; + CByteBuffer byteBuffer; + const size_t kBufferSize = (1 << 21); + byteBuffer.SetCapacity(kBufferSize); + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + size_t processedSize = kBufferSize; + RINOK(ReadStream(stream, byteBuffer, &processedSize)); + if (processedSize == 0) + return S_FALSE; + + const Byte *buf = byteBuffer; + CByteBuffer hashBuffer; + const UInt32 kNumVals = 1 << (kNumHashBytes * 8); + hashBuffer.SetCapacity(kNumVals); + Byte *hash = hashBuffer; + memset(hash, 0xFF, kNumVals); + Byte prevs[256]; + if (orderIndices.Size() >= 256) + return S_FALSE; + int i; + for (i = 0; i < orderIndices.Size(); i++) + { + const CArcInfoEx &ai = codecs->Formats[orderIndices[i]]; + const CByteBuffer &sig = ai.StartSignature; + if (sig.GetCapacity() < kNumHashBytes) + continue; + UInt32 v = HASH_VAL(sig, 0); + prevs[i] = hash[v]; + hash[v] = (Byte)i; + } + + processedSize -= (kNumHashBytes - 1); + for (UInt32 pos = 0; pos < processedSize; pos++) + { + for (; pos < processedSize && hash[HASH_VAL(buf, pos)] == 0xFF; pos++); + if (pos == processedSize) + break; + UInt32 v = HASH_VAL(buf, pos); + Byte *ptr = &hash[v]; + int i = *ptr; + do + { + int index = orderIndices[i]; + const CArcInfoEx &ai = codecs->Formats[index]; + const CByteBuffer &sig = ai.StartSignature; + if (sig.GetCapacity() != 0 && pos + sig.GetCapacity() <= processedSize + (kNumHashBytes - 1) && + TestSignature(buf + pos, sig, sig.GetCapacity())) + { + orderIndices2.Add(index); + orderIndices[i] = 0xFF; + *ptr = prevs[i]; + } + else + ptr = &prevs[i]; + i = *ptr; + } + while (i != 0xFF); + } + + for (i = 0; i < orderIndices.Size(); i++) + { + int val = orderIndices[i]; + if (val != 0xFF) + orderIndices2.Add(val); + } + orderIndices = orderIndices2; + } + else if (extension == L"000" || extension == L"001") + { + CByteBuffer byteBuffer; + const size_t kBufferSize = (1 << 10); + byteBuffer.SetCapacity(kBufferSize); + Byte *buffer = byteBuffer; + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + size_t processedSize = kBufferSize; + RINOK(ReadStream(stream, buffer, &processedSize)); + if (processedSize >= 16) + { + Byte kRarHeader[] = {0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00}; + if (TestSignature(buffer, kRarHeader, 7) && buffer[9] == 0x73 && (buffer[10] & 1) != 0) + { + for (int i = 0; i < orderIndices.Size(); i++) + { + int index = orderIndices[i]; + const CArcInfoEx &ai = codecs->Formats[index]; + if (ai.Name.CompareNoCase(L"rar") != 0) + continue; + orderIndices.Delete(i--); + orderIndices.Insert(0, index); + break; + } + } + } + } + if (orderIndices.Size() >= 2) + { + int isoIndex = codecs->FindFormatForArchiveType(L"iso"); + int udfIndex = codecs->FindFormatForArchiveType(L"udf"); + int iIso = -1; + int iUdf = -1; + for (int i = 0; i < orderIndices.Size(); i++) + { + if (orderIndices[i] == isoIndex) iIso = i; + if (orderIndices[i] == udfIndex) iUdf = i; + } + if (iUdf > iIso && iIso >= 0) + { + orderIndices[iUdf] = isoIndex; + orderIndices[iIso] = udfIndex; + } + } + + #endif + } + + for (int i = 0; i < orderIndices.Size(); i++) + { + if (stream) + { + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + } + CMyComPtr archive; + + FormatIndex = orderIndices[i]; + RINOK(codecs->CreateInArchive(FormatIndex, archive)); + if (!archive) + continue; + + #ifdef EXTERNAL_CODECS + { + CMyComPtr setCompressCodecsInfo; + archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); + if (setCompressCodecsInfo) + { + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs)); + } + } + #endif + + // OutputDebugStringW(codecs->Formats[FormatIndex].Name); + + HRESULT result; + if (stream) + result = archive->Open(stream, &kMaxCheckStartPosition, callback); + else + { + CMyComPtr openSeq; + archive.QueryInterface(IID_IArchiveOpenSeq, (void **)&openSeq); + if (!openSeq) + return E_NOTIMPL; + result = openSeq->OpenSeq(seqStream); + } + + if (result == S_FALSE) + continue; + RINOK(result); + + { + NCOM::CPropVariant prop; + archive->GetArchiveProperty(kpidError, &prop); + if (prop.vt != VT_EMPTY) + ErrorMessage = (prop.vt == VT_BSTR) ? prop.bstrVal : L"Unknown error"; + } + + Archive = archive; + const CArcInfoEx &format = codecs->Formats[FormatIndex]; + if (format.Exts.Size() == 0) + DefaultName = GetDefaultName2(fileName, L"", L""); + else + { + int subExtIndex = format.FindExtension(extension); + if (subExtIndex < 0) + subExtIndex = 0; + const CArcExtInfo &extInfo = format.Exts[subExtIndex]; + DefaultName = GetDefaultName2(fileName, extInfo.Ext, extInfo.AddExt); + } + return S_OK; + } + return S_FALSE; +} + +HRESULT CArc::OpenStreamOrFile( + CCodecs *codecs, + int formatIndex, + bool stdInMode, + IInStream *stream, + IArchiveOpenCallback *callback) +{ + CMyComPtr fileStream; + CMyComPtr seqStream; + if (stdInMode) + seqStream = new CStdInFileStream; + else if (!stream) + { + CInFileStream *fileStreamSpec = new CInFileStream; + fileStream = fileStreamSpec; + if (!fileStreamSpec->Open(Path)) + return GetLastError(); + stream = fileStream; + } + + /* + if (callback) + { + UInt64 fileSize; + RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); + RINOK(callback->SetTotal(NULL, &fileSize)) + } + */ + + return OpenStream(codecs, formatIndex, stream, seqStream, callback); +} + +HRESULT CArchiveLink::Close() +{ + for (int i = Arcs.Size() - 1; i >= 0; i--) + { + RINOK(Arcs[i].Archive->Close()); + } + IsOpen = false; + return S_OK; +} + +void CArchiveLink::Release() +{ + while (!Arcs.IsEmpty()) + Arcs.DeleteBack(); +} + +HRESULT CArchiveLink::Open( + CCodecs *codecs, + const CIntVector &formatIndices, + bool stdInMode, + IInStream *stream, + const UString &filePath, + IArchiveOpenCallback *callback) +{ + Release(); + if (formatIndices.Size() >= 32) + return E_NOTIMPL; + + HRESULT resSpec; + + for (;;) + { + resSpec = S_OK; + int formatIndex = -1; + if (formatIndices.Size() >= 1) + { + if (Arcs.Size() >= formatIndices.Size()) + break; + formatIndex = formatIndices[formatIndices.Size() - Arcs.Size() - 1]; + } + else if (Arcs.Size() >= 32) + break; + + if (Arcs.IsEmpty()) + { + CArc arc; + arc.Path = filePath; + arc.SubfileIndex = (UInt32)(Int32)-1; + RINOK(arc.OpenStreamOrFile(codecs, formatIndex, stdInMode, stream, callback)); + Arcs.Add(arc); + continue; + } + + const CArc &arc = Arcs.Back(); + + resSpec = (formatIndices.Size() == 0 ? S_OK : E_NOTIMPL); + + UInt32 mainSubfile; + { + NCOM::CPropVariant prop; + RINOK(arc.Archive->GetArchiveProperty(kpidMainSubfile, &prop)); + if (prop.vt == VT_UI4) + mainSubfile = prop.ulVal; + else + break; + UInt32 numItems; + RINOK(arc.Archive->GetNumberOfItems(&numItems)); + if (mainSubfile >= numItems) + break; + } + + + CMyComPtr getStream; + if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream) + break; + + CMyComPtr subSeqStream; + if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream) + break; + + CMyComPtr subStream; + if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK || !subStream) + break; + + CArc arc2; + RINOK(arc.GetItemPath(mainSubfile, arc2.Path)); + + CMyComPtr setSubArchiveName; + callback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName); + if (setSubArchiveName) + setSubArchiveName->SetSubArchiveName(arc2.Path); + + arc2.SubfileIndex = mainSubfile; + HRESULT result = arc2.OpenStream(codecs, formatIndex, subStream, NULL, callback); + resSpec = (formatIndices.Size() == 0 ? S_OK : S_FALSE); + if (result == S_FALSE) + break; + RINOK(result); + RINOK(arc.GetItemMTime(mainSubfile, arc2.MTime, arc2.MTimeDefined)); + Arcs.Add(arc2); + } + IsOpen = !Arcs.IsEmpty(); + return S_OK; +} + +static void SetCallback(const UString &filePath, + IOpenCallbackUI *callbackUI, + IArchiveOpenCallback *reOpenCallback, + CMyComPtr &callback) +{ + COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; + callback = openCallbackSpec; + openCallbackSpec->Callback = callbackUI; + openCallbackSpec->ReOpenCallback = reOpenCallback; + + UString fullName; + int fileNamePartStartIndex; + NFile::NDirectory::MyGetFullPathName(filePath, fullName, fileNamePartStartIndex); + openCallbackSpec->Init( + fullName.Left(fileNamePartStartIndex), + fullName.Mid(fileNamePartStartIndex)); +} + +HRESULT CArchiveLink::Open2(CCodecs *codecs, + const CIntVector &formatIndices, + bool stdInMode, + IInStream *stream, + const UString &filePath, + IOpenCallbackUI *callbackUI) +{ + VolumesSize = 0; + COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; + CMyComPtr callback = openCallbackSpec; + openCallbackSpec->Callback = callbackUI; + + UString fullName, prefix, name; + if (!stream && !stdInMode) + { + int fileNamePartStartIndex; + if (!NFile::NDirectory::MyGetFullPathName(filePath, fullName, fileNamePartStartIndex)) + return GetLastError(); + prefix = fullName.Left(fileNamePartStartIndex); + name = fullName.Mid(fileNamePartStartIndex); + openCallbackSpec->Init(prefix, name); + } + else + { + openCallbackSpec->SetSubArchiveName(filePath); + } + + RINOK(Open(codecs, formatIndices, stdInMode, stream, filePath, callback)); + VolumePaths.Add(prefix + name); + for (int i = 0; i < openCallbackSpec->FileNames.Size(); i++) + VolumePaths.Add(prefix + openCallbackSpec->FileNames[i]); + VolumesSize = openCallbackSpec->TotalSize; + return S_OK; +} + +HRESULT CArchiveLink::ReOpen(CCodecs *codecs, const UString &filePath, + IArchiveOpenCallback *callback) +{ + if (Arcs.Size() > 1) + return E_NOTIMPL; + + if (Arcs.Size() == 0) + return Open2(codecs, CIntVector(), false, NULL, filePath, 0); + + CMyComPtr openCallbackNew; + SetCallback(filePath, NULL, callback, openCallbackNew); + + CInFileStream *fileStreamSpec = new CInFileStream; + CMyComPtr stream(fileStreamSpec); + if (!fileStreamSpec->Open(filePath)) + return GetLastError(); + HRESULT res = GetArchive()->Open(stream, &kMaxCheckStartPosition, callback); + IsOpen = (res == S_OK); + return res; +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.h b/src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.h new file mode 100644 index 000000000..4a003ee63 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.h @@ -0,0 +1,87 @@ +// OpenArchive.h + +#ifndef __OPEN_ARCHIVE_H +#define __OPEN_ARCHIVE_H + +#include "Common/MyString.h" + +#include "Windows/FileFind.h" + +#include "../../Archive/IArchive.h" + +#include "ArchiveOpenCallback.h" +#include "LoadCodecs.h" + +HRESULT GetArchiveItemBoolProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result); +HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result); + +struct CArc +{ + CMyComPtr Archive; + UString Path; + UString DefaultName; + int FormatIndex; + int SubfileIndex; + FILETIME MTime; + bool MTimeDefined; + UString ErrorMessage; + + CArc(): MTimeDefined(false) {} + + HRESULT GetItemPath(UInt32 index, UString &result) const; + HRESULT GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const; + HRESULT IsItemAnti(UInt32 index, bool &result) const + { return GetArchiveItemBoolProp(Archive, index, kpidIsAnti, result); } + + HRESULT OpenStream( + CCodecs *codecs, + int formatIndex, + IInStream *stream, + ISequentialInStream *seqStream, + IArchiveOpenCallback *callback); + + HRESULT OpenStreamOrFile( + CCodecs *codecs, + int formatIndex, + bool stdInMode, + IInStream *stream, + IArchiveOpenCallback *callback); +}; + +struct CArchiveLink +{ + CObjectVector Arcs; + UStringVector VolumePaths; + UInt64 VolumesSize; + bool IsOpen; + + CArchiveLink(): VolumesSize(0), IsOpen(false) {} + HRESULT Close(); + void Release(); + ~CArchiveLink() { Release(); } + + IInArchive *GetArchive() const { return Arcs.Back().Archive; } + + HRESULT Open( + CCodecs *codecs, + const CIntVector &formatIndices, + bool stdInMode, + IInStream *stream, + const UString &filePath, + IArchiveOpenCallback *callback); + + HRESULT Open2( + CCodecs *codecs, + const CIntVector &formatIndices, + bool stdInMode, + IInStream *stream, + const UString &filePath, + IOpenCallbackUI *callbackUI); + + HRESULT ReOpen( + CCodecs *codecs, + const UString &filePath, + IArchiveOpenCallback *callback); +}; + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.cpp new file mode 100644 index 000000000..dacaca5f9 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.cpp @@ -0,0 +1,120 @@ +// PropIDUtils.cpp + +#include "StdAfx.h" + +#include "Common/IntToString.h" + +#include "Windows/FileFind.h" +#include "Windows/PropVariantConversions.h" + +#include "../../PropID.h" + +#include "PropIDUtils.h" + +using namespace NWindows; + +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'; +} + +static const char g_WinAttrib[17] = "RHS8DAdNTsrCOnE_"; +/* +0 READONLY +1 HIDDEN +3 SYSTEM + +4 DIRECTORY +5 ARCHIVE +6 DEVICE +7 NORMAL +8 TEMPORARY +9 SPARSE_FILE +10 REPARSE_POINT +11 COMPRESSED +12 OFFLINE +13 NOT_CONTENT_INDEXED +14 ENCRYPTED + +16 VIRTUAL +*/ + +static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' }; +#define MY_ATTR_CHAR(a, n, c) ((a )& (1 << (n))) ? c : L'-'; + +UString ConvertPropertyToString(const PROPVARIANT &prop, PROPID propID, bool full) +{ + switch(propID) + { + case kpidCTime: + case kpidATime: + case kpidMTime: + { + if (prop.vt != VT_FILETIME) + break; + FILETIME localFileTime; + if ((prop.filetime.dwHighDateTime == 0 && + prop.filetime.dwLowDateTime == 0) || + !::FileTimeToLocalFileTime(&prop.filetime, &localFileTime)) + return UString(); + return ConvertFileTimeToString(localFileTime, true, full); + } + case kpidCRC: + { + if (prop.vt != VT_UI4) + break; + wchar_t temp[12]; + ConvertUInt32ToHex(prop.ulVal, temp); + return temp; + } + case kpidAttrib: + { + if (prop.vt != VT_UI4) + break; + UInt32 a = prop.ulVal; + wchar_t sz[32]; + int pos = 0; + for (int i = 0; i < 16; i++) + if (a & (1 << i) && i != 7) + sz[pos++] = g_WinAttrib[i]; + sz[pos] = '\0'; + return sz; + } + case kpidPosixAttrib: + { + if (prop.vt != VT_UI4) + break; + UString res; + UInt32 a = prop.ulVal; + wchar_t temp[16]; + + temp[0] = kPosixTypes[(a >> 12) & 0xF]; + for (int i = 6; i >= 0; i -= 3) + { + temp[7 - i] = MY_ATTR_CHAR(a, i + 2, L'r'); + temp[8 - i] = MY_ATTR_CHAR(a, i + 1, L'w'); + temp[9 - i] = MY_ATTR_CHAR(a, i + 0, L'x'); + } + if ((a & 0x800) != 0) temp[3] = ((a & (1 << 6)) ? 's' : 'S'); + if ((a & 0x400) != 0) temp[6] = ((a & (1 << 3)) ? 's' : 'S'); + if ((a & 0x200) != 0) temp[9] = ((a & (1 << 0)) ? 't' : 'T'); + temp[10] = 0; + res = temp; + + a &= ~(UInt32)0xFFFF; + if (a != 0) + { + ConvertUInt32ToHex(a, temp); + res = UString(temp) + L' ' + res; + } + return res; + } + } + return ConvertPropVariantToString(prop); +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.h b/src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.h new file mode 100644 index 000000000..ca14d091d --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.h @@ -0,0 +1,12 @@ +// PropIDUtils.h + +#ifndef __PROPID_UTILS_H +#define __PROPID_UTILS_H + +#include "Common/MyString.h" +#include "Common/Types.h" + +void ConvertUInt32ToHex(UInt32 value, wchar_t *s); +UString ConvertPropertyToString(const PROPVARIANT &propVariant, PROPID propID, bool full = true); + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/Property.h b/src/libs/7zip/win/CPP/7zip/UI/Common/Property.h new file mode 100644 index 000000000..9fd340cbc --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/Property.h @@ -0,0 +1,14 @@ +// Property.h + +#ifndef __PROPERTY_H +#define __PROPERTY_H + +#include "Common/MyString.h" + +struct CProperty +{ + UString Name; + UString Value; +}; + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.cpp new file mode 100644 index 000000000..4827f2a78 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.cpp @@ -0,0 +1,79 @@ +// SetProperties.cpp + +#include "StdAfx.h" + +#include "SetProperties.h" + +#include "Windows/PropVariant.h" +#include "Common/MyString.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 &properties) +{ + if (properties.IsEmpty()) + return S_OK; + CMyComPtr 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; + UString name = property.Name; + if (property.Value.IsEmpty()) + { + if (!name.IsEmpty()) + { + wchar_t c = name[name.Length() - 1]; + if (c == L'-') + propVariant = false; + else if (c == L'+') + propVariant = true; + if (propVariant.vt != VT_EMPTY) + name = name.Left(name.Length() - 1); + } + } + else + ParseNumberString(property.Value, propVariant); + realNames.Add(name); + values[i] = propVariant; + } + CRecordVector 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/src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.h b/src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.h new file mode 100644 index 000000000..892f1a210 --- /dev/null +++ b/src/libs/7zip/win/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 &properties); + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.cpp new file mode 100644 index 000000000..061e77730 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.cpp @@ -0,0 +1,22 @@ +// SortUtils.cpp + +#include "StdAfx.h" + +#include "SortUtils.h" +#include "Common/Wildcard.h" + +static int CompareStrings(const int *p1, const int *p2, void *param) +{ + const UStringVector &strings = *(const UStringVector *)param; + return CompareFileNames(strings[*p1], strings[*p2]); +} + +void SortFileNames(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); +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.h b/src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.h new file mode 100644 index 000000000..e15224611 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.h @@ -0,0 +1,10 @@ +// SortUtils.h + +#ifndef __SORTUTLS_H +#define __SORTUTLS_H + +#include "Common/MyString.h" + +void SortFileNames(const UStringVector &strings, CIntVector &indices); + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/StdAfx.h b/src/libs/7zip/win/CPP/7zip/UI/Common/StdAfx.h new file mode 100644 index 000000000..9a8e7d21a --- /dev/null +++ b/src/libs/7zip/win/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/src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.cpp new file mode 100644 index 000000000..eeaec1802 --- /dev/null +++ b/src/libs/7zip/win/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((LPCWSTR)Paths.Back()); + Paths.DeleteBack(); + } +} + + diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.h b/src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.h new file mode 100644 index 000000000..eb474a760 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.h @@ -0,0 +1,16 @@ +// TempFiles.h + +#ifndef __TEMPFILES_H +#define __TEMPFILES_H + +#include "Common/MyString.h" + +class CTempFiles +{ + void Clear(); +public: + UStringVector Paths; + ~CTempFiles() { Clear(); } +}; + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/Update.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/Update.cpp new file mode 100644 index 000000000..a57ec2a6b --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/Update.cpp @@ -0,0 +1,910 @@ +// Update.cpp + +#include "StdAfx.h" + +#include "Update.h" + +#include "Common/IntToString.h" +#include "Common/StringConvert.h" + +#ifdef _WIN32 +#include "Windows/DLL.h" +#endif + +#include "Windows/FileDir.h" +#include "Windows/FileFind.h" +#include "Windows/FileName.h" +#include "Windows/PropVariant.h" +#include "Windows/PropVariantConversions.h" +#include "Windows/Time.h" + +#include "../../Common/FileStreams.h" + +#include "../../Compress/CopyCoder.h" + +#include "../Common/DirItem.h" +#include "../Common/EnumDirItems.h" +#include "../Common/OpenArchive.h" +#include "../Common/UpdateProduce.h" + +#include "EnumDirItems.h" +#include "SetProperties.h" +#include "TempFiles.h" +#include "UpdateCallback.h" + +static const char *kUpdateIsNotSupoorted = + "update operations are not supported for this archive"; + +using namespace NWindows; +using namespace NCOM; +using namespace NFile; +using namespace NName; + +static const wchar_t *kTempFolderPrefix = L"7zE"; + +using namespace NUpdateArchive; + +class COutMultiVolStream: + public IOutStream, + public CMyUnknownImp +{ + int _streamIndex; // required stream + UInt64 _offsetPos; // offset from start of _streamIndex index + UInt64 _absPos; + UInt64 _length; + + struct CSubStreamInfo + { + COutFileStream *StreamSpec; + CMyComPtr Stream; + UString Name; + UInt64 Pos; + UInt64 RealSize; + }; + CObjectVector Streams; +public: + // CMyComPtr VolumeCallback; + CRecordVector Sizes; + UString Prefix; + CTempFiles *TempFiles; + + void Init() + { + _streamIndex = 0; + _offsetPos = 0; + _absPos = 0; + _length = 0; + } + + HRESULT Close(); + + MY_UNKNOWN_IMP1(IOutStream) + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); + STDMETHOD(SetSize)(UInt64 newSize); +}; + +// static NSynchronization::CCriticalSection g_TempPathsCS; + +HRESULT COutMultiVolStream::Close() +{ + HRESULT res = S_OK; + for (int i = 0; i < Streams.Size(); i++) + { + CSubStreamInfo &s = Streams[i]; + if (s.StreamSpec) + { + HRESULT res2 = s.StreamSpec->Close(); + if (res2 != S_OK) + res = res2; + } + } + return res; +} + +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[16]; + ConvertUInt32ToString(_streamIndex + 1, temp); + UString res = temp; + while (res.Length() < 3) + res = UString(L'0') + res; + UString name = Prefix + res; + subStream.StreamSpec = new COutFileStream; + subStream.Stream = subStream.StreamSpec; + if (!subStream.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 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(UInt64 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 const wchar_t *kDefaultArchiveType = L"7z"; +static const wchar_t *kSFXExtension = + #ifdef _WIN32 + L"exe"; + #else + L""; + #endif + +bool CUpdateOptions::Init(const CCodecs *codecs, const CIntVector &formatIndices, const UString &arcPath) +{ + if (formatIndices.Size() > 1) + return false; + int arcTypeIndex = -1; + if (formatIndices.Size() != 0) + arcTypeIndex = formatIndices[0]; + if (arcTypeIndex >= 0) + MethodMode.FormatIndex = arcTypeIndex; + else + { + MethodMode.FormatIndex = codecs->FindFormatForArchiveName(arcPath); + // It works incorrectly for update command if archive has some non-default extension! + if (MethodMode.FormatIndex < 0) + MethodMode.FormatIndex = codecs->FindFormatForArchiveType(kDefaultArchiveType); + } + if (MethodMode.FormatIndex < 0) + return false; + const CArcInfoEx &arcInfo = codecs->Formats[MethodMode.FormatIndex]; + if (!arcInfo.UpdateEnabled) + return false; + UString typeExt = arcInfo.GetMainExt(); + UString ext = typeExt; + if (SfxMode) + ext = kSFXExtension; + ArchivePath.BaseExtension = ext; + ArchivePath.VolExtension = typeExt; + ArchivePath.ParseFromPath(arcPath); + for (int i = 0; i < Commands.Size(); i++) + { + CUpdateArchiveCommand &uc = Commands[i]; + uc.ArchivePath.BaseExtension = ext; + uc.ArchivePath.VolExtension = typeExt; + uc.ArchivePath.ParseFromPath(uc.UserArchivePath); + } + return true; +} + +/* +struct CUpdateProduceCallbackImp: public IUpdateProduceCallback +{ + const CObjectVector *_arcItems; + IUpdateCallbackUI *_callback; + + CUpdateProduceCallbackImp(const CObjectVector *a, + IUpdateCallbackUI *callback): _arcItems(a), _callback(callback) {} + virtual HRESULT ShowDeleteFile(int arcIndex); +}; + +HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(int arcIndex) +{ + return _callback->ShowDeleteFile((*_arcItems)[arcIndex].Name); +} +*/ + +static HRESULT Compress( + CCodecs *codecs, + const CActionSet &actionSet, + IInArchive *archive, + const CCompressionMethodMode &compressionMethod, + CArchivePath &archivePath, + const CObjectVector &arcItems, + bool shareForWrite, + bool stdInMode, + /* const UString & stdInFileName, */ + bool stdOutMode, + const CDirItems &dirItems, + bool sfxMode, + const UString &sfxModule, + const CRecordVector &volumesSizes, + CTempFiles &tempFiles, + CUpdateErrorInfo &errorInfo, + IUpdateCallbackUI *callback) +{ + CMyComPtr outArchive; + if (archive != NULL) + { + CMyComPtr archive2 = archive; + HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive); + if (result != S_OK) + throw kUpdateIsNotSupoorted; + } + else + { + RINOK(codecs->CreateOutArchive(compressionMethod.FormatIndex, outArchive)); + + #ifdef EXTERNAL_CODECS + { + CMyComPtr setCompressCodecsInfo; + outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); + if (setCompressCodecsInfo) + { + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs)); + } + } + #endif + } + if (outArchive == 0) + throw kUpdateIsNotSupoorted; + + NFileTimeType::EEnum fileTimeType; + UInt32 value; + RINOK(outArchive->GetFileTimeType(&value)); + + switch(value) + { + case NFileTimeType::kWindows: + case NFileTimeType::kUnix: + case NFileTimeType::kDOS: + fileTimeType = (NFileTimeType::EEnum)value; + break; + default: + return E_FAIL; + } + + CRecordVector updatePairs2; + + { + CRecordVector updatePairs; + GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); // must be done only once!!! + // CUpdateProduceCallbackImp upCallback(&arcItems, callback); + UpdateProduce(updatePairs, actionSet, updatePairs2, NULL /* &upCallback */); + } + + UInt32 numFiles = 0; + for (int i = 0; i < updatePairs2.Size(); i++) + if (updatePairs2[i].NewData) + numFiles++; + + RINOK(callback->SetNumFiles(numFiles)); + + + CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; + CMyComPtr updateCallback(updateCallbackSpec); + + updateCallbackSpec->ShareForWrite = shareForWrite; + updateCallbackSpec->StdInMode = stdInMode; + updateCallbackSpec->Callback = callback; + updateCallbackSpec->DirItems = &dirItems; + updateCallbackSpec->ArcItems = &arcItems; + updateCallbackSpec->UpdatePairs = &updatePairs2; + + CMyComPtr outStream; + + if (!stdOutMode) + { + UString resultPath; + int pos; + if (!NFile::NDirectory::MyGetFullPathName(archivePath.GetFinalPath(), resultPath, pos)) + throw 1417161; + NFile::NDirectory::CreateComplexDirectory(resultPath.Left(pos)); + } + + COutFileStream *outStreamSpec = NULL; + COutMultiVolStream *volStreamSpec = NULL; + + if (volumesSizes.Size() == 0) + { + if (stdOutMode) + outStream = new CStdOutFileStream; + else + { + 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[16]; + ConvertUInt32ToString(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"7-Zip cannot open file"; + return E_FAIL; + } + } + } + else + { + if (stdOutMode) + return E_FAIL; + 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 sfxStream(sfxStreamSpec); + if (!sfxStreamSpec->Open(sfxModule)) + { + errorInfo.SystemError = ::GetLastError(); + errorInfo.Message = L"7-Zip cannot open SFX module"; + errorInfo.FileName = sfxModule; + return E_FAIL; + } + + CMyComPtr sfxOutStream; + COutFileStream *outStreamSpec = NULL; + if (volumesSizes.Size() == 0) + sfxOutStream = outStream; + else + { + outStreamSpec = new COutFileStream; + sfxOutStream = outStreamSpec; + UString realPath = archivePath.GetFinalPath(); + if (!outStreamSpec->Create(realPath, false)) + { + errorInfo.SystemError = ::GetLastError(); + errorInfo.FileName = realPath; + errorInfo.Message = L"7-Zip cannot open file"; + return E_FAIL; + } + } + RINOK(NCompress::CopyStream(sfxStream, sfxOutStream, NULL)); + if (outStreamSpec) + { + RINOK(outStreamSpec->Close()); + } + } + + HRESULT result = outArchive->UpdateItems(outStream, updatePairs2.Size(), updateCallback); + callback->Finilize(); + RINOK(result); + if (outStreamSpec) + result = outStreamSpec->Close(); + else if (volStreamSpec) + result = volStreamSpec->Close(); + return result; +} + +HRESULT EnumerateInArchiveItems(const NWildcard::CCensor &censor, + const CArc &arc, + CObjectVector &arcItems) +{ + arcItems.Clear(); + UInt32 numItems; + IInArchive *archive = arc.Archive; + RINOK(archive->GetNumberOfItems(&numItems)); + arcItems.Reserve(numItems); + for (UInt32 i = 0; i < numItems; i++) + { + CArcItem ai; + + RINOK(arc.GetItemPath(i, ai.Name)); + RINOK(IsArchiveItemFolder(archive, i, ai.IsDir)); + ai.Censored = censor.CheckPath(ai.Name, !ai.IsDir); + RINOK(arc.GetItemMTime(i, ai.MTime, ai.MTimeDefined)); + + { + CPropVariant prop; + RINOK(archive->GetProperty(i, kpidSize, &prop)); + ai.SizeDefined = (prop.vt != VT_EMPTY); + if (ai.SizeDefined) + ai.Size = ConvertPropVariantToUInt64(prop); + } + + { + CPropVariant prop; + RINOK(archive->GetProperty(i, kpidTimeType, &prop)); + if (prop.vt == VT_UI4) + { + ai.TimeType = (int)(NFileTimeType::EEnum)prop.ulVal; + switch(ai.TimeType) + { + case NFileTimeType::kWindows: + case NFileTimeType::kUnix: + case NFileTimeType::kDOS: + break; + default: + return E_FAIL; + } + } + } + + ai.IndexInServer = i; + arcItems.Add(ai); + } + return S_OK; +} + + +static HRESULT UpdateWithItemLists( + CCodecs *codecs, + CUpdateOptions &options, + IInArchive *archive, + const CObjectVector &arcItems, + CDirItems &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(L"stdout", archive != 0)); + } + else + { + RINOK(callback->StartArchive(command.ArchivePath.GetFinalPath(), + i == 0 && options.UpdateArchiveItself && archive != 0)); + } + + RINOK(Compress( + codecs, + command.ActionSet, archive, + options.MethodMode, + command.ArchivePath, + arcItems, + options.OpenShareForWrite, + options.StdInMode, + /* options.StdInFileName, */ + options.StdOutMode, + dirItems, + options.SfxMode, options.SfxModule, + options.VolumesSizes, + tempFiles, + errorInfo, callback)); + + RINOK(callback->FinishArchive()); + } + return S_OK; +} + +#if defined(_WIN32) && !defined(UNDER_CE) +class CCurrentDirRestorer +{ + UString _path; +public: + CCurrentDirRestorer() { NFile::NDirectory::MyGetCurrentDirectory(_path); } + ~CCurrentDirRestorer() { RestoreDirectory();} + bool RestoreDirectory() { return BOOLToBool(NFile::NDirectory::MySetCurrentDirectory(_path)); } +}; +#endif + +struct CEnumDirItemUpdateCallback: public IEnumDirItemCallback +{ + IUpdateCallbackUI2 *Callback; + HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, const wchar_t *path) + { + return Callback->ScanProgress(numFolders, numFiles, path); + } +}; + +#ifdef _WIN32 +typedef ULONG (FAR PASCAL MY_MAPISENDDOCUMENTS)( + ULONG_PTR ulUIParam, + LPSTR lpszDelimChar, + LPSTR lpszFilePaths, + LPSTR lpszFileNames, + ULONG ulReserved +); +typedef MY_MAPISENDDOCUMENTS FAR *MY_LPMAPISENDDOCUMENTS; +#endif + +HRESULT UpdateArchive( + CCodecs *codecs, + 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; + #ifdef UNDER_CE + if (!NFind::DoesFileExist(name)) + #else + if (!NDirectory::MySearchPath(NULL, name, NULL, options.SfxModule)) + #endif + { + errorInfo.SystemError = ::GetLastError(); + errorInfo.Message = L"7-Zip cannot find specified SFX module"; + errorInfo.FileName = name; + return E_FAIL; + } + } + + + CArchiveLink arcLink; + const UString arcPath = options.ArchivePath.GetFinalPath(); + + if (!options.ArchivePath.OriginalPath.IsEmpty()) + { + NFind::CFileInfoW fi; + if (fi.Find(arcPath)) + { + if (fi.IsDir()) + throw "there is no such archive"; + if (options.VolumesSizes.Size() > 0) + return E_NOTIMPL; + CIntVector formatIndices; + if (options.MethodMode.FormatIndex >= 0) + formatIndices.Add(options.MethodMode.FormatIndex); + HRESULT result = arcLink.Open2(codecs, formatIndices, false, NULL, arcPath, openCallback); + if (result == E_ABORT) + return result; + RINOK(callback->OpenResult(arcPath, result)); + RINOK(result); + if (arcLink.VolumePaths.Size() > 1) + { + errorInfo.SystemError = (DWORD)E_NOTIMPL; + errorInfo.Message = L"Updating for multivolume archives is not implemented"; + return E_NOTIMPL; + } + + CArc &arc = arcLink.Arcs.Back(); + arc.MTimeDefined = !fi.IsDevice; + arc.MTime = fi.MTime; + } + } + else + { + /* + if (archiveType.IsEmpty()) + throw "type of archive is not specified"; + */ + } + + CDirItems dirItems; + if (options.StdInMode) + { + CDirItem di; + di.Name = options.StdInFileName; + di.Size = (UInt64)(Int64)-1; + di.Attrib = 0; + NTime::GetCurUtcFileTime(di.MTime); + di.CTime = di.ATime = di.MTime; + dirItems.Items.Add(di); + } + 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 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) + { + if (res != E_ABORT) + errorInfo.Message = L"Scanning error"; + 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; + + bool thereIsInArchive = arcLink.IsOpen; + + if (!options.StdOutMode && options.UpdateArchiveItself) + { + CArchivePath &ap = options.Commands[0].ArchivePath; + ap = options.ArchivePath; + // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty()) + if ((thereIsInArchive || !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 (!options.StdOutMode && + (i > 0 || !createTempFile)) + { + const UString &path = ap.GetFinalPath(); + if (NFind::DoesFileOrDirExist(path)) + { + errorInfo.SystemError = 0; + errorInfo.Message = L"The file already exists"; + errorInfo.FileName = path; + return E_FAIL; + } + } + } + + CObjectVector arcItems; + if (thereIsInArchive) + { + RINOK(EnumerateInArchiveItems(censor, arcLink.Arcs.Back(), arcItems)); + } + + RINOK(UpdateWithItemLists(codecs, options, + thereIsInArchive ? arcLink.GetArchive() : 0, + arcItems, dirItems, + tempFiles, errorInfo, callback)); + + if (thereIsInArchive) + { + RINOK(arcLink.Close()); + arcLink.Release(); + } + + tempFiles.Paths.Clear(); + if (createTempFile) + { + try + { + CArchivePath &ap = options.Commands[0].ArchivePath; + const UString &tempPath = ap.GetTempPath(); + if (thereIsInArchive) + if (!NDirectory::DeleteFileAlways(arcPath)) + { + errorInfo.SystemError = ::GetLastError(); + errorInfo.Message = L"7-Zip cannot delete the file"; + errorInfo.FileName = arcPath; + return E_FAIL; + } + if (!NDirectory::MyMoveFile(tempPath, arcPath)) + { + errorInfo.SystemError = ::GetLastError(); + errorInfo.Message = L"7-Zip cannot move the file"; + errorInfo.FileName = tempPath; + errorInfo.FileName2 = arcPath; + return E_FAIL; + } + } + catch(...) + { + throw; + } + } + + #if defined(_WIN32) && !defined(UNDER_CE) + if (options.EMailMode) + { + NDLL::CLibrary mapiLib; + if (!mapiLib.Load(TEXT("Mapi32.dll"))) + { + errorInfo.SystemError = ::GetLastError(); + errorInfo.Message = L"7-Zip cannot load Mapi32.dll"; + return E_FAIL; + } + MY_LPMAPISENDDOCUMENTS fnSend = (MY_LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments"); + if (fnSend == 0) + { + errorInfo.SystemError = ::GetLastError(); + errorInfo.Message = L"7-Zip cannot 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(); + errorInfo.Message = L"GetFullPathName error"; + 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/src/libs/7zip/win/CPP/7zip/UI/Common/Update.h b/src/libs/7zip/win/CPP/7zip/UI/Common/Update.h new file mode 100644 index 000000000..49af0092a --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/Update.h @@ -0,0 +1,175 @@ +// Update.h + +#ifndef __COMMON_UPDATE_H +#define __COMMON_UPDATE_H + +#include "Common/Wildcard.h" + +#include "ArchiveOpenCallback.h" +#include "LoadCodecs.h" +#include "Property.h" +#include "UpdateAction.h" +#include "UpdateCallback.h" + +struct CArchivePath +{ + UString OriginalPath; + + 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) + { + OriginalPath = path; + + SplitPathToParts(path, Prefix, Name); + 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 +{ + UString UserArchivePath; + CArchivePath ArchivePath; + NUpdateArchive::CActionSet ActionSet; +}; + +struct CCompressionMethodMode +{ + int FormatIndex; + CObjectVector Properties; + CCompressionMethodMode(): FormatIndex(-1) {} +}; + +struct CUpdateOptions +{ + CCompressionMethodMode MethodMode; + + CObjectVector Commands; + bool UpdateArchiveItself; + CArchivePath ArchivePath; + + bool SfxMode; + UString SfxModule; + + bool OpenShareForWrite; + + bool StdInMode; + UString StdInFileName; + bool StdOutMode; + + bool EMailMode; + bool EMailRemoveAfter; + UString EMailAddress; + + UString WorkingDir; + + bool Init(const CCodecs *codecs, const CIntVector &formatIndices, const UString &arcPath); + + CUpdateOptions(): + UpdateArchiveItself(true), + SfxMode(false), + StdInMode(false), + StdOutMode(false), + EMailMode(false), + EMailRemoveAfter(false), + OpenShareForWrite(false) + {}; + + void SetAddActionCommand() + { + Commands.Clear(); + CUpdateArchiveCommand c; + c.ActionSet = NUpdateArchive::kAddActionSet; + Commands.Add(c); + } + + CRecordVector VolumesSizes; +}; + +struct CErrorInfo +{ + DWORD SystemError; + UString FileName; + UString FileName2; + UString Message; + // UStringVector ErrorPaths; + // CRecordVector ErrorCodes; + CErrorInfo(): SystemError(0) {}; +}; + +struct CUpdateErrorInfo: public CErrorInfo +{ +}; + +#define INTERFACE_IUpdateCallbackUI2(x) \ + INTERFACE_IUpdateCallbackUI(x) \ + virtual HRESULT OpenResult(const wchar_t *name, HRESULT result) x; \ + virtual HRESULT StartScanning() x; \ + virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, const wchar_t *path) x; \ + virtual HRESULT CanNotFindError(const wchar_t *name, DWORD systemError) x; \ + virtual HRESULT FinishScanning() x; \ + virtual HRESULT StartArchive(const wchar_t *name, bool updating) x; \ + virtual HRESULT FinishArchive() x; \ + +struct IUpdateCallbackUI2: public IUpdateCallbackUI +{ + INTERFACE_IUpdateCallbackUI2(=0) +}; + +HRESULT UpdateArchive( + CCodecs *codecs, + const NWildcard::CCensor &censor, + CUpdateOptions &options, + CUpdateErrorInfo &errorInfo, + IOpenCallbackUI *openCallback, + IUpdateCallbackUI2 *callback); + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.cpp new file mode 100644 index 000000000..879a49c57 --- /dev/null +++ b/src/libs/7zip/win/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/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.h b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.h new file mode 100644 index 000000000..0ac1c1080 --- /dev/null +++ b/src/libs/7zip/win/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/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.cpp new file mode 100644 index 000000000..0f229058c --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.cpp @@ -0,0 +1,249 @@ +// UpdateCallback.cpp + +#include "StdAfx.h" + +#include "Common/ComTry.h" +#include "Common/Defs.h" +#include "Common/IntToString.h" +#include "Common/StringConvert.h" + +#include "Windows/PropVariant.h" + +#include "../../Common/FileStreams.h" + +#include "UpdateCallback.h" + +using namespace NWindows; + +CArchiveUpdateCallback::CArchiveUpdateCallback(): + Callback(0), + ShareForWrite(false), + StdInMode(false), + DirItems(0), + ArcItems(0), + UpdatePairs(0), + NewNames(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 +} + +STDMETHODIMP CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + COM_TRY_BEGIN + return Callback->SetRatioInfo(inSize, outSize); + COM_TRY_END +} + + +/* +STATPROPSTG kProperties[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidIsDir, VT_BOOL}, + { NULL, kpidSize, VT_UI8}, + { NULL, kpidCTime, VT_FILETIME}, + { NULL, kpidATime, VT_FILETIME}, + { NULL, kpidMTime, VT_FILETIME}, + { NULL, kpidAttrib, VT_UI4}, + { NULL, kpidIsAnti, VT_BOOL} +}; + +STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **) +{ + return CStatPropEnumerator::CreateEnumerator(kProperties, sizeof(kProperties) / sizeof(kProperties[0]), enumerator); +} +*/ + +STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index, + Int32 *newData, Int32 *newProps, UInt32 *indexInArchive) +{ + COM_TRY_BEGIN + RINOK(Callback->CheckBreak()); + const CUpdatePair2 &up = (*UpdatePairs)[index]; + if (newData != NULL) *newData = BoolToInt(up.NewData); + if (newProps != NULL) *newProps = BoolToInt(up.NewProps); + if (indexInArchive != NULL) + { + *indexInArchive = (UInt32)-1; + if (up.ExistInArchive()) + *indexInArchive = (ArcItems == 0) ? up.ArcIndex : (*ArcItems)[up.ArcIndex].IndexInServer; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + const CUpdatePair2 &up = (*UpdatePairs)[index]; + NWindows::NCOM::CPropVariant prop; + + if (propID == kpidIsAnti) + { + prop = up.IsAnti; + prop.Detach(value); + return S_OK; + } + + if (up.IsAnti) + { + switch(propID) + { + case kpidIsDir: + case kpidPath: + break; + case kpidSize: + prop = (UInt64)0; + prop.Detach(value); + return S_OK; + default: + prop.Detach(value); + return S_OK; + } + } + + if (up.ExistOnDisk()) + { + const CDirItem &di = DirItems->Items[up.DirIndex]; + switch(propID) + { + case kpidPath: prop = DirItems->GetLogPath(up.DirIndex); break; + case kpidIsDir: prop = di.IsDir(); break; + case kpidSize: prop = di.Size; break; + case kpidAttrib: prop = di.Attrib; break; + case kpidCTime: prop = di.CTime; break; + case kpidATime: prop = di.ATime; break; + case kpidMTime: prop = di.MTime; break; + } + } + else + { + if (propID == kpidPath) + { + if (up.NewNameIndex >= 0) + { + prop = (*NewNames)[up.NewNameIndex]; + prop.Detach(value); + return S_OK; + } + } + if (up.ExistInArchive() && Archive) + { + UInt32 indexInArchive; + if (ArcItems == 0) + indexInArchive = up.ArcIndex; + else + indexInArchive = (*ArcItems)[up.ArcIndex].IndexInServer; + return Archive->GetProperty(indexInArchive, propID, value); + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream) +{ + COM_TRY_BEGIN + const CUpdatePair2 &up = (*UpdatePairs)[index]; + if (!up.NewData) + return E_FAIL; + + RINOK(Callback->CheckBreak()); + RINOK(Callback->Finilize()); + + if (up.IsAnti) + { + return Callback->GetStream((*ArcItems)[up.ArcIndex].Name, true); + } + const CDirItem &di = DirItems->Items[up.DirIndex]; + RINOK(Callback->GetStream(DirItems->GetLogPath(up.DirIndex), false)); + + if (di.IsDir()) + return S_OK; + + if (StdInMode) + { + CStdInFileStream *inStreamSpec = new CStdInFileStream; + CMyComPtr inStreamLoc(inStreamSpec); + *inStream = inStreamLoc.Detach(); + } + else + { + CInFileStream *inStreamSpec = new CInFileStream; + CMyComPtr inStreamLoc(inStreamSpec); + const UString path = DirItems->GetPhyPath(up.DirIndex); + if (!inStreamSpec->OpenShared(path, ShareForWrite)) + { + 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[16]; + ConvertUInt32ToString(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 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 +} + +STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password) +{ + COM_TRY_BEGIN + return Callback->CryptoGetTextPassword(password); + COM_TRY_END +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.h b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.h new file mode 100644 index 000000000..9a20c3159 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.h @@ -0,0 +1,74 @@ +// UpdateCallback.h + +#ifndef __UPDATECALLBACK_H +#define __UPDATECALLBACK_H + +#include "Common/MyCom.h" +#include "Common/MyString.h" + +#include "../../IPassword.h" +#include "../../ICoder.h" + +#include "../Common/UpdatePair.h" +#include "../Common/UpdateProduce.h" + +#define INTERFACE_IUpdateCallbackUI(x) \ + virtual HRESULT SetTotal(UInt64 size) x; \ + virtual HRESULT SetCompleted(const UInt64 *completeValue) x; \ + virtual HRESULT SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) x; \ + virtual HRESULT CheckBreak() x; \ + virtual HRESULT Finilize() x; \ + virtual HRESULT SetNumFiles(UInt64 numFiles) x; \ + virtual HRESULT GetStream(const wchar_t *name, bool isAnti) x; \ + virtual HRESULT OpenFileError(const wchar_t *name, DWORD systemError) x; \ + virtual HRESULT SetOperationResult(Int32 operationResult) x; \ + virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x; \ + virtual HRESULT CryptoGetTextPassword(BSTR *password) x; \ + /* virtual HRESULT ShowDeleteFile(const wchar_t *name) x; */ \ + /* virtual HRESULT CloseProgress() { return S_OK; }; */ + +struct IUpdateCallbackUI +{ + INTERFACE_IUpdateCallbackUI(=0) +}; + +class CArchiveUpdateCallback: + public IArchiveUpdateCallback2, + public ICryptoGetTextPassword2, + public ICryptoGetTextPassword, + public ICompressProgressInfo, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP4( + IArchiveUpdateCallback2, + ICryptoGetTextPassword2, + ICryptoGetTextPassword, + ICompressProgressInfo) + + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); + + INTERFACE_IArchiveUpdateCallback2(;) + + STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password); + STDMETHOD(CryptoGetTextPassword)(BSTR *password); + +public: + CRecordVector VolumesSizes; + UString VolName; + UString VolExt; + + IUpdateCallbackUI *Callback; + + bool ShareForWrite; + bool StdInMode; + const CDirItems *DirItems; + const CObjectVector *ArcItems; + const CRecordVector *UpdatePairs; + const UStringVector *NewNames; + CMyComPtr Archive; + + CArchiveUpdateCallback(); +}; + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.cpp new file mode 100644 index 000000000..a43a9e770 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.cpp @@ -0,0 +1,158 @@ +// UpdatePair.cpp + +#include "StdAfx.h" + +#include + +#include "Common/Defs.h" +#include "Common/Wildcard.h" + +#include "Windows/Time.h" + +#include "SortUtils.h" +#include "UpdatePair.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; + FileTimeToUnixTime(time1, unixTime1); + FileTimeToUnixTime(time2, unixTime2); + return MyCompare(unixTime1, unixTime2); + } + case NFileTimeType::kDOS: + { + UInt32 dosTime1, dosTime2; + FileTimeToDosTime(time1, dosTime1); + FileTimeToDosTime(time2, dosTime2); + return MyCompare(dosTime1, dosTime2); + } + } + throw 4191618; +} + +static const wchar_t *kDuplicateFileNameMessage = L"Duplicate filename:"; +static const wchar_t *kNotCensoredCollisionMessaged = L"Internal file name collision (file on disk, file in archive):"; + +static void ThrowError(const UString &message, const UString &s1, const UString &s2) +{ + UString m = message; + m += L'\n'; + m += s1; + m += L'\n'; + m += s2; + throw m; +} + +static void TestDuplicateString(const UStringVector &strings, const CIntVector &indices) +{ + for(int i = 0; i + 1 < indices.Size(); i++) + if (CompareFileNames(strings[indices[i]], strings[indices[i + 1]]) == 0) + ThrowError(kDuplicateFileNameMessage, strings[indices[i]], strings[indices[i + 1]]); +} + +void GetUpdatePairInfoList( + const CDirItems &dirItems, + const CObjectVector &arcItems, + NFileTimeType::EEnum fileTimeType, + CRecordVector &updatePairs) +{ + CIntVector dirIndices, arcIndices; + + int numDirItems = dirItems.Items.Size(); + int numArcItems = arcItems.Size(); + + + { + UStringVector arcNames; + arcNames.Reserve(numArcItems); + for (int i = 0; i < numArcItems; i++) + arcNames.Add(arcItems[i].Name); + SortFileNames(arcNames, arcIndices); + TestDuplicateString(arcNames, arcIndices); + } + + UStringVector dirNames; + { + dirNames.Reserve(numDirItems); + for (int i = 0; i < numDirItems; i++) + dirNames.Add(dirItems.GetLogPath(i)); + SortFileNames(dirNames, dirIndices); + TestDuplicateString(dirNames, dirIndices); + } + + int dirIndex = 0, arcIndex = 0; + while (dirIndex < numDirItems && arcIndex < numArcItems) + { + CUpdatePair pair; + int dirIndex2 = dirIndices[dirIndex]; + int arcIndex2 = arcIndices[arcIndex]; + const CDirItem &di = dirItems.Items[dirIndex2]; + const CArcItem &ai = arcItems[arcIndex2]; + int compareResult = CompareFileNames(dirNames[dirIndex2], ai.Name); + if (compareResult < 0) + { + pair.State = NUpdateArchive::NPairState::kOnlyOnDisk; + pair.DirIndex = dirIndex2; + dirIndex++; + } + else if (compareResult > 0) + { + pair.State = ai.Censored ? + NUpdateArchive::NPairState::kOnlyInArchive: + NUpdateArchive::NPairState::kNotMasked; + pair.ArcIndex = arcIndex2; + arcIndex++; + } + else + { + if (!ai.Censored) + ThrowError(kNotCensoredCollisionMessaged, dirNames[dirIndex2], ai.Name); + pair.DirIndex = dirIndex2; + pair.ArcIndex = arcIndex2; + switch (ai.MTimeDefined ? MyCompareTime( + ai.TimeType != - 1 ? (NFileTimeType::EEnum)ai.TimeType : fileTimeType, + di.MTime, ai.MTime): 0) + { + case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break; + case 1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break; + default: + pair.State = (ai.SizeDefined && di.Size == ai.Size) ? + NUpdateArchive::NPairState::kSameFiles : + NUpdateArchive::NPairState::kUnknowNewerFiles; + } + dirIndex++; + arcIndex++; + } + updatePairs.Add(pair); + } + + for (; dirIndex < numDirItems; dirIndex++) + { + CUpdatePair pair; + pair.State = NUpdateArchive::NPairState::kOnlyOnDisk; + pair.DirIndex = dirIndices[dirIndex]; + updatePairs.Add(pair); + } + + for (; arcIndex < numArcItems; arcIndex++) + { + CUpdatePair pair; + int arcIndex2 = arcIndices[arcIndex]; + pair.State = arcItems[arcIndex2].Censored ? + NUpdateArchive::NPairState::kOnlyInArchive: + NUpdateArchive::NPairState::kNotMasked; + pair.ArcIndex = arcIndex2; + updatePairs.Add(pair); + } + + updatePairs.ReserveDown(); +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.h b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.h new file mode 100644 index 000000000..3a332649c --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.h @@ -0,0 +1,25 @@ +// 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 ArcIndex; + int DirIndex; + CUpdatePair(): ArcIndex(-1), DirIndex(-1) {} +}; + +void GetUpdatePairInfoList( + const CDirItems &dirItems, + const CObjectVector &arcItems, + NFileTimeType::EEnum fileTimeType, + CRecordVector &updatePairs); + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.cpp new file mode 100644 index 000000000..c21db3b2a --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.cpp @@ -0,0 +1,58 @@ +// UpdateProduce.cpp + +#include "StdAfx.h" + +#include "UpdateProduce.h" + +using namespace NUpdateArchive; + +static const char *kUpdateActionSetCollision = "Internal collision in update action set"; + +void UpdateProduce( + const CRecordVector &updatePairs, + const CActionSet &actionSet, + CRecordVector &operationChain, + IUpdateProduceCallback *callback) +{ + for (int i = 0; i < updatePairs.Size(); i++) + { + const CUpdatePair &pair = updatePairs[i]; + + CUpdatePair2 up2; + up2.IsAnti = false; + up2.DirIndex = pair.DirIndex; + up2.ArcIndex = pair.ArcIndex; + up2.NewData = up2.NewProps = true; + + switch(actionSet.StateActions[pair.State]) + { + case NPairAction::kIgnore: + /* + if (pair.State != NPairState::kOnlyOnDisk) + IgnoreArchiveItem(m_ArchiveItems[pair.ArcIndex]); + // cout << "deleting"; + */ + if (callback) + callback->ShowDeleteFile(pair.ArcIndex); + continue; + + case NPairAction::kCopy: + if (pair.State == NPairState::kOnlyOnDisk) + throw kUpdateActionSetCollision; + up2.NewData = up2.NewProps = false; + break; + + case NPairAction::kCompress: + if (pair.State == NPairState::kOnlyInArchive || + pair.State == NPairState::kNotMasked) + throw kUpdateActionSetCollision; + break; + + case NPairAction::kCompressAsAnti: + up2.IsAnti = true; + break; + } + operationChain.Add(up2); + } + operationChain.ReserveDown(); +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.h b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.h new file mode 100644 index 000000000..e18648cd9 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.h @@ -0,0 +1,35 @@ +// UpdateProduce.h + +#ifndef __UPDATE_PRODUCE_H +#define __UPDATE_PRODUCE_H + +#include "UpdatePair.h" + +struct CUpdatePair2 +{ + bool NewData; + bool NewProps; + bool IsAnti; + + int DirIndex; + int ArcIndex; + int NewNameIndex; + + bool ExistOnDisk() const { return DirIndex != -1; } + bool ExistInArchive() const { return ArcIndex != -1; } + + CUpdatePair2(): IsAnti(false), DirIndex(-1), ArcIndex(-1), NewNameIndex(-1) {} +}; + +struct IUpdateProduceCallback +{ + virtual HRESULT ShowDeleteFile(int arcIndex) = 0; +}; + +void UpdateProduce( + const CRecordVector &updatePairs, + const NUpdateArchive::CActionSet &actionSet, + CRecordVector &operationChain, + IUpdateProduceCallback *callback); + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.cpp new file mode 100644 index 000000000..164118e2c --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.cpp @@ -0,0 +1,59 @@ +// WorkDir.cpp + +#include "StdAfx.h" + +#include "Common/StringConvert.h" +#include "Common/Wildcard.h" + +#include "Windows/FileDir.h" +#include "Windows/FileName.h" + +#include "WorkDir.h" + +using namespace NWindows; +using namespace NFile; + +UString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const UString &path) +{ + NWorkDir::NMode::EEnum mode = workDirInfo.Mode; + #ifndef UNDER_CE + if (workDirInfo.ForRemovableOnly) + { + mode = NWorkDir::NMode::kCurrent; + UString prefix = path.Left(3); + if (prefix[1] == L':' && prefix[2] == L'\\') + { + UINT driveType = GetDriveType(GetSystemString(prefix, ::AreFileApisANSI() ? CP_ACP : CP_OEMCP)); + 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; + */ + } + #endif + switch(mode) + { + case NWorkDir::NMode::kCurrent: + { + return ExtractDirPrefixFromPath(path); + } + case NWorkDir::NMode::kSpecified: + { + UString tempDir = workDirInfo.Path; + NName::NormalizeDirPathPrefix(tempDir); + return tempDir; + } + default: + { + UString tempDir; + if (!NDirectory::MyGetTempPath(tempDir)) + throw 141717; + return tempDir; + } + } +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.h b/src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.h new file mode 100644 index 000000000..0643d67a4 --- /dev/null +++ b/src/libs/7zip/win/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/src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.cpp new file mode 100644 index 000000000..ac178078a --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.cpp @@ -0,0 +1,293 @@ +// ZipRegistry.cpp + +#include "StdAfx.h" + +#include "Common/IntToString.h" +#include "Common/StringConvert.h" + +#include "Windows/FileDir.h" +#include "Windows/Registry.h" +#include "Windows/Synchronization.h" + +#include "ZipRegistry.h" + +using namespace NWindows; +using namespace NRegistry; + +static NSynchronization::CCriticalSection g_CS; +#define CS_LOCK NSynchronization::CCriticalSectionLock lock(g_CS); + +static const TCHAR *kCuPrefix = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip") TEXT(STRING_PATH_SEPARATOR); + +static CSysString GetKeyPath(const CSysString &path) { return kCuPrefix + path; } + +static LONG OpenMainKey(CKey &key, LPCTSTR keyName) +{ + return key.Open(HKEY_CURRENT_USER, GetKeyPath(keyName), KEY_READ); +} + +static LONG CreateMainKey(CKey &key, LPCTSTR keyName) +{ + return key.Create(HKEY_CURRENT_USER, GetKeyPath(keyName)); +} + +namespace NExtract +{ + +static const TCHAR *kKeyName = TEXT("Extraction"); + +static const TCHAR *kExtractMode = TEXT("ExtractMode"); +static const TCHAR *kOverwriteMode = TEXT("OverwriteMode"); +static const TCHAR *kShowPassword = TEXT("ShowPassword"); +static const TCHAR *kPathHistory = TEXT("PathHistory"); + +void CInfo::Save() const +{ + CS_LOCK + CKey key; + CreateMainKey(key, kKeyName); + key.SetValue(kExtractMode, (UInt32)PathMode); + key.SetValue(kOverwriteMode, (UInt32)OverwriteMode); + key.SetValue(kShowPassword, ShowPassword); + key.RecurseDeleteKey(kPathHistory); + key.SetValue_Strings(kPathHistory, Paths); +} + + +void CInfo::Load() +{ + PathMode = NPathMode::kCurrentPathnames; + OverwriteMode = NOverwriteMode::kAskBefore; + ShowPassword = false; + Paths.Clear(); + + CS_LOCK + CKey key; + if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS) + return; + + key.GetValue_Strings(kPathHistory, Paths); + UInt32 v; + if (key.QueryValue(kExtractMode, v) == ERROR_SUCCESS && v <= NPathMode::kNoPathnames) + PathMode = (NPathMode::EEnum)v; + if (key.QueryValue(kOverwriteMode, v) == ERROR_SUCCESS && v <= NOverwriteMode::kAutoRenameExisting) + OverwriteMode = (NOverwriteMode::EEnum)v; + key.GetValue_IfOk(kShowPassword, ShowPassword); +} + +} + +namespace NCompression +{ + +static const TCHAR *kKeyName = TEXT("Compression"); + +static const TCHAR *kArcHistory = TEXT("ArcHistory"); +static const WCHAR *kArchiver = L"Archiver"; +static const TCHAR *kShowPassword = TEXT("ShowPassword"); +static const TCHAR *kEncryptHeaders = TEXT("EncryptHeaders"); + +static const TCHAR *kOptionsKeyName = TEXT("Options"); + +static const TCHAR *kLevel = TEXT("Level"); +static const TCHAR *kDictionary = TEXT("Dictionary"); +static const TCHAR *kOrder = TEXT("Order"); +static const TCHAR *kBlockSize = TEXT("BlockSize"); +static const TCHAR *kNumThreads = TEXT("NumThreads"); +static const WCHAR *kMethod = L"Method"; +static const WCHAR *kOptions = L"Options"; +static const WCHAR *kEncryptionMethod = L"EncryptionMethod"; + +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 CInfo::Save() const +{ + CS_LOCK + + CKey key; + CreateMainKey(key, kKeyName); + key.SetValue(kLevel, (UInt32)Level); + key.SetValue(kArchiver, ArcType); + key.SetValue(kShowPassword, ShowPassword); + key.SetValue(kEncryptHeaders, EncryptHeaders); + key.RecurseDeleteKey(kArcHistory); + key.SetValue_Strings(kArcHistory, ArcPaths); + + key.RecurseDeleteKey(kOptionsKeyName); + { + CKey optionsKey; + optionsKey.Create(key, kOptionsKeyName); + for (int i = 0; i < Formats.Size(); i++) + { + const CFormatOptions &fo = Formats[i]; + CKey fk; + fk.Create(optionsKey, fo.FormatID); + + SetRegUInt32(fk, kLevel, fo.Level); + SetRegUInt32(fk, kDictionary, fo.Dictionary); + SetRegUInt32(fk, kOrder, fo.Order); + SetRegUInt32(fk, kBlockSize, fo.BlockLogSize); + SetRegUInt32(fk, kNumThreads, fo.NumThreads); + + SetRegString(fk, kMethod, fo.Method); + SetRegString(fk, kOptions, fo.Options); + SetRegString(fk, kEncryptionMethod, fo.EncryptionMethod); + } + } +} + +void CInfo::Load() +{ + ArcPaths.Clear(); + Formats.Clear(); + + Level = 5; + ArcType = L"7z"; + ShowPassword = false; + EncryptHeaders = false; + + CS_LOCK + CKey key; + + if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS) + return; + + key.GetValue_Strings(kArcHistory, ArcPaths); + + { + CKey optionsKey; + if (optionsKey.Open(key, kOptionsKeyName, KEY_READ) == ERROR_SUCCESS) + { + CSysStringVector formatIDs; + optionsKey.EnumKeys(formatIDs); + for (int i = 0; i < formatIDs.Size(); i++) + { + CKey fk; + CFormatOptions fo; + fo.FormatID = formatIDs[i]; + if (fk.Open(optionsKey, fo.FormatID, KEY_READ) == ERROR_SUCCESS) + { + GetRegString(fk, kOptions, fo.Options); + GetRegString(fk, kMethod, fo.Method); + GetRegString(fk, kEncryptionMethod, fo.EncryptionMethod); + + GetRegUInt32(fk, kLevel, fo.Level); + GetRegUInt32(fk, kDictionary, fo.Dictionary); + GetRegUInt32(fk, kOrder, fo.Order); + GetRegUInt32(fk, kBlockSize, fo.BlockLogSize); + GetRegUInt32(fk, kNumThreads, fo.NumThreads); + + Formats.Add(fo); + } + } + } + } + + UString a; + if (key.QueryValue(kArchiver, a) == ERROR_SUCCESS) + ArcType = a; + key.GetValue_IfOk(kLevel, Level); + key.GetValue_IfOk(kShowPassword, ShowPassword); + key.GetValue_IfOk(kEncryptHeaders, EncryptHeaders); +} + +} + +static const TCHAR *kOptionsInfoKeyName = TEXT("Options"); + +namespace NWorkDir +{ +static const TCHAR *kWorkDirType = TEXT("WorkDirType"); +static const WCHAR *kWorkDirPath = L"WorkDirPath"; +static const TCHAR *kTempRemovableOnly = TEXT("TempRemovableOnly"); + + +void CInfo::Save()const +{ + CS_LOCK + CKey key; + CreateMainKey(key, kOptionsInfoKeyName); + key.SetValue(kWorkDirType, (UInt32)Mode); + key.SetValue(kWorkDirPath, Path); + key.SetValue(kTempRemovableOnly, ForRemovableOnly); +} + +void CInfo::Load() +{ + SetDefault(); + + CS_LOCK + CKey key; + if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS) + return; + + UInt32 dirType; + if (key.QueryValue(kWorkDirType, dirType) != ERROR_SUCCESS) + return; + switch (dirType) + { + case NMode::kSystem: + case NMode::kCurrent: + case NMode::kSpecified: + Mode = (NMode::EEnum)dirType; + } + if (key.QueryValue(kWorkDirPath, Path) != ERROR_SUCCESS) + { + Path.Empty(); + if (Mode == NMode::kSpecified) + Mode = NMode::kSystem; + } + key.GetValue_IfOk(kTempRemovableOnly, ForRemovableOnly); +} + +} + +static const TCHAR *kCascadedMenu = TEXT("CascadedMenu"); +static const TCHAR *kContextMenu = TEXT("ContextMenu"); + +void CContextMenuInfo::Save() const +{ + CS_LOCK + CKey key; + CreateMainKey(key, kOptionsInfoKeyName); + key.SetValue(kCascadedMenu, Cascaded); + key.SetValue(kContextMenu, Flags); +} + +void CContextMenuInfo::Load() +{ + Cascaded = true; + Flags = (UInt32)-1; + CS_LOCK + CKey key; + if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS) + return; + key.GetValue_IfOk(kCascadedMenu, Cascaded); + key.GetValue_IfOk(kContextMenu, Flags); +} diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.h new file mode 100644 index 000000000..378353868 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.h @@ -0,0 +1,105 @@ +// ZipRegistry.h + +#ifndef __ZIP_REGISTRY_H +#define __ZIP_REGISTRY_H + +#include "Common/MyString.h" +#include "Common/Types.h" + +#include "ExtractMode.h" + +namespace NExtract +{ + struct CInfo + { + NPathMode::EEnum PathMode; + NOverwriteMode::EEnum OverwriteMode; + bool ShowPassword; + UStringVector Paths; + + void Save() const; + void Load(); + }; +} + +namespace NCompression +{ + struct CFormatOptions + { + UInt32 Level; + UInt32 Dictionary; + UInt32 Order; + UInt32 BlockLogSize; + UInt32 NumThreads; + + CSysString FormatID; + UString Method; + UString Options; + UString EncryptionMethod; + + void ResetForLevelChange() + { + BlockLogSize = NumThreads = Level = Dictionary = Order = UInt32(-1); + Method.Empty(); + // Options.Empty(); + // EncryptionMethod.Empty(); + } + CFormatOptions() { ResetForLevelChange(); } + }; + + struct CInfo + { + UInt32 Level; + bool ShowPassword; + bool EncryptHeaders; + UString ArcType; + UStringVector ArcPaths; + + CObjectVector Formats; + + void Save() const; + void Load(); + }; +} + +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 Save() const; + void Load(); + }; +} + + +struct CContextMenuInfo +{ + bool Cascaded; + UInt32 Flags; + + void Save() const; + void Load(); +}; + +#endif -- cgit v1.2.3