This commit is contained in:
Igor Pavlov
2005-05-30 00:00:00 +00:00
committed by Kornel Lesiński
parent 8c1b5c7b7e
commit 3c510ba80b
926 changed files with 40559 additions and 23519 deletions

View File

@@ -0,0 +1,830 @@
// ArchiveCommandLine.cpp
#include "StdAfx.h"
#include <io.h>
#include <stdio.h>
#include "Common/ListFileUtils.h"
#include "Common/StringConvert.h"
#include "Common/StringToInt.h"
#include "Windows/FileName.h"
#include "Windows/FileDir.h"
#ifdef _WIN32
#include "Windows/FileMapping.h"
#include "Windows/Synchronization.h"
#endif
#include "ArchiveCommandLine.h"
#include "UpdateAction.h"
#include "Update.h"
#include "ArchiverInfo.h"
#include "SortUtils.h"
#include "EnumDirItems.h"
using namespace NCommandLineParser;
using namespace NWindows;
using namespace NFile;
static const int kNumSwitches = 24;
namespace NKey {
enum Enum
{
kHelp1 = 0,
kHelp2,
kDisableHeaders,
kDisablePercents,
kArchiveType,
kYes,
kPassword,
kProperty,
kOutputDir,
kWorkingDir,
kInclude,
kExclude,
kArInclude,
kArExclude,
kNoArName,
kUpdate,
kVolume,
kRecursed,
kSfx,
kStdIn,
kStdOut,
kOverwrite,
kEmail,
kShowDialog
};
}
static const wchar_t kRecursedIDChar = 'R';
static const wchar_t *kRecursedPostCharSet = L"0-";
static const wchar_t *kDefaultArchiveType = L"7z";
static const wchar_t *kSFXExtension = L"exe";
namespace NRecursedPostCharIndex {
enum EEnum
{
kWildCardRecursionOnly = 0,
kNoRecursion = 1
};
}
static const char kImmediateNameID = '!';
static const char kMapNameID = '#';
static const char kFileListID = '@';
static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be
static const wchar_t *kOverwritePostCharSet = L"asut";
NExtract::NOverwriteMode::EEnum k_OverwriteModes[] =
{
NExtract::NOverwriteMode::kWithoutPrompt,
NExtract::NOverwriteMode::kSkipExisting,
NExtract::NOverwriteMode::kAutoRename,
NExtract::NOverwriteMode::kAutoRenameExisting
};
static const CSwitchForm kSwitchForms[kNumSwitches] =
{
{ L"?", NSwitchType::kSimple, false },
{ L"H", NSwitchType::kSimple, false },
{ L"BA", NSwitchType::kSimple, false },
{ L"BD", NSwitchType::kSimple, false },
{ L"T", NSwitchType::kUnLimitedPostString, false, 1 },
{ L"Y", NSwitchType::kSimple, false },
{ L"P", NSwitchType::kUnLimitedPostString, false, 0 },
{ L"M", NSwitchType::kUnLimitedPostString, true, 1 },
{ L"O", NSwitchType::kUnLimitedPostString, false, 1 },
{ L"W", NSwitchType::kUnLimitedPostString, false, 0 },
{ L"I", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
{ L"X", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
{ L"AI", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
{ L"AX", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
{ L"AN", NSwitchType::kSimple, false },
{ L"U", NSwitchType::kUnLimitedPostString, true, 1},
{ L"V", NSwitchType::kUnLimitedPostString, true, 1},
{ L"R", NSwitchType::kPostChar, false, 0, 0, kRecursedPostCharSet },
{ L"SFX", NSwitchType::kUnLimitedPostString, false, 0 },
{ L"SI", NSwitchType::kUnLimitedPostString, false, 0 },
{ L"SO", NSwitchType::kSimple, false, 0 },
{ L"AO", NSwitchType::kPostChar, false, 1, 1, kOverwritePostCharSet},
{ L"SEML", NSwitchType::kUnLimitedPostString, false, 0},
{ L"AD", NSwitchType::kSimple, false }
};
static const int kNumCommandForms = 7;
static const CCommandForm g_CommandForms[kNumCommandForms] =
{
{ L"A", false },
{ L"U", false },
{ L"D", false },
{ L"T", false },
{ L"E", false },
{ L"X", false },
{ L"L", false }
};
static const int kMaxCmdLineSize = 1000;
static const wchar_t *kUniversalWildcard = L"*";
static const int kMinNonSwitchWords = 1;
static const int kCommandIndex = 0;
// ---------------------------
// exception messages
static const char *kUserErrorMessage = "Incorrect command line";
static const char *kIncorrectListFile = "Incorrect wildcard in listfile";
static const char *kIncorrectWildCardInListFile = "Incorrect wildcard in listfile";
static const char *kIncorrectWildCardInCommandLine = "Incorrect wildcard in command line";
static const char *kTerminalOutError = "I won't write compressed data to a terminal";
// ---------------------------
bool CArchiveCommand::IsFromExtractGroup() const
{
switch(CommandType)
{
case NCommandType::kTest:
case NCommandType::kExtract:
case NCommandType::kFullExtract:
return true;
default:
return false;
}
}
NExtract::NPathMode::EEnum CArchiveCommand::GetPathMode() const
{
switch(CommandType)
{
case NCommandType::kTest:
case NCommandType::kFullExtract:
return NExtract::NPathMode::kFullPathnames;
default:
return NExtract::NPathMode::kNoPathnames;
}
}
bool CArchiveCommand::IsFromUpdateGroup() const
{
return (CommandType == NCommandType::kAdd ||
CommandType == NCommandType::kUpdate ||
CommandType == NCommandType::kDelete);
}
static NRecursedType::EEnum GetRecursedTypeFromIndex(int index)
{
switch (index)
{
case NRecursedPostCharIndex::kWildCardRecursionOnly:
return NRecursedType::kWildCardOnlyRecursed;
case NRecursedPostCharIndex::kNoRecursion:
return NRecursedType::kNonRecursed;
default:
return NRecursedType::kRecursed;
}
}
static bool ParseArchiveCommand(const UString &commandString, CArchiveCommand &command)
{
UString commandStringUpper = commandString;
commandStringUpper.MakeUpper();
UString postString;
int commandIndex = ParseCommand(kNumCommandForms, g_CommandForms, commandStringUpper,
postString) ;
if (commandIndex < 0)
return false;
command.CommandType = (NCommandType::EEnum)commandIndex;
return true;
}
// ------------------------------------------------------------------
// filenames functions
static bool AddNameToCensor(NWildcard::CCensor &wildcardCensor,
const UString &name, bool include, NRecursedType::EEnum type)
{
bool isWildCard = DoesNameContainWildCard(name);
bool recursed;
switch (type)
{
case NRecursedType::kWildCardOnlyRecursed:
recursed = isWildCard;
break;
case NRecursedType::kRecursed:
recursed = true;
break;
case NRecursedType::kNonRecursed:
recursed = false;
break;
}
wildcardCensor.AddItem(name, include, recursed);
return true;
}
static inline UINT GetCurrentCodePage()
{ return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; }
static void AddToCensorFromListFile(NWildcard::CCensor &wildcardCensor,
LPCWSTR fileName, bool include, NRecursedType::EEnum type)
{
UStringVector names;
if (!ReadNamesFromListFile(GetSystemString(fileName,
GetCurrentCodePage()), names))
throw kIncorrectListFile;
for (int i = 0; i < names.Size(); i++)
if (!AddNameToCensor(wildcardCensor, names[i], include, type))
throw kIncorrectWildCardInListFile;
}
static void AddCommandLineWildCardToCensr(NWildcard::CCensor &wildcardCensor,
const UString &name, bool include, NRecursedType::EEnum recursedType)
{
if (!AddNameToCensor(wildcardCensor, name, include, recursedType))
throw kIncorrectWildCardInCommandLine;
}
static void AddToCensorFromNonSwitchesStrings(
int startIndex,
NWildcard::CCensor &wildcardCensor,
const UStringVector &nonSwitchStrings, NRecursedType::EEnum type,
bool thereAreSwitchIncludes)
{
if(nonSwitchStrings.Size() == startIndex && (!thereAreSwitchIncludes))
AddCommandLineWildCardToCensr(wildcardCensor, kUniversalWildcard, true, type);
for(int i = startIndex; i < nonSwitchStrings.Size(); i++)
{
const UString &s = nonSwitchStrings[i];
if (s[0] == kFileListID)
AddToCensorFromListFile(wildcardCensor, s.Mid(1), true, type);
else
AddCommandLineWildCardToCensr(wildcardCensor, s, true, type);
}
}
#ifdef _WIN32
static void ParseMapWithPaths(NWildcard::CCensor &wildcardCensor,
const UString &switchParam, bool include,
NRecursedType::EEnum commonRecursedType)
{
int splitPos = switchParam.Find(L':');
if (splitPos < 0)
throw kUserErrorMessage;
UString mappingName = switchParam.Left(splitPos);
UString switchParam2 = switchParam.Mid(splitPos + 1);
splitPos = switchParam2.Find(L':');
if (splitPos < 0)
throw kUserErrorMessage;
UString mappingSize = switchParam2.Left(splitPos);
UString eventName = switchParam2.Mid(splitPos + 1);
UInt64 dataSize64 = ConvertStringToUInt64(mappingSize, NULL);
UInt32 dataSize = (UInt32)dataSize64;
{
CFileMapping fileMapping;
if (!fileMapping.Open(FILE_MAP_READ, false, GetSystemString(mappingName)))
throw L"Can not open mapping";
LPVOID data = fileMapping.MapViewOfFile(FILE_MAP_READ, 0, dataSize);
if (data == NULL)
throw L"MapViewOfFile error";
try
{
const wchar_t *curData = (const wchar_t *)data;
if (*curData != 0)
throw L"Incorrect mapping data";
UInt32 numChars = dataSize / sizeof(wchar_t);
UString name;
for (UInt32 i = 1; i < numChars; i++)
{
wchar_t c = curData[i];
if (c == L'\0')
{
AddCommandLineWildCardToCensr(wildcardCensor,
name, include, commonRecursedType);
name.Empty();
}
else
name += c;
}
if (!name.IsEmpty())
throw L"data error";
}
catch(...)
{
UnmapViewOfFile(data);
throw;
}
UnmapViewOfFile(data);
}
{
NSynchronization::CEvent event;
event.Open(EVENT_MODIFY_STATE, false, GetSystemString(eventName));
event.Set();
}
}
#endif
static void AddSwitchWildCardsToCensor(NWildcard::CCensor &wildcardCensor,
const UStringVector &strings, bool include,
NRecursedType::EEnum commonRecursedType)
{
for(int i = 0; i < strings.Size(); i++)
{
const UString &name = strings[i];
NRecursedType::EEnum recursedType;
int pos = 0;
if (name.Length() < kSomeCludePostStringMinSize)
throw kUserErrorMessage;
if (::MyCharUpper(name[pos]) == kRecursedIDChar)
{
pos++;
int index = UString(kRecursedPostCharSet).Find(name[pos]);
recursedType = GetRecursedTypeFromIndex(index);
if (index >= 0)
pos++;
}
else
recursedType = commonRecursedType;
if (name.Length() < pos + kSomeCludeAfterRecursedPostStringMinSize)
throw kUserErrorMessage;
UString tail = name.Mid(pos + 1);
if (name[pos] == kImmediateNameID)
AddCommandLineWildCardToCensr(wildcardCensor, tail, include, recursedType);
else if (name[pos] == kFileListID)
AddToCensorFromListFile(wildcardCensor, tail, include, recursedType);
#ifdef _WIN32
else if (name[pos] == kMapNameID)
ParseMapWithPaths(wildcardCensor, tail, include, recursedType);
#endif
else
throw kUserErrorMessage;
}
}
static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i)
{
switch(i)
{
case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore;
case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy;
case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress;
case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti;
}
throw 98111603;
}
const UString kUpdatePairStateIDSet = L"PQRXYZW";
const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1};
const UString kUpdatePairActionIDSet = L"0123"; //Ignore, Copy, Compress, Create Anti
const wchar_t *kUpdateIgnoreItselfPostStringID = L"-";
const wchar_t kUpdateNewArchivePostCharID = '!';
static bool ParseUpdateCommandString2(const UString &command,
NUpdateArchive::CActionSet &actionSet, UString &postString)
{
for(int i = 0; i < command.Length();)
{
wchar_t c = MyCharUpper(command[i]);
int statePos = kUpdatePairStateIDSet.Find(c);
if (statePos < 0)
{
postString = command.Mid(i);
return true;
}
i++;
if (i >= command.Length())
return false;
int actionPos = kUpdatePairActionIDSet.Find(::MyCharUpper(command[i]));
if (actionPos < 0)
return false;
actionSet.StateActions[statePos] = GetUpdatePairActionType(actionPos);
if (kUpdatePairStateNotSupportedActions[statePos] == actionPos)
return false;
i++;
}
postString.Empty();
return true;
}
static void ParseUpdateCommandString(CUpdateOptions &options,
const UStringVector &updatePostStrings,
const NUpdateArchive::CActionSet &defaultActionSet)
{
for(int i = 0; i < updatePostStrings.Size(); i++)
{
const UString &updateString = updatePostStrings[i];
if(updateString.CompareNoCase(kUpdateIgnoreItselfPostStringID) == 0)
{
if(options.UpdateArchiveItself)
{
options.UpdateArchiveItself = false;
options.Commands.Delete(0);
}
}
else
{
NUpdateArchive::CActionSet actionSet = defaultActionSet;
UString postString;
if (!ParseUpdateCommandString2(updateString, actionSet, postString))
throw kUserErrorMessage;
if(postString.IsEmpty())
{
if(options.UpdateArchiveItself)
options.Commands[0].ActionSet = actionSet;
}
else
{
if(MyCharUpper(postString[0]) != kUpdateNewArchivePostCharID)
throw kUserErrorMessage;
CUpdateArchiveCommand uc;
UString archivePath = postString.Mid(1);
if (archivePath.IsEmpty())
throw kUserErrorMessage;
uc.ArchivePath.BaseExtension = options.ArchivePath.BaseExtension;
uc.ArchivePath.VolExtension = options.ArchivePath.VolExtension;
uc.ArchivePath.ParseFromPath(archivePath);
uc.ActionSet = actionSet;
options.Commands.Add(uc);
}
}
}
}
static const char kByteSymbol = 'B';
static const char kKiloSymbol = 'K';
static const char kMegaSymbol = 'M';
static const char kGigaSymbol = 'G';
static bool ParseComplexSize(const UString &src, UInt64 &result)
{
UString s = src;
s.MakeUpper();
const wchar_t *start = s;
const wchar_t *end;
UInt64 number = ConvertStringToUInt64(start, &end);
int numDigits = end - start;
if (numDigits == 0 || s.Length() > numDigits + 1)
return false;
if (s.Length() == numDigits)
{
result = number;
return true;
}
int numBits;
switch (s[numDigits])
{
case kByteSymbol:
result = number;
return true;
case kKiloSymbol:
numBits = 10;
break;
case kMegaSymbol:
numBits = 20;
break;
case kGigaSymbol:
numBits = 30;
break;
default:
return false;
}
if (number >= ((UInt64)1 << (64 - numBits)))
return false;
result = number << numBits;
return true;
}
static void SetAddCommandOptions(
NCommandType::EEnum commandType,
const CParser &parser,
CUpdateOptions &options)
{
NUpdateArchive::CActionSet defaultActionSet;
switch(commandType)
{
case NCommandType::kAdd:
defaultActionSet = NUpdateArchive::kAddActionSet;
break;
case NCommandType::kDelete:
defaultActionSet = NUpdateArchive::kDeleteActionSet;
break;
default:
defaultActionSet = NUpdateArchive::kUpdateActionSet;
}
options.UpdateArchiveItself = true;
options.Commands.Clear();
CUpdateArchiveCommand updateMainCommand;
updateMainCommand.ActionSet = defaultActionSet;
options.Commands.Add(updateMainCommand);
if(parser[NKey::kUpdate].ThereIs)
ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings,
defaultActionSet);
if(parser[NKey::kWorkingDir].ThereIs)
{
const UString &postString = parser[NKey::kWorkingDir].PostStrings[0];
if (postString.IsEmpty())
NDirectory::MyGetTempPath(options.WorkingDir);
else
options.WorkingDir = postString;
}
if(options.SfxMode = parser[NKey::kSfx].ThereIs)
options.SfxModule = parser[NKey::kSfx].PostStrings[0];
if (parser[NKey::kVolume].ThereIs)
{
const UStringVector &sv = parser[NKey::kVolume].PostStrings;
for (int i = 0; i < sv.Size(); i++)
{
const UString &s = sv[i];
UInt64 size;
if (!ParseComplexSize(sv[i], size))
throw "incorrect volume size";
options.VolumesSizes.Add(size);
}
}
}
static void SetMethodOptions(const CParser &parser,
CUpdateOptions &options)
{
if (parser[NKey::kProperty].ThereIs)
{
// options.MethodMode.Properties.Clear();
for(int i = 0; i < parser[NKey::kProperty].PostStrings.Size(); i++)
{
CProperty property;
const UString &postString = parser[NKey::kProperty].PostStrings[i];
int index = postString.Find(L'=');
if (index < 0)
property.Name = postString;
else
{
property.Name = postString.Left(index);
property.Value = postString.Mid(index + 1);
}
options.MethodMode.Properties.Add(property);
}
}
}
static void SetArchiveType(const UString &archiveType,
#ifndef EXCLUDE_COM
UString &filePath, CLSID &classID,
#else
UString &formatName,
#endif
UString &archiveExtension)
{
CObjectVector<CArchiverInfo> archiverInfoVector;
ReadArchiverInfoList(archiverInfoVector);
if (archiverInfoVector.Size() == 0)
throw "There are no installed archive handlers";
if (archiveType.IsEmpty())
throw "Incorrect archive type was assigned";
for (int i = 0; i < archiverInfoVector.Size(); i++)
{
const CArchiverInfo &archiverInfo = archiverInfoVector[i];
if (archiverInfo.Name.CompareNoCase(archiveType) == 0)
{
#ifndef EXCLUDE_COM
classID = archiverInfo.ClassID;
filePath = archiverInfo.FilePath;
#else
formatName = archiverInfo.Name;
#endif
archiveExtension = archiverInfo.GetMainExtension();
return;
}
}
throw "Incorrect archive type was assigned";
}
CArchiveCommandLineParser::CArchiveCommandLineParser(): parser(kNumSwitches) {}
void CArchiveCommandLineParser::Parse1(UStringVector commandStrings,
CArchiveCommandLineOptions &options)
{
try
{
parser.ParseStrings(kSwitchForms, commandStrings);
}
catch(...)
{
throw kUserErrorMessage;
}
options.IsInTerminal = (isatty(fileno(stdin)) != 0);
options.IsStdOutTerminal = (isatty(fileno(stdout)) != 0);
options.IsStdErrTerminal = (isatty(fileno(stderr)) != 0);
options.StdOutMode = parser[NKey::kStdOut].ThereIs;
options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs;
options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs;
}
void CArchiveCommandLineParser::Parse2(CArchiveCommandLineOptions &options)
{
const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
int numNonSwitchStrings = nonSwitchStrings.Size();
if(numNonSwitchStrings < kMinNonSwitchWords)
throw kUserErrorMessage;
if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command))
throw kUserErrorMessage;
NRecursedType::EEnum recursedType;
if (parser[NKey::kRecursed].ThereIs)
recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex);
else
recursedType = NRecursedType::kNonRecursed;
bool thereAreSwitchIncludes = false;
if (parser[NKey::kInclude].ThereIs)
{
thereAreSwitchIncludes = true;
AddSwitchWildCardsToCensor(options.WildcardCensor,
parser[NKey::kInclude].PostStrings, true, recursedType);
}
if (parser[NKey::kExclude].ThereIs)
AddSwitchWildCardsToCensor(options.WildcardCensor,
parser[NKey::kExclude].PostStrings, false, recursedType);
int curCommandIndex = kCommandIndex + 1;
bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs;
if (thereIsArchiveName)
{
if(curCommandIndex >= numNonSwitchStrings)
throw kUserErrorMessage;
options.ArchiveName = nonSwitchStrings[curCommandIndex++];
}
AddToCensorFromNonSwitchesStrings(
curCommandIndex, options.WildcardCensor,
nonSwitchStrings, recursedType, thereAreSwitchIncludes);
options.YesToAll = parser[NKey::kYes].ThereIs;
bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
options.PasswordEnabled = parser[NKey::kPassword].ThereIs;
if(options.PasswordEnabled)
options.Password = parser[NKey::kPassword].PostStrings[0];
options.StdInMode = parser[NKey::kStdIn].ThereIs;
options.ShowDialog = parser[NKey::kShowDialog].ThereIs;
if(isExtractGroupCommand || options.Command.CommandType == NCommandType::kList)
{
if (options.StdInMode)
throw "reading archives from stdin is not implemented";
if (!options.WildcardCensor.AllAreRelative())
throw "cannot use absolute pathnames for this command";
NWildcard::CCensor archiveWildcardCensor;
if (parser[NKey::kArInclude].ThereIs)
{
AddSwitchWildCardsToCensor(archiveWildcardCensor,
parser[NKey::kArInclude].PostStrings, true, NRecursedType::kNonRecursed);
}
if (parser[NKey::kArExclude].ThereIs)
AddSwitchWildCardsToCensor(archiveWildcardCensor,
parser[NKey::kArExclude].PostStrings, false, NRecursedType::kNonRecursed);
if (thereIsArchiveName)
AddCommandLineWildCardToCensr(archiveWildcardCensor, options.ArchiveName, true, NRecursedType::kNonRecursed);
CObjectVector<CDirItem> dirItems;
EnumerateItems(archiveWildcardCensor, dirItems, NULL);
UStringVector archivePaths;
int i;
for (i = 0; i < dirItems.Size(); i++)
archivePaths.Add(dirItems[i].FullPath);
if (archivePaths.Size() == 0)
throw "there is no such archive";
UStringVector archivePathsFull;
for (i = 0; i < archivePaths.Size(); i++)
{
UString fullPath;
NFile::NDirectory::MyGetFullPathName(archivePaths[i], fullPath);
archivePathsFull.Add(fullPath);
}
CIntVector indices;
SortStringsToIndices(archivePathsFull, indices);
options.ArchivePathsSorted.Reserve(indices.Size());
options.ArchivePathsFullSorted.Reserve(indices.Size());
for (i = 0; i < indices.Size(); i++)
{
options.ArchivePathsSorted.Add(archivePaths[indices[i]]);
options.ArchivePathsFullSorted.Add(archivePathsFull[indices[i]]);
}
if(isExtractGroupCommand)
{
if (options.StdOutMode && options.IsStdOutTerminal)
throw kTerminalOutError;
if(parser[NKey::kOutputDir].ThereIs)
{
options.OutputDir = parser[NKey::kOutputDir].PostStrings[0];
NFile::NName::NormalizeDirPathPrefix(options.OutputDir);
}
options.OverwriteMode = NExtract::NOverwriteMode::kAskBefore;
if(parser[NKey::kOverwrite].ThereIs)
options.OverwriteMode =
k_OverwriteModes[parser[NKey::kOverwrite].PostCharIndex];
else if (options.YesToAll)
options.OverwriteMode = NExtract::NOverwriteMode::kWithoutPrompt;
}
}
else if(options.Command.IsFromUpdateGroup())
{
CUpdateOptions &updateOptions = options.UpdateOptions;
UString archiveType;
if(parser[NKey::kArchiveType].ThereIs)
archiveType = parser[NKey::kArchiveType].PostStrings[0];
else
archiveType = kDefaultArchiveType;
UString typeExtension;
if (!archiveType.IsEmpty())
{
#ifndef EXCLUDE_COM
SetArchiveType(archiveType, updateOptions.MethodMode.FilePath,
updateOptions.MethodMode.ClassID, typeExtension);
#else
SetArchiveType(archiveType, updateOptions.MethodMode.Name, typeExtension);
#endif
}
UString extension = typeExtension;
if(parser[NKey::kSfx].ThereIs)
extension = kSFXExtension;
updateOptions.ArchivePath.BaseExtension = extension;
updateOptions.ArchivePath.VolExtension = typeExtension;
updateOptions.ArchivePath.ParseFromPath(options.ArchiveName);
SetAddCommandOptions(options.Command.CommandType, parser,
updateOptions);
SetMethodOptions(parser, updateOptions);
options.EnablePercents = !parser[NKey::kDisablePercents].ThereIs;
if (options.EnablePercents)
{
if ((options.StdOutMode && !options.IsStdErrTerminal) ||
(!options.StdOutMode && !options.IsStdOutTerminal))
options.EnablePercents = false;
}
if (updateOptions.EMailMode = parser[NKey::kEmail].ThereIs)
{
updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front();
if (updateOptions.EMailAddress.Length() > 0)
if (updateOptions.EMailAddress[0] == L'.')
{
updateOptions.EMailRemoveAfter = true;
updateOptions.EMailAddress.Delete(0);
}
}
updateOptions.StdOutMode = options.StdOutMode;
updateOptions.StdInMode = options.StdInMode;
if (updateOptions.StdOutMode && updateOptions.EMailMode)
throw "stdout mode and email mode cannot be combined";
if (updateOptions.StdOutMode && options.IsStdOutTerminal)
throw kTerminalOutError;
if(updateOptions.StdInMode)
updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front();
}
else
throw kUserErrorMessage;
}

View File

@@ -0,0 +1,84 @@
// ArchiveCommandLine.h
#ifndef __ARCHIVECOMMANDLINE_H
#define __ARCHIVECOMMANDLINE_H
#include "Common/Wildcard.h"
#include "Common/CommandLineParser.h"
#include "Extract.h"
#include "Update.h"
namespace NCommandType { enum EEnum
{
kAdd = 0,
kUpdate,
kDelete,
kTest,
kExtract,
kFullExtract,
kList
};}
namespace NRecursedType { enum EEnum
{
kRecursed,
kWildCardOnlyRecursed,
kNonRecursed,
};}
struct CArchiveCommand
{
NCommandType::EEnum CommandType;
bool IsFromExtractGroup() const;
bool IsFromUpdateGroup() const;
bool IsTestMode() const { return CommandType == NCommandType::kTest; }
NExtract::NPathMode::EEnum GetPathMode() const;
};
struct CArchiveCommandLineOptions
{
bool HelpMode;
bool IsInTerminal;
bool IsStdOutTerminal;
bool IsStdErrTerminal;
bool StdInMode;
bool StdOutMode;
bool EnableHeaders;
bool YesToAll;
bool ShowDialog;
// NWildcard::CCensor ArchiveWildcardCensor;
NWildcard::CCensor WildcardCensor;
CArchiveCommand Command;
UString ArchiveName;
bool PasswordEnabled;
UString Password;
// Extract
bool AppendName;
UString OutputDir;
NExtract::NOverwriteMode::EEnum OverwriteMode;
UStringVector ArchivePathsSorted;
UStringVector ArchivePathsFullSorted;
CUpdateOptions UpdateOptions;
bool EnablePercents;
CArchiveCommandLineOptions(): StdInMode(false), StdOutMode(false) {};
};
class CArchiveCommandLineParser
{
NCommandLineParser::CParser parser;
public:
CArchiveCommandLineParser();
void Parse1(const UStringVector commandStrings, CArchiveCommandLineOptions &options);
void Parse2(CArchiveCommandLineOptions &options);
};
#endif

View File

@@ -0,0 +1,392 @@
// ArchiveExtractCallback.cpp
#include "StdAfx.h"
#include "ArchiveExtractCallback.h"
#include "Common/Wildcard.h"
#include "Common/StringConvert.h"
#include "Windows/FileDir.h"
#include "Windows/FileFind.h"
#include "Windows/Time.h"
#include "Windows/Defs.h"
#include "Windows/PropVariant.h"
#include "Windows/PropVariantConversions.h"
#include "../../Common/FilePathAutoRename.h"
#include "../Common/ExtractingFilePath.h"
#include "OpenArchive.h"
using namespace NWindows;
static const wchar_t *kCantAutoRename = L"ERROR: Can not create file with auto name";
static const wchar_t *kCantRenameFile = L"ERROR: Can not rename existing file ";
static const wchar_t *kCantDeleteOutputFile = L"ERROR: Can not delete output file ";
void CArchiveExtractCallback::Init(
IInArchive *archiveHandler,
IFolderArchiveExtractCallback *extractCallback2,
bool stdOutMode,
const UString &directoryPath,
NExtract::NPathMode::EEnum pathMode,
NExtract::NOverwriteMode::EEnum overwriteMode,
const UStringVector &removePathParts,
const UString &itemDefaultName,
const FILETIME &utcLastWriteTimeDefault,
UInt32 attributesDefault)
{
_stdOutMode = stdOutMode;
_numErrors = 0;
_extractCallback2 = extractCallback2;
_itemDefaultName = itemDefaultName;
_utcLastWriteTimeDefault = utcLastWriteTimeDefault;
_attributesDefault = attributesDefault;
_removePathParts = removePathParts;
_pathMode = pathMode;
_overwriteMode = overwriteMode;
_archiveHandler = archiveHandler;
_directoryPath = directoryPath;
NFile::NName::NormalizeDirPathPrefix(_directoryPath);
}
STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size)
{
return _extractCallback2->SetTotal(size);
}
STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue)
{
return _extractCallback2->SetCompleted(completeValue);
}
void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts)
{
UString fullPath = _directoryPath;
for(int i = 0; i < dirPathParts.Size(); i++)
{
fullPath += dirPathParts[i];
NFile::NDirectory::MyCreateDirectory(fullPath);
fullPath += wchar_t(NFile::NName::kDirDelimiter);
}
}
static UString MakePathNameFromParts(const UStringVector &parts)
{
UString result;
for(int i = 0; i < parts.Size(); i++)
{
if(i != 0)
result += wchar_t(NFile::NName::kDirDelimiter);
result += parts[i];
}
return result;
}
STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index,
ISequentialOutStream **outStream, Int32 askExtractMode)
{
*outStream = 0;
_outFileStream.Release();
NCOM::CPropVariant propVariant;
RINOK(_archiveHandler->GetProperty(index, kpidPath, &propVariant));
UString fullPath;
if(propVariant.vt == VT_EMPTY)
fullPath = _itemDefaultName;
else
{
if(propVariant.vt != VT_BSTR)
return E_FAIL;
fullPath = propVariant.bstrVal;
}
// UString fullPathCorrect = GetCorrectPath(fullPath);
_filePath = fullPath;
_isSplit = false;
RINOK(_archiveHandler->GetProperty(index, kpidPosition, &propVariant));
if (propVariant.vt != VT_EMPTY)
{
if (propVariant.vt != VT_UI8)
return E_FAIL;
_position = propVariant.uhVal.QuadPart;
_isSplit = true;
}
if(askExtractMode == NArchive::NExtract::NAskMode::kExtract)
{
if (_stdOutMode)
{
CMyComPtr<ISequentialOutStream> outStreamLoc = new CStdOutFileStream;
*outStream = outStreamLoc.Detach();
return S_OK;
}
RINOK(_archiveHandler->GetProperty(index, kpidAttributes, &propVariant));
if (propVariant.vt == VT_EMPTY)
{
_processedFileInfo.Attributes = _attributesDefault;
_processedFileInfo.AttributesAreDefined = false;
}
else
{
if (propVariant.vt != VT_UI4)
throw "incorrect item";
_processedFileInfo.Attributes = propVariant.ulVal;
_processedFileInfo.AttributesAreDefined = true;
}
RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.IsDirectory));
RINOK(_archiveHandler->GetProperty(index, kpidLastWriteTime, &propVariant));
switch(propVariant.vt)
{
case VT_EMPTY:
_processedFileInfo.UTCLastWriteTime = _utcLastWriteTimeDefault;
break;
case VT_FILETIME:
_processedFileInfo.UTCLastWriteTime = propVariant.filetime;
break;
default:
return E_FAIL;
}
RINOK(_archiveHandler->GetProperty(index, kpidSize, &propVariant));
bool newFileSizeDefined = (propVariant.vt != VT_EMPTY);
UInt64 newFileSize;
if (newFileSizeDefined)
newFileSize = ConvertPropVariantToUInt64(propVariant);
bool isAnti = false;
{
NCOM::CPropVariant propVariantTemp;
RINOK(_archiveHandler->GetProperty(index, kpidIsAnti,
&propVariantTemp));
if (propVariantTemp.vt == VT_BOOL)
isAnti = VARIANT_BOOLToBool(propVariantTemp.boolVal);
}
UStringVector pathParts;
SplitPathToParts(fullPath, pathParts);
if(pathParts.IsEmpty())
return E_FAIL;
UString processedPath;
switch(_pathMode)
{
case NExtract::NPathMode::kFullPathnames:
{
processedPath = fullPath;
break;
}
case NExtract::NPathMode::kCurrentPathnames:
{
// for incorrect paths: "/dir1/dir2/file"
int numRemovePathParts = _removePathParts.Size();
if(pathParts.Size() <= numRemovePathParts)
return E_FAIL;
for(int i = 0; i < numRemovePathParts; i++)
if(_removePathParts[i].CollateNoCase(pathParts[i]) != 0)
return E_FAIL;
pathParts.Delete(0, numRemovePathParts);
processedPath = MakePathNameFromParts(pathParts);
break;
}
case NExtract::NPathMode::kNoPathnames:
{
processedPath = pathParts.Back();
pathParts.Delete(0, pathParts.Size() - 1); // Test it!!
break;
}
}
processedPath = GetCorrectPath(processedPath);
if(!_processedFileInfo.IsDirectory)
pathParts.DeleteBack();
MakeCorrectPath(pathParts);
if (!isAnti)
if (!pathParts.IsEmpty())
CreateComplexDirectory(pathParts);
UString fullProcessedPath = _directoryPath + processedPath;
if(_processedFileInfo.IsDirectory)
{
_diskFilePath = fullProcessedPath;
if (isAnti)
NFile::NDirectory::MyRemoveDirectory(_diskFilePath);
return S_OK;
}
if (!_isSplit)
{
NFile::NFind::CFileInfoW fileInfo;
if(NFile::NFind::FindFile(fullProcessedPath, fileInfo))
{
switch(_overwriteMode)
{
case NExtract::NOverwriteMode::kSkipExisting:
return S_OK;
case NExtract::NOverwriteMode::kAskBefore:
{
Int32 overwiteResult;
RINOK(_extractCallback2->AskOverwrite(
fullProcessedPath, &fileInfo.LastWriteTime, &fileInfo.Size,
fullPath, &_processedFileInfo.UTCLastWriteTime, newFileSizeDefined?
&newFileSize : NULL, &overwiteResult))
switch(overwiteResult)
{
case NOverwriteAnswer::kCancel:
return E_ABORT;
case NOverwriteAnswer::kNo:
return S_OK;
case NOverwriteAnswer::kNoToAll:
_overwriteMode = NExtract::NOverwriteMode::kSkipExisting;
return S_OK;
case NOverwriteAnswer::kYesToAll:
_overwriteMode = NExtract::NOverwriteMode::kWithoutPrompt;
break;
case NOverwriteAnswer::kYes:
break;
case NOverwriteAnswer::kAutoRename:
_overwriteMode = NExtract::NOverwriteMode::kAutoRename;
break;
default:
throw 20413;
}
}
}
if (_overwriteMode == NExtract::NOverwriteMode::kAutoRename)
{
if (!AutoRenamePath(fullProcessedPath))
{
UString message = UString(kCantAutoRename) +
fullProcessedPath;
RINOK(_extractCallback2->MessageError(message));
return E_ABORT;
}
}
else if (_overwriteMode == NExtract::NOverwriteMode::kAutoRenameExisting)
{
UString existPath = fullProcessedPath;
if (!AutoRenamePath(existPath))
{
UString message = kCantAutoRename + fullProcessedPath;
RINOK(_extractCallback2->MessageError(message));
return E_ABORT;
}
if(!NFile::NDirectory::MyMoveFile(fullProcessedPath, existPath))
{
UString message = UString(kCantRenameFile) + fullProcessedPath;
RINOK(_extractCallback2->MessageError(message));
return E_ABORT;
}
}
else
if (!NFile::NDirectory::DeleteFileAlways(fullProcessedPath))
{
UString message = UString(kCantDeleteOutputFile) +
fullProcessedPath;
RINOK(_extractCallback2->MessageError(message));
return E_ABORT;
}
}
}
if (!isAnti)
{
_outFileStreamSpec = new COutFileStream;
CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
if (!_outFileStreamSpec->File.Open(fullProcessedPath,
_isSplit ? OPEN_ALWAYS: CREATE_ALWAYS))
{
// if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit)
{
UString message = L"can not open output file " + fullProcessedPath;
RINOK(_extractCallback2->MessageError(message));
return S_OK;
}
}
if (_isSplit)
{
RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL));
}
_outFileStream = outStreamLoc;
*outStream = outStreamLoc.Detach();
}
_diskFilePath = fullProcessedPath;
}
else
{
*outStream = NULL;
}
return S_OK;
}
STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)
{
_extractMode = false;
switch (askExtractMode)
{
case NArchive::NExtract::NAskMode::kExtract:
_extractMode = true;
};
return _extractCallback2->PrepareOperation(_filePath, askExtractMode, _isSplit ? &_position: 0);
}
void CArchiveExtractCallback::AddErrorMessage(LPCTSTR message)
{
_messages.Add(message);
}
STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult)
{
switch(operationResult)
{
case NArchive::NExtract::NOperationResult::kOK:
case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
case NArchive::NExtract::NOperationResult::kCRCError:
case NArchive::NExtract::NOperationResult::kDataError:
break;
default:
_outFileStream.Release();
return E_FAIL;
}
if(_outFileStream != NULL)
_outFileStreamSpec->File.SetLastWriteTime(&_processedFileInfo.UTCLastWriteTime);
_outFileStream.Release();
if (_extractMode && _processedFileInfo.AttributesAreDefined)
NFile::NDirectory::MySetFileAttributes(_diskFilePath, _processedFileInfo.Attributes);
RINOK(_extractCallback2->SetOperationResult(operationResult));
return S_OK;
}
/*
STDMETHODIMP CArchiveExtractCallback::GetInStream(
const wchar_t *name, ISequentialInStream **inStream)
{
CInFileStream *inFile = new CInFileStream;
CMyComPtr<ISequentialInStream> inStreamTemp = inFile;
if (!inFile->Open(_srcDirectoryPrefix + name))
return ::GetLastError();
*inStream = inStreamTemp.Detach();
return S_OK;
}
*/
STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
{
if (!_cryptoGetTextPassword)
{
RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword,
&_cryptoGetTextPassword));
}
return _cryptoGetTextPassword->CryptoGetTextPassword(password);
}

View File

@@ -0,0 +1,95 @@
// ArchiveExtractCallback.h
#ifndef __ARCHIVEEXTRACTCALLBACK_H
#define __ARCHIVEEXTRACTCALLBACK_H
#include "../../Archive/IArchive.h"
#include "IFileExtractCallback.h"
#include "Common/String.h"
#include "Common/MyCom.h"
#include "../../Common/FileStreams.h"
#include "../../IPassword.h"
#include "ExtractMode.h"
class CArchiveExtractCallback:
public IArchiveExtractCallback,
// public IArchiveVolumeExtractCallback,
public ICryptoGetTextPassword,
public CMyUnknownImp
{
public:
MY_UNKNOWN_IMP1(ICryptoGetTextPassword)
// COM_INTERFACE_ENTRY(IArchiveVolumeExtractCallback)
// IProgress
STDMETHOD(SetTotal)(UInt64 aize);
STDMETHOD(SetCompleted)(const UInt64 *completeValue);
// IExtractCallBack
STDMETHOD(GetStream)(UInt32 anIndex, ISequentialOutStream **outStream,
Int32 askExtractMode);
STDMETHOD(PrepareOperation)(Int32 askExtractMode);
STDMETHOD(SetOperationResult)(Int32 resultEOperationResult);
// IArchiveVolumeExtractCallback
// STDMETHOD(GetInStream)(const wchar_t *name, ISequentialInStream **inStream);
// ICryptoGetTextPassword
STDMETHOD(CryptoGetTextPassword)(BSTR *aPassword);
private:
CMyComPtr<IInArchive> _archiveHandler;
CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2;
CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
UString _directoryPath;
NExtract::NPathMode::EEnum _pathMode;
NExtract::NOverwriteMode::EEnum _overwriteMode;
UString _filePath;
UInt64 _position;
bool _isSplit;
UString _diskFilePath;
CSysStringVector _messages;
bool _extractMode;
struct CProcessedFileInfo
{
FILETIME UTCLastWriteTime;
bool IsDirectory;
bool AttributesAreDefined;
UInt32 Attributes;
} _processedFileInfo;
COutFileStream *_outFileStreamSpec;
CMyComPtr<ISequentialOutStream> _outFileStream;
UStringVector _removePathParts;
UString _itemDefaultName;
FILETIME _utcLastWriteTimeDefault;
UInt32 _attributesDefault;
bool _stdOutMode;
void CreateComplexDirectory(const UStringVector &dirPathParts);
void AddErrorMessage(LPCTSTR message);
public:
void Init(
IInArchive *archiveHandler,
IFolderArchiveExtractCallback *extractCallback2,
bool stdOutMode,
const UString &directoryPath,
NExtract::NPathMode::EEnum pathMode,
NExtract::NOverwriteMode::EEnum overwriteMode,
const UStringVector &removePathParts,
const UString &itemDefaultName,
const FILETIME &utcLastWriteTimeDefault,
UInt32 attributesDefault);
UInt64 _numErrors;
};
#endif

View File

@@ -29,7 +29,7 @@ UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName)
{
NFile::NFind::CFileInfoW fileInfo;
if (!NFile::NFind::FindFile(srcName, fileInfo))
return ::GetLastError();
return resultName;
resultName = fileInfo.Name;
if (!fileInfo.IsDirectory() && !keepName)
{

View File

@@ -1,7 +1,5 @@
// ArchiveName.h
#pragma once
#ifndef __ARCHIVENAME_H
#define __ARCHIVENAME_H
@@ -9,4 +7,4 @@
UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName);
#endif
#endif

View File

@@ -0,0 +1,117 @@
// ArchiveOpenCallback.cpp
#include "StdAfx.h"
#include "ArchiveOpenCallback.h"
#include "Common/StringConvert.h"
#include "Windows/PropVariant.h"
#include "../../Common/FileStreams.h"
using namespace NWindows;
STDMETHODIMP COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes)
{
return Callback->SetTotal(files, bytes);
}
STDMETHODIMP COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes)
{
return Callback->SetTotal(files, bytes);
}
STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value)
{
NCOM::CPropVariant propVariant;
if (_subArchiveMode)
{
switch(propID)
{
case kpidName:
propVariant = _subArchiveName;
break;
}
propVariant.Detach(value);
return S_OK;
}
switch(propID)
{
case kpidName:
propVariant = _fileInfo.Name;
break;
case kpidIsFolder:
propVariant = _fileInfo.IsDirectory();
break;
case kpidSize:
propVariant = _fileInfo.Size;
break;
case kpidAttributes:
propVariant = (UInt32)_fileInfo.Attributes;
break;
case kpidLastAccessTime:
propVariant = _fileInfo.LastAccessTime;
break;
case kpidCreationTime:
propVariant = _fileInfo.CreationTime;
break;
case kpidLastWriteTime:
propVariant = _fileInfo.LastWriteTime;
break;
}
propVariant.Detach(value);
return S_OK;
}
int COpenCallbackImp::FindName(const UString &name)
{
for (int i = 0; i < FileNames.Size(); i++)
if (name.CompareNoCase(FileNames[i]) == 0)
return i;
return -1;
}
struct CInFileStreamVol: public CInFileStream
{
UString Name;
COpenCallbackImp *OpenCallbackImp;
CMyComPtr<IArchiveOpenCallback> OpenCallbackRef;
~CInFileStreamVol()
{
int index = OpenCallbackImp->FindName(Name);
if (index >= 0)
OpenCallbackImp->FileNames.Delete(index);
}
};
STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name,
IInStream **inStream)
{
if (_subArchiveMode)
return S_FALSE;
RINOK(Callback->CheckBreak());
*inStream = NULL;
UString fullPath = _folderPrefix + name;
if (!NFile::NFind::FindFile(fullPath, _fileInfo))
return S_FALSE;
if (_fileInfo.IsDirectory())
return S_FALSE;
CInFileStreamVol *inFile = new CInFileStreamVol;
CMyComPtr<IInStream> inStreamTemp = inFile;
if (!inFile->Open(fullPath))
return ::GetLastError();
*inStream = inStreamTemp.Detach();
inFile->Name = name;
inFile->OpenCallbackImp = this;
inFile->OpenCallbackRef = this;
FileNames.Add(name);
return S_OK;
}
#ifndef _NO_CRYPTO
STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password)
{
return Callback->CryptoGetTextPassword(password);
}
#endif

View File

@@ -0,0 +1,87 @@
// ArchiveOpenCallback.h
#ifndef __ARCHIVE_OPEN_CALLBACK_H
#define __ARCHIVE_OPEN_CALLBACK_H
#include "Common/String.h"
#include "Common/MyCom.h"
#include "Windows/FileFind.h"
#ifndef _NO_CRYPTO
#include "../../IPassword.h"
#endif
#include "../../Archive/IArchive.h"
struct IOpenCallbackUI
{
virtual HRESULT CheckBreak() = 0;
virtual HRESULT SetTotal(const UInt64 *files, const UInt64 *bytes) = 0;
virtual HRESULT SetCompleted(const UInt64 *files, const UInt64 *bytes) = 0;
#ifndef _NO_CRYPTO
virtual HRESULT CryptoGetTextPassword(BSTR *password) = 0;
virtual HRESULT GetPasswordIfAny(UString &password) = 0;
#endif
};
class COpenCallbackImp:
public IArchiveOpenCallback,
public IArchiveOpenVolumeCallback,
public IArchiveOpenSetSubArchiveName,
#ifndef _NO_CRYPTO
public ICryptoGetTextPassword,
#endif
public CMyUnknownImp
{
public:
#ifndef _NO_CRYPTO
MY_UNKNOWN_IMP3(
IArchiveOpenVolumeCallback,
ICryptoGetTextPassword,
IArchiveOpenSetSubArchiveName
)
#else
MY_UNKNOWN_IMP2(
IArchiveOpenVolumeCallback,
IArchiveOpenSetSubArchiveName
)
#endif
STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes);
STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes);
// IArchiveOpenVolumeCallback
STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value);
STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream);
#ifndef _NO_CRYPTO
// ICryptoGetTextPassword
STDMETHOD(CryptoGetTextPassword)(BSTR *password);
#endif
STDMETHOD(SetSubArchiveName(const wchar_t *name))
{
_subArchiveMode = true;
_subArchiveName = name;
return S_OK;
}
private:
UString _folderPrefix;
NWindows::NFile::NFind::CFileInfoW _fileInfo;
bool _subArchiveMode;
UString _subArchiveName;
public:
UStringVector FileNames;
IOpenCallbackUI *Callback;
void Init(const UString &folderPrefix, const UString &fileName)
{
_folderPrefix = folderPrefix;
if (!NWindows::NFile::NFind::FindFile(_folderPrefix + fileName, _fileInfo))
throw 1;
FileNames.Clear();
_subArchiveMode = false;
}
int FindName(const UString &name);
};
#endif

View File

@@ -10,7 +10,9 @@
#include "Windows/FileFind.h"
#include "Windows/FileName.h"
#include "Windows/DLL.h"
#ifdef _WIN32
#include "Windows/Registry.h"
#endif
#include "Windows/PropVariant.h"
#include "../../Archive/IArchive.h"
@@ -48,7 +50,7 @@ static void SplitString(const UString &srcString, UStringVector &destStrings)
destStrings.Add(string);
}
typedef UINT32 (WINAPI * GetHandlerPropertyFunc)(
typedef UInt32 (WINAPI * GetHandlerPropertyFunc)(
PROPID propID, PROPVARIANT *value);
/*
@@ -72,7 +74,7 @@ static wchar_t *kFormatFolderName = L"Formats";
static LPCTSTR kRegistryPath = TEXT("Software\\7-zip");
static LPCTSTR kProgramPathValue = TEXT("Path");
UString GetBaseFolderPrefix()
static UString GetBaseFolderPrefixFromRegistry()
{
UString moduleFolderPrefix = GetModuleFolderPrefix();
NFind::CFileInfoW fileInfo;
@@ -80,6 +82,7 @@ UString GetBaseFolderPrefix()
if (fileInfo.IsDirectory())
return moduleFolderPrefix;
CSysString pathSys;
#ifdef _WIN32
{
NRegistry::CKey key;
if(key.Open(HKEY_CURRENT_USER, kRegistryPath, KEY_READ) == ERROR_SUCCESS)
@@ -100,16 +103,25 @@ UString GetBaseFolderPrefix()
return path;
}
}
#endif
return moduleFolderPrefix;
}
typedef UINT32 (WINAPI *CreateObjectPointer)(
typedef UInt32 (WINAPI *CreateObjectPointer)(
const GUID *clsID,
const GUID *interfaceID,
void **outObject);
#endif
#ifndef _SFX
static void SetBuffer(CByteBuffer &bb, const Byte *data, int size)
{
bb.SetCapacity(size);
memmove((Byte *)bb, data, size);
}
#endif
void ReadArchiverInfoList(CObjectVector<CArchiverInfo> &archivers)
{
archivers.Clear();
@@ -123,6 +135,10 @@ void ReadArchiverInfoList(CObjectVector<CArchiverInfo> &archivers)
item.KeepName = false;
item.Name = L"7z";
item.Extensions.Add(CArchiverExtInfo(L"7z"));
#ifndef _SFX
const unsigned char kSig[] = {'7' , 'z', 0xBC, 0xAF, 0x27, 0x1C};
SetBuffer(item.StartSignature, kSig, 6);
#endif
archivers.Add(item);
}
#endif
@@ -135,6 +151,10 @@ void ReadArchiverInfoList(CObjectVector<CArchiverInfo> &archivers)
item.Name = L"BZip2";
item.Extensions.Add(CArchiverExtInfo(L"bz2"));
item.Extensions.Add(CArchiverExtInfo(L"tbz2", L".tar"));
#ifndef _SFX
const unsigned char sig[] = {'B' , 'Z', 'h' };
SetBuffer(item.StartSignature, sig, 3);
#endif
archivers.Add(item);
}
#endif
@@ -147,6 +167,21 @@ void ReadArchiverInfoList(CObjectVector<CArchiverInfo> &archivers)
item.Name = L"GZip";
item.Extensions.Add(CArchiverExtInfo(L"gz"));
item.Extensions.Add(CArchiverExtInfo(L"tgz", L".tar"));
#ifndef _SFX
const unsigned char sig[] = { 0x1F, 0x8B };
SetBuffer(item.StartSignature, sig, 2);
#endif
archivers.Add(item);
}
#endif
#ifdef FORMAT_SPLIT
{
CArchiverInfo item;
item.UpdateEnabled = false;
item.KeepName = true;
item.Name = L"Split";
item.Extensions.Add(CArchiverExtInfo(L"001"));
archivers.Add(item);
}
#endif
@@ -169,6 +204,10 @@ void ReadArchiverInfoList(CObjectVector<CArchiverInfo> &archivers)
item.KeepName = false;
item.Name = L"Zip";
item.Extensions.Add(CArchiverExtInfo(L"zip"));
#ifndef _SFX
const unsigned char sig[] = { 0x50, 0x4B, 0x03, 0x04 };
SetBuffer(item.StartSignature, sig, 4);
#endif
archivers.Add(item);
}
#endif
@@ -199,13 +238,31 @@ void ReadArchiverInfoList(CObjectVector<CArchiverInfo> &archivers)
item.UpdateEnabled = false;
item.Name = L"Arj";
item.Extensions.Add(CArchiverExtInfo(L"arj"));
#ifndef _SFX
const unsigned char sig[] = { 0x60, 0xEA };
SetBuffer(item.StartSignature, sig, 2);
#endif
archivers.Add(item);
}
#endif
#ifdef FORMAT_Z
{
CArchiverInfo item;
item.UpdateEnabled = false;
item.Name = L"Z";
item.Extensions.Add(CArchiverExtInfo(L"Z"));
#ifndef _SFX
const unsigned char sig[] = { 0x1F, 0x9D };
SetBuffer(item.StartSignature, sig, 2);
#endif
archivers.Add(item);
}
#endif
#else
UString folderPath = GetBaseFolderPrefix() +
UString folderPath = GetBaseFolderPrefixFromRegistry() +
kFormatFolderName + L"\\";
NFind::CEnumeratorW enumerator(folderPath + L"*");
NFind::CFileInfoW fileInfo;
@@ -253,6 +310,7 @@ void ReadArchiverInfoList(CObjectVector<CArchiverInfo> &archivers)
UString ext = prop.bstrVal;
// item.Extension = prop.bstrVal;
prop.Clear();
UString addExt;
@@ -282,23 +340,30 @@ void ReadArchiverInfoList(CObjectVector<CArchiverInfo> &archivers)
item.Extensions.Add(extInfo);
}
if (getHandlerProperty(NArchive::kUpdate, &prop) != S_OK)
continue;
if (prop.vt != VT_BOOL)
continue;
item.UpdateEnabled = VARIANT_BOOLToBool(prop.boolVal);
if (getHandlerProperty(NArchive::kUpdate, &prop) == S_OK)
if (prop.vt == VT_BOOL)
item.UpdateEnabled = VARIANT_BOOLToBool(prop.boolVal);
prop.Clear();
if (item.UpdateEnabled)
{
if (getHandlerProperty(NArchive::kKeepName, &prop) != S_OK)
continue;
if (prop.vt != VT_BOOL)
continue;
item.KeepName = VARIANT_BOOLToBool(prop.boolVal);
if (getHandlerProperty(NArchive::kKeepName, &prop) == S_OK)
if (prop.vt == VT_BOOL)
item.KeepName = VARIANT_BOOLToBool(prop.boolVal);
prop.Clear();
}
if (getHandlerProperty(NArchive::kStartSignature, &prop) == S_OK)
{
if (prop.vt == VT_BSTR)
{
UINT len = ::SysStringByteLen(prop.bstrVal);
item.StartSignature.SetCapacity(len);
memmove(item.StartSignature, prop.bstrVal, len);
}
}
prop.Clear();
archivers.Add(item);
}

View File

@@ -1,12 +1,11 @@
// ArchiverInfo.h
#pragma once
#ifndef __ARCHIVERINFO_H
#define __ARCHIVERINFO_H
#include "Common/String.h"
#include "Common/Types.h"
#include "Common/Buffer.h"
struct CArchiverExtInfo
{
@@ -27,6 +26,10 @@ struct CArchiverInfo
#endif
UString Name;
CObjectVector<CArchiverExtInfo> Extensions;
#ifndef _SFX
CByteBuffer StartSignature;
CByteBuffer FinishSignature;
#endif
int FindExtension(const UString &ext) const
{
for (int i = 0; i < Extensions.Size(); i++)

View File

@@ -11,14 +11,18 @@
#include "Windows/Synchronization.h"
#include "Windows/FileMapping.h"
#include "Windows/FileDir.h"
#include "../../FileManager/ProgramLocation.h"
using namespace NWindows;
static LPCWSTR kShowDialogSwitch = L" -ad";
static LPCWSTR kEmailSwitch = L" -seml";
static LPCWSTR kEmailSwitch = L" -seml.";
static LPCWSTR kMapSwitch = L" -i#";
static LPCWSTR kArchiveNoNameSwitch = L" -an";
static LPCWSTR kArchiveMapSwitch = L" -ai#";
static LPCWSTR kStopSwitchParsing = L" --";
static bool IsItWindowsNT()
@@ -31,6 +35,7 @@ static bool IsItWindowsNT()
}
HRESULT MyCreateProcess(const UString &params,
LPCTSTR curDir,
NWindows::NSynchronization::CEvent *event)
{
STARTUPINFO startupInfo;
@@ -45,7 +50,8 @@ HRESULT MyCreateProcess(const UString &params,
PROCESS_INFORMATION processInformation;
BOOL result = ::CreateProcess(NULL, (TCHAR *)(const TCHAR *)
GetSystemString(params),
NULL, NULL, FALSE, 0, NULL, NULL,
NULL, NULL, FALSE, 0, NULL,
curDir,
&startupInfo, &processInformation);
if (result == 0)
return ::GetLastError();
@@ -70,7 +76,7 @@ static UString GetQuotedString(const UString &s)
static UString Get7zGuiPath()
{
UString path = L"\"";
UString path;
UString folder;
if (GetProgramFolderPath(folder))
path += folder;
@@ -78,28 +84,117 @@ static UString Get7zGuiPath()
path += L"7zgn.exe";
else
path += L"7zg.exe";
path += L"\"";
return path;
// path += L"7z.exe";
return GetQuotedString(path);
}
static HRESULT CreateMap(const UStringVector &names,
const UString &id,
CFileMapping &fileMapping, NSynchronization::CEvent &event,
UString &params)
{
UInt32 extraSize = 2;
UInt32 dataSize = 0;
for (int i = 0; i < names.Size(); i++)
dataSize += (names[i].Length() + 1) * sizeof(wchar_t);
UInt32 totalSize = extraSize + dataSize;
UString mappingName;
UString eventName;
CRandom random;
random.Init(GetTickCount());
while(true)
{
int number = random.Generate();
wchar_t temp[32];
ConvertUInt64ToString(UInt32(number), temp);
mappingName = id;
mappingName += L"Mapping";
mappingName += temp;
if (!fileMapping.Create(INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, totalSize, GetSystemString(mappingName)))
return E_FAIL;
if (::GetLastError() != ERROR_ALREADY_EXISTS)
break;
fileMapping.Close();
}
while(true)
{
int number = random.Generate();
wchar_t temp[32];
ConvertUInt64ToString(UInt32(number), temp);
eventName = id;
eventName += L"MappingEndEvent";
eventName += temp;
if (!event.Create(true, false, GetSystemString(eventName)))
return E_FAIL;
if (::GetLastError() != ERROR_ALREADY_EXISTS)
break;
event.Close();
}
params += mappingName;
params += L":";
wchar_t string[10];
ConvertUInt64ToString(totalSize, string);
params += string;
params += L":";
params += eventName;
LPVOID data = fileMapping.MapViewOfFile(FILE_MAP_WRITE, 0, totalSize);
if (data == NULL)
return E_FAIL;
try
{
wchar_t *curData = (wchar_t *)data;
*curData = 0;
curData++;
for (int i = 0; i < names.Size(); i++)
{
const UString &s = names[i];
memcpy(curData, (const wchar_t *)s, s.Length() * sizeof(wchar_t));
curData += s.Length();
*curData++ = L'\0';
}
}
catch(...)
{
UnmapViewOfFile(data);
throw;
}
// UnmapViewOfFile(data);
return S_OK;
}
HRESULT CompressFiles(
const UString &curDir,
const UString &archiveName,
const UStringVector &names,
// const UString &outFolder,
bool email,
bool showDialog)
{
/*
UString curDir;
if (names.Size() > 0)
{
NFile::NDirectory::GetOnlyDirPrefix(names[0], curDir);
}
*/
UString params;
params = Get7zGuiPath();
params += L" a";
params += kMapSwitch;
// params += _fileNames[0];
UINT32 extraSize = 2;
UINT32 dataSize = 0;
UInt32 extraSize = 2;
UInt32 dataSize = 0;
for (int i = 0; i < names.Size(); i++)
dataSize += (names[i].Length() + 1) * sizeof(wchar_t);
UINT32 totalSize = extraSize + dataSize;
UInt32 totalSize = extraSize + dataSize;
UString mappingName;
UString eventName;
@@ -111,7 +206,7 @@ HRESULT CompressFiles(
{
int number = random.Generate();
wchar_t temp[32];
ConvertUINT64ToString(UINT32(number), temp);
ConvertUInt64ToString(UInt32(number), temp);
mappingName = L"7zCompressMapping";
mappingName += temp;
if (!fileMapping.Create(INVALID_HANDLE_VALUE, NULL,
@@ -130,7 +225,7 @@ HRESULT CompressFiles(
{
int number = random.Generate();
wchar_t temp[32];
ConvertUINT64ToString(UINT32(number), temp);
ConvertUInt64ToString(UInt32(number), temp);
eventName = L"7zCompressMappingEndEvent";
eventName += temp;
if (!event.Create(true, false, GetSystemString(eventName)))
@@ -146,7 +241,7 @@ HRESULT CompressFiles(
params += mappingName;
params += L":";
wchar_t string[10];
ConvertUINT64ToString(totalSize, string);
ConvertUInt64ToString(totalSize, string);
params += string;
params += L":";
@@ -158,7 +253,9 @@ HRESULT CompressFiles(
if (showDialog)
params += kShowDialogSwitch;
params += kStopSwitchParsing;
params += L" ";
params += GetQuotedString(archiveName);
LPVOID data = fileMapping.MapViewOfFile(FILE_MAP_WRITE, 0, totalSize);
@@ -177,11 +274,14 @@ HRESULT CompressFiles(
const UString &unicodeString = names[i];
memcpy(curData, (const wchar_t *)unicodeString ,
unicodeString .Length() * sizeof(wchar_t));
curData += unicodeString .Length();
curData += unicodeString.Length();
*curData++ = L'\0';
}
// MessageBox(0, params, 0, 0);
RINOK(MyCreateProcess(params, &event));
CSysString sysCurDir = GetSystemString(curDir);
RINOK(MyCreateProcess(params,
(sysCurDir.IsEmpty()? 0: (LPCTSTR)sysCurDir),
&event));
}
catch(...)
{
@@ -190,8 +290,7 @@ HRESULT CompressFiles(
}
UnmapViewOfFile(data);
/*
CThreadCompressMain *compressor = new CThreadCompressMain();;
compressor->FileNames = _fileNames;
@@ -202,13 +301,24 @@ HRESULT CompressFiles(
return S_OK;
}
HRESULT ExtractArchive(const UString &archiveName,
static HRESULT ExtractGroupCommand(const UStringVector &archivePaths,
const UString &params)
{
UString params2 = params;
params2 += kArchiveNoNameSwitch;
params2 += kArchiveMapSwitch;
CFileMapping fileMapping;
NSynchronization::CEvent event;
RINOK(CreateMap(archivePaths, L"7zExtract", fileMapping, event, params2));
return MyCreateProcess(params2, 0, &event);
}
HRESULT ExtractArchives(const UStringVector &archivePaths,
const UString &outFolder, bool showDialog)
{
UString params;
params = Get7zGuiPath();
params += L" x ";
params += GetQuotedString(archiveName);
params += L" x";
if (!outFolder.IsEmpty())
{
params += L" -o";
@@ -216,14 +326,13 @@ HRESULT ExtractArchive(const UString &archiveName,
}
if (showDialog)
params += kShowDialogSwitch;
return MyCreateProcess(params);
return ExtractGroupCommand(archivePaths, params);
}
HRESULT TestArchive(const UString &archiveName)
HRESULT TestArchives(const UStringVector &archivePaths)
{
UString params;
params = Get7zGuiPath();
params += L" t ";
params += GetQuotedString(archiveName);
return MyCreateProcess(params);
params += L" t";
return ExtractGroupCommand(archivePaths, params);
}

View File

@@ -6,17 +6,21 @@
#include "Common/String.h"
#include "Windows/Synchronization.h"
HRESULT MyCreateProcess(const UString &params,
NWindows::NSynchronization::CEvent *event = NULL);
HRESULT CompressFiles(const UString &archiveName,
HRESULT MyCreateProcess(const UString &params,
LPCTSTR lpCurrentDirectory,
NWindows::NSynchronization::CEvent *event = NULL);
HRESULT CompressFiles(
const UString &curDir,
const UString &archiveName,
const UStringVector &names,
// const UString &outFolder,
bool email, bool showDialog);
HRESULT ExtractArchive(const UString &archiveName,
HRESULT ExtractArchives(
const UStringVector &archivePaths,
const UString &outFolder, bool showDialog);
HRESULT TestArchive(const UString &archiveName);
HRESULT TestArchives(const UStringVector &archivePaths);
#endif

View File

@@ -2,32 +2,22 @@
#include "StdAfx.h"
#include "Windows/FileDir.h"
#include "Common/StringConvert.h"
#include "DefaultName.h"
const wchar_t *kEmptyFileAlias = L"[Content]";
static const wchar_t *kEmptyFileAlias = L"[Content]";
using namespace NWindows;
using namespace NFile;
using namespace NDirectory;
UString GetDefaultName(const UString &fullFileName,
UString GetDefaultName2(const UString &fileName,
const UString &extension, const UString &addSubExtension)
{
UString fileName;
if (!GetOnlyName(fullFileName, fileName))
throw 5011749;
int extLength = extension.Length();
int fileNameLength = fileName.Length();
if (fileNameLength <= extLength + 1)
return kEmptyFileAlias;
int dotPos = fileNameLength - (extLength + 1);
if (fileName[dotPos] != '.')
return kEmptyFileAlias;
if (extension.CollateNoCase(fileName.Mid(dotPos + 1)) == 0)
return fileName.Left(dotPos) + addSubExtension;
if (fileNameLength > extLength + 1)
{
int dotPos = fileNameLength - (extLength + 1);
if (fileName[dotPos] == '.')
if (extension.CollateNoCase(fileName.Mid(dotPos + 1)) == 0)
return fileName.Left(dotPos) + addSubExtension;
}
return kEmptyFileAlias;
}

View File

@@ -1,13 +1,11 @@
// DefaultName.h
#pragma once
#ifndef __DEFAULTNAME_H
#define __DEFAULTNAME_H
#include "Common/String.h"
UString GetDefaultName(const UString &fullFileName,
UString GetDefaultName2(const UString &fileName,
const UString &extension, const UString &addSubExtension);
#endif

View File

@@ -1,21 +1,18 @@
// DirItem.h
#pragma once
#ifndef __DIR_ITEM_H
#define __DIR_ITEM_H
// #include "Common/Types.h"
#include "Common/String.h"
// #include "Windows/PropVariant.h"
#include "Common/Types.h"
struct CDirItem
{
UINT32 Attributes;
UInt32 Attributes;
FILETIME CreationTime;
FILETIME LastAccessTime;
FILETIME LastWriteTime;
UINT64 Size;
UInt64 Size;
UString Name;
UString FullPath;
bool IsDirectory() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0 ; }
@@ -28,7 +25,7 @@ struct CArchiveItem
// NWindows::NCOM::CPropVariant LastWriteTime;
FILETIME LastWriteTime;
bool SizeIsDefined;
UINT64 Size;
UInt64 Size;
UString Name;
bool Censored;
int IndexInServer;

View File

@@ -2,8 +2,11 @@
#include "StdAfx.h"
#include "EnumDirItems.h"
#include "Common/StringConvert.h"
#include "Common/Wildcard.h"
#include "Common/MyCom.h"
#include "EnumDirItems.h"
using namespace NWindows;
using namespace NFile;
@@ -28,27 +31,33 @@ void AddDirFileInfo(
dirItems.Add(item);
}
static void EnumerateDirectory(
static HRESULT EnumerateDirectory(
const UString &baseFolderPrefix,
const UString &directory,
const UString &prefix,
CObjectVector<CDirItem> &dirItems)
{
NFind::CEnumeratorW enumerator(baseFolderPrefix + directory + wchar_t(kAnyStringWildcard));
NFind::CFileInfoW fileInfo;
while (enumerator.Next(fileInfo))
while (true)
{
NFind::CFileInfoW fileInfo;
bool found;
if (!enumerator.Next(fileInfo, found))
return ::GetLastError();
if (!found)
break;
AddDirFileInfo(prefix, directory + fileInfo.Name, fileInfo,
dirItems);
if (fileInfo.IsDirectory())
{
EnumerateDirectory(baseFolderPrefix, directory + fileInfo.Name + wchar_t(kDirDelimiter),
prefix + fileInfo.Name + wchar_t(kDirDelimiter), dirItems);
RINOK(EnumerateDirectory(baseFolderPrefix, directory + fileInfo.Name + wchar_t(kDirDelimiter),
prefix + fileInfo.Name + wchar_t(kDirDelimiter), dirItems));
}
}
return S_OK;
}
void EnumerateDirItems(
HRESULT EnumerateDirItems(
const UString &baseFolderPrefix,
const UStringVector &fileNames,
const UString &archiveNamePrefix,
@@ -63,9 +72,88 @@ void EnumerateDirItems(
AddDirFileInfo(archiveNamePrefix, fileName, fileInfo, dirItems);
if (fileInfo.IsDirectory())
{
EnumerateDirectory(baseFolderPrefix, fileName + wchar_t(kDirDelimiter),
RINOK(EnumerateDirectory(baseFolderPrefix, fileName + wchar_t(kDirDelimiter),
archiveNamePrefix + fileInfo.Name + wchar_t(kDirDelimiter),
dirItems);
dirItems));
}
}
return S_OK;
}
static HRESULT EnumerateDirItems(
const NWildcard::CCensorNode &curNode,
const UString &diskPrefix,
const UString &archivePrefix,
const UString &addArchivePrefix,
CObjectVector<CDirItem> &dirItems,
bool enterToSubFolders,
IEnumDirItemCallback *callback)
{
if (!enterToSubFolders)
if (curNode.NeedCheckSubDirs())
enterToSubFolders = true;
if (callback)
RINOK(callback->CheckBreak());
NFind::CEnumeratorW enumerator(diskPrefix + wchar_t(kAnyStringWildcard));
while (true)
{
NFind::CFileInfoW fileInfo;
bool found;
if (!enumerator.Next(fileInfo, found))
return ::GetLastError();
if (!found)
break;
if (callback)
RINOK(callback->CheckBreak());
UString name = fileInfo.Name;
bool enterToSubFolders2 = enterToSubFolders;
if (curNode.CheckPathToRoot(addArchivePrefix + name, !fileInfo.IsDirectory()))
{
AddDirFileInfo(archivePrefix, diskPrefix + fileInfo.Name, fileInfo, dirItems);
if (fileInfo.IsDirectory())
enterToSubFolders2 = true;;
}
if (!fileInfo.IsDirectory())
continue;
const NWildcard::CCensorNode *nextNode = 0;
if (addArchivePrefix.IsEmpty())
{
int index = curNode.FindSubNode(name);
if (index >= 0)
nextNode = &curNode.SubNodes[index];
}
if (!enterToSubFolders2 && nextNode == 0)
continue;
UString archivePrefixNew = archivePrefix;
UString addArchivePrefixNew = addArchivePrefix;
if (nextNode == 0)
{
nextNode = &curNode;
addArchivePrefixNew += name;
addArchivePrefixNew += wchar_t(kDirDelimiter);
}
archivePrefixNew += name;
archivePrefixNew += wchar_t(kDirDelimiter);
RINOK(EnumerateDirItems(*nextNode,
diskPrefix + fileInfo.Name + wchar_t(kDirDelimiter),
archivePrefixNew, addArchivePrefixNew,
dirItems, enterToSubFolders2, callback));
}
return S_OK;
}
HRESULT EnumerateItems(const NWildcard::CCensor &censor,
CObjectVector<CDirItem> &dirItems, IEnumDirItemCallback *callback)
{
for (int i = 0; i < censor.Pairs.Size(); i++)
{
if (callback)
RINOK(callback->CheckBreak());
const NWildcard::CPair &pair = censor.Pairs[i];
RINOK(EnumerateDirItems(pair.Head, pair.Prefix, L"", L"", dirItems, false, callback));
}
return S_OK;
}

View File

@@ -1,14 +1,10 @@
// EnumDirItems.h
#pragma once
#ifndef __ENUM_DIR_ITEMS_H
#define __ENUM_DIR_ITEMS_H
#include "Common/String.h"
#include "Common/Vector.h"
#include "Common/Wildcard.h"
#include "DirItem.h"
// #include "UpdatePairBasic.h"
#include "Windows/FileFind.h"
@@ -18,16 +14,20 @@ void AddDirFileInfo(
NWindows::NFile::NFind::CFileInfoW &fileInfo,
CObjectVector<CDirItem> &dirItems);
void EnumerateDirItems(
HRESULT EnumerateDirItems(
const UString &baseFolderPrefix,
const UStringVector &fileNames,
const UString &archiveNamePrefix,
CObjectVector<CDirItem> &dirItems);
/*
void EnumerateItems(const CSysStringVector &filePaths,
const UString &archiveNamePrefix,
CArchiveStyleDirItemInfoVector &dirFileInfoVector, UINT codePage);
*/
struct IEnumDirItemCallback
{
virtual HRESULT CheckBreak() { return S_OK; }
};
HRESULT EnumerateItems(const NWildcard::CCensor &censor,
CObjectVector<CDirItem> &dirItems, IEnumDirItemCallback *callback);
#endif

27
7zip/UI/Common/ExitCode.h Executable file
View File

@@ -0,0 +1,27 @@
// ExitCode.h
#ifndef __EXIT_CODE_H
#define __EXIT_CODE_H
namespace NExitCode {
enum EEnum {
kSuccess = 0, // Successful operation
kWarning = 1, // Non fatal error(s) occurred
kFatalError = 2, // A fatal error occurred
// kCRCError = 3, // A CRC error occurred when unpacking
// kLockedArchive = 4, // Attempt to modify an archive previously locked
// kWriteError = 5, // Write to disk error
// kOpenError = 6, // Open file error
kUserError = 7, // Command line option error
kMemoryError = 8, // Not enough memory for operation
// kCreateFileError = 9, // Create file error
kUserBreak = 255 // User stopped the process
};
}
#endif

127
7zip/UI/Common/Extract.cpp Executable file
View File

@@ -0,0 +1,127 @@
// Extract.cpp
#include "StdAfx.h"
#include "Extract.h"
#include "Windows/Defs.h"
#include "Windows/PropVariant.h"
#include "Windows/FileDir.h"
#include "OpenArchive.h"
#ifndef EXCLUDE_COM
#include "Windows/DLL.h"
#endif
using namespace NWindows;
HRESULT DecompressArchive(
IInArchive *archive,
const UString &defaultName,
const NWildcard::CCensorNode &wildcardCensor,
const CExtractOptions &options,
IExtractCallbackUI *callback)
{
CRecordVector<UInt32> realIndices;
UInt32 numItems;
RINOK(archive->GetNumberOfItems(&numItems));
for(UInt32 i = 0; i < numItems; i++)
{
UString filePath;
RINOK(GetArchiveItemPath(archive, i, options.DefaultItemName, filePath));
bool isFolder;
RINOK(IsArchiveItemFolder(archive, i, isFolder));
if (!wildcardCensor.CheckPath(filePath, !isFolder))
continue;
realIndices.Add(i);
}
if (realIndices.Size() == 0)
{
callback->ThereAreNoFiles();
return S_OK;
}
CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec);
UStringVector removePathParts;
UString outDir = options.OutputDir;
outDir.Replace(L"*", defaultName);
if(!outDir.IsEmpty())
if(!NFile::NDirectory::CreateComplexDirectory(outDir))
{
throw UString(L"Can not create output directory ") + outDir;
}
extractCallbackSpec->Init(
archive,
callback,
options.StdOutMode,
outDir,
options.PathMode,
options.OverwriteMode,
removePathParts,
options.DefaultItemName,
options.ArchiveFileInfo.LastWriteTime,
options.ArchiveFileInfo.Attributes);
HRESULT result = archive->Extract(&realIndices.Front(),
realIndices.Size(), options.TestMode? 1: 0,
extractCallback);
return callback->ExtractResult(result);
}
HRESULT DecompressArchives(
UStringVector &archivePaths, UStringVector &archivePathsFull,
const NWildcard::CCensorNode &wildcardCensor,
const CExtractOptions &optionsSpec,
IOpenCallbackUI *openCallback,
IExtractCallbackUI *extractCallback)
{
CExtractOptions options = optionsSpec;
for (int i = 0; i < archivePaths.Size(); i++)
{
const UString &archivePath = archivePaths[i];
NFile::NFind::CFileInfoW archiveFileInfo;
if (!NFile::NFind::FindFile(archivePath, archiveFileInfo))
throw "there is no such archive";
if (archiveFileInfo.IsDirectory())
throw "there is no such archive";
options.ArchiveFileInfo = archiveFileInfo;
RINOK(extractCallback->BeforeOpen(archivePath));
CArchiveLink archiveLink;
HRESULT result = MyOpenArchive(archivePath, archiveLink, openCallback);
RINOK(extractCallback->OpenResult(archivePath, result));
if (result != S_OK)
continue;
for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)
{
int index = archivePathsFull.FindInSorted(archiveLink.VolumePaths[v]);
if (index >= 0 && index > i)
{
archivePaths.Delete(index);
archivePathsFull.Delete(index);
}
}
UString password;
RINOK(openCallback->GetPasswordIfAny(password));
if (!password.IsEmpty())
{
RINOK(extractCallback->SetPassword(password));
}
options.DefaultItemName = archiveLink.GetDefaultItemName();
RINOK(DecompressArchive(
archiveLink.GetArchive(), archiveLink.GetDefaultItemName(),
wildcardCensor, options, extractCallback));
}
return S_OK;
}

55
7zip/UI/Common/Extract.h Executable file
View File

@@ -0,0 +1,55 @@
// Extract.h
#ifndef __EXTRACT_H
#define __EXTRACT_H
#include "Common/Wildcard.h"
#include "Windows/FileFind.h"
#include "../../Archive/IArchive.h"
#include "../Common/ZipRegistry.h"
#include "ArchiveExtractCallback.h"
#include "ArchiveOpenCallback.h"
#include "ExtractMode.h"
class CExtractOptions
{
public:
bool StdOutMode;
bool TestMode;
NExtract::NPathMode::EEnum PathMode;
UString OutputDir;
bool YesToAll;
UString DefaultItemName;
NWindows::NFile::NFind::CFileInfoW ArchiveFileInfo;
// bool ShowDialog;
// bool PasswordEnabled;
// UString Password;
NExtract::NOverwriteMode::EEnum OverwriteMode;
CExtractOptions():
StdOutMode(false),
YesToAll(false),
TestMode(false),
PathMode(NExtract::NPathMode::kFullPathnames),
OverwriteMode(NExtract::NOverwriteMode::kAskBefore)
{}
/*
bool FullPathMode() const { return (ExtractMode == NExtractMode::kTest) ||
(ExtractMode == NExtractMode::kFullPath); }
*/
};
HRESULT DecompressArchives(
UStringVector &archivePaths, UStringVector &archivePathsFull,
const NWildcard::CCensorNode &wildcardCensor,
const CExtractOptions &options,
IOpenCallbackUI *openCallback,
IExtractCallbackUI *extractCallback);
#endif

31
7zip/UI/Common/ExtractMode.h Executable file
View File

@@ -0,0 +1,31 @@
// ExtractMode.h
#ifndef __EXTRACT_MODE_H
#define __EXTRACT_MODE_H
namespace NExtract {
namespace NPathMode
{
enum EEnum
{
kFullPathnames,
kCurrentPathnames,
kNoPathnames
};
}
namespace NOverwriteMode
{
enum EEnum
{
kAskBefore,
kWithoutPrompt,
kSkipExisting,
kAutoRename,
kAutoRenameExisting
};
}
}
#endif

View File

@@ -3,20 +3,32 @@
#include "StdAfx.h"
#include "ExtractingFilePath.h"
static void ReplaceDisk(UString &s)
{
int i;
for (i = 0; i < s.Length(); i++)
if (s[i] != ' ')
break;
if (s.Length() > i + 1)
{
if (s[i + 1] == L':')
{
s.Delete(i + 1);
// s.Insert(i + 1, L'_');
}
}
}
UString GetCorrectFileName(const UString &path)
{
UString result = path;
result.Trim();
result.Replace(L"..\\", L"");
result.Replace(L"../", L"");
if (result.Length() > 1)
{
if (result[1] == L':')
{
result.Delete(1);
// result.Insert(first + 1, L'_');
}
UString test = path;
test.Trim();
if (test == L"..")
result.Replace(L"..", L"");
}
ReplaceDisk(result);
return result;
}
@@ -29,7 +41,6 @@ UString GetCorrectPath(const UString &path)
break;
while(result.Length() > first)
{
if (result[first] == L'\\' || result[first] == L'/')
{
result.Delete(first);
@@ -40,15 +51,19 @@ UString GetCorrectPath(const UString &path)
result.Replace(L"..\\", L"");
result.Replace(L"../", L"");
if (result.Length() > 1)
{
if (result[first + 1] == L':')
{
result.Delete(first + 1);
// result.Insert(first + 1, L'_');
}
}
ReplaceDisk(result);
return result;
}
void MakeCorrectPath(UStringVector &pathParts)
{
for (int i = 0; i < pathParts.Size();)
{
UString &s = pathParts[i];
s = GetCorrectFileName(s);
if (s.IsEmpty())
pathParts.Delete(i);
else
i++;
}
}

View File

@@ -1,7 +1,5 @@
// ExtractingFilePath.h
#pragma once
#ifndef __EXTRACTINGFILEPATH_H
#define __EXTRACTINGFILEPATH_H
@@ -9,5 +7,6 @@
UString GetCorrectFileName(const UString &path);
UString GetCorrectPath(const UString &path);
void MakeCorrectPath(UStringVector &pathParts);
#endif

View File

@@ -1,14 +1,12 @@
// HandlerLoader.h
#pragma once
#ifndef __HANDLERLOADER_H
#define __HANDLERLOADER_H
#include "../../ICoder.h"
#include "Windows/DLL.h"
typedef UINT32 (WINAPI * CreateObjectFunc)(
typedef UInt32 (WINAPI * CreateObjectFunc)(
const GUID *clsID,
const GUID *interfaceID,
void **outObject);
@@ -37,6 +35,4 @@ public:
}
};
#endif

View File

@@ -0,0 +1,46 @@
// IFileExtractCallback.h
#ifndef __IFILEEXTRACTCALLBACK_H
#define __IFILEEXTRACTCALLBACK_H
#include "Common/String.h"
namespace NOverwriteAnswer
{
enum EEnum
{
kYes,
kYesToAll,
kNo,
kNoToAll,
kAutoRename,
kCancel,
};
}
// {23170F69-40C1-278A-0000-000100070000}
DEFINE_GUID(IID_IFolderArchiveExtractCallback,
0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00);
MIDL_INTERFACE("23170F69-40C1-278A-0000-000100070000")
IFolderArchiveExtractCallback: public IProgress
{
public:
STDMETHOD(AskOverwrite)(
const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
Int32 *answer) PURE;
STDMETHOD(PrepareOperation)(const wchar_t *name, Int32 askExtractMode, const UInt64 *position) PURE;
STDMETHOD(MessageError)(const wchar_t *message) PURE;
STDMETHOD(SetOperationResult)(Int32 operationResult) PURE;
};
struct IExtractCallbackUI: IFolderArchiveExtractCallback
{
virtual HRESULT BeforeOpen(const wchar_t *name) = 0;
virtual HRESULT OpenResult(const wchar_t *name, HRESULT result) = 0;
virtual HRESULT ThereAreNoFiles() = 0;
virtual HRESULT ExtractResult(HRESULT result) = 0;
virtual HRESULT SetPassword(const UString &password) = 0;
};
#endif

View File

@@ -4,9 +4,12 @@
#include "OpenArchive.h"
#include "Common/Wildcard.h"
#include "Windows/FileName.h"
#include "Windows/FileDir.h"
#include "Windows/Defs.h"
#include "Windows/PropVariant.h"
#include "../../Common/FileStreams.h"
@@ -24,6 +27,10 @@
#include "../../Archive/GZip/GZipHandler.h"
#endif
#ifdef FORMAT_SPLIT
#include "../../Archive/Split/SplitHandler.h"
#endif
#ifdef FORMAT_TAR
#include "../../Archive/Tar/TarHandler.h"
#endif
@@ -32,17 +39,86 @@
#include "../../Archive/Zip/ZipHandler.h"
#endif
#ifdef FORMAT_Z
#include "../../Archive/Z/ZHandler.h"
#endif
#ifndef EXCLUDE_COM
#include "HandlerLoader.h"
#endif
#include "DefaultName.h"
using namespace NWindows;
const UINT64 kMaxCheckStartPosition = 1 << 20;
HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, UString &result)
{
NCOM::CPropVariant prop;
RINOK(archive->GetProperty(index, kpidPath, &prop));
if(prop.vt == VT_BSTR)
result = prop.bstrVal;
else if (prop.vt == VT_EMPTY)
result.Empty();
else
return E_FAIL;
return S_OK;
}
HRESULT ReOpenArchive(IInArchive *archive,
const UString &fileName)
HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, const UString &defaultName, UString &result)
{
RINOK(GetArchiveItemPath(archive, index, result));
if (result.IsEmpty())
result = defaultName;
return S_OK;
}
HRESULT GetArchiveItemFileTime(IInArchive *archive, UInt32 index,
const FILETIME &defaultFileTime, FILETIME &fileTime)
{
NCOM::CPropVariant prop;
RINOK(archive->GetProperty(index, kpidLastWriteTime, &prop));
if (prop.vt == VT_FILETIME)
fileTime = prop.filetime;
else if (prop.vt == VT_EMPTY)
fileTime = defaultFileTime;
else
return E_FAIL;
return S_OK;
}
static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
{
NCOM::CPropVariant prop;
RINOK(archive->GetProperty(index, propID, &prop));
if(prop.vt == VT_BOOL)
result = VARIANT_BOOLToBool(prop.boolVal);
else if (prop.vt == VT_EMPTY)
result = false;
else
return E_FAIL;
return S_OK;
}
HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
{
return IsArchiveItemProp(archive, index, kpidIsFolder, result);
}
HRESULT IsArchiveItemAnti(IInArchive *archive, UInt32 index, bool &result)
{
return IsArchiveItemProp(archive, index, kpidIsAnti, result);
}
// Static-SFX (for Linux) can be big
const UInt64 kMaxCheckStartPosition =
#ifdef _WIN32
1 << 20;
#else
1 << 22;
#endif
HRESULT ReOpenArchive(IInArchive *archive, const UString &fileName)
{
CInFileStream *inStreamSpec = new CInFileStream;
CMyComPtr<IInStream> inStream(inStreamSpec);
@@ -50,49 +126,87 @@ HRESULT ReOpenArchive(IInArchive *archive,
return archive->Open(inStream, &kMaxCheckStartPosition, NULL);
}
HRESULT OpenArchive(const UString &fileName,
#ifndef _SFX
static inline bool TestSignature(const Byte *p1, const Byte *p2, UInt32 size)
{
for (UInt32 i = 0; i < size; i++)
if (p1[i] != p2[i])
return false;
return true;
}
#endif
HRESULT OpenArchive(
IInStream *inStream,
const UString &fileName,
#ifndef EXCLUDE_COM
HMODULE *module,
#endif
IInArchive **archiveResult,
CArchiverInfo &archiverInfoResult,
int &subExtIndex,
UString &defaultItemName,
IArchiveOpenCallback *openArchiveCallback)
{
CInFileStream *inStreamSpec = new CInFileStream;
CMyComPtr<IInStream> inStream(inStreamSpec);
if (!inStreamSpec->Open(fileName))
return GetLastError();
*archiveResult = NULL;
CObjectVector<CArchiverInfo> archiverInfoList;
ReadArchiverInfoList(archiverInfoList);
UString extension;
{
UString name, pureName, dot;
if(!NFile::NDirectory::GetOnlyName(fileName, name))
return E_FAIL;
NFile::NName::SplitNameToPureNameAndExtension(name, pureName, dot, extension);
int dotPos = fileName.ReverseFind(L'.');
if (dotPos >= 0)
extension = fileName.Mid(dotPos + 1);
}
CIntVector orderIndices;
int firstArchiverIndex;
for(firstArchiverIndex = 0;
firstArchiverIndex < archiverInfoList.Size(); firstArchiverIndex++)
int i;
bool finded = false;
for(i = 0; i < archiverInfoList.Size(); i++)
{
int subIndex = archiverInfoList[firstArchiverIndex].FindExtension(extension);
if (subIndex >= 0)
break;
if (archiverInfoList[i].FindExtension(extension) >= 0)
{
orderIndices.Insert(0, i);
finded = true;
}
else
orderIndices.Add(i);
}
if(firstArchiverIndex < archiverInfoList.Size())
orderIndices.Add(firstArchiverIndex);
for(int j = 0; j < archiverInfoList.Size(); j++)
if(j != firstArchiverIndex)
orderIndices.Add(j);
HRESULT badResult = S_OK;
for(int i = 0; i < orderIndices.Size(); i++)
#ifndef _SFX
if (!finded)
{
inStreamSpec->Seek(0, STREAM_SEEK_SET, NULL);
CByteBuffer byteBuffer;
const UInt32 kBufferSize = (200 << 10);
byteBuffer.SetCapacity(kBufferSize);
Byte *buffer = byteBuffer;
RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
UInt32 processedSize;
RINOK(inStream->Read(buffer, kBufferSize, &processedSize));
int numFinded = 0;
for (int pos = (int)processedSize; pos >= 0 ; pos--)
{
for(int i = numFinded; i < orderIndices.Size(); i++)
{
int index = orderIndices[i];
const CArchiverInfo &ai = archiverInfoList[index];
const CByteBuffer &sig = ai.StartSignature;
if (sig.GetCapacity() == 0)
continue;
if (pos + sig.GetCapacity() > processedSize)
continue;
if (TestSignature(buffer + pos, sig, sig.GetCapacity()))
{
orderIndices.Delete(i);
orderIndices.Insert(0, index);
numFinded++;
}
}
}
}
#endif
HRESULT badResult = S_OK;
for(i = 0; i < orderIndices.Size(); i++)
{
inStream->Seek(0, STREAM_SEEK_SET, NULL);
const CArchiverInfo &archiverInfo = archiverInfoList[orderIndices[i]];
#ifndef EXCLUDE_COM
CHandlerLoader loader;
@@ -114,6 +228,11 @@ HRESULT OpenArchive(const UString &fileName,
archive = new NArchive::NGZip::CHandler;
#endif
#ifdef FORMAT_SPLIT
if (archiverInfo.Name.CompareNoCase(L"Split") == 0)
archive = new NArchive::NSplit::CHandler;
#endif
#ifdef FORMAT_TAR
if (archiverInfo.Name.CompareNoCase(L"Tar") == 0)
archive = new NArchive::NTar::CHandler;
@@ -124,6 +243,11 @@ HRESULT OpenArchive(const UString &fileName,
archive = new NArchive::NZip::CHandler;
#endif
#ifdef FORMAT_Z
if (archiverInfo.Name.CompareNoCase(L"Z") == 0)
archive = new NArchive::NZ::CHandler;
#endif
#ifndef EXCLUDE_COM
if (!archive)
@@ -144,28 +268,260 @@ HRESULT OpenArchive(const UString &fileName,
if(result != S_OK)
{
badResult = result;
if(result == E_ABORT)
break;
continue;
// return result;
}
*archiveResult = archive.Detach();
#ifndef EXCLUDE_COM
*module = loader.Detach();
#endif
archiverInfoResult = archiverInfo;
subExtIndex = archiverInfo.FindExtension(extension);
int subExtIndex = archiverInfo.FindExtension(extension);
if (subExtIndex < 0)
subExtIndex = 0;
defaultItemName = GetDefaultName2(fileName,
archiverInfo.Extensions[subExtIndex].Extension,
archiverInfo.Extensions[subExtIndex].AddExtension);
return S_OK;
}
if (badResult != S_OK)
return badResult;
return S_FALSE;
/*
#else
return S_FALSE;
#endif
#endif
*/
}
HRESULT OpenArchive(const UString &filePath,
#ifndef EXCLUDE_COM
HMODULE *module,
#endif
IInArchive **archiveResult,
CArchiverInfo &archiverInfo,
UString &defaultItemName,
IArchiveOpenCallback *openArchiveCallback)
{
CInFileStream *inStreamSpec = new CInFileStream;
CMyComPtr<IInStream> inStream(inStreamSpec);
if (!inStreamSpec->Open(filePath))
return GetLastError();
return OpenArchive(inStream, ExtractFileNameFromPath(filePath),
#ifndef EXCLUDE_COM
module,
#endif
archiveResult, archiverInfo,
defaultItemName, openArchiveCallback);
}
static void MakeDefaultName(UString &name)
{
int dotPos = name.ReverseFind(L'.');
if (dotPos < 0)
return;
UString ext = name.Mid(dotPos + 1);
if (ext.IsEmpty())
return;
for (int pos = 0; pos < ext.Length(); pos++)
if (ext[pos] < L'0' || ext[pos] > L'9')
return;
name = name.Left(dotPos);
}
HRESULT OpenArchive(const UString &fileName,
#ifndef EXCLUDE_COM
HMODULE *module0,
HMODULE *module1,
#endif
IInArchive **archive0,
IInArchive **archive1,
CArchiverInfo &archiverInfo0,
CArchiverInfo &archiverInfo1,
UString &defaultItemName0,
UString &defaultItemName1,
IArchiveOpenCallback *openArchiveCallback)
{
HRESULT result = OpenArchive(fileName,
#ifndef EXCLUDE_COM
module0,
#endif
archive0, archiverInfo0, defaultItemName0, openArchiveCallback);
RINOK(result);
CMyComPtr<IInArchiveGetStream> getStream;
result = (*archive0)->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream);
if (result != S_OK || getStream == 0)
return S_OK;
CMyComPtr<ISequentialInStream> subSeqStream;
result = getStream->GetStream(0, &subSeqStream);
if (result != S_OK)
return S_OK;
CMyComPtr<IInStream> subStream;
if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK)
return S_OK;
if (!subStream)
return S_OK;
UInt32 numItems;
RINOK((*archive0)->GetNumberOfItems(&numItems));
if (numItems < 1)
return S_OK;
UString subPath;
RINOK(GetArchiveItemPath(*archive0, 0, subPath))
if (subPath.IsEmpty())
{
MakeDefaultName(defaultItemName0);
subPath = defaultItemName0;
if (archiverInfo0.Name.CompareNoCase(L"7z") == 0)
{
if (subPath.Right(3).CompareNoCase(L".7z") != 0)
subPath += L".7z";
}
}
else
subPath = ExtractFileNameFromPath(subPath);
CMyComPtr<IArchiveOpenSetSubArchiveName> setSubArchiveName;
openArchiveCallback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName);
if (setSubArchiveName)
setSubArchiveName->SetSubArchiveName(subPath);
result = OpenArchive(subStream, subPath,
#ifndef EXCLUDE_COM
module1,
#endif
archive1, archiverInfo1, defaultItemName1, openArchiveCallback);
return S_OK;
}
HRESULT MyOpenArchive(const UString &archiveName,
#ifndef EXCLUDE_COM
HMODULE *module,
#endif
IInArchive **archive,
UString &defaultItemName,
IOpenCallbackUI *openCallbackUI)
{
COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
CMyComPtr<IArchiveOpenCallback> openCallback = openCallbackSpec;
openCallbackSpec->Callback = openCallbackUI;
UString fullName;
int fileNamePartStartIndex;
NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex);
openCallbackSpec->Init(
fullName.Left(fileNamePartStartIndex),
fullName.Mid(fileNamePartStartIndex));
CArchiverInfo archiverInfo;
return OpenArchive(archiveName,
#ifndef EXCLUDE_COM
module,
#endif
archive,
archiverInfo,
defaultItemName,
openCallback);
}
HRESULT MyOpenArchive(const UString &archiveName,
#ifndef EXCLUDE_COM
HMODULE *module0,
HMODULE *module1,
#endif
IInArchive **archive0,
IInArchive **archive1,
UString &defaultItemName0,
UString &defaultItemName1,
UStringVector &volumePaths,
IOpenCallbackUI *openCallbackUI)
{
COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
CMyComPtr<IArchiveOpenCallback> openCallback = openCallbackSpec;
openCallbackSpec->Callback = openCallbackUI;
UString fullName;
int fileNamePartStartIndex;
NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex);
UString prefix = fullName.Left(fileNamePartStartIndex);
UString name = fullName.Mid(fileNamePartStartIndex);
openCallbackSpec->Init(prefix, name);
CArchiverInfo archiverInfo0, archiverInfo1;
HRESULT result = OpenArchive(archiveName,
#ifndef EXCLUDE_COM
module0,
module1,
#endif
archive0,
archive1,
archiverInfo0,
archiverInfo1,
defaultItemName0,
defaultItemName1,
openCallback);
RINOK(result);
volumePaths.Add(prefix + name);
for (int i = 0; i < openCallbackSpec->FileNames.Size(); i++)
volumePaths.Add(prefix + openCallbackSpec->FileNames[i]);
return S_OK;
}
HRESULT CArchiveLink::Close()
{
if (Archive1 != 0)
RINOK(Archive1->Close());
if (Archive0 != 0)
RINOK(Archive0->Close());
return S_OK;
}
void CArchiveLink::Release()
{
if (Archive1 != 0)
Archive1.Release();
if (Archive0 != 0)
Archive0.Release();
#ifndef EXCLUDE_COM
Library1.Free();
Library0.Free();
#endif
}
HRESULT OpenArchive(const UString &archiveName,
CArchiveLink &archiveLink,
IArchiveOpenCallback *openCallback)
{
return OpenArchive(archiveName,
#ifndef EXCLUDE_COM
&archiveLink.Library0, &archiveLink.Library1,
#endif
&archiveLink.Archive0, &archiveLink.Archive1,
archiveLink.ArchiverInfo0, archiveLink.ArchiverInfo1,
archiveLink.DefaultItemName0, archiveLink.DefaultItemName1,
openCallback);
}
HRESULT MyOpenArchive(const UString &archiveName,
CArchiveLink &archiveLink,
IOpenCallbackUI *openCallbackUI)
{
return MyOpenArchive(archiveName,
#ifndef EXCLUDE_COM
&archiveLink.Library0, &archiveLink.Library1,
#endif
&archiveLink.Archive0, &archiveLink.Archive1,
archiveLink.DefaultItemName0, archiveLink.DefaultItemName1,
archiveLink.VolumePaths,
openCallbackUI);
}
HRESULT ReOpenArchive(CArchiveLink &archiveLink,
const UString &fileName)
{
if (archiveLink.GetNumLevels() > 1)
return E_NOTIMPL;
if (archiveLink.GetNumLevels() == 0)
return MyOpenArchive(fileName, archiveLink, 0);
return ReOpenArchive(archiveLink.GetArchive(), fileName);
}

View File

@@ -4,21 +4,130 @@
#define __OPENARCHIVE_H
#include "Common/String.h"
#include "Windows/FileFind.h"
#include "../../Archive/IArchive.h"
#include "ArchiverInfo.h"
#include "ArchiveOpenCallback.h"
HRESULT OpenArchive(const UString &fileName,
#ifndef EXCLUDE_COM
#include "Windows/DLL.h"
#endif
HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, const UString &defaultName, UString &result);
HRESULT GetArchiveItemFileTime(IInArchive *archive, UInt32 index,
const FILETIME &defaultFileTime, FILETIME &fileTime);
HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result);
HRESULT IsArchiveItemAnti(IInArchive *archive, UInt32 index, bool &result);
struct ISetSubArchiveName
{
virtual void SetSubArchiveName(const wchar_t *name) = 0;
};
HRESULT OpenArchive(
IInStream *inStream,
const UString &fileName,
#ifndef EXCLUDE_COM
HMODULE *module,
#endif
IInArchive **archiveResult,
CArchiverInfo &archiverInfoResult,
UString &defaultItemName,
IArchiveOpenCallback *openArchiveCallback);
HRESULT OpenArchive(const UString &filePath,
#ifndef EXCLUDE_COM
HMODULE *module,
#endif
IInArchive **archive,
CArchiverInfo &archiverInfoResult,
int &subExtIndex,
CArchiverInfo &archiverInfo,
UString &defaultItemName,
IArchiveOpenCallback *openArchiveCallback);
HRESULT OpenArchive(const UString &filePath,
#ifndef EXCLUDE_COM
HMODULE *module0,
HMODULE *module1,
#endif
IInArchive **archive0,
IInArchive **archive1,
CArchiverInfo &archiverInfo0,
CArchiverInfo &archiverInfo1,
UString &defaultItemName0,
UString &defaultItemName1,
IArchiveOpenCallback *openArchiveCallback);
HRESULT ReOpenArchive(IInArchive *archive,
const UString &fileName);
HRESULT MyOpenArchive(const UString &archiveName,
#ifndef EXCLUDE_COM
HMODULE *module,
#endif
IInArchive **archive,
UString &defaultItemName,
IOpenCallbackUI *openCallbackUI);
HRESULT MyOpenArchive(const UString &archiveName,
#ifndef EXCLUDE_COM
HMODULE *module0,
HMODULE *module1,
#endif
IInArchive **archive0,
IInArchive **archive1,
UString &defaultItemName0,
UString &defaultItemName1,
UStringVector &volumePaths,
IOpenCallbackUI *openCallbackUI);
struct CArchiveLink
{
#ifndef EXCLUDE_COM
NWindows::NDLL::CLibrary Library0;
NWindows::NDLL::CLibrary Library1;
#endif
CMyComPtr<IInArchive> Archive0;
CMyComPtr<IInArchive> Archive1;
UString DefaultItemName0;
UString DefaultItemName1;
CArchiverInfo ArchiverInfo0;
CArchiverInfo ArchiverInfo1;
UStringVector VolumePaths;
int GetNumLevels() const
{
int result = 0;
if (Archive0)
{
result++;
if (Archive1)
result++;
}
return result;
}
IInArchive *GetArchive() { return Archive1 != 0 ? Archive1: Archive0; }
UString GetDefaultItemName() { return Archive1 != 0 ? DefaultItemName1: DefaultItemName0; }
const CArchiverInfo &GetArchiverInfo() { return Archive1 != 0 ? ArchiverInfo1: ArchiverInfo0; }
HRESULT Close();
void Release();
};
HRESULT OpenArchive(const UString &archiveName,
CArchiveLink &archiveLink,
IArchiveOpenCallback *openCallback);
HRESULT MyOpenArchive(const UString &archiveName,
CArchiveLink &archiveLink,
IOpenCallbackUI *openCallbackUI);
HRESULT ReOpenArchive(CArchiveLink &archiveLink,
const UString &fileName);
#endif

View File

@@ -14,13 +14,24 @@
using namespace NWindows;
static UString ConvertUINT32ToString(UINT32 value)
static UString ConvertUInt32ToString(UInt32 value)
{
wchar_t buffer[32];
ConvertUINT64ToString(value, buffer);
ConvertUInt64ToString(value, buffer);
return buffer;
}
static void ConvertUInt32ToHex(UInt32 value, wchar_t *s)
{
for (int i = 0; i < 8; i++)
{
int t = value & 0xF;
value >>= 4;
s[7 - i] = (wchar_t)((t < 10) ? (L'0' + t) : (L'A' + (t - 10)));
}
s[8] = L'\0';
}
UString ConvertPropertyToString(const PROPVARIANT &propVariant,
PROPID propID, bool full)
{
@@ -38,22 +49,22 @@ UString ConvertPropertyToString(const PROPVARIANT &propVariant,
return UString();
if (!::FileTimeToLocalFileTime(&propVariant.filetime, &localFileTime))
return UString(); // It is error;
return ConvertFileTimeToString2(localFileTime, true, full);
return ConvertFileTimeToString(localFileTime, true, full);
}
case kpidCRC:
{
if(propVariant.vt != VT_UI4)
break;
TCHAR temp[17];
wsprintf(temp, TEXT("%08X"), propVariant.ulVal);
return GetUnicodeString(temp);
wchar_t temp[12];
ConvertUInt32ToHex(propVariant.ulVal, temp);
return temp;
}
case kpidAttributes:
{
if(propVariant.vt != VT_UI4)
break;
UString result;
UINT32 attributes = propVariant.ulVal;
UInt32 attributes = propVariant.ulVal;
if (NFile::NFind::NAttributes::IsReadOnly(attributes)) result += L'R';
if (NFile::NFind::NAttributes::IsHidden(attributes)) result += L'H';
if (NFile::NFind::NAttributes::IsSystem(attributes)) result += L'S';
@@ -67,12 +78,12 @@ UString ConvertPropertyToString(const PROPVARIANT &propVariant,
{
if(propVariant.vt != VT_UI4)
break;
UINT32 size = propVariant.ulVal;
UInt32 size = propVariant.ulVal;
if (size % (1 << 20) == 0)
return ConvertUINT32ToString(size >> 20) + L"MB";
return ConvertUInt32ToString(size >> 20) + L"MB";
if (size % (1 << 10) == 0)
return ConvertUINT32ToString(size >> 10) + L"KB";
return ConvertUINT32ToString(size);
return ConvertUInt32ToString(size >> 10) + L"KB";
return ConvertUInt32ToString(size);
}
}
return ConvertPropVariantToString(propVariant);

View File

@@ -1,7 +1,5 @@
// PropIDUtils.h
#pragma once
#ifndef __PROPIDUTILS_H
#define __PROPIDUTILS_H

View File

@@ -11,7 +11,7 @@ static int __cdecl CompareStrings(const void *a1, const void *a2)
return s1.CompareNoCase(s2);
}
void SortStringsToIndices(UStringVector &strings, CIntVector &indices)
void SortStringsToIndices(const UStringVector &strings, CIntVector &indices)
{
indices.Clear();
if (strings.IsEmpty())
@@ -22,9 +22,19 @@ void SortStringsToIndices(UStringVector &strings, CIntVector &indices)
indices.Reserve(numItems);
int i;
for(i = 0; i < numItems; i++)
pointers.Add(&strings.CPointerVector::operator[](i));
pointers.Add((void *)&strings.CPointerVector::operator[](i));
void **stringsBase = (void **)pointers[0];
qsort(&pointers[0], numItems, sizeof(void *), CompareStrings);
for(i = 0; i < numItems; i++)
indices.Add((void **)pointers[i] - stringsBase);
}
void SortStrings(const UStringVector &src, UStringVector &dest)
{
CIntVector indices;
SortStringsToIndices(src, indices);
dest.Clear();
dest.Reserve(indices.Size());
for (int i = 0; i < indices.Size(); i++)
dest.Add(src[indices[i]]);
}

View File

@@ -1,12 +1,11 @@
// SortUtils.h
#pragma once
#ifndef __SORTUTLS_H
#define __SORTUTLS_H
#include "Common/String.h"
void SortStringsToIndices(UStringVector &strings, CIntVector &indices);
void SortStringsToIndices(const UStringVector &strings, CIntVector &indices);
void SortStrings(const UStringVector &src, UStringVector &dest);
#endif

22
7zip/UI/Common/TempFiles.cpp Executable file
View File

@@ -0,0 +1,22 @@
// TempFiles.cpp
#include "StdAfx.h"
#include "TempFiles.h"
#include "Windows/FileDir.h"
#include "Windows/FileIO.h"
using namespace NWindows;
using namespace NFile;
void CTempFiles::Clear()
{
while(!Paths.IsEmpty())
{
NDirectory::DeleteFileAlways(Paths.Back());
Paths.DeleteBack();
}
}

16
7zip/UI/Common/TempFiles.h Executable file
View File

@@ -0,0 +1,16 @@
// TempFiles.h
#ifndef __TEMPFILES_H
#define __TEMPFILES_H
#include "Common/String.h"
class CTempFiles
{
void Clear();
public:
UStringVector Paths;
~CTempFiles() { Clear(); }
};
#endif

850
7zip/UI/Common/Update.cpp Executable file
View File

@@ -0,0 +1,850 @@
// Update.cpp
#include "StdAfx.h"
#ifdef _WIN32
#include <mapi.h>
#endif
#include "Update.h"
#include "Common/IntToString.h"
#include "Common/StringToInt.h"
#include "Common/StringConvert.h"
#include "Common/CommandLineParser.h"
#ifdef _WIN32
#include "Windows/DLL.h"
#endif
#include "Windows/Defs.h"
#include "Windows/FileDir.h"
#include "Windows/FileFind.h"
#include "Windows/FileName.h"
#include "Windows/PropVariant.h"
#include "Windows/PropVariantConversions.h"
// #include "Windows/Synchronization.h"
#include "../../Common/FileStreams.h"
#include "../../Compress/Copy/CopyCoder.h"
#include "../Common/DirItem.h"
#include "../Common/EnumDirItems.h"
#include "../Common/UpdateProduce.h"
#include "../Common/OpenArchive.h"
#include "TempFiles.h"
#include "UpdateCallback.h"
#include "EnumDirItems.h"
#ifdef FORMAT_7Z
#include "../../Archive/7z/7zHandler.h"
#endif
#ifdef FORMAT_BZIP2
#include "../../Archive/BZip2/BZip2Handler.h"
#endif
#ifdef FORMAT_GZIP
#include "../../Archive/GZip/GZipHandler.h"
#endif
#ifdef FORMAT_TAR
#include "../../Archive/Tar/TarHandler.h"
#endif
#ifdef FORMAT_ZIP
#include "../../Archive/Zip/ZipHandler.h"
#endif
#ifndef EXCLUDE_COM
#include "../Common/HandlerLoader.h"
#endif
static const char *kUpdateIsNotSupoorted =
"update operations are not supported for this archive";
using namespace NCommandLineParser;
using namespace NWindows;
using namespace NCOM;
using namespace NFile;
using namespace NName;
static const wchar_t *kTempArchiveFilePrefixString = L"7zi";
static const wchar_t *kTempFolderPrefix = L"7zE";
static const char *kIllegalFileNameMessage = "Illegal file name for temp archive";
using namespace NUpdateArchive;
static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
{
const wchar_t *endPtr;
UInt64 result = ConvertStringToUInt64(s, &endPtr);
if (endPtr - (const wchar_t *)s != s.Length())
prop = s;
else if (result <= 0xFFFFFFFF)
prop = (UInt32)result;
else
prop = result;
}
static HRESULT CopyBlock(ISequentialInStream *inStream, ISequentialOutStream *outStream)
{
CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
return copyCoder->Code(inStream, outStream, NULL, NULL, NULL);
}
class COutMultiVolStream:
public IOutStream,
public CMyUnknownImp
{
size_t _streamIndex; // required stream
UInt64 _offsetPos; // offset from start of _streamIndex index
UInt64 _absPos;
UInt64 _length;
struct CSubStreamInfo
{
CMyComPtr<IOutStream> Stream;
UString Name;
UInt64 Pos;
UInt64 RealSize;
};
CObjectVector<CSubStreamInfo> Streams;
public:
// CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
CRecordVector<UInt64> Sizes;
UString Prefix;
CTempFiles *TempFiles;
void Init()
{
_streamIndex = 0;
_offsetPos = 0;
_absPos = 0;
_length = 0;
}
MY_UNKNOWN_IMP1(IOutStream)
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
STDMETHOD(WritePart)(const void *data, UInt32 size, UInt32 *processedSize);
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
STDMETHOD(SetSize)(Int64 newSize);
};
// static NSynchronization::CCriticalSection g_TempPathsCS;
STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
{
if(processedSize != NULL)
*processedSize = 0;
while(size > 0)
{
if (_streamIndex >= (size_t)Streams.Size())
{
CSubStreamInfo subStream;
wchar_t temp[32];
ConvertUInt64ToString(_streamIndex + 1, temp);
UString res = temp;
while (res.Length() < 3)
res = UString(L'0') + res;
UString name = Prefix + res;
COutFileStream *streamSpec = new COutFileStream;
subStream.Stream = streamSpec;
if(!streamSpec->Create(name, false))
return ::GetLastError();
{
// NSynchronization::CCriticalSectionLock lock(g_TempPathsCS);
TempFiles->Paths.Add(name);
}
subStream.Pos = 0;
subStream.RealSize = 0;
subStream.Name = name;
Streams.Add(subStream);
continue;
}
CSubStreamInfo &subStream = Streams[_streamIndex];
int index = _streamIndex;
if (index >= Sizes.Size())
index = Sizes.Size() - 1;
UInt64 volSize = Sizes[index];
if (_offsetPos >= volSize)
{
_offsetPos -= volSize;
_streamIndex++;
continue;
}
if (_offsetPos != subStream.Pos)
{
// CMyComPtr<IOutStream> outStream;
// RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));
RINOK(subStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));
subStream.Pos = _offsetPos;
}
UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - subStream.Pos);
UInt32 realProcessed;
RINOK(subStream.Stream->Write(data, curSize, &realProcessed));
data = (void *)((Byte *)data + realProcessed);
size -= realProcessed;
subStream.Pos += realProcessed;
_offsetPos += realProcessed;
_absPos += realProcessed;
if (_absPos > _length)
_length = _absPos;
if (_offsetPos > subStream.RealSize)
subStream.RealSize = _offsetPos;
if(processedSize != NULL)
*processedSize += realProcessed;
if (subStream.Pos == volSize)
{
_streamIndex++;
_offsetPos = 0;
}
if (realProcessed != curSize)
return E_FAIL;
}
return S_OK;
}
STDMETHODIMP COutMultiVolStream::WritePart(const void *data, UInt32 size, UInt32 *processedSize)
{
return Write(data, size, processedSize);
}
STDMETHODIMP COutMultiVolStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
{
if(seekOrigin >= 3)
return STG_E_INVALIDFUNCTION;
switch(seekOrigin)
{
case STREAM_SEEK_SET:
_absPos = offset;
break;
case STREAM_SEEK_CUR:
_absPos += offset;
break;
case STREAM_SEEK_END:
_absPos = _length + offset;
break;
}
_offsetPos = _absPos;
if (newPosition != NULL)
*newPosition = _absPos;
_streamIndex = 0;
return S_OK;
}
STDMETHODIMP COutMultiVolStream::SetSize(Int64 newSize)
{
if (newSize < 0)
return E_INVALIDARG;
int i = 0;
while (i < Streams.Size())
{
CSubStreamInfo &subStream = Streams[i++];
if ((UInt64)newSize < subStream.RealSize)
{
RINOK(subStream.Stream->SetSize(newSize));
subStream.RealSize = newSize;
break;
}
newSize -= subStream.RealSize;
}
while (i < Streams.Size())
{
{
CSubStreamInfo &subStream = Streams.Back();
subStream.Stream.Release();
NDirectory::DeleteFileAlways(subStream.Name);
}
Streams.DeleteBack();
}
_offsetPos = _absPos;
_streamIndex = 0;
_length = newSize;
return S_OK;
}
static HRESULT Compress(
const CActionSet &actionSet,
IInArchive *archive,
const CCompressionMethodMode &compressionMethod,
CArchivePath &archivePath,
const CObjectVector<CArchiveItem> &archiveItems,
bool stdInMode,
const UString &stdInFileName,
bool stdOutMode,
const CObjectVector<CDirItem> &dirItems,
bool sfxMode,
const UString &sfxModule,
const CRecordVector<UInt64> &volumesSizes,
CTempFiles &tempFiles,
CUpdateErrorInfo &errorInfo,
IUpdateCallbackUI *callback)
{
#ifndef EXCLUDE_COM
CHandlerLoader loader;
#endif
CMyComPtr<IOutArchive> outArchive;
if(archive != NULL)
{
CMyComPtr<IInArchive> archive2 = archive;
HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive);
if(result != S_OK)
throw kUpdateIsNotSupoorted;
}
else
{
#ifndef EXCLUDE_COM
if (loader.CreateHandler(compressionMethod.FilePath,
compressionMethod.ClassID, (void **)&outArchive, true) != S_OK)
throw kUpdateIsNotSupoorted;
#endif
#ifdef FORMAT_7Z
if (compressionMethod.Name.CompareNoCase(L"7z") == 0)
outArchive = new NArchive::N7z::CHandler;
#endif
#ifdef FORMAT_BZIP2
if (compressionMethod.Name.CompareNoCase(L"BZip2") == 0)
outArchive = new NArchive::NBZip2::CHandler;
#endif
#ifdef FORMAT_GZIP
if (compressionMethod.Name.CompareNoCase(L"GZip") == 0)
outArchive = new NArchive::NGZip::CHandler;
#endif
#ifdef FORMAT_TAR
if (compressionMethod.Name.CompareNoCase(L"Tar") == 0)
outArchive = new NArchive::NTar::CHandler;
#endif
#ifdef FORMAT_ZIP
if (compressionMethod.Name.CompareNoCase(L"Zip") == 0)
outArchive = new NArchive::NZip::CHandler;
#endif
}
if (outArchive == 0)
throw kUpdateIsNotSupoorted;
NFileTimeType::EEnum fileTimeType;
UInt32 value;
RINOK(outArchive->GetFileTimeType(&value));
switch(value)
{
case NFileTimeType::kWindows:
case NFileTimeType::kDOS:
case NFileTimeType::kUnix:
fileTimeType = NFileTimeType::EEnum(value);
break;
default:
return E_FAIL;
}
CObjectVector<CUpdatePair> updatePairs;
GetUpdatePairInfoList(dirItems, archiveItems, fileTimeType, updatePairs); // must be done only once!!!
CObjectVector<CUpdatePair2> updatePairs2;
UpdateProduce(dirItems, archiveItems, updatePairs, actionSet, updatePairs2);
CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec );
updateCallbackSpec->StdInMode = stdInMode;
updateCallbackSpec->Callback = callback;
updateCallbackSpec->DirItems = &dirItems;
updateCallbackSpec->ArchiveItems = &archiveItems;
updateCallbackSpec->UpdatePairs = &updatePairs2;
CMyComPtr<ISequentialOutStream> outStream;
const UString &archiveName = archivePath.GetFinalPath();
if (!stdOutMode)
{
UString resultPath;
int pos;
if(!NFile::NDirectory::MyGetFullPathName(archiveName, resultPath, pos))
throw 1417161;
NFile::NDirectory::CreateComplexDirectory(resultPath.Left(pos));
}
if (volumesSizes.Size() == 0)
{
if (stdOutMode)
outStream = new CStdOutFileStream;
else
{
COutFileStream *outStreamSpec = new COutFileStream;
outStream = outStreamSpec;
bool isOK = false;
UString realPath;
for (int i = 0; i < (1 << 16); i++)
{
if (archivePath.Temp)
{
if (i > 0)
{
wchar_t s[32];
ConvertUInt64ToString(i, s);
archivePath.TempPostfix = s;
}
realPath = archivePath.GetTempPath();
}
else
realPath = archivePath.GetFinalPath();
if (outStreamSpec->Create(realPath, false))
{
tempFiles.Paths.Add(realPath);
isOK = true;
break;
}
if (::GetLastError() != ERROR_FILE_EXISTS)
break;
if (!archivePath.Temp)
break;
}
if (!isOK)
{
errorInfo.SystemError = ::GetLastError();
errorInfo.FileName = realPath;
errorInfo.Message = L"Can not open file";
return E_FAIL;
}
}
}
else
{
if (stdOutMode)
return E_FAIL;
COutMultiVolStream *volStreamSpec = new COutMultiVolStream;
outStream = volStreamSpec;
volStreamSpec->Sizes = volumesSizes;
volStreamSpec->Prefix = archivePath.GetFinalPath() + UString(L".");
volStreamSpec->TempFiles = &tempFiles;
volStreamSpec->Init();
/*
updateCallbackSpec->VolumesSizes = volumesSizes;
updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name;
if (!archivePath.VolExtension.IsEmpty())
updateCallbackSpec->VolExt = UString(L'.') + archivePath.VolExtension;
*/
}
CMyComPtr<ISetProperties> setProperties;
if (outArchive.QueryInterface(IID_ISetProperties, &setProperties) == S_OK)
{
UStringVector realNames;
CPropVariant *values = new CPropVariant[compressionMethod.Properties.Size()];
try
{
int i;
for(i = 0; i < compressionMethod.Properties.Size(); i++)
{
const CProperty &property = compressionMethod.Properties[i];
NCOM::CPropVariant propVariant;
if (!property.Value.IsEmpty())
ParseNumberString(property.Value, propVariant);
realNames.Add(property.Name);
values[i] = propVariant;
}
CRecordVector<const wchar_t *> names;
for(i = 0; i < realNames.Size(); i++)
names.Add((const wchar_t *)realNames[i]);
RINOK(setProperties->SetProperties(&names.Front(), values, names.Size()));
}
catch(...)
{
delete []values;
throw;
}
delete []values;
}
if (sfxMode)
{
CInFileStream *sfxStreamSpec = new CInFileStream;
CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
if (!sfxStreamSpec->Open(sfxModule))
{
errorInfo.SystemError = ::GetLastError();
errorInfo.Message = L"Can't open sfx module";
errorInfo.FileName = sfxModule;
return E_FAIL;
}
CMyComPtr<ISequentialOutStream> sfxOutStream;
if (volumesSizes.Size() == 0)
sfxOutStream = outStream;
else
{
COutFileStream *outStreamSpec = new COutFileStream;
sfxOutStream = outStreamSpec;
UString realPath = archivePath.GetFinalPath();
if (!outStreamSpec->Create(realPath, false))
{
errorInfo.SystemError = ::GetLastError();
errorInfo.FileName = realPath;
errorInfo.Message = L"Can not open file";
return E_FAIL;
}
}
RINOK(CopyBlock(sfxStream, sfxOutStream));
}
HRESULT result = outArchive->UpdateItems(outStream, updatePairs2.Size(),
updateCallback);
callback->Finilize();
return result;
}
HRESULT EnumerateInArchiveItems(const NWildcard::CCensor &censor,
IInArchive *archive,
const UString &defaultItemName,
const NWindows::NFile::NFind::CFileInfoW &archiveFileInfo,
CObjectVector<CArchiveItem> &archiveItems)
{
archiveItems.Clear();
UInt32 numItems;
RINOK(archive->GetNumberOfItems(&numItems));
archiveItems.Reserve(numItems);
for(UInt32 i = 0; i < numItems; i++)
{
CArchiveItem ai;
RINOK(GetArchiveItemPath(archive, i, defaultItemName, ai.Name));
RINOK(IsArchiveItemFolder(archive, i, ai.IsDirectory));
ai.Censored = censor.CheckPath(ai.Name, !ai.IsDirectory);
RINOK(GetArchiveItemFileTime(archive, i,
archiveFileInfo.LastWriteTime, ai.LastWriteTime));
CPropVariant propertySize;
RINOK(archive->GetProperty(i, kpidSize, &propertySize));
if (ai.SizeIsDefined = (propertySize.vt != VT_EMPTY))
ai.Size = ConvertPropVariantToUInt64(propertySize);
ai.IndexInServer = i;
archiveItems.Add(ai);
}
return S_OK;
}
static HRESULT UpdateWithItemLists(
CUpdateOptions &options,
IInArchive *archive,
const CObjectVector<CArchiveItem> &archiveItems,
const CObjectVector<CDirItem> &dirItems,
CTempFiles &tempFiles,
CUpdateErrorInfo &errorInfo,
IUpdateCallbackUI2 *callback)
{
for(int i = 0; i < options.Commands.Size(); i++)
{
CUpdateArchiveCommand &command = options.Commands[i];
if (options.StdOutMode)
{
RINOK(callback->StartArchive(0, archive != 0));
}
else
{
RINOK(callback->StartArchive(command.ArchivePath.GetFinalPath(),
i == 0 && options.UpdateArchiveItself && archive != 0));
}
RINOK(Compress(command.ActionSet, archive,
options.MethodMode,
command.ArchivePath,
archiveItems,
options.StdInMode, options.StdInFileName,
options.StdOutMode,
dirItems,
options.SfxMode, options.SfxModule,
options.VolumesSizes,
tempFiles,
errorInfo, callback));
RINOK(callback->FinishArchive());
}
return S_OK;
}
#ifdef _WIN32
class CCurrentDirRestorer
{
CSysString m_CurrentDirectory;
public:
CCurrentDirRestorer()
{ NFile::NDirectory::MyGetCurrentDirectory(m_CurrentDirectory); }
~CCurrentDirRestorer()
{ RestoreDirectory();}
bool RestoreDirectory()
{ return BOOLToBool(::SetCurrentDirectory(m_CurrentDirectory)); }
};
#endif
struct CEnumDirItemUpdateCallback: public IEnumDirItemCallback
{
IUpdateCallbackUI2 *Callback;
HRESULT CheckBreak() { return Callback->CheckBreak(); }
};
HRESULT UpdateArchive(const NWildcard::CCensor &censor,
CUpdateOptions &options,
CUpdateErrorInfo &errorInfo,
IOpenCallbackUI *openCallback,
IUpdateCallbackUI2 *callback)
{
if (options.StdOutMode && options.EMailMode)
return E_FAIL;
if (options.VolumesSizes.Size() > 0 && (options.EMailMode || options.SfxMode))
return E_NOTIMPL;
if (options.SfxMode)
{
CProperty property;
property.Name = L"rsfx";
property.Value = L"on";
options.MethodMode.Properties.Add(property);
if (options.SfxModule.IsEmpty())
{
errorInfo.Message = L"sfx file is not specified";
return E_FAIL;
}
UString name = options.SfxModule;
if (!NDirectory::MySearchPath(NULL, name, NULL, options.SfxModule))
{
errorInfo.Message = L"can't find specified sfx module";
return E_FAIL;
}
}
const UString archiveName = options.ArchivePath.GetFinalPath();
UString defaultItemName;
NFind::CFileInfoW archiveFileInfo;
CArchiveLink archiveLink;
IInArchive *archive = 0;
if (NFind::FindFile(archiveName, archiveFileInfo))
{
if (archiveFileInfo.IsDirectory())
throw "there is no such archive";
if (options.VolumesSizes.Size() > 0)
return E_NOTIMPL;
HRESULT result = MyOpenArchive(archiveName, archiveLink, openCallback);
RINOK(callback->OpenResult(archiveName, result));
RINOK(result);
if (archiveLink.VolumePaths.Size() > 1)
{
errorInfo.SystemError = E_NOTIMPL;
errorInfo.Message = L"Updating for multivolume archives is not implemented";
return E_NOTIMPL;
}
archive = archiveLink.GetArchive();
defaultItemName = archiveLink.GetDefaultItemName();
}
else
{
/*
if (archiveType.IsEmpty())
throw "type of archive is not specified";
*/
}
CObjectVector<CDirItem> dirItems;
if (options.StdInMode)
{
CDirItem item;
item.FullPath = item.Name = options.StdInFileName;
item.Size = (UInt64)(Int64)-1;
item.Attributes = 0;
SYSTEMTIME st;
FILETIME ft;
GetSystemTime(&st);
SystemTimeToFileTime(&st, &ft);
item.CreationTime = item.LastAccessTime = item.LastWriteTime = ft;
dirItems.Add(item);
}
else
{
bool needScanning = false;
for(int i = 0; i < options.Commands.Size(); i++)
if (options.Commands[i].ActionSet.NeedScanning())
needScanning = true;
if (needScanning)
{
CEnumDirItemUpdateCallback enumCallback;
enumCallback.Callback = callback;
RINOK(callback->StartScanning());
RINOK(EnumerateItems(censor, dirItems, &enumCallback));
RINOK(callback->FinishScanning());
}
}
UString tempDirPrefix;
bool usesTempDir = false;
#ifdef _WIN32
NDirectory::CTempDirectoryW tempDirectory;
if (options.EMailMode && options.EMailRemoveAfter)
{
tempDirectory.Create(kTempFolderPrefix);
tempDirPrefix = tempDirectory.GetPath();
NormalizeDirPathPrefix(tempDirPrefix);
usesTempDir = true;
}
#endif
CTempFiles tempFiles;
bool createTempFile = false;
if(!options.StdOutMode && options.UpdateArchiveItself)
{
CArchivePath &ap = options.Commands[0].ArchivePath;
ap = options.ArchivePath;
// if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty())
if ((archive != 0 || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0)
{
createTempFile = true;
ap.Temp = true;
if (!options.WorkingDir.IsEmpty())
{
ap.TempPrefix = options.WorkingDir;
NormalizeDirPathPrefix(ap.TempPrefix);
}
}
}
for(int i = 0; i < options.Commands.Size(); i++)
{
CArchivePath &ap = options.Commands[i].ArchivePath;
if (usesTempDir)
{
// Check it
ap.Prefix = tempDirPrefix;
// ap.Temp = true;
// ap.TempPrefix = tempDirPrefix;
}
if (i > 0 || !createTempFile)
{
const UString &path = ap.GetFinalPath();
if (NFind::DoesFileExist(path))
{
errorInfo.SystemError = 0;
errorInfo.Message = L"File already exists";
errorInfo.FileName = path;
return E_FAIL;
}
}
}
CObjectVector<CArchiveItem> archiveItems;
if (archive != NULL)
{
RINOK(EnumerateInArchiveItems(censor,
archive, defaultItemName, archiveFileInfo, archiveItems));
}
RINOK(UpdateWithItemLists(options, archive, archiveItems, dirItems,
tempFiles, errorInfo, callback));
if (archive != NULL)
{
RINOK(archiveLink.Close());
archiveLink.Release();
}
tempFiles.Paths.Clear();
if(createTempFile)
{
try
{
CArchivePath &ap = options.Commands[0].ArchivePath;
const UString &tempPath = ap.GetTempPath();
if (archive != NULL)
if (!NDirectory::DeleteFileAlways(archiveName))
{
errorInfo.SystemError = ::GetLastError();
errorInfo.Message = L"delete file error";
errorInfo.FileName = archiveName;
return E_FAIL;
}
if (!NDirectory::MyMoveFile(tempPath, archiveName))
{
errorInfo.SystemError = ::GetLastError();
errorInfo.Message = L"move file error";
errorInfo.FileName = tempPath;
errorInfo.FileName2 = archiveName;
return E_FAIL;
}
}
catch(...)
{
throw;
}
}
#ifdef _WIN32
if (options.EMailMode)
{
NDLL::CLibrary mapiLib;
if (!mapiLib.Load(TEXT("Mapi32.dll")))
{
errorInfo.SystemError = ::GetLastError();
errorInfo.Message = L"can not load Mapi32.dll";
return E_FAIL;
}
LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)
mapiLib.GetProcAddress("MAPISendDocuments");
if (fnSend == 0)
{
errorInfo.SystemError = ::GetLastError();
errorInfo.Message = L"can not find MAPISendDocuments function";
return E_FAIL;
}
UStringVector fullPaths;
int i;
for(i = 0; i < options.Commands.Size(); i++)
{
CArchivePath &ap = options.Commands[i].ArchivePath;
UString arcPath;
if(!NFile::NDirectory::MyGetFullPathName(ap.GetFinalPath(), arcPath))
{
errorInfo.SystemError = ::GetLastError();
return E_FAIL;
}
fullPaths.Add(arcPath);
}
CCurrentDirRestorer curDirRestorer;
for(i = 0; i < fullPaths.Size(); i++)
{
UString arcPath = fullPaths[i];
UString fileName = ExtractFileNameFromPath(arcPath);
AString path = GetAnsiString(arcPath);
AString name = GetAnsiString(fileName);
// Warning!!! MAPISendDocuments function changes Current directory
fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0);
}
}
#endif
return S_OK;
}

157
7zip/UI/Common/Update.h Executable file
View File

@@ -0,0 +1,157 @@
// Update.h
#ifndef __UPDATE_H
#define __UPDATE_H
#include "Common/Wildcard.h"
#include "Windows/FileFind.h"
#include "../../Archive/IArchive.h"
#include "UpdateAction.h"
#include "ArchiveOpenCallback.h"
#include "UpdateCallback.h"
struct CArchivePath
{
UString Prefix; // path(folder) prefix including slash
UString Name; // base name
UString BaseExtension; // archive type extension or "exe" extension
UString VolExtension; // archive type extension for volumes
bool Temp;
UString TempPrefix; // path(folder) for temp location
UString TempPostfix;
CArchivePath(): Temp(false) {};
void ParseFromPath(const UString &path)
{
SplitPathToParts(path, Prefix, Name);
if (Name.IsEmpty())
return;
int dotPos = Name.ReverseFind(L'.');
if (dotPos < 0)
return;
if (dotPos == Name.Length() - 1)
{
Name = Name.Left(dotPos);
BaseExtension.Empty();
return;
}
if (BaseExtension.CompareNoCase(Name.Mid(dotPos + 1)) == 0)
Name = Name.Left(dotPos);
else
BaseExtension.Empty();
}
UString GetPathWithoutExt() const
{
return Prefix + Name;
}
UString GetFinalPath() const
{
UString path = GetPathWithoutExt();
if (!BaseExtension.IsEmpty())
path += UString(L'.') + BaseExtension;
return path;
}
UString GetTempPath() const
{
UString path = TempPrefix + Name;
if (!BaseExtension.IsEmpty())
path += UString(L'.') + BaseExtension;
path += L".tmp";
path += TempPostfix;
return path;
}
};
struct CUpdateArchiveCommand
{
CArchivePath ArchivePath;
NUpdateArchive::CActionSet ActionSet;
};
struct CProperty
{
UString Name;
UString Value;
};
struct CCompressionMethodMode
{
#ifndef EXCLUDE_COM
UString FilePath;
CLSID ClassID;
#else
UString Name;
#endif
CObjectVector<CProperty> Properties;
};
struct CUpdateOptions
{
CCompressionMethodMode MethodMode;
CObjectVector<CUpdateArchiveCommand> Commands;
bool UpdateArchiveItself;
CArchivePath ArchivePath;
bool SfxMode;
UString SfxModule;
bool StdInMode;
UString StdInFileName;
bool StdOutMode;
bool EMailMode;
bool EMailRemoveAfter;
UString EMailAddress;
UString WorkingDir;
CUpdateOptions():
UpdateArchiveItself(true),
SfxMode(false),
StdInMode(false),
StdOutMode(false),
EMailMode(false),
EMailRemoveAfter(false)
{};
CRecordVector<UInt64> VolumesSizes;
};
struct CErrorInfo
{
DWORD SystemError;
UString FileName;
UString FileName2;
UString Message;
CErrorInfo(): SystemError(0) {};
};
struct CUpdateErrorInfo: public CErrorInfo
{
};
struct IUpdateCallbackUI2: public IUpdateCallbackUI
{
virtual HRESULT OpenResult(const wchar_t *name, HRESULT result) = 0;
virtual HRESULT StartScanning() = 0;
virtual HRESULT FinishScanning() = 0;
virtual HRESULT StartArchive(const wchar_t *name, bool updating) = 0;
virtual HRESULT FinishArchive() = 0;
};
HRESULT UpdateArchive(const NWildcard::CCensor &censor,
CUpdateOptions &options,
CUpdateErrorInfo &errorInfo,
IOpenCallbackUI *openCallback,
IUpdateCallbackUI2 *callback);
#endif

View File

@@ -1,7 +1,5 @@
// UpdateAction.h
#pragma once
#ifndef __UPDATE_ACTION_H
#define __UPDATE_ACTION_H
@@ -34,6 +32,17 @@ namespace NUpdateArchive {
struct CActionSet
{
NPairAction::EEnum StateActions[NPairState::kNumValues];
bool NeedScanning() const
{
int i;
for (i = 0; i < NPairState::kNumValues; i++)
if (StateActions[i] == NPairAction::kCompress)
return true;
for (i = 1; i < NPairState::kNumValues; i++)
if (StateActions[i] != NPairAction::kIgnore)
return true;
return false;
}
};
extern const CActionSet kAddActionSet;
extern const CActionSet kUpdateActionSet;

242
7zip/UI/Common/UpdateCallback.cpp Executable file
View File

@@ -0,0 +1,242 @@
// UpdateCallback.cpp
#include "StdAfx.h"
#include "UpdateCallback.h"
#include "Common/StringConvert.h"
#include "Common/IntToString.h"
#include "Common/Defs.h"
#include "Windows/PropVariant.h"
#include "../../Common/FileStreams.h"
using namespace NWindows;
CArchiveUpdateCallback::CArchiveUpdateCallback():
Callback(0),
StdInMode(false),
DirItems(0),
ArchiveItems(0),
UpdatePairs(0)
{}
STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 size)
{
return Callback->SetTotal(size);
}
STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)
{
return Callback->SetCompleted(completeValue);
}
/*
STATPROPSTG kProperties[] =
{
{ NULL, kpidPath, VT_BSTR},
{ NULL, kpidIsFolder, VT_BOOL},
{ NULL, kpidSize, VT_UI8},
{ NULL, kpidLastAccessTime, VT_FILETIME},
{ NULL, kpidCreationTime, VT_FILETIME},
{ NULL, kpidLastWriteTime, VT_FILETIME},
{ NULL, kpidAttributes, VT_UI4},
{ NULL, kpidIsAnti, VT_BOOL}
};
*/
STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **enumerator)
{
return E_NOTIMPL;
/*
return CStatPropEnumerator::CreateEnumerator(kProperties,
sizeof(kProperties) / sizeof(kProperties[0]), enumerator);
*/
}
STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index,
Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive)
{
RINOK(Callback->CheckBreak());
const CUpdatePair2 &updatePair = (*UpdatePairs)[index];
if(newData != NULL)
*newData = BoolToInt(updatePair.NewData);
if(newProperties != NULL)
*newProperties = BoolToInt(updatePair.NewProperties);
if(indexInArchive != NULL)
{
if (updatePair.ExistInArchive)
{
if (ArchiveItems == 0)
*indexInArchive = updatePair.ArchiveItemIndex;
else
*indexInArchive = (*ArchiveItems)[updatePair.ArchiveItemIndex].IndexInServer;
}
else
*indexInArchive = UInt32(-1);
}
return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
const CUpdatePair2 &updatePair = (*UpdatePairs)[index];
NWindows::NCOM::CPropVariant propVariant;
if (propID == kpidIsAnti)
{
propVariant = updatePair.IsAnti;
propVariant.Detach(value);
return S_OK;
}
if (updatePair.IsAnti)
{
switch(propID)
{
case kpidIsFolder:
case kpidPath:
break;
case kpidSize:
propVariant = (UInt64)0;
propVariant.Detach(value);
return S_OK;
default:
propVariant.Detach(value);
return S_OK;
}
}
if(updatePair.ExistOnDisk)
{
const CDirItem &dirItem = (*DirItems)[updatePair.DirItemIndex];
switch(propID)
{
case kpidPath:
propVariant = dirItem.Name;
break;
case kpidIsFolder:
propVariant = dirItem.IsDirectory();
break;
case kpidSize:
propVariant = dirItem.Size;
break;
case kpidAttributes:
propVariant = dirItem.Attributes;
break;
case kpidLastAccessTime:
propVariant = dirItem.LastAccessTime;
break;
case kpidCreationTime:
propVariant = dirItem.CreationTime;
break;
case kpidLastWriteTime:
propVariant = dirItem.LastWriteTime;
break;
}
}
else
{
if (propID == kpidPath)
{
if (updatePair.NewNameIsDefined)
{
propVariant = updatePair.NewName;
propVariant.Detach(value);
return S_OK;
}
}
if (updatePair.ExistInArchive && Archive)
{
UInt32 indexInArchive;
if (ArchiveItems == 0)
indexInArchive = updatePair.ArchiveItemIndex;
else
indexInArchive = (*ArchiveItems)[updatePair.ArchiveItemIndex].IndexInServer;
return Archive->GetProperty(indexInArchive, propID, value);
}
}
propVariant.Detach(value);
return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index,
ISequentialInStream **inStream)
{
const CUpdatePair2 &updatePair = (*UpdatePairs)[index];
if(!updatePair.NewData)
return E_FAIL;
RINOK(Callback->CheckBreak());
RINOK(Callback->Finilize());
if(updatePair.IsAnti)
{
return Callback->GetStream((*ArchiveItems)[updatePair.ArchiveItemIndex].Name, true);
}
const CDirItem &dirItem = (*DirItems)[updatePair.DirItemIndex];
RINOK(Callback->GetStream(dirItem.Name, false));
if(dirItem.IsDirectory())
return S_OK;
if (StdInMode)
{
CStdInFileStream *inStreamSpec = new CStdInFileStream;
CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
*inStream = inStreamLoc.Detach();
}
else
{
CInFileStream *inStreamSpec = new CInFileStream;
CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
UString path = DirPrefix + dirItem.FullPath;
if(!inStreamSpec->Open(path))
{
return Callback->OpenFileError(path, ::GetLastError());
}
*inStream = inStreamLoc.Detach();
}
return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 operationResult)
{
return Callback->SetOperationResult(operationResult);
}
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)
{
wchar_t temp[32];
ConvertUInt64ToString(index + 1, temp);
UString res = temp;
while (res.Length() < 2)
res = UString(L'0') + res;
UString fileName = VolName;
fileName += L'.';
fileName += res;
fileName += VolExt;
COutFileStream *streamSpec = new COutFileStream;
CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
if(!streamSpec->Create(fileName, false))
return ::GetLastError();
*volumeStream = streamLoc.Detach();
return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
{
return Callback->CryptoGetTextPassword2(passwordIsDefined, password);
}

70
7zip/UI/Common/UpdateCallback.h Executable file
View File

@@ -0,0 +1,70 @@
// UpdateCallback.h
#ifndef __UPDATECALLBACK_H
#define __UPDATECALLBACK_H
#include "Common/MyCom.h"
#include "Common/String.h"
#include "../../IPassword.h"
#include "../Common/UpdatePair.h"
#include "../Common/UpdateProduce.h"
struct IUpdateCallbackUI
{
virtual HRESULT SetTotal(UInt64 size) = 0;
virtual HRESULT SetCompleted(const UInt64 *completeValue) = 0;
virtual HRESULT CheckBreak() = 0;
virtual HRESULT Finilize() = 0;
virtual HRESULT GetStream(const wchar_t *name, bool isAnti) = 0;
virtual HRESULT OpenFileError(const wchar_t *name, DWORD systemError) = 0;
virtual HRESULT SetOperationResult(Int32 operationResult) = 0;
virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) = 0;
virtual HRESULT CloseProgress() { return S_OK; };
};
class CArchiveUpdateCallback:
public IArchiveUpdateCallback2,
public ICryptoGetTextPassword2,
public CMyUnknownImp
{
public:
MY_UNKNOWN_IMP2(IArchiveUpdateCallback2,
ICryptoGetTextPassword2)
// IProgress
STDMETHOD(SetTotal)(UInt64 size);
STDMETHOD(SetCompleted)(const UInt64 *completeValue);
// IUpdateCallback
STDMETHOD(EnumProperties)(IEnumSTATPROPSTG **enumerator);
STDMETHOD(GetUpdateItemInfo)(UInt32 index,
Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive);
STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream);
STDMETHOD(SetOperationResult)(Int32 operationResult);
STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size);
STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream);
STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password);
public:
CRecordVector<UInt64> VolumesSizes;
UString VolName;
UString VolExt;
IUpdateCallbackUI *Callback;
UString DirPrefix;
bool StdInMode;
const CObjectVector<CDirItem> *DirItems;
const CObjectVector<CArchiveItem> *ArchiveItems;
const CObjectVector<CUpdatePair2> *UpdatePairs;
CMyComPtr<IInArchive> Archive;
CArchiveUpdateCallback();
};
#endif

View File

@@ -11,7 +11,6 @@
#include "SortUtils.h"
using namespace NWindows;
// using namespace NCOM;
using namespace NTime;
static int MyCompareTime(NFileTimeType::EEnum fileTimeType,
@@ -23,7 +22,7 @@ static int MyCompareTime(NFileTimeType::EEnum fileTimeType,
return ::CompareFileTime(&time1, &time2);
case NFileTimeType::kUnix:
{
time_t unixTime1, unixTime2;
UInt32 unixTime1, unixTime2;
if (!FileTimeToUnixTime(time1, unixTime1))
throw 4191614;
if (!FileTimeToUnixTime(time2, unixTime2))
@@ -32,7 +31,7 @@ static int MyCompareTime(NFileTimeType::EEnum fileTimeType,
}
case NFileTimeType::kDOS:
{
UINT32 dosTime1, dosTime2;
UInt32 dosTime1, dosTime2;
if (!FileTimeToDosTime(time1, dosTime1))
throw 4191616;
if (!FileTimeToDosTime(time2, dosTime2))
@@ -51,23 +50,32 @@ static const char *kSameTimeChangedSizeCollisionMessaged =
"Collision between files with same date/time and different sizes:\n";
*/
static void TestDuplicateString(const UStringVector &strings,
const CIntVector &indices)
static inline int MyFileNameCompare(const UString &s1, const UString &s2)
{
return
#ifdef _WIN32
s1.CollateNoCase(s2);
#else
s1.Compare(s2);
#endif
}
static void TestDuplicateString(const UStringVector &strings, const CIntVector &indices)
{
for(int i = 0; i + 1 < indices.Size(); i++)
if (strings[indices[i]].CollateNoCase(strings[indices[i + 1]]) == 0)
if (MyFileNameCompare(strings[indices[i]], strings[indices[i + 1]]) == 0)
{
UString message = kDuplicateFileNameMessage;
message += L"\n";
message += strings[indices[i]];
message += L"\n";
message += strings[indices[i+1]];
message += strings[indices[i + 1]];
throw message;
}
}
void GetUpdatePairInfoList(
const CObjectVector<CDirItem> &dirItems,
const CObjectVector<CDirItem> &dirItems,
const CObjectVector<CArchiveItem> &archiveItems,
NFileTimeType::EEnum fileTimeType,
CObjectVector<CUpdatePair> &updatePairs)
@@ -96,7 +104,7 @@ void GetUpdatePairInfoList(
archiveItemIndex2 = archiveIndices[archiveItemIndex];
const CDirItem &dirItem = dirItems[dirItemIndex2];
const CArchiveItem &archiveItem = archiveItems[archiveItemIndex2];
int compareResult = dirItem.Name.CollateNoCase(archiveItem.Name);
int compareResult = MyFileNameCompare(dirItem.Name, archiveItem.Name);
if (compareResult < 0)
{
pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;

View File

@@ -1,9 +1,7 @@
// UpdatePair.h
#pragma once
#ifndef __UPDATEPAIR_H
#define __UPDATEPAIR_H
#ifndef __UPDATE_PAIR_H
#define __UPDATE_PAIR_H
#include "DirItem.h"
#include "UpdateAction.h"

View File

@@ -1,9 +1,7 @@
// UpdateProduce.h
#pragma once
#ifndef __UPDATEPRODUCE_H
#define __UPDATEPRODUCE_H
#ifndef __UPDATE_PRODUCE_H
#define __UPDATE_PRODUCE_H
#include "UpdatePair.h"

View File

@@ -5,6 +5,7 @@
#include "WorkDir.h"
#include "Common/StringConvert.h"
#include "Common/Wildcard.h"
#include "Windows/FileName.h"
#include "Windows/FileDir.h"
@@ -16,23 +17,13 @@ using namespace NWindows;
using namespace NFile;
using namespace NName;
static UString GetContainingDir(const UString &path)
{
UString resultPath;
int pos;
if(!NFile::NDirectory::MyGetFullPathName(path, resultPath, pos))
throw 141716;
return resultPath.Left(pos);
}
UString GetWorkDir(const NWorkDir::CInfo &workDirInfo,
const UString &archiveName)
UString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const UString &path)
{
NWorkDir::NMode::EEnum mode = workDirInfo.Mode;
if (workDirInfo.ForRemovableOnly)
{
mode = NWorkDir::NMode::kCurrent;
UString prefix = archiveName.Left(3);
UString prefix = path.Left(3);
if (prefix[1] == L':' && prefix[2] == L'\\')
{
UINT driveType = GetDriveType(GetSystemString(prefix, GetCurrentCodePage()));
@@ -51,7 +42,7 @@ UString GetWorkDir(const NWorkDir::CInfo &workDirInfo,
{
case NWorkDir::NMode::kCurrent:
{
return GetContainingDir(archiveName);
return ExtractDirPrefixFromPath(path);
}
case NWorkDir::NMode::kSpecified:
{
@@ -59,7 +50,7 @@ UString GetWorkDir(const NWorkDir::CInfo &workDirInfo,
NormalizeDirPathPrefix(tempDir);
return tempDir;
}
default: // NZipSettings::NWorkDir::NMode::kSystem:
default:
{
UString tempDir;
if(!NFile::NDirectory::MyGetTempPath(tempDir))

View File

@@ -1,14 +1,10 @@
// WorkDir.h
#pragma once
#ifndef __WORKDIR_H
#define __WORKDIR_H
#include "../Common/ZipRegistry.h"
#include "ZipRegistry.h"
UString GetWorkDir(const NWorkDir::CInfo &workDirInfo,
const UString &archiveName);
UString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const UString &path);
#endif

View File

@@ -36,7 +36,7 @@ static CSysString GetKeyPath(const CSysString &path)
return CSysString(kCUBasePath) + CSysString('\\') + CSysString(path);
}
void SaveExtractionInfo(const NExtraction::CInfo &info)
void SaveExtractionInfo(const NExtract::CInfo &info)
{
NSynchronization::CCriticalSectionLock lock(g_RegistryOperationsCriticalSection);
CKey extractionKey;
@@ -48,20 +48,20 @@ void SaveExtractionInfo(const NExtraction::CInfo &info)
for(int i = 0; i < info.Paths.Size(); i++)
{
TCHAR numberString[16];
ConvertUINT64ToString(i, numberString);
ConvertUInt64ToString(i, numberString);
pathHistoryKey.SetValue(numberString, info.Paths[i]);
}
}
extractionKey.SetValue(kExtractionExtractModeValueName, UINT32(info.PathMode));
extractionKey.SetValue(kExtractionOverwriteModeValueName, UINT32(info.OverwriteMode));
extractionKey.SetValue(kExtractionExtractModeValueName, UInt32(info.PathMode));
extractionKey.SetValue(kExtractionOverwriteModeValueName, UInt32(info.OverwriteMode));
extractionKey.SetValue(kExtractionShowPasswordValueName, info.ShowPassword);
}
void ReadExtractionInfo(NExtraction::CInfo &info)
void ReadExtractionInfo(NExtract::CInfo &info)
{
info.Paths.Clear();
info.PathMode = NExtraction::NPathMode::kFullPathnames;
info.OverwriteMode = NExtraction::NOverwriteMode::kAskBefore;
info.PathMode = NExtract::NPathMode::kCurrentPathnames;
info.OverwriteMode = NExtract::NOverwriteMode::kAskBefore;
info.ShowPassword = false;
NSynchronization::CCriticalSectionLock lock(g_RegistryOperationsCriticalSection);
@@ -77,7 +77,7 @@ void ReadExtractionInfo(NExtraction::CInfo &info)
while(true)
{
TCHAR numberString[16];
ConvertUINT64ToString(info.Paths.Size(), numberString);
ConvertUInt64ToString(info.Paths.Size(), numberString);
CSysString path;
if (pathHistoryKey.QueryValue(numberString, path) != ERROR_SUCCESS)
break;
@@ -85,29 +85,29 @@ void ReadExtractionInfo(NExtraction::CInfo &info)
}
}
}
UINT32 extractModeIndex;
UInt32 extractModeIndex;
if (extractionKey.QueryValue(kExtractionExtractModeValueName, extractModeIndex) == ERROR_SUCCESS)
{
switch (extractModeIndex)
{
case NExtraction::NPathMode::kFullPathnames:
case NExtraction::NPathMode::kCurrentPathnames:
case NExtraction::NPathMode::kNoPathnames:
info.PathMode = NExtraction::NPathMode::EEnum(extractModeIndex);
case NExtract::NPathMode::kFullPathnames:
case NExtract::NPathMode::kCurrentPathnames:
case NExtract::NPathMode::kNoPathnames:
info.PathMode = NExtract::NPathMode::EEnum(extractModeIndex);
break;
}
}
UINT32 overwriteModeIndex;
UInt32 overwriteModeIndex;
if (extractionKey.QueryValue(kExtractionOverwriteModeValueName, overwriteModeIndex) == ERROR_SUCCESS)
{
switch (overwriteModeIndex)
{
case NExtraction::NOverwriteMode::kAskBefore:
case NExtraction::NOverwriteMode::kWithoutPrompt:
case NExtraction::NOverwriteMode::kSkipExisting:
case NExtraction::NOverwriteMode::kAutoRename:
case NExtraction::NOverwriteMode::kAutoRenameExisting:
info.OverwriteMode = NExtraction::NOverwriteMode::EEnum(overwriteModeIndex);
case NExtract::NOverwriteMode::kAskBefore:
case NExtract::NOverwriteMode::kWithoutPrompt:
case NExtract::NOverwriteMode::kSkipExisting:
case NExtract::NOverwriteMode::kAutoRename:
case NExtract::NOverwriteMode::kAutoRenameExisting:
info.OverwriteMode = NExtract::NOverwriteMode::EEnum(overwriteModeIndex);
break;
}
}
@@ -151,7 +151,7 @@ void SaveCompressionInfo(const NCompression::CInfo &info)
for(int i = 0; i < info.HistoryArchives.Size(); i++)
{
TCHAR numberString[16];
ConvertUINT64ToString(i, numberString);
ConvertUInt64ToString(i, numberString);
historyArchivesKey.SetValue(numberString, info.HistoryArchives[i]);
}
}
@@ -171,7 +171,7 @@ void SaveCompressionInfo(const NCompression::CInfo &info)
formatKey.DeleteValue(kCompressionOptions);
else
formatKey.SetValue(kCompressionOptions, fo.Options);
if (fo.Level == UINT32(-1))
if (fo.Level == UInt32(-1))
formatKey.DeleteValue(kCompressionLevel);
else
formatKey.SetValue(kCompressionLevel, fo.Level);
@@ -179,18 +179,18 @@ void SaveCompressionInfo(const NCompression::CInfo &info)
formatKey.DeleteValue(kCompressionMethod);
else
formatKey.SetValue(kCompressionMethod, fo.Method);
if (fo.Dictionary == UINT32(-1))
if (fo.Dictionary == UInt32(-1))
formatKey.DeleteValue(kCompressionDictionary);
else
formatKey.SetValue(kCompressionDictionary, fo.Dictionary);
if (fo.Order == UINT32(-1))
if (fo.Order == UInt32(-1))
formatKey.DeleteValue(kCompressionOrder);
else
formatKey.SetValue(kCompressionOrder, fo.Order);
}
}
compressionKey.SetValue(kCompressionLevelValueName, UINT32(info.Level));
compressionKey.SetValue(kCompressionLevelValueName, UInt32(info.Level));
compressionKey.SetValue(kCompressionLastFormatValueName,
GetSystemString(info.ArchiveType));
@@ -235,7 +235,7 @@ void ReadCompressionInfo(NCompression::CInfo &info)
while(true)
{
TCHAR numberString[16];
ConvertUINT64ToString(info.HistoryArchives.Size(), numberString);
ConvertUInt64ToString(info.HistoryArchives.Size(), numberString);
CSysString path;
if (historyArchivesKey.QueryValue(numberString, path) != ERROR_SUCCESS)
break;
@@ -269,13 +269,13 @@ void ReadCompressionInfo(NCompression::CInfo &info)
if (formatKey.QueryValue(kCompressionOptions, fo.Options) != ERROR_SUCCESS)
fo.Options.Empty();
if (formatKey.QueryValue(kCompressionLevel, fo.Level) != ERROR_SUCCESS)
fo.Level = UINT32(-1);
fo.Level = UInt32(-1);
if (formatKey.QueryValue(kCompressionMethod, fo.Method) != ERROR_SUCCESS)
fo.Method.Empty();;
if (formatKey.QueryValue(kCompressionDictionary, fo.Dictionary) != ERROR_SUCCESS)
fo.Dictionary = UINT32(-1);
fo.Dictionary = UInt32(-1);
if (formatKey.QueryValue(kCompressionOrder, fo.Order) != ERROR_SUCCESS)
fo.Order = UINT32(-1);
fo.Order = UInt32(-1);
info.FormatOptionsVector.Add(fo);
}
@@ -283,7 +283,7 @@ void ReadCompressionInfo(NCompression::CInfo &info)
}
}
UINT32 level;
UInt32 level;
if (compressionKey.QueryValue(kCompressionLevelValueName, level) == ERROR_SUCCESS)
info.Level = level;
CSysString archiveType;
@@ -318,7 +318,7 @@ void SaveWorkDirInfo(const NWorkDir::CInfo &info)
NSynchronization::CCriticalSectionLock lock(g_RegistryOperationsCriticalSection);
CKey optionsKey;
optionsKey.Create(HKEY_CURRENT_USER, GetKeyPath(kOptionsInfoKeyName));
optionsKey.SetValue(kWorkDirTypeValueName, UINT32(info.Mode));
optionsKey.SetValue(kWorkDirTypeValueName, UInt32(info.Mode));
optionsKey.SetValue(kWorkDirPathValueName, GetSystemString(info.Path));
optionsKey.SetValue(kTempRemovableOnlyValueName, info.ForRemovableOnly);
}
@@ -332,7 +332,7 @@ void ReadWorkDirInfo(NWorkDir::CInfo &info)
if(optionsKey.Open(HKEY_CURRENT_USER, GetKeyPath(kOptionsInfoKeyName), KEY_READ) != ERROR_SUCCESS)
return;
UINT32 dirType;
UInt32 dirType;
if (optionsKey.QueryValue(kWorkDirTypeValueName, dirType) != ERROR_SUCCESS)
return;
switch (dirType)
@@ -380,7 +380,7 @@ bool ReadCascadedMenu()
{ return ReadOption(kCascadedMenuValueName, false); }
static void SaveValue(const TCHAR *value, UINT32 valueToWrite)
static void SaveValue(const TCHAR *value, UInt32 valueToWrite)
{
NSynchronization::CCriticalSectionLock lock(g_RegistryOperationsCriticalSection);
CKey optionsKey;
@@ -388,7 +388,7 @@ static void SaveValue(const TCHAR *value, UINT32 valueToWrite)
optionsKey.SetValue(value, valueToWrite);
}
static bool ReadValue(const TCHAR *value, UINT32 &result)
static bool ReadValue(const TCHAR *value, UInt32 &result)
{
NSynchronization::CCriticalSectionLock lock(g_RegistryOperationsCriticalSection);
CKey optionsKey;
@@ -397,8 +397,8 @@ static bool ReadValue(const TCHAR *value, UINT32 &result)
return (optionsKey.QueryValue(value, result) == ERROR_SUCCESS);
}
void SaveContextMenuStatus(UINT32 value)
void SaveContextMenuStatus(UInt32 value)
{ SaveValue(kContextMenuValueName, value); }
bool ReadContextMenuStatus(UINT32 &value)
bool ReadContextMenuStatus(UInt32 &value)
{ return ReadValue(kContextMenuValueName, value); }

View File

@@ -1,36 +1,14 @@
// ZipRegistry.h
#pragma once
#ifndef __ZIPREGISTRY_H
#define __ZIPREGISTRY_H
#include "Common/String.h"
#include "Common/Types.h"
#include "ExtractMode.h"
namespace NExtraction {
namespace NPathMode
{
enum EEnum
{
kFullPathnames,
kCurrentPathnames,
kNoPathnames
};
}
namespace NOverwriteMode
{
enum EEnum
{
kAskBefore,
kWithoutPrompt,
kSkipExisting,
kAutoRename,
kAutoRenameExisting
};
}
namespace NExtract
{
struct CInfo
{
NPathMode::EEnum PathMode;
@@ -46,13 +24,13 @@ namespace NCompression {
{
CSysString FormatID;
CSysString Options;
UINT32 Level;
UInt32 Level;
CSysString Method;
UINT32 Dictionary;
UINT32 Order;
UInt32 Dictionary;
UInt32 Order;
void Init()
{
Level = Dictionary = Order = UINT32(-1);
Level = Dictionary = Order = UInt32(-1);
Method.Empty();
// Options.Empty();
}
@@ -63,7 +41,7 @@ namespace NCompression {
{
CSysStringVector HistoryArchives;
// bool LevelIsDefined;
UINT32 Level;
UInt32 Level;
UString ArchiveType;
bool Solid;
@@ -101,8 +79,8 @@ namespace NWorkDir{
};
}
void SaveExtractionInfo(const NExtraction::CInfo &info);
void ReadExtractionInfo(NExtraction::CInfo &info);
void SaveExtractionInfo(const NExtract::CInfo &info);
void ReadExtractionInfo(NExtract::CInfo &info);
void SaveCompressionInfo(const NCompression::CInfo &info);
void ReadCompressionInfo(NCompression::CInfo &info);
@@ -113,7 +91,7 @@ void ReadWorkDirInfo(NWorkDir::CInfo &info);
void SaveCascadedMenu(bool enabled);
bool ReadCascadedMenu();
void SaveContextMenuStatus(UINT32 value);
bool ReadContextMenuStatus(UINT32 &value);
void SaveContextMenuStatus(UInt32 value);
bool ReadContextMenuStatus(UInt32 &value);
#endif