X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=lzma%2FCPP%2F7zip%2FUI%2FCommon%2FArchiveCommandLine.cpp;fp=lzma%2FCPP%2F7zip%2FUI%2FCommon%2FArchiveCommandLine.cpp;h=6cf95f2740624308c7e2cbc45b5f972c9d079cde;hb=1a2e54b98aaab3669eebd38facb83687c4ac7baf;hp=0000000000000000000000000000000000000000;hpb=0b9bdac28929054558b5d7f315403fe3399a1413;p=physicsfs diff --git a/lzma/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/lzma/CPP/7zip/UI/Common/ArchiveCommandLine.cpp new file mode 100644 index 0000000..6cf95f2 --- /dev/null +++ b/lzma/CPP/7zip/UI/Common/ArchiveCommandLine.cpp @@ -0,0 +1,1003 @@ +// ArchiveCommandLine.cpp + +#include "StdAfx.h" + +#ifdef _WIN32 +#include +#endif +#include + +#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 "SortUtils.h" +#include "EnumDirItems.h" + +extern bool g_CaseSensitive; + +#if _MSC_VER >= 1400 +#define MY_isatty_fileno(x) _isatty(_fileno(x)) +#else +#define MY_isatty_fileno(x) isatty(fileno(x)) +#endif + +#define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0); + +using namespace NCommandLineParser; +using namespace NWindows; +using namespace NFile; + +namespace NKey { +enum Enum +{ + kHelp1 = 0, + kHelp2, + kHelp3, + kDisableHeaders, + kDisablePercents, + kArchiveType, + kYes, + kPassword, + kProperty, + kOutputDir, + kWorkingDir, + kInclude, + kExclude, + kArInclude, + kArExclude, + kNoArName, + kUpdate, + kVolume, + kRecursed, + kSfx, + kStdIn, + kStdOut, + kOverwrite, + kEmail, + kShowDialog, + kLargePages, + kCharSet, + kTechMode, + kShareForWrite, + kCaseSensitive +}; + +} + + +static const wchar_t kRecursedIDChar = 'R'; +static const wchar_t *kRecursedPostCharSet = L"0-"; + +namespace NRecursedPostCharIndex { + enum EEnum + { + kWildCardRecursionOnly = 0, + kNoRecursion = 1 + }; +} + +static const char kImmediateNameID = '!'; +static const char kMapNameID = '#'; +static const char kFileListID = '@'; + +static const char kSomeCludePostStringMinSize = 2; // at least <@|!>ame must be +static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!>ame must be + +static const wchar_t *kOverwritePostCharSet = L"asut"; + +NExtract::NOverwriteMode::EEnum k_OverwriteModes[] = +{ + NExtract::NOverwriteMode::kWithoutPrompt, + NExtract::NOverwriteMode::kSkipExisting, + NExtract::NOverwriteMode::kAutoRename, + NExtract::NOverwriteMode::kAutoRenameExisting +}; + +static const CSwitchForm kSwitchForms[] = + { + { L"?", NSwitchType::kSimple, false }, + { L"H", NSwitchType::kSimple, false }, + { L"-HELP", NSwitchType::kSimple, false }, + { L"BA", NSwitchType::kSimple, false }, + { L"BD", NSwitchType::kSimple, false }, + { L"T", NSwitchType::kUnLimitedPostString, false, 1 }, + { L"Y", NSwitchType::kSimple, false }, + { L"P", NSwitchType::kUnLimitedPostString, false, 0 }, + { L"M", NSwitchType::kUnLimitedPostString, true, 1 }, + { L"O", NSwitchType::kUnLimitedPostString, false, 1 }, + { L"W", NSwitchType::kUnLimitedPostString, false, 0 }, + { L"I", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize}, + { L"X", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize}, + { L"AI", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize}, + { L"AX", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize}, + { L"AN", NSwitchType::kSimple, false }, + { L"U", NSwitchType::kUnLimitedPostString, true, 1}, + { L"V", NSwitchType::kUnLimitedPostString, true, 1}, + { L"R", NSwitchType::kPostChar, false, 0, 0, kRecursedPostCharSet }, + { L"SFX", NSwitchType::kUnLimitedPostString, false, 0 }, + { L"SI", NSwitchType::kUnLimitedPostString, false, 0 }, + { L"SO", NSwitchType::kSimple, false, 0 }, + { L"AO", NSwitchType::kPostChar, false, 1, 1, kOverwritePostCharSet}, + { L"SEML", NSwitchType::kUnLimitedPostString, false, 0}, + { L"AD", NSwitchType::kSimple, false }, + { L"SLP", NSwitchType::kUnLimitedPostString, false, 0}, + { L"SCS", NSwitchType::kUnLimitedPostString, false, 0}, + { L"SLT", NSwitchType::kSimple, false }, + { L"SSW", NSwitchType::kSimple, false }, + { L"SSC", NSwitchType::kPostChar, false, 0, 0, L"-" } + }; + +static const CCommandForm g_CommandForms[] = +{ + { L"A", false }, + { L"U", false }, + { L"D", false }, + { L"T", false }, + { L"E", false }, + { L"X", false }, + { L"L", false }, + { L"B", false }, + { L"I", false } +}; + +static const int kNumCommandForms = sizeof(g_CommandForms) / sizeof(g_CommandForms[0]); + +static const wchar_t *kUniversalWildcard = L"*"; +static const int kMinNonSwitchWords = 1; +static const int kCommandIndex = 0; + +// --------------------------- +// exception messages + +static const char *kUserErrorMessage = "Incorrect command line"; +static const char *kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch."; +static const char *kIncorrectWildCardInListFile = "Incorrect wildcard in listfile"; +static const char *kIncorrectWildCardInCommandLine = "Incorrect wildcard in command line"; +static const char *kTerminalOutError = "I won't write compressed data to a terminal"; +static const char *kSameTerminalError = "I won't write data and program's messages to same terminal"; + +static void ThrowException(const char *errorMessage) +{ + throw CArchiveCommandLineException(errorMessage); +}; + +static void ThrowUserErrorException() +{ + ThrowException(kUserErrorMessage); +}; + +// --------------------------- + +bool CArchiveCommand::IsFromExtractGroup() const +{ + switch(CommandType) + { + case NCommandType::kTest: + case NCommandType::kExtract: + case NCommandType::kFullExtract: + return true; + default: + return false; + } +} + +NExtract::NPathMode::EEnum CArchiveCommand::GetPathMode() const +{ + switch(CommandType) + { + case NCommandType::kTest: + case NCommandType::kFullExtract: + return NExtract::NPathMode::kFullPathnames; + default: + return NExtract::NPathMode::kNoPathnames; + } +} + +bool CArchiveCommand::IsFromUpdateGroup() const +{ + return (CommandType == NCommandType::kAdd || + CommandType == NCommandType::kUpdate || + CommandType == NCommandType::kDelete); +} + +static NRecursedType::EEnum GetRecursedTypeFromIndex(int index) +{ + switch (index) + { + case NRecursedPostCharIndex::kWildCardRecursionOnly: + return NRecursedType::kWildCardOnlyRecursed; + case NRecursedPostCharIndex::kNoRecursion: + return NRecursedType::kNonRecursed; + default: + return NRecursedType::kRecursed; + } +} + +static bool ParseArchiveCommand(const UString &commandString, CArchiveCommand &command) +{ + UString commandStringUpper = commandString; + commandStringUpper.MakeUpper(); + UString postString; + int commandIndex = ParseCommand(kNumCommandForms, g_CommandForms, commandStringUpper, + postString) ; + if (commandIndex < 0) + return false; + command.CommandType = (NCommandType::EEnum)commandIndex; + return true; +} + +// ------------------------------------------------------------------ +// filenames functions + +static bool AddNameToCensor(NWildcard::CCensor &wildcardCensor, + const UString &name, bool include, NRecursedType::EEnum type) +{ + bool isWildCard = DoesNameContainWildCard(name); + bool recursed = false; + + switch (type) + { + case NRecursedType::kWildCardOnlyRecursed: + recursed = isWildCard; + break; + case NRecursedType::kRecursed: + recursed = true; + break; + case NRecursedType::kNonRecursed: + recursed = false; + break; + } + wildcardCensor.AddItem(include, name, recursed); + return true; +} + +static void AddToCensorFromListFile(NWildcard::CCensor &wildcardCensor, + LPCWSTR fileName, bool include, NRecursedType::EEnum type, UINT codePage) +{ + UStringVector names; + if (!ReadNamesFromListFile(fileName, names, codePage)) + throw kIncorrectListFile; + for (int i = 0; i < names.Size(); i++) + if (!AddNameToCensor(wildcardCensor, names[i], include, type)) + throw kIncorrectWildCardInListFile; +} + +static void AddCommandLineWildCardToCensr(NWildcard::CCensor &wildcardCensor, + const UString &name, bool include, NRecursedType::EEnum recursedType) +{ + if (!AddNameToCensor(wildcardCensor, name, include, recursedType)) + throw kIncorrectWildCardInCommandLine; +} + +static void AddToCensorFromNonSwitchesStrings( + int startIndex, + NWildcard::CCensor &wildcardCensor, + const UStringVector &nonSwitchStrings, NRecursedType::EEnum type, + bool thereAreSwitchIncludes, UINT codePage) +{ + if(nonSwitchStrings.Size() == startIndex && (!thereAreSwitchIncludes)) + AddCommandLineWildCardToCensr(wildcardCensor, kUniversalWildcard, true, type); + for(int i = startIndex; i < nonSwitchStrings.Size(); i++) + { + const UString &s = nonSwitchStrings[i]; + if (s[0] == kFileListID) + AddToCensorFromListFile(wildcardCensor, s.Mid(1), true, type, codePage); + else + AddCommandLineWildCardToCensr(wildcardCensor, s, true, type); + } +} + +#ifdef _WIN32 +static void ParseMapWithPaths(NWildcard::CCensor &wildcardCensor, + const UString &switchParam, bool include, + NRecursedType::EEnum commonRecursedType) +{ + int splitPos = switchParam.Find(L':'); + if (splitPos < 0) + ThrowUserErrorException(); + UString mappingName = switchParam.Left(splitPos); + + UString switchParam2 = switchParam.Mid(splitPos + 1); + splitPos = switchParam2.Find(L':'); + if (splitPos < 0) + ThrowUserErrorException(); + + UString mappingSize = switchParam2.Left(splitPos); + UString eventName = switchParam2.Mid(splitPos + 1); + + UInt64 dataSize64 = ConvertStringToUInt64(mappingSize, NULL); + UInt32 dataSize = (UInt32)dataSize64; + { + CFileMapping fileMapping; + if (!fileMapping.Open(FILE_MAP_READ, false, GetSystemString(mappingName))) + ThrowException("Can not open mapping"); + LPVOID data = fileMapping.MapViewOfFile(FILE_MAP_READ, 0, dataSize); + if (data == NULL) + ThrowException("MapViewOfFile error"); + try + { + const wchar_t *curData = (const wchar_t *)data; + if (*curData != 0) + ThrowException("Incorrect mapping data"); + UInt32 numChars = dataSize / sizeof(wchar_t); + UString name; + for (UInt32 i = 1; i < numChars; i++) + { + wchar_t c = curData[i]; + if (c == L'\0') + { + AddCommandLineWildCardToCensr(wildcardCensor, + name, include, commonRecursedType); + name.Empty(); + } + else + name += c; + } + if (!name.IsEmpty()) + ThrowException("data error"); + } + catch(...) + { + UnmapViewOfFile(data); + throw; + } + UnmapViewOfFile(data); + } + + { + NSynchronization::CManualResetEvent event; + if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(eventName)) == S_OK) + event.Set(); + } +} +#endif + +static void AddSwitchWildCardsToCensor(NWildcard::CCensor &wildcardCensor, + const UStringVector &strings, bool include, + NRecursedType::EEnum commonRecursedType, UINT codePage) +{ + for(int i = 0; i < strings.Size(); i++) + { + const UString &name = strings[i]; + NRecursedType::EEnum recursedType; + int pos = 0; + if (name.Length() < kSomeCludePostStringMinSize) + ThrowUserErrorException(); + if (::MyCharUpper(name[pos]) == kRecursedIDChar) + { + pos++; + int index = UString(kRecursedPostCharSet).Find(name[pos]); + recursedType = GetRecursedTypeFromIndex(index); + if (index >= 0) + pos++; + } + else + recursedType = commonRecursedType; + if (name.Length() < pos + kSomeCludeAfterRecursedPostStringMinSize) + ThrowUserErrorException(); + UString tail = name.Mid(pos + 1); + if (name[pos] == kImmediateNameID) + AddCommandLineWildCardToCensr(wildcardCensor, tail, include, recursedType); + else if (name[pos] == kFileListID) + AddToCensorFromListFile(wildcardCensor, tail, include, recursedType, codePage); + #ifdef _WIN32 + else if (name[pos] == kMapNameID) + ParseMapWithPaths(wildcardCensor, tail, include, recursedType); + #endif + else + ThrowUserErrorException(); + } +} + +#ifdef _WIN32 + +// This code converts all short file names to long file names. + +static void ConvertToLongName(const UString &prefix, UString &name) +{ + if (name.IsEmpty() || DoesNameContainWildCard(name)) + return; + NFind::CFileInfoW fileInfo; + if (NFind::FindFile(prefix + name, fileInfo)) + name = fileInfo.Name; +} + +static void ConvertToLongNames(const UString &prefix, CObjectVector &items) +{ + for (int i = 0; i < items.Size(); i++) + { + NWildcard::CItem &item = items[i]; + if (item.Recursive || item.PathParts.Size() != 1) + continue; + ConvertToLongName(prefix, item.PathParts.Front()); + } +} + +static void ConvertToLongNames(const UString &prefix, NWildcard::CCensorNode &node) +{ + ConvertToLongNames(prefix, node.IncludeItems); + ConvertToLongNames(prefix, node.ExcludeItems); + int i; + for (i = 0; i < node.SubNodes.Size(); i++) + ConvertToLongName(prefix, node.SubNodes[i].Name); + // mix folders with same name + for (i = 0; i < node.SubNodes.Size(); i++) + { + NWildcard::CCensorNode &nextNode1 = node.SubNodes[i]; + for (int j = i + 1; j < node.SubNodes.Size();) + { + const NWildcard::CCensorNode &nextNode2 = node.SubNodes[j]; + if (nextNode1.Name.CompareNoCase(nextNode2.Name) == 0) + { + nextNode1.IncludeItems += nextNode2.IncludeItems; + nextNode1.ExcludeItems += nextNode2.ExcludeItems; + node.SubNodes.Delete(j); + } + else + j++; + } + } + for (i = 0; i < node.SubNodes.Size(); i++) + { + NWildcard::CCensorNode &nextNode = node.SubNodes[i]; + ConvertToLongNames(prefix + nextNode.Name + wchar_t(NFile::NName::kDirDelimiter), nextNode); + } +} + +static void ConvertToLongNames(NWildcard::CCensor &censor) +{ + for (int i = 0; i < censor.Pairs.Size(); i++) + { + NWildcard::CPair &pair = censor.Pairs[i]; + ConvertToLongNames(pair.Prefix, pair.Head); + } +} + +#endif + +static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i) +{ + switch(i) + { + case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore; + case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy; + case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress; + case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti; + } + throw 98111603; +} + +const UString kUpdatePairStateIDSet = L"PQRXYZW"; +const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1}; + +const UString kUpdatePairActionIDSet = L"0123"; //Ignore, Copy, Compress, Create Anti + +const wchar_t *kUpdateIgnoreItselfPostStringID = L"-"; +const wchar_t kUpdateNewArchivePostCharID = '!'; + + +static bool ParseUpdateCommandString2(const UString &command, + NUpdateArchive::CActionSet &actionSet, UString &postString) +{ + for(int i = 0; i < command.Length();) + { + wchar_t c = MyCharUpper(command[i]); + int statePos = kUpdatePairStateIDSet.Find(c); + if (statePos < 0) + { + postString = command.Mid(i); + return true; + } + i++; + if (i >= command.Length()) + return false; + int actionPos = kUpdatePairActionIDSet.Find(::MyCharUpper(command[i])); + if (actionPos < 0) + return false; + actionSet.StateActions[statePos] = GetUpdatePairActionType(actionPos); + if (kUpdatePairStateNotSupportedActions[statePos] == actionPos) + return false; + i++; + } + postString.Empty(); + return true; +} + +static void ParseUpdateCommandString(CUpdateOptions &options, + const UStringVector &updatePostStrings, + const NUpdateArchive::CActionSet &defaultActionSet) +{ + for(int i = 0; i < updatePostStrings.Size(); i++) + { + const UString &updateString = updatePostStrings[i]; + if(updateString.CompareNoCase(kUpdateIgnoreItselfPostStringID) == 0) + { + if(options.UpdateArchiveItself) + { + options.UpdateArchiveItself = false; + options.Commands.Delete(0); + } + } + else + { + NUpdateArchive::CActionSet actionSet = defaultActionSet; + + UString postString; + if (!ParseUpdateCommandString2(updateString, actionSet, postString)) + ThrowUserErrorException(); + if(postString.IsEmpty()) + { + if(options.UpdateArchiveItself) + options.Commands[0].ActionSet = actionSet; + } + else + { + if(MyCharUpper(postString[0]) != kUpdateNewArchivePostCharID) + ThrowUserErrorException(); + CUpdateArchiveCommand uc; + UString archivePath = postString.Mid(1); + if (archivePath.IsEmpty()) + ThrowUserErrorException(); + uc.UserArchivePath = archivePath; + uc.ActionSet = actionSet; + options.Commands.Add(uc); + } + } + } +} + +static const char kByteSymbol = 'B'; +static const char kKiloSymbol = 'K'; +static const char kMegaSymbol = 'M'; +static const char kGigaSymbol = 'G'; + +static bool ParseComplexSize(const UString &src, UInt64 &result) +{ + UString s = src; + s.MakeUpper(); + + const wchar_t *start = s; + const wchar_t *end; + UInt64 number = ConvertStringToUInt64(start, &end); + int numDigits = (int)(end - start); + if (numDigits == 0 || s.Length() > numDigits + 1) + return false; + if (s.Length() == numDigits) + { + result = number; + return true; + } + int numBits; + switch (s[numDigits]) + { + case kByteSymbol: + result = number; + return true; + case kKiloSymbol: + numBits = 10; + break; + case kMegaSymbol: + numBits = 20; + break; + case kGigaSymbol: + numBits = 30; + break; + default: + return false; + } + if (number >= ((UInt64)1 << (64 - numBits))) + return false; + result = number << numBits; + return true; +} + +static void SetAddCommandOptions( + NCommandType::EEnum commandType, + const CParser &parser, + CUpdateOptions &options) +{ + NUpdateArchive::CActionSet defaultActionSet; + switch(commandType) + { + case NCommandType::kAdd: + defaultActionSet = NUpdateArchive::kAddActionSet; + break; + case NCommandType::kDelete: + defaultActionSet = NUpdateArchive::kDeleteActionSet; + break; + default: + defaultActionSet = NUpdateArchive::kUpdateActionSet; + } + + options.UpdateArchiveItself = true; + + options.Commands.Clear(); + CUpdateArchiveCommand updateMainCommand; + updateMainCommand.ActionSet = defaultActionSet; + options.Commands.Add(updateMainCommand); + if(parser[NKey::kUpdate].ThereIs) + ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings, + defaultActionSet); + if(parser[NKey::kWorkingDir].ThereIs) + { + const UString &postString = parser[NKey::kWorkingDir].PostStrings[0]; + if (postString.IsEmpty()) + NDirectory::MyGetTempPath(options.WorkingDir); + else + options.WorkingDir = postString; + } + options.SfxMode = parser[NKey::kSfx].ThereIs; + if (options.SfxMode) + options.SfxModule = parser[NKey::kSfx].PostStrings[0]; + + if (parser[NKey::kVolume].ThereIs) + { + const UStringVector &sv = parser[NKey::kVolume].PostStrings; + for (int i = 0; i < sv.Size(); i++) + { + UInt64 size; + if (!ParseComplexSize(sv[i], size)) + ThrowException("Incorrect volume size"); + options.VolumesSizes.Add(size); + } + } +} + +static void SetMethodOptions(const CParser &parser, CObjectVector &properties) +{ + if (parser[NKey::kProperty].ThereIs) + { + // options.MethodMode.Properties.Clear(); + for(int i = 0; i < parser[NKey::kProperty].PostStrings.Size(); i++) + { + CProperty property; + const UString &postString = parser[NKey::kProperty].PostStrings[i]; + int index = postString.Find(L'='); + if (index < 0) + property.Name = postString; + else + { + property.Name = postString.Left(index); + property.Value = postString.Mid(index + 1); + } + properties.Add(property); + } + } +} + +CArchiveCommandLineParser::CArchiveCommandLineParser(): + parser(sizeof(kSwitchForms) / sizeof(kSwitchForms[0])) {} + +void CArchiveCommandLineParser::Parse1(const UStringVector &commandStrings, + CArchiveCommandLineOptions &options) +{ + try + { + parser.ParseStrings(kSwitchForms, commandStrings); + } + catch(...) + { + ThrowUserErrorException(); + } + + options.IsInTerminal = MY_IS_TERMINAL(stdin); + options.IsStdOutTerminal = MY_IS_TERMINAL(stdout); + options.IsStdErrTerminal = MY_IS_TERMINAL(stderr); + options.StdOutMode = parser[NKey::kStdOut].ThereIs; + options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs; + options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs || parser[NKey::kHelp3].ThereIs; + + #ifdef _WIN32 + options.LargePages = false; + if (parser[NKey::kLargePages].ThereIs) + { + const UString &postString = parser[NKey::kLargePages].PostStrings.Front(); + if (postString.IsEmpty()) + options.LargePages = true; + } + #endif +} + +struct CCodePagePair +{ + const wchar_t *Name; + UINT CodePage; +}; + +static CCodePagePair g_CodePagePairs[] = +{ + { L"UTF-8", CP_UTF8 }, + { L"WIN", CP_ACP }, + { L"DOS", CP_OEMCP } +}; + +static const int kNumCodePages = sizeof(g_CodePagePairs) / sizeof(g_CodePagePairs[0]); + +static bool ConvertStringToUInt32(const wchar_t *s, UInt32 &v) +{ + const wchar_t *end; + UInt64 number = ConvertStringToUInt64(s, &end); + if (*end != 0) + return false; + if (number > (UInt32)0xFFFFFFFF) + return false; + v = (UInt32)number; + return true; +} + +void CArchiveCommandLineParser::Parse2(CArchiveCommandLineOptions &options) +{ + const UStringVector &nonSwitchStrings = parser.NonSwitchStrings; + int numNonSwitchStrings = nonSwitchStrings.Size(); + if(numNonSwitchStrings < kMinNonSwitchWords) + ThrowUserErrorException(); + + if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command)) + ThrowUserErrorException(); + + options.TechMode = parser[NKey::kTechMode].ThereIs; + + if (parser[NKey::kCaseSensitive].ThereIs) + g_CaseSensitive = (parser[NKey::kCaseSensitive].PostCharIndex < 0); + + NRecursedType::EEnum recursedType; + if (parser[NKey::kRecursed].ThereIs) + recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex); + else + recursedType = NRecursedType::kNonRecursed; + + UINT codePage = CP_UTF8; + if (parser[NKey::kCharSet].ThereIs) + { + UString name = parser[NKey::kCharSet].PostStrings.Front(); + name.MakeUpper(); + int i; + for (i = 0; i < kNumCodePages; i++) + { + const CCodePagePair &pair = g_CodePagePairs[i]; + if (name.Compare(pair.Name) == 0) + { + codePage = pair.CodePage; + break; + } + } + if (i >= kNumCodePages) + ThrowUserErrorException(); + } + + bool thereAreSwitchIncludes = false; + if (parser[NKey::kInclude].ThereIs) + { + thereAreSwitchIncludes = true; + AddSwitchWildCardsToCensor(options.WildcardCensor, + parser[NKey::kInclude].PostStrings, true, recursedType, codePage); + } + if (parser[NKey::kExclude].ThereIs) + AddSwitchWildCardsToCensor(options.WildcardCensor, + parser[NKey::kExclude].PostStrings, false, recursedType, codePage); + + int curCommandIndex = kCommandIndex + 1; + bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs && + options.Command.CommandType != NCommandType::kBenchmark && + options.Command.CommandType != NCommandType::kInfo; + if (thereIsArchiveName) + { + if(curCommandIndex >= numNonSwitchStrings) + ThrowUserErrorException(); + options.ArchiveName = nonSwitchStrings[curCommandIndex++]; + } + + AddToCensorFromNonSwitchesStrings( + curCommandIndex, options.WildcardCensor, + nonSwitchStrings, recursedType, thereAreSwitchIncludes, codePage); + + options.YesToAll = parser[NKey::kYes].ThereIs; + + bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); + + options.PasswordEnabled = parser[NKey::kPassword].ThereIs; + + if(options.PasswordEnabled) + options.Password = parser[NKey::kPassword].PostStrings[0]; + + options.StdInMode = parser[NKey::kStdIn].ThereIs; + options.ShowDialog = parser[NKey::kShowDialog].ThereIs; + + if(isExtractGroupCommand || options.Command.CommandType == NCommandType::kList) + { + if (options.StdInMode) + ThrowException("Reading archives from stdin is not implemented"); + if (!options.WildcardCensor.AllAreRelative()) + ThrowException("Cannot use absolute pathnames for this command"); + + NWildcard::CCensor archiveWildcardCensor; + + if (parser[NKey::kArInclude].ThereIs) + { + AddSwitchWildCardsToCensor(archiveWildcardCensor, + parser[NKey::kArInclude].PostStrings, true, NRecursedType::kNonRecursed, codePage); + } + if (parser[NKey::kArExclude].ThereIs) + AddSwitchWildCardsToCensor(archiveWildcardCensor, + parser[NKey::kArExclude].PostStrings, false, NRecursedType::kNonRecursed, codePage); + + if (thereIsArchiveName) + AddCommandLineWildCardToCensr(archiveWildcardCensor, options.ArchiveName, true, NRecursedType::kNonRecursed); + + #ifdef _WIN32 + ConvertToLongNames(archiveWildcardCensor); + #endif + + archiveWildcardCensor.ExtendExclude(); + + CObjectVector dirItems; + { + UStringVector errorPaths; + CRecordVector errorCodes; + HRESULT res = EnumerateItems(archiveWildcardCensor, dirItems, NULL, errorPaths, errorCodes); + if (res != S_OK || errorPaths.Size() > 0) + throw "cannot find archive"; + } + UStringVector archivePaths; + int i; + for (i = 0; i < dirItems.Size(); i++) + { + const CDirItem &dirItem = dirItems[i]; + if (!dirItem.IsDirectory()) + archivePaths.Add(dirItem.FullPath); + } + + if (archivePaths.Size() == 0) + throw "there is no such archive"; + + UStringVector archivePathsFull; + + for (i = 0; i < archivePaths.Size(); i++) + { + UString fullPath; + NFile::NDirectory::MyGetFullPathName(archivePaths[i], fullPath); + archivePathsFull.Add(fullPath); + } + CIntVector indices; + SortFileNames(archivePathsFull, indices); + options.ArchivePathsSorted.Reserve(indices.Size()); + options.ArchivePathsFullSorted.Reserve(indices.Size()); + for (i = 0; i < indices.Size(); i++) + { + options.ArchivePathsSorted.Add(archivePaths[indices[i]]); + options.ArchivePathsFullSorted.Add(archivePathsFull[indices[i]]); + } + + if (isExtractGroupCommand) + { + SetMethodOptions(parser, options.ExtractProperties); + if (options.StdOutMode && options.IsStdOutTerminal && options.IsStdErrTerminal) + throw kSameTerminalError; + if(parser[NKey::kOutputDir].ThereIs) + { + options.OutputDir = parser[NKey::kOutputDir].PostStrings[0]; + NFile::NName::NormalizeDirPathPrefix(options.OutputDir); + } + + options.OverwriteMode = NExtract::NOverwriteMode::kAskBefore; + if(parser[NKey::kOverwrite].ThereIs) + options.OverwriteMode = + k_OverwriteModes[parser[NKey::kOverwrite].PostCharIndex]; + else if (options.YesToAll) + options.OverwriteMode = NExtract::NOverwriteMode::kWithoutPrompt; + } + } + else if(options.Command.IsFromUpdateGroup()) + { + CUpdateOptions &updateOptions = options.UpdateOptions; + + if(parser[NKey::kArchiveType].ThereIs) + options.ArcType = parser[NKey::kArchiveType].PostStrings[0]; + + SetAddCommandOptions(options.Command.CommandType, parser, updateOptions); + + SetMethodOptions(parser, updateOptions.MethodMode.Properties); + + if (parser[NKey::kShareForWrite].ThereIs) + updateOptions.OpenShareForWrite = true; + + options.EnablePercents = !parser[NKey::kDisablePercents].ThereIs; + + if (options.EnablePercents) + { + if ((options.StdOutMode && !options.IsStdErrTerminal) || + (!options.StdOutMode && !options.IsStdOutTerminal)) + options.EnablePercents = false; + } + + updateOptions.EMailMode = parser[NKey::kEmail].ThereIs; + if (updateOptions.EMailMode) + { + updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front(); + if (updateOptions.EMailAddress.Length() > 0) + if (updateOptions.EMailAddress[0] == L'.') + { + updateOptions.EMailRemoveAfter = true; + updateOptions.EMailAddress.Delete(0); + } + } + + updateOptions.StdOutMode = options.StdOutMode; + updateOptions.StdInMode = options.StdInMode; + + if (updateOptions.StdOutMode && updateOptions.EMailMode) + throw "stdout mode and email mode cannot be combined"; + if (updateOptions.StdOutMode && options.IsStdOutTerminal) + throw kTerminalOutError; + if(updateOptions.StdInMode) + updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front(); + + #ifdef _WIN32 + ConvertToLongNames(options.WildcardCensor); + #endif + } + else if(options.Command.CommandType == NCommandType::kBenchmark) + { + options.NumThreads = (UInt32)-1; + options.DictionarySize = (UInt32)-1; + options.NumIterations = 1; + if (curCommandIndex < numNonSwitchStrings) + { + if (!ConvertStringToUInt32(nonSwitchStrings[curCommandIndex++], options.NumIterations)) + ThrowUserErrorException(); + } + for (int i = 0; i < parser[NKey::kProperty].PostStrings.Size(); i++) + { + UString postString = parser[NKey::kProperty].PostStrings[i]; + postString.MakeUpper(); + if (postString.Length() < 2) + ThrowUserErrorException(); + if (postString[0] == 'D') + { + int pos = 1; + if (postString[pos] == '=') + pos++; + UInt32 logSize; + if (!ConvertStringToUInt32((const wchar_t *)postString + pos, logSize)) + ThrowUserErrorException(); + if (logSize > 31) + ThrowUserErrorException(); + options.DictionarySize = 1 << logSize; + } + else if (postString[0] == 'M' && postString[1] == 'T' ) + { + int pos = 2; + if (postString[pos] == '=') + pos++; + if (postString[pos] != 0) + if (!ConvertStringToUInt32((const wchar_t *)postString + pos, options.NumThreads)) + ThrowUserErrorException(); + } + else if (postString[0] == 'M' && postString[1] == '=' ) + { + int pos = 2; + if (postString[pos] != 0) + options.Method = postString.Mid(2); + } + else + ThrowUserErrorException(); + } + } + else if(options.Command.CommandType == NCommandType::kInfo) + { + } + else + ThrowUserErrorException(); + options.WildcardCensor.ExtendExclude(); +}