diff options
Diffstat (limited to 'src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common')
43 files changed, 13873 insertions, 0 deletions
diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.cpp new file mode 100644 index 000000000..48587264f --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.cpp @@ -0,0 +1,1266 @@ +// ArchiveCommandLine.cpp + +#include "StdAfx.h" +#undef printf +#undef sprintf + +#ifdef _WIN32 +#ifndef UNDER_CE +#include <io.h> +#endif +#endif +#include <stdio.h> + +#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" +#else +#include "myPrivate.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; + +static bool StringToUInt32(const wchar_t *s, UInt32 &v) +{ + if (*s == 0) + return false; + const wchar_t *end; + v = ConvertStringToUInt32(s, &end); + return *end == 0; +} + +static void AddNewLine(UString &s) +{ + s += L'\n'; +} + +CArcCmdLineException::CArcCmdLineException(const char *a, const wchar_t *u) +{ + (*this) += MultiByteToUnicodeString(a); + if (u) + { + AddNewLine(*this); + (*this) += u; + } +} + +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, +#ifdef _WIN32 + kShareForWrite, +#endif + kUseLStat, + kCaseSensitive, + kHash, + kArcNameMode, + + kDisableWildcardParsing, + kElimDup, + kFullPathMode, + + kHardLinks, + kSymLinks, + kNtSecurity, + kAltStreams, + kReplaceColonForAltStream, + kWriteToAltStreamIfColon, + + kDeleteAfterCompressing, + kSetArcMTime, + kExcludedArcType +}; + +} + + +static const wchar_t kRecursedIDChar = 'r'; +static const char *kRecursedPostCharSet = "0-"; + +static const char *k_ArcNameMode_PostCharSet = "sea"; + +static inline const EArcNameMode ParseArcNameMode(int postCharIndex) +{ + switch (postCharIndex) + { + case 1: return k_ArcNameMode_Exact; + case 2: return k_ArcNameMode_Add; + default: return k_ArcNameMode_Smart; + } +} + +namespace NRecursedPostCharIndex { + enum EEnum + { + kWildcardRecursionOnly = 0, + kNoRecursion = 1 + }; +} + +static const char kImmediateNameID = '!'; +static const char kMapNameID = '#'; +static const char kFileListID = '@'; + +static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be +static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be + +static const char *kOverwritePostCharSet = "asut"; + +NExtract::NOverwriteMode::EEnum k_OverwriteModes[] = +{ + NExtract::NOverwriteMode::kOverwrite, + NExtract::NOverwriteMode::kSkip, + NExtract::NOverwriteMode::kRename, + NExtract::NOverwriteMode::kRenameExisting +}; + +static const CSwitchForm kSwitchForms[] = +{ + { "?" }, + { "h" }, + { "-help" }, + { "ba" }, + { "bd" }, + { "t", NSwitchType::kString, false, 1 }, + { "y" }, + #ifndef _NO_CRYPTO + { "p", NSwitchType::kString }, + #endif + { "m", NSwitchType::kString, true, 1 }, + { "o", NSwitchType::kString, false, 1 }, + { "w", NSwitchType::kString }, + { "i", NSwitchType::kString, true, kSomeCludePostStringMinSize}, + { "x", NSwitchType::kString, true, kSomeCludePostStringMinSize}, + { "ai", NSwitchType::kString, true, kSomeCludePostStringMinSize}, + { "ax", NSwitchType::kString, true, kSomeCludePostStringMinSize}, + { "an" }, + { "u", NSwitchType::kString, true, 1}, + { "v", NSwitchType::kString, true, 1}, + { "r", NSwitchType::kChar, false, 0, kRecursedPostCharSet }, + { "sfx", NSwitchType::kString }, + { "si", NSwitchType::kString }, + { "so" }, + { "ao", NSwitchType::kChar, false, 1, kOverwritePostCharSet}, + { "seml", NSwitchType::kString, false, 0}, + { "ad" }, + { "slp", NSwitchType::kMinus }, + // { "scs", NSwitchType::kString }, + // { "scc", NSwitchType::kString }, + { "slt" }, + // { "ssw" }, + { "l" }, + { "ssc", NSwitchType::kMinus }, + { "scrc", NSwitchType::kString, true, 0 }, + { "sa", NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet }, + + { "spd" }, + { "spe", NSwitchType::kMinus }, + { "spf", NSwitchType::kString, false, 0 }, + + { "snh", NSwitchType::kMinus }, + { "snl", NSwitchType::kMinus }, + { "sni" }, + { "sns", NSwitchType::kMinus }, + + { "snr" }, + { "snc" }, + + { "sdel" }, + { "stl" }, + { "stx", NSwitchType::kString, true, 1 } +}; + +static const wchar_t *kUniversalWildcard = L"*"; +static const int kMinNonSwitchWords = 1; +static const int kCommandIndex = 0; + +// 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 const char *kCannotFindArchive = "Cannot find archive"; + +bool CArcCommand::IsFromExtractGroup() const +{ + switch (CommandType) + { + case NCommandType::kTest: + case NCommandType::kExtract: + case NCommandType::kExtractFull: + return true; + } + return false; +} + +NExtract::NPathMode::EEnum CArcCommand::GetPathMode() const +{ + switch (CommandType) + { + case NCommandType::kTest: + case NCommandType::kExtractFull: + return NExtract::NPathMode::kFullPaths; + } + return NExtract::NPathMode::kNoPaths; +} + +bool CArcCommand::IsFromUpdateGroup() const +{ + switch (CommandType) + { + case NCommandType::kAdd: + case NCommandType::kUpdate: + case NCommandType::kDelete: + case NCommandType::kRename: + return true; + } + return false; +} + +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 const char *g_Commands = "audtexlbih"; + +static bool ParseArchiveCommand(const UString &commandString, CArcCommand &command) +{ + UString s = commandString; + s.MakeLower_Ascii(); + if (s.Len() == 1) + { + if (s[0] > 0x7F) + return false; + int index = FindCharPosInString(g_Commands, (char)s[0]); + if (index < 0) + return false; + command.CommandType = (NCommandType::EEnum)index; + return true; + } + if (s.Len() == 2 && s[0] == 'r' && s[1] == 'n') + { + command.CommandType = (NCommandType::kRename); + return true; + } + return false; +} + +// ------------------------------------------------------------------ +// filenames functions + +static void AddNameToCensor(NWildcard::CCensor &censor, + const UString &name, bool include, NRecursedType::EEnum type, bool wildcardMatching) +{ + bool recursed = false; + + switch (type) + { + case NRecursedType::kWildcardOnlyRecursed: + recursed = DoesNameContainWildcard(name); + break; + case NRecursedType::kRecursed: + recursed = true; + break; + } + censor.AddPreItem(include, name, recursed, wildcardMatching); +} + +static void AddRenamePair(CObjectVector<CRenamePair> *renamePairs, + const UString &oldName, const UString &newName, NRecursedType::EEnum type, + bool wildcardMatching) +{ + CRenamePair &pair = renamePairs->AddNew(); + pair.OldName = oldName; + pair.NewName = newName; + pair.RecursedType = type; + pair.WildcardParsing = wildcardMatching; + + if (!pair.Prepare()) + { + UString val; + val += pair.OldName; + AddNewLine(val); + val += pair.NewName; + AddNewLine(val); + if (type == NRecursedType::kRecursed) + val += L"-r"; + else if (type == NRecursedType::kRecursed) + val += L"-r0"; + throw CArcCmdLineException("Unsupported rename command:", val); + } +} + +static void AddToCensorFromListFile( + CObjectVector<CRenamePair> *renamePairs, + NWildcard::CCensor &censor, + LPCWSTR fileName, bool include, NRecursedType::EEnum type, bool wildcardMatching, Int32 codePage) +{ + UStringVector names; + if (!NFind::DoesFileExist(us2fs(fileName))) + throw CArcCmdLineException(kCannotFindListFile, fileName); + if (!ReadNamesFromListFile(us2fs(fileName), names, codePage)) + throw CArcCmdLineException(kIncorrectListFile, fileName); + if (renamePairs) + { + if ((names.Size() & 1) != 0) + throw CArcCmdLineException(kIncorrectListFile, fileName); + for (unsigned i = 0; i < names.Size(); i += 2) + { + // change type !!!! + AddRenamePair(renamePairs, names[i], names[i + 1], type, wildcardMatching); + } + } + else + FOR_VECTOR (i, names) + AddNameToCensor(censor, names[i], include, type, wildcardMatching); +} + +static void AddToCensorFromNonSwitchesStrings( + CObjectVector<CRenamePair> *renamePairs, + unsigned startIndex, + NWildcard::CCensor &censor, + const UStringVector &nonSwitchStrings, NRecursedType::EEnum type, + bool wildcardMatching, + bool thereAreSwitchIncludes, Int32 codePage) +{ + if ((renamePairs || nonSwitchStrings.Size() == startIndex) && !thereAreSwitchIncludes) + AddNameToCensor(censor, kUniversalWildcard, true, type, + true // wildcardMatching + ); + + int oldIndex = -1; + + for (unsigned i = startIndex; i < nonSwitchStrings.Size(); i++) + { + const UString &s = nonSwitchStrings[i]; + if (s.IsEmpty()) + throw CArcCmdLineException(kEmptyFilePath); + if (s[0] == kFileListID) + AddToCensorFromListFile(renamePairs, censor, s.Ptr(1), true, type, wildcardMatching, codePage); + else if (renamePairs) + { + if (oldIndex == -1) + oldIndex = startIndex; + else + { + // NRecursedType::EEnum type is used for global wildcard (-i! switches) + AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, NRecursedType::kNonRecursed, wildcardMatching); + // AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, type); + oldIndex = -1; + } + } + else + AddNameToCensor(censor, s, true, type, wildcardMatching); + } + + if (oldIndex != -1) + { + throw CArcCmdLineException("There is no second file name for rename pair:", nonSwitchStrings[oldIndex]); + } +} + +#ifdef _WIN32 + +struct CEventSetEnd +{ + UString Name; + + CEventSetEnd(const wchar_t *name): Name(name) {} + ~CEventSetEnd() + { + NSynchronization::CManualResetEvent event; + if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(Name)) == 0) + event.Set(); + } +}; + +const char *k_IncorrectMapCommand = "Incorrect Map command"; + +static const char *ParseMapWithPaths( + NWildcard::CCensor &censor, + const UString &s2, bool include, + NRecursedType::EEnum commonRecursedType, + bool wildcardMatching) +{ + UString s = s2; + int pos = s.Find(L':'); + if (pos < 0) + return k_IncorrectMapCommand; + int pos2 = s.Find(L':', pos + 1); + if (pos2 < 0) + return k_IncorrectMapCommand; + + CEventSetEnd eventSetEnd((const wchar_t *)s + (pos2 + 1)); + s.DeleteFrom(pos2); + UInt32 size; + if (!StringToUInt32(s.Ptr(pos + 1), size) + || size < sizeof(wchar_t) + || size > ((UInt32)1 << 31) + || size % sizeof(wchar_t) != 0) + return "Unsupported Map data size"; + + s.DeleteFrom(pos); + CFileMapping map; + if (map.Open(FILE_MAP_READ, GetSystemString(s)) != 0) + return "Can not open mapping"; + LPVOID data = map.Map(FILE_MAP_READ, 0, size); + if (!data) + return "MapViewOfFile error"; + CFileUnmapper unmapper(data); + + UString name; + const wchar_t *p = (const wchar_t *)data; + if (*p != 0) // data format marker + return "Unsupported Map data"; + UInt32 numChars = size / sizeof(wchar_t); + for (UInt32 i = 1; i < numChars; i++) + { + wchar_t c = p[i]; + if (c == 0) + { + // MessageBoxW(0, name, L"7-Zip", 0); + AddNameToCensor(censor, name, include, commonRecursedType, wildcardMatching); + name.Empty(); + } + else + name += c; + } + if (!name.IsEmpty()) + return "Map data error"; + + return NULL; +} + +#endif + +static void AddSwitchWildcardsToCensor( + NWildcard::CCensor &censor, + const UStringVector &strings, bool include, + NRecursedType::EEnum commonRecursedType, + bool wildcardMatching, + Int32 codePage) +{ + const char *errorMessage = NULL; + unsigned i; + for (i = 0; i < strings.Size(); i++) + { + const UString &name = strings[i]; + NRecursedType::EEnum recursedType; + unsigned pos = 0; + + if (name.Len() < kSomeCludePostStringMinSize) + { + errorMessage = "Too short switch"; + break; + } + + if (::MyCharLower_Ascii(name[pos]) == kRecursedIDChar) + { + pos++; + wchar_t c = name[pos]; + int index = -1; + if (c <= 0x7F) + index = FindCharPosInString(kRecursedPostCharSet, (char)c); + recursedType = GetRecursedTypeFromIndex(index); + if (index >= 0) + pos++; + } + else + recursedType = commonRecursedType; + + if (name.Len() < pos + kSomeCludeAfterRecursedPostStringMinSize) + { + errorMessage = "Too short switch"; + break; + } + + UString tail = name.Ptr(pos + 1); + + if (name[pos] == kImmediateNameID) + AddNameToCensor(censor, tail, include, recursedType, wildcardMatching); + else if (name[pos] == kFileListID) + AddToCensorFromListFile(NULL, censor, tail, include, recursedType, wildcardMatching, codePage); + #ifdef _WIN32 + else if (name[pos] == kMapNameID) + { + errorMessage = ParseMapWithPaths(censor, tail, include, recursedType, wildcardMatching); + if (errorMessage) + break; + } + #endif + else + { + errorMessage = "Incorrect wildcarc type marker"; + break; + } + } + if (i != strings.Size()) + throw CArcCmdLineException(errorMessage, strings[i]); +} + +#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::CFileInfo fi; + const FString path = us2fs(prefix + name); + if (NFile::NName::IsDevicePath(path)) + return; + if (fi.Find(path)) + name = fs2us(fi.Name); +} + +static void ConvertToLongNames(const UString &prefix, CObjectVector<NWildcard::CItem> &items) +{ + FOR_VECTOR (i, items) + { + NWildcard::CItem &item = items[i]; + if (item.Recursive || item.PathParts.Size() != 1) + continue; + if (prefix.IsEmpty() && item.IsDriveItem()) + continue; + ConvertToLongName(prefix, item.PathParts.Front()); + } +} + +static void ConvertToLongNames(const UString &prefix, NWildcard::CCensorNode &node) +{ + ConvertToLongNames(prefix, node.IncludeItems); + ConvertToLongNames(prefix, node.ExcludeItems); + unsigned i; + for (i = 0; i < node.SubNodes.Size(); i++) + { + UString &name = node.SubNodes[i].Name; + if (prefix.IsEmpty() && NWildcard::IsDriveColonName(name)) + continue; + ConvertToLongName(prefix, name); + } + // mix folders with same name + for (i = 0; i < node.SubNodes.Size(); i++) + { + NWildcard::CCensorNode &nextNode1 = node.SubNodes[i]; + for (unsigned j = i + 1; j < node.SubNodes.Size();) + { + const NWildcard::CCensorNode &nextNode2 = node.SubNodes[j]; + if (nextNode1.Name.IsEqualToNoCase(nextNode2.Name)) + { + 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_PATH_SEPARATOR, nextNode); + } +} + +void ConvertToLongNames(NWildcard::CCensor &censor) +{ + FOR_VECTOR (i, censor.Pairs) + { + 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; +} +*/ + +static const wchar_t *kUpdatePairStateIDSet = L"pqrxyzw"; +static const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1}; + +static const unsigned kNumUpdatePairActions = 4; +static const char *kUpdateIgnoreItselfPostStringID = "-"; +static const wchar_t kUpdateNewArchivePostCharID = '!'; + + +static bool ParseUpdateCommandString2(const UString &command, + NUpdateArchive::CActionSet &actionSet, UString &postString) +{ + for (unsigned i = 0; i < command.Len();) + { + wchar_t c = MyCharLower_Ascii(command[i]); + int statePos = FindCharPosInString(kUpdatePairStateIDSet, c); + if (statePos < 0) + { + postString = command.Ptr(i); + return true; + } + i++; + if (i >= command.Len()) + return false; + c = command[i]; + if (c < '0' || c >= '0' + kNumUpdatePairActions) + return false; + int actionPos = c - '0'; + actionSet.StateActions[statePos] = (NUpdateArchive::NPairAction::EEnum)(actionPos); + if (kUpdatePairStateNotSupportedActions[statePos] == actionPos) + return false; + i++; + } + postString.Empty(); + return true; +} + +static void ParseUpdateCommandString(CUpdateOptions &options, + const UStringVector &updatePostStrings, + const NUpdateArchive::CActionSet &defaultActionSet) +{ + const char *errorMessage = "incorrect update switch command"; + unsigned i; + for (i = 0; i < updatePostStrings.Size(); i++) + { + const UString &updateString = updatePostStrings[i]; + if (updateString.IsEqualTo(kUpdateIgnoreItselfPostStringID)) + { + if (options.UpdateArchiveItself) + { + options.UpdateArchiveItself = false; + options.Commands.Delete(0); + } + } + else + { + NUpdateArchive::CActionSet actionSet = defaultActionSet; + + UString postString; + if (!ParseUpdateCommandString2(updateString, actionSet, postString)) + break; + if (postString.IsEmpty()) + { + if (options.UpdateArchiveItself) + options.Commands[0].ActionSet = actionSet; + } + else + { + if (postString[0] != kUpdateNewArchivePostCharID) + break; + CUpdateArchiveCommand uc; + UString archivePath = postString.Ptr(1); + if (archivePath.IsEmpty()) + break; + uc.UserArchivePath = archivePath; + uc.ActionSet = actionSet; + options.Commands.Add(uc); + } + } + } + if (i != updatePostStrings.Size()) + throw CArcCmdLineException(errorMessage, updatePostStrings[i]); +} + +bool ParseComplexSize(const wchar_t *s, UInt64 &result); + +static void SetAddCommandOptions( + NCommandType::EEnum commandType, + const CParser &parser, + CUpdateOptions &options) +{ + NUpdateArchive::CActionSet defaultActionSet; + switch (commandType) + { + case NCommandType::kAdd: + defaultActionSet = NUpdateArchive::k_ActionSet_Add; + break; + case NCommandType::kDelete: + defaultActionSet = NUpdateArchive::k_ActionSet_Delete; + break; + default: + defaultActionSet = NUpdateArchive::k_ActionSet_Update; + } + + 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()) + NDir::MyGetTempPath(options.WorkingDir); + else + options.WorkingDir = us2fs(postString); + } + options.SfxMode = parser[NKey::kSfx].ThereIs; + if (options.SfxMode) + options.SfxModule = us2fs(parser[NKey::kSfx].PostStrings[0]); + + if (parser[NKey::kVolume].ThereIs) + { + const UStringVector &sv = parser[NKey::kVolume].PostStrings; + FOR_VECTOR (i, sv) + { + UInt64 size; + if (!ParseComplexSize(sv[i], size) || size == 0) + throw CArcCmdLineException("Incorrect volume size:", sv[i]); + options.VolumesSizes.Add(size); + } + } +} + +static void SetMethodOptions(const CParser &parser, CObjectVector<CProperty> &properties) +{ + if (parser[NKey::kProperty].ThereIs) + { + FOR_VECTOR (i, parser[NKey::kProperty].PostStrings) + { + CProperty prop; + prop.Name = parser[NKey::kProperty].PostStrings[i]; + int index = prop.Name.Find(L'='); + if (index >= 0) + { + prop.Value = prop.Name.Ptr(index + 1); + prop.Name.DeleteFrom(index); + } + properties.Add(prop); + } + } +} + +CArcCmdLineParser::CArcCmdLineParser(): parser(ARRAY_SIZE(kSwitchForms)) {} + +void CArcCmdLineParser::Parse1(const UStringVector &commandStrings, + CArcCmdLineOptions &options) +{ + if (!parser.ParseStrings(kSwitchForms, commandStrings)) + throw CArcCmdLineException(parser.ErrorMessage, parser.ErrorLine); + + 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; + + if (parser[NKey::kCaseSensitive].ThereIs) + { + g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus; + options.CaseSensitiveChange = true; + options.CaseSensitive = g_CaseSensitive; + } + + #ifdef _7ZIP_LARGE_PAGES + options.LargePages = false; + if (parser[NKey::kLargePages].ThereIs) + { + options.LargePages = !parser[NKey::kLargePages].WithMinus; + } + #endif +} + +struct CCodePagePair +{ + const char *Name; + Int32 CodePage; +}; + +static const unsigned kNumByteOnlyCodePages = 3; + +static CCodePagePair g_CodePagePairs[] = +{ + { "utf-8", CP_UTF8 }, + { "win", CP_ACP }, + { "dos", CP_OEMCP }, + { "utf-16le", MY__CP_UTF16 }, + { "utf-16be", MY__CP_UTF16BE } +}; + +static Int32 FindCharset(const NCommandLineParser::CParser &parser, int keyIndex, + bool byteOnlyCodePages, Int32 defaultVal) +{ + if (!parser[keyIndex].ThereIs) + return defaultVal; + + UString name = parser[keyIndex].PostStrings.Back(); + UInt32 v; + if (StringToUInt32(name, v)) + if (v < ((UInt32)1 << 16)) + return (Int32)v; + name.MakeLower_Ascii(); + unsigned num = byteOnlyCodePages ? kNumByteOnlyCodePages : ARRAY_SIZE(g_CodePagePairs); + for (unsigned i = 0;; i++) + { + if (i == num) // to disable warnings from different compilers + throw CArcCmdLineException("Unsupported charset:", name); + const CCodePagePair &pair = g_CodePagePairs[i]; + if (name.IsEqualTo(pair.Name)) + return pair.CodePage; + } +} + +void EnumerateDirItemsAndSort( + bool storeAltStreams, + NWildcard::CCensor &censor, + NWildcard::ECensorPathMode censorPathMode, + const UString &addPathPrefix, + UStringVector &sortedPaths, + UStringVector &sortedFullPaths) +{ + UStringVector paths; + { + CDirItems dirItems; + { + dirItems.ScanAltStreams = storeAltStreams; + HRESULT res = EnumerateItems(censor, censorPathMode, addPathPrefix, dirItems, NULL); + if (res != S_OK || dirItems.ErrorPaths.Size() > 0) + { + UString errorPath; + if (dirItems.ErrorPaths.Size() > 0) + errorPath = fs2us(dirItems.ErrorPaths[0]); + throw CArcCmdLineException(kCannotFindArchive, + dirItems.ErrorPaths.Size() > 0 ? (const wchar_t *)errorPath : NULL); + } + } + FOR_VECTOR (i, dirItems.Items) + { + const CDirItem &dirItem = dirItems.Items[i]; + if (!dirItem.IsDir()) + paths.Add(dirItems.GetPhyPath(i)); + } + } + + if (paths.Size() == 0) + throw CArcCmdLineException(kCannotFindArchive); + + UStringVector fullPaths; + + unsigned i; + for (i = 0; i < paths.Size(); i++) + { + FString fullPath; + NFile::NDir::MyGetFullPathName(us2fs(paths[i]), fullPath); + fullPaths.Add(fs2us(fullPath)); + } + CUIntVector indices; + SortFileNames(fullPaths, indices); + sortedPaths.ClearAndReserve(indices.Size()); + sortedFullPaths.ClearAndReserve(indices.Size()); + for (i = 0; i < indices.Size(); i++) + { + unsigned index = indices[i]; + sortedPaths.AddInReserved(paths[index]); + sortedFullPaths.AddInReserved(fullPaths[index]); + if (i > 0 && CompareFileNames(sortedFullPaths[i], sortedFullPaths[i - 1]) == 0) + throw CArcCmdLineException("Duplicate archive path:", sortedFullPaths[i]); + } +} + +static void SetBoolPair(NCommandLineParser::CParser &parser, unsigned switchID, CBoolPair &bp) +{ + bp.Def = parser[switchID].ThereIs; + if (bp.Def) + bp.Val = !parser[switchID].WithMinus; +} + +void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) +{ + const UStringVector &nonSwitchStrings = parser.NonSwitchStrings; + int numNonSwitchStrings = nonSwitchStrings.Size(); + if (numNonSwitchStrings < kMinNonSwitchWords) + throw CArcCmdLineException("The command must be spcified"); + + if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command)) + throw CArcCmdLineException("Unsupported command:", nonSwitchStrings[kCommandIndex]); + + options.TechMode = parser[NKey::kTechMode].ThereIs; + if (parser[NKey::kHash].ThereIs) + options.HashMethods = parser[NKey::kHash].PostStrings; + + if (parser[NKey::kElimDup].ThereIs) + { + options.ExtractOptions.ElimDup.Def = true; + options.ExtractOptions.ElimDup.Val = !parser[NKey::kElimDup].WithMinus; + } + + NWildcard::ECensorPathMode censorPathMode = NWildcard::k_RelatPath; + bool fullPathMode = parser[NKey::kFullPathMode].ThereIs; + if (fullPathMode) + { + censorPathMode = NWildcard::k_AbsPath; + const UString &s = parser[NKey::kFullPathMode].PostStrings[0]; + if (!s.IsEmpty()) + { + if (s == L"2") + censorPathMode = NWildcard::k_FullPath; + else + throw CArcCmdLineException("Unsupported -spf:", s); + } + } + + NRecursedType::EEnum recursedType; + if (parser[NKey::kRecursed].ThereIs) + recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex); + else + recursedType = NRecursedType::kNonRecursed; + + bool wildcardMatching = true; + if (parser[NKey::kDisableWildcardParsing].ThereIs) + wildcardMatching = false; + + Int32 codePage = CP_ACP; + + bool thereAreSwitchIncludes = false; + + if (parser[NKey::kInclude].ThereIs) + { + thereAreSwitchIncludes = true; + AddSwitchWildcardsToCensor(options.Censor, + parser[NKey::kInclude].PostStrings, true, recursedType, wildcardMatching, codePage); + } + + if (parser[NKey::kExclude].ThereIs) + AddSwitchWildcardsToCensor(options.Censor, + parser[NKey::kExclude].PostStrings, false, recursedType, wildcardMatching, codePage); + + int curCommandIndex = kCommandIndex + 1; + bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs && + options.Command.CommandType != NCommandType::kBenchmark && + options.Command.CommandType != NCommandType::kInfo && + options.Command.CommandType != NCommandType::kHash; + + bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); + bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList; + bool isRename = options.Command.CommandType == NCommandType::kRename; + + if ((isExtractOrList || isRename) && options.StdInMode) + thereIsArchiveName = false; + + if (parser[NKey::kArcNameMode].ThereIs) + options.UpdateOptions.ArcNameMode = ParseArcNameMode(parser[NKey::kArcNameMode].PostCharIndex); + + if (thereIsArchiveName) + { + if (curCommandIndex >= numNonSwitchStrings) + throw CArcCmdLineException("Cannot find archive name"); + options.ArchiveName = nonSwitchStrings[curCommandIndex++]; + if (options.ArchiveName.IsEmpty()) + throw CArcCmdLineException("Archive name cannot by empty"); + } + + AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL, + curCommandIndex, options.Censor, + nonSwitchStrings, recursedType, wildcardMatching, + 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]; + + options.ExcludedArcTypes = parser[NKey::kExcludedArcType].PostStrings; + + SetMethodOptions(parser, options.Properties); + + options.EnablePercents = !parser[NKey::kDisablePercents].ThereIs; + + if (options.EnablePercents) + { + if ((options.StdOutMode && !options.IsStdErrTerminal) || + (!options.StdOutMode && !options.IsStdOutTerminal)) + options.EnablePercents = false; + } + + if (parser[NKey::kNtSecurity].ThereIs) options.NtSecurity.SetTrueTrue(); + + SetBoolPair(parser, NKey::kAltStreams, options.AltStreams); + SetBoolPair(parser, NKey::kHardLinks, options.HardLinks); + SetBoolPair(parser, NKey::kSymLinks, options.SymLinks); + + if (isExtractOrList) + { + CExtractOptionsBase &eo = options.ExtractOptions; + + { + CExtractNtOptions &nt = eo.NtOptions; + nt.NtSecurity = options.NtSecurity; + + nt.AltStreams = options.AltStreams; + if (!options.AltStreams.Def) + nt.AltStreams.Val = true; + + nt.HardLinks = options.HardLinks; + if (!options.HardLinks.Def) + nt.HardLinks.Val = true; + + nt.SymLinks = options.SymLinks; + if (!options.SymLinks.Def) + nt.SymLinks.Val = true; + + nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs; + nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs; + } + + options.Censor.AddPathsToCensor(NWildcard::k_AbsPath); + options.Censor.ExtendExclude(); + + // are there paths that look as non-relative (!Prefix.IsEmpty()) + if (!options.Censor.AllAreRelative()) + throw CArcCmdLineException("Cannot use absolute pathnames for this command"); + + NWildcard::CCensor arcCensor; + + if (parser[NKey::kArInclude].ThereIs) + AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, true, NRecursedType::kNonRecursed, wildcardMatching, codePage); + if (parser[NKey::kArExclude].ThereIs) + AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, false, NRecursedType::kNonRecursed, wildcardMatching, codePage); + + if (thereIsArchiveName) + AddNameToCensor(arcCensor, options.ArchiveName, true, NRecursedType::kNonRecursed, wildcardMatching); + + arcCensor.AddPathsToCensor(NWildcard::k_RelatPath); + + #ifdef _WIN32 + ConvertToLongNames(arcCensor); + #endif + + arcCensor.ExtendExclude(); + + if (options.StdInMode) + { + UString arcName = parser[NKey::kStdIn].PostStrings.Front(); + options.ArchivePathsSorted.Add(arcName); + options.ArchivePathsFullSorted.Add(arcName); + } + else + { + EnumerateDirItemsAndSort( + false, // scanAltStreams + arcCensor, + NWildcard::k_RelatPath, + UString(), // addPathPrefix + options.ArchivePathsSorted, + options.ArchivePathsFullSorted); + } + + if (isExtractGroupCommand) + { + if (options.StdOutMode && options.IsStdOutTerminal && options.IsStdErrTerminal) + throw CArcCmdLineException(kSameTerminalError); + if (parser[NKey::kOutputDir].ThereIs) + { + eo.OutputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]); + NFile::NName::NormalizeDirPathPrefix(eo.OutputDir); + } + + eo.OverwriteMode = NExtract::NOverwriteMode::kAsk; + if (parser[NKey::kOverwrite].ThereIs) + { + eo.OverwriteMode = k_OverwriteModes[parser[NKey::kOverwrite].PostCharIndex]; + eo.OverwriteMode_Force = true; + } + else if (options.YesToAll) + { + eo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite; + eo.OverwriteMode_Force = true; + } + } + + eo.PathMode = options.Command.GetPathMode(); + if (censorPathMode == NWildcard::k_AbsPath) + { + eo.PathMode = NExtract::NPathMode::kAbsPaths; + eo.PathMode_Force = true; + } + else if (censorPathMode == NWildcard::k_FullPath) + { + eo.PathMode = NExtract::NPathMode::kFullPaths; + eo.PathMode_Force = true; + } + } + else if (options.Command.IsFromUpdateGroup()) + { + if (parser[NKey::kArInclude].ThereIs) + throw CArcCmdLineException("-ai switch is not supported for this command"); + + CUpdateOptions &updateOptions = options.UpdateOptions; + + SetAddCommandOptions(options.Command.CommandType, parser, updateOptions); + + updateOptions.MethodMode.Properties = options.Properties; + +#ifdef _WIN32 + if (parser[NKey::kShareForWrite].ThereIs) + updateOptions.OpenShareForWrite = true; +#endif + + updateOptions.PathMode = censorPathMode; + + updateOptions.AltStreams = options.AltStreams; + updateOptions.NtSecurity = options.NtSecurity; + updateOptions.HardLinks = options.HardLinks; + updateOptions.SymLinks = options.SymLinks; + + updateOptions.EMailMode = parser[NKey::kEmail].ThereIs; + if (updateOptions.EMailMode) + { + updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front(); + if (updateOptions.EMailAddress.Len() > 0) + if (updateOptions.EMailAddress[0] == L'.') + { + updateOptions.EMailRemoveAfter = true; + updateOptions.EMailAddress.Delete(0); + } + } + + updateOptions.StdOutMode = options.StdOutMode; + updateOptions.StdInMode = options.StdInMode; + + updateOptions.DeleteAfterCompressing = parser[NKey::kDeleteAfterCompressing].ThereIs; + updateOptions.SetArcMTime = parser[NKey::kSetArcMTime].ThereIs; + + if (updateOptions.StdOutMode && updateOptions.EMailMode) + throw CArcCmdLineException("stdout mode and email mode cannot be combined"); + if (updateOptions.StdOutMode && options.IsStdOutTerminal) + throw CArcCmdLineException(kTerminalOutError); + if (updateOptions.StdInMode) + updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front(); + + if (options.Command.CommandType == NCommandType::kRename) + if (updateOptions.Commands.Size() != 1) + throw CArcCmdLineException("Only one archive can be created with rename command"); + } + else if (options.Command.CommandType == NCommandType::kBenchmark) + { + options.NumIterations = 1; + if (curCommandIndex < numNonSwitchStrings) + { + if (!StringToUInt32(nonSwitchStrings[curCommandIndex], options.NumIterations)) + throw CArcCmdLineException("Incorrect Number of benmchmark iterations", nonSwitchStrings[curCommandIndex]); + curCommandIndex++; + } + } + else if (options.Command.CommandType == NCommandType::kHash) + { + options.Censor.AddPathsToCensor(censorPathMode); + options.Censor.ExtendExclude(); + + CHashOptions &hashOptions = options.HashOptions; + hashOptions.PathMode = censorPathMode; + hashOptions.Methods = options.HashMethods; +#ifdef _WIN32 + if (parser[NKey::kShareForWrite].ThereIs) + hashOptions.OpenShareForWrite = true; +#endif + hashOptions.StdInMode = options.StdInMode; + hashOptions.AltStreamsMode = options.AltStreams.Val; + } + else if (options.Command.CommandType == NCommandType::kInfo) + { + } + else + throw 815676711; // FIXME 9815676711; +} diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.h new file mode 100644 index 000000000..255e12c3c --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.h @@ -0,0 +1,122 @@ +// ArchiveCommandLine.h + +#ifndef __ARCHIVE_COMMAND_LINE_H +#define __ARCHIVE_COMMAND_LINE_H + +#include "../../../Common/CommandLineParser.h" +#include "../../../Common/Wildcard.h" + +#include "Extract.h" +#include "HashCalc.h" +#include "Update.h" + +struct CArcCmdLineException: public UString +{ + CArcCmdLineException(const char *a, const wchar_t *u = NULL); +}; + +namespace NCommandType { enum EEnum +{ + kAdd = 0, + kUpdate, + kDelete, + kTest, + kExtract, + kExtractFull, + kList, + kBenchmark, + kInfo, + kHash, + kRename +};} + +struct CArcCommand +{ + NCommandType::EEnum CommandType; + + bool IsFromExtractGroup() const; + bool IsFromUpdateGroup() const; + bool IsTestCommand() const { return CommandType == NCommandType::kTest; } + NExtract::NPathMode::EEnum GetPathMode() const; +}; + +struct CArcCmdLineOptions +{ + bool HelpMode; + + #ifdef _7ZIP_LARGE_PAGES + bool LargePages; + #endif + bool CaseSensitiveChange; + bool CaseSensitive; + + bool IsInTerminal; + bool IsStdOutTerminal; + bool IsStdErrTerminal; + bool StdInMode; + bool StdOutMode; + bool EnableHeaders; + + bool YesToAll; + bool ShowDialog; + NWildcard::CCensor Censor; + + CArcCommand Command; + UString ArchiveName; + + #ifndef _NO_CRYPTO + bool PasswordEnabled; + UString Password; + #endif + + bool TechMode; + + UStringVector HashMethods; + + bool AppendName; + UStringVector ArchivePathsSorted; + UStringVector ArchivePathsFullSorted; + CObjectVector<CProperty> Properties; + + CExtractOptionsBase ExtractOptions; + + CBoolPair NtSecurity; + CBoolPair AltStreams; + CBoolPair HardLinks; + CBoolPair SymLinks; + + CUpdateOptions UpdateOptions; + CHashOptions HashOptions; + UString ArcType; + UStringVector ExcludedArcTypes; + bool EnablePercents; + + // Benchmark + UInt32 NumIterations; + + CArcCmdLineOptions(): + StdInMode(false), + StdOutMode(false), + CaseSensitiveChange(false), + CaseSensitive(false) + {}; +}; + +class CArcCmdLineParser +{ + NCommandLineParser::CParser parser; +public: + CArcCmdLineParser(); + void Parse1(const UStringVector &commandStrings, CArcCmdLineOptions &options); + void Parse2(CArcCmdLineOptions &options); +}; + +void EnumerateDirItemsAndSort( + bool storeAltStreams, + NWildcard::CCensor &censor, + NWildcard::ECensorPathMode pathMode, + const UString &addPathPrefix, + UStringVector &sortedPaths, + UStringVector &sortedFullPaths); + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp new file mode 100644 index 000000000..250f66797 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp @@ -0,0 +1,1191 @@ +// ArchiveExtractCallback.cpp + +#include "StdAfx.h" + +#undef sprintf +#undef printf + +#include "../../../Common/ComTry.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantConv.h" + +#if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX) +#define _USE_SECURITY_CODE +#include "../../../Windows/SecurityUtils.h" +#endif + +#include "../../Common/FilePathAutoRename.h" + +#include "../Common/ExtractingFilePath.h" +#include "../Common/PropIDUtils.h" + +#include "ArchiveExtractCallback.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +static const char *kCantAutoRename = "Can not create file with auto name"; +static const char *kCantRenameFile = "Can not rename existing file"; +static const char *kCantDeleteOutputFile = "Can not delete output file"; +static const char *kCantDeleteOutputDir = "Can not delete output folder"; + + +#ifndef _SFX + +STDMETHODIMP COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, size, &size); + if (_calculate) + _hash->Update(data, size); + _size += size; + if (processedSize) + *processedSize = size; + return result; +} + +#endif + +#ifdef _USE_SECURITY_CODE +bool InitLocalPrivileges() +{ + NSecurity::CAccessToken token; + if (!token.OpenProcessToken(GetCurrentProcess(), + TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES)) + return false; + + TOKEN_PRIVILEGES tp; + + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (!::LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &tp.Privileges[0].Luid)) + return false; + if (!token.AdjustPrivileges(&tp)) + return false; + return (GetLastError() == ERROR_SUCCESS); +} +#endif + +#ifdef SUPPORT_LINKS + +int CHardLinkNode::Compare(const CHardLinkNode &a) const +{ + if (StreamId < a.StreamId) return -1; + if (StreamId > a.StreamId) return 1; + return MyCompare(INode, a.INode); +} + +HRESULT Archive_Get_HardLinkNode(IInArchive *archive, UInt32 index, CHardLinkNode &h, bool &defined) +{ + h.INode = 0; + h.StreamId = (UInt64)(Int64)-1; + defined = false; + { + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidINode, &prop)); + if (!ConvertPropVariantToUInt64(prop, h.INode)) + return S_OK; + } + { + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidStreamId, &prop)); + ConvertPropVariantToUInt64(prop, h.StreamId); + } + defined = true; + return S_OK; +} + + +HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *realIndices) +{ + _hardLinks.Clear(); + + if (!_arc->Ask_INode) + return S_OK; + + IInArchive *archive = _arc->Archive; + CRecordVector<CHardLinkNode> &hardIDs = _hardLinks.IDs; + + { + UInt32 numItems; + if (realIndices) + numItems = realIndices->Size(); + else + { + RINOK(archive->GetNumberOfItems(&numItems)); + } + + for (UInt32 i = 0; i < numItems; i++) + { + CHardLinkNode h; + bool defined; + RINOK(Archive_Get_HardLinkNode(archive, realIndices ? (*realIndices)[i] : i, h, defined)); + if (defined) + hardIDs.Add(h); + } + } + + hardIDs.Sort2(); + + { + // wee keep only items that have 2 or more items + unsigned k = 0; + unsigned numSame = 1; + for (unsigned i = 1; i < hardIDs.Size(); i++) + { + if (hardIDs[i].Compare(hardIDs[i - 1]) != 0) + numSame = 1; + else if (++numSame == 2) + { + if (i - 1 != k) + hardIDs[k] = hardIDs[i - 1]; + k++; + } + } + hardIDs.DeleteFrom(k); + } + + _hardLinks.PrepareLinks(); + return S_OK; +} + +#endif + +CArchiveExtractCallback::CArchiveExtractCallback(): + WriteCTime(true), + WriteATime(true), + WriteMTime(true), + _multiArchives(false) +{ + LocalProgressSpec = new CLocalProgress(); + _localProgress = LocalProgressSpec; + + #ifdef _USE_SECURITY_CODE + _saclEnabled = InitLocalPrivileges(); + #endif +} + +void CArchiveExtractCallback::Init( + const CExtractNtOptions &ntOptions, + const NWildcard::CCensorNode *wildcardCensor, + const CArc *arc, + IFolderArchiveExtractCallback *extractCallback2, + bool stdOutMode, bool testMode, + const FString &directoryPath, + const UStringVector &removePathParts, + UInt64 packSize) +{ + _extractedFolderPaths.Clear(); + _extractedFolderIndices.Clear(); + + #ifdef SUPPORT_LINKS + _hardLinks.Clear(); + #endif + + _ntOptions = ntOptions; + _wildcardCensor = wildcardCensor; + + _stdOutMode = stdOutMode; + _testMode = testMode; + _unpTotal = 1; + _packTotal = packSize; + + _extractCallback2 = extractCallback2; + _compressProgress.Release(); + _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress); + + #ifndef _SFX + + _extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback); + if (ExtractToStreamCallback) + { + Int32 useStreams = 0; + if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK) + useStreams = 0; + if (useStreams == 0) + ExtractToStreamCallback.Release(); + } + + #endif + + LocalProgressSpec->Init(extractCallback2, true); + LocalProgressSpec->SendProgress = false; + + _removePathParts = removePathParts; + _baseParentFolder = (UInt32)(Int32)-1; + _use_baseParentFolder_mode = false; + + _arc = arc; + _directoryPath = directoryPath; + NName::NormalizeDirPathPrefix(_directoryPath); + NDir::MyGetFullPathName(directoryPath, _directoryPathFull); +} + +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 +} + +#define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') + +static inline bool IsDriveName(const UString &s) +{ + return s.Len() == 2 && s[1] == ':' && IS_LETTER_CHAR(s[0]); +} + +void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath) +{ + bool isAbsPath = false; + + if (!dirPathParts.IsEmpty()) + { + const UString &s = dirPathParts[0]; + if (s.IsEmpty()) + isAbsPath = true; + #ifdef _WIN32 + else + { + if (dirPathParts.Size() > 1 && IsDriveName(s)) + isAbsPath = true; + } + #endif + } + + if (_pathMode == NExtract::NPathMode::kAbsPaths && isAbsPath) + fullPath.Empty(); + else + fullPath = _directoryPath; + + FOR_VECTOR (i, dirPathParts) + { + if (i > 0) + fullPath += FCHAR_PATH_SEPARATOR; + const UString &s = dirPathParts[i]; + fullPath += us2fs(s); + #ifdef _WIN32 + if (_pathMode == NExtract::NPathMode::kAbsPaths) + if (i == 0 && IsDriveName(s)) + continue; + #endif + CreateDir(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() +{ + return _arc->GetItemSize(_index, _curSize, _curSizeDefined); +} + +HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path) +{ + return _extractCallback2->MessageError( + UString(L"ERROR: ") + + GetUnicodeString(message) + L": " + fs2us(path)); +} + +HRESULT CArchiveExtractCallback::SendMessageError2(const char *message, const FString &path1, const FString &path2) +{ + return _extractCallback2->MessageError( + UString(L"ERROR: ") + + GetUnicodeString(message) + UString(L": ") + fs2us(path1) + UString(L" : ") + fs2us(path2)); +} + +#ifndef _SFX + +STDMETHODIMP CGetProp::GetProp(PROPID propID, PROPVARIANT *value) +{ + if (propID == kpidName) + { + COM_TRY_BEGIN + NCOM::CPropVariant prop = Name.Ptr(); + prop.Detach(value); + return S_OK; + COM_TRY_END + } + return Arc->Archive->GetProperty(IndexInArc, propID, value); +} + +#endif + + +#ifdef SUPPORT_LINKS + +static UString GetDirPrefixOf(const UString &src) +{ + UString s = src; + if (!s.IsEmpty()) + { + if (s.Back() == WCHAR_PATH_SEPARATOR) + s.DeleteBack(); + int pos = s.ReverseFind(WCHAR_PATH_SEPARATOR); + s.DeleteFrom(pos + 1); + } + return s; +} + +static bool IsSafePath(const UString &path) +{ + UStringVector parts; + SplitPathToParts(path, parts); + int level = 0; + FOR_VECTOR(i, parts) + { + const UString &s = parts[i]; + if (s.IsEmpty()) + continue; + if (s == L".") + continue; + if (s == L"..") + { + if (level <= 0) + return false; + level--; + } + else + level++; + } + return level > 0; +} + +#endif + + +STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) +{ + COM_TRY_BEGIN + + *outStream = 0; + + #ifndef _SFX + if (_hashStream) + _hashStreamSpec->ReleaseStream(); + _hashStreamWasUsed = false; + #endif + + _outFileStream.Release(); + + _encrypted = false; + _isSplit = false; + _isAltStream = false; + _curSize = 0; + _curSizeDefined = false; + _index = index; + + UString fullPath; + + IInArchive *archive = _arc->Archive; + RINOK(_arc->GetItemPath(index, fullPath)); + RINOK(Archive_IsItem_Folder(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; + } + } + + #ifdef SUPPORT_LINKS + + bool isHardLink = false; + bool isJunction = false; + bool isRelative = false; + + UString linkPath; + // RINOK(Archive_GetItemBoolProp(archive, index, kpidIsHardLink, isHardLink)); + // if (isHardLink) + { + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidHardLink, &prop)); + if (prop.vt == VT_BSTR) + { + isHardLink = true; + linkPath = prop.bstrVal; + isRelative = false; // TAR: hard links are from root folder of archive + } + else if (prop.vt == VT_EMPTY) + { + // linkPath.Empty(); + } + else + return E_FAIL; + } + { + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidSymLink, &prop)); + if (prop.vt == VT_BSTR) + { + isHardLink = false; + linkPath = prop.bstrVal; + isRelative = true; // TAR: symbolic links are relative + } + else if (prop.vt == VT_EMPTY) + { + // linkPath.Empty(); + } + else + return E_FAIL; + } + + bool isOkReparse = false; + + if (linkPath.IsEmpty() && _arc->GetRawProps) + { + const void *data; + UInt32 dataSize; + UInt32 propType; + _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType); + if (dataSize != 0) + { + if (propType != NPropDataType::kRaw) + return E_FAIL; + UString s; + CReparseAttr reparse; + isOkReparse = reparse.Parse((const Byte *)data, dataSize); + if (isOkReparse) + { + isHardLink = false; + linkPath = reparse.GetPath(); + isJunction = reparse.IsMountPoint(); + isRelative = reparse.IsRelative(); + #ifndef _WIN32 + linkPath.Replace(WCHAR_PATH_SEPARATOR, '/', ); + #endif + } + } + } + + if (!linkPath.IsEmpty()) + { + #ifdef _WIN32 + linkPath.Replace('/', WCHAR_PATH_SEPARATOR); + #endif + + for (;;) + // while (NName::IsAbsolutePath(linkPath)) + { + unsigned n = NName::GetRootPrefixSize(linkPath); + if (n == 0) + break; + isRelative = false; + linkPath.DeleteFrontal(n); + } + } + + if (!linkPath.IsEmpty() && !isRelative && _removePathParts.Size() != 0) + { + UStringVector pathParts; + SplitPathToParts(linkPath, pathParts); + bool badPrefix = false; + FOR_VECTOR (i, _removePathParts) + { + if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0) + { + badPrefix = true; + break; + } + } + if (!badPrefix) + pathParts.DeleteFrontal(_removePathParts.Size()); + linkPath = MakePathNameFromParts(pathParts); + } + + #endif + + RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted)); + + RINOK(GetUnpackSize()); + + RINOK(Archive_IsItem_AltStream(archive, index, _isAltStream)); + + if (!_ntOptions.AltStreams.Val && _isAltStream) + return S_OK; + + if (_wildcardCensor) + { + if (!_wildcardCensor->CheckPath(_isAltStream, fullPath, !_fi.IsDir)) + return S_OK; + } + + + UStringVector pathParts; + + if (_use_baseParentFolder_mode) + { + int baseParent = _baseParentFolder; + if (_pathMode == NExtract::NPathMode::kFullPaths || + _pathMode == NExtract::NPathMode::kAbsPaths) + baseParent = -1; + RINOK(_arc->GetItemPathToParent(index, baseParent, pathParts)); + if (_pathMode == NExtract::NPathMode::kNoPaths && !pathParts.IsEmpty()) + pathParts.DeleteFrontal(pathParts.Size() - 1); + } + else + { + SplitPathToParts(fullPath, pathParts); + + if (pathParts.IsEmpty()) + return E_FAIL; + unsigned numRemovePathParts = 0; + + switch (_pathMode) + { + case NExtract::NPathMode::kCurPaths: + { + bool badPrefix = false; + if (pathParts.Size() <= _removePathParts.Size()) + badPrefix = true; + else + { + FOR_VECTOR (i, _removePathParts) + { + if (!_removePathParts[i].IsEqualToNoCase(pathParts[i])) + { + badPrefix = true; + break; + } + } + } + if (badPrefix) + { + if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) + return E_FAIL; + } + else + numRemovePathParts = _removePathParts.Size(); + break; + } + case NExtract::NPathMode::kNoPaths: + { + numRemovePathParts = pathParts.Size() - 1; + break; + } + /* + case NExtract::NPathMode::kFullPaths: + case NExtract::NPathMode::kAbsPaths: + break; + */ + } + + pathParts.DeleteFrontal(numRemovePathParts); + } + + #ifndef _SFX + + if (ExtractToStreamCallback) + { + if (!GetProp) + { + GetProp_Spec = new CGetProp; + GetProp = GetProp_Spec; + } + GetProp_Spec->Arc = _arc; + GetProp_Spec->IndexInArc = index; + GetProp_Spec->Name = MakePathNameFromParts(pathParts); + + return ExtractToStreamCallback->GetStream7(GetProp_Spec->Name, _fi.IsDir, outStream, askExtractMode, GetProp); + } + + #endif + + CMyComPtr<ISequentialOutStream> outStreamLoc; + +if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) +{ + if (_stdOutMode) + { + outStreamLoc = new CStdOutFileStream; + } + else + { + { + 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)); + + bool replace = _isAltStream ? + _ntOptions.ReplaceColonForAltStream : + !_ntOptions.WriteToAltStreamIfColon; + + if (_pathMode != NExtract::NPathMode::kAbsPaths) + MakeCorrectPath(_directoryPath.IsEmpty(), pathParts, replace); + Correct_IfEmptyLastPart(pathParts); + UString processedPath = MakePathNameFromParts(pathParts); + + if (!isAnti) + { + if (!_fi.IsDir) + { + if (!pathParts.IsEmpty()) + pathParts.DeleteBack(); + } + + if (!pathParts.IsEmpty()) + { + FString fullPathNew; + CreateComplexDirectory(pathParts, fullPathNew); + if (_fi.IsDir) + { + _extractedFolderPaths.Add(fullPathNew); + _extractedFolderIndices.Add(index); + SetDirTime(fullPathNew, + (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL, + (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL, + (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); + } + } + } + + + FString fullProcessedPath = us2fs(processedPath); + if (_pathMode != NExtract::NPathMode::kAbsPaths || + !NName::IsAbsolutePath(processedPath)) + fullProcessedPath = _directoryPath + fullProcessedPath; + + if (_fi.IsDir) + { + _diskFilePath = fullProcessedPath; + if (isAnti) + RemoveDir(_diskFilePath); + #ifdef SUPPORT_LINKS + if (linkPath.IsEmpty()) + #endif + return S_OK; + } + else if (!_isSplit) + { + NFind::CFileInfo fileInfo; + if (fileInfo.Find(fullProcessedPath)) + { + switch (_overwriteMode) + { + case NExtract::NOverwriteMode::kSkip: + return S_OK; + case NExtract::NOverwriteMode::kAsk: + { + int slashPos = fullProcessedPath.ReverseFind(FTEXT('/')); + #ifdef _WIN32 + int slash1Pos = fullProcessedPath.ReverseFind(FTEXT('\\')); + slashPos = MyMax(slashPos, slash1Pos); + #endif + FString realFullProcessedPath = fullProcessedPath.Left(slashPos + 1) + fileInfo.Name; + + Int32 overwiteResult; + RINOK(_extractCallback2->AskOverwrite( + fs2us(realFullProcessedPath), &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::kSkip; return S_OK; + case NOverwriteAnswer::kYes: break; + case NOverwriteAnswer::kYesToAll: _overwriteMode = NExtract::NOverwriteMode::kOverwrite; break; + case NOverwriteAnswer::kAutoRename: _overwriteMode = NExtract::NOverwriteMode::kRename; break; + default: + return E_FAIL; + } + } + } + if (_overwriteMode == NExtract::NOverwriteMode::kRename) + { + if (!AutoRenamePath(fullProcessedPath)) + { + RINOK(SendMessageError(kCantAutoRename, fullProcessedPath)); + return E_FAIL; + } + } + else if (_overwriteMode == NExtract::NOverwriteMode::kRenameExisting) + { + FString existPath = fullProcessedPath; + if (!AutoRenamePath(existPath)) + { + RINOK(SendMessageError(kCantAutoRename, fullProcessedPath)); + return E_FAIL; + } + // MyMoveFile can raname folders. So it's OK to use it folders too + if (!MyMoveFile(fullProcessedPath, existPath)) + { + RINOK(SendMessageError(kCantRenameFile, fullProcessedPath)); + return E_FAIL; + } + } + else + { + if (fileInfo.IsDir()) + { + // do we need to delete all files in folder? + if (!RemoveDir(fullProcessedPath)) + { + RINOK(SendMessageError(kCantDeleteOutputDir, fullProcessedPath)); + return S_OK; + } + } + else if (!DeleteFileAlways(fullProcessedPath)) + { + RINOK(SendMessageError(kCantDeleteOutputFile, fullProcessedPath)); + return S_OK; + // return E_FAIL; + } + } + } + } + _diskFilePath = fullProcessedPath; + + + if (!isAnti) + { + #ifdef SUPPORT_LINKS + + if (!linkPath.IsEmpty()) + { + #ifndef UNDER_CE + + UString relatPath; + if (isRelative) + relatPath = GetDirPrefixOf(_filePath); + relatPath += linkPath; + + if (!IsSafePath(relatPath)) + { + RINOK(SendMessageError("Dangerous link path was ignored", us2fs(relatPath))); + } + else + { + FString existPath; + if (isHardLink || !isRelative) + { + if (!NName::GetFullPath(_directoryPathFull, us2fs(relatPath), existPath)) + { + RINOK(SendMessageError("Incorrect path", us2fs(relatPath))); + } + } + else + { + existPath = us2fs(linkPath); + } + + if (!existPath.IsEmpty()) + { + if (isHardLink) + { + if (!MyCreateHardLink(fullProcessedPath, existPath)) + { + RINOK(SendMessageError2("Can not create hard link", fullProcessedPath, existPath)); + // return S_OK; + } + } + else if (_ntOptions.SymLinks.Val) + { + // bool isSymLink = true; // = false for junction + if (_fi.IsDir && !isRelative) + { + // if it's before Vista we use Junction Point + // isJunction = true; + // convertToAbs = true; + } + + CByteBuffer data; + if (FillLinkData(data, fs2us(existPath), !isJunction)) + { + CReparseAttr attr; + if (!attr.Parse(data, data.Size())) + { + return E_FAIL; // "Internal conversion error"; + } + + if (!NFile::NIO::SetReparseData(fullProcessedPath, _fi.IsDir, data, (DWORD)data.Size())) + { + RINOK(SendMessageError("Can not set reparse data", fullProcessedPath)); + } + } + } + } + } + + #endif + } + else + #endif // SUPPORT_LINKS + { + bool needWriteFile = true; + + #ifdef SUPPORT_LINKS + if (!_hardLinks.IDs.IsEmpty()) + { + CHardLinkNode h; + bool defined; + RINOK(Archive_Get_HardLinkNode(archive, index, h, defined)); + if (defined) + { + { + int linkIndex = _hardLinks.IDs.FindInSorted2(h); + if (linkIndex >= 0) + { + FString &hl = _hardLinks.Links[linkIndex]; + if (hl.IsEmpty()) + hl = fullProcessedPath; + else + { + if (!MyCreateHardLink(fullProcessedPath, hl)) + { + RINOK(SendMessageError2("Can not create hard link", fullProcessedPath, hl)); + return S_OK; + } + needWriteFile = false; + } + } + } + } + } + #endif + + if (needWriteFile) + { + _outFileStreamSpec = new COutFileStream; + CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec); + if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS)) + { + // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit) + { + RINOK(SendMessageError("Can not open output file ", fullProcessedPath)); + return S_OK; + } + } + if (_isSplit) + { + RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL)); + } + _outFileStream = outStreamLoc; + } + } + } + + outStreamLoc = _outFileStream; + } +} + + #ifndef _SFX + + if (_hashStream) + { + if (askExtractMode == NArchive::NExtract::NAskMode::kExtract || + askExtractMode == NArchive::NExtract::NAskMode::kTest) + { + _hashStreamSpec->SetStream(outStreamLoc); + outStreamLoc = _hashStream; + _hashStreamSpec->Init(true); + _hashStreamWasUsed = true; + } + } + + #endif + + if (outStreamLoc) + *outStream = outStreamLoc.Detach(); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode) +{ + COM_TRY_BEGIN + + #ifndef _SFX + if (ExtractToStreamCallback) + return ExtractToStreamCallback->PrepareOperation7(askExtractMode); + #endif + + _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 + + #ifndef _SFX + if (ExtractToStreamCallback) + return ExtractToStreamCallback->SetOperationResult7(operationResult, _encrypted); + #endif + + #ifndef _SFX + + if (_hashStreamWasUsed) + { + _hashStreamSpec->_hash->Final(_fi.IsDir, _isAltStream, _filePath); + _curSize = _hashStreamSpec->GetSize(); + _curSizeDefined = true; + _hashStreamSpec->ReleaseStream(); + _hashStreamWasUsed = false; + } + + #endif + + 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(); + } + + #ifdef _USE_SECURITY_CODE + if (_ntOptions.NtSecurity.Val && _arc->GetRawProps) + { + const void *data; + UInt32 dataSize; + UInt32 propType; + _arc->GetRawProps->GetRawProp(_index, kpidNtSecure, &data, &dataSize, &propType); + if (dataSize != 0) + { + if (propType != NPropDataType::kRaw) + return E_FAIL; + if (CheckNtSecure((const Byte *)data, dataSize)) + { + SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION; + if (_saclEnabled) + securInfo |= SACL_SECURITY_INFORMATION; + ::SetFileSecurityW(fs2us(_diskFilePath), securInfo, (PSECURITY_DESCRIPTOR)(void *)data); + } + } + } + #endif + + if (!_curSizeDefined) + GetUnpackSize(); + if (_curSizeDefined) + { + if (_isAltStream) + AltStreams_UnpackSize += _curSize; + else + UnpackSize += _curSize; + } + + if (_fi.IsDir) + NumFolders++; + else if (_isAltStream) + NumAltStreams++; + else + NumFiles++; + + if (_extractMode && _fi.AttribDefined) + SetFileAttrib(_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<ISequentialInStream> inStreamTemp = inFile; + if (!inFile->Open(_srcDirectoryPrefix + name)) + return ::GetLastError(); + *inStream = inStreamTemp.Detach(); + return S_OK; + COM_TRY_END +} +*/ + +STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password) +{ + COM_TRY_BEGIN + if (!_cryptoGetTextPassword) + { + RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword, + &_cryptoGetTextPassword)); + } + return _cryptoGetTextPassword->CryptoGetTextPassword(password); + COM_TRY_END +} + + +struct CExtrRefSortPair +{ + int Len; + int Index; + + int Compare(const CExtrRefSortPair &a) const; +}; + +#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } + +int CExtrRefSortPair::Compare(const CExtrRefSortPair &a) const +{ + RINOZ(-MyCompare(Len, a.Len)); + return MyCompare(Index, a.Index); +} + +static int GetNumSlashes(const FChar *s) +{ + for (int numSlashes = 0;;) + { + FChar c = *s++; + if (c == 0) + return numSlashes; + if ( + #ifdef _WIN32 + c == FTEXT('\\') || + #endif + c == FTEXT('/')) + numSlashes++; + } +} + +HRESULT CArchiveExtractCallback::SetDirsTimes() +{ + CRecordVector<CExtrRefSortPair> pairs; + pairs.ClearAndSetSize(_extractedFolderPaths.Size()); + unsigned i; + + for (i = 0; i < _extractedFolderPaths.Size(); i++) + { + CExtrRefSortPair &pair = pairs[i]; + pair.Index = i; + pair.Len = GetNumSlashes(_extractedFolderPaths[i]); + } + + pairs.Sort2(); + + for (i = 0; i < pairs.Size(); i++) + { + int pairIndex = pairs[i].Index; + int index = _extractedFolderIndices[pairIndex]; + + FILETIME CTime; + FILETIME ATime; + FILETIME MTime; + + bool CTimeDefined; + bool ATimeDefined; + bool MTimeDefined; + + RINOK(GetTime(index, kpidCTime, CTime, CTimeDefined)); + RINOK(GetTime(index, kpidATime, ATime, ATimeDefined)); + RINOK(GetTime(index, kpidMTime, MTime, MTimeDefined)); + + // printf("\n%S", _extractedFolderPaths[pairIndex]); + SetDirTime(_extractedFolderPaths[pairIndex], + (WriteCTime && CTimeDefined) ? &CTime : NULL, + (WriteATime && ATimeDefined) ? &ATime : NULL, + (WriteMTime && MTimeDefined) ? &MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); + } + return S_OK; +} diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.h new file mode 100644 index 000000000..374297651 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.h @@ -0,0 +1,299 @@ +// 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 "ExtractMode.h" +#include "IFileExtractCallback.h" +#include "OpenArchive.h" + +#include "HashCalc.h" + +#ifndef _SFX + +class COutStreamWithHash: + public ISequentialOutStream, + public CMyUnknownImp +{ + CMyComPtr<ISequentialOutStream> _stream; + UInt64 _size; + bool _calculate; +public: + IHashCalc *_hash; + + MY_UNKNOWN_IMP + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init(bool calculate = true) + { + InitCRC(); + _size = 0; + _calculate = calculate; + } + void EnableCalc(bool calculate) { _calculate = calculate; } + void InitCRC() { _hash->InitForNewFile(); } + UInt64 GetSize() const { return _size; } +}; + +#endif + +struct CExtractNtOptions +{ + CBoolPair NtSecurity; + CBoolPair SymLinks; + CBoolPair HardLinks; + CBoolPair AltStreams; + bool ReplaceColonForAltStream; + bool WriteToAltStreamIfColon; + + CExtractNtOptions(): + ReplaceColonForAltStream(false), + WriteToAltStreamIfColon(false) + { + SymLinks.Val = true; + HardLinks.Val = true; + AltStreams.Val = true; + } +}; + +#ifndef _SFX + +class CGetProp: + public IGetProp, + public CMyUnknownImp +{ +public: + const CArc *Arc; + UInt32 IndexInArc; + UString Name; // relative path + + MY_UNKNOWN_IMP1(IGetProp) + INTERFACE_IGetProp(;) +}; + +#endif + +#ifndef _SFX +#ifndef UNDER_CE + +// FIXME #define SUPPORT_LINKS + +#endif +#endif + + +#ifdef SUPPORT_LINKS + +struct CHardLinkNode +{ + UInt64 StreamId; + UInt64 INode; + + int Compare(const CHardLinkNode &a) const; +}; + +class CHardLinks +{ +public: + CRecordVector<CHardLinkNode> IDs; + CObjectVector<FString> Links; + + void Clear() + { + IDs.Clear(); + Links.Clear(); + } + + void PrepareLinks() + { + while (Links.Size() < IDs.Size()) + Links.AddNew(); + } +}; + +#endif + +class CArchiveExtractCallback: + public IArchiveExtractCallback, + // public IArchiveVolumeExtractCallback, + public ICryptoGetTextPassword, + public ICompressProgressInfo, + public CMyUnknownImp +{ + const CArc *_arc; + CExtractNtOptions _ntOptions; + + const NWildcard::CCensorNode *_wildcardCensor; + CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2; + CMyComPtr<ICompressProgressInfo> _compressProgress; + CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword; + FString _directoryPath; + FString _directoryPathFull; + NExtract::NPathMode::EEnum _pathMode; + NExtract::NOverwriteMode::EEnum _overwriteMode; + + #ifndef _SFX + + CMyComPtr<IFolderExtractToStreamCallback> ExtractToStreamCallback; + CGetProp *GetProp_Spec; + CMyComPtr<IGetProp> GetProp; + + #endif + + FString _diskFilePath; + UString _filePath; + UInt64 _position; + bool _isSplit; + bool _isAltStream; + + 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<ISequentialOutStream> _outFileStream; + + #ifndef _SFX + + COutStreamWithHash *_hashStreamSpec; + CMyComPtr<ISequentialOutStream> _hashStream; + bool _hashStreamWasUsed; + + #endif + + UStringVector _removePathParts; + bool _use_baseParentFolder_mode; + UInt32 _baseParentFolder; + + bool _stdOutMode; + bool _testMode; + bool _multiArchives; + + CMyComPtr<ICompressProgressInfo> _localProgress; + UInt64 _packTotal; + UInt64 _unpTotal; + + FStringVector _extractedFolderPaths; + CRecordVector<UInt32> _extractedFolderIndices; + + #if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX) + bool _saclEnabled; + #endif + + void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath); + HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined); + HRESULT GetUnpackSize(); + + HRESULT SendMessageError(const char *message, const FString &path); + HRESULT SendMessageError2(const char *message, const FString &path1, const FString &path2); + +public: + + CLocalProgress *LocalProgressSpec; + + UInt64 NumFolders; + UInt64 NumFiles; + UInt64 NumAltStreams; + UInt64 UnpackSize; + UInt64 AltStreams_UnpackSize; + + 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(); + + void InitForMulti(bool multiArchives, + NExtract::NPathMode::EEnum pathMode, + NExtract::NOverwriteMode::EEnum overwriteMode) + { + _multiArchives = multiArchives; + _pathMode = pathMode; + _overwriteMode = overwriteMode; + NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0; + } + + #ifndef _SFX + + void SetHashMethods(IHashCalc *hash) + { + if (!hash) + return; + _hashStreamSpec = new COutStreamWithHash; + _hashStream = _hashStreamSpec; + _hashStreamSpec->_hash = hash; + } + + #endif + + void Init( + const CExtractNtOptions &ntOptions, + const NWildcard::CCensorNode *wildcardCensor, + const CArc *arc, + IFolderArchiveExtractCallback *extractCallback2, + bool stdOutMode, bool testMode, + const FString &directoryPath, + const UStringVector &removePathParts, + UInt64 packSize); + + #ifdef SUPPORT_LINKS +private: + CHardLinks _hardLinks; +public: + // call PrepareHardLinks() after Init() + HRESULT PrepareHardLinks(const CRecordVector<UInt32> *realIndices); // NULL means all items + #endif + + // call it after Init() + + void SetBaseParentFolderIndex(UInt32 indexInArc) + { + _use_baseParentFolder_mode = true; + _baseParentFolder = indexInArc; + } + + HRESULT SetDirsTimes(); +}; + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp new file mode 100644 index 000000000..9eab39d31 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp @@ -0,0 +1,125 @@ +// ArchiveOpenCallback.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" + +#include "../../../Windows/FileName.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 +} + +struct CInFileStreamVol: public CInFileStream +{ + int FileNameIndex; + COpenCallbackImp *OpenCallbackImp; + CMyComPtr<IArchiveOpenCallback> OpenCallbackRef; + CInFileStreamVol(bool ignoreLink = false) : CInFileStream(ignoreLink) { } + ~CInFileStreamVol() + { + if (OpenCallbackRef) + OpenCallbackImp->FileNames_WasUsed[FileNameIndex] = false; + } +}; + +STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream) +{ + COM_TRY_BEGIN + *inStream = NULL; + if (_subArchiveMode) + return S_FALSE; + if (Callback) + { + RINOK(Callback->Open_CheckBreak()); + } + FString fullPath; + if (!NFile::NName::GetFullPath(_folderPrefix, us2fs(name), fullPath)) + return S_FALSE; + if (!_fileInfo.Find(fullPath,true)) + return S_FALSE; + if (_fileInfo.IsDir()) + return S_FALSE; + CInFileStreamVol *inFile = new CInFileStreamVol(true); + CMyComPtr<IInStream> inStreamTemp = inFile; + if (!inFile->Open(fullPath)) + return ::GetLastError(); + + FileSizes.Add(_fileInfo.Size); + FileNames.Add(name); + inFile->FileNameIndex = FileNames_WasUsed.Add(true); + inFile->OpenCallbackImp = this; + inFile->OpenCallbackRef = this; + // TotalSize += _fileInfo.Size; + *inStream = inStreamTemp.Detach(); + return S_OK; + COM_TRY_END +} + +#ifndef _NO_CRYPTO +STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password) +{ + COM_TRY_BEGIN + if (ReOpenCallback) + { + CMyComPtr<ICryptoGetTextPassword> 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/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.h new file mode 100644 index 000000000..b72892c2f --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.h @@ -0,0 +1,111 @@ +// ArchiveOpenCallback.h + +#ifndef __ARCHIVE_OPEN_CALLBACK_H +#define __ARCHIVE_OPEN_CALLBACK_H + +#include "../../../Common/MyCom.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(bool &passwordIsDefined, 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: + FString _folderPrefix; + NWindows::NFile::NFind::CFileInfo _fileInfo; + bool _subArchiveMode; + UString _subArchiveName; + +public: + UStringVector FileNames; + CBoolVector FileNames_WasUsed; + CRecordVector<UInt64> FileSizes; + + IOpenCallbackUI *Callback; + CMyComPtr<IArchiveOpenCallback> ReOpenCallback; + // UInt64 TotalSize; + + COpenCallbackImp(): Callback(NULL) {} + void Init(const FString &folderPrefix, const FString &fileName) + { + _folderPrefix = folderPrefix; + if (!_fileInfo.Find(_folderPrefix + fileName,true)) + throw 20121118; + FileNames.Clear(); + FileNames_WasUsed.Clear(); + FileSizes.Clear(); + _subArchiveMode = false; + // TotalSize = 0; + } + bool SetSecondFileInfo(CFSTR newName) + { + return _fileInfo.Find(newName) && !_fileInfo.IsDir(); + } +}; + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Common.pri b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Common.pri new file mode 100644 index 000000000..a1d75b674 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Common.pri @@ -0,0 +1,43 @@ +HEADERS += $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveOpenCallback.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveExtractCallback.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveCommandLine.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/DefaultName.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/DirItem.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/EnumDirItems.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/Extract.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/ExtractMode.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/ExtractingFilePath.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/HashCalc.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/IFileExtractCallback.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/LoadCodecs.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/OpenArchive.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/Property.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/PropIDUtils.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/SetProperties.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/SortUtils.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/TempFiles.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/Update.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateAction.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateCallback.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/UpdatePair.h \ + $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateProduce.h + +SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveCommandLine.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/DefaultName.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/EnumDirItems.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/Extract.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/ExtractingFilePath.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/HashCalc.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/LoadCodecs.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/OpenArchive.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/PropIDUtils.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/SetProperties.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/SortUtils.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/TempFiles.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/Update.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateAction.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateCallback.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/UpdatePair.cpp \ + $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateProduce.cpp diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/DefaultName.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/DefaultName.cpp new file mode 100644 index 000000000..ce0b327b5 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/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.Len(); + int fileNameLength = fileName.Len(); + if (fileNameLength > extLength + 1) + { + int dotPos = fileNameLength - (extLength + 1); + if (fileName[dotPos] == '.') + if (extension.IsEqualToNoCase(fileName.Ptr(dotPos + 1))) + 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/3rdparty/7zip/unix/CPP/7zip/UI/Common/DefaultName.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/DefaultName.h new file mode 100644 index 000000000..df1645602 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/DefaultName.h @@ -0,0 +1,11 @@ +// DefaultName.h + +#ifndef __DEFAULT_NAME_H +#define __DEFAULT_NAME_H + +#include "../../../Common/MyString.h" + +UString GetDefaultName2(const UString &fileName, + const UString &extension, const UString &addSubExtension); + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/DirItem.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/DirItem.h new file mode 100644 index 000000000..82203c03a --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/DirItem.h @@ -0,0 +1,126 @@ +// DirItem.h + +#ifndef __DIR_ITEM_H +#define __DIR_ITEM_H + +#include "../../../Common/MyString.h" + +#include "../../../Windows/FileFind.h" + +#include "../../Common/UniqBlocks.h" + +#include "../../Archive/IArchive.h" + +struct CDirItem +{ + UInt64 Size; + FILETIME CTime; + FILETIME ATime; + FILETIME MTime; + UString Name; + + #if defined(_WIN32) && !defined(UNDER_CE) + // UString ShortName; + CByteBuffer ReparseData; + CByteBuffer ReparseData2; // fixed (reduced) absolute links + + bool AreReparseData() const { return ReparseData.Size() != 0 || ReparseData2.Size() != 0; } + #endif + + UInt32 Attrib; + int PhyParent; + int LogParent; + int SecureIndex; + + bool IsAltStream; + + CDirItem(): PhyParent(-1), LogParent(-1), SecureIndex(-1), IsAltStream(false) {} + 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; + + void EnumerateDir(int phyParent, int logParent, const FString &phyPrefix); + +public: + CObjectVector<CDirItem> Items; + + bool SymLinks; + + bool ScanAltStreams; + FStringVector ErrorPaths; + CRecordVector<DWORD> ErrorCodes; + UInt64 TotalSize; + + + #ifndef UNDER_CE + void SetLinkInfo(CDirItem &dirItem, const NWindows::NFile::NFind::CFileInfo &fi, + const FString &phyPrefix); + #endif + + void AddError(const FString &path, DWORD errorCode) + { + ErrorCodes.Add(errorCode); + ErrorPaths.Add(path); + } + + void AddError(const FString &path) + { + AddError(path, ::GetLastError()); + } + + #if defined(_WIN32) && !defined(UNDER_CE) + + CUniqBlocks SecureBlocks; + CByteBuffer TempSecureBuf; + bool _saclEnabled; + bool ReadSecure; + + void AddSecurityItem(const FString &path, int &secureIndex); + + #endif + + CDirItems(); + + int GetNumFolders() const { return Prefixes.Size(); } + UString GetPhyPath(unsigned index) const; + UString GetLogPath(unsigned index) const; + + unsigned AddPrefix(int phyParent, int logParent, const UString &prefix); + void DeleteLastPrefix(); + void EnumerateItems2( + const FString &phyPrefix, + const UString &logPrefix, + const FStringVector &filePaths, + FStringVector *requestedPaths); + + #if defined(_WIN32) && !defined(UNDER_CE) + void FillFixedReparse(); + #endif + + void ReserveDown(); +}; + +struct CArcItem +{ + UInt64 Size; + FILETIME MTime; + UString Name; + bool IsDir; + bool IsAltStream; + bool SizeDefined; + bool MTimeDefined; + bool Censored; + UInt32 IndexInServer; + int TimeType; + + CArcItem(): IsDir(false), IsAltStream(false), SizeDefined(false), MTimeDefined(false), Censored(false), TimeType(-1) {} +}; + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.cpp new file mode 100644 index 000000000..b94e6274c --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.cpp @@ -0,0 +1,757 @@ +// EnumDirItems.cpp + +#include "StdAfx.h" + +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileIO.h" +#include "../../../Windows/FileName.h" + +#if defined(_WIN32) && !defined(UNDER_CE) +#define _USE_SECURITY_CODE +#include "../../../Windows/SecurityUtils.h" +#endif + +#include "EnumDirItems.h" + +using namespace NWindows; +using namespace NFile; +using namespace NName; + +void AddDirFileInfo(int phyParent, int logParent, int secureIndex, + const NFind::CFileInfo &fi, CObjectVector<CDirItem> &dirItems) +{ + CDirItem di; + di.Size = fi.Size; + di.CTime = fi.CTime; + di.ATime = fi.ATime; + di.MTime = fi.MTime; + di.Attrib = fi.Attrib; + // FIXME di.IsAltStream = fi.IsAltStream; + di.PhyParent = phyParent; + di.LogParent = logParent; + di.SecureIndex = secureIndex; + di.Name = fs2us(fi.Name); + #if defined(_WIN32) && !defined(UNDER_CE) + // di.ShortName = fs2us(fi.ShortName); + #endif + dirItems.Add(di); +} + +UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const +{ + UString path; + unsigned len = name.Len(); + int i; + for (i = index; i >= 0; i = parents[i]) + len += Prefixes[i].Len(); + unsigned totalLen = len; + wchar_t *p = path.GetBuffer(len); + p[len] = 0; + len -= name.Len(); + memcpy(p + len, (const wchar_t *)name, name.Len() * sizeof(wchar_t)); + for (i = index; i >= 0; i = parents[i]) + { + const UString &s = Prefixes[i]; + len -= s.Len(); + memcpy(p + len, (const wchar_t *)s, s.Len() * sizeof(wchar_t)); + } + path.ReleaseBuffer(totalLen); + return path; +} + +UString CDirItems::GetPhyPath(unsigned index) const +{ + const CDirItem &di = Items[index]; + return GetPrefixesPath(PhyParents, di.PhyParent, di.Name); +} + +UString CDirItems::GetLogPath(unsigned 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(); +} + +unsigned 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(); +} + +bool InitLocalPrivileges(); + +CDirItems::CDirItems(): + SymLinks(false), + TotalSize(0) + #ifdef _USE_SECURITY_CODE + , ReadSecure(false) + #endif +{ + #ifdef _USE_SECURITY_CODE + _saclEnabled = InitLocalPrivileges(); + #endif +} + +#ifdef _USE_SECURITY_CODE + +void CDirItems::AddSecurityItem(const FString &path, int &secureIndex) +{ + secureIndex = -1; + + SECURITY_INFORMATION securInfo = + DACL_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + OWNER_SECURITY_INFORMATION; + if (_saclEnabled) + securInfo |= SACL_SECURITY_INFORMATION; + + DWORD errorCode = 0; + DWORD secureSize; + BOOL res = ::GetFileSecurityW(fs2us(path), securInfo, TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize); + if (res) + { + if (secureSize == 0) + return; + if (secureSize > TempSecureBuf.Size()) + errorCode = ERROR_INVALID_FUNCTION; + } + else + { + errorCode = GetLastError(); + if (errorCode == ERROR_INSUFFICIENT_BUFFER) + { + if (secureSize <= TempSecureBuf.Size()) + errorCode = ERROR_INVALID_FUNCTION; + else + { + TempSecureBuf.Alloc(secureSize); + res = ::GetFileSecurityW(fs2us(path), securInfo, TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize); + if (res) + { + if (secureSize != TempSecureBuf.Size()) + errorCode = ERROR_INVALID_FUNCTION;; + } + else + errorCode = GetLastError(); + } + } + } + if (res) + { + secureIndex = SecureBlocks.AddUniq(TempSecureBuf, secureSize); + return; + } + if (errorCode == 0) + errorCode = ERROR_INVALID_FUNCTION; + AddError(path, errorCode); +} + +#endif + +void CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phyPrefix) +{ + NFind::CEnumerator enumerator(phyPrefix + FCHAR_ANY_MASK); + for (;;) + { + NFind::CFileInfo fi; + bool found; + if (!enumerator.Next(fi, found)) + { + AddError(phyPrefix); + return; + } + if (!found) + break; + + int secureIndex = -1; + #ifdef _USE_SECURITY_CODE + if (ReadSecure) + AddSecurityItem(phyPrefix + fi.Name, secureIndex); + #endif + + AddDirFileInfo(phyParent, logParent, secureIndex, fi, Items); + + if (fi.IsDir()) + { + const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR; + unsigned parent = AddPrefix(phyParent, logParent, fs2us(name2)); + EnumerateDir(parent, parent, phyPrefix + name2); + } + } +} + +void CDirItems::EnumerateItems2( + const FString &phyPrefix, + const UString &logPrefix, + const FStringVector &filePaths, + FStringVector *requestedPaths) +{ + int phyParent = phyPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, fs2us(phyPrefix)); + int logParent = logPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, logPrefix); + + FOR_VECTOR (i, filePaths) + { + const FString &filePath = filePaths[i]; + NFind::CFileInfo fi; + const FString phyPath = phyPrefix + filePath; + if (!fi.Find(phyPath)) + { + AddError(phyPath); + continue; + } + if (requestedPaths) + requestedPaths->Add(phyPath); + + int delimiter = filePath.ReverseFind(FCHAR_PATH_SEPARATOR); + FString phyPrefixCur; + int phyParentCur = phyParent; + if (delimiter >= 0) + { + phyPrefixCur.SetFrom(filePath, delimiter + 1); + phyParentCur = AddPrefix(phyParent, logParent, fs2us(phyPrefixCur)); + } + + int secureIndex = -1; + #ifdef _USE_SECURITY_CODE + if (ReadSecure) + AddSecurityItem(phyPath, secureIndex); + #endif + + AddDirFileInfo(phyParentCur, logParent, secureIndex, fi, Items); + + if (fi.IsDir()) + { + const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR; + unsigned parent = AddPrefix(phyParentCur, logParent, fs2us(name2)); + EnumerateDir(parent, parent, phyPrefix + phyPrefixCur + name2); + } + } + ReserveDown(); +} + + + + + + +static HRESULT EnumerateDirItems( + const NWildcard::CCensorNode &curNode, + int phyParent, int logParent, const FString &phyPrefix, + const UStringVector &addArchivePrefix, + CDirItems &dirItems, + bool enterToSubFolders, + IEnumDirItemCallback *callback); + +static HRESULT EnumerateDirItems_Spec( + const NWildcard::CCensorNode &curNode, + int phyParent, int logParent, const FString &curFolderName, + const FString &phyPrefix, + const UStringVector &addArchivePrefix, + CDirItems &dirItems, + bool enterToSubFolders, + IEnumDirItemCallback *callback) +{ + const FString name2 = curFolderName + FCHAR_PATH_SEPARATOR; + unsigned parent = dirItems.AddPrefix(phyParent, logParent, fs2us(name2)); + unsigned numItems = dirItems.Items.Size(); + HRESULT res = EnumerateDirItems( + curNode, parent, parent, phyPrefix + name2, + addArchivePrefix, dirItems, enterToSubFolders, callback); + if (numItems == dirItems.Items.Size()) + dirItems.DeleteLastPrefix(); + return res; +} + +#if 0 // #ifndef UNDER_CE + +static void EnumerateAltStreams( + const NFind::CFileInfo &fi, + const NWildcard::CCensorNode &curNode, + int phyParent, int logParent, const FString &phyPrefix, + const UStringVector &addArchivePrefix, // prefix from curNode + CDirItems &dirItems) +{ + const FString fullPath = phyPrefix + fi.Name; + NFind::CStreamEnumerator enumerator(fullPath); + for (;;) + { + NFind::CStreamInfo si; + bool found; + if (!enumerator.Next(si, found)) + { + dirItems.AddError(fullPath + FTEXT(":*"), (DWORD)E_FAIL); + break; + } + if (!found) + break; + if (si.IsMainStream()) + continue; + UStringVector addArchivePrefixNew = addArchivePrefix; + UString reducedName = si.GetReducedName(); + addArchivePrefixNew.Back() += reducedName; + if (curNode.CheckPathToRoot(false, addArchivePrefixNew, true)) + continue; + NFind::CFileInfo fi2 = fi; + fi2.Name += us2fs(reducedName); + fi2.Size = si.Size; + fi2.Attrib &= ~FILE_ATTRIBUTE_DIRECTORY; + fi2.IsAltStream = true; + AddDirFileInfo(phyParent, logParent, -1, fi2, dirItems.Items); + dirItems.TotalSize += fi2.Size; + } +} + +void CDirItems::SetLinkInfo(CDirItem &dirItem, const NFind::CFileInfo &fi, + const FString &phyPrefix) +{ + if (!SymLinks || !fi.HasReparsePoint()) + return; + const FString path = phyPrefix + fi.Name; + CByteBuffer &buf = dirItem.ReparseData; + if (NIO::GetReparseData(path, buf)) + { + CReparseAttr attr; + if (attr.Parse(buf, buf.Size())) + return; + } + AddError(path); + buf.Free(); +} + +#endif + +static HRESULT EnumerateForItem( + NFind::CFileInfo &fi, + const NWildcard::CCensorNode &curNode, + int phyParent, int logParent, const FString &phyPrefix, + const UStringVector &addArchivePrefix, // prefix from curNode + CDirItems &dirItems, + bool enterToSubFolders, + IEnumDirItemCallback *callback) +{ + const UString name = fs2us(fi.Name); + bool enterToSubFolders2 = enterToSubFolders; + UStringVector addArchivePrefixNew = addArchivePrefix; + addArchivePrefixNew.Add(name); + { + UStringVector addArchivePrefixNewTemp(addArchivePrefixNew); + if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fi.IsDir())) + return S_OK; + } + int dirItemIndex = -1; + + if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir())) + { + int secureIndex = -1; + #ifdef _USE_SECURITY_CODE + if (dirItems.ReadSecure) + dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex); + #endif + + dirItemIndex = dirItems.Items.Size(); + AddDirFileInfo(phyParent, logParent, secureIndex, fi, dirItems.Items); + dirItems.TotalSize += fi.Size; + if (fi.IsDir()) + enterToSubFolders2 = true; + } + + #if 0 // #ifndef UNDER_CE + if (dirItems.ScanAltStreams) + { + EnumerateAltStreams(fi, curNode, phyParent, logParent, phyPrefix, + addArchivePrefixNew, dirItems); + } + + if (dirItemIndex >= 0) + { + CDirItem &dirItem = dirItems.Items[dirItemIndex]; + dirItems.SetLinkInfo(dirItem, fi, phyPrefix); + if (dirItem.ReparseData.Size() != 0) + return S_OK; + } + #endif + + if (!fi.IsDir()) + return S_OK; + + const NWildcard::CCensorNode *nextNode = 0; + if (addArchivePrefix.IsEmpty()) + { + int index = curNode.FindSubNode(name); + if (index >= 0) + nextNode = &curNode.SubNodes[index]; + } + if (!enterToSubFolders2 && nextNode == 0) + return S_OK; + + addArchivePrefixNew = addArchivePrefix; + if (nextNode == 0) + { + nextNode = &curNode; + addArchivePrefixNew.Add(name); + } + + return EnumerateDirItems_Spec( + *nextNode, phyParent, logParent, fi.Name, phyPrefix, + addArchivePrefixNew, + dirItems, + enterToSubFolders2, callback); +} + + +static bool CanUseFsDirect(const NWildcard::CCensorNode &curNode) +{ + FOR_VECTOR (i, curNode.IncludeItems) + { + const NWildcard::CItem &item = curNode.IncludeItems[i]; + if (item.Recursive || item.PathParts.Size() != 1) + return false; + const UString &name = item.PathParts.Front(); + if (name.IsEmpty()) + return false; + + /* Windows doesn't support file name with wildcard. + but if another system supports file name with wildcard, + and wildcard mode is disabled, we can ignore wildcard in name */ + /* + if (!item.WildcardParsing) + continue; + */ + if (DoesNameContainWildcard(name)) + return false; + } + return true; +} + + +static HRESULT EnumerateDirItems( + const NWildcard::CCensorNode &curNode, + int phyParent, int logParent, const FString &phyPrefix, + const UStringVector &addArchivePrefix, // prefix from curNode + CDirItems &dirItems, + bool enterToSubFolders, + IEnumDirItemCallback *callback) +{ + if (!enterToSubFolders) + if (curNode.NeedCheckSubDirs()) + enterToSubFolders = true; + if (callback) + RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), dirItems.TotalSize, fs2us(phyPrefix), true)); + + // try direct_names case at first + if (addArchivePrefix.IsEmpty() && !enterToSubFolders) + { + if (CanUseFsDirect(curNode)) + { + // all names are direct (no wildcards) + // so we don't need file_system's dir enumerator + CRecordVector<bool> needEnterVector; + unsigned i; + + for (i = 0; i < curNode.IncludeItems.Size(); i++) + { + const NWildcard::CItem &item = curNode.IncludeItems[i]; + const UString &name = item.PathParts.Front(); + const FString fullPath = phyPrefix + us2fs(name); + NFind::CFileInfo fi; + #ifdef _WIN32 + if (phyPrefix.IsEmpty() && item.IsDriveItem()) + { + fi.SetAsDir(); + fi.Name = fullPath; + } + else + #endif + if (!fi.Find(fullPath)) + { + dirItems.AddError(fullPath); + continue; + } + bool isDir = fi.IsDir(); + if (isDir && !item.ForDir || !isDir && !item.ForFile) + { + dirItems.AddError(fullPath, (DWORD)E_FAIL); + continue; + } + { + UStringVector pathParts; + pathParts.Add(fs2us(fi.Name)); + if (curNode.CheckPathToRoot(false, pathParts, !isDir)) + continue; + } + + int secureIndex = -1; + #ifdef _USE_SECURITY_CODE + if (dirItems.ReadSecure) + dirItems.AddSecurityItem(fullPath, secureIndex); + #endif + + AddDirFileInfo(phyParent, logParent, secureIndex, fi, dirItems.Items); + + #if 0 // #ifndef UNDER_CE + { + CDirItem &dirItem = dirItems.Items.Back(); + dirItems.SetLinkInfo(dirItem, fi, phyPrefix); + if (dirItem.ReparseData.Size() != 0) + continue; + } + #endif + + dirItems.TotalSize += fi.Size; + + #if 0 // #ifndef UNDER_CE + if (dirItems.ScanAltStreams) + { + UStringVector pathParts; + pathParts.Add(fs2us(fi.Name)); + EnumerateAltStreams(fi, curNode, phyParent, logParent, phyPrefix, + pathParts, dirItems); + } + #endif + + 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)); + } + + for (i = 0; i < curNode.SubNodes.Size(); i++) + { + if (i < needEnterVector.Size()) + if (!needEnterVector[i]) + continue; + const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i]; + const FString fullPath = phyPrefix + us2fs(nextNode.Name); + NFind::CFileInfo fi; + #ifdef _WIN32 + if (phyPrefix.IsEmpty() && NWildcard::IsDriveColonName(nextNode.Name)) + { + fi.SetAsDir(); + fi.Name = fullPath; + } + else + #endif + if (!fi.Find(fullPath,true)) + { + if (!nextNode.AreThereIncludeItems()) + continue; + dirItems.AddError(fullPath); + continue; + } + if (!fi.IsDir()) + { + dirItems.AddError(fullPath, (DWORD)E_FAIL); + continue; + } + + RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix, + UStringVector(), dirItems, false, callback)); + } + + return S_OK; + } + } + + #ifdef _WIN32 + #ifndef UNDER_CE + + // scan drives, if wildcard is "*:\" + + if (phyPrefix.IsEmpty() && curNode.IncludeItems.Size() > 0) + { + unsigned i; + for (i = 0; i < curNode.IncludeItems.Size(); i++) + { + const NWildcard::CItem &item = curNode.IncludeItems[i]; + if (item.PathParts.Size() < 1) + break; + const UString &name = item.PathParts.Front(); + if (name.Len() != 2 || name[1] != ':') + break; + if (item.PathParts.Size() == 1) + if (item.ForFile || !item.ForDir) + break; + if (NWildcard::IsDriveColonName(name)) + continue; + if (name[0] != '*' && name[0] != '?') + break; + } + if (i == curNode.IncludeItems.Size()) + { + FStringVector driveStrings; + NFind::MyGetLogicalDriveStrings(driveStrings); + for (i = 0; i < driveStrings.Size(); i++) + { + FString driveName = driveStrings[i]; + if (driveName.Len() < 3 || driveName.Back() != '\\') + return E_FAIL; + driveName.DeleteBack(); + NFind::CFileInfo fi; + fi.SetAsDir(); + fi.Name = driveName; + + RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix, + addArchivePrefix, dirItems, enterToSubFolders, callback)); + } + return S_OK; + } + } + + #endif + #endif + + NFind::CEnumerator enumerator(phyPrefix + FCHAR_ANY_MASK); + for (unsigned ttt = 0; ; ttt++) + { + NFind::CFileInfo fi; + bool found; + if (!enumerator.Next(fi, found)) + { + dirItems.AddError(phyPrefix); + break; + } + if (!found) + break; + + if (callback && (ttt & 0xFF) == 0xFF) + RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), dirItems.TotalSize, fs2us(phyPrefix), true)); + + RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix, + addArchivePrefix, dirItems, enterToSubFolders, callback)); + } + return S_OK; +} + +HRESULT EnumerateItems( + const NWildcard::CCensor &censor, + const NWildcard::ECensorPathMode pathMode, + const UString &addPathPrefix, + CDirItems &dirItems, + IEnumDirItemCallback *callback) +{ + FOR_VECTOR (i, censor.Pairs) + { + const NWildcard::CPair &pair = censor.Pairs[i]; + int phyParent = pair.Prefix.IsEmpty() ? -1 : dirItems.AddPrefix(-1, -1, pair.Prefix); + int logParent = -1; + + if (pathMode == NWildcard::k_AbsPath) + logParent = phyParent; + else + { + if (!addPathPrefix.IsEmpty()) + logParent = dirItems.AddPrefix(-1, -1, addPathPrefix); + } + + RINOK(EnumerateDirItems(pair.Head, phyParent, logParent, us2fs(pair.Prefix), UStringVector(), + dirItems, + false, // enterToSubFolders + callback)); + } + dirItems.ReserveDown(); + + #if defined(_WIN32) && !defined(UNDER_CE) + dirItems.FillFixedReparse(); + #endif + + return S_OK; +} + +#if defined(_WIN32) && !defined(UNDER_CE) + +void CDirItems::FillFixedReparse() +{ + /* imagex/WIM reduces absolute pathes in links (raparse data), + if we archive non root folder. We do same thing here */ + + if (!SymLinks) + return; + + FOR_VECTOR(i, Items) + { + CDirItem &item = Items[i]; + if (item.ReparseData.Size() == 0) + continue; + + CReparseAttr attr; + if (!attr.Parse(item.ReparseData, item.ReparseData.Size())) + continue; + if (attr.IsRelative()) + continue; + + const UString &link = attr.GetPath(); + if (!IsDrivePath(link)) + continue; + // maybe we need to support networks paths also ? + + FString fullPathF; + if (!NDir::MyGetFullPathName(us2fs(GetPhyPath(i)), fullPathF)) + continue; + UString fullPath = fs2us(fullPathF); + const UString logPath = GetLogPath(i); + if (logPath.Len() >= fullPath.Len()) + continue; + if (CompareFileNames(logPath, fullPath.RightPtr(logPath.Len())) != 0) + continue; + + const UString prefix = fullPath.Left(fullPath.Len() - logPath.Len()); + if (prefix.Back() != WCHAR_PATH_SEPARATOR) + continue; + + unsigned rootPrefixSize = GetRootPrefixSize(prefix); + if (rootPrefixSize == 0) + continue; + if (rootPrefixSize == prefix.Len()) + continue; // simple case: paths are from root + + if (link.Len() <= prefix.Len()) + continue; + + if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0) + continue; + + UString newLink = prefix.Left(rootPrefixSize); + newLink += link.Ptr(prefix.Len()); + + CByteBuffer data; + if (!FillLinkData(data, newLink, attr.IsSymLink())) + continue; + item.ReparseData2 = data; + } +} + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.h new file mode 100644 index 000000000..803a64e7d --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.h @@ -0,0 +1,27 @@ +// 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, int secureIndex, + const NWindows::NFile::NFind::CFileInfo &fi, CObjectVector<CDirItem> &dirItems); + +struct IEnumDirItemCallback +{ + virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) = 0; +}; + +HRESULT EnumerateItems( + const NWildcard::CCensor &censor, + NWildcard::ECensorPathMode pathMode, + const UString &addPathPrefix, + CDirItems &dirItems, + IEnumDirItemCallback *callback); + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Extract.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Extract.cpp new file mode 100644 index 000000000..5f94254ef --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Extract.cpp @@ -0,0 +1,473 @@ +// Extract.cpp + +#include "StdAfx.h" + +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantConv.h" + +#include "../Common/ExtractingFilePath.h" + +#include "Extract.h" +#include "SetProperties.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +static HRESULT DecompressArchive( + CCodecs *codecs, + const CArchiveLink &arcLink, + UInt64 packSize, + const NWildcard::CCensorNode &wildcardCensor, + const CExtractOptions &options, + bool calcCrc, + IExtractCallbackUI *callback, + CArchiveExtractCallback *ecs, + UString &errorMessage, + UInt64 &stdInProcessed) +{ + const CArc &arc = arcLink.Arcs.Back(); + stdInProcessed = 0; + IInArchive *archive = arc.Archive; + CRecordVector<UInt32> realIndices; + + UStringVector removePathParts; + + FString outDir = options.OutputDir; + UString replaceName = arc.DefaultName; + + if (arcLink.Arcs.Size() > 1) + { + // Most "pe" archives have same name of archive subfile "[0]" or ".rsrc_1". + // So it extracts different archives to one folder. + // We will use top level archive name + const CArc &arc0 = arcLink.Arcs[0]; + if (StringsAreEqualNoCase_Ascii(codecs->Formats[arc0.FormatIndex].Name, "pe")) + replaceName = arc0.DefaultName; + } + + outDir.Replace(FSTRING_ANY_MASK, us2fs(GetCorrectFsPath(replaceName))); + + bool elimIsPossible = false; + UString elimPrefix; // only pure name without dir delimiter + FString outDirReduced = outDir; + + if (options.ElimDup.Val) + { + UString dirPrefix; + SplitPathToParts_Smart(fs2us(outDir), dirPrefix, elimPrefix); + if (!elimPrefix.IsEmpty()) + { + if (IsCharDirLimiter(elimPrefix.Back())) + elimPrefix.DeleteBack(); + if (!elimPrefix.IsEmpty()) + { + outDirReduced = us2fs(dirPrefix); + elimIsPossible = true; + } + } + } + + if (!options.StdInMode) + { + UInt32 numItems; + RINOK(archive->GetNumberOfItems(&numItems)); + + UString filePath; + + for (UInt32 i = 0; i < numItems; i++) + { + RINOK(arc.GetItemPath(i, filePath)); + + if (elimIsPossible && options.ElimDup.Val) + { + if (!IsPath1PrefixedByPath2(filePath, elimPrefix)) + elimIsPossible = false; + else + { + wchar_t c = filePath[elimPrefix.Len()]; + if (c != 0 && !IsCharDirLimiter(c)) + elimIsPossible = false; + } + } + + bool isFolder; + RINOK(Archive_IsItem_Folder(archive, i, isFolder)); + bool isAltStream; + RINOK(Archive_IsItem_AltStream(archive, i, isAltStream)); + if (!options.NtOptions.AltStreams.Val && isAltStream) + continue; + if (!wildcardCensor.CheckPath(isAltStream, filePath, !isFolder)) + continue; + realIndices.Add(i); + } + + if (realIndices.Size() == 0) + { + callback->ThereAreNoFiles(); + return callback->ExtractResult(S_OK); + } + } + + if (elimIsPossible) + outDir = outDirReduced; + + #ifdef _WIN32 + // GetCorrectFullFsPath doesn't like "..". + // outDir.TrimRight(); + // outDir = GetCorrectFullFsPath(outDir); + #endif + + if (outDir.IsEmpty()) + outDir = FString(FTEXT(".")) + FString(FSTRING_PATH_SEPARATOR); + else + if (!CreateComplexDir(outDir)) + { + HRESULT res = ::GetLastError(); + if (res == S_OK) + res = E_FAIL; + errorMessage = ((UString)L"Can not create output directory ") + fs2us(outDir); + return res; + } + + ecs->Init( + options.NtOptions, + options.StdInMode ? &wildcardCensor : NULL, + &arc, + callback, + options.StdOutMode, options.TestMode, + outDir, + removePathParts, + packSize); + + + #ifdef SUPPORT_LINKS + + if (!options.StdInMode && + !options.TestMode && + options.NtOptions.HardLinks.Val) + { + RINOK(ecs->PrepareHardLinks(&realIndices)); + } + + #endif + + + HRESULT result; + Int32 testMode = (options.TestMode && !calcCrc) ? 1: 0; + if (options.StdInMode) + { + result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, ecs); + NCOM::CPropVariant prop; + if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK) + ConvertPropVariantToUInt64(prop, stdInProcessed); + } + else + result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, ecs); + if (result == S_OK && !options.StdInMode) + result = ecs->SetDirsTimes(); + return callback->ExtractResult(result); +} + +/* v9.31: BUG was fixed: + Sorted list for file paths was sorted with case insensitive compare function. + But FindInSorted function did binary search via case sensitive compare function */ + +int Find_FileName_InSortedVector(const UStringVector &fileName, const UString &name) +{ + unsigned left = 0, right = fileName.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + const UString &midValue = fileName[mid]; + int compare = CompareFileNames(name, midValue); + if (compare == 0) + return mid; + if (compare < 0) + right = mid; + else + left = mid + 1; + } + return -1; +} + +HRESULT Extract( + CCodecs *codecs, + const CObjectVector<COpenType> &types, + const CIntVector &excludedFormats, + UStringVector &arcPaths, UStringVector &arcPathsFull, + const NWildcard::CCensorNode &wildcardCensor, + const CExtractOptions &options, + IOpenCallbackUI *openCallback, + IExtractCallbackUI *extractCallback, + #ifndef _SFX + IHashCalc *hash, + #endif + UString &errorMessage, + CDecompressStat &stat) +{ + stat.Clear(); + UInt64 totalPackSize = 0; + CRecordVector<UInt64> arcSizes; + + unsigned numArcs = options.StdInMode ? 1 : arcPaths.Size(); + + unsigned i; + for (i = 0; i < numArcs; i++) + { + NFind::CFileInfo fi; + fi.Size = 0; + if (!options.StdInMode) + { + const FString &arcPath = us2fs(arcPaths[i]); + if (!fi.Find(arcPath,true)) + throw "there is no such archive"; + if (fi.IsDir()) + throw "can't decompress folder"; + } + arcSizes.Add(fi.Size); + totalPackSize += fi.Size; + } + + CBoolArr skipArcs(numArcs); + for (i = 0; i < numArcs; i++) + skipArcs[i] = false; + + CArchiveExtractCallback *ecs = new CArchiveExtractCallback; + CMyComPtr<IArchiveExtractCallback> ec(ecs); + bool multi = (numArcs > 1); + ecs->InitForMulti(multi, options.PathMode, options.OverwriteMode); + #ifndef _SFX + ecs->SetHashMethods(hash); + #endif + + if (multi) + { + RINOK(extractCallback->SetTotal(totalPackSize)); + } + + UInt64 totalPackProcessed = 0; + bool thereAreNotOpenArcs = false; + + for (i = 0; i < numArcs; i++) + { + if (skipArcs[i]) + continue; + + const UString &arcPath = arcPaths[i]; + NFind::CFileInfo fi; + if (options.StdInMode) + { + fi.Size = 0; + fi.Attrib = 0; + } + else + { + if (!fi.Find(us2fs(arcPath),true) || fi.IsDir()) + throw "there is no such archive"; + } + + #ifndef _NO_CRYPTO + openCallback->Open_ClearPasswordWasAskedFlag(); + #endif + + RINOK(extractCallback->BeforeOpen(arcPath)); + CArchiveLink arcLink; + + CObjectVector<COpenType> types2 = types; + /* + #ifndef _SFX + if (types.IsEmpty()) + { + int pos = arcPath.ReverseFind(L'.'); + if (pos >= 0) + { + UString s = arcPath.Ptr(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.Ptr(pos + 1)); + if (index2 >= 0) // && s.CompareNoCase(L"rar") != 0 + { + types2.Add(index2); + types2.Add(index); + } + } + } + } + } + #endif + */ + + COpenOptions op; + #ifndef _SFX + op.props = &options.Properties; + #endif + op.codecs = codecs; + op.types = &types2; + op.excludedFormats = &excludedFormats; + op.stdInMode = options.StdInMode; + op.stream = NULL; + op.filePath = arcPath; + HRESULT result = arcLink.Open2(op, openCallback); + + if (result == E_ABORT) + return result; + + bool crypted = false; + #ifndef _NO_CRYPTO + crypted = openCallback->Open_WasPasswordAsked(); + #endif + + if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) + result = S_FALSE; + + // arcLink.Set_ErrorsText(); + RINOK(extractCallback->OpenResult(arcPath, result, crypted)); + + + { + FOR_VECTOR (r, arcLink.Arcs) + { + const CArc &arc = arcLink.Arcs[r]; + const CArcErrorInfo &er = arc.ErrorInfo; + if (er.IsThereErrorOrWarning()) + { + RINOK(extractCallback->SetError(r, arc.Path, + er.GetErrorFlags(), er.ErrorMessage, + er.GetWarningFlags(), er.WarningMessage)); + } + } + } + + if (result != S_OK) + { + thereAreNotOpenArcs = true; + if (!options.StdInMode) + { + NFind::CFileInfo fi; + if (fi.Find(us2fs(arcPath))) + if (!fi.IsDir()) + totalPackProcessed += fi.Size; + } + continue; + } + + if (!options.StdInMode) + { + // numVolumes += arcLink.VolumePaths.Size(); + // arcLink.VolumesSize; + + // totalPackSize -= DeleteUsedFileNamesFromList(arcLink, i + 1, arcPaths, arcPathsFull, &arcSizes); + // numArcs = arcPaths.Size(); + if (arcLink.VolumePaths.Size() != 0) + { + Int64 correctionSize = arcLink.VolumesSize; + FOR_VECTOR (v, arcLink.VolumePaths) + { + int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]); + if (index >= 0) + { + if ((unsigned)index > i) + { + skipArcs[index] = true; + correctionSize -= arcSizes[index]; + } + } + } + if (correctionSize != 0) + { + Int64 newPackSize = (Int64)totalPackSize + correctionSize; + if (newPackSize < 0) + newPackSize = 0; + totalPackSize = newPackSize; + RINOK(extractCallback->SetTotal(totalPackSize)); + } + } + } + + #ifndef _NO_CRYPTO + bool passwordIsDefined; + UString password; + RINOK(openCallback->Open_GetPasswordIfAny(passwordIsDefined, password)); + if (passwordIsDefined) + { + RINOK(extractCallback->SetPassword(password)); + } + #endif + + FOR_VECTOR (k, arcLink.Arcs) + { + const CArc &arc = arcLink.Arcs[k]; + const CArcErrorInfo &er = arc.ErrorInfo; + + if (er.ErrorFormatIndex >= 0) + { + RINOK(extractCallback->OpenTypeWarning(arc.Path, + codecs->GetFormatNamePtr(arc.FormatIndex), + codecs->GetFormatNamePtr(er.ErrorFormatIndex))) + /* + UString s = L"Can not open the file as [" + codecs->Formats[arc.ErrorFormatIndex].Name + L"] archive\n"; + s += L"The file is open as [" + codecs->Formats[arc.FormatIndex].Name + L"] archive"; + RINOK(extractCallback->MessageError(s)); + */ + } + { + const UString &s = er.ErrorMessage; + if (!s.IsEmpty()) + { + RINOK(extractCallback->MessageError(s)); + } + } + } + + CArc &arc = arcLink.Arcs.Back(); + arc.MTimeDefined = (!options.StdInMode && !fi.IsDevice); + arc.MTime = fi.MTime; + + UInt64 packProcessed; + bool calcCrc = + #ifndef _SFX + (hash != NULL); + #else + false; + #endif + + RINOK(DecompressArchive( + codecs, + arcLink, + fi.Size + arcLink.VolumesSize, + wildcardCensor, + options, + calcCrc, + extractCallback, ecs, errorMessage, packProcessed)); + if (!options.StdInMode) + packProcessed = fi.Size + arcLink.VolumesSize; + totalPackProcessed += packProcessed; + ecs->LocalProgressSpec->InSize += packProcessed; + ecs->LocalProgressSpec->OutSize = ecs->UnpackSize; + if (!errorMessage.IsEmpty()) + return E_FAIL; + } + + if (multi || thereAreNotOpenArcs) + { + RINOK(extractCallback->SetTotal(totalPackSize)); + RINOK(extractCallback->SetCompleted(&totalPackProcessed)); + } + stat.NumFolders = ecs->NumFolders; + stat.NumFiles = ecs->NumFiles; + stat.NumAltStreams = ecs->NumAltStreams; + stat.UnpackSize = ecs->UnpackSize; + stat.AltStreams_UnpackSize = ecs->AltStreams_UnpackSize; + stat.NumArchives = arcPaths.Size(); + stat.PackSize = ecs->LocalProgressSpec->InSize; + return S_OK; +} diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Extract.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Extract.h new file mode 100644 index 000000000..052b2f7d3 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Extract.h @@ -0,0 +1,94 @@ +// 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 CExtractOptionsBase +{ + CBoolPair ElimDup; + + bool PathMode_Force; + bool OverwriteMode_Force; + NExtract::NPathMode::EEnum PathMode; + NExtract::NOverwriteMode::EEnum OverwriteMode; + + FString OutputDir; + CExtractNtOptions NtOptions; + + CExtractOptionsBase(): + PathMode_Force(false), + OverwriteMode_Force(false), + PathMode(NExtract::NPathMode::kFullPaths), + OverwriteMode(NExtract::NOverwriteMode::kAsk) + {} +}; + +struct CExtractOptions: public CExtractOptionsBase +{ + bool StdInMode; + bool StdOutMode; + bool YesToAll; + bool TestMode; + + // bool ShowDialog; + // bool PasswordEnabled; + // UString Password; + #ifndef _SFX + CObjectVector<CProperty> Properties; + #endif + + #ifdef EXTERNAL_CODECS + CCodecs *Codecs; + #endif + + CExtractOptions(): + TestMode(false), + StdInMode(false), + StdOutMode(false), + YesToAll(false) + {} +}; + +struct CDecompressStat +{ + UInt64 NumArchives; + UInt64 UnpackSize; + UInt64 AltStreams_UnpackSize; + UInt64 PackSize; + UInt64 NumFolders; + UInt64 NumFiles; + UInt64 NumAltStreams; + + void Clear() + { + NumArchives = UnpackSize = AltStreams_UnpackSize = PackSize = NumFolders = NumFiles = NumAltStreams = 0; + } +}; + +HRESULT Extract( + CCodecs *codecs, + const CObjectVector<COpenType> &types, + const CIntVector &excludedFormats, + UStringVector &archivePaths, UStringVector &archivePathsFull, + const NWildcard::CCensorNode &wildcardCensor, + const CExtractOptions &options, + IOpenCallbackUI *openCallback, + IExtractCallbackUI *extractCallback, + #ifndef _SFX + IHashCalc *hash, + #endif + UString &errorMessage, + CDecompressStat &stat); + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ExtractMode.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ExtractMode.h new file mode 100644 index 000000000..a54376705 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ExtractMode.h @@ -0,0 +1,33 @@ +// ExtractMode.h + +#ifndef __EXTRACT_MODE_H +#define __EXTRACT_MODE_H + +namespace NExtract { + +namespace NPathMode +{ + enum EEnum + { + kFullPaths, + kCurPaths, + kNoPaths, + kAbsPaths + }; +} + +namespace NOverwriteMode +{ + enum EEnum + { + kAsk, + kOverwrite, + kSkip, + kRename, + kRenameExisting + }; +} + +} + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.cpp new file mode 100644 index 000000000..852fd5adb --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.cpp @@ -0,0 +1,190 @@ +// ExtractingFilePath.cpp + +#include "StdAfx.h" + +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileName.h" + +#include "ExtractingFilePath.h" + +static UString ReplaceIncorrectChars(const UString &s, bool repaceColon) +{ + #ifdef _WIN32 + UString res; + bool beforeColon = true; + { + for (unsigned i = 0; i < s.Len(); i++) + { + wchar_t c = s[i]; + if (beforeColon) + if (c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"') + c = '_'; + if (c == ':') + { + if (repaceColon) + c = '_'; + else + beforeColon = false; + } + res += c; + } + } + if (beforeColon) + { + for (int i = res.Len() - 1; i >= 0; i--) + { + wchar_t c = res[i]; + if (c != '.' && c != ' ') + break; + res.ReplaceOneCharAtPos(i, '_'); + } + } + 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, unsigned len) +{ + int dotPos = name.Find(L'.'); + if (dotPos < 0) + dotPos = name.Len(); + UString s = name.Left(dotPos); + s.TrimRight(); + return s.Len() != len; +} + +static bool CheckNameNum(const UString &name, const wchar_t *reservedName) +{ + unsigned len = MyStringLen(reservedName); + if (name.Len() <= len) + return true; + if (MyStringCompareNoCase_N(name, reservedName, len) != 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 (unsigned i = 0; i < ARRAY_SIZE(g_ReservedNames); i++) + { + const wchar_t *reservedName = g_ReservedNames[i]; + unsigned len = MyStringLen(reservedName); + if (name.Len() < len) + continue; + if (MyStringCompareNoCase_N(name, reservedName, len) != 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, bool repaceColon) +{ + if (path == L".." || path == L".") + return UString(); + return ReplaceIncorrectChars(path, repaceColon); +} + +void MakeCorrectPath(bool isPathFromRoot, UStringVector &pathParts, bool replaceAltStreamColon) +{ + for (unsigned i = 0; i < pathParts.Size();) + { + UString &s = pathParts[i]; + #ifdef _WIN32 + bool needReplaceColon = (replaceAltStreamColon || i != pathParts.Size() - 1); + if (i == 0 && isPathFromRoot && NWindows::NFile::NName::IsDrivePath(s)) + { + UString s2 = s[0]; + s2 += L'_'; + s2 += GetCorrectFileName(s.Ptr(2), needReplaceColon); + s = s2; + } + else + s = GetCorrectFileName(s, needReplaceColon); + #endif + + 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_VECTOR (i, parts) + { + if (i != 0) + result += WCHAR_PATH_SEPARATOR; + result += parts[i]; + } + return result; +} + +static const wchar_t *k_EmptyReplaceName = L"[]"; + +void Correct_IfEmptyLastPart(UStringVector &parts) +{ + if (parts.IsEmpty()) + parts.Add(k_EmptyReplaceName); + else + { + UString &s = parts.Back(); + if (s.IsEmpty()) + s = k_EmptyReplaceName; + } +} + +UString GetCorrectFsPath(const UString &path) +{ + UString res = GetCorrectFileName(path, true); + #ifdef _WIN32 + if (!IsSupportedName(res)) + res = (UString)L"_" + res; + #endif + if (res.IsEmpty()) + res = k_EmptyReplaceName; + return res; +} + +UString GetCorrectFullFsPath(const UString &path) +{ + UStringVector parts; + SplitPathToParts(path, parts); + FOR_VECTOR (i, parts) + { + UString &s = parts[i]; + #ifdef _WIN32 + while (!s.IsEmpty() && (s.Back() == '.' || s.Back() == ' ')) + s.DeleteBack(); + if (!IsSupportedName(s)) + s.InsertAtFront(L'_'); + #endif + } + return MakePathNameFromParts(parts); +} diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.h new file mode 100644 index 000000000..751248a97 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.h @@ -0,0 +1,21 @@ +// ExtractingFilePath.h + +#ifndef __EXTRACTING_FILE_PATH_H +#define __EXTRACTING_FILE_PATH_H + +#include "../../../Common/MyString.h" + +UString MakePathNameFromParts(const UStringVector &parts); + +/* for WIN32: + if (isRoot == true), and pathParts[0] contains path like "c:name", + it thinks that "c:" is drive prefix (it's not ":name alt stream) and + the function changes part to c_name */ +void MakeCorrectPath(bool isPathFromRoot, UStringVector &pathParts, bool replaceAltStreamColon); + +UString GetCorrectFsPath(const UString &path); +UString GetCorrectFullFsPath(const UString &path); + +void Correct_IfEmptyLastPart(UStringVector &parts); + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/HashCalc.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/HashCalc.cpp new file mode 100644 index 000000000..2d13a2af1 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/HashCalc.cpp @@ -0,0 +1,361 @@ +// HashCalc.cpp + +#include "StdAfx.h" + +#include "../../../../C/Alloc.h" + +#include "../../../Common/StringToInt.h" + +#include "../../Common/FileStreams.h" +#include "../../Common/StreamUtils.h" + +#include "EnumDirItems.h" +#include "HashCalc.h" + +using namespace NWindows; + +class CHashMidBuf +{ + void *_data; +public: + CHashMidBuf(): _data(0) {} + operator void *() { return _data; } + bool Alloc(size_t size) + { + if (_data != 0) + return false; + _data = ::MidAlloc(size); + return _data != 0; + } + ~CHashMidBuf() { ::MidFree(_data); } +}; + +struct CEnumDirItemCallback_Hash: public IEnumDirItemCallback +{ + IHashCallbackUI *Callback; + + HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) + { + return Callback->ScanProgress(numFolders, numFiles, totalSize, path, isDir); + } +}; + +static const wchar_t *k_DefaultHashMethod = L"CRC32"; + +HRESULT CHashBundle::SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &hashMethods) +{ + UStringVector names = hashMethods; + if (names.IsEmpty()) + names.Add(k_DefaultHashMethod); + + CRecordVector<CMethodId> ids; + CObjectVector<COneMethodInfo> methods; + + unsigned i; + for (i = 0; i < names.Size(); i++) + { + COneMethodInfo m; + RINOK(m.ParseMethodFromString(names[i])); + + if (m.MethodName.IsEmpty()) + m.MethodName = k_DefaultHashMethod; + + if (m.MethodName == L"*") + { + CRecordVector<CMethodId> tempMethods; + GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods); + methods.Clear(); + ids.Clear(); + FOR_VECTOR (t, tempMethods) + { + int index = ids.AddToUniqueSorted(tempMethods[t]); + if (ids.Size() != methods.Size()) + methods.Insert(index, m); + } + break; + } + else + { + // m.MethodName.RemoveChar(L'-'); + CMethodId id; + if (!FindHashMethod(EXTERNAL_CODECS_LOC_VARS m.MethodName, id)) + return E_NOTIMPL; + int index = ids.AddToUniqueSorted(id); + if (ids.Size() != methods.Size()) + methods.Insert(index, m); + } + } + + for (i = 0; i < ids.Size(); i++) + { + CMyComPtr<IHasher> hasher; + UString name; + RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS ids[i], name, hasher)); + if (!hasher) + throw "Can't create hasher"; + const COneMethodInfo &m = methods[i]; + { + CMyComPtr<ICompressSetCoderProperties> scp; + hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp); + if (scp) + { + RINOK(m.SetCoderProps(scp, NULL)); + } + } + UInt32 digestSize = hasher->GetDigestSize(); + if (digestSize > k_HashCalc_DigestSize_Max) + return E_NOTIMPL; + CHasherState &h = Hashers.AddNew(); + h.Hasher = hasher; + h.Name = name; + h.DigestSize = digestSize; + for (int i = 0; i < k_HashCalc_NumGroups; i++) + memset(h.Digests[i], 0, digestSize); + } + return S_OK; +} + +void CHashBundle::InitForNewFile() +{ + CurSize = 0; + FOR_VECTOR (i, Hashers) + { + CHasherState &h = Hashers[i]; + h.Hasher->Init(); + memset(h.Digests[k_HashCalc_Index_Current], 0, h.DigestSize); + } +} + +void CHashBundle::Update(const void *data, UInt32 size) +{ + CurSize += size; + FOR_VECTOR (i, Hashers) + Hashers[i].Hasher->Update(data, size); +} + +void CHashBundle::SetSize(UInt64 size) +{ + CurSize = size; +} + +static void AddDigests(Byte *dest, const Byte *src, UInt32 size) +{ + unsigned next = 0; + for (UInt32 i = 0; i < size; i++) + { + next += (unsigned)dest[i] + (unsigned)src[i]; + dest[i] = (Byte)next; + next >>= 8; + } +} + +void CHashBundle::Final(bool isDir, bool isAltStream, const UString &path) +{ + if (isDir) + NumDirs++; + else if (isAltStream) + { + NumAltStreams++; + AltStreamsSize += CurSize; + } + else + { + NumFiles++; + FilesSize += CurSize; + } + + Byte pre[16]; + memset(pre, 0, sizeof(pre)); + if (isDir) + pre[0] = 1; + + FOR_VECTOR (i, Hashers) + { + CHasherState &h = Hashers[i]; + if (!isDir) + { + h.Hasher->Final(h.Digests[0]); + if (!isAltStream) + AddDigests(h.Digests[k_HashCalc_Index_DataSum], h.Digests[0], h.DigestSize); + } + + h.Hasher->Init(); + h.Hasher->Update(pre, sizeof(pre)); + h.Hasher->Update(h.Digests[0], h.DigestSize); + + for (unsigned k = 0; k < path.Len(); k++) + { + wchar_t c = path[k]; + Byte temp[2] = { (Byte)(c & 0xFF), (Byte)((c >> 8) & 0xFF) }; + h.Hasher->Update(temp, 2); + } + + Byte tempDigest[k_HashCalc_DigestSize_Max]; + h.Hasher->Final(tempDigest); + if (!isAltStream) + AddDigests(h.Digests[k_HashCalc_Index_NamesSum], tempDigest, h.DigestSize); + AddDigests(h.Digests[k_HashCalc_Index_StreamsSum], tempDigest, h.DigestSize); + } +} + + +HRESULT HashCalc( + DECL_EXTERNAL_CODECS_LOC_VARS + const NWildcard::CCensor &censor, + const CHashOptions &options, + UString &errorInfo, + IHashCallbackUI *callback) +{ + CDirItems dirItems; + + UInt64 numErrors = 0; + UInt64 totalBytes = 0; + if (options.StdInMode) + { + CDirItem di; + di.Size = (UInt64)(Int64)-1; + di.Attrib = 0; + di.MTime.dwLowDateTime = 0; + di.MTime.dwHighDateTime = 0; + di.CTime = di.ATime = di.MTime; + dirItems.Items.Add(di); + } + else + { + CEnumDirItemCallback_Hash enumCallback; + enumCallback.Callback = callback; + RINOK(callback->StartScanning()); + dirItems.ScanAltStreams = options.AltStreamsMode; + HRESULT res = EnumerateItems(censor, + options.PathMode, + UString(), + dirItems, &enumCallback); + totalBytes = dirItems.TotalSize; + FOR_VECTOR (i, dirItems.ErrorPaths) + { + RINOK(callback->CanNotFindError(fs2us(dirItems.ErrorPaths[i]), dirItems.ErrorCodes[i])); + } + numErrors = dirItems.ErrorPaths.Size(); + if (res != S_OK) + { + if (res != E_ABORT) + errorInfo = L"Scanning error"; + return res; + } + RINOK(callback->FinishScanning()); + } + + unsigned i; + CHashBundle hb; + RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS options.Methods)); + hb.Init(); + hb.NumErrors = numErrors; + + if (options.StdInMode) + { + RINOK(callback->SetNumFiles(1)); + } + else + { + RINOK(callback->SetTotal(totalBytes)); + } + + const UInt32 kBufSize = 1 << 15; + CHashMidBuf buf; + if (!buf.Alloc(kBufSize)) + return E_OUTOFMEMORY; + + UInt64 completeValue = 0; + + RINOK(callback->BeforeFirstFile(hb)); + + for (i = 0; i < dirItems.Items.Size(); i++) + { + CMyComPtr<ISequentialInStream> inStream; + UString path; + bool isDir = false; + bool isAltStream = false; + if (options.StdInMode) + { + inStream = new CStdInFileStream; + } + else + { + CInFileStream *inStreamSpec = new CInFileStream; + inStream = inStreamSpec; + const CDirItem &dirItem = dirItems.Items[i]; + isDir = dirItem.IsDir(); + isAltStream = dirItem.IsAltStream; + path = dirItems.GetLogPath(i); + if (!isDir) + { + UString phyPath = dirItems.GetPhyPath(i); + if (!inStreamSpec->OpenShared(us2fs(phyPath), options.OpenShareForWrite)) + { + HRESULT res = callback->OpenFileError(phyPath, ::GetLastError()); + hb.NumErrors++; + if (res != S_FALSE) + return res; + continue; + } + } + } + RINOK(callback->GetStream(path, isDir)); + UInt64 fileSize = 0; + + hb.InitForNewFile(); + if (!isDir) + { + for (UInt32 step = 0;; step++) + { + if ((step & 0xFF) == 0) + RINOK(callback->SetCompleted(&completeValue)); + UInt32 size; + RINOK(inStream->Read(buf, kBufSize, &size)); + if (size == 0) + break; + hb.Update(buf, size); + fileSize += size; + completeValue += size; + } + } + hb.Final(isDir, isAltStream, path); + RINOK(callback->SetOperationResult(fileSize, hb, !isDir)); + RINOK(callback->SetCompleted(&completeValue)); + } + return callback->AfterLastFile(hb); +} + + +static inline char GetHex(Byte value) +{ + return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); +} + +void AddHashHexToString(char *dest, const Byte *data, UInt32 size) +{ + dest[size * 2] = 0; + if (!data) + { + for (UInt32 i = 0; i < size; i++) + { + dest[0] = ' '; + dest[1] = ' '; + dest += 2; + } + return; + } + int step = 2; + if (size <= 8) + { + step = -2; + dest += size * 2 - 2; + } + for (UInt32 i = 0; i < size; i++) + { + Byte b = data[i]; + dest[0] = GetHex((Byte)((b >> 4) & 0xF)); + dest[1] = GetHex((Byte)(b & 0xF)); + dest += step; + } +} diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/HashCalc.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/HashCalc.h new file mode 100644 index 000000000..68e2404cc --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/HashCalc.h @@ -0,0 +1,107 @@ +// HashCalc.h + +#ifndef __HASH_CALC_H +#define __HASH_CALC_H + +#include "../../../Common/Wildcard.h" + +#include "../../Common/CreateCoder.h" +#include "../../Common/MethodProps.h" + +#include "Property.h" + +const unsigned k_HashCalc_DigestSize_Max = 64; + +const unsigned k_HashCalc_NumGroups = 4; + +enum +{ + k_HashCalc_Index_Current, + k_HashCalc_Index_DataSum, + k_HashCalc_Index_NamesSum, + k_HashCalc_Index_StreamsSum +}; + +struct CHasherState +{ + CMyComPtr<IHasher> Hasher; + UString Name; + UInt32 DigestSize; + Byte Digests[k_HashCalc_NumGroups][k_HashCalc_DigestSize_Max]; +}; + +struct IHashCalc +{ + virtual void InitForNewFile() = 0; + virtual void Update(const void *data, UInt32 size) = 0; + virtual void SetSize(UInt64 size) = 0; + virtual void Final(bool isDir, bool isAltStream, const UString &path) = 0; +}; + +struct CHashBundle: public IHashCalc +{ + CObjectVector<CHasherState> Hashers; + + UInt64 NumFiles; + UInt64 NumDirs; + UInt64 NumAltStreams; + UInt64 FilesSize; + UInt64 AltStreamsSize; + UInt64 NumErrors; + + UInt64 CurSize; + + HRESULT SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &methods); + + void Init() + { + NumFiles = NumDirs = NumAltStreams = FilesSize = AltStreamsSize = NumErrors = 0; + } + + void InitForNewFile(); + void Update(const void *data, UInt32 size); + void SetSize(UInt64 size); + void Final(bool isDir, bool isAltStream, const UString &path); +}; + +#define INTERFACE_IHashCallbackUI(x) \ + virtual HRESULT StartScanning() x; \ + virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) x; \ + virtual HRESULT CanNotFindError(const wchar_t *name, DWORD systemError) x; \ + virtual HRESULT FinishScanning() x; \ + virtual HRESULT SetNumFiles(UInt64 numFiles) x; \ + virtual HRESULT SetTotal(UInt64 size) x; \ + virtual HRESULT SetCompleted(const UInt64 *completeValue) x; \ + virtual HRESULT CheckBreak() x; \ + virtual HRESULT BeforeFirstFile(const CHashBundle &hb) x; \ + virtual HRESULT GetStream(const wchar_t *name, bool isFolder) x; \ + virtual HRESULT OpenFileError(const wchar_t *name, DWORD systemError) x; \ + virtual HRESULT SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) x; \ + virtual HRESULT AfterLastFile(const CHashBundle &hb) x; \ + +struct IHashCallbackUI +{ + INTERFACE_IHashCallbackUI(=0) +}; + +struct CHashOptions +{ + UStringVector Methods; + bool OpenShareForWrite; + bool StdInMode; + bool AltStreamsMode; + NWildcard::ECensorPathMode PathMode; + + CHashOptions(): StdInMode(false), OpenShareForWrite(false), AltStreamsMode(false), PathMode(NWildcard::k_RelatPath) {}; +}; + +HRESULT HashCalc( + DECL_EXTERNAL_CODECS_LOC_VARS + const NWildcard::CCensor &censor, + const CHashOptions &options, + UString &errorInfo, + IHashCallbackUI *callback); + +void AddHashHexToString(char *dest, const Byte *data, UInt32 size); + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/IFileExtractCallback.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/IFileExtractCallback.h new file mode 100644 index 000000000..7bb852795 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/IFileExtractCallback.h @@ -0,0 +1,72 @@ +// IFileExtractCallback.h + +#ifndef __I_FILE_EXTRACT_CALLBACK_H +#define __I_FILE_EXTRACT_CALLBACK_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 SetError(int level, const wchar_t *name, + UInt32 errorFlags, const wchar_t *errors, + UInt32 warningFlags, const wchar_t *warnings) = 0; + virtual HRESULT ThereAreNoFiles() = 0; + virtual HRESULT ExtractResult(HRESULT result) = 0; + virtual HRESULT OpenTypeWarning(const wchar_t *name, const wchar_t *okType, const wchar_t *errorType) = 0; + + #ifndef _NO_CRYPTO + virtual HRESULT SetPassword(const UString &password) = 0; + #endif +}; + + +#define INTERFACE_IGetProp(x) \ + STDMETHOD(GetProp)(PROPID propID, PROPVARIANT *value) x; \ + +DECL_INTERFACE_SUB(IGetProp, IUnknown, 0x01, 0x20) +{ + INTERFACE_IGetProp(PURE) +}; + +#define INTERFACE_IFolderExtractToStreamCallback(x) \ + STDMETHOD(UseExtractToStream)(Int32 *res) x; \ + STDMETHOD(GetStream7)(const wchar_t *name, Int32 isDir, ISequentialOutStream **outStream, Int32 askExtractMode, IGetProp *getProp) x; \ + STDMETHOD(PrepareOperation7)(Int32 askExtractMode) x; \ + STDMETHOD(SetOperationResult7)(Int32 resultEOperationResult, bool encrypted) x; \ + +DECL_INTERFACE_SUB(IFolderExtractToStreamCallback, IUnknown, 0x01, 0x30) +{ + INTERFACE_IFolderExtractToStreamCallback(PURE) +}; + + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.cpp new file mode 100644 index 000000000..09c79147d --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.cpp @@ -0,0 +1,910 @@ +// LoadCodecs.cpp + +#include "StdAfx.h" + +#include "../../../../C/7zVersion.h" + +#include "../../../Common/MyCom.h" +#include "../../../Common/StringToInt.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/PropVariant.h" + +#include "LoadCodecs.h" + +using namespace NWindows; + +#ifdef NEW_FOLDER_INTERFACE +#include "../../../Common/StringToInt.h" +#endif + +#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/FileName.h" +#include "../../../Windows/Registry.h" +#else +#include "../../../Common/StringConvert.h" +#endif + +using namespace NFile; + +#ifdef _WIN32 +extern HINSTANCE g_hInstance; +#endif + +#define kCodecsFolderName FTEXT("Codecs") +#define kFormatsFolderName FTEXT("Formats") +static CFSTR kMainDll = FTEXT("7z.dll"); + +#ifdef _WIN32 + +static LPCTSTR kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip"); +static LPCWSTR kProgramPathValue = L"Path"; +static LPCWSTR kProgramPath2Value = L"Path" + #ifdef _WIN64 + L"64"; + #else + L"32"; + #endif + +static bool ReadPathFromRegistry(HKEY baseKey, LPCWSTR value, FString &path) +{ + NRegistry::CKey key; + if (key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS) + { + UString pathU; + if (key.QueryValue(value, pathU) == ERROR_SUCCESS) + { + path = us2fs(pathU); + NName::NormalizeDirPathPrefix(path); + return NFind::DoesFileExist(path + kMainDll); + } + } + return false; +} + +#endif // _WIN32 + +#endif // EXTERNAL_CODECS + + +static const unsigned kNumArcsMax = 48; +static unsigned g_NumArcs = 0; +static const CArcInfo *g_Arcs[kNumArcsMax]; + +void RegisterArc(const CArcInfo *arcInfo) throw() +{ + if (g_NumArcs < kNumArcsMax) + { + g_Arcs[g_NumArcs] = arcInfo; + g_NumArcs++; + } +} + +static void SplitString(const UString &srcString, UStringVector &destStrings) +{ + destStrings.Clear(); + UString s; + unsigned len = srcString.Len(); + if (len == 0) + return; + for (unsigned 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); +} + +int CArcInfoEx::FindExtension(const UString &ext) const +{ + FOR_VECTOR (i, Exts) + if (ext.IsEqualToNoCase(Exts[i].Ext)) + return i; + return -1; +} + +void CArcInfoEx::AddExts(const UString &ext, const UString &addExt) +{ + UStringVector exts, addExts; + SplitString(ext, exts); + SplitString(addExt, addExts); + FOR_VECTOR (i, exts) + { + CArcExtInfo extInfo; + extInfo.Ext = exts[i]; + if (i < addExts.Size()) + { + extInfo.AddExt = addExts[i]; + if (extInfo.AddExt == L"*") + extInfo.AddExt.Empty(); + } + Exts.Add(extInfo); + } +} + +#ifndef _SFX + +static bool ParseSignatures(const Byte *data, unsigned size, CObjectVector<CByteBuffer> &signatures) +{ + signatures.Clear(); + while (size > 0) + { + unsigned len = *data++; + size--; + if (len > size) + return false; + signatures.AddNew().CopyFrom(data, len); + data += len; + size -= len; + } + return true; +} + +#endif // _SFX + +#ifdef EXTERNAL_CODECS + +static FString GetBaseFolderPrefixFromRegistry() +{ + FString moduleFolderPrefix = NDLL::GetModuleDirPrefix(); + #ifdef _WIN32 + if (!NFind::DoesFileExist(moduleFolderPrefix + kMainDll) && + !NFind::DoesDirExist(moduleFolderPrefix + kCodecsFolderName) && + !NFind::DoesDirExist(moduleFolderPrefix + kFormatsFolderName)) + { + FString path; + if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPath2Value, path)) return path; + if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPath2Value, path)) return path; + if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPathValue, path)) return path; + if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPathValue, path)) return path; + } + #endif + return moduleFolderPrefix; +} + +static HRESULT GetCoderClass(Func_GetMethodProperty getMethodProperty, UInt32 index, + PROPID propId, CLSID &clsId, bool &isAssigned) +{ + NCOM::CPropVariant prop; + isAssigned = false; + RINOK(getMethodProperty(index, propId, &prop)); + if (prop.vt == VT_BSTR) + { + if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID)) + return E_FAIL; + 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 = (Func_GetMethodProperty)lib.Lib.GetProc("GetMethodProperty"); + if (lib.GetMethodProperty) + { + UInt32 numMethods = 1; + Func_GetNumberOfMethods getNumberOfMethodsFunc = (Func_GetNumberOfMethods)lib.Lib.GetProc("GetNumberOfMethods"); + if (getNumberOfMethodsFunc) + { + 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); + } + } + + Func_GetHashers getHashers = (Func_GetHashers)lib.Lib.GetProc("GetHashers"); + if (getHashers) + { + RINOK(getHashers(&lib.Hashers)); + if (lib.Hashers) + { + UInt32 numMethods = lib.Hashers->GetNumHashers(); + for (UInt32 i = 0; i < numMethods; i++) + { + CDllHasherInfo info; + info.LibIndex = Libs.Size() - 1; + info.HasherIndex = i; + Hashers.Add(info); + } + } + } + return S_OK; +} + +static HRESULT GetProp( + Func_GetHandlerProperty getProp, + Func_GetHandlerProperty2 getProp2, + UInt32 index, PROPID propID, NCOM::CPropVariant &prop) +{ + if (getProp2) + return getProp2(index, propID, &prop);; + return getProp(propID, &prop); +} + +static HRESULT GetProp_Bool( + Func_GetHandlerProperty getProp, + Func_GetHandlerProperty2 getProp2, + UInt32 index, PROPID propID, bool &res) +{ + res = false; + NCOM::CPropVariant prop; + RINOK(GetProp(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 GetProp_UInt32( + Func_GetHandlerProperty getProp, + Func_GetHandlerProperty2 getProp2, + UInt32 index, PROPID propID, UInt32 &res, bool &defined) +{ + res = 0; + defined = false; + NCOM::CPropVariant prop; + RINOK(GetProp(getProp, getProp2, index, propID, prop)); + if (prop.vt == VT_UI4) + { + res = prop.ulVal; + defined = true; + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +static HRESULT GetProp_String( + Func_GetHandlerProperty getProp, + Func_GetHandlerProperty2 getProp2, + UInt32 index, PROPID propID, UString &res) +{ + res.Empty(); + NCOM::CPropVariant prop; + RINOK(GetProp(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; +} + +static HRESULT GetProp_RawData( + Func_GetHandlerProperty getProp, + Func_GetHandlerProperty2 getProp2, + UInt32 index, PROPID propID, CByteBuffer &bb) +{ + bb.Free(); + NCOM::CPropVariant prop; + RINOK(GetProp(getProp, getProp2, index, propID, prop)); + if (prop.vt == VT_BSTR) + { + UINT len = ::SysStringByteLen(prop.bstrVal); + bb.CopyFrom((const Byte *)prop.bstrVal, len); + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +static const UInt32 kArcFlagsPars[] = +{ + NArchive::NHandlerPropID::kKeepName, NArcInfoFlags::kKeepName, + NArchive::NHandlerPropID::kAltStreams, NArcInfoFlags::kAltStreams, + NArchive::NHandlerPropID::kNtSecure, NArcInfoFlags::kNtSecure +}; + +HRESULT CCodecs::LoadFormats() +{ + const NDLL::CLibrary &lib = Libs.Back().Lib; + + Func_GetHandlerProperty getProp = NULL; + Func_GetHandlerProperty2 getProp2 = (Func_GetHandlerProperty2)lib.GetProc("GetHandlerProperty2"); + Func_GetIsArc getIsArc = (Func_GetIsArc)lib.GetProc("GetIsArc"); + + UInt32 numFormats = 1; + + if (getProp2) + { + Func_GetNumberOfFormats getNumberOfFormats = (Func_GetNumberOfFormats)lib.GetProc("GetNumberOfFormats"); + if (getNumberOfFormats) + { + RINOK(getNumberOfFormats(&numFormats)); + } + } + else + { + getProp = (Func_GetHandlerProperty)lib.GetProc("GetHandlerProperty"); + if (!getProp) + return S_OK; + } + + for (UInt32 i = 0; i < numFormats; i++) + { + CArcInfoEx item; + item.LibIndex = Libs.Size() - 1; + item.FormatIndex = i; + + RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kName, item.Name)); + + { + NCOM::CPropVariant prop; + if (GetProp(getProp, getProp2, i, NArchive::NHandlerPropID::kClassID, prop) != S_OK) + continue; + if (prop.vt != VT_BSTR) + continue; + if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID)) + return E_FAIL; + item.ClassID = *(const GUID *)prop.bstrVal; + prop.Clear(); + } + + UString ext, addExt; + RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kExtension, ext)); + RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kAddExtension, addExt)); + item.AddExts(ext, addExt); + + GetProp_Bool(getProp, getProp2, i, NArchive::NHandlerPropID::kUpdate, item.UpdateEnabled); + bool flags_Defined = false; + RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kFlags, item.Flags, flags_Defined)); + item.NewInterface = flags_Defined; + if (!flags_Defined) // && item.UpdateEnabled + { + // support for DLL version before 9.31: + for (unsigned j = 0; j < ARRAY_SIZE(kArcFlagsPars); j += 2) + { + bool val = false; + GetProp_Bool(getProp, getProp2, i, kArcFlagsPars[j], val); + if (val) + item.Flags |= kArcFlagsPars[j + 1]; + } + } + + CByteBuffer sig; + RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kSignature, sig)); + if (sig.Size() != 0) + item.Signatures.Add(sig); + else + { + RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kMultiSignature, sig)); + ParseSignatures(sig, (unsigned)sig.Size(), item.Signatures); + } + + bool signatureOffset_Defined; + RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kSignatureOffset, item.SignatureOffset, signatureOffset_Defined)); + + // bool version_Defined; + // RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kVersion, item.Version, version_Defined)); + + if (getIsArc) + getIsArc(i, &item.IsArcFunc); + + Formats.Add(item); + } + return S_OK; +} + +#ifdef NEW_FOLDER_INTERFACE +void CCodecIcons::LoadIcons(HMODULE m) +{ +#ifdef _WIN32 + UString iconTypes; + MyLoadString(m, kIconTypesResId, iconTypes); + UStringVector pairs; + SplitString(iconTypes, pairs); + FOR_VECTOR (i, pairs) + { + const UString &s = pairs[i]; + int pos = s.Find(L':'); + CIconPair iconPair; + iconPair.IconIndex = -1; + if (pos < 0) + pos = s.Len(); + else + { + UString num = s.Ptr(pos + 1); + if (!num.IsEmpty()) + { + const wchar_t *end; + iconPair.IconIndex = ConvertStringToUInt32(num, &end); + if (*end != 0) + continue; + } + } + iconPair.Ext = s.Left(pos); + IconPairs.Add(iconPair); + } +#endif // #ifdef _WIN32 +} + +bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const +{ +#ifdef _WIN32 + iconIndex = -1; + FOR_VECTOR (i, IconPairs) + { + const CIconPair &pair = IconPairs[i]; + if (ext.IsEqualToNoCase(pair.Ext)) + { + iconIndex = pair.IconIndex; + return true; + } + } +#endif // #ifdef _WIN32 + return false; +} + +#endif // EXTERNAL_CODECS + +#ifdef _7ZIP_LARGE_PAGES +extern "C" +{ + extern size_t g_LargePageSize; +} +#endif + +HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll) +{ +#ifdef _WIN32 + if (needCheckDll) + { + NDLL::CLibrary library; + if (!library.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE)) + return S_OK; + } +#endif + Libs.Add(CCodecLib()); + CCodecLib &lib = Libs.Back(); + lib.Path = dllPath; + 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) + { + Func_SetLargePageMode setLargePageMode = (Func_SetLargePageMode)lib.Lib.GetProc("SetLargePageMode"); + if (setLargePageMode) + setLargePageMode(); + } + #endif + + if (CaseSensitiveChange) + { + Func_SetCaseSensitive setCaseSensitive = (Func_SetCaseSensitive)lib.Lib.GetProc("SetCaseSensitive"); + if (setCaseSensitive) + setCaseSensitive(CaseSensitive ? 1 : 0); + } + + lib.CreateObject = (Func_CreateObject)lib.Lib.GetProc("CreateObject"); + if (lib.CreateObject) + { + unsigned startSize = Codecs.Size() + Hashers.Size(); + res = LoadCodecs(); + used = (startSize != Codecs.Size() + Hashers.Size()); + if (res == S_OK) + { + startSize = Formats.Size(); + res = LoadFormats(); + if (startSize != Formats.Size()) + used = true; + } + } + } + if (!used) + Libs.DeleteBack(); + return res; +} + +HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPrefix) +{ + NFile::NFind::CEnumerator enumerator(folderPrefix + FCHAR_ANY_MASK); + NFile::NFind::CFileInfo fi; + while (enumerator.Next(fi)) + { + if (fi.IsDir()) + continue; + RINOK(LoadDll(folderPrefix + fi.Name, true)); + } + return S_OK; +} + +#endif + +HRESULT CCodecs::Load() +{ + #ifdef NEW_FOLDER_INTERFACE + #ifdef _WIN32 + InternalIcons.LoadIcons(g_hInstance); + #endif + #endif + + Formats.Clear(); + + #ifdef EXTERNAL_CODECS + Codecs.Clear(); + Hashers.Clear(); + #endif + + for (UInt32 i = 0; i < g_NumArcs; i++) + { + const CArcInfo &arc = *g_Arcs[i]; + CArcInfoEx item; + + item.Name.SetFromAscii(arc.Name); + item.CreateInArchive = arc.CreateInArchive; + item.IsArcFunc = arc.IsArc; + item.Flags = arc.Flags; + + { + UString e, ae; + if (arc.Ext) + e.SetFromAscii(arc.Ext); + if (arc.AddExt) + ae.SetFromAscii(arc.AddExt); + item.AddExts(e, ae); + } + + #ifndef _SFX + + item.CreateOutArchive = arc.CreateOutArchive; + item.UpdateEnabled = (arc.CreateOutArchive != NULL); + item.SignatureOffset = arc.SignatureOffset; + // item.Version = MY_VER_MIX; + item.NewInterface = true; + + if (arc.IsMultiSignature()) + ParseSignatures(arc.Signature, arc.SignatureSize, item.Signatures); + else + item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize); + + #endif + + Formats.Add(item); + } + + #ifdef EXTERNAL_CODECS + const FString baseFolder = GetBaseFolderPrefixFromRegistry(); + RINOK(LoadDll(baseFolder + kMainDll, false)); + RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName FSTRING_PATH_SEPARATOR)); + RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName FSTRING_PATH_SEPARATOR)); + #endif + + return S_OK; +} + +#ifndef _SFX + +int CCodecs::FindFormatForArchiveName(const UString &arcPath) const +{ + int slashPos = arcPath.ReverseFind(WCHAR_PATH_SEPARATOR); + int dotPos = arcPath.ReverseFind(L'.'); + if (dotPos < 0 || dotPos < slashPos) + return -1; + const UString ext = arcPath.Ptr(dotPos + 1); + if (ext.IsEmpty()) + return -1; + if (ext.IsEqualToNoCase(L"exe")) + return -1; + FOR_VECTOR (i, Formats) + { + 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_VECTOR (i, Formats) + if (Formats[i].FindExtension(ext) >= 0) + return i; + return -1; +} + +int CCodecs::FindFormatForArchiveType(const UString &arcType) const +{ + FOR_VECTOR (i, Formats) + if (Formats[i].Name.IsEqualToNoCase(arcType)) + return i; + return -1; +} + +bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const +{ + formatIndices.Clear(); + for (unsigned pos = 0; pos < arcType.Len();) + { + int pos2 = arcType.Find('.', pos); + if (pos2 < 0) + pos2 = arcType.Len(); + const UString name = arcType.Mid(pos, pos2 - pos); + if (name.IsEmpty()) + return false; + int index = FindFormatForArchiveType(name); + if (index < 0 && name != L"*") + { + formatIndices.Clear(); + return false; + } + formatIndices.Add(index); + pos = pos2 + 1; + } + return true; +} + +#endif // _SFX + + +#ifdef EXTERNAL_CODECS + +// #define EXPORT_CODECS + +#ifdef EXPORT_CODECS + +extern unsigned g_NumCodecs; +STDAPI CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject); +STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); +#define NUM_EXPORT_CODECS g_NumCodecs + +extern unsigned g_NumHashers; +STDAPI CreateHasher(UInt32 index, IHasher **hasher); +STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); +#define NUM_EXPORT_HASHERS g_NumHashers + +#else // EXPORT_CODECS + +#define NUM_EXPORT_CODECS 0 +#define NUM_EXPORT_HASHERS 0 + +#endif // EXPORT_CODECS + +STDMETHODIMP CCodecs::GetNumberOfMethods(UInt32 *numMethods) +{ + *numMethods = NUM_EXPORT_CODECS + #ifdef EXTERNAL_CODECS + + Codecs.Size() + #endif + ; + 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 + + #ifdef EXTERNAL_CODECS + const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; + + if (propID == NMethodPropID::kDecoderIsAssigned || + propID == NMethodPropID::kEncoderIsAssigned) + { + NCOM::CPropVariant prop; + prop = (propID == NMethodPropID::kDecoderIsAssigned) ? + ci.DecoderIsAssigned : + ci.EncoderIsAssigned; + prop.Detach(value); + return S_OK; + } + return Libs[ci.LibIndex].GetMethodProperty(ci.CodecIndex, propID, value); + #else + return E_FAIL; + #endif +} + +STDMETHODIMP CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder) +{ + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + return CreateCoder2(false, index, iid, coder); + #endif + #ifdef EXTERNAL_CODECS + const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; + if (ci.DecoderIsAssigned) + return Libs[ci.LibIndex].CreateObject(&ci.Decoder, iid, (void **)coder); + return S_OK; + #else + return E_FAIL; + #endif +} + +STDMETHODIMP CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder) +{ + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + return CreateCoder2(true, index, iid, coder); + #endif + #ifdef EXTERNAL_CODECS + const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; + if (ci.EncoderIsAssigned) + return Libs[ci.LibIndex].CreateObject(&ci.Encoder, iid, (void **)coder); + return S_OK; + #else + return E_FAIL; + #endif +} + + +STDMETHODIMP_(UInt32) CCodecs::GetNumHashers() +{ + return NUM_EXPORT_HASHERS + #ifdef EXTERNAL_CODECS + + Hashers.Size() + #endif + ; +} + +STDMETHODIMP CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + #ifdef EXPORT_CODECS + if (index < g_NumHashers) + return ::GetHasherProp(index, propID, value); + #endif + + #ifdef EXTERNAL_CODECS + const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; + return Libs[ci.LibIndex].Hashers->GetHasherProp(ci.HasherIndex, propID, value); + #else + return E_FAIL; + #endif +} + +STDMETHODIMP CCodecs::CreateHasher(UInt32 index, IHasher **hasher) +{ + #ifdef EXPORT_CODECS + if (index < g_NumHashers) + return CreateHasher(index, hasher); + #endif + #ifdef EXTERNAL_CODECS + const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; + return Libs[ci.LibIndex].Hashers->CreateHasher(ci.HasherIndex, hasher); + #else + return E_FAIL; + #endif +} + +int CCodecs::GetCodecLibIndex(UInt32 index) +{ + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + return -1; + #endif + #ifdef EXTERNAL_CODECS + const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; + return ci.LibIndex; + #else + return -1; + #endif +} + +int CCodecs::GetHasherLibIndex(UInt32 index) +{ + #ifdef EXPORT_CODECS + if (index < g_NumHashers) + return -1; + #endif + #ifdef EXTERNAL_CODECS + const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; + return ci.LibIndex; + #else + return -1; + #endif +} + +bool CCodecs::GetCodecEncoderIsAssigned(UInt32 index) +{ + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + { + 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 - NUM_EXPORT_CODECS]; + return ci.EncoderIsAssigned; + #else + return false; + #endif +} + +HRESULT CCodecs::GetCodecId(UInt32 index, UInt64 &id) +{ + 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; + NCOM::CPropVariant prop; + if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK) + if (prop.vt == VT_BSTR) + s = prop.bstrVal; + return s; +} + +UInt64 CCodecs::GetHasherId(UInt32 index) +{ + NCOM::CPropVariant prop; + RINOK(GetHasherProp(index, NMethodPropID::kID, &prop)); + if (prop.vt != VT_UI8) + return 0; + return prop.uhVal.QuadPart; +} + +UString CCodecs::GetHasherName(UInt32 index) +{ + UString s; + NCOM::CPropVariant prop; + if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK) + if (prop.vt == VT_BSTR) + s = prop.bstrVal; + return s; +} + +UInt32 CCodecs::GetHasherDigestSize(UInt32 index) +{ + NCOM::CPropVariant prop; + RINOK(GetHasherProp(index, NMethodPropID::kDigestSize, &prop)); + if (prop.vt != VT_UI4) + return 0; + return prop.ulVal; +} + +#endif // EXTERNAL_CODECS diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.h new file mode 100644 index 000000000..d254ae659 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.h @@ -0,0 +1,303 @@ +// LoadCodecs.h + +#ifndef __LOAD_CODECS_H +#define __LOAD_CODECS_H + +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyCom.h" +#include "../../../Common/MyString.h" +#include "../../../Common/ComTry.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; +}; + +struct CDllHasherInfo +{ + int LibIndex; + UInt32 HasherIndex; +}; + +#include "../../Archive/IArchive.h" + +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 +{ + UInt32 Flags; + + Func_CreateInArchive CreateInArchive; + Func_IsArc IsArcFunc; + + UString Name; + CObjectVector<CArcExtInfo> Exts; + + #ifndef _SFX + Func_CreateOutArchive CreateOutArchive; + bool UpdateEnabled; + bool NewInterface; + // UInt32 Version; + UInt32 SignatureOffset; + CObjectVector<CByteBuffer> Signatures; + #ifdef NEW_FOLDER_INTERFACE + UStringVector AssociateExts; + #endif + #endif + + #ifdef EXTERNAL_CODECS + int LibIndex; + UInt32 FormatIndex; + CLSID ClassID; + #endif + + bool Flags_KeepName() const { return (Flags & NArcInfoFlags::kKeepName) != 0; } + bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; } + + bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; } + bool Flags_NtSecure() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; } + bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; } + bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; } + + bool Flags_UseGlobalOffset() const { return (Flags & NArcInfoFlags::kUseGlobalOffset) != 0; } + bool Flags_StartOpen() const { return (Flags & NArcInfoFlags::kStartOpen) != 0; } + bool Flags_BackwardOpen() const { return (Flags & NArcInfoFlags::kBackwardOpen) != 0; } + bool Flags_PreArc() const { return (Flags & NArcInfoFlags::kPreArc) != 0; } + bool Flags_PureStartOpen() const { return (Flags & NArcInfoFlags::kPureStartOpen) != 0; } + + UString GetMainExt() const + { + if (Exts.IsEmpty()) + return UString(); + return Exts[0].Ext; + } + int FindExtension(const UString &ext) const; + + /* + 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 UString &ext, const UString &addExt); + + bool IsSplit() const { return StringsAreEqualNoCase_Ascii(Name, "Split"); } + // bool IsRar() const { return StringsAreEqualNoCase_Ascii(Name, "Rar"); } + + CArcInfoEx(): + Flags(0), + CreateInArchive(NULL), + IsArcFunc(NULL) + #ifndef _SFX + , CreateOutArchive(NULL) + , UpdateEnabled(false) + , NewInterface(false) + // , Version(0) + , SignatureOffset(0) + #endif + #ifdef EXTERNAL_CODECS + , LibIndex(-1) + #endif + {} +}; + +#ifdef EXTERNAL_CODECS + +#ifdef NEW_FOLDER_INTERFACE +struct CCodecIcons +{ + struct CIconPair + { + UString Ext; + int IconIndex; + }; + CObjectVector<CIconPair> 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; + FString Path; + Func_GetMethodProperty GetMethodProperty; + Func_CreateObject CreateObject; + CMyComPtr<IHashers> Hashers; + + #ifdef NEW_FOLDER_INTERFACE + void LoadIcons() { CCodecIcons::LoadIcons((HMODULE)Lib); } + #endif + + CCodecLib(): GetMethodProperty(NULL) {} +}; +#endif + +class CCodecs: + #ifdef EXTERNAL_CODECS + public ICompressCodecsInfo, + public IHashers, + #else + public IUnknown, + #endif + public CMyUnknownImp +{ +public: + #ifdef EXTERNAL_CODECS + CObjectVector<CCodecLib> Libs; + CRecordVector<CDllCodecInfo> Codecs; + CRecordVector<CDllHasherInfo> Hashers; + + #ifdef NEW_FOLDER_INTERFACE + CCodecIcons InternalIcons; + #endif + + HRESULT LoadCodecs(); + HRESULT LoadFormats(); + HRESULT LoadDll(const FString &path, bool needCheckDll); + HRESULT LoadDllsFromFolder(const FString &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<CArcInfoEx> Formats; + bool CaseSensitiveChange; + bool CaseSensitive; + + CCodecs(): CaseSensitiveChange(false), CaseSensitive(false) {} + + const wchar_t *GetFormatNamePtr(int formatIndex) + { + return formatIndex < 0 ? L"#" : (const wchar_t *)Formats[formatIndex].Name; + } + + 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 + + #ifdef EXTERNAL_CODECS + + MY_UNKNOWN_IMP2(ICompressCodecsInfo, IHashers) + + 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); + + STDMETHOD_(UInt32, GetNumHashers)(); + STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value); + STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher); + + #else + + MY_UNKNOWN_IMP + + #endif // EXTERNAL_CODECS + + #ifdef EXTERNAL_CODECS + + int GetCodecLibIndex(UInt32 index); + bool GetCodecEncoderIsAssigned(UInt32 index); + HRESULT GetCodecId(UInt32 index, UInt64 &id); + UString GetCodecName(UInt32 index); + + int GetHasherLibIndex(UInt32 index); + UInt64 GetHasherId(UInt32 index); + UString GetHasherName(UInt32 index); + UInt32 GetHasherDigestSize(UInt32 index); + + #endif + + HRESULT CreateInArchive(unsigned formatIndex, CMyComPtr<IInArchive> &archive) const + { + const CArcInfoEx &ai = Formats[formatIndex]; + #ifdef EXTERNAL_CODECS + if (ai.LibIndex < 0) + #endif + { + COM_TRY_BEGIN + archive = ai.CreateInArchive(); + return S_OK; + COM_TRY_END + } + #ifdef EXTERNAL_CODECS + return CreateArchiveHandler(ai, (void **)&archive, false); + #endif + } + + #ifndef _SFX + + HRESULT CreateOutArchive(unsigned formatIndex, CMyComPtr<IOutArchive> &archive) const + { + const CArcInfoEx &ai = Formats[formatIndex]; + #ifdef EXTERNAL_CODECS + if (ai.LibIndex < 0) + #endif + { + COM_TRY_BEGIN + archive = ai.CreateOutArchive(); + return S_OK; + COM_TRY_END + } + #ifdef EXTERNAL_CODECS + return CreateArchiveHandler(ai, (void **)&archive, true); + #endif + } + + int FindOutFormatFromName(const UString &name) const + { + FOR_VECTOR (i, Formats) + { + const CArcInfoEx &arc = Formats[i]; + if (!arc.UpdateEnabled) + continue; + if (arc.Name.IsEqualToNoCase(name)) + return i; + } + return -1; + } + + #endif // _SFX +}; + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/OpenArchive.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/OpenArchive.cpp new file mode 100644 index 000000000..7c53bd99f --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/OpenArchive.cpp @@ -0,0 +1,3210 @@ +// OpenArchive.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include <stdio.h> +#endif + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/StringToInt.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileDir.h" + +#include "../../Common/FileStreams.h" +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/CopyCoder.h" + +#include "DefaultName.h" +#include "OpenArchive.h" + +#ifndef _SFX +#include "SetProperties.h" +#endif + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +// increase it, if you need to support larger SFX stubs +static const UInt64 kMaxCheckStartPosition = 1 << 22; + +/* +Open: + - formatIndex >= 0 (exact Format) + 1) Open with main type. Archive handler is allowed to use archive start finder. + Warning, if there is tail. + + - formatIndex = -1 (Parser:0) (default) + - same as #1 but doesn't return Parser + + - formatIndex = -2 (#1) + - file has supported extension (like a.7z) + Open with that main type (only starting from start of file). + - open OK: + - if there is no tail - return OK + - if there is tail: + - archive is not "Self Exe" - return OK with Warning, that there is tail + - archive is "Self Exe" + ignore "Self Exe" stub, and tries to open tail + - tail can be open as archive - shows that archive and stub size property. + - tail can't be open as archive - shows Parser ??? + - open FAIL: + Try to open with all other types from offset 0 only. + If some open type is OK and physical archive size is uequal or larger + than file size, then return that archive with warning that can not be open as [extension type]. + If extension was EXE, it will try to open as unknown_extension case + - file has unknown extension (like a.hhh) + It tries to open via parser code. + - if there is full archive or tail archive and unknown block or "Self Exe" + at front, it shows tail archive and stub size property. + - in another cases, if there is some archive inside file, it returns parser/ + - in another cases, it retuens S_FALSE + + + - formatIndex = -3 (#2) + - same as #1, but + - stub (EXE) + archive is open in Parser + + - formatIndex = -4 (#3) + - returns only Parser. skip full file archive. And show other sub-archives + + - formatIndex = -5 (#4) + - returns only Parser. skip full file archive. And show other sub-archives for each byte pos + +*/ + + + + +using namespace NWindows; + +/* +#ifdef _SFX +#define OPEN_PROPS_PARAM +#else +#define OPEN_PROPS_PARAM , props +#endif +*/ + +/* +CArc::~CArc() +{ + GetRawProps.Release(); + Archive.Release(); + printf("\nCArc::~CArc()\n"); +} +*/ + +#ifndef _SFX + +namespace NArchive { +namespace NParser { + +struct CParseItem +{ + UInt64 Offset; + UInt64 Size; + // UInt64 OkSize; + UString Name; + UString Extension; + FILETIME FileTime; + UString Comment; + UString ArcType; + + bool FileTime_Defined; + bool UnpackSize_Defined; + bool NumSubDirs_Defined; + bool NumSubFiles_Defined; + + bool IsSelfExe; + bool IsNotArcType; + + UInt64 UnpackSize; + UInt64 NumSubDirs; + UInt64 NumSubFiles; + + int FormatIndex; + + bool LenIsUnknown; + + CParseItem(): + LenIsUnknown(false), + FileTime_Defined(false), + UnpackSize_Defined(false), + NumSubFiles_Defined(false), + NumSubDirs_Defined(false), + IsSelfExe(false), + IsNotArcType(false) + // OkSize(0) + {} + + /* + bool IsEqualTo(const CParseItem &item) const + { + return Offset == item.Offset && Size == item.Size; + } + */ + + void NormalizeOffset() + { + if ((Int64)Offset < 0) + { + Size += Offset; + // OkSize += Offset; + Offset = 0; + } + } +}; + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ +public: + CObjectVector<CParseItem> _items; + UInt64 _maxEndOffset; + CMyComPtr<IInStream> _stream; + + MY_UNKNOWN_IMP2( + IInArchive, + IInArchiveGetStream) + + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + + UInt64 GetLastEnd() const + { + if (_items.IsEmpty()) + return 0; + const CParseItem &back = _items.Back(); + return back.Offset + back.Size; + } + + void AddUnknownItem(UInt64 next); + int FindInsertPos(const CParseItem &item); + void AddItem(const CParseItem &item); + // void Init(); + + CHandler() + { + _maxEndOffset = 0; + } +}; + +int CHandler::FindInsertPos(const CParseItem &item) +{ + unsigned left = 0, right = _items.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + const CParseItem & midItem = _items[mid]; + if (item.Offset < midItem.Offset) + right = mid; + else if (item.Offset > midItem.Offset) + left = mid + 1; + else if (item.Size < midItem.Size) + right = mid; + else if (item.Size > midItem.Size) + left = mid + 1; + else + { + left = mid + 1; + // return -1; + } + } + return left; +} + +void CHandler::AddUnknownItem(UInt64 next) +{ + /* + UInt64 prevEnd = 0; + if (!_items.IsEmpty()) + { + const CParseItem &back = _items.Back(); + prevEnd = back.Offset + back.Size; + } + */ + if (_maxEndOffset < next) + { + CParseItem item2; + item2.Offset = _maxEndOffset; + item2.Size = next - _maxEndOffset; + _maxEndOffset = next; + _items.Add(item2); + } + else if (_maxEndOffset > next && !_items.IsEmpty()) + { + CParseItem &back = _items.Back(); + if (back.LenIsUnknown) + { + back.Size = next - back.Offset; + _maxEndOffset = next; + } + } +} + +void CHandler::AddItem(const CParseItem &item) +{ + AddUnknownItem(item.Offset); + int pos = FindInsertPos(item); + if (pos >= 0) + { + _items.Insert(pos, item); + UInt64 next = item.Offset + item.Size; + if (_maxEndOffset < next) + _maxEndOffset = next; + } +} + +/* +static const STATPROPSTG kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidSize, VT_UI8}, + { NULL, kpidMTime, VT_FILETIME}, + { NULL, kpidType, VT_BSTR}, + { NULL, kpidComment, VT_BSTR}, + { NULL, kpidOffset, VT_UI8}, + { NULL, kpidUnpackSize, VT_UI8}, +// { NULL, kpidNumSubDirs, VT_UI8}, +}; +*/ + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidMTime, + kpidType, + kpidComment, + kpidOffset, + kpidUnpackSize +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + { + Close(); + _stream = stream; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _items.Clear(); + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + const CParseItem &item = _items[index]; + + switch (propID) + { + case kpidPath: + { + wchar_t sz[32]; + ConvertUInt32ToString(index + 1, sz); + UString s = sz; + if (!item.Name.IsEmpty()) + { + s += L'.'; + s += item.Name; + } + if (!item.Extension.IsEmpty()) + { + s += L'.'; + s += item.Extension; + } + prop = s; break; + } + case kpidSize: + case kpidPackSize: prop = item.Size; break; + case kpidOffset: prop = item.Offset; break; + case kpidUnpackSize: if (item.UnpackSize_Defined) prop = item.UnpackSize; break; + case kpidNumSubFiles: if (item.NumSubFiles_Defined) prop = item.NumSubFiles; break; + case kpidNumSubDirs: if (item.NumSubDirs_Defined) prop = item.NumSubDirs; break; + case kpidMTime: if (item.FileTime_Defined) prop = item.FileTime; break; + case kpidComment: if (!item.Comment.IsEmpty()) prop = item.Comment; break; + case kpidType: if (!item.ArcType.IsEmpty()) prop = item.ArcType; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (_stream && numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _items[allFilesMode ? i : indices[i]].Size; + extractCallback->SetTotal(totalSize); + + totalSize = 0; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> inStream(streamSpec); + streamSpec->SetStream(_stream); + + CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; + CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + CMyComPtr<ISequentialOutStream> realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + const CParseItem &item = _items[index]; + + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + UInt64 unpackSize = item.Size; + totalSize += unpackSize; + bool skipMode = false; + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + + outStreamSpec->SetStream(realOutStream); + realOutStream.Release(); + outStreamSpec->Init(skipMode ? 0 : unpackSize, true); + + Int32 opRes = NExtract::NOperationResult::kOK; + RINOK(_stream->Seek(item.Offset, STREAM_SEEK_SET, NULL)); + streamSpec->Init(unpackSize); + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); + + if (outStreamSpec->GetRem() != 0) + opRes = NExtract::NOperationResult::kDataError; + outStreamSpec->ReleaseStream(); + RINOK(extractCallback->SetOperationResult(opRes)); + } + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + const CParseItem &item = _items[index]; + return CreateLimitedInStream(_stream, item.Offset, item.Size, stream); + COM_TRY_END +} + +}} + +#endif + +HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw() +{ + NCOM::CPropVariant prop; + result = false; + RINOK(arc->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 Archive_IsItem_Folder(IInArchive *arc, UInt32 index, bool &result) throw() +{ + return Archive_GetItemBoolProp(arc, index, kpidIsDir, result); +} + +HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw() +{ + return Archive_GetItemBoolProp(arc, index, kpidIsAux, result); +} + +HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw() +{ + return Archive_GetItemBoolProp(arc, index, kpidIsAltStream, result); +} + +HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &result) throw() +{ + return Archive_GetItemBoolProp(arc, index, kpidIsDeleted, result); +} + +static HRESULT Archive_GetArcBoolProp(IInArchive *arc, PROPID propid, bool &result) +{ + NCOM::CPropVariant prop; + result = false; + RINOK(arc->GetArchiveProperty(propid, &prop)); + if (prop.vt == VT_BOOL) + result = VARIANT_BOOLToBool(prop.boolVal); + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +static HRESULT Archive_GetArcProp_UInt(IInArchive *arc, PROPID propid, UInt64 &result, bool &defined) +{ + defined = false; + NCOM::CPropVariant prop; + RINOK(arc->GetArchiveProperty(propid, &prop)); + switch (prop.vt) + { + case VT_UI4: result = prop.ulVal; defined = true; break; + case VT_I4: result = prop.lVal; defined = true; break; + case VT_UI8: result = (UInt64)prop.uhVal.QuadPart; defined = true; break; + case VT_I8: result = (UInt64)prop.hVal.QuadPart; defined = true; break; + case VT_EMPTY: break; + default: return E_FAIL; + } + return S_OK; +} + +static HRESULT Archive_GetArcProp_Int(IInArchive *arc, PROPID propid, Int64 &result, bool &defined) +{ + defined = false; + NCOM::CPropVariant prop; + RINOK(arc->GetArchiveProperty(propid, &prop)); + switch (prop.vt) + { + case VT_UI4: result = prop.ulVal; defined = true; break; + case VT_I4: result = prop.lVal; defined = true; break; + case VT_UI8: result = (Int64)prop.uhVal.QuadPart; defined = true; break; + case VT_I8: result = (Int64)prop.hVal.QuadPart; defined = true; break; + case VT_EMPTY: break; + default: return E_FAIL; + } + return S_OK; +} + +HRESULT CArc::GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const +{ + if (!GetRawProps) + return E_FAIL; + UInt32 curIndex = index; + bool prevWasAltStream = false; + for (;;) + { + UString s; + + #ifdef MY_CPU_LE + const void *p; + UInt32 size; + UInt32 propType; + RINOK(GetRawProps->GetRawProp(curIndex, kpidName, &p, &size, &propType)); + if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE) + s = (const wchar_t *)p; + else + #endif + { + NCOM::CPropVariant prop; + RINOK(Archive->GetProperty(curIndex, kpidName, &prop)); + if (prop.vt == VT_BSTR) + s = prop.bstrVal; + else if (prop.vt == VT_EMPTY) + s = L"[Content]"; + else + return E_FAIL; + } + + if (prevWasAltStream) + parts[0] = s + L":" + parts[0]; + else + parts.Insert(0, s); + + UInt32 curParent = (UInt32)(Int32)-1; + UInt32 parentType = 0; + RINOK(GetRawProps->GetParent(curIndex, &curParent, &parentType)); + if (parent == curParent) + return S_OK; + if (curParent == (UInt32)(Int32)-1) + return E_FAIL; + prevWasAltStream = (parentType == NParentType::kAltStream); + curIndex = curParent; + } +} + +HRESULT CArc::GetItemPath(UInt32 index, UString &result) const +{ + #ifdef MY_CPU_LE + if (GetRawProps) + { + const void *p; + UInt32 size; + UInt32 propType; + if (!IsTree) + { + if (GetRawProps->GetRawProp(index, kpidPath, &p, &size, &propType) == S_OK && + propType == NPropDataType::kUtf16z) + { + unsigned len = size / 2 - 1; + wchar_t *s = result.GetBuffer(len); + for (unsigned i = 0; i < len; i++) + { + wchar_t c = GetUi16(p); + p = (const void *)((const Byte *)p + 2); + #if WCHAR_PATH_SEPARATOR != L'/' + if (c == L'/') + c = WCHAR_PATH_SEPARATOR; + #endif + *s++ = c; + } + result.ReleaseBuffer(len); + if (len != 0) + return S_OK; + } + } + /* + else if (GetRawProps->GetRawProp(index, kpidName, &p, &size, &propType) == S_OK && + p && propType == NPropDataType::kUtf16z) + { + UInt32 totalSize = size; + bool isOK = false; + { + UInt32 index2 = index; + for (;;) + { + UInt32 parent = (UInt32)(Int32)-1; + UInt32 parentType = 0; + if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK) + break; + if (parent == (UInt32)(Int32)-1) + { + isOK = true; + break; + } + index2 = parent; + UInt32 size2; + const void *p2; + if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK) + break; + totalSize += size2; + } + } + + if (isOK) + { + wchar_t *sz = result.GetBuffer(totalSize / 2); + UInt32 pos = totalSize - size; + memcpy((Byte *)sz + pos, p, size - 2); + UInt32 index2 = index; + for (;;) + { + UInt32 parent = (UInt32)(Int32)-1; + UInt32 parentType = 0; + if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK) + break; + if (parent == (UInt32)(Int32)-1) + break; + index2 = parent; + UInt32 size2; + const void *p2; + if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK) + break; + pos -= size2; + memcpy((Byte *)sz + pos, p2, size2); + sz[(pos + size2 - 2) / 2] = (parentType == 0) ? WCHAR_PATH_SEPARATOR : L':'; + } + result.ReleaseBuffer((totalSize - 2) / 2); + #ifdef _WIN32 + // result.Replace(L'/', WCHAR_PATH_SEPARATOR); + #endif + return S_OK; + } + } + */ + } + #endif + + { + 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::GetItemPath2(UInt32 index, UString &result) const +{ + RINOK(GetItemPath(index, result)); + if (Ask_Deleted) + { + bool isDeleted = false; + RINOK(Archive_IsItem_Deleted(Archive, index, isDeleted)); + if (isDeleted) + result.Insert(0, L"[DELETED]" WSTRING_PATH_SEPARATOR); + } + return S_OK; +} + +#ifndef _SFX + +static HRESULT Archive_GetItem_Size(IInArchive *archive, UInt32 index, UInt64 &size, bool &defined) +{ + NCOM::CPropVariant prop; + defined = false; + size = 0; + RINOK(archive->GetProperty(index, kpidSize, &prop)); + switch (prop.vt) + { + case VT_UI1: size = prop.bVal; break; + case VT_UI2: size = prop.uiVal; break; + case VT_UI4: size = prop.ulVal; break; + case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break; + case VT_EMPTY: return S_OK; + default: return E_FAIL; + } + defined = true; + return S_OK; +} + +#endif + +HRESULT CArc::GetItemSize(UInt32 index, UInt64 &size, bool &defined) const +{ + NCOM::CPropVariant prop; + defined = false; + size = 0; + RINOK(Archive->GetProperty(index, kpidSize, &prop)); + switch (prop.vt) + { + case VT_UI1: size = prop.bVal; break; + case VT_UI2: size = prop.uiVal; break; + case VT_UI4: size = prop.ulVal; break; + case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break; + case VT_EMPTY: return S_OK; + default: return E_FAIL; + } + defined = true; + 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; +} + +static void MakeCheckOrder(CCodecs *codecs, + CIntVector &orderIndices, unsigned numTypes, CIntVector &orderIndices2, + const Byte *data, size_t dataSize) +{ + for (unsigned i = 0; i < numTypes; i++) + { + int index = orderIndices[i]; + if (index < 0) + continue; + const CArcInfoEx &ai = codecs->Formats[index]; + if (ai.SignatureOffset != 0) + { + orderIndices2.Add(index); + orderIndices[i] = -1; + continue; + } + + const CObjectVector<CByteBuffer> &sigs = ai.Signatures; + FOR_VECTOR (k, sigs) + { + const CByteBuffer &sig = sigs[k]; + if (sig.Size() == 0 && dataSize == 0 || + sig.Size() != 0 && sig.Size() <= dataSize && + TestSignature(data, sig, sig.Size())) + { + orderIndices2.Add(index); + orderIndices[i] = -1; + break; + } + } + } +} + +#endif + +#ifdef UNDER_CE + static const unsigned kNumHashBytes = 1; + #define HASH_VAL(buf, pos) ((buf)[pos]) +#else + static const unsigned kNumHashBytes = 2; + #define HASH_VAL(buf, pos) ((buf)[pos] | ((UInt32)(buf)[pos + 1] << 8)) +#endif + + +#ifndef _SFX + +static bool IsExeExt(const UString &ext) +{ + return ext.IsEqualToNoCase(L"exe"); +} + +static const char *k_PreArcFormats[] = +{ + "pe" + , "elf" + , "macho" + , "mub" + , "te" +}; + +static bool IsNameFromList(const UString &s, const char *names[], size_t num) +{ + for (unsigned i = 0; i < num; i++) + if (StringsAreEqualNoCase_Ascii(s, names[i])) + return true; + return false; +} + + +static bool IsPreArcFormat(const CArcInfoEx &ai) +{ + if (ai.Flags_PreArc()) + return true; + return IsNameFromList(ai.Name, k_PreArcFormats, ARRAY_SIZE(k_PreArcFormats)); +} + +static const char *k_Formats_with_simple_signuature[] = +{ + "7z" + , "xz" + , "rar" + , "bzip2" + , "gzip" + , "cab" + , "wim" + , "rpm" + , "vhd" + , "xar" +}; + +static bool IsNewStyleSignature(const CArcInfoEx &ai) +{ + // if (ai.Version >= 0x91F) + if (ai.NewInterface) + return true; + return IsNameFromList(ai.Name, k_Formats_with_simple_signuature, ARRAY_SIZE(k_Formats_with_simple_signuature)); +} + +class CArchiveOpenCallback_Offset: + public IArchiveOpenCallback, + #ifndef _NO_CRYPTO + public ICryptoGetTextPassword, + #endif + public CMyUnknownImp +{ +public: + CMyComPtr<IArchiveOpenCallback> Callback; + UInt64 Files; + UInt64 Offset; + + #ifndef _NO_CRYPTO + CMyComPtr<ICryptoGetTextPassword> GetTextPassword; + MY_UNKNOWN_IMP2( + IArchiveOpenCallback, + ICryptoGetTextPassword) + #else + MY_UNKNOWN_IMP1(IArchiveOpenCallback) + #endif + STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes); + STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes); + #ifndef _NO_CRYPTO + STDMETHOD(CryptoGetTextPassword)(BSTR *password); + #endif +}; + +#ifndef _NO_CRYPTO +STDMETHODIMP CArchiveOpenCallback_Offset::CryptoGetTextPassword(BSTR *password) +{ + COM_TRY_BEGIN + if (GetTextPassword) + return GetTextPassword->CryptoGetTextPassword(password); + return E_NOTIMPL; + COM_TRY_END +} +#endif + +STDMETHODIMP CArchiveOpenCallback_Offset::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */) +{ + return S_OK; +} + +STDMETHODIMP CArchiveOpenCallback_Offset::SetCompleted(const UInt64 * /* files */, const UInt64 *bytes) +{ + if (!Callback) + return S_OK; + UInt64 value = Offset; + if (bytes) + value += *bytes; + return Callback->SetCompleted(&Files, &value); +} + +#endif + +UInt32 GetOpenArcErrorFlags(const NCOM::CPropVariant &prop, bool *isDefinedProp) +{ + if (isDefinedProp != NULL) + *isDefinedProp = false; + + switch (prop.vt) + { + case VT_UI8: if (isDefinedProp) *isDefinedProp = true; return (UInt32)prop.uhVal.QuadPart; + case VT_UI4: if (isDefinedProp) *isDefinedProp = true; return prop.ulVal; + case VT_EMPTY: return 0; + default: throw 151199; + } +} + +void CArcErrorInfo::ClearErrors() +{ + // ErrorFormatIndex = -1; // we don't need to clear ErrorFormatIndex here !!! + + ThereIsTail = false; + UnexpecedEnd = false; + IgnoreTail = false; + // NonZerosTail = false; + ErrorFlags_Defined = false; + ErrorFlags = 0; + WarningFlags = 0; + TailSize = 0; + + ErrorMessage.Empty(); + WarningMessage.Empty(); +} + +HRESULT CArc::ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes) +{ + // OkPhySize_Defined = false; + PhySizeDefined = false; + PhySize = 0; + Offset = 0; + AvailPhySize = FileSize - startPos; + + ErrorInfo.ClearErrors(); + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidErrorFlags, &prop)); + ErrorInfo.ErrorFlags = GetOpenArcErrorFlags(prop, &ErrorInfo.ErrorFlags_Defined); + } + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidWarningFlags, &prop)); + ErrorInfo.WarningFlags = GetOpenArcErrorFlags(prop); + } + + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidError, &prop)); + if (prop.vt != VT_EMPTY) + ErrorInfo.ErrorMessage = (prop.vt == VT_BSTR) ? prop.bstrVal : L"Unknown error"; + } + + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidWarning, &prop)); + if (prop.vt != VT_EMPTY) + ErrorInfo.WarningMessage = (prop.vt == VT_BSTR) ? prop.bstrVal : L"Unknown warning"; + } + + if (openRes == S_OK || ErrorInfo.IsArc_After_NonOpen()) + { + RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, PhySize, PhySizeDefined)); + /* + RINOK(Archive_GetArcProp_UInt(archive, kpidOkPhySize, OkPhySize, OkPhySize_Defined)); + if (!OkPhySize_Defined) + { + OkPhySize_Defined = PhySizeDefined; + OkPhySize = PhySize; + } + */ + + bool offsetDefined; + RINOK(Archive_GetArcProp_Int(archive, kpidOffset, Offset, offsetDefined)); + + Int64 globalOffset = startPos + Offset; + AvailPhySize = FileSize - globalOffset; + if (PhySizeDefined) + { + UInt64 endPos = globalOffset + PhySize; + if (endPos < FileSize) + { + AvailPhySize = PhySize; + ErrorInfo.ThereIsTail = true; + ErrorInfo.TailSize = FileSize - endPos; + } + else if (endPos > FileSize) + ErrorInfo.UnexpecedEnd = true; + } + } + + return S_OK; +} + +/* +static PrintNumber(const char *s, int n) +{ + char temp[100]; + sprintf(temp, "%s %d", s, n); + OutputDebugStringA(temp); +} +*/ + +HRESULT CArc::PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive) +{ + // OutputDebugStringW(L"a1"); + // PrintNumber("formatIndex", formatIndex); + + RINOK(op.codecs->CreateInArchive(formatIndex, archive)); + // OutputDebugStringW(L"a2"); + if (!archive) + return S_OK; + + #ifdef EXTERNAL_CODECS + { + CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; + archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); + if (setCompressCodecsInfo) + { + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(op.codecs)); + } + } + #endif + + // OutputDebugStringW(ai.Name); + // OutputDebugStringW(L"a3"); + + #ifndef _SFX + const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; + if (ai.Flags_PreArc()) + { + /* we notify parsers that extract executables, that they don't need + to open archive, if there is tail after executable (for SFX cases) */ + CMyComPtr<IArchiveAllowTail> allowTail; + archive.QueryInterface(IID_IArchiveAllowTail, (void **)&allowTail); + if (allowTail) + allowTail->AllowTail(BoolToInt(true)); + } + if (op.props) + { + /* + FOR_VECTOR (y, op.props) + { + const COptionalOpenProperties &optProps = (*op.props)[y]; + if (optProps.FormatName.IsEmpty() || optProps.FormatName.CompareNoCase(ai.Name) == 0) + { + RINOK(SetProperties(archive, optProps.Props)); + break; + } + } + */ + RINOK(SetProperties(archive, *op.props)); + } + #endif + return S_OK; +} + +#ifndef _SFX + +static HRESULT ReadParseItemProps(IInArchive *archive, const CArcInfoEx &ai, NArchive::NParser::CParseItem &pi) +{ + pi.Extension = ai.GetMainExt(); + pi.FileTime_Defined = false; + pi.ArcType = ai.Name; + + RINOK(Archive_GetArcBoolProp(archive, kpidIsNotArcType, pi.IsNotArcType)); + + // RINOK(Archive_GetArcBoolProp(archive, kpidIsSelfExe, pi.IsSelfExe)); + pi.IsSelfExe = ai.Flags_PreArc(); + + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidMTime, &prop)); + if (prop.vt == VT_FILETIME) + { + pi.FileTime_Defined = true; + pi.FileTime = prop.filetime; + } + } + + if (!pi.FileTime_Defined) + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidCTime, &prop)); + if (prop.vt == VT_FILETIME) + { + pi.FileTime_Defined = true; + pi.FileTime = prop.filetime; + } + } + + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidName, &prop)); + if (prop.vt == VT_BSTR) + { + pi.Name = prop.bstrVal; + pi.Extension.Empty(); + } + else + { + RINOK(archive->GetArchiveProperty(kpidExtension, &prop)); + if (prop.vt == VT_BSTR) + pi.Extension = prop.bstrVal; + } + } + + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidShortComment, &prop)); + if (prop.vt == VT_BSTR) + pi.Comment = prop.bstrVal; + } + + + UInt32 numItems; + RINOK(archive->GetNumberOfItems(&numItems)); + + // pi.NumSubFiles = numItems; + // RINOK(Archive_GetArcProp_UInt(archive, kpidUnpackSize, pi.UnpackSize, pi.UnpackSize_Defined)); + // if (!pi.UnpackSize_Defined) + { + pi.NumSubFiles = 0; + pi.NumSubDirs = 0; + pi.UnpackSize = 0; + for (UInt32 i = 0; i < numItems; i++) + { + UInt64 size = 0; + bool defined = false; + Archive_GetItem_Size(archive, i, size, defined); + if (defined) + { + pi.UnpackSize_Defined = true; + pi.UnpackSize += size; + } + + bool isDir = false; + Archive_IsItem_Folder(archive, i, isDir); + if (isDir) + pi.NumSubDirs++; + else + pi.NumSubFiles++; + } + if (pi.NumSubDirs != 0) + pi.NumSubDirs_Defined = true; + pi.NumSubFiles_Defined = true; + } + + return S_OK; +} + +#endif + +HRESULT CArc::CheckZerosTail(const COpenOptions &op, UInt64 offset) +{ + if (!op.stream) + return S_OK; + RINOK(op.stream->Seek(offset, STREAM_SEEK_SET, NULL)); + const UInt32 kBufSize = 1 << 11; + Byte buf[kBufSize]; + + for (;;) + { + UInt32 processed = 0; + RINOK(op.stream->Read(buf, kBufSize, &processed)); + if (processed == 0) + { + // ErrorInfo.NonZerosTail = false; + ErrorInfo.IgnoreTail = true; + return S_OK; + } + for (size_t i = 0; i < processed; i++) + { + if (buf[i] != 0) + { + // ErrorInfo.IgnoreTail = false; + // ErrorInfo.NonZerosTail = true; + return S_OK; + } + } + } +} + +#ifndef _SFX + +class CExtractCallback_To_OpenCallback: + public IArchiveExtractCallback, + public ICompressProgressInfo, + public CMyUnknownImp +{ +public: + CMyComPtr<IArchiveOpenCallback> Callback; + UInt64 Files; + UInt64 Offset; + + MY_UNKNOWN_IMP2(IArchiveExtractCallback, ICompressProgressInfo) + INTERFACE_IArchiveExtractCallback(;) + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); + void Init(IArchiveOpenCallback *callback) + { + Callback = callback; + Files = 0; + Offset = 0; + } +}; + +STDMETHODIMP CExtractCallback_To_OpenCallback::SetTotal(UInt64 /* size */) +{ + return S_OK; +} + +STDMETHODIMP CExtractCallback_To_OpenCallback::SetCompleted(const UInt64 * /* completeValue */) +{ + return S_OK; +} + +STDMETHODIMP CExtractCallback_To_OpenCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */) +{ + if (Callback) + { + UInt64 value = Offset; + if (inSize) + value += *inSize; + return Callback->SetCompleted(&Files, &value); + } + return S_OK; +} + +STDMETHODIMP CExtractCallback_To_OpenCallback::GetStream(UInt32 /* index */, ISequentialOutStream **outStream, Int32 /* askExtractMode */) +{ + *outStream = 0; + return S_OK; +} + +STDMETHODIMP CExtractCallback_To_OpenCallback::PrepareOperation(Int32 /* askExtractMode */) +{ + return S_OK; +} + +STDMETHODIMP CExtractCallback_To_OpenCallback::SetOperationResult(Int32 /* operationResult */) +{ + return S_OK; +} + +static HRESULT OpenArchiveSpec(IInArchive *archive, bool needPhySize, + IInStream *stream, const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openCallback, + IArchiveExtractCallback *extractCallback) +{ + /* + if (needPhySize) + { + CMyComPtr<IArchiveOpen2> open2; + archive->QueryInterface(IID_IArchiveOpen2, (void **)&open2); + if (open2) + return open2->ArcOpen2(stream, kOpenFlags_RealPhySize, openCallback); + } + */ + RINOK(archive->Open(stream, maxCheckStartPosition, openCallback)); + if (needPhySize) + { + bool phySize_Defined = false; + UInt64 phySize = 0; + RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, phySize, phySize_Defined)); + if (phySize_Defined) + return S_OK; + + bool phySizeCantBeDetected = false;; + RINOK(Archive_GetArcBoolProp(archive, kpidPhySizeCantBeDetected, phySizeCantBeDetected)); + + if (!phySizeCantBeDetected) + { + RINOK(archive->Extract(0, (UInt32)(Int32)-1, BoolToInt(true), extractCallback)); + } + } + return S_OK; +} + +static int FindFormatForArchiveType(CCodecs *codecs, CIntVector orderIndices, const char *name) +{ + FOR_VECTOR (i, orderIndices) + if (StringsAreEqualNoCase_Ascii(codecs->Formats[orderIndices[i]].Name, name)) + return i; + return -1; +} + +#endif + +HRESULT CArc::OpenStream2(const COpenOptions &op) +{ + // fprintf(stdout, "\nOpen: %S", Path); fflush(stdout); + + Archive.Release(); + GetRawProps.Release(); + GetRootProps.Release(); + + ErrorInfo.ClearErrors(); + ErrorInfo.ErrorFormatIndex = -1; + + IsParseArc = false; + ArcStreamOffset = 0; + + // OutputDebugStringW(L"1"); + // OutputDebugStringW(Path); + + const UString fileName = ExtractFileNameFromPath(Path); + UString extension; + { + int dotPos = fileName.ReverseFind(L'.'); + if (dotPos >= 0) + extension = fileName.Ptr(dotPos + 1); + } + + CIntVector orderIndices; + + bool searchMarkerInHandler = false; + #ifdef _SFX + searchMarkerInHandler = true; + #endif + + CBoolArr isMainFormatArr(op.codecs->Formats.Size()); + { + FOR_VECTOR(i, op.codecs->Formats) + isMainFormatArr[i] = false; + } + + UInt64 maxStartOffset = + op.openType.MaxStartOffset_Defined ? + op.openType.MaxStartOffset : + kMaxCheckStartPosition; + + #ifndef _SFX + bool isUnknownExt = false; + #endif + + bool isForced = false; + unsigned numMainTypes = 0; + int formatIndex = op.openType.FormatIndex; + + if (formatIndex >= 0) + { + isForced = true; + orderIndices.Add(formatIndex); + numMainTypes = 1; + isMainFormatArr[formatIndex] = true; + + searchMarkerInHandler = true; + } + else + { + unsigned numFinded = 0; + #ifndef _SFX + bool isPrearcExt = false; + #endif + + { + FOR_VECTOR (i, op.codecs->Formats) + { + const CArcInfoEx &ai = op.codecs->Formats[i]; + + if (IgnoreSplit || !op.openType.CanReturnArc) + if (ai.IsSplit()) + continue; + if (op.excludedFormats->FindInSorted(i) >= 0) + continue; + + #ifndef _SFX + if (IsPreArcFormat(ai)) + isPrearcExt = true; + #endif + + if (ai.FindExtension(extension) >= 0) + { + // PrintNumber("orderIndices.Insert", i); + orderIndices.Insert(numFinded++, i); + isMainFormatArr[i] = true; + } + else + orderIndices.Add(i); + } + } + + if (!op.stream) + { + if (numFinded != 1) + return E_NOTIMPL; + orderIndices.DeleteFrom(1); + } + // PrintNumber("numFinded", numFinded ); + + /* + if (op.openOnlySpecifiedByExtension) + { + if (numFinded != 0 && !IsExeExt(extension)) + orderIndices.DeleteFrom(numFinded); + } + */ + + #ifndef _SFX + + if (op.stream && orderIndices.Size() >= 2) + { + RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); + CByteBuffer byteBuffer; + CIntVector orderIndices2; + if (numFinded == 0 || IsExeExt(extension)) + { + // signature search was here + } + else if (extension == L"000" || extension == L"001") + { + int i = FindFormatForArchiveType(op.codecs, orderIndices, "rar"); + if (i >= 0) + { + const size_t kBufSize = (1 << 10); + byteBuffer.Alloc(kBufSize); + size_t processedSize = kBufSize; + RINOK(ReadStream(op.stream, byteBuffer, &processedSize)); + if (processedSize >= 16) + { + const Byte *buf = byteBuffer; + const Byte kRarHeader[] = { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }; + if (TestSignature(buf, kRarHeader, 7) && buf[9] == 0x73 && (buf[10] & 1) != 0) + { + orderIndices2.Add(orderIndices[i]); + orderIndices[i] = -1; + if (i >= (int)numFinded) + numFinded++; + } + } + } + } + else + { + const size_t kBufSize = (1 << 10); + byteBuffer.Alloc(kBufSize); + size_t processedSize = kBufSize; + RINOK(ReadStream(op.stream, byteBuffer, &processedSize)); + if (processedSize == 0) + return S_FALSE; + + /* + check type order: + 1) matched extension, no signuature + 2) matched extension, matched signuature + // 3) no signuature + // 4) matched signuature + */ + + MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, NULL, 0); + MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, byteBuffer, processedSize); + // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, NULL, 0); + // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, byteBuffer, processedSize); + } + + FOR_VECTOR (i, orderIndices) + { + int val = orderIndices[i]; + if (val != -1) + orderIndices2.Add(val); + } + orderIndices = orderIndices2; + } + + if (orderIndices.Size() >= 2) + { + int iIso = FindFormatForArchiveType(op.codecs, orderIndices, "iso"); + int iUdf = FindFormatForArchiveType(op.codecs, orderIndices, "udf"); + if (iUdf > iIso && iIso >= 0) + { + int isoIndex = orderIndices[iIso]; + int udfIndex = orderIndices[iUdf]; + orderIndices[iUdf] = isoIndex; + orderIndices[iIso] = udfIndex; + } + } + + numMainTypes = numFinded; + isUnknownExt = (numMainTypes == 0) || isPrearcExt; + + #else // _SFX + + numMainTypes = orderIndices.Size(); + + #endif + } + + UInt64 fileSize = 0; + if (op.stream) + { + RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize)); + RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); + } + FileSize = fileSize; + + + #ifndef _SFX + + CBoolArr skipFrontalFormat(op.codecs->Formats.Size()); + { + FOR_VECTOR(i, op.codecs->Formats) + skipFrontalFormat[i] = false; + } + + #endif + + const COpenType &mode = op.openType; + + + + + + if (mode.CanReturnArc) + { + // ---------- OPEN main type by extenssion ---------- + + unsigned numCheckTypes = orderIndices.Size(); + if (formatIndex >= 0) + numCheckTypes = numMainTypes; + + for (unsigned i = 0; i < numCheckTypes; i++) + { + FormatIndex = orderIndices[i]; + const CArcInfoEx &ai = op.codecs->Formats[FormatIndex]; + // OutputDebugStringW(ai.Name); + + bool exactOnly = false; + if (i >= numMainTypes) + { + if (!ai.Flags_BackwardOpen() + // && !ai.Flags_PureStartOpen() + ) + continue; + exactOnly = true; + } + + // Some handlers do not set total bytes. So we set it here + RINOK(op.callback->SetTotal(NULL, &fileSize)); + if (op.stream) + { + RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); + } + + CMyComPtr<IInArchive> archive; + + RINOK(PrepareToOpen(op, FormatIndex, archive)); + if (!archive) + continue; + + HRESULT result; + if (op.stream) + { + UInt64 searchLimit = (!exactOnly && searchMarkerInHandler) ? maxStartOffset: 0; + result = archive->Open(op.stream, &searchLimit, op.callback); + } + else + { + CMyComPtr<IArchiveOpenSeq> openSeq; + archive.QueryInterface(IID_IArchiveOpenSeq, (void **)&openSeq); + if (!openSeq) + return E_NOTIMPL; + result = openSeq->OpenSeq(op.seqStream); + } + + RINOK(ReadBasicProps(archive, 0, result)); + + if (result == S_FALSE) + { + bool isArc = ErrorInfo.IsArc_After_NonOpen(); + + #ifndef _SFX + // if it's archive, we allow another open attempt for parser + if (!mode.CanReturnParser || !isArc) + skipFrontalFormat[FormatIndex] = true; + #endif + + if (exactOnly) + continue; + + if (i == 0 && numMainTypes == 1) + { + // we set NonOpenErrorInfo, only if there is only one main format (defined by extension). + ErrorInfo.ErrorFormatIndex = FormatIndex; + NonOpen_ErrorInfo = ErrorInfo; + + if (!mode.CanReturnParser && isArc) + { + // if (formatIndex < 0 && !searchMarkerInHandler) + { + // if bad archive was detected, we don't need additional open attempts + #ifndef _SFX + if (!IsPreArcFormat(ai) /* || !mode.SkipSfxStub */) + #endif + return S_FALSE; + } + } + } + + /* + #ifndef _SFX + if (IsExeExt(extension) || ai.Flags_PreArc()) + { + // openOnlyFullArc = false; + // canReturnTailArc = true; + // limitSignatureSearch = true; + } + #endif + */ + + continue; + } + + RINOK(result); + + #ifndef _SFX + + bool isMainFormat = isMainFormatArr[FormatIndex]; + const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); + + bool thereIsTail = ErrorInfo.ThereIsTail; + if (thereIsTail && mode.ZerosTailIsAllowed) + { + RINOK(CheckZerosTail(op, Offset + PhySize)); + if (ErrorInfo.IgnoreTail) + thereIsTail = false; + } + + if (Offset > 0) + { + if (exactOnly + || !searchMarkerInHandler + || !specFlags.CanReturn_NonStart() + || (mode.MaxStartOffset_Defined && (UInt64)Offset > mode.MaxStartOffset)) + continue; + } + if (thereIsTail) + { + if (Offset > 0) + { + if (!specFlags.CanReturnMid) + continue; + } + else if (!specFlags.CanReturnFrontal) + continue; + } + + if (Offset > 0 || thereIsTail) + { + if (formatIndex < 0) + { + if (IsPreArcFormat(ai)) + { + // openOnlyFullArc = false; + // canReturnTailArc = true; + /* + if (mode.SkipSfxStub) + limitSignatureSearch = true; + */ + // if (mode.SkipSfxStub) + { + // skipFrontalFormat[FormatIndex] = true; + continue; + } + } + } + } + + #endif + + Archive = archive; + return S_OK; + } + } + + + + #ifndef _SFX + + if (!op.stream) + return S_FALSE; + + if (formatIndex >= 0 && !mode.CanReturnParser) + { + if (mode.MaxStartOffset_Defined) + { + if (mode.MaxStartOffset == 0) + return S_FALSE; + } + else + { + const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; + if (ai.FindExtension(extension) >= 0) + { + const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; + if (ai.Flags_FindSignature() && searchMarkerInHandler) + return S_FALSE; + } + } + } + + NArchive::NParser::CHandler *handlerSpec = new NArchive::NParser::CHandler; + CMyComPtr<IInArchive> handler = handlerSpec; + + CExtractCallback_To_OpenCallback *extractCallback_To_OpenCallback_Spec = new CExtractCallback_To_OpenCallback; + CMyComPtr<IArchiveExtractCallback> extractCallback_To_OpenCallback = extractCallback_To_OpenCallback_Spec; + extractCallback_To_OpenCallback_Spec->Init(op.callback); + + { + // ---------- Check all possible START archives ---------- + // this code is better for full file archives than Parser's code. + + CByteBuffer byteBuffer; + bool endOfFile = false; + size_t processedSize; + { + size_t bufSize = 1 << 20; // it must be larger than max signature offset or IsArcFunc offset ((1 << 19) + x for UDF) + if (bufSize > fileSize) + { + bufSize = (size_t)fileSize; + endOfFile = true; + } + byteBuffer.Alloc(bufSize); + RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); + processedSize = bufSize; + RINOK(ReadStream(op.stream, byteBuffer, &processedSize)); + if (processedSize == 0) + return S_FALSE; + if (processedSize < bufSize) + endOfFile = true; + } + CUIntVector sortedFormats; + + unsigned i; + + int splitIndex = -1; + + for (i = 0; i < orderIndices.Size(); i++) + { + unsigned form = orderIndices[i]; + if (skipFrontalFormat[form]) + continue; + const CArcInfoEx &ai = op.codecs->Formats[form]; + if (ai.IsSplit()) + { + splitIndex = form; + continue; + } + + if (ai.IsArcFunc) + { + UInt32 isArcRes = ai.IsArcFunc(byteBuffer, processedSize); + if (isArcRes == k_IsArc_Res_NO) + continue; + if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile) + continue; + // if (isArcRes == k_IsArc_Res_YES_LOW_PROB) continue; + sortedFormats.Insert(0, form); + continue; + } + + bool isNewStyleSignature = IsNewStyleSignature(ai); + bool needCheck = !isNewStyleSignature + || ai.Signatures.IsEmpty() + || ai.Flags_PureStartOpen() + || ai.Flags_StartOpen() + || ai.Flags_BackwardOpen(); + + if (isNewStyleSignature && !ai.Signatures.IsEmpty()) + { + unsigned k; + for (k = 0; k < ai.Signatures.Size(); k++) + { + const CByteBuffer &sig = ai.Signatures[k]; + UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size(); + if (processedSize < signatureEnd) + { + if (!endOfFile) + needCheck = true; + } + else if (memcmp(sig, byteBuffer + ai.SignatureOffset, sig.Size()) == 0) + break; + } + if (k != ai.Signatures.Size()) + { + sortedFormats.Insert(0, form); + continue; + } + } + if (needCheck) + sortedFormats.Add(form); + } + + if (splitIndex >= 0) + sortedFormats.Insert(0, splitIndex); + + for (i = 0; i < sortedFormats.Size(); i++) + { + FormatIndex = sortedFormats[i]; + const CArcInfoEx &ai = op.codecs->Formats[FormatIndex]; + + RINOK(op.callback->SetTotal(NULL, &fileSize)); + RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); + + CMyComPtr<IInArchive> archive; + RINOK(PrepareToOpen(op, FormatIndex, archive)); + if (!archive) + continue; + + PRF(printf("\nSorted Open %S", (const wchar_t *)ai.Name)); + HRESULT result; + { + UInt64 searchLimit = 0; + /* + if (mode.CanReturnArc) + result = archive->Open(op.stream, &searchLimit, op.callback); + else + */ + result = OpenArchiveSpec(archive, !mode.CanReturnArc, op.stream, &searchLimit, op.callback, extractCallback_To_OpenCallback); + } + + if (result == S_FALSE) + { + skipFrontalFormat[FormatIndex] = true; + // FIXME: maybe we must use LenIsUnknown. + // printf(" OpenForSize Error"); + continue; + } + RINOK(result); + + RINOK(ReadBasicProps(archive, 0, result)); + + if (Offset > 0) + { + continue; // good handler doesn't return such Offset > 0 + // but there are some cases like false prefixed PK00 archive, when + // we can support it? + } + + NArchive::NParser::CParseItem pi; + pi.Offset = Offset; + pi.Size = AvailPhySize; + + // bool needScan = false; + + if (!PhySizeDefined) + { + // it's for Z format + pi.LenIsUnknown = true; + // needScan = true; + // phySize = arcRem; + // nextNeedCheckStartOpen = false; + } + + /* + if (OkPhySize_Defined) + pi.OkSize = pi.OkPhySize; + else + pi.OkSize = pi.Size; + */ + + pi.NormalizeOffset(); + // printf(" phySize = %8d", (unsigned)phySize); + + + if (mode.CanReturnArc) + { + bool isMainFormat = isMainFormatArr[FormatIndex]; + const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); + bool openCur = false; + + if (!ErrorInfo.ThereIsTail) + openCur = true; + else + { + if (mode.ZerosTailIsAllowed) + { + RINOK(CheckZerosTail(op, Offset + PhySize)); + if (ErrorInfo.IgnoreTail) + openCur = true; + } + if (!openCur) + { + openCur = specFlags.CanReturnFrontal; + if (formatIndex < 0) // format is not forced + { + if (IsPreArcFormat(ai)) + { + // if (mode.SkipSfxStub) + { + openCur = false; + } + } + } + } + } + + if (openCur) + { + InStream = op.stream; + Archive = archive; + return S_OK; + } + } + + skipFrontalFormat[FormatIndex] = true; + + + // if (!mode.CanReturnArc) + /* + if (!ErrorInfo.ThereIsTail) + continue; + */ + if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize) + continue; + + // printf("\nAdd offset = %d", (int)pi.Offset); + RINOK(ReadParseItemProps(archive, ai, pi)); + handlerSpec->AddItem(pi); + } + } + + + + + + // ---------- PARSER ---------- + + CUIntVector arc2sig; // formatIndex to signatureIndex + CUIntVector sig2arc; // signatureIndex to formatIndex; + { + unsigned sum = 0; + FOR_VECTOR (i, op.codecs->Formats) + { + arc2sig.Add(sum); + const CObjectVector<CByteBuffer> &sigs = op.codecs->Formats[i].Signatures; + sum += sigs.Size(); + FOR_VECTOR (k, sigs) + sig2arc.Add(i); + } + } + + { + CArchiveOpenCallback_Offset *openCallback_Offset_Spec = new CArchiveOpenCallback_Offset; + CMyComPtr<IArchiveOpenCallback> openCallback_Offset = openCallback_Offset_Spec; + + const size_t kBeforeSize = 1 << 16; + const size_t kAfterSize = 1 << 20; + const size_t kBufSize = 1 << 22; // it must be more than kBeforeSize + kAfterSize + + const UInt32 kNumVals = (UInt32)1 << (kNumHashBytes * 8); + CByteArr hashBuffer(kNumVals); + Byte *hash = hashBuffer; + memset(hash, 0xFF, kNumVals); + Byte prevs[256]; + memset(prevs, 0xFF, sizeof(prevs)); + if (sig2arc.Size() >= 0xFF) + return S_FALSE; + + CUIntVector difficultFormats; + CBoolArr difficultBools(256); + { + for (unsigned i = 0; i < 256; i++) + difficultBools[i] = false; + } + + bool thereAreHandlersForSearch = false; + + // UInt32 maxSignatureEnd = 0; + + FOR_VECTOR (i, orderIndices) + { + int index = orderIndices[i]; + if (index < 0) + continue; + const CArcInfoEx &ai = op.codecs->Formats[index]; + bool isDifficult = false; + // if (ai.Version < 0x91F) // we don't use parser with old DLL (before 9.31) + if (!ai.NewInterface) + isDifficult = true; + else + { + if (ai.Flags_StartOpen()) + isDifficult = true; + FOR_VECTOR (k, ai.Signatures) + { + const CByteBuffer &sig = ai.Signatures[k]; + /* + UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size(); + if (maxSignatureEnd < signatureEnd) + maxSignatureEnd = signatureEnd; + */ + if (sig.Size() < kNumHashBytes) + { + isDifficult = true; + continue; + } + thereAreHandlersForSearch = true; + UInt32 v = HASH_VAL(sig, 0); + unsigned sigIndex = arc2sig[index] + k; + prevs[sigIndex] = hash[v]; + hash[v] = (Byte)sigIndex; + } + } + if (isDifficult) + { + difficultFormats.Add(index); + difficultBools[index] = true; + } + } + + if (!thereAreHandlersForSearch) + { + // openOnlyFullArc = true; + // canReturnTailArc = true; + } + + RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); + + CLimitedCachedInStream *limitedStreamSpec = new CLimitedCachedInStream; + CMyComPtr<IInStream> limitedStream = limitedStreamSpec; + limitedStreamSpec->SetStream(op.stream); + + openCallback_Offset_Spec->Callback = op.callback; + + #ifndef _NO_CRYPTO + if (op.callback) + { + openCallback_Offset_Spec->Callback.QueryInterface(IID_ICryptoGetTextPassword, &openCallback_Offset_Spec->GetTextPassword); + } + #endif + + RINOK(op.callback->SetTotal(NULL, &fileSize)); + CByteBuffer &byteBuffer = limitedStreamSpec->Buffer; + byteBuffer.Alloc(kBufSize); + + UInt64 callbackPrev = 0; + bool needCheckStartOpen = true; // = true, if we need to test all archives types for current pos. + + bool endOfFile = false; + UInt64 bufPhyPos = 0; + size_t bytesInBuf = 0; + // UInt64 prevPos = 0; + + // ---------- Main Scan Loop ---------- + + UInt64 pos = 0; + + if (!mode.EachPos && handlerSpec->_items.Size() == 1) + { + NArchive::NParser::CParseItem &pi = handlerSpec->_items[0]; + if (!pi.LenIsUnknown && pi.Offset == 0) + pos = pi.Size; + } + + for (;;) + { + // printf("\nPos = %d", (int)pos); + UInt64 posInBuf = pos - bufPhyPos; + + // if (pos > ((UInt64)1 << 35)) break; + + if (!endOfFile) + { + if (bytesInBuf < kBufSize) + { + size_t processedSize = kBufSize - bytesInBuf; + // printf("\nRead ask = %d", (unsigned)processedSize); + UInt64 seekPos = bufPhyPos + bytesInBuf; + RINOK(op.stream->Seek(bufPhyPos + bytesInBuf, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream(op.stream, byteBuffer + bytesInBuf, &processedSize)); + // printf(" processed = %d", (unsigned)processedSize); + if (processedSize == 0) + { + fileSize = seekPos; + endOfFile = true; + } + else + { + bytesInBuf += processedSize; + limitedStreamSpec->SetCache(processedSize, (size_t)bufPhyPos); + } + continue; + } + + if (bytesInBuf < posInBuf) + { + UInt64 skipSize = posInBuf - bytesInBuf; + if (skipSize <= kBeforeSize) + { + size_t keepSize = (size_t)(kBeforeSize - skipSize); + // printf("\nmemmove skip = %d", (int)keepSize); + memmove(byteBuffer, byteBuffer + bytesInBuf - keepSize, keepSize); + bytesInBuf = keepSize; + bufPhyPos = pos - keepSize; + continue; + } + // printf("\nSkip %d", (int)(skipSize - kBeforeSize)); + // RINOK(op.stream->Seek(skipSize - kBeforeSize, STREAM_SEEK_CUR, NULL)); + bytesInBuf = 0; + bufPhyPos = pos - kBeforeSize; + continue; + } + + if (bytesInBuf - posInBuf < kAfterSize) + { + size_t beg = (size_t)posInBuf - kBeforeSize; + // printf("\nmemmove for after beg = %d", (int)beg); + memmove(byteBuffer, byteBuffer + beg, bytesInBuf - beg); + bufPhyPos += beg; + bytesInBuf -= beg; + continue; + } + } + + if (pos >= callbackPrev + (1 << 23)) + { + openCallback_Offset_Spec->Files = handlerSpec->_items.Size(); + openCallback_Offset_Spec->Offset = pos; + RINOK(openCallback_Offset->SetCompleted(NULL, NULL)); + callbackPrev = pos; + } + + { + UInt64 endPos = bufPhyPos + bytesInBuf; + if (fileSize < endPos) + { + FileSize = fileSize; // why ???? + fileSize = endPos; + } + } + + size_t availSize = bytesInBuf - (size_t)posInBuf; + if (availSize < kNumHashBytes) + break; + size_t scanSize = availSize - + ((availSize >= kAfterSize) ? kAfterSize : kNumHashBytes); + + { + /* + UInt64 scanLimit = openOnlyFullArc ? + maxSignatureEnd : + op.openType.ScanSize + maxSignatureEnd; + */ + if (!mode.CanReturnParser) + { + if (pos > maxStartOffset) + break; + UInt64 remScan = maxStartOffset - pos; + if (scanSize > remScan) + scanSize = (size_t)remScan; + } + } + + scanSize++; + + const Byte *buf = byteBuffer + (size_t)posInBuf; + size_t ppp = 0; + + if (!needCheckStartOpen) + { + for (; ppp < scanSize && hash[HASH_VAL(buf, ppp)] == 0xFF; ppp++); + pos += ppp; + if (ppp == scanSize) + continue; + } + + UInt32 v = HASH_VAL(buf, ppp); + bool nextNeedCheckStartOpen = true; + unsigned i = hash[v]; + unsigned indexOfDifficult = 0; + + // ---------- Open Loop for Current Pos ---------- + bool wasOpen = false; + + for (;;) + { + unsigned index; + bool isDifficult; + if (needCheckStartOpen && indexOfDifficult < difficultFormats.Size()) + { + index = difficultFormats[indexOfDifficult++]; + isDifficult = true; + } + else + { + if (i == 0xFF) + break; + index = sig2arc[i]; + unsigned sigIndex = i - arc2sig[index]; + i = prevs[i]; + if (needCheckStartOpen && difficultBools[index]) + continue; + const CArcInfoEx &ai = op.codecs->Formats[index]; + + if (pos < ai.SignatureOffset) + continue; + + /* + if (openOnlyFullArc) + if (pos != ai.SignatureOffset) + continue; + */ + + const CByteBuffer &sig = ai.Signatures[sigIndex]; + + if (ppp + sig.Size() > availSize + || !TestSignature(buf + ppp, sig, sig.Size())) + continue; + // printf("\nSignature OK: %10S %8x %5d", (const wchar_t *)ai.Name, (int)pos, (int)(pos - prevPos)); + // prevPos = pos; + isDifficult = false; + } + + const CArcInfoEx &ai = op.codecs->Formats[index]; + + + if ((isDifficult && pos == 0) || ai.SignatureOffset == pos) + { + // we don't check same archive second time */ + if (skipFrontalFormat[index]) + continue; + } + + UInt64 startArcPos = pos; + if (!isDifficult) + { + if (pos < ai.SignatureOffset) + continue; + startArcPos = pos - ai.SignatureOffset; + /* + // we don't need the check for Z files + if (startArcPos < handlerSpec->GetLastEnd()) + continue; + */ + } + + if (ai.IsArcFunc && startArcPos >= bufPhyPos) + { + size_t offsetInBuf = (size_t)(startArcPos - bufPhyPos); + if (offsetInBuf < bytesInBuf) + { + UInt32 isArcRes = ai.IsArcFunc(byteBuffer + offsetInBuf, bytesInBuf - offsetInBuf); + if (isArcRes == k_IsArc_Res_NO) + continue; + if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile) + continue; + /* + if (isArcRes == k_IsArc_Res_YES_LOW_PROB) + { + // if (pos != ai.SignatureOffset) + continue; + } + */ + } + // printf("\nIsArc OK: %S", (const wchar_t *)ai.Name); + } + + /* + if (pos == 67109888) + pos = pos; + */ + PRF(printf("\npos = %9I64d : %S", pos, (const wchar_t *)ai.Name)); + + bool isMainFormat = isMainFormatArr[index]; + const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); + + CMyComPtr<IInArchive> archive; + RINOK(PrepareToOpen(op, index, archive)); + if (!archive) + return E_FAIL; + + // OutputDebugStringW(ai.Name); + + UInt64 rem = fileSize - startArcPos; + + UInt64 arcStreamOffset = 0; + + if (ai.Flags_UseGlobalOffset()) + { + limitedStreamSpec->InitAndSeek(0, fileSize); + limitedStream->Seek(startArcPos, STREAM_SEEK_SET, NULL); + } + else + { + limitedStreamSpec->InitAndSeek(startArcPos, rem); + arcStreamOffset = startArcPos; + } + + UInt64 maxCheckStartPosition = 0; + openCallback_Offset_Spec->Files = handlerSpec->_items.Size(); + openCallback_Offset_Spec->Offset = startArcPos; + // HRESULT result = archive->Open(limitedStream, &maxCheckStartPosition, openCallback_Offset); + extractCallback_To_OpenCallback_Spec->Files = 0; + extractCallback_To_OpenCallback_Spec->Offset = startArcPos; + + HRESULT result = OpenArchiveSpec(archive, true, limitedStream, &maxCheckStartPosition, openCallback_Offset, extractCallback_To_OpenCallback); + + RINOK(ReadBasicProps(archive, ai.Flags_UseGlobalOffset() ? 0 : startArcPos, result)); + + bool isOpen = false; + if (result == S_FALSE) + { + if (!mode.CanReturnParser) + { + if (formatIndex < 0 && ErrorInfo.IsArc_After_NonOpen()) + { + ErrorInfo.ErrorFormatIndex = index; + NonOpen_ErrorInfo = ErrorInfo; + // if archive was detected, we don't need additional open attempts + return S_FALSE; + } + continue; + } + if (!ErrorInfo.IsArc_After_NonOpen() || !PhySizeDefined || PhySize == 0) + continue; + } + else + { + isOpen = true; + RINOK(result); + PRF(printf(" OK ")); + } + + // fprintf(stderr, "\n %8X %S", startArcPos, Path); + // printf("\nOpen OK: %S", ai.Name); + + + NArchive::NParser::CParseItem pi; + pi.Offset = startArcPos; + + if (ai.Flags_UseGlobalOffset()) + pi.Offset = Offset; + else if (Offset != 0) + return E_FAIL; + UInt64 arcRem = FileSize - pi.Offset; + UInt64 phySize = arcRem; + bool phySizeDefined = PhySizeDefined; + if (phySizeDefined) + { + if (pi.Offset + PhySize > FileSize) + { + // ErrorInfo.ThereIsTail = true; + PhySize = FileSize - pi.Offset; + } + phySize = PhySize; + } + if (phySize == 0 || (UInt64)phySize > ((UInt64)1 << 63)) + return E_FAIL; + + /* + if (!ai.UseGlobalOffset) + { + if (phySize > arcRem) + { + ThereIsTail = true; + phySize = arcRem; + } + } + */ + + bool needScan = false; + + + if (isOpen && !phySizeDefined) + { + // it's for Z format + pi.LenIsUnknown = true; + needScan = true; + phySize = arcRem; + nextNeedCheckStartOpen = false; + } + + pi.Size = phySize; + /* + if (OkPhySize_Defined) + pi.OkSize = OkPhySize; + */ + pi.NormalizeOffset(); + // printf(" phySize = %8d", (unsigned)phySize); + + /* + if (needSkipFullArc) + if (pi.Offset == 0 && phySizeDefined && pi.Size >= fileSize) + continue; + */ + if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize) + { + // it's possible for dmg archives + if (!mode.CanReturnArc) + continue; + } + + if (mode.EachPos) + pos++; + else if (needScan) + { + pos++; + /* + if (!OkPhySize_Defined) + pos++; + else + pos = pi.Offset + pi.OkSize; + */ + } + else + pos = pi.Offset + pi.Size; + + + RINOK(ReadParseItemProps(archive, ai, pi)); + + if (pi.Offset < startArcPos && !mode.EachPos /* && phySizeDefined */) + { + /* It's for DMG format. + This code deletes all previous items that are included to current item */ + + while (!handlerSpec->_items.IsEmpty()) + { + { + const NArchive::NParser::CParseItem &back = handlerSpec->_items.Back(); + if (back.Offset < pi.Offset) + break; + if (back.Offset + back.Size > pi.Offset + pi.Size) + break; + } + handlerSpec->_items.DeleteBack(); + } + } + + + if (isOpen && mode.CanReturnArc && phySizeDefined) + { + // if (pi.Offset + pi.Size >= fileSize) + bool openCur = false; + + bool thereIsTail = ErrorInfo.ThereIsTail; + if (thereIsTail && mode.ZerosTailIsAllowed) + { + RINOK(CheckZerosTail(op, arcStreamOffset + Offset + PhySize)); + if (ErrorInfo.IgnoreTail) + thereIsTail = false; + } + + if (pi.Offset != 0) + { + if (!pi.IsNotArcType) + if (thereIsTail) + openCur = specFlags.CanReturnMid; + else + openCur = specFlags.CanReturnTail; + } + else + { + if (!thereIsTail) + openCur = true; + else + openCur = specFlags.CanReturnFrontal; + + + if (formatIndex >= -2) + openCur = true; + } + if (formatIndex < 0 && pi.IsSelfExe /* && mode.SkipSfxStub */) + openCur = false; + + // We open file as SFX, if there is front archive or first archive is "Self Executable" + if (!openCur && !pi.IsSelfExe && !thereIsTail && + (!pi.IsNotArcType || pi.Offset == 0)) + { + if (handlerSpec->_items.IsEmpty()) + { + if (specFlags.CanReturnTail) + openCur = true; + } + else if (handlerSpec->_items.Size() == 1) + { + if (handlerSpec->_items[0].IsSelfExe) + { + if (mode.SpecUnknownExt.CanReturnTail) + openCur = true; + } + } + } + + if (openCur) + { + InStream = op.stream; + Archive = archive; + FormatIndex = index; + ArcStreamOffset = arcStreamOffset; + return S_OK; + } + } + + /* + if (openOnlyFullArc) + { + ErrorInfo.ClearErrors(); + return S_FALSE; + } + */ + + pi.FormatIndex = index; + + // printf("\nAdd offset = %d", (int)pi.Offset); + handlerSpec->AddItem(pi); + wasOpen = true; + break; + } + // ---------- End of Open Loop for Current Pos ---------- + + if (!wasOpen) + pos++; + needCheckStartOpen = (nextNeedCheckStartOpen && wasOpen); + } + // ---------- End of Main Scan Loop ---------- + + /* + if (handlerSpec->_items.Size() == 1) + { + const NArchive::NParser::CParseItem &pi = handlerSpec->_items[0]; + if (pi.Size == fileSize && pi.Offset == 0) + { + Archive = archive; + FormatIndex2 = pi.FormatIndex; + return S_OK; + } + } + */ + + if (mode.CanReturnParser) + { + bool returnParser = (handlerSpec->_items.Size() == 1); // it's possible if fileSize was not correct at start of parsing + handlerSpec->AddUnknownItem(fileSize); + if (handlerSpec->_items.Size() == 0) + return S_FALSE; + if (returnParser || handlerSpec->_items.Size() != 1) + { + // return S_FALSE; + handlerSpec->_stream = op.stream; + Archive = handler; + ErrorInfo.ClearErrors(); + IsParseArc = true; + FormatIndex = -1; // It's parser + Offset = 0; + return S_OK; + } + } + } + + #endif + + if (!Archive) + return S_FALSE; + return S_OK; +} + +HRESULT CArc::OpenStream(const COpenOptions &op) +{ + RINOK(OpenStream2(op)); + // PrintNumber("op.formatIndex 3", op.formatIndex); + + if (Archive) + { + GetRawProps.Release(); + GetRootProps.Release(); + Archive->QueryInterface(IID_IArchiveGetRawProps, (void **)&GetRawProps); + Archive->QueryInterface(IID_IArchiveGetRootProps, (void **)&GetRootProps); + + RINOK(Archive_GetArcBoolProp(Archive, kpidIsTree, IsTree)); + RINOK(Archive_GetArcBoolProp(Archive, kpidIsDeleted, Ask_Deleted)); + RINOK(Archive_GetArcBoolProp(Archive, kpidIsAltStream, Ask_AltStream)); + RINOK(Archive_GetArcBoolProp(Archive, kpidIsAux, Ask_Aux)); + RINOK(Archive_GetArcBoolProp(Archive, kpidINode, Ask_INode)); + + const UString fileName = ExtractFileNameFromPath(Path); + UString extension; + { + int dotPos = fileName.ReverseFind(L'.'); + if (dotPos >= 0) + extension = fileName.Ptr(dotPos + 1); + } + + DefaultName.Empty(); + if (FormatIndex >= 0) + { + const CArcInfoEx &ai = op.codecs->Formats[FormatIndex]; + if (ai.Exts.Size() == 0) + DefaultName = GetDefaultName2(fileName, L"", L""); + else + { + int subExtIndex = ai.FindExtension(extension); + if (subExtIndex < 0) + subExtIndex = 0; + const CArcExtInfo &extInfo = ai.Exts[subExtIndex]; + DefaultName = GetDefaultName2(fileName, extInfo.Ext, extInfo.AddExt); + } + } + } + + return S_OK; +} + +#ifdef _SFX + +#ifdef _WIN32 + static const wchar_t *k_ExeExt = L".exe"; + static const unsigned k_ExeExt_Len = 4; +#else + static const wchar_t *k_ExeExt = L""; + static const unsigned k_ExeExt_Len = 0; +#endif + +#endif + +HRESULT CArc::OpenStreamOrFile(COpenOptions &op) +{ + CMyComPtr<IInStream> fileStream; + CMyComPtr<ISequentialInStream> seqStream; + CInFileStream *fileStreamSpec = NULL; + if (op.stdInMode) + { + seqStream = new CStdInFileStream; + op.seqStream = seqStream; + } + else if (!op.stream) + { + fileStreamSpec = new CInFileStream(true); + fileStream = fileStreamSpec; + Path = filePath; + if (!fileStreamSpec->Open(us2fs(Path))) + { + return GetLastError(); + } + op.stream = fileStream; + #ifdef _SFX + IgnoreSplit = true; + #endif + } + + /* + if (callback) + { + UInt64 fileSize; + RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize)); + RINOK(op.callback->SetTotal(NULL, &fileSize)) + } + */ + + HRESULT res = OpenStream(op); + IgnoreSplit = false; + + #ifdef _SFX + + if (res != S_FALSE + || !fileStreamSpec + || !op.callbackSpec + || NonOpen_ErrorInfo.IsArc_After_NonOpen()) + return res; + { + if (filePath.Len() > k_ExeExt_Len + && MyStringCompareNoCase(filePath.RightPtr(k_ExeExt_Len), k_ExeExt) == 0) + { + const UString path2 = filePath.Left(filePath.Len() - k_ExeExt_Len); + FOR_VECTOR (i, op.codecs->Formats) + { + const CArcInfoEx &ai = op.codecs->Formats[i]; + if (ai.IsSplit()) + continue; + UString path3 = path2; + path3 += L"."; + path3 += ai.GetMainExt(); // "7z" for SFX. + Path = path3 + L".001"; + bool isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path)); + if (!isOk) + { + Path = path3; + isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path)); + } + if (isOk) + { + if (fileStreamSpec->Open(us2fs(Path))) + { + op.stream = fileStream; + NonOpen_ErrorInfo.ClearErrors_Full(); + if (OpenStream(op) == S_OK) + return S_OK; + } + } + } + } + } + + #endif + + return res; +} + +void CArchiveLink::KeepModeForNextOpen() +{ + for (int i = Arcs.Size() - 1; i >= 0; i--) + { + CMyComPtr<IArchiveKeepModeForNextOpen> keep; + Arcs[i].Archive->QueryInterface(IID_IArchiveKeepModeForNextOpen, (void **)&keep); + if (keep) + keep->KeepModeForNextOpen(); + } +} + +HRESULT CArchiveLink::Close() +{ + for (int i = Arcs.Size() - 1; i >= 0; i--) + { + RINOK(Arcs[i].Close()); + } + IsOpen = false; + // ErrorsText.Empty(); + return S_OK; +} + +void CArchiveLink::Release() +{ + // NonOpenErrorFormatIndex = -1; + NonOpen_ErrorInfo.ClearErrors(); + NonOpen_ArcPath.Empty(); + while (!Arcs.IsEmpty()) + Arcs.DeleteBack(); +} + +/* +void CArchiveLink::Set_ErrorsText() +{ + FOR_VECTOR(i, Arcs) + { + const CArc &arc = Arcs[i]; + if (!arc.ErrorFlagsText.IsEmpty()) + { + if (!ErrorsText.IsEmpty()) + ErrorsText += L'\n'; + ErrorsText += GetUnicodeString(arc.ErrorFlagsText); + } + if (!arc.ErrorMessage.IsEmpty()) + { + if (!ErrorsText.IsEmpty()) + ErrorsText += L'\n'; + ErrorsText += arc.ErrorMessage; + } + + if (!arc.WarningMessage.IsEmpty()) + { + if (!ErrorsText.IsEmpty()) + ErrorsText += L'\n'; + ErrorsText += arc.WarningMessage; + } + } +} +*/ + +HRESULT CArchiveLink::Open(COpenOptions &op) +{ + Release(); + if (op.types->Size() >= 32) + return E_NOTIMPL; + + HRESULT resSpec; + + for (;;) + { + resSpec = S_OK; + + op.openType = COpenType(); + if (op.types->Size() >= 1) + { + COpenType latest; + if (Arcs.Size() < op.types->Size()) + latest = (*op.types)[op.types->Size() - Arcs.Size() - 1]; + else + { + latest = (*op.types)[0]; + if (!latest.Recursive) + break; + } + op.openType = latest; + } + else if (Arcs.Size() >= 32) + break; + + /* + op.formatIndex = -1; + if (op.types->Size() >= 1) + { + int latest; + if (Arcs.Size() < op.types->Size()) + latest = (*op.types)[op.types->Size() - Arcs.Size() - 1]; + else + { + latest = (*op.types)[0]; + if (latest != -2 && latest != -3) + break; + } + if (latest >= 0) + op.formatIndex = latest; + else if (latest == -1 || latest == -2) + { + // default + } + else if (latest == -3) + op.formatIndex = -2; + else + op.formatIndex = latest + 2; + } + else if (Arcs.Size() >= 32) + break; + */ + + if (Arcs.IsEmpty()) + { + CArc arc; + arc.filePath = op.filePath; + arc.Path = op.filePath; + arc.SubfileIndex = (UInt32)(Int32)-1; + HRESULT result = arc.OpenStreamOrFile(op); + if (result != S_OK) + { + if (result == S_FALSE) + { + NonOpen_ErrorInfo = arc.NonOpen_ErrorInfo; + // NonOpenErrorFormatIndex = arc.ErrorFormatIndex; + NonOpen_ArcPath = arc.Path; + } + return result; + } + Arcs.Add(arc); + continue; + } + + // PrintNumber("op.formatIndex 11", op.formatIndex); + + const CArc &arc = Arcs.Back(); + + if (op.types->Size() > Arcs.Size()) + resSpec = 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<IInArchiveGetStream> getStream; + if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream) + break; + + CMyComPtr<ISequentialInStream> subSeqStream; + if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream) + break; + + CMyComPtr<IInStream> subStream; + if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK || !subStream) + break; + + CArc arc2; + RINOK(arc.GetItemPath(mainSubfile, arc2.Path)); + + bool zerosTailIsAllowed; + RINOK(Archive_GetItemBoolProp(arc.Archive, mainSubfile, kpidZerosTailIsAllowed, zerosTailIsAllowed)); + + CMyComPtr<IArchiveOpenSetSubArchiveName> setSubArchiveName; + op.callback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName); + if (setSubArchiveName) + setSubArchiveName->SetSubArchiveName(arc2.Path); + + arc2.SubfileIndex = mainSubfile; + + // CIntVector incl; + CIntVector excl; + + COpenOptions op2; + #ifndef _SFX + op2.props = op.props; + #endif + op2.codecs = op.codecs; + // op2.types = &incl; + op2.openType = op.openType; + op2.openType.ZerosTailIsAllowed = zerosTailIsAllowed; + op2.excludedFormats = ! + op2.stdInMode = false; + op2.stream = subStream; + op2.filePath = arc2.Path; + op2.callback = op.callback; + op2.callbackSpec = op.callbackSpec; + + + HRESULT result = arc2.OpenStream(op2); + resSpec = (op.types->Size() == 0 ? S_OK : S_FALSE); + if (result == S_FALSE) + { + NonOpen_ErrorInfo = arc2.ErrorInfo; + NonOpen_ArcPath = arc2.Path; + break; + } + RINOK(result); + RINOK(arc.GetItemMTime(mainSubfile, arc2.MTime, arc2.MTimeDefined)); + Arcs.Add(arc2); + } + IsOpen = !Arcs.IsEmpty(); + return resSpec; +} + +static void SetCallback(const FString &filePath, + IOpenCallbackUI *callbackUI, + IArchiveOpenCallback *reOpenCallback, + CMyComPtr<IArchiveOpenCallback> &callback) +{ + COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; + callback = openCallbackSpec; + openCallbackSpec->Callback = callbackUI; + openCallbackSpec->ReOpenCallback = reOpenCallback; + + FString dirPrefix, fileName; + NFile::NDir::GetFullPathAndSplit(filePath, dirPrefix, fileName); + openCallbackSpec->Init(dirPrefix, fileName); +} + +HRESULT CArchiveLink::Open2(COpenOptions &op, + IOpenCallbackUI *callbackUI) +{ + VolumesSize = 0; + COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; + CMyComPtr<IArchiveOpenCallback> callback = openCallbackSpec; + openCallbackSpec->Callback = callbackUI; + + FString prefix, name; + if (!op.stream && !op.stdInMode) + { + NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), prefix, name); + openCallbackSpec->Init(prefix, name); + } + else + { + openCallbackSpec->SetSubArchiveName(op.filePath); + } + + op.callback = callback; + op.callbackSpec = openCallbackSpec; + RINOK(Open(op)); + // VolumePaths.Add(fs2us(prefix + name)); + + FOR_VECTOR (i, openCallbackSpec->FileNames_WasUsed) + { + if (openCallbackSpec->FileNames_WasUsed[i]) + { + VolumePaths.Add(fs2us(prefix) + openCallbackSpec->FileNames[i]); + VolumesSize += openCallbackSpec->FileSizes[i]; + } + } + // VolumesSize = openCallbackSpec->TotalSize; + return S_OK; +} + +HRESULT CArc::ReOpen(const COpenOptions &op) +{ + ErrorInfo.ClearErrors(); + ErrorInfo.ErrorFormatIndex = -1; + + UInt64 fileSize = 0; + if (op.stream) + { + RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize)); + RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); + } + FileSize = fileSize; + + CMyComPtr<IInStream> stream2; + Int64 globalOffset = GetGlobalOffset(); + if (globalOffset <= 0) + stream2 = op.stream; + else + { + CTailInStream *tailStreamSpec = new CTailInStream; + stream2 = tailStreamSpec; + tailStreamSpec->Stream = op.stream; + tailStreamSpec->Offset = globalOffset; + tailStreamSpec->Init(); + RINOK(tailStreamSpec->SeekToStart()); + } + + // There are archives with embedded STUBs (like ZIP), so we must support signature scanning + // But for another archives we can use 0 here. So the code can be fixed !!! + UInt64 maxStartPosition = kMaxCheckStartPosition; + HRESULT res = Archive->Open(stream2, &maxStartPosition, op.callback); + + if (res == S_OK) + { + RINOK(ReadBasicProps(Archive, globalOffset, res)); + ArcStreamOffset = globalOffset; + if (ArcStreamOffset != 0) + InStream = op.stream; + } + return res; +} + + +HRESULT CArchiveLink::ReOpen(COpenOptions &op) +{ + if (Arcs.Size() > 1) + return E_NOTIMPL; + + CObjectVector<COpenType> inc; + CIntVector excl; + + op.types = &inc; + op.excludedFormats = ! + op.stdInMode = false; + op.stream = NULL; + if (Arcs.Size() == 0) // ??? + return Open2(op, NULL); + + CMyComPtr<IArchiveOpenCallback> openCallbackNew; + SetCallback(us2fs(op.filePath), NULL, op.callback, openCallbackNew); + CInFileStream *fileStreamSpec = new CInFileStream(true); + CMyComPtr<IInStream> stream(fileStreamSpec); + if (!fileStreamSpec->Open(us2fs(op.filePath))) + return GetLastError(); + op.stream = stream; + + CArc &arc = Arcs[0]; + HRESULT res = arc.ReOpen(op); + IsOpen = (res == S_OK); + return res; +} + +#ifndef _SFX + +bool ParseComplexSize(const wchar_t *s, UInt64 &result) +{ + result = 0; + const wchar_t *end; + UInt64 number = ConvertStringToUInt64(s, &end); + if (end == s) + return false; + if (*end == 0) + { + result = number; + return true; + } + if (end[1] != 0) + return false; + unsigned numBits; + switch (MyCharLower_Ascii(*end)) + { + case 'b': result = number; return true; + case 'k': numBits = 10; break; + case 'm': numBits = 20; break; + case 'g': numBits = 30; break; + case 't': numBits = 40; break; + default: return false; + } + if (number >= ((UInt64)1 << (64 - numBits))) + return false; + result = number << numBits; + return true; +} + +static bool ParseTypeParams(const UString &s, COpenType &type) +{ + if (s[0] == 0) + return true; + if (s[1] == 0) + { + switch ((unsigned)(Byte)s[0]) + { + case 'e': type.EachPos = true; return true; + case 'a': type.CanReturnArc = true; return true; + case 'r': type.Recursive = true; return true; + } + return false; + } + if (s[0] == 's') + { + UInt64 result; + if (!ParseComplexSize(s.Ptr(1), result)) + return false; + type.MaxStartOffset = result; + type.MaxStartOffset_Defined = true; + return true; + } + + return false; +} + +bool ParseType(CCodecs &codecs, const UString &s, COpenType &type) +{ + int pos2 = s.Find(':'); + UString name; + if (pos2 < 0) + { + name = s; + pos2 = s.Len(); + } + else + { + name = s.Left(pos2); + pos2++; + } + + int index = codecs.FindFormatForArchiveType(name); + type.Recursive = false; + + if (index < 0) + { + if (name[0] == '*') + { + if (name[1] != 0) + return false; + } + else if (name[0] == '#') + { + if (name[1] != 0) + return false; + type.CanReturnArc = false; + type.CanReturnParser = true; + } + else + return false; + } + + type.FormatIndex = index; + + for (unsigned i = pos2; i < s.Len();) + { + int next = s.Find(':', i); + if (next < 0) + next = s.Len(); + UString name = s.Mid(i, next - i); + if (name.IsEmpty()) + return false; + if (!ParseTypeParams(name, type)) + return false; + i = next + 1; + } + + return true; +} + +bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types) +{ + types.Clear(); + for (unsigned pos = 0; pos < s.Len();) + { + int pos2 = s.Find('.', pos); + if (pos2 < 0) + pos2 = s.Len(); + UString name = s.Mid(pos, pos2 - pos); + if (name.IsEmpty()) + return false; + COpenType type; + if (!ParseType(codecs, name, type)) + return false; + types.Add(type); + pos = pos2 + 1; + } + return true; +} + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/OpenArchive.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/OpenArchive.h new file mode 100644 index 000000000..f2a5ce9fe --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/OpenArchive.h @@ -0,0 +1,346 @@ +// OpenArchive.h + +#ifndef __OPEN_ARCHIVE_H +#define __OPEN_ARCHIVE_H + +#include "../../../Windows/PropVariant.h" + +#include "ArchiveOpenCallback.h" +#include "LoadCodecs.h" +#include "Property.h" + +HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw(); +HRESULT Archive_IsItem_Folder(IInArchive *arc, UInt32 index, bool &result) throw(); +HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw(); +HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw(); +HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &deleted) throw(); + +/* +struct COptionalOpenProperties +{ + UString FormatName; + CObjectVector<CProperty> Props; +}; +*/ + +#ifdef _SFX +#define OPEN_PROPS_DECL +#else +#define OPEN_PROPS_DECL const CObjectVector<CProperty> *props; +// #define OPEN_PROPS_DECL , const CObjectVector<COptionalOpenProperties> *props +#endif + +struct COpenSpecFlags +{ + // bool CanReturnFull; + bool CanReturnFrontal; + bool CanReturnTail; + bool CanReturnMid; + + bool CanReturn_NonStart() const { return CanReturnTail || CanReturnMid; } + + COpenSpecFlags(): + // CanReturnFull(true), + CanReturnFrontal(false), + CanReturnTail(false), + CanReturnMid(false) + {} +}; + +struct COpenType +{ + int FormatIndex; + + COpenSpecFlags SpecForcedType; + COpenSpecFlags SpecMainType; + COpenSpecFlags SpecWrongExt; + COpenSpecFlags SpecUnknownExt; + + bool Recursive; + + bool CanReturnArc; + bool CanReturnParser; + bool EachPos; + + // bool SkipSfxStub; + // bool ExeAsUnknown; + + bool ZerosTailIsAllowed; + + bool MaxStartOffset_Defined; + UInt64 MaxStartOffset; + + const COpenSpecFlags &GetSpec(bool isForced, bool isMain, bool isUnknown) const + { + return isForced ? SpecForcedType : (isMain ? SpecMainType : (isUnknown ? SpecUnknownExt : SpecWrongExt)); + } + + COpenType(): + FormatIndex(-1), + Recursive(true), + CanReturnArc(true), + CanReturnParser(false), + EachPos(false), + // SkipSfxStub(true), + // ExeAsUnknown(true), + ZerosTailIsAllowed(false), + MaxStartOffset_Defined(false), + MaxStartOffset(0) + { + SpecForcedType.CanReturnFrontal = true; + SpecForcedType.CanReturnTail = true; + SpecForcedType.CanReturnMid = true; + + SpecMainType.CanReturnFrontal = true; + + SpecUnknownExt.CanReturnTail = true; // for sfx + SpecUnknownExt.CanReturnMid = true; + SpecUnknownExt.CanReturnFrontal = true; // for alt streams of sfx with pad + + // ZerosTailIsAllowed = true; + } +}; + +struct COpenOptions +{ + CCodecs *codecs; + COpenType openType; + const CObjectVector<COpenType> *types; + const CIntVector *excludedFormats; + + IInStream *stream; + ISequentialInStream *seqStream; + IArchiveOpenCallback *callback; + COpenCallbackImp *callbackSpec; + OPEN_PROPS_DECL + // bool openOnlySpecifiedByExtension, + + bool stdInMode; + UString filePath; + + COpenOptions(): + codecs(NULL), + types(NULL), + excludedFormats(NULL), + stream(NULL), + seqStream(NULL), + callback(NULL), + callbackSpec(NULL), + stdInMode(false) + {} + +}; + +UInt32 GetOpenArcErrorFlags(const NWindows::NCOM::CPropVariant &prop, bool *isDefinedProp = NULL); + +struct CArcErrorInfo +{ + bool ThereIsTail; + bool UnexpecedEnd; + bool IgnoreTail; // all are zeros + // bool NonZerosTail; + bool ErrorFlags_Defined; + UInt32 ErrorFlags; + UInt32 WarningFlags; + int ErrorFormatIndex; // - 1 means no Error. + // if FormatIndex == ErrorFormatIndex, the archive is open with offset + UInt64 TailSize; + + /* if CArc is Open OK with some format: + - ErrorFormatIndex shows error format index, if extension is incorrect + - other variables show message and warnings of archive that is open */ + + UString ErrorMessage; + UString WarningMessage; + + // call IsArc_After_NonOpen only if Open returns S_FALSE + bool IsArc_After_NonOpen() const + { + return (ErrorFlags_Defined && (ErrorFlags & kpv_ErrorFlags_IsNotArc) == 0); + } + + + CArcErrorInfo(): + ThereIsTail(false), + UnexpecedEnd(false), + IgnoreTail(false), + // NonZerosTail(false), + ErrorFlags_Defined(false), + ErrorFlags(0), + WarningFlags(0), + ErrorFormatIndex(-1), + TailSize(0) + {} + + void ClearErrors(); + + void ClearErrors_Full() + { + ErrorFormatIndex = -1; + ClearErrors(); + } + + bool IsThereErrorOrWarning() const + { + return ErrorFlags != 0 + || WarningFlags != 0 + || NeedTailWarning() + || UnexpecedEnd + || !ErrorMessage.IsEmpty() + || !WarningMessage.IsEmpty(); + } + + bool AreThereErrors() const { return ErrorFlags != 0 || UnexpecedEnd; } + bool AreThereWarnings() const { return WarningFlags != 0 || NeedTailWarning(); } + + bool NeedTailWarning() const { return !IgnoreTail && ThereIsTail; } + + UInt32 GetWarningFlags() const + { + UInt32 a = WarningFlags; + if (NeedTailWarning() && (ErrorFlags & kpv_ErrorFlags_DataAfterEnd) == 0) + a |= kpv_ErrorFlags_DataAfterEnd; + return a; + } + + UInt32 GetErrorFlags() const + { + UInt32 a = ErrorFlags; + if (UnexpecedEnd) + a |= kpv_ErrorFlags_UnexpectedEnd; + return a; + } +}; + +class CArc +{ + HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive); + HRESULT CheckZerosTail(const COpenOptions &op, UInt64 offset); + HRESULT OpenStream2(const COpenOptions &options); + +public: + CMyComPtr<IInArchive> Archive; + CMyComPtr<IInStream> InStream; + // we use InStream in 2 cases (ArcStreamOffset != 0): + // 1) if we use additional cache stream + // 2) we reopen sfx archive with CTailInStream + + CMyComPtr<IArchiveGetRawProps> GetRawProps; + CMyComPtr<IArchiveGetRootProps> GetRootProps; + + CArcErrorInfo ErrorInfo; // for OK archives + CArcErrorInfo NonOpen_ErrorInfo; // ErrorInfo for mainArchive (false OPEN) + + UString Path; + UString filePath; + UString DefaultName; + int FormatIndex; // - 1 means Parser. + int SubfileIndex; + FILETIME MTime; + bool MTimeDefined; + + Int64 Offset; // it's offset of start of archive inside stream that is open by Archive Handler + UInt64 PhySize; + // UInt64 OkPhySize; + bool PhySizeDefined; + // bool OkPhySize_Defined; + UInt64 FileSize; + UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file + // bool offsetDefined; + + UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler + Int64 GetGlobalOffset() const { return ArcStreamOffset + Offset; } // it's global offset of archive + + // AString ErrorFlagsText; + + bool IsParseArc; + + bool IsTree; + + bool Ask_Deleted; + bool Ask_AltStream; + bool Ask_Aux; + bool Ask_INode; + + bool IgnoreSplit; // don't try split handler + + // void Set_ErrorFlagsText(); + + CArc(): + MTimeDefined(false), + IsTree(false), + Ask_Deleted(false), + Ask_AltStream(false), + Ask_Aux(false), + Ask_INode(false), + IgnoreSplit(false) + {} + + HRESULT ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes); + + // ~CArc(); + + HRESULT Close() + { + InStream.Release(); + return Archive->Close(); + } + + // AltStream's name is concatenated with base file name in one string in parts.Back() + HRESULT GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const; + + HRESULT GetItemPath(UInt32 index, UString &result) const; + + // GetItemPath2 adds [DELETED] dir prefix for deleted items. + HRESULT GetItemPath2(UInt32 index, UString &result) const; + + HRESULT GetItemSize(UInt32 index, UInt64 &size, bool &defined) const; + HRESULT GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const; + HRESULT IsItemAnti(UInt32 index, bool &result) const + { return Archive_GetItemBoolProp(Archive, index, kpidIsAnti, result); } + + + HRESULT OpenStream(const COpenOptions &options); + HRESULT OpenStreamOrFile(COpenOptions &options); + + HRESULT ReOpen(const COpenOptions &options); + + HRESULT CreateNewTailStream(CMyComPtr<IInStream> &stream); +}; + +struct CArchiveLink +{ + CObjectVector<CArc> Arcs; + UStringVector VolumePaths; + UInt64 VolumesSize; + bool IsOpen; + + // int NonOpenErrorFormatIndex; // - 1 means no Error. + UString NonOpen_ArcPath; + + CArcErrorInfo NonOpen_ErrorInfo; + + // UString ErrorsText; + // void Set_ErrorsText(); + + CArchiveLink(): VolumesSize(0), IsOpen(false) {} + void KeepModeForNextOpen(); + HRESULT Close(); + void Release(); + ~CArchiveLink() { Release(); } + + const CArc *GetArc() const { return &Arcs.Back(); } + IInArchive *GetArchive() const { return Arcs.Back().Archive; } + IArchiveGetRawProps *GetArchiveGetRawProps() const { return Arcs.Back().GetRawProps; } + IArchiveGetRootProps *GetArchiveGetRootProps() const { return Arcs.Back().GetRootProps; } + + HRESULT Open(COpenOptions &options); + + HRESULT Open2(COpenOptions &options, IOpenCallbackUI *callbackUI); + + HRESULT ReOpen(COpenOptions &options); +}; + +bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types); + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.cpp new file mode 100644 index 000000000..5ba8c7a89 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.cpp @@ -0,0 +1,555 @@ +// PropIDUtils.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileIO.h" +#include "../../../Windows/PropVariantConv.h" + +#include "../../PropID.h" + +#include "PropIDUtils.h" + +#define Get16(x) GetUi16(x) +#define Get32(x) GetUi32(x) + +using namespace NWindows; + +static const char g_WinAttribChars[16 + 1] = "RHS8DAdNTsLCOnE_"; +/* +0 READONLY +1 HIDDEN +2 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 +*/ + +void ConvertWinAttribToString(char *s, UInt32 wa) +{ + for (int i = 0; i < 16; i++) + if ((wa & (1 << i)) && i != 7) + *s++ = g_WinAttribChars[i]; + *s = 0; +} + +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 : '-'; + +void ConvertPropertyToShortString(char *dest, const PROPVARIANT &prop, PROPID propID, bool full) throw() +{ + *dest = 0; + if (prop.vt == VT_FILETIME) + { + FILETIME localFileTime; + if ((prop.filetime.dwHighDateTime == 0 && + prop.filetime.dwLowDateTime == 0) || + !::FileTimeToLocalFileTime(&prop.filetime, &localFileTime)) + return; + ConvertFileTimeToString(localFileTime, dest, true, full); + return; + } + switch (propID) + { + case kpidCRC: + { + if (prop.vt != VT_UI4) + break; + ConvertUInt32ToHex8Digits(prop.ulVal, dest); + return; + } + case kpidAttrib: + { + if (prop.vt != VT_UI4) + break; + ConvertWinAttribToString(dest, prop.ulVal); + return; + } + case kpidPosixAttrib: + { + if (prop.vt != VT_UI4) + break; + UString res; + UInt32 a = prop.ulVal; + + dest[0] = kPosixTypes[(a >> 12) & 0xF]; + for (int i = 6; i >= 0; i -= 3) + { + dest[7 - i] = MY_ATTR_CHAR(a, i + 2, 'r'); + dest[8 - i] = MY_ATTR_CHAR(a, i + 1, 'w'); + dest[9 - i] = MY_ATTR_CHAR(a, i + 0, 'x'); + } + if ((a & 0x800) != 0) dest[3] = ((a & (1 << 6)) ? 's' : 'S'); + if ((a & 0x400) != 0) dest[6] = ((a & (1 << 3)) ? 's' : 'S'); + if ((a & 0x200) != 0) dest[9] = ((a & (1 << 0)) ? 't' : 'T'); + dest[10] = 0; + + a &= ~(UInt32)0xFFFF; + if (a != 0) + { + dest[10] = ' '; + ConvertUInt32ToHex8Digits(a, dest + 11); + } + return; + } + case kpidINode: + { + if (prop.vt != VT_UI8) + break; + ConvertUInt32ToString((UInt32)(prop.uhVal.QuadPart >> 48), dest); + dest += strlen(dest); + *dest++ = '-'; + UInt64 low = prop.uhVal.QuadPart & (((UInt64)1 << 48) - 1); + ConvertUInt64ToString(low, dest); + return; + } + case kpidVa: + { + UInt64 v = 0; + if (ConvertPropVariantToUInt64(prop, v)) + { + dest[0] = '0'; + dest[1] = 'x'; + ConvertUInt64ToHex(prop.ulVal, dest + 2); + return; + } + break; + } + } + ConvertPropVariantToShortString(prop, dest); +} + +void ConvertPropertyToString(UString &dest, const PROPVARIANT &prop, PROPID propID, bool full) +{ + if (prop.vt == VT_BSTR) + { + dest = prop.bstrVal; + return; + } + char temp[64]; + ConvertPropertyToShortString(temp, prop, propID, full); + int len = MyStringLen(temp); + wchar_t *str = dest.GetBuffer(len); + for (int i = 0; i < len; i++) + str[i] = temp[i]; + dest.ReleaseBuffer(len); +} + +static inline char GetHex(Byte value) +{ + return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); +} + +#ifndef _SFX + +static inline void AddHexToString(AString &res, Byte value) +{ + res += GetHex((Byte)(value >> 4)); + res += GetHex((Byte)(value & 0xF)); + res += ' '; +} + +/* +static AString Data_To_Hex(const Byte *data, size_t size) +{ + AString s; + for (size_t i = 0; i < size; i++) + AddHexToString(s, data[i]); + return s; +} +*/ + +static const char *sidNames[] = +{ + "0", + "Dialup", + "Network", + "Batch", + "Interactive", + "Logon", // S-1-5-5-X-Y + "Service", + "Anonymous", + "Proxy", + "EnterpriseDC", + "Self", + "AuthenticatedUsers", + "RestrictedCode", + "TerminalServer", + "RemoteInteractiveLogon", + "ThisOrganization", + "16", + "IUserIIS", + "LocalSystem", + "LocalService", + "NetworkService", + "Domains" +}; + +struct CSecID2Name +{ + UInt32 n; + const char *sz; +}; + +const CSecID2Name sid_32_Names[] = +{ + { 544, "Administrators" }, + { 545, "Users" }, + { 546, "Guests" }, + { 547, "PowerUsers" }, + { 548, "AccountOperators" }, + { 549, "ServerOperators" }, + { 550, "PrintOperators" }, + { 551, "BackupOperators" }, + { 552, "Replicators" }, + { 553, "Backup Operators" }, + { 554, "PreWindows2000CompatibleAccess" }, + { 555, "RemoteDesktopUsers" }, + { 556, "NetworkConfigurationOperators" }, + { 557, "IncomingForestTrustBuilders" }, + { 558, "PerformanceMonitorUsers" }, + { 559, "PerformanceLogUsers" }, + { 560, "WindowsAuthorizationAccessGroup" }, + { 561, "TerminalServerLicenseServers" }, + { 562, "DistributedCOMUsers" }, + { 569, "CryptographicOperators" }, + { 573, "EventLogReaders" }, + { 574, "CertificateServiceDCOMAccess" } +}; + +static const CSecID2Name sid_21_Names[] = +{ + { 500, "Administrator" }, + { 501, "Guest" }, + { 502, "KRBTGT" }, + { 512, "DomainAdmins" }, + { 513, "DomainUsers" }, + { 515, "DomainComputers" }, + { 516, "DomainControllers" }, + { 517, "CertPublishers" }, + { 518, "SchemaAdmins" }, + { 519, "EnterpriseAdmins" }, + { 520, "GroupPolicyCreatorOwners" }, + { 553, "RASandIASServers" }, + { 553, "RASandIASServers" }, + { 571, "AllowedRODCPasswordReplicationGroup" }, + { 572, "DeniedRODCPasswordReplicationGroup" } +}; + +struct CServicesToName +{ + UInt32 n[5]; + const char *sz; +}; + +static const CServicesToName services_to_name[] = +{ + { { 0x38FB89B5, 0xCBC28419, 0x6D236C5C, 0x6E770057, 0x876402C0 } , "TrustedInstaller" } +}; + +static void ParseSid(AString &s, const Byte *p, UInt32 lim, UInt32 &sidSize) +{ + sidSize = 0; + if (lim < 8) + { + s += "ERROR"; + return; + } + UInt32 rev = p[0]; + if (rev != 1) + { + s += "UNSUPPORTED"; + return; + } + UInt32 num = p[1]; + if (8 + num * 4 > lim) + { + s += "ERROR"; + return; + } + sidSize = 8 + num * 4; + UInt32 authority = GetBe32(p + 4); + + if (p[2] == 0 && p[3] == 0 && authority == 5 && num >= 1) + { + UInt32 v0 = Get32(p + 8); + if (v0 < ARRAY_SIZE(sidNames)) + { + s += sidNames[v0]; + return; + } + if (v0 == 32 && num == 2) + { + UInt32 v1 = Get32(p + 12); + for (int i = 0; i < ARRAY_SIZE(sid_32_Names); i++) + if (sid_32_Names[i].n == v1) + { + s += sid_32_Names[i].sz; + return; + } + } + if (v0 == 21 && num == 5) + { + UInt32 v4 = Get32(p + 8 + 4 * 4); + for (int i = 0; i < ARRAY_SIZE(sid_21_Names); i++) + if (sid_21_Names[i].n == v4) + { + s += sid_21_Names[i].sz; + return; + } + } + if (v0 == 80 && num == 6) + { + for (int i = 0; i < ARRAY_SIZE(services_to_name); i++) + { + const CServicesToName &sn = services_to_name[i]; + int j; + for (j = 0; j < 5 && sn.n[j] == Get32(p + 8 + 4 + j * 4); j++); + if (j == 5) + { + s += sn.sz; + return; + } + } + } + } + + char sz[16]; + s += "S-1-"; + if (p[2] == 0 && p[3] == 0) + { + ConvertUInt32ToString(authority, sz); + s += sz; + } + else + { + s += "0x"; + for (int i = 2; i < 8; i++) + AddHexToString(s, p[i]); + } + for (UInt32 i = 0; i < num; i++) + { + s += '-'; + ConvertUInt32ToString(Get32(p + 8 + i * 4), sz); + s += sz; + } +} + +static void ParseOwner(AString &s, const Byte *p, UInt32 size, UInt32 pos) +{ + if (pos > size) + { + s += "ERROR"; + return; + } + UInt32 sidSize = 0; + ParseSid(s, p + pos, size - pos, sidSize); +} + +static void AddUInt32ToString(AString &s, UInt32 val) +{ + char sz[16]; + ConvertUInt32ToString(val, sz); + s += sz; +} + +static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName, UInt32 flags, UInt32 offset) +{ + UInt32 control = Get16(p + 2); + if ((flags & control) == 0) + return; + UInt32 pos = Get32(p + offset); + s += ' '; + s += strName; + if (pos >= size) + return; + p += pos; + size -= pos; + if (size < 8) + return; + if (Get16(p) != 2) // revision + return; + // UInt32 aclSize = Get16(p + 2); + UInt32 num = Get32(p + 4); + AddUInt32ToString(s, num); + /* + if (num >= (1 << 16)) + return; + if (aclSize > size) + return; + size = aclSize; + size -= 8; + p += 8; + for (UInt32 i = 0 ; i < num; i++) + { + if (size <= 8) + return; + // Byte type = p[0]; + // Byte flags = p[1]; + // UInt32 aceSize = Get16(p + 2); + // UInt32 mask = Get32(p + 4); + p += 8; + size -= 8; + + UInt32 sidSize = 0; + s += ' '; + s += ParseSid(p, size, sidSize); + if (sidSize == 0) + return; + p += sidSize; + size -= sidSize; + } + if (size != 0) + s += " ERROR"; + */ +} + +#define MY_SE_OWNER_DEFAULTED (0x0001) +#define MY_SE_GROUP_DEFAULTED (0x0002) +#define MY_SE_DACL_PRESENT (0x0004) +#define MY_SE_DACL_DEFAULTED (0x0008) +#define MY_SE_SACL_PRESENT (0x0010) +#define MY_SE_SACL_DEFAULTED (0x0020) +#define MY_SE_DACL_AUTO_INHERIT_REQ (0x0100) +#define MY_SE_SACL_AUTO_INHERIT_REQ (0x0200) +#define MY_SE_DACL_AUTO_INHERITED (0x0400) +#define MY_SE_SACL_AUTO_INHERITED (0x0800) +#define MY_SE_DACL_PROTECTED (0x1000) +#define MY_SE_SACL_PROTECTED (0x2000) +#define MY_SE_RM_CONTROL_VALID (0x4000) +#define MY_SE_SELF_RELATIVE (0x8000) + +void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s) +{ + s.Empty(); + if (size < 20 || size > (1 << 18)) + { + s += "ERROR"; + return; + } + if (Get16(data) != 1) // revision + { + s += "UNSUPPORTED"; + return; + } + ParseOwner(s, data, size, Get32(data + 4)); + s += ' '; + ParseOwner(s, data, size, Get32(data + 8)); + ParseAcl(s, data, size, "s:", MY_SE_SACL_PRESENT, 12); + ParseAcl(s, data, size, "d:", MY_SE_DACL_PRESENT, 16); + s += ' '; + AddUInt32ToString(s, size); + // s += '\n'; + // s += Data_To_Hex(data, size); +} + +#ifdef _WIN32 + +static bool CheckSid(const Byte *data, UInt32 size, UInt32 pos) +{ + if (pos >= size) + return false; + size -= pos; + if (size < 8) + return false; + UInt32 rev = data[pos]; + if (rev != 1) + return false; + UInt32 num = data[pos + 1]; + return (8 + num * 4 <= size); +} + +static bool CheckAcl(const Byte *p, UInt32 size, UInt32 flags, UInt32 offset) +{ + UInt32 control = Get16(p + 2); + if ((flags & control) == 0) + return true; + UInt32 pos = Get32(p + offset); + if (pos >= size) + return false; + p += pos; + size -= pos; + if (size < 8) + return false; + UInt32 aclSize = Get16(p + 2); + return (aclSize <= size); +} + +bool CheckNtSecure(const Byte *data, UInt32 size) +{ + if (size < 20) + return false; + if (Get16(data) != 1) // revision + return true; // windows function can handle such error, so we allow it + if (size > (1 << 18)) + return false; + if (!CheckSid(data, size, Get32(data + 4))) return false; + if (!CheckSid(data, size, Get32(data + 8))) return false; + if (!CheckAcl(data, size, MY_SE_SACL_PRESENT, 12)) return false; + if (!CheckAcl(data, size, MY_SE_DACL_PRESENT, 16)) return false; + return true; +} + +#endif + +#ifdef _WIN32 +bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s) +{ + s.Empty(); + NFile::CReparseAttr attr; + if (attr.Parse(data, size)) + { + if (!attr.IsSymLink()) + s += L"Junction: "; + s += attr.GetPath(); + if (!attr.IsOkNamePair()) + { + s += L" : "; + s += attr.PrintName; + } + return true; + } + + if (size < 8) + return false; + UInt32 tag = Get32(data); + UInt32 len = Get16(data + 4); + if (len + 8 > size) + return false; + if (Get16(data + 6) != 0) // padding + return false; + + char hex[16]; + ConvertUInt32ToHex8Digits(tag, hex); + s.AddAsciiStr(hex); + s += L' '; + + data += 8; + + for (UInt32 i = 0; i < len; i++) + { + Byte b = ((const Byte *)data)[i]; + s += (wchar_t)GetHex((Byte)((b >> 4) & 0xF)); + s += (wchar_t)GetHex((Byte)(b & 0xF)); + } + return true; +} +#endif + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.h new file mode 100644 index 000000000..3ee2981de --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.h @@ -0,0 +1,17 @@ +// PropIDUtils.h + +#ifndef __PROPID_UTILS_H +#define __PROPID_UTILS_H + +#include "../../../Common/MyString.h" + +// provide at least 64 bytes for buffer including zero-end +void ConvertPropertyToShortString(char *dest, const PROPVARIANT &propVariant, PROPID propID, bool full = true) throw(); +void ConvertPropertyToString(UString &dest, const PROPVARIANT &propVariant, PROPID propID, bool full = true); + +bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s); +void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s); +bool CheckNtSecure(const Byte *data, UInt32 size); +void ConvertWinAttribToString(char *s, UInt32 wa); + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Property.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Property.h new file mode 100644 index 000000000..8b57a2a64 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Property.h @@ -0,0 +1,14 @@ +// Property.h + +#ifndef __7Z_PROPERTY_H +#define __7Z_PROPERTY_H + +#include "../../../Common/MyString.h" + +struct CProperty +{ + UString Name; + UString Value; +}; + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/SetProperties.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/SetProperties.cpp new file mode 100644 index 000000000..64b9d92a6 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/SetProperties.cpp @@ -0,0 +1,80 @@ +// SetProperties.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyCom.h" +#include "../../../Common/MyString.h" +#include "../../../Common/StringToInt.h" + +#include "../../../Windows/PropVariant.h" + +#include "../../Archive/IArchive.h" + +#include "SetProperties.h" + +using namespace NWindows; +using namespace NCOM; + +static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop) +{ + const wchar_t *end; + UInt64 result = ConvertStringToUInt64(s, &end); + if (*end != 0 || s.IsEmpty()) + prop = s; + else if (result <= (UInt32)0xFFFFFFFF) + prop = (UInt32)result; + else + prop = result; +} + +HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties) +{ + if (properties.IsEmpty()) + return S_OK; + CMyComPtr<ISetProperties> setProperties; + unknown->QueryInterface(IID_ISetProperties, (void **)&setProperties); + if (!setProperties) + return S_OK; + + UStringVector realNames; + CPropVariant *values = new CPropVariant[properties.Size()]; + try + { + unsigned 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.Back(); + if (c == L'-') + propVariant = false; + else if (c == L'+') + propVariant = true; + if (propVariant.vt != VT_EMPTY) + name.DeleteBack(); + } + } + else + ParseNumberString(property.Value, propVariant); + realNames.Add(name); + values[i] = propVariant; + } + CRecordVector<const wchar_t *> names; + for (i = 0; i < realNames.Size(); i++) + names.Add((const wchar_t *)realNames[i]); + + RINOK(setProperties->SetProperties(&names.Front(), values, names.Size())); + } + catch(...) + { + delete []values; + throw; + } + delete []values; + return S_OK; +} diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/SetProperties.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/SetProperties.h new file mode 100644 index 000000000..892f1a210 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/SetProperties.h @@ -0,0 +1,10 @@ +// SetProperties.h + +#ifndef __SETPROPERTIES_H +#define __SETPROPERTIES_H + +#include "Property.h" + +HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties); + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/SortUtils.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/SortUtils.cpp new file mode 100644 index 000000000..b7e422a29 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/SortUtils.cpp @@ -0,0 +1,23 @@ +// SortUtils.cpp + +#include "StdAfx.h" + +#include "../../../Common/Wildcard.h" + +#include "SortUtils.h" + +static int CompareStrings(const unsigned *p1, const unsigned *p2, void *param) +{ + const UStringVector &strings = *(const UStringVector *)param; + return CompareFileNames(strings[*p1], strings[*p2]); +} + +void SortFileNames(const UStringVector &strings, CUIntVector &indices) +{ + unsigned numItems = strings.Size(); + indices.ClearAndSetSize(numItems); + unsigned *vals = &indices[0]; + for (unsigned i = 0; i < numItems; i++) + vals[i] = i; + indices.Sort(CompareStrings, (void *)&strings); +} diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/SortUtils.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/SortUtils.h new file mode 100644 index 000000000..8e42e0682 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/SortUtils.h @@ -0,0 +1,10 @@ +// SortUtils.h + +#ifndef __SORT_UTLS_H +#define __SORT_UTLS_H + +#include "../../../Common/MyString.h" + +void SortFileNames(const UStringVector &strings, CUIntVector &indices); + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/TempFiles.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/TempFiles.cpp new file mode 100644 index 000000000..0c13ae158 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/TempFiles.cpp @@ -0,0 +1,21 @@ +// TempFiles.cpp + +#include "StdAfx.h" + +#include "../../../Windows/FileDir.h" + +#include "TempFiles.h" + +using namespace NWindows; +using namespace NFile; + +void CTempFiles::Clear() +{ + while (!Paths.IsEmpty()) + { + NDir::DeleteFileAlways(Paths.Back()); + Paths.DeleteBack(); + } +} + + diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/TempFiles.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/TempFiles.h new file mode 100644 index 000000000..4099e6558 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/TempFiles.h @@ -0,0 +1,16 @@ +// TempFiles.h + +#ifndef __TEMP_FILES_H +#define __TEMP_FILES_H + +#include "../../../Common/MyString.h" + +class CTempFiles +{ + void Clear(); +public: + FStringVector Paths; + ~CTempFiles() { Clear(); } +}; + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Update.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Update.cpp new file mode 100644 index 000000000..4697dca46 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Update.cpp @@ -0,0 +1,1490 @@ +// Update.cpp + +#include "StdAfx.h" + +#include "Update.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantConv.h" +#include "../../../Windows/TimeUtils.h" + +#include "../../Common/FileStreams.h" +#include "../../Common/LimitedStreams.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 NDir; +using namespace NName; + +static CFSTR kTempFolderPrefix = FTEXT("7zE"); + +#ifdef ENV_UNIX +FString GetModuleDirPrefix() +{ + FString s; + + const char *p7zip_home_dir = getenv("P7ZIP_HOME_DIR"); + if (p7zip_home_dir) { + return MultiByteToUnicodeString(p7zip_home_dir,CP_ACP); + } + + return FTEXT(".") FSTRING_PATH_SEPARATOR; +} +#endif + +static bool DeleteEmptyFolderAndEmptySubFolders(const FString &path) +{ + NFind::CFileInfo fileInfo; + FString pathPrefix = path + FCHAR_PATH_SEPARATOR; + { + NFind::CEnumerator enumerator(pathPrefix + FCHAR_ANY_MASK); + while (enumerator.Next(fileInfo)) + { + if (fileInfo.IsDir()) + if (!DeleteEmptyFolderAndEmptySubFolders(pathPrefix + fileInfo.Name)) + return false; + } + } + /* + // we don't need clear read-only for folders + if (!MySetFileAttributes(path, 0)) + return false; + */ + return RemoveDir(path); +} + + +using namespace NUpdateArchive; + +class COutMultiVolStream: + public IOutStream, + public CMyUnknownImp +{ + unsigned _streamIndex; // required stream + UInt64 _offsetPos; // offset from start of _streamIndex index + UInt64 _absPos; + UInt64 _length; + + struct CAltStreamInfo + { + COutFileStream *StreamSpec; + CMyComPtr<IOutStream> Stream; + FString Name; + UInt64 Pos; + UInt64 RealSize; + }; + CObjectVector<CAltStreamInfo> Streams; +public: + // CMyComPtr<IArchiveUpdateCallback2> VolumeCallback; + CRecordVector<UInt64> Sizes; + FString Prefix; + CTempFiles *TempFiles; + + void Init() + { + _streamIndex = 0; + _offsetPos = 0; + _absPos = 0; + _length = 0; + } + + bool SetMTime(const FILETIME *mTime); + 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_VECTOR (i, Streams) + { + COutFileStream *s = Streams[i].StreamSpec; + if (s) + { + HRESULT res2 = s->Close(); + if (res2 != S_OK) + res = res2; + } + } + return res; +} + +bool COutMultiVolStream::SetMTime(const FILETIME *mTime) +{ + bool res = true; + FOR_VECTOR (i, Streams) + { + COutFileStream *s = Streams[i].StreamSpec; + if (s) + if (!s->SetMTime(mTime)) + res = false; + } + return res; +} + +STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize != NULL) + *processedSize = 0; + while (size > 0) + { + if (_streamIndex >= Streams.Size()) + { + CAltStreamInfo altStream; + + FChar temp[16]; + ConvertUInt32ToString(_streamIndex + 1, temp); + FString res = temp; + while (res.Len() < 3) + res = FString(FTEXT('0')) + res; + FString name = Prefix + res; + altStream.StreamSpec = new COutFileStream; + altStream.Stream = altStream.StreamSpec; + if (!altStream.StreamSpec->Create(name, false)) + return ::GetLastError(); + { + // NSynchronization::CCriticalSectionLock lock(g_TempPathsCS); + TempFiles->Paths.Add(name); + } + + altStream.Pos = 0; + altStream.RealSize = 0; + altStream.Name = name; + Streams.Add(altStream); + continue; + } + CAltStreamInfo &altStream = Streams[_streamIndex]; + + unsigned index = _streamIndex; + if (index >= Sizes.Size()) + index = Sizes.Size() - 1; + UInt64 volSize = Sizes[index]; + + if (_offsetPos >= volSize) + { + _offsetPos -= volSize; + _streamIndex++; + continue; + } + if (_offsetPos != altStream.Pos) + { + // CMyComPtr<IOutStream> outStream; + // RINOK(altStream.Stream.QueryInterface(IID_IOutStream, &outStream)); + RINOK(altStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL)); + altStream.Pos = _offsetPos; + } + + UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - altStream.Pos); + UInt32 realProcessed; + RINOK(altStream.Stream->Write(data, curSize, &realProcessed)); + data = (void *)((Byte *)data + realProcessed); + size -= realProcessed; + altStream.Pos += realProcessed; + _offsetPos += realProcessed; + _absPos += realProcessed; + if (_absPos > _length) + _length = _absPos; + if (_offsetPos > altStream.RealSize) + altStream.RealSize = _offsetPos; + if (processedSize != NULL) + *processedSize += realProcessed; + if (altStream.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; + unsigned i = 0; + while (i < Streams.Size()) + { + CAltStreamInfo &altStream = Streams[i++]; + if ((UInt64)newSize < altStream.RealSize) + { + RINOK(altStream.Stream->SetSize(newSize)); + altStream.RealSize = newSize; + break; + } + newSize -= altStream.RealSize; + } + while (i < Streams.Size()) + { + { + CAltStreamInfo &altStream = Streams.Back(); + altStream.Stream.Release(); + DeleteFileAlways(altStream.Name); + } + Streams.DeleteBack(); + } + _offsetPos = _absPos; + _streamIndex = 0; + _length = newSize; + return S_OK; +} + +void CArchivePath::ParseFromPath(const UString &path, EArcNameMode mode) +{ + OriginalPath = path; + + SplitPathToParts_2(path, Prefix, Name); + + if (mode == k_ArcNameMode_Add) + return; + if (mode == k_ArcNameMode_Exact) + { + BaseExtension.Empty(); + return; + } + + int dotPos = Name.ReverseFind(L'.'); + if (dotPos < 0) + return; + if ((unsigned)dotPos == Name.Len() - 1) + { + Name.DeleteBack(); + BaseExtension.Empty(); + return; + } + const UString ext = Name.Ptr(dotPos + 1); + if (BaseExtension.IsEqualToNoCase(ext)) + { + BaseExtension = ext; + Name.DeleteFrom(dotPos); + } + else + BaseExtension.Empty(); +} + +UString CArchivePath::GetFinalPath() const +{ + UString path = GetPathWithoutExt(); + if (!BaseExtension.IsEmpty()) + path += UString(L'.') + BaseExtension; + return path; +} + +UString CArchivePath::GetFinalVolPath() const +{ + UString path = GetPathWithoutExt(); + if (!BaseExtension.IsEmpty()) + path += UString(L'.') + VolExtension; + return path; +} + +FString CArchivePath::GetTempPath() const +{ + FString path = TempPrefix + us2fs(Name); + if (!BaseExtension.IsEmpty()) + path += FString(FTEXT('.')) + us2fs(BaseExtension); + path += FTEXT(".tmp"); + path += TempPostfix; + return path; +} + +static const wchar_t *kDefaultArcType = L"7z"; +static const wchar_t *kDefaultArcExt = L"7z"; +static const wchar_t *kSFXExtension = + #ifdef _WIN32 + L"exe"; + #else + L""; + #endif + +bool CUpdateOptions::InitFormatIndex(const CCodecs *codecs, + const CObjectVector<COpenType> &types, const UString &arcPath) +{ + if (types.Size() > 1) + return false; + // int arcTypeIndex = -1; + if (types.Size() != 0) + { + MethodMode.Type = types[0]; + MethodMode.Type_Defined = true; + } + if (MethodMode.Type.FormatIndex < 0) + { + // MethodMode.Type = -1; + MethodMode.Type = COpenType(); + if (ArcNameMode != k_ArcNameMode_Add) + { + MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveName(arcPath); + if (MethodMode.Type.FormatIndex >= 0) + MethodMode.Type_Defined = true; + } + } + return true; +} + +bool CUpdateOptions::SetArcPath(const CCodecs *codecs, const UString &arcPath) +{ + UString typeExt; + int formatIndex = MethodMode.Type.FormatIndex; + if (formatIndex < 0) + { + typeExt = kDefaultArcExt; + } + else + { + const CArcInfoEx &arcInfo = codecs->Formats[formatIndex]; + if (!arcInfo.UpdateEnabled) + return false; + typeExt = arcInfo.GetMainExt(); + } + UString ext = typeExt; + if (SfxMode) + ext = kSFXExtension; + ArchivePath.BaseExtension = ext; + ArchivePath.VolExtension = typeExt; + ArchivePath.ParseFromPath(arcPath, ArcNameMode); + FOR_VECTOR (i, Commands) + { + CUpdateArchiveCommand &uc = Commands[i]; + uc.ArchivePath.BaseExtension = ext; + uc.ArchivePath.VolExtension = typeExt; + uc.ArchivePath.ParseFromPath(uc.UserArchivePath, ArcNameMode); + } + return true; +} + +/* +struct CUpdateProduceCallbackImp: public IUpdateProduceCallback +{ + const CObjectVector<CArcItem> *_arcItems; + IUpdateCallbackUI *_callback; + + CUpdateProduceCallbackImp(const CObjectVector<CArcItem> *a, + IUpdateCallbackUI *callback): _arcItems(a), _callback(callback) {} + virtual HRESULT ShowDeleteFile(int arcIndex); +}; + +HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(int arcIndex) +{ + return _callback->ShowDeleteFile((*_arcItems)[arcIndex].Name); +} +*/ + +bool CRenamePair::Prepare() +{ + if (RecursedType != NRecursedType::kNonRecursed) + return false; + if (!WildcardParsing) + return true; + return !DoesNameContainWildcard(OldName); +} + +extern bool g_CaseSensitive; + +static int CompareTwoNames(const wchar_t *s1, const wchar_t *s2) +{ + for (int i = 0;; i++) + { + wchar_t c1 = s1[i]; + wchar_t c2 = s2[i]; + if (c1 == 0 || c2 == 0) + return i; + if (c1 == c2) + continue; + if (!g_CaseSensitive && (MyCharUpper(c1) == MyCharUpper(c2))) + continue; + if (IsCharDirLimiter(c1) && IsCharDirLimiter(c2)) + continue; + return i; + } +} + +bool CRenamePair::GetNewPath(bool isFolder, const UString &src, UString &dest) const +{ + int num = CompareTwoNames(OldName, src); + if (OldName[num] == 0) + { + if (src[num] != 0 && !IsCharDirLimiter(src[num]) && num != 0 && !IsCharDirLimiter(src[num - 1])) + return false; + } + else + { + // OldName[num] != 0 + // OldName = "1\1a.txt" + // src = "1" + + if (!isFolder || + src[num] != 0 || + !IsCharDirLimiter(OldName[num]) || + OldName[num + 1] != 0) + return false; + } + dest = NewName + src.Ptr(num); + return true; +} + +static int GetReverseSlashPos(const UString &name) +{ + int slashPos = name.ReverseFind(L'/'); + #ifdef _WIN32 + int slash1Pos = name.ReverseFind(L'\\'); + slashPos = MyMax(slashPos, slash1Pos); + #endif + return slashPos; +} + +static HRESULT Compress( + const CUpdateOptions &options, + CCodecs *codecs, + const CActionSet &actionSet, + const CArc *arc, + CArchivePath &archivePath, + const CObjectVector<CArcItem> &arcItems, + Byte *processedItemsStatuses, + const CDirItems &dirItems, + const CDirItem *parentDirItem, + CTempFiles &tempFiles, + CUpdateErrorInfo &errorInfo, + IUpdateCallbackUI *callback) +{ + CMyComPtr<IOutArchive> outArchive; + int formatIndex = options.MethodMode.Type.FormatIndex; + if (arc) + { + formatIndex = arc->FormatIndex; + if (formatIndex < 0) + return E_NOTIMPL; + CMyComPtr<IInArchive> archive2 = arc->Archive; + HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive); + if (result != S_OK) + throw kUpdateIsNotSupoorted; + } + else + { + RINOK(codecs->CreateOutArchive(formatIndex, outArchive)); + + #ifdef EXTERNAL_CODECS + { + CMyComPtr<ISetCompressCodecsInfo> 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; + } + + { + const CArcInfoEx &arcInfo = codecs->Formats[formatIndex]; + if (options.AltStreams.Val && !arcInfo.Flags_AltStreams()) + return E_NOTIMPL; + if (options.NtSecurity.Val && !arcInfo.Flags_NtSecure()) + return E_NOTIMPL; + } + + CRecordVector<CUpdatePair2> updatePairs2; + + UStringVector newNames; + + if (options.RenamePairs.Size() != 0) + { + FOR_VECTOR (i, arcItems) + { + const CArcItem &ai = arcItems[i]; + bool needRename = false; + UString dest; + if (ai.Censored) + { + FOR_VECTOR (j, options.RenamePairs) + { + const CRenamePair &rp = options.RenamePairs[j]; + if (rp.GetNewPath(ai.IsDir, ai.Name, dest)) + { + needRename = true; + break; + } + if (ai.IsAltStream) + { + int colonPos = ai.Name.ReverseFind(':'); + int slashPosPos = GetReverseSlashPos(ai.Name); + if (colonPos > slashPosPos) + { + UString mainName = ai.Name.Left(colonPos); + /* + actually we must improve that code to support cases + with folder renaming like: rn arc dir1\ dir2\ + */ + if (rp.GetNewPath(false, mainName, dest)) + { + needRename = true; + dest += ':'; + dest += ai.Name.Ptr(colonPos + 1); + break; + } + } + } + } + } + CUpdatePair2 up2; + up2.SetAs_NoChangeArcItem(ai.IndexInServer); + if (needRename) + { + up2.NewProps = true; + RINOK(arc->IsItemAnti(i, up2.IsAnti)); + up2.NewNameIndex = newNames.Add(dest); + } + updatePairs2.Add(up2); + } + } + else + { + CRecordVector<CUpdatePair> 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_VECTOR (i, updatePairs2) + if (updatePairs2[i].NewData) + numFiles++; + + RINOK(callback->SetNumFiles(numFiles)); + + CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; + CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec); + + updateCallbackSpec->ShareForWrite = options.OpenShareForWrite; + updateCallbackSpec->StdInMode = options.StdInMode; + updateCallbackSpec->Callback = callback; + + if (arc) + { + // we set Archive to allow to transfer GetProperty requests back to DLL. + updateCallbackSpec->Archive = arc->Archive; + updateCallbackSpec->GetRawProps = arc->GetRawProps; + updateCallbackSpec->GetRootProps = arc->GetRootProps; + } + + updateCallbackSpec->DirItems = &dirItems; + updateCallbackSpec->ParentDirItem = parentDirItem; + + updateCallbackSpec->StoreNtSecurity = options.NtSecurity.Val; + updateCallbackSpec->StoreHardLinks = options.HardLinks.Val; + updateCallbackSpec->StoreSymLinks = options.SymLinks.Val; + + updateCallbackSpec->ArcItems = &arcItems; + updateCallbackSpec->UpdatePairs = &updatePairs2; + + updateCallbackSpec->ProcessedItemsStatuses = processedItemsStatuses; + + if (options.RenamePairs.Size() != 0) + updateCallbackSpec->NewNames = &newNames; + + CMyComPtr<IOutStream> outSeekStream; + CMyComPtr<ISequentialOutStream> outStream; + + if (!options.StdOutMode) + { + FString dirPrefix; + if (!GetOnlyDirPrefix(us2fs(archivePath.GetFinalPath()), dirPrefix)) + throw 1417161; + CreateComplexDir(dirPrefix); + } + + COutFileStream *outStreamSpec = NULL; + COutMultiVolStream *volStreamSpec = NULL; + + if (options.VolumesSizes.Size() == 0) + { + if (options.StdOutMode) + outStream = new CStdOutFileStream; + else + { + outStreamSpec = new COutFileStream; + outSeekStream = outStreamSpec; + outStream = outSeekStream; + bool isOK = false; + FString realPath; + for (int i = 0; i < (1 << 16); i++) + { + if (archivePath.Temp) + { + if (i > 0) + { + FChar s[16]; + ConvertUInt32ToString(i, s); + archivePath.TempPostfix = s; + } + realPath = archivePath.GetTempPath(); + } + else + realPath = us2fs(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 (options.StdOutMode) + return E_FAIL; + if (arc && arc->GetGlobalOffset() > 0) + return E_NOTIMPL; + + volStreamSpec = new COutMultiVolStream; + outSeekStream = volStreamSpec; + outStream = outSeekStream; + volStreamSpec->Sizes = options.VolumesSizes; + volStreamSpec->Prefix = us2fs(archivePath.GetFinalVolPath() + 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, options.MethodMode.Properties)); + + if (options.SfxMode) + { + CInFileStream *sfxStreamSpec = new CInFileStream; + CMyComPtr<IInStream> sfxStream(sfxStreamSpec); + if (!sfxStreamSpec->Open(options.SfxModule)) + { + errorInfo.SystemError = ::GetLastError(); + errorInfo.Message = L"7-Zip cannot open SFX module"; + errorInfo.FileName = options.SfxModule; + return E_FAIL; + } + + CMyComPtr<ISequentialOutStream> sfxOutStream; + COutFileStream *outStreamSpec = NULL; + if (options.VolumesSizes.Size() == 0) + sfxOutStream = outStream; + else + { + outStreamSpec = new COutFileStream; + sfxOutStream = outStreamSpec; + FString realPath = us2fs(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()); + } + } + + CMyComPtr<ISequentialOutStream> tailStream; + + if (options.SfxMode || !arc || arc->ArcStreamOffset == 0) + tailStream = outStream; + else + { + // Int64 globalOffset = arc->GetGlobalOffset(); + RINOK(arc->InStream->Seek(0, STREAM_SEEK_SET, NULL)); + RINOK(NCompress::CopyStream_ExactSize(arc->InStream, outStream, arc->ArcStreamOffset, NULL)); + if (options.StdOutMode) + tailStream = outStream; + else + { + CTailOutStream *tailStreamSpec = new CTailOutStream; + tailStream = tailStreamSpec; + tailStreamSpec->Stream = outSeekStream; + tailStreamSpec->Offset = arc->ArcStreamOffset; + tailStreamSpec->Init(); + } + } + + + HRESULT result = outArchive->UpdateItems(tailStream, updatePairs2.Size(), updateCallback); + callback->Finilize(); + RINOK(result); + + + if (options.SetArcMTime) + { + FILETIME ft; + ft.dwLowDateTime = 0; + ft.dwHighDateTime = 0; + FOR_VECTOR (i, updatePairs2) + { + CUpdatePair2 &pair2 = updatePairs2[i]; + const FILETIME *ft2 = NULL; + if (pair2.NewProps && pair2.DirIndex >= 0) + ft2 = &dirItems.Items[pair2.DirIndex].MTime; + else if (pair2.UseArcProps && pair2.ArcIndex >= 0) + ft2 = &arcItems[pair2.ArcIndex].MTime; + if (ft2) + { + if (::CompareFileTime(&ft, ft2) < 0) + ft = *ft2; + } + } + if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0) + { + if (outStreamSpec) + outStreamSpec->SetMTime(&ft); + else if (volStreamSpec) + volStreamSpec->SetMTime(&ft);; + } + } + + if (outStreamSpec) + result = outStreamSpec->Close(); + else if (volStreamSpec) + result = volStreamSpec->Close(); + return result; +} + +static HRESULT EnumerateInArchiveItems( + // bool storeStreamsMode, + const NWildcard::CCensor &censor, + const CArc &arc, + CObjectVector<CArcItem> &arcItems) +{ + arcItems.Clear(); + UInt32 numItems; + IInArchive *archive = arc.Archive; + RINOK(archive->GetNumberOfItems(&numItems)); + arcItems.ClearAndReserve(numItems); + for (UInt32 i = 0; i < numItems; i++) + { + CArcItem ai; + + RINOK(arc.GetItemPath(i, ai.Name)); + RINOK(Archive_IsItem_Folder(archive, i, ai.IsDir)); + RINOK(Archive_IsItem_AltStream(archive, i, ai.IsAltStream)); + /* + if (!storeStreamsMode && ai.IsAltStream) + continue; + */ + ai.Censored = censor.CheckPath(ai.IsAltStream, ai.Name, !ai.IsDir); + RINOK(arc.GetItemMTime(i, ai.MTime, ai.MTimeDefined)); + RINOK(arc.GetItemSize(i, ai.Size, ai.SizeDefined)); + + { + 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.AddInReserved(ai); + } + return S_OK; +} + +struct CEnumDirItemUpdateCallback: public IEnumDirItemCallback +{ + IUpdateCallbackUI2 *Callback; + HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) + { + return Callback->ScanProgress(numFolders, numFiles, totalSize, path, isDir); + } +}; + +#if defined(_WIN32) && !defined(UNDER_CE) + +#include <mapi.h> + +#endif + +struct CRefSortPair +{ + int Len; + int Index; +}; + +#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } + +static int CompareRefSortPair(const CRefSortPair *a1, const CRefSortPair *a2, void *) +{ + RINOZ(-MyCompare(a1->Len, a2->Len)); + return MyCompare(a1->Index, a2->Index); +} + +static int GetNumSlashes(const FChar *s) +{ + for (int numSlashes = 0;;) + { + FChar c = *s++; + if (c == 0) + return numSlashes; + if ( + #ifdef _WIN32 + c == FTEXT('\\') || + #endif + c == FTEXT('/')) + numSlashes++; + } +} + +#ifdef _WIN32 +void ConvertToLongNames(NWildcard::CCensor &censor); +#endif + +HRESULT UpdateArchive( + CCodecs *codecs, + const CObjectVector<COpenType> &types, + const UString &cmdArcPath2, + NWildcard::CCensor &censor, + CUpdateOptions &options, + CUpdateErrorInfo &errorInfo, + IOpenCallbackUI *openCallback, + IUpdateCallbackUI2 *callback, + bool needSetPath) +{ + if (options.StdOutMode && options.EMailMode) + return E_FAIL; + + if (types.Size() > 1) + return E_NOTIMPL; + + bool renameMode = !options.RenamePairs.IsEmpty(); + if (renameMode) + { + if (options.Commands.Size() != 1) + return E_FAIL; + } + + if (options.DeleteAfterCompressing) + { + if (options.Commands.Size() != 1) + return E_NOTIMPL; + const CActionSet &as = options.Commands[0].ActionSet; + for (int i = 2; i < NPairState::kNumValues; i++) + if (as.StateActions[i] != NPairAction::kCompress) + return E_NOTIMPL; + } + + censor.AddPathsToCensor(options.PathMode); + #ifdef _WIN32 + ConvertToLongNames(censor); + #endif + censor.ExtendExclude(); + + + 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; + } + bool found = false; + if (options.SfxModule.Find(FCHAR_PATH_SEPARATOR) < 0) + { + const FString fullName = ::GetModuleDirPrefix() + options.SfxModule; + if (NFind::DoesFileExist(fullName)) + { + options.SfxModule = fullName; + found = true; + } + } + if (!found) + { + if (!NFind::DoesFileExist(options.SfxModule)) + { + errorInfo.SystemError = ::GetLastError(); + errorInfo.Message = L"7-Zip cannot find specified SFX module"; + errorInfo.FileName = options.SfxModule; + return E_FAIL; + } + } + } + + CArchiveLink arcLink; + + + if (needSetPath) + { + if (!options.InitFormatIndex(codecs, types, cmdArcPath2) || + !options.SetArcPath(codecs, cmdArcPath2)) + return E_NOTIMPL; + } + UString arcPath = options.ArchivePath.GetFinalPath(); + + if (cmdArcPath2.IsEmpty()) + { + if (options.MethodMode.Type.FormatIndex < 0) + throw "type of archive is not specified"; + } + else + { + NFind::CFileInfo fi; + if (!fi.Find(us2fs(arcPath))) + { + if (renameMode) + throw "can't find archive";; + if (options.MethodMode.Type.FormatIndex < 0) + { + if (!options.SetArcPath(codecs, cmdArcPath2)) + return E_NOTIMPL; + } + } + else + { + if (fi.IsDir()) + throw "there is no such archive"; + if (fi.IsDevice) + return E_NOTIMPL; + if (options.VolumesSizes.Size() > 0) + return E_NOTIMPL; + CObjectVector<COpenType> types; + // change it. + if (options.MethodMode.Type_Defined) + types.Add(options.MethodMode.Type); + // We need to set Properties to open archive only in some cases (WIM archives). + + CIntVector excl; + COpenOptions op; + #ifndef _SFX + op.props = &options.MethodMode.Properties; + #endif + op.codecs = codecs; + op.types = &types; + op.excludedFormats = ! + op.stdInMode = false; + op.stream = NULL; + op.filePath = arcPath; + + HRESULT result = arcLink.Open2(op, openCallback); + + if (result == E_ABORT) + return result; + + const wchar_t *errorArcType = NULL; + if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex > 0) + errorArcType = codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name; + RINOK(callback->OpenResult(arcPath, result, errorArcType)); + /* + if (result == S_FALSE) + return E_FAIL; + */ + 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; + + if (arc.ErrorInfo.ThereIsTail) + { + errorInfo.SystemError = (DWORD)E_NOTIMPL; + errorInfo.Message = L"There is some data block after the end of the archive"; + return E_NOTIMPL; + } + if (options.MethodMode.Type.FormatIndex < 0) + { + options.MethodMode.Type.FormatIndex = arcLink.GetArc()->FormatIndex; + if (!options.SetArcPath(codecs, cmdArcPath2)) + return E_NOTIMPL; + } + } + } + + if (options.MethodMode.Type.FormatIndex < 0) + { + options.MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveType(kDefaultArcType); + if (options.MethodMode.Type.FormatIndex < 0) + return E_NOTIMPL; + } + + bool thereIsInArchive = arcLink.IsOpen; + if (!thereIsInArchive && renameMode) + return E_FAIL; + + CDirItems dirItems; + CDirItem parentDirItem; + CDirItem *parentDirItem_Ptr = NULL; + + /* + FStringVector requestedPaths; + FStringVector *requestedPaths_Ptr = NULL; + if (options.DeleteAfterCompressing) + requestedPaths_Ptr = &requestedPaths; + */ + + 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; + if (!renameMode) + FOR_VECTOR (i, options.Commands) + if (options.Commands[i].ActionSet.NeedScanning()) + needScanning = true; + if (needScanning) + { + CEnumDirItemUpdateCallback enumCallback; + enumCallback.Callback = callback; + RINOK(callback->StartScanning()); + + dirItems.SymLinks = options.SymLinks.Val; + + #if defined(_WIN32) && !defined(UNDER_CE) + dirItems.ReadSecure = options.NtSecurity.Val; + #endif + + dirItems.ScanAltStreams = options.AltStreams.Val; + HRESULT res = EnumerateItems(censor, + options.PathMode, + options.AddPathPrefix, + dirItems, &enumCallback); + FOR_VECTOR (i, dirItems.ErrorPaths) + { + RINOK(callback->CanNotFindError(fs2us(dirItems.ErrorPaths[i]), dirItems.ErrorCodes[i])); + } + if (res != S_OK) + { + if (res != E_ABORT) + errorInfo.Message = L"Scanning error"; + return res; + } + RINOK(callback->FinishScanning()); + + if (censor.Pairs.Size() == 1) + { + NFind::CFileInfo fi; + FString prefix = us2fs(censor.Pairs[0].Prefix) + FTEXT("."); + // UString prefix = censor.Pairs[0].Prefix; + /* + if (prefix.Back() == WCHAR_PATH_SEPARATOR) + { + prefix.DeleteBack(); + } + */ + if (fi.Find(prefix)) + if (fi.IsDir()) + { + parentDirItem.Size = fi.Size; + parentDirItem.CTime = fi.CTime; + parentDirItem.ATime = fi.ATime; + parentDirItem.MTime = fi.MTime; + parentDirItem.Attrib = fi.Attrib; + parentDirItem_Ptr = &parentDirItem; + + int secureIndex = -1; + #if defined(_WIN32) && !defined(UNDER_CE) + if (options.NtSecurity.Val) + dirItems.AddSecurityItem(prefix, secureIndex); + #endif + parentDirItem.SecureIndex = secureIndex; + + parentDirItem_Ptr = &parentDirItem; + } + } + } + } + + FString tempDirPrefix; + bool usesTempDir = false; + + #ifdef _WIN32 + CTempDir tempDirectory; + if (options.EMailMode && options.EMailRemoveAfter) + { + tempDirectory.Create(kTempFolderPrefix); + tempDirPrefix = tempDirectory.GetPath(); + NormalizeDirPathPrefix(tempDirPrefix); + usesTempDir = true; + } + #endif + + CTempFiles tempFiles; + + bool createTempFile = false; + + if (!options.StdOutMode && options.UpdateArchiveItself) + { + CArchivePath &ap = options.Commands[0].ArchivePath; + ap = options.ArchivePath; + // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty()) + if ((thereIsInArchive || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0) + { + createTempFile = true; + ap.Temp = true; + if (!options.WorkingDir.IsEmpty()) + ap.TempPrefix = options.WorkingDir; + else + ap.TempPrefix = us2fs(ap.Prefix); + NormalizeDirPathPrefix(ap.TempPrefix); + } + } + + unsigned i; + for (i = 0; i < options.Commands.Size(); i++) + { + CArchivePath &ap = options.Commands[i].ArchivePath; + if (usesTempDir) + { + // Check it + ap.Prefix = fs2us(tempDirPrefix); + // ap.Temp = true; + // ap.TempPrefix = tempDirPrefix; + } + if (!options.StdOutMode && + (i > 0 || !createTempFile)) + { + const FString path = us2fs(ap.GetFinalPath()); + if (NFind::DoesFileOrDirExist(path)) + { + errorInfo.SystemError = 0; + errorInfo.Message = L"The file already exists"; + errorInfo.FileName = path; + return E_FAIL; + } + } + } + + CObjectVector<CArcItem> arcItems; + if (thereIsInArchive) + { + RINOK(EnumerateInArchiveItems( + // options.StoreAltStreams, + censor, arcLink.Arcs.Back(), arcItems)); + } + + /* + FStringVector processedFilePaths; + FStringVector *processedFilePaths_Ptr = NULL; + if (options.DeleteAfterCompressing) + processedFilePaths_Ptr = &processedFilePaths; + */ + + CByteBuffer processedItems; + if (options.DeleteAfterCompressing) + { + unsigned num = dirItems.Items.Size(); + processedItems.Alloc(num); + for (i = 0; i < num; i++) + processedItems[i] = 0; + } + + for (i = 0; i < options.Commands.Size(); i++) + { + const CArc *arc = thereIsInArchive ? arcLink.GetArc() : 0; + // IInArchiveExtra *archiveExtra = thereIsInArchive ? arcLink.GetArchiveExtra() : 0; + // IArchiveGetRootProps *archiveGetRootProps = thereIsInArchive ? arcLink.GetArchiveGetRootProps() : 0; + CUpdateArchiveCommand &command = options.Commands[i]; + UString name; + bool isUpdating; + if (options.StdOutMode) + { + name = L"stdout"; + isUpdating = arc != 0; + } + else + { + name = command.ArchivePath.GetFinalPath(); + isUpdating = (i == 0 && options.UpdateArchiveItself && arc != 0); + } + RINOK(callback->StartArchive(name, isUpdating)) + + RINOK(Compress(options, + codecs, + command.ActionSet, + arc, + command.ArchivePath, + arcItems, + options.DeleteAfterCompressing ? (Byte *)processedItems : NULL, + + dirItems, + parentDirItem_Ptr, + + tempFiles, + errorInfo, callback)); + + RINOK(callback->FinishArchive()); + } + + + if (thereIsInArchive) + { + RINOK(arcLink.Close()); + arcLink.Release(); + } + + tempFiles.Paths.Clear(); + if (createTempFile) + { + try + { + CArchivePath &ap = options.Commands[0].ArchivePath; + const FString &tempPath = ap.GetTempPath(); + if (thereIsInArchive) + if (!DeleteFileAlways(us2fs(arcPath))) + { + errorInfo.SystemError = ::GetLastError(); + errorInfo.Message = L"7-Zip cannot delete the file"; + errorInfo.FileName = us2fs(arcPath); + return E_FAIL; + } + if (!MyMoveFile(tempPath, us2fs(arcPath))) + { + errorInfo.SystemError = ::GetLastError(); + errorInfo.Message = L"7-Zip cannot move the file"; + errorInfo.FileName = tempPath; + errorInfo.FileName2 = us2fs(arcPath); + return E_FAIL; + } + } + catch(...) + { + throw; + } + } + + + #if defined(_WIN32) && !defined(UNDER_CE) + if (options.EMailMode) + { + NDLL::CLibrary mapiLib; + if (!mapiLib.Load(FTEXT("Mapi32.dll"))) + { + errorInfo.SystemError = ::GetLastError(); + errorInfo.Message = L"7-Zip cannot load Mapi32.dll"; + return E_FAIL; + } + + /* + LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments"); + if (fnSend == 0) + { + errorInfo.SystemError = ::GetLastError(); + errorInfo.Message = L"7-Zip cannot find MAPISendDocuments function"; + return E_FAIL; + } + */ + LPMAPISENDMAIL sendMail = (LPMAPISENDMAIL)mapiLib.GetProc("MAPISendMail"); + if (sendMail == 0) + { + errorInfo.SystemError = ::GetLastError(); + errorInfo.Message = L"7-Zip cannot find MAPISendMail function"; + return E_FAIL; + } + + FStringVector fullPaths; + unsigned i; + for (i = 0; i < options.Commands.Size(); i++) + { + CArchivePath &ap = options.Commands[i].ArchivePath; + FString arcPath; + if (!MyGetFullPathName(us2fs(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 = fs2us(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); + + MapiFileDesc f; + memset(&f, 0, sizeof(f)); + f.nPosition = 0xFFFFFFFF; + f.lpszPathName = (char *)(const char *)path; + f.lpszFileName = (char *)(const char *)name; + + MapiMessage m; + memset(&m, 0, sizeof(m)); + m.nFileCount = 1; + m.lpFiles = &f; + + const AString addr = GetAnsiString(options.EMailAddress); + MapiRecipDesc rec; + if (!addr.IsEmpty()) + { + memset(&rec, 0, sizeof(rec)); + rec.ulRecipClass = MAPI_TO; + rec.lpszAddress = (char *)(const char *)addr; + m.nRecipCount = 1; + m.lpRecips = &rec; + } + + sendMail((LHANDLE)0, 0, &m, MAPI_DIALOG, 0); + } + } + #endif + + if (options.DeleteAfterCompressing) + { + CRecordVector<CRefSortPair> pairs; + FStringVector foldersNames; + for (i = 0; i < dirItems.Items.Size(); i++) + { + const CDirItem &dirItem = dirItems.Items[i]; + FString phyPath = us2fs(dirItems.GetPhyPath(i)); + if (dirItem.IsDir()) + { + CRefSortPair pair; + pair.Index = i; + pair.Len = GetNumSlashes(phyPath); + pairs.Add(pair); + } + else + { + if (processedItems[i] != 0 || dirItem.Size == 0) + { + DeleteFileAlways(phyPath); + } + else + { + // file was skipped + /* + errorInfo.SystemError = 0; + errorInfo.Message = L"file was not processed"; + errorInfo.FileName = phyPath; + return E_FAIL; + */ + } + } + } + + pairs.Sort(CompareRefSortPair, NULL); + for (i = 0; i < pairs.Size(); i++) + { + FString phyPath = us2fs(dirItems.GetPhyPath(pairs[i].Index)); + if (NFind::DoesDirExist(phyPath)) + { + // printf("delete %S\n", phyPath); + RemoveDir(phyPath); + } + } + } + return S_OK; +} diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Update.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Update.h new file mode 100644 index 000000000..b2fdb4647 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/Update.h @@ -0,0 +1,188 @@ +// Update.h + +#ifndef __COMMON_UPDATE_H +#define __COMMON_UPDATE_H + +#include "../../../Common/Wildcard.h" + +#include "ArchiveOpenCallback.h" +#include "LoadCodecs.h" +#include "OpenArchive.h" +#include "Property.h" +#include "UpdateAction.h" +#include "UpdateCallback.h" + +enum EArcNameMode +{ + k_ArcNameMode_Smart, + k_ArcNameMode_Exact, + k_ArcNameMode_Add, +}; + +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; + FString TempPrefix; // path(folder) for temp location + FString TempPostfix; + + CArchivePath(): Temp(false) {}; + + void ParseFromPath(const UString &path, EArcNameMode mode); + UString GetPathWithoutExt() const { return Prefix + Name; } + UString GetFinalPath() const; + UString GetFinalVolPath() const; + FString GetTempPath() const; +}; + +struct CUpdateArchiveCommand +{ + UString UserArchivePath; + CArchivePath ArchivePath; + NUpdateArchive::CActionSet ActionSet; +}; + +struct CCompressionMethodMode +{ + bool Type_Defined; + COpenType Type; + CObjectVector<CProperty> Properties; + + CCompressionMethodMode(): Type_Defined(false) {} +}; + +namespace NRecursedType { enum EEnum +{ + kRecursed, + kWildcardOnlyRecursed, + kNonRecursed +};} + +struct CRenamePair +{ + UString OldName; + UString NewName; + bool WildcardParsing; + NRecursedType::EEnum RecursedType; + + CRenamePair(): WildcardParsing(true), RecursedType(NRecursedType::kNonRecursed) {} + + bool Prepare(); + bool GetNewPath(bool isFolder, const UString &src, UString &dest) const; +}; + +struct CUpdateOptions +{ + CCompressionMethodMode MethodMode; + + CObjectVector<CUpdateArchiveCommand> Commands; + bool UpdateArchiveItself; + CArchivePath ArchivePath; + EArcNameMode ArcNameMode; + + bool SfxMode; + FString SfxModule; + + bool OpenShareForWrite; + + bool StdInMode; + UString StdInFileName; + bool StdOutMode; + + bool EMailMode; + bool EMailRemoveAfter; + UString EMailAddress; + + FString WorkingDir; + NWildcard::ECensorPathMode PathMode; + UString AddPathPrefix; + + CBoolPair NtSecurity; + CBoolPair AltStreams; + CBoolPair HardLinks; + CBoolPair SymLinks; + + bool DeleteAfterCompressing; + + bool SetArcMTime; + + CObjectVector<CRenamePair> RenamePairs; + + bool InitFormatIndex(const CCodecs *codecs, const CObjectVector<COpenType> &types, const UString &arcPath); + bool SetArcPath(const CCodecs *codecs, const UString &arcPath); + + CUpdateOptions(): + UpdateArchiveItself(true), + ArcNameMode(k_ArcNameMode_Smart), + SfxMode(false), + OpenShareForWrite(false), + StdInMode(false), + StdOutMode(false), + EMailMode(false), + EMailRemoveAfter(false), + PathMode(NWildcard::k_RelatPath), + + DeleteAfterCompressing(false), + SetArcMTime(false) + + {}; + + void SetActionCommand_Add() + { + Commands.Clear(); + CUpdateArchiveCommand c; + c.ActionSet = NUpdateArchive::k_ActionSet_Add; + Commands.Add(c); + } + + CRecordVector<UInt64> VolumesSizes; +}; + +struct CErrorInfo +{ + DWORD SystemError; + FString FileName; + FString FileName2; + UString Message; + // UStringVector ErrorPaths; + // CRecordVector<DWORD> ErrorCodes; + CErrorInfo(): SystemError(0) {}; +}; + +struct CUpdateErrorInfo: public CErrorInfo +{ +}; + +#define INTERFACE_IUpdateCallbackUI2(x) \ + INTERFACE_IUpdateCallbackUI(x) \ + virtual HRESULT OpenResult(const wchar_t *name, HRESULT result, const wchar_t *errorArcType) x; \ + virtual HRESULT StartScanning() x; \ + virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) 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 CObjectVector<COpenType> &types, + const UString &cmdArcPath2, + NWildcard::CCensor &censor, + CUpdateOptions &options, + CUpdateErrorInfo &errorInfo, + IOpenCallbackUI *openCallback, + IUpdateCallbackUI2 *callback, + bool needSetPath); + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateAction.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateAction.cpp new file mode 100644 index 000000000..a80db7212 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateAction.cpp @@ -0,0 +1,64 @@ +// UpdateAction.cpp + +#include "StdAfx.h" + +#include "UpdateAction.h" + +namespace NUpdateArchive { + +const CActionSet k_ActionSet_Add = +{{ + NPairAction::kCopy, + NPairAction::kCopy, + NPairAction::kCompress, + NPairAction::kCompress, + NPairAction::kCompress, + NPairAction::kCompress, + NPairAction::kCompress +}}; + +const CActionSet k_ActionSet_Update = +{{ + NPairAction::kCopy, + NPairAction::kCopy, + NPairAction::kCompress, + NPairAction::kCopy, + NPairAction::kCompress, + NPairAction::kCopy, + NPairAction::kCompress +}}; + +const CActionSet k_ActionSet_Fresh = +{{ + NPairAction::kCopy, + NPairAction::kCopy, + NPairAction::kIgnore, + NPairAction::kCopy, + NPairAction::kCompress, + NPairAction::kCopy, + NPairAction::kCompress +}}; + +const CActionSet k_ActionSet_Sync = +{{ + NPairAction::kCopy, + NPairAction::kIgnore, + NPairAction::kCompress, + NPairAction::kCopy, + NPairAction::kCompress, + NPairAction::kCopy, + NPairAction::kCompress, +}}; + +const CActionSet k_ActionSet_Delete = +{{ + NPairAction::kCopy, + NPairAction::kIgnore, + NPairAction::kIgnore, + NPairAction::kIgnore, + NPairAction::kIgnore, + NPairAction::kIgnore, + NPairAction::kIgnore +}}; + +} diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateAction.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateAction.h new file mode 100644 index 000000000..b6645cbdd --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateAction.h @@ -0,0 +1,66 @@ +// UpdateAction.h + +#ifndef __UPDATE_ACTION_H +#define __UPDATE_ACTION_H + +namespace NUpdateArchive { + + namespace NPairState + { + const unsigned 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 IsEqualTo(const CActionSet &a) const + { + for (unsigned i = 0; i < NPairState::kNumValues; i++) + if (StateActions[i] != a.StateActions[i]) + return false; + return true; + } + + bool NeedScanning() const + { + unsigned 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 k_ActionSet_Add; + extern const CActionSet k_ActionSet_Update; + extern const CActionSet k_ActionSet_Fresh; + extern const CActionSet k_ActionSet_Sync; + extern const CActionSet k_ActionSet_Delete; +} + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.cpp new file mode 100644 index 000000000..609ece856 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.cpp @@ -0,0 +1,576 @@ +// UpdateCallback.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/Synchronization.h" + +#include "../../Common/FileStreams.h" +#include "../../Common/StreamObjects.h" + +#include "UpdateCallback.h" + +#if defined(_WIN32) && !defined(UNDER_CE) +#define _USE_SECURITY_CODE +#include "../../../Windows/SecurityUtils.h" +#endif + +using namespace NWindows; +using namespace NFile; + +#ifdef _USE_SECURITY_CODE +bool InitLocalPrivileges(); +#endif + +CArchiveUpdateCallback::CArchiveUpdateCallback(): + Callback(0), + ShareForWrite(false), + StdInMode(false), + DirItems(0), + ArcItems(0), + UpdatePairs(0), + NewNames(0), + KeepOriginalItemNames(false), + ProcessedItemsStatuses(NULL), + ParentDirItem(NULL), + StoreNtSecurity(false), + StoreHardLinks(false), + StoreSymLinks(false), + _hardIndex_From((UInt32)(Int32)-1) +{ + #ifdef _USE_SECURITY_CODE + _saclEnabled = InitLocalPrivileges(); + #endif +} + + +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 +} + + +/* +static const STATPROPSTG kProps[] = +{ + { 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(kProps, ARRAY_SIZE(kProps), 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) *newData = BoolToInt(up.NewData); + if (newProps) *newProps = BoolToInt(up.NewProps); + if (indexInArchive) + { + *indexInArchive = (UInt32)(Int32)-1; + if (up.ExistInArchive()) + *indexInArchive = (ArcItems == 0) ? up.ArcIndex : (*ArcItems)[up.ArcIndex].IndexInServer; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidIsDir: prop = true; break; + case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->Attrib; break; + case kpidCTime: if (ParentDirItem) prop = ParentDirItem->CTime; break; + case kpidATime: if (ParentDirItem) prop = ParentDirItem->ATime; break; + case kpidMTime: if (ParentDirItem) prop = ParentDirItem->MTime; break; + } + prop.Detach(value); + return S_OK; +} + +STDMETHODIMP CArchiveUpdateCallback::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType) +{ + *parentType = NParentType::kDir; + *parent = (UInt32)(Int32)-1; + return S_OK; +} + +STDMETHODIMP CArchiveUpdateCallback::GetNumRawProps(UInt32 *numProps) +{ + *numProps = 0; + if (StoreNtSecurity) + *numProps = 1; + return S_OK; +} + +STDMETHODIMP CArchiveUpdateCallback::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) +{ + *name = NULL; + *propID = kpidNtSecure; + return S_OK; +} + +STDMETHODIMP CArchiveUpdateCallback::GetRootRawProp(PROPID + #ifdef _USE_SECURITY_CODE + propID + #endif + , const void **data, UInt32 *dataSize, UInt32 *propType) +{ + *data = 0; + *dataSize = 0; + *propType = 0; + if (!StoreNtSecurity) + return S_OK; + #ifdef _USE_SECURITY_CODE + if (propID == kpidNtSecure) + { + if (StdInMode) + return S_OK; + + if (ParentDirItem) + { + if (ParentDirItem->SecureIndex < 0) + return S_OK; + const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[ParentDirItem->SecureIndex]; + *data = buf; + *dataSize = (UInt32)buf.Size(); + *propType = NPropDataType::kRaw; + return S_OK; + } + + if (GetRootProps) + return GetRootProps->GetRootRawProp(propID, data, dataSize, propType); + } + #endif + return S_OK; +} + +// #ifdef _USE_SECURITY_CODE +// #endif + +STDMETHODIMP CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) +{ + *data = 0; + *dataSize = 0; + *propType = 0; + + if (propID == kpidNtSecure || + propID == kpidNtReparse) + { + if (StdInMode) + return S_OK; + + const CUpdatePair2 &up = (*UpdatePairs)[index]; + if (up.UseArcProps && up.ExistInArchive() && GetRawProps) + return GetRawProps->GetRawProp( + ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex, + propID, data, dataSize, propType); + + { + const CUpdatePair2 &up = (*UpdatePairs)[index]; + /* + if (!up.NewData) + return E_FAIL; + */ + if (up.IsAnti) + return S_OK; + + #ifndef UNDER_CE + const CDirItem &di = DirItems->Items[up.DirIndex]; + #endif + + #ifdef _USE_SECURITY_CODE + if (propID == kpidNtSecure) + { + if (!StoreNtSecurity) + return S_OK; + if (di.SecureIndex < 0) + return S_OK; + const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[di.SecureIndex]; + *data = buf; + *dataSize = (UInt32)buf.Size(); + *propType = NPropDataType::kRaw; + } + else + #endif + { + // propID == kpidNtReparse + if (!StoreSymLinks) + return S_OK; + #if 0 // #ifndef UNDER_CE + const CByteBuffer *buf = &di.ReparseData2; + if (buf->Size() == 0) + buf = &di.ReparseData; + if (buf->Size() != 0) + { + *data = *buf; + *dataSize = (UInt32)buf->Size(); + *propType = NPropDataType::kRaw; + } + #endif + } + + return S_OK; + } + } + + return S_OK; +} + +#ifndef UNDER_CE + +static UString GetRelativePath(const UString &to, const UString &from) +{ + UStringVector partsTo, partsFrom; + SplitPathToParts(to, partsTo); + SplitPathToParts(from, partsFrom); + + unsigned i; + for (i = 0;; i++) + { + if (i + 1 >= partsFrom.Size() || + i + 1 >= partsTo.Size()) + break; + if (CompareFileNames(partsFrom[i], partsTo[i]) != 0) + break; + } + + if (i == 0) + { + #ifdef _WIN32 + if (NName::IsDrivePath(to) || + NName::IsDrivePath(from)) + return to; + #endif + } + + UString s; + unsigned k; + + for (k = i + 1; k < partsFrom.Size(); k++) + s += L".." WSTRING_PATH_SEPARATOR; + + for (k = i; k < partsTo.Size(); k++) + { + if (k != i) + s += WCHAR_PATH_SEPARATOR; + s += partsTo[k]; + } + + return s; +} + +#endif + +STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + const CUpdatePair2 &up = (*UpdatePairs)[index]; + NCOM::CPropVariant prop; + + if (up.NewData) + { + /* + if (propID == kpidIsHardLink) + { + prop = _isHardLink; + prop.Detach(value); + return S_OK; + } + */ + if (propID == kpidSymLink) + { + if (index == _hardIndex_From) + { + prop.Detach(value); + return S_OK; + } + if (up.DirIndex >= 0) + { + #if 0 // #ifndef UNDER_CE + const CDirItem &di = DirItems->Items[up.DirIndex]; + // if (di.IsDir()) + { + CReparseAttr attr; + if (attr.Parse(di.ReparseData, di.ReparseData.Size())) + { + UString simpleName = attr.GetPath(); + if (attr.IsRelative()) + prop = simpleName; + else + { + const UString phyPath = DirItems->GetPhyPath(up.DirIndex); + FString fullPath; + if (NDir::MyGetFullPathName(us2fs(phyPath), fullPath)) + { + prop = GetRelativePath(simpleName, fs2us(fullPath)); + } + } + prop.Detach(value); + return S_OK; + } + } + #endif + } + } + else if (propID == kpidHardLink) + { + if (index == _hardIndex_From) + { + const CKeyKeyValPair &pair = _map[_hardIndex_To]; + const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value]; + prop = DirItems->GetLogPath(up2.DirIndex); + prop.Detach(value); + return S_OK; + } + if (up.DirIndex >= 0) + { + prop.Detach(value); + return S_OK; + } + } + } + + if (up.IsAnti + && propID != kpidIsDir + && propID != kpidPath + && propID != kpidIsAltStream) + { + switch (propID) + { + case kpidSize: prop = (UInt64)0; break; + case kpidIsAnti: prop = true; break; + } + } + else if (propID == kpidPath && up.NewNameIndex >= 0) + prop = (*NewNames)[up.NewNameIndex]; + else if (propID == kpidShortName && up.NewNameIndex >= 0 && up.IsMainRenameItem) + { + // we can generate new ShortName here; + } + else if ((up.UseArcProps + || (KeepOriginalItemNames && (propID == kpidPath || propID == kpidIsAltStream))) + && up.ExistInArchive() && Archive) + return Archive->GetProperty(ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex, propID, value); + else 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; + case kpidIsAltStream: prop = di.IsAltStream; break; + #if defined(_WIN32) && !defined(UNDER_CE) + // case kpidShortName: prop = di.ShortName; break; + #endif + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +static NSynchronization::CCriticalSection CS; + +STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream) +{ + COM_TRY_BEGIN + *inStream = NULL; + const CUpdatePair2 &up = (*UpdatePairs)[index]; + if (!up.NewData) + return E_FAIL; + + RINOK(Callback->CheckBreak()); + RINOK(Callback->Finilize()); + + bool isDir = IsDir(up); + + if (up.IsAnti) + { + UString name; + if (up.ArcIndex >= 0) + name = (*ArcItems)[up.ArcIndex].Name; + else if (up.DirIndex >= 0) + name = DirItems->GetLogPath(up.DirIndex); + RINOK(Callback->GetStream(name, true)); + + /* 9.33: fixed. Handlers expect real stream object for files, even for anti-file. + so we return empty stream */ + + if (!isDir) + { + CBufInStream *inStreamSpec = new CBufInStream(); + CMyComPtr<ISequentialInStream> inStreamLoc = inStreamSpec; + inStreamSpec->Init(NULL, 0); + *inStream = inStreamLoc.Detach(); + } + return S_OK; + } + + RINOK(Callback->GetStream(DirItems->GetLogPath(up.DirIndex), false)); + + if (isDir) + return S_OK; + + if (StdInMode) + { + CStdInFileStream *inStreamSpec = new CStdInFileStream; + CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec); + *inStream = inStreamLoc.Detach(); + } + else + { + CInFileStream *inStreamSpec = new CInFileStream; + CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec); + + inStreamSpec->SupportHardLinks = StoreHardLinks; + + const UString path = DirItems->GetPhyPath(up.DirIndex); + + #if defined(_WIN32) && !defined(UNDER_CE) + if (DirItems->Items[up.DirIndex].AreReparseData()) + { + if (!inStreamSpec->File.OpenReparse(us2fs(path))) + { + return Callback->OpenFileError(path, ::GetLastError()); + } + } + else + #endif + if (!inStreamSpec->OpenShared(us2fs(path), ShareForWrite)) + { + return Callback->OpenFileError(path, ::GetLastError()); + } + +#if 0 // FIXME + if (StoreHardLinks) + { + CStreamFileProps props; + if (inStreamSpec->GetProps2(&props) == S_OK) + { + if (props.NumLinks > 1) + { + CKeyKeyValPair pair; + pair.Key1 = props.VolID; + pair.Key2 = props.FileID_Low; + pair.Value = index; + unsigned numItems = _map.Size(); + unsigned pairIndex = _map.AddToUniqueSorted2(pair); + if (numItems == _map.Size()) + { + // const CKeyKeyValPair &pair2 = _map.Pairs[pairIndex]; + _hardIndex_From = index; + _hardIndex_To = pairIndex; + // we could return NULL as stream, but it's better to return real stream + // return S_OK; + } + } + } + } +#endif + + if (ProcessedItemsStatuses) + { + NSynchronization::CCriticalSectionLock lock(CS); + ProcessedItemsStatuses[up.DirIndex] = 1; + } + *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 + FChar temp[16]; + ConvertUInt32ToString(index + 1, temp); + FString res = temp; + while (res.Len() < 2) + res.InsertAtFront(FTEXT('0')); + FString fileName = VolName; + fileName += L'.'; + fileName += res; + fileName += VolExt; + COutFileStream *streamSpec = new COutFileStream; + CMyComPtr<ISequentialOutStream> streamLoc(streamSpec); + if (!streamSpec->Create(fileName, false)) + return ::GetLastError(); + *volumeStream = streamLoc.Detach(); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) +{ + COM_TRY_BEGIN + return Callback->CryptoGetTextPassword2(passwordIsDefined, password); + COM_TRY_END +} + +STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password) +{ + COM_TRY_BEGIN + return Callback->CryptoGetTextPassword(password); + COM_TRY_END +} diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.h new file mode 100644 index 000000000..81982e61d --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.h @@ -0,0 +1,122 @@ +// UpdateCallback.h + +#ifndef __UPDATE_CALLBACK_H +#define __UPDATE_CALLBACK_H + +#include "../../../Common/MyCom.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) +}; + +struct CKeyKeyValPair +{ + UInt64 Key1; + UInt64 Key2; + unsigned Value; + + int Compare(const CKeyKeyValPair &a) const + { + if (Key1 < a.Key1) return -1; + if (Key1 > a.Key1) return 1; + return MyCompare(Key2, a.Key2); + } +}; + + +class CArchiveUpdateCallback: + public IArchiveUpdateCallback2, + public IArchiveGetRawProps, + public IArchiveGetRootProps, + public ICryptoGetTextPassword2, + public ICryptoGetTextPassword, + public ICompressProgressInfo, + public CMyUnknownImp +{ + #if defined(_WIN32) && !defined(UNDER_CE) + bool _saclEnabled; + #endif + CRecordVector<CKeyKeyValPair> _map; + + UInt32 _hardIndex_From; + UInt32 _hardIndex_To; + +public: + MY_UNKNOWN_IMP6( + IArchiveUpdateCallback2, + IArchiveGetRawProps, + IArchiveGetRootProps, + ICryptoGetTextPassword2, + ICryptoGetTextPassword, + ICompressProgressInfo) + + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); + + INTERFACE_IArchiveUpdateCallback2(;) + INTERFACE_IArchiveGetRawProps(;) + INTERFACE_IArchiveGetRootProps(;) + + STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password); + STDMETHOD(CryptoGetTextPassword)(BSTR *password); + + CRecordVector<UInt64> VolumesSizes; + FString VolName; + FString VolExt; + + IUpdateCallbackUI *Callback; + + bool ShareForWrite; + bool StdInMode; + + const CDirItems *DirItems; + const CDirItem *ParentDirItem; + + const CObjectVector<CArcItem> *ArcItems; + const CRecordVector<CUpdatePair2> *UpdatePairs; + const UStringVector *NewNames; + CMyComPtr<IInArchive> Archive; + CMyComPtr<IArchiveGetRawProps> GetRawProps; + CMyComPtr<IArchiveGetRootProps> GetRootProps; + + bool KeepOriginalItemNames; + bool StoreNtSecurity; + bool StoreHardLinks; + bool StoreSymLinks; + + Byte *ProcessedItemsStatuses; + + CArchiveUpdateCallback(); + + bool IsDir(const CUpdatePair2 &up) const + { + if (up.DirIndex >= 0) + return DirItems->Items[up.DirIndex].IsDir(); + else if (up.ArcIndex >= 0) + return (*ArcItems)[up.ArcIndex].IsDir; + return false; + } +}; + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdatePair.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdatePair.cpp new file mode 100644 index 000000000..95afdd694 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdatePair.cpp @@ -0,0 +1,233 @@ +// UpdatePair.cpp + +#include "StdAfx.h" + +#include <time.h> + +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/TimeUtils.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 char *k_Duplicate_inArc_Message = "Duplicate filename in archive:"; +static const char *k_Duplicate_inDir_Message = "Duplicate filename on disk:"; +static const char *k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):"; + +static void ThrowError(const char *message, const UString &s1, const UString &s2) +{ + UString m; + m.SetFromAscii(message); + m += L'\n'; m += s1; + m += L'\n'; m += s2; + throw m; +} + +static int CompareArcItemsBase(const CArcItem &ai1, const CArcItem &ai2) +{ + int res = CompareFileNames(ai1.Name, ai2.Name); + if (res != 0) + return res; + if (ai1.IsDir != ai2.IsDir) + return ai1.IsDir ? -1 : 1; + return 0; +} + +static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param) +{ + unsigned i1 = *p1; + unsigned i2 = *p2; + const CObjectVector<CArcItem> &arcItems = *(const CObjectVector<CArcItem> *)param; + int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]); + if (res != 0) + return res; + return MyCompare(i1, i2); +} + +void GetUpdatePairInfoList( + const CDirItems &dirItems, + const CObjectVector<CArcItem> &arcItems, + NFileTimeType::EEnum fileTimeType, + CRecordVector<CUpdatePair> &updatePairs) +{ + CUIntVector dirIndices, arcIndices; + + unsigned numDirItems = dirItems.Items.Size(); + unsigned numArcItems = arcItems.Size(); + + CIntArr duplicatedArcItem(numArcItems); + { + int *vals = &duplicatedArcItem[0]; + for (unsigned i = 0; i < numArcItems; i++) + vals[i] = 0; + } + + { + arcIndices.ClearAndSetSize(numArcItems); + { + unsigned *vals = &arcIndices[0]; + for (unsigned i = 0; i < numArcItems; i++) + vals[i] = i; + } + arcIndices.Sort(CompareArcItems, (void *)&arcItems); + for (unsigned i = 0; i + 1 < numArcItems; i++) + if (CompareArcItemsBase( + arcItems[arcIndices[i]], + arcItems[arcIndices[i + 1]]) == 0) + { + duplicatedArcItem[i] = 1; + duplicatedArcItem[i + 1] = -1; + } + } + + UStringVector dirNames; + { + dirNames.ClearAndReserve(numDirItems); + unsigned i; + for (i = 0; i < numDirItems; i++) + dirNames.AddInReserved(dirItems.GetLogPath(i)); + SortFileNames(dirNames, dirIndices); + for (i = 0; i + 1 < numDirItems; i++) + { + const UString &s1 = dirNames[dirIndices[i]]; + const UString &s2 = dirNames[dirIndices[i + 1]]; + if (CompareFileNames(s1, s2) == 0) + ThrowError(k_Duplicate_inDir_Message, s1, s2); + } + } + + unsigned dirIndex = 0; + unsigned arcIndex = 0; + + int prevHostFile = -1; + const UString *prevHostName = NULL; + + while (dirIndex < numDirItems || arcIndex < numArcItems) + { + CUpdatePair pair; + + int dirIndex2 = -1; + int arcIndex2 = -1; + const CDirItem *di = NULL; + const CArcItem *ai = NULL; + + int compareResult = -1; + const UString *name = NULL; + + if (dirIndex < numDirItems) + { + dirIndex2 = dirIndices[dirIndex]; + di = &dirItems.Items[dirIndex2]; + } + + if (arcIndex < numArcItems) + { + arcIndex2 = arcIndices[arcIndex]; + ai = &arcItems[arcIndex2]; + compareResult = 1; + if (dirIndex < numDirItems) + { + compareResult = CompareFileNames(dirNames[dirIndex2], ai->Name); + if (compareResult == 0) + { + if (di->IsDir() != ai->IsDir) + compareResult = (ai->IsDir ? 1 : -1); + } + } + } + + if (compareResult < 0) + { + name = &dirNames[dirIndex2]; + pair.State = NUpdateArchive::NPairState::kOnlyOnDisk; + pair.DirIndex = dirIndex2; + dirIndex++; + } + else if (compareResult > 0) + { + name = &ai->Name; + pair.State = ai->Censored ? + NUpdateArchive::NPairState::kOnlyInArchive: + NUpdateArchive::NPairState::kNotMasked; + pair.ArcIndex = arcIndex2; + arcIndex++; + } + else + { + int dupl = duplicatedArcItem[arcIndex]; + if (dupl != 0) + ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[arcIndex + dupl]].Name); + + name = &dirNames[dirIndex2]; + if (!ai->Censored) + ThrowError(k_NotCensoredCollision_Message, *name, 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++; + } + + if ((di && di->IsAltStream) || + (ai && ai->IsAltStream)) + { + if (prevHostName) + { + unsigned hostLen = prevHostName->Len(); + if (name->Len() > hostLen) + if ((*name)[hostLen] == ':' && CompareFileNames(*prevHostName, name->Left(hostLen)) == 0) + pair.HostIndex = prevHostFile; + } + } + else + { + prevHostFile = updatePairs.Size(); + prevHostName = name; + } + + updatePairs.Add(pair); + } + + updatePairs.ReserveDown(); +} diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdatePair.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdatePair.h new file mode 100644 index 000000000..296d3b097 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdatePair.h @@ -0,0 +1,27 @@ +// 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; + int HostIndex; // >= 0 for alt streams only, contains index of host pair + + CUpdatePair(): ArcIndex(-1), DirIndex(-1), HostIndex(-1) {} +}; + +void GetUpdatePairInfoList( + const CDirItems &dirItems, + const CObjectVector<CArcItem> &arcItems, + NFileTimeType::EEnum fileTimeType, + CRecordVector<CUpdatePair> &updatePairs); + +#endif diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.cpp new file mode 100644 index 000000000..2c4c28583 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.cpp @@ -0,0 +1,73 @@ +// 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<CUpdatePair> &updatePairs, + const CActionSet &actionSet, + CRecordVector<CUpdatePair2> &operationChain, + IUpdateProduceCallback *callback) +{ + FOR_VECTOR (i, updatePairs) + { + const CUpdatePair &pair = updatePairs[i]; + + CUpdatePair2 up2; + up2.DirIndex = pair.DirIndex; + up2.ArcIndex = pair.ArcIndex; + up2.NewData = up2.NewProps = true; + up2.UseArcProps = false; + + 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; + if (pair.State == NPairState::kOnlyInArchive) + { + if (pair.HostIndex >= 0) + { + /* + ignore alt stream if + 1) no such alt stream in Disk + 2) there is Host file in disk + */ + if (updatePairs[pair.HostIndex].DirIndex >= 0) + continue; + } + } + up2.NewData = up2.NewProps = false; + up2.UseArcProps = true; + break; + + case NPairAction::kCompress: + if (pair.State == NPairState::kOnlyInArchive || + pair.State == NPairState::kNotMasked) + throw kUpdateActionSetCollision; + break; + + case NPairAction::kCompressAsAnti: + up2.IsAnti = true; + up2.UseArcProps = (pair.ArcIndex >= 0); + break; + } + operationChain.Add(up2); + } + operationChain.ReserveDown(); +} diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.h b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.h new file mode 100644 index 000000000..ef7b0f7a3 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.h @@ -0,0 +1,55 @@ +// UpdateProduce.h + +#ifndef __UPDATE_PRODUCE_H +#define __UPDATE_PRODUCE_H + +#include "UpdatePair.h" + +struct CUpdatePair2 +{ + bool NewData; + bool NewProps; + bool UseArcProps; // if (UseArcProps && NewProps), we want to change only some properties. + bool IsAnti; // if (!IsAnti) we use other ways to detect Anti status + + int DirIndex; + int ArcIndex; + int NewNameIndex; + + bool IsMainRenameItem; + + void SetAs_NoChangeArcItem(int arcIndex) + { + NewData = NewProps = false; + UseArcProps = true; + IsAnti = false; + ArcIndex = arcIndex; + } + + bool ExistOnDisk() const { return DirIndex != -1; } + bool ExistInArchive() const { return ArcIndex != -1; } + + CUpdatePair2(): + NewData(false), + NewProps(false), + UseArcProps(false), + IsAnti(false), + DirIndex(-1), + ArcIndex(-1), + NewNameIndex(-1), + IsMainRenameItem(false) + {} +}; + +struct IUpdateProduceCallback +{ + virtual HRESULT ShowDeleteFile(int arcIndex) = 0; +}; + +void UpdateProduce( + const CRecordVector<CUpdatePair> &updatePairs, + const NUpdateArchive::CActionSet &actionSet, + CRecordVector<CUpdatePair2> &operationChain, + IUpdateProduceCallback *callback); + +#endif |