summaryrefslogtreecommitdiffstats
path: root/other-licenses/7zstub/src/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'other-licenses/7zstub/src/CPP/7zip/UI/Common/ArchiveCommandLine.cpp')
-rw-r--r--other-licenses/7zstub/src/CPP/7zip/UI/Common/ArchiveCommandLine.cpp1281
1 files changed, 1281 insertions, 0 deletions
diff --git a/other-licenses/7zstub/src/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/other-licenses/7zstub/src/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
new file mode 100644
index 000000000..f14aafbaf
--- /dev/null
+++ b/other-licenses/7zstub/src/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
@@ -0,0 +1,1281 @@
+// ArchiveCommandLine.cpp
+
+#include "StdAfx.h"
+#undef printf
+#undef sprintf
+
+#ifdef _WIN32
+#ifndef UNDER_CE
+#include <io.h>
+#endif
+#else
+// for isatty()
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef _7ZIP_LARGE_PAGES
+#include "../../../../C/Alloc.h"
+#endif
+
+#include "../../../Common/ListFileUtils.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+#ifdef _WIN32
+#include "../../../Windows/FileMapping.h"
+#include "../../../Windows/MemoryLock.h"
+#include "../../../Windows/Synchronization.h"
+#endif
+
+#include "ArchiveCommandLine.h"
+#include "EnumDirItems.h"
+#include "Update.h"
+#include "UpdateAction.h"
+
+extern bool g_CaseSensitive;
+extern bool g_PathTrailReplaceMode;
+
+bool g_LargePagesMode = false;
+
+#ifdef UNDER_CE
+
+#define MY_IS_TERMINAL(x) false;
+
+#else
+
+#if _MSC_VER >= 1400
+#define MY_isatty_fileno(x) _isatty(_fileno(x))
+#else
+#define MY_isatty_fileno(x) isatty(fileno(x))
+#endif
+
+#define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0);
+
+#endif
+
+using namespace NCommandLineParser;
+using namespace NWindows;
+using namespace NFile;
+
+static bool StringToUInt32(const wchar_t *s, UInt32 &v)
+{
+ if (*s == 0)
+ return false;
+ const wchar_t *end;
+ v = ConvertStringToUInt32(s, &end);
+ return *end == 0;
+}
+
+
+int g_CodePage = -1;
+
+namespace NKey {
+enum Enum
+{
+ kHelp1 = 0,
+ kHelp2,
+ kHelp3,
+
+ kDisableHeaders,
+ kDisablePercents,
+ kShowTime,
+ kLogLevel,
+
+ kOutStream,
+ kErrStream,
+ kPercentStream,
+
+ kYes,
+
+ kShowDialog,
+ kOverwrite,
+
+ kArchiveType,
+ kExcludedArcType,
+
+ kProperty,
+ kOutputDir,
+ kWorkingDir,
+
+ kInclude,
+ kExclude,
+ kArInclude,
+ kArExclude,
+ kNoArName,
+
+ kUpdate,
+ kVolume,
+ kRecursed,
+
+ kAffinity,
+ kSfx,
+ kEmail,
+ kHash,
+
+ kStdIn,
+ kStdOut,
+
+ kLargePages,
+ kListfileCharSet,
+ kConsoleCharSet,
+ kTechMode,
+
+ kShareForWrite,
+ kStopAfterOpenError,
+ kCaseSensitive,
+ kArcNameMode,
+
+ kDisableWildcardParsing,
+ kElimDup,
+ kFullPathMode,
+
+ kHardLinks,
+ kSymLinks,
+ kNtSecurity,
+
+ kAltStreams,
+ kReplaceColonForAltStream,
+ kWriteToAltStreamIfColon,
+
+ kNameTrailReplace,
+
+ kDeleteAfterCompressing,
+ kSetArcMTime
+
+ #ifndef _NO_CRYPTO
+ , kPassword
+ #endif
+};
+
+}
+
+
+static const wchar_t kRecursedIDChar = 'r';
+static const char * const kRecursedPostCharSet = "0-";
+
+static const char * const k_ArcNameMode_PostCharSet = "sea";
+
+static const char * const k_Stream_PostCharSet = "012";
+
+static inline const EArcNameMode ParseArcNameMode(int postCharIndex)
+{
+ switch (postCharIndex)
+ {
+ case 1: return k_ArcNameMode_Exact;
+ case 2: return k_ArcNameMode_Add;
+ default: return k_ArcNameMode_Smart;
+ }
+}
+
+namespace NRecursedPostCharIndex {
+ enum EEnum
+ {
+ kWildcardRecursionOnly = 0,
+ kNoRecursion = 1
+ };
+}
+
+static const char kImmediateNameID = '!';
+static const char kMapNameID = '#';
+static const char kFileListID = '@';
+
+static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
+static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be
+
+static const char * const kOverwritePostCharSet = "asut";
+
+static const NExtract::NOverwriteMode::EEnum k_OverwriteModes[] =
+{
+ NExtract::NOverwriteMode::kOverwrite,
+ NExtract::NOverwriteMode::kSkip,
+ NExtract::NOverwriteMode::kRename,
+ NExtract::NOverwriteMode::kRenameExisting
+};
+
+static const CSwitchForm kSwitchForms[] =
+{
+ { "?" },
+ { "h" },
+ { "-help" },
+
+ { "ba" },
+ { "bd" },
+ { "bt" },
+ { "bb", NSwitchType::kString, false, 0 },
+
+ { "bso", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
+ { "bse", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
+ { "bsp", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
+
+ { "y" },
+
+ { "ad" },
+ { "ao", NSwitchType::kChar, false, 1, kOverwritePostCharSet},
+
+ { "t", NSwitchType::kString, false, 1 },
+ { "stx", NSwitchType::kString, true, 1 },
+
+ { "m", NSwitchType::kString, true, 1 },
+ { "o", NSwitchType::kString, false, 1 },
+ { "w", NSwitchType::kString },
+
+ { "i", NSwitchType::kString, true, kSomeCludePostStringMinSize},
+ { "x", NSwitchType::kString, true, kSomeCludePostStringMinSize},
+ { "ai", NSwitchType::kString, true, kSomeCludePostStringMinSize},
+ { "ax", NSwitchType::kString, true, kSomeCludePostStringMinSize},
+ { "an" },
+
+ { "u", NSwitchType::kString, true, 1},
+ { "v", NSwitchType::kString, true, 1},
+ { "r", NSwitchType::kChar, false, 0, kRecursedPostCharSet },
+
+ { "stm", NSwitchType::kString },
+ { "sfx", NSwitchType::kString },
+ { "seml", NSwitchType::kString, false, 0},
+ { "scrc", NSwitchType::kString, true, 0 },
+
+ { "si", NSwitchType::kString },
+ { "so" },
+
+ { "slp", NSwitchType::kString },
+ { "scs", NSwitchType::kString },
+ { "scc", NSwitchType::kString },
+ { "slt" },
+
+ { "ssw" },
+ { "sse" },
+ { "ssc", NSwitchType::kMinus },
+ { "sa", NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet },
+
+ { "spd" },
+ { "spe", NSwitchType::kMinus },
+ { "spf", NSwitchType::kString, false, 0 },
+
+ { "snh", NSwitchType::kMinus },
+ { "snl", NSwitchType::kMinus },
+ { "sni" },
+
+ { "sns", NSwitchType::kMinus },
+ { "snr" },
+ { "snc" },
+
+ { "snt", NSwitchType::kMinus },
+
+ { "sdel" },
+ { "stl" }
+
+ #ifndef _NO_CRYPTO
+ , { "p", NSwitchType::kString }
+ #endif
+};
+
+static const char * const kUniversalWildcard = "*";
+static const unsigned kMinNonSwitchWords = 1;
+static const unsigned kCommandIndex = 0;
+
+// static const char * const kUserErrorMessage = "Incorrect command line";
+static const char * const kCannotFindListFile = "Cannot find listfile";
+static const char * const kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch.";
+static const char * const kTerminalOutError = "I won't write compressed data to a terminal";
+static const char * const kSameTerminalError = "I won't write data and program's messages to same stream";
+static const char * const kEmptyFilePath = "Empty file path";
+
+bool CArcCommand::IsFromExtractGroup() const
+{
+ switch (CommandType)
+ {
+ case NCommandType::kTest:
+ case NCommandType::kExtract:
+ case NCommandType::kExtractFull:
+ return true;
+ }
+ return false;
+}
+
+NExtract::NPathMode::EEnum CArcCommand::GetPathMode() const
+{
+ switch (CommandType)
+ {
+ case NCommandType::kTest:
+ case NCommandType::kExtractFull:
+ return NExtract::NPathMode::kFullPaths;
+ }
+ return NExtract::NPathMode::kNoPaths;
+}
+
+bool CArcCommand::IsFromUpdateGroup() const
+{
+ switch (CommandType)
+ {
+ case NCommandType::kAdd:
+ case NCommandType::kUpdate:
+ case NCommandType::kDelete:
+ case NCommandType::kRename:
+ return true;
+ }
+ return false;
+}
+
+static NRecursedType::EEnum GetRecursedTypeFromIndex(int index)
+{
+ switch (index)
+ {
+ case NRecursedPostCharIndex::kWildcardRecursionOnly:
+ return NRecursedType::kWildcardOnlyRecursed;
+ case NRecursedPostCharIndex::kNoRecursion:
+ return NRecursedType::kNonRecursed;
+ default:
+ return NRecursedType::kRecursed;
+ }
+}
+
+static const char *g_Commands = "audtexlbih";
+
+static bool ParseArchiveCommand(const UString &commandString, CArcCommand &command)
+{
+ UString s (commandString);
+ s.MakeLower_Ascii();
+ if (s.Len() == 1)
+ {
+ if (s[0] > 0x7F)
+ return false;
+ int index = FindCharPosInString(g_Commands, (char)s[0]);
+ if (index < 0)
+ return false;
+ command.CommandType = (NCommandType::EEnum)index;
+ return true;
+ }
+ if (s.Len() == 2 && s[0] == 'r' && s[1] == 'n')
+ {
+ command.CommandType = (NCommandType::kRename);
+ return true;
+ }
+ return false;
+}
+
+// ------------------------------------------------------------------
+// filenames functions
+
+static void AddNameToCensor(NWildcard::CCensor &censor,
+ const UString &name, bool include, NRecursedType::EEnum type, bool wildcardMatching)
+{
+ bool recursed = false;
+
+ switch (type)
+ {
+ case NRecursedType::kWildcardOnlyRecursed:
+ recursed = DoesNameContainWildcard(name);
+ break;
+ case NRecursedType::kRecursed:
+ recursed = true;
+ break;
+ }
+ censor.AddPreItem(include, name, recursed, wildcardMatching);
+}
+
+static void AddRenamePair(CObjectVector<CRenamePair> *renamePairs,
+ const UString &oldName, const UString &newName, NRecursedType::EEnum type,
+ bool wildcardMatching)
+{
+ CRenamePair &pair = renamePairs->AddNew();
+ pair.OldName = oldName;
+ pair.NewName = newName;
+ pair.RecursedType = type;
+ pair.WildcardParsing = wildcardMatching;
+
+ if (!pair.Prepare())
+ {
+ UString val;
+ val += pair.OldName;
+ val.Add_LF();
+ val += pair.NewName;
+ val.Add_LF();
+ if (type == NRecursedType::kRecursed)
+ val += "-r";
+ else if (type == NRecursedType::kWildcardOnlyRecursed)
+ val += "-r0";
+ throw CArcCmdLineException("Unsupported rename command:", val);
+ }
+}
+
+static void AddToCensorFromListFile(
+ CObjectVector<CRenamePair> *renamePairs,
+ NWildcard::CCensor &censor,
+ LPCWSTR fileName, bool include, NRecursedType::EEnum type, bool wildcardMatching, Int32 codePage)
+{
+ UStringVector names;
+ if (!NFind::DoesFileExist(us2fs(fileName)))
+ throw CArcCmdLineException(kCannotFindListFile, fileName);
+ if (!ReadNamesFromListFile(us2fs(fileName), names, codePage))
+ throw CArcCmdLineException(kIncorrectListFile, fileName);
+ if (renamePairs)
+ {
+ if ((names.Size() & 1) != 0)
+ throw CArcCmdLineException(kIncorrectListFile, fileName);
+ for (unsigned i = 0; i < names.Size(); i += 2)
+ {
+ // change type !!!!
+ AddRenamePair(renamePairs, names[i], names[i + 1], type, wildcardMatching);
+ }
+ }
+ else
+ FOR_VECTOR (i, names)
+ AddNameToCensor(censor, names[i], include, type, wildcardMatching);
+}
+
+static void AddToCensorFromNonSwitchesStrings(
+ CObjectVector<CRenamePair> *renamePairs,
+ unsigned startIndex,
+ NWildcard::CCensor &censor,
+ const UStringVector &nonSwitchStrings,
+ int stopSwitchIndex,
+ NRecursedType::EEnum type,
+ bool wildcardMatching,
+ bool thereAreSwitchIncludes, Int32 codePage)
+{
+ if ((renamePairs || nonSwitchStrings.Size() == startIndex) && !thereAreSwitchIncludes)
+ AddNameToCensor(censor, UString(kUniversalWildcard), true, type,
+ true // wildcardMatching
+ );
+
+ int oldIndex = -1;
+
+ if (stopSwitchIndex < 0)
+ stopSwitchIndex = nonSwitchStrings.Size();
+
+ for (unsigned i = startIndex; i < nonSwitchStrings.Size(); i++)
+ {
+ const UString &s = nonSwitchStrings[i];
+ if (s.IsEmpty())
+ throw CArcCmdLineException(kEmptyFilePath);
+ if (i < (unsigned)stopSwitchIndex && s[0] == kFileListID)
+ AddToCensorFromListFile(renamePairs, censor, s.Ptr(1), true, type, wildcardMatching, codePage);
+ else if (renamePairs)
+ {
+ if (oldIndex == -1)
+ oldIndex = i;
+ else
+ {
+ // NRecursedType::EEnum type is used for global wildcard (-i! switches)
+ AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, NRecursedType::kNonRecursed, wildcardMatching);
+ // AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, type);
+ oldIndex = -1;
+ }
+ }
+ else
+ AddNameToCensor(censor, s, true, type, wildcardMatching);
+ }
+
+ if (oldIndex != -1)
+ {
+ throw CArcCmdLineException("There is no second file name for rename pair:", nonSwitchStrings[oldIndex]);
+ }
+}
+
+#ifdef _WIN32
+
+struct CEventSetEnd
+{
+ UString Name;
+
+ CEventSetEnd(const wchar_t *name): Name(name) {}
+ ~CEventSetEnd()
+ {
+ NSynchronization::CManualResetEvent event;
+ if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(Name)) == 0)
+ event.Set();
+ }
+};
+
+static const char * const k_IncorrectMapCommand = "Incorrect Map command";
+
+static const char *ParseMapWithPaths(
+ NWildcard::CCensor &censor,
+ const UString &s2, bool include,
+ NRecursedType::EEnum commonRecursedType,
+ bool wildcardMatching)
+{
+ UString s (s2);
+ int pos = s.Find(L':');
+ if (pos < 0)
+ return k_IncorrectMapCommand;
+ int pos2 = s.Find(L':', pos + 1);
+ if (pos2 < 0)
+ return k_IncorrectMapCommand;
+
+ CEventSetEnd eventSetEnd((const wchar_t *)s + ((unsigned)pos2 + 1));
+ s.DeleteFrom(pos2);
+ UInt32 size;
+ if (!StringToUInt32(s.Ptr(pos + 1), size)
+ || size < sizeof(wchar_t)
+ || size > ((UInt32)1 << 31)
+ || size % sizeof(wchar_t) != 0)
+ return "Unsupported Map data size";
+
+ s.DeleteFrom(pos);
+ CFileMapping map;
+ if (map.Open(FILE_MAP_READ, GetSystemString(s)) != 0)
+ return "Can not open mapping";
+ LPVOID data = map.Map(FILE_MAP_READ, 0, size);
+ if (!data)
+ return "MapViewOfFile error";
+ CFileUnmapper unmapper(data);
+
+ UString name;
+ const wchar_t *p = (const wchar_t *)data;
+ if (*p != 0) // data format marker
+ return "Unsupported Map data";
+ UInt32 numChars = size / sizeof(wchar_t);
+ for (UInt32 i = 1; i < numChars; i++)
+ {
+ wchar_t c = p[i];
+ if (c == 0)
+ {
+ // MessageBoxW(0, name, L"7-Zip", 0);
+ AddNameToCensor(censor, name, include, commonRecursedType, wildcardMatching);
+ name.Empty();
+ }
+ else
+ name += c;
+ }
+ if (!name.IsEmpty())
+ return "Map data error";
+
+ return NULL;
+}
+
+#endif
+
+static void AddSwitchWildcardsToCensor(
+ NWildcard::CCensor &censor,
+ const UStringVector &strings, bool include,
+ NRecursedType::EEnum commonRecursedType,
+ bool wildcardMatching,
+ Int32 codePage)
+{
+ const char *errorMessage = NULL;
+ unsigned i;
+ for (i = 0; i < strings.Size(); i++)
+ {
+ const UString &name = strings[i];
+ NRecursedType::EEnum recursedType;
+ unsigned pos = 0;
+
+ if (name.Len() < kSomeCludePostStringMinSize)
+ {
+ errorMessage = "Too short switch";
+ break;
+ }
+
+ if (::MyCharLower_Ascii(name[pos]) == kRecursedIDChar)
+ {
+ pos++;
+ wchar_t c = name[pos];
+ int index = -1;
+ if (c <= 0x7F)
+ index = FindCharPosInString(kRecursedPostCharSet, (char)c);
+ recursedType = GetRecursedTypeFromIndex(index);
+ if (index >= 0)
+ pos++;
+ }
+ else
+ recursedType = commonRecursedType;
+
+ if (name.Len() < pos + kSomeCludeAfterRecursedPostStringMinSize)
+ {
+ errorMessage = "Too short switch";
+ break;
+ }
+
+ const UString tail = name.Ptr(pos + 1);
+
+ if (name[pos] == kImmediateNameID)
+ AddNameToCensor(censor, tail, include, recursedType, wildcardMatching);
+ else if (name[pos] == kFileListID)
+ AddToCensorFromListFile(NULL, censor, tail, include, recursedType, wildcardMatching, codePage);
+ #ifdef _WIN32
+ else if (name[pos] == kMapNameID)
+ {
+ errorMessage = ParseMapWithPaths(censor, tail, include, recursedType, wildcardMatching);
+ if (errorMessage)
+ break;
+ }
+ #endif
+ else
+ {
+ errorMessage = "Incorrect wildcard type marker";
+ break;
+ }
+ }
+ if (i != strings.Size())
+ throw CArcCmdLineException(errorMessage, strings[i]);
+}
+
+/*
+static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i)
+{
+ switch (i)
+ {
+ case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore;
+ case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy;
+ case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress;
+ case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti;
+ }
+ throw 98111603;
+}
+*/
+
+static const char * const kUpdatePairStateIDSet = "pqrxyzw";
+static const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1};
+
+static const unsigned kNumUpdatePairActions = 4;
+static const char * const kUpdateIgnoreItselfPostStringID = "-";
+static const wchar_t kUpdateNewArchivePostCharID = '!';
+
+
+static bool ParseUpdateCommandString2(const UString &command,
+ NUpdateArchive::CActionSet &actionSet, UString &postString)
+{
+ for (unsigned i = 0; i < command.Len();)
+ {
+ wchar_t c = MyCharLower_Ascii(command[i]);
+ int statePos = FindCharPosInString(kUpdatePairStateIDSet, (char)c);
+ if (c > 0x7F || statePos < 0)
+ {
+ postString = command.Ptr(i);
+ return true;
+ }
+ i++;
+ if (i >= command.Len())
+ return false;
+ c = command[i];
+ if (c < '0' || c >= '0' + kNumUpdatePairActions)
+ return false;
+ unsigned actionPos = c - '0';
+ actionSet.StateActions[(unsigned)statePos] = (NUpdateArchive::NPairAction::EEnum)(actionPos);
+ if (kUpdatePairStateNotSupportedActions[(unsigned)statePos] == (int)actionPos)
+ return false;
+ i++;
+ }
+ postString.Empty();
+ return true;
+}
+
+static void ParseUpdateCommandString(CUpdateOptions &options,
+ const UStringVector &updatePostStrings,
+ const NUpdateArchive::CActionSet &defaultActionSet)
+{
+ const char *errorMessage = "incorrect update switch command";
+ unsigned i;
+ for (i = 0; i < updatePostStrings.Size(); i++)
+ {
+ const UString &updateString = updatePostStrings[i];
+ if (updateString.IsEqualTo(kUpdateIgnoreItselfPostStringID))
+ {
+ if (options.UpdateArchiveItself)
+ {
+ options.UpdateArchiveItself = false;
+ options.Commands.Delete(0);
+ }
+ }
+ else
+ {
+ NUpdateArchive::CActionSet actionSet = defaultActionSet;
+
+ UString postString;
+ if (!ParseUpdateCommandString2(updateString, actionSet, postString))
+ break;
+ if (postString.IsEmpty())
+ {
+ if (options.UpdateArchiveItself)
+ options.Commands[0].ActionSet = actionSet;
+ }
+ else
+ {
+ if (postString[0] != kUpdateNewArchivePostCharID)
+ break;
+ CUpdateArchiveCommand uc;
+ UString archivePath = postString.Ptr(1);
+ if (archivePath.IsEmpty())
+ break;
+ uc.UserArchivePath = archivePath;
+ uc.ActionSet = actionSet;
+ options.Commands.Add(uc);
+ }
+ }
+ }
+ if (i != updatePostStrings.Size())
+ throw CArcCmdLineException(errorMessage, updatePostStrings[i]);
+}
+
+bool ParseComplexSize(const wchar_t *s, UInt64 &result);
+
+static void SetAddCommandOptions(
+ NCommandType::EEnum commandType,
+ const CParser &parser,
+ CUpdateOptions &options)
+{
+ NUpdateArchive::CActionSet defaultActionSet;
+ switch (commandType)
+ {
+ case NCommandType::kAdd:
+ defaultActionSet = NUpdateArchive::k_ActionSet_Add;
+ break;
+ case NCommandType::kDelete:
+ defaultActionSet = NUpdateArchive::k_ActionSet_Delete;
+ break;
+ default:
+ defaultActionSet = NUpdateArchive::k_ActionSet_Update;
+ }
+
+ options.UpdateArchiveItself = true;
+
+ options.Commands.Clear();
+ CUpdateArchiveCommand updateMainCommand;
+ updateMainCommand.ActionSet = defaultActionSet;
+ options.Commands.Add(updateMainCommand);
+ if (parser[NKey::kUpdate].ThereIs)
+ ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings,
+ defaultActionSet);
+ if (parser[NKey::kWorkingDir].ThereIs)
+ {
+ const UString &postString = parser[NKey::kWorkingDir].PostStrings[0];
+ if (postString.IsEmpty())
+ NDir::MyGetTempPath(options.WorkingDir);
+ else
+ options.WorkingDir = us2fs(postString);
+ }
+ options.SfxMode = parser[NKey::kSfx].ThereIs;
+ if (options.SfxMode)
+ options.SfxModule = us2fs(parser[NKey::kSfx].PostStrings[0]);
+
+ if (parser[NKey::kVolume].ThereIs)
+ {
+ const UStringVector &sv = parser[NKey::kVolume].PostStrings;
+ FOR_VECTOR (i, sv)
+ {
+ UInt64 size;
+ if (!ParseComplexSize(sv[i], size) || size == 0)
+ throw CArcCmdLineException("Incorrect volume size:", sv[i]);
+ options.VolumesSizes.Add(size);
+ }
+ }
+}
+
+static void SetMethodOptions(const CParser &parser, CObjectVector<CProperty> &properties)
+{
+ if (parser[NKey::kProperty].ThereIs)
+ {
+ FOR_VECTOR (i, parser[NKey::kProperty].PostStrings)
+ {
+ CProperty prop;
+ prop.Name = parser[NKey::kProperty].PostStrings[i];
+ int index = prop.Name.Find(L'=');
+ if (index >= 0)
+ {
+ prop.Value = prop.Name.Ptr(index + 1);
+ prop.Name.DeleteFrom(index);
+ }
+ properties.Add(prop);
+ }
+ }
+}
+
+
+static inline void SetStreamMode(const CSwitchResult &sw, unsigned &res)
+{
+ if (sw.ThereIs)
+ res = sw.PostCharIndex;
+}
+
+
+void CArcCmdLineParser::Parse1(const UStringVector &commandStrings,
+ CArcCmdLineOptions &options)
+{
+ if (!parser.ParseStrings(kSwitchForms, ARRAY_SIZE(kSwitchForms), commandStrings))
+ throw CArcCmdLineException(parser.ErrorMessage, parser.ErrorLine);
+
+ options.IsInTerminal = MY_IS_TERMINAL(stdin);
+ options.IsStdOutTerminal = MY_IS_TERMINAL(stdout);
+ options.IsStdErrTerminal = MY_IS_TERMINAL(stderr);
+
+ options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs || parser[NKey::kHelp3].ThereIs;
+
+ options.StdInMode = parser[NKey::kStdIn].ThereIs;
+ options.StdOutMode = parser[NKey::kStdOut].ThereIs;
+ options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs;
+ options.TechMode = parser[NKey::kTechMode].ThereIs;
+ options.ShowTime = parser[NKey::kShowTime].ThereIs;
+
+ if (parser[NKey::kDisablePercents].ThereIs
+ || options.StdOutMode
+ || !options.IsStdOutTerminal)
+ options.Number_for_Percents = k_OutStream_disabled;
+
+ if (options.StdOutMode)
+ options.Number_for_Out = k_OutStream_disabled;
+
+ SetStreamMode(parser[NKey::kOutStream], options.Number_for_Out);
+ SetStreamMode(parser[NKey::kErrStream], options.Number_for_Errors);
+ SetStreamMode(parser[NKey::kPercentStream], options.Number_for_Percents);
+
+ if (parser[NKey::kLogLevel].ThereIs)
+ {
+ const UString &s = parser[NKey::kLogLevel].PostStrings[0];
+ if (s.IsEmpty())
+ options.LogLevel = 1;
+ else
+ {
+ UInt32 v;
+ if (!StringToUInt32(s, v))
+ throw CArcCmdLineException("Unsupported switch postfix -bb", s);
+ options.LogLevel = (unsigned)v;
+ }
+ }
+
+ if (parser[NKey::kCaseSensitive].ThereIs)
+ {
+ g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus;
+ options.CaseSensitiveChange = true;
+ options.CaseSensitive = g_CaseSensitive;
+ }
+
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ NSecurity::EnablePrivilege_SymLink();
+ #endif
+
+ // options.LargePages = false;
+
+ if (parser[NKey::kLargePages].ThereIs)
+ {
+ unsigned slp = 0;
+ const UString &s = parser[NKey::kLargePages].PostStrings[0];
+ if (s.IsEmpty())
+ slp = 1;
+ else if (s != L"-")
+ {
+ if (!StringToUInt32(s, slp))
+ throw CArcCmdLineException("Unsupported switch postfix for -slp", s);
+ }
+
+ #ifdef _7ZIP_LARGE_PAGES
+ if (slp >
+ #ifndef UNDER_CE
+ (unsigned)NSecurity::Get_LargePages_RiskLevel()
+ #else
+ 0
+ #endif
+ )
+ {
+ SetLargePageSize();
+ // note: this process also can inherit that Privilege from parent process
+ g_LargePagesMode =
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ NSecurity::EnablePrivilege_LockMemory();
+ #else
+ true;
+ #endif
+ }
+ #endif
+ }
+
+
+ #ifndef UNDER_CE
+
+ if (parser[NKey::kAffinity].ThereIs)
+ {
+ const UString &s = parser[NKey::kAffinity].PostStrings[0];
+ if (!s.IsEmpty())
+ {
+ UInt32 v = 0;
+ AString a;
+ a.SetFromWStr_if_Ascii(s);
+ if (!a.IsEmpty())
+ {
+ const char *end;
+ v = ConvertHexStringToUInt32(a, &end);
+ if (*end != 0)
+ a.Empty();
+ }
+ if (a.IsEmpty())
+ throw CArcCmdLineException("Unsupported switch postfix -stm", s);
+
+ #ifdef _WIN32
+ SetProcessAffinityMask(GetCurrentProcess(), v);
+ #endif
+ }
+ }
+
+ #endif
+}
+
+struct CCodePagePair
+{
+ const char *Name;
+ Int32 CodePage;
+};
+
+static const unsigned kNumByteOnlyCodePages = 3;
+
+static const CCodePagePair g_CodePagePairs[] =
+{
+ { "utf-8", CP_UTF8 },
+ { "win", CP_ACP },
+ { "dos", CP_OEMCP },
+ { "utf-16le", MY__CP_UTF16 },
+ { "utf-16be", MY__CP_UTF16BE }
+};
+
+static Int32 FindCharset(const NCommandLineParser::CParser &parser, unsigned keyIndex,
+ bool byteOnlyCodePages, Int32 defaultVal)
+{
+ if (!parser[keyIndex].ThereIs)
+ return defaultVal;
+
+ UString name (parser[keyIndex].PostStrings.Back());
+ UInt32 v;
+ if (StringToUInt32(name, v))
+ if (v < ((UInt32)1 << 16))
+ return (Int32)v;
+ name.MakeLower_Ascii();
+ unsigned num = byteOnlyCodePages ? kNumByteOnlyCodePages : ARRAY_SIZE(g_CodePagePairs);
+ for (unsigned i = 0;; i++)
+ {
+ if (i == num) // to disable warnings from different compilers
+ throw CArcCmdLineException("Unsupported charset:", name);
+ const CCodePagePair &pair = g_CodePagePairs[i];
+ if (name.IsEqualTo(pair.Name))
+ return pair.CodePage;
+ }
+}
+
+
+static void SetBoolPair(NCommandLineParser::CParser &parser, unsigned switchID, CBoolPair &bp)
+{
+ bp.Def = parser[switchID].ThereIs;
+ if (bp.Def)
+ bp.Val = !parser[switchID].WithMinus;
+}
+
+void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
+{
+ const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
+ const unsigned numNonSwitchStrings = nonSwitchStrings.Size();
+ if (numNonSwitchStrings < kMinNonSwitchWords)
+ throw CArcCmdLineException("The command must be specified");
+
+ if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command))
+ throw CArcCmdLineException("Unsupported command:", nonSwitchStrings[kCommandIndex]);
+
+ if (parser[NKey::kHash].ThereIs)
+ options.HashMethods = parser[NKey::kHash].PostStrings;
+
+ if (parser[NKey::kElimDup].ThereIs)
+ {
+ options.ExtractOptions.ElimDup.Def = true;
+ options.ExtractOptions.ElimDup.Val = !parser[NKey::kElimDup].WithMinus;
+ }
+
+ NWildcard::ECensorPathMode censorPathMode = NWildcard::k_RelatPath;
+ bool fullPathMode = parser[NKey::kFullPathMode].ThereIs;
+ if (fullPathMode)
+ {
+ censorPathMode = NWildcard::k_AbsPath;
+ const UString &s = parser[NKey::kFullPathMode].PostStrings[0];
+ if (!s.IsEmpty())
+ {
+ if (s == L"2")
+ censorPathMode = NWildcard::k_FullPath;
+ else
+ throw CArcCmdLineException("Unsupported -spf:", s);
+ }
+ }
+
+ if (parser[NKey::kNameTrailReplace].ThereIs)
+ g_PathTrailReplaceMode = !parser[NKey::kNameTrailReplace].WithMinus;
+
+ NRecursedType::EEnum recursedType;
+ if (parser[NKey::kRecursed].ThereIs)
+ recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex);
+ else
+ recursedType = NRecursedType::kNonRecursed;
+
+ bool wildcardMatching = true;
+ if (parser[NKey::kDisableWildcardParsing].ThereIs)
+ wildcardMatching = false;
+
+ g_CodePage = FindCharset(parser, NKey::kConsoleCharSet, true, -1);
+ Int32 codePage = FindCharset(parser, NKey::kListfileCharSet, false, CP_UTF8);
+
+ bool thereAreSwitchIncludes = false;
+
+ if (parser[NKey::kInclude].ThereIs)
+ {
+ thereAreSwitchIncludes = true;
+ AddSwitchWildcardsToCensor(options.Censor,
+ parser[NKey::kInclude].PostStrings, true, recursedType, wildcardMatching, codePage);
+ }
+
+ if (parser[NKey::kExclude].ThereIs)
+ AddSwitchWildcardsToCensor(options.Censor,
+ parser[NKey::kExclude].PostStrings, false, recursedType, wildcardMatching, codePage);
+
+ unsigned curCommandIndex = kCommandIndex + 1;
+ bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs &&
+ options.Command.CommandType != NCommandType::kBenchmark &&
+ options.Command.CommandType != NCommandType::kInfo &&
+ options.Command.CommandType != NCommandType::kHash;
+
+ bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
+ bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList;
+ bool isRename = options.Command.CommandType == NCommandType::kRename;
+
+ if ((isExtractOrList || isRename) && options.StdInMode)
+ thereIsArchiveName = false;
+
+ if (parser[NKey::kArcNameMode].ThereIs)
+ options.UpdateOptions.ArcNameMode = ParseArcNameMode(parser[NKey::kArcNameMode].PostCharIndex);
+
+ if (thereIsArchiveName)
+ {
+ if (curCommandIndex >= numNonSwitchStrings)
+ throw CArcCmdLineException("Cannot find archive name");
+ options.ArchiveName = nonSwitchStrings[curCommandIndex++];
+ if (options.ArchiveName.IsEmpty())
+ throw CArcCmdLineException("Archive name cannot by empty");
+ #ifdef _WIN32
+ // options.ArchiveName.Replace(L'/', WCHAR_PATH_SEPARATOR);
+ #endif
+ }
+
+ AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL,
+ curCommandIndex, options.Censor,
+ nonSwitchStrings, parser.StopSwitchIndex,
+ recursedType, wildcardMatching,
+ thereAreSwitchIncludes, codePage);
+
+ options.YesToAll = parser[NKey::kYes].ThereIs;
+
+
+ #ifndef _NO_CRYPTO
+ options.PasswordEnabled = parser[NKey::kPassword].ThereIs;
+ if (options.PasswordEnabled)
+ options.Password = parser[NKey::kPassword].PostStrings[0];
+ #endif
+
+ options.ShowDialog = parser[NKey::kShowDialog].ThereIs;
+
+ if (parser[NKey::kArchiveType].ThereIs)
+ options.ArcType = parser[NKey::kArchiveType].PostStrings[0];
+
+ options.ExcludedArcTypes = parser[NKey::kExcludedArcType].PostStrings;
+
+ SetMethodOptions(parser, options.Properties);
+
+ if (parser[NKey::kNtSecurity].ThereIs) options.NtSecurity.SetTrueTrue();
+
+ SetBoolPair(parser, NKey::kAltStreams, options.AltStreams);
+ SetBoolPair(parser, NKey::kHardLinks, options.HardLinks);
+ SetBoolPair(parser, NKey::kSymLinks, options.SymLinks);
+
+ if (isExtractOrList)
+ {
+ CExtractOptionsBase &eo = options.ExtractOptions;
+
+ {
+ CExtractNtOptions &nt = eo.NtOptions;
+ nt.NtSecurity = options.NtSecurity;
+
+ nt.AltStreams = options.AltStreams;
+ if (!options.AltStreams.Def)
+ nt.AltStreams.Val = true;
+
+ nt.HardLinks = options.HardLinks;
+ if (!options.HardLinks.Def)
+ nt.HardLinks.Val = true;
+
+ nt.SymLinks = options.SymLinks;
+ if (!options.SymLinks.Def)
+ nt.SymLinks.Val = true;
+
+ nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs;
+ nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs;
+ }
+
+ options.Censor.AddPathsToCensor(NWildcard::k_AbsPath);
+ options.Censor.ExtendExclude();
+
+ // are there paths that look as non-relative (!Prefix.IsEmpty())
+ if (!options.Censor.AllAreRelative())
+ throw CArcCmdLineException("Cannot use absolute pathnames for this command");
+
+ NWildcard::CCensor &arcCensor = options.arcCensor;
+
+ if (parser[NKey::kArInclude].ThereIs)
+ AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, true, NRecursedType::kNonRecursed, wildcardMatching, codePage);
+ if (parser[NKey::kArExclude].ThereIs)
+ AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, false, NRecursedType::kNonRecursed, wildcardMatching, codePage);
+
+ if (thereIsArchiveName)
+ AddNameToCensor(arcCensor, options.ArchiveName, true, NRecursedType::kNonRecursed, wildcardMatching);
+
+ arcCensor.AddPathsToCensor(NWildcard::k_RelatPath);
+
+ #ifdef _WIN32
+ ConvertToLongNames(arcCensor);
+ #endif
+
+ arcCensor.ExtendExclude();
+
+ if (options.StdInMode)
+ options.ArcName_for_StdInMode = parser[NKey::kStdIn].PostStrings.Front();
+
+ if (isExtractGroupCommand)
+ {
+ if (options.StdOutMode)
+ {
+ if (
+ options.Number_for_Percents == k_OutStream_stdout
+ // || options.Number_for_Out == k_OutStream_stdout
+ // || options.Number_for_Errors == k_OutStream_stdout
+ ||
+ (
+ (options.IsStdOutTerminal && options.IsStdErrTerminal)
+ &&
+ (
+ options.Number_for_Percents != k_OutStream_disabled
+ // || options.Number_for_Out != k_OutStream_disabled
+ // || options.Number_for_Errors != k_OutStream_disabled
+ )
+ )
+ )
+ throw CArcCmdLineException(kSameTerminalError);
+ }
+
+ if (parser[NKey::kOutputDir].ThereIs)
+ {
+ eo.OutputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]);
+ NFile::NName::NormalizeDirPathPrefix(eo.OutputDir);
+ }
+
+ eo.OverwriteMode = NExtract::NOverwriteMode::kAsk;
+ if (parser[NKey::kOverwrite].ThereIs)
+ {
+ eo.OverwriteMode = k_OverwriteModes[(unsigned)parser[NKey::kOverwrite].PostCharIndex];
+ eo.OverwriteMode_Force = true;
+ }
+ else if (options.YesToAll)
+ {
+ eo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite;
+ eo.OverwriteMode_Force = true;
+ }
+ }
+
+ eo.PathMode = options.Command.GetPathMode();
+ if (censorPathMode == NWildcard::k_AbsPath)
+ {
+ eo.PathMode = NExtract::NPathMode::kAbsPaths;
+ eo.PathMode_Force = true;
+ }
+ else if (censorPathMode == NWildcard::k_FullPath)
+ {
+ eo.PathMode = NExtract::NPathMode::kFullPaths;
+ eo.PathMode_Force = true;
+ }
+ }
+ else if (options.Command.IsFromUpdateGroup())
+ {
+ if (parser[NKey::kArInclude].ThereIs)
+ throw CArcCmdLineException("-ai switch is not supported for this command");
+
+ CUpdateOptions &updateOptions = options.UpdateOptions;
+
+ SetAddCommandOptions(options.Command.CommandType, parser, updateOptions);
+
+ updateOptions.MethodMode.Properties = options.Properties;
+
+ if (parser[NKey::kShareForWrite].ThereIs)
+ updateOptions.OpenShareForWrite = true;
+ if (parser[NKey::kStopAfterOpenError].ThereIs)
+ updateOptions.StopAfterOpenError = true;
+
+ updateOptions.PathMode = censorPathMode;
+
+ updateOptions.AltStreams = options.AltStreams;
+ updateOptions.NtSecurity = options.NtSecurity;
+ updateOptions.HardLinks = options.HardLinks;
+ updateOptions.SymLinks = options.SymLinks;
+
+ updateOptions.EMailMode = parser[NKey::kEmail].ThereIs;
+ if (updateOptions.EMailMode)
+ {
+ updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front();
+ if (updateOptions.EMailAddress.Len() > 0)
+ if (updateOptions.EMailAddress[0] == L'.')
+ {
+ updateOptions.EMailRemoveAfter = true;
+ updateOptions.EMailAddress.Delete(0);
+ }
+ }
+
+ updateOptions.StdOutMode = options.StdOutMode;
+ updateOptions.StdInMode = options.StdInMode;
+
+ updateOptions.DeleteAfterCompressing = parser[NKey::kDeleteAfterCompressing].ThereIs;
+ updateOptions.SetArcMTime = parser[NKey::kSetArcMTime].ThereIs;
+
+ if (updateOptions.StdOutMode && updateOptions.EMailMode)
+ throw CArcCmdLineException("stdout mode and email mode cannot be combined");
+
+ if (updateOptions.StdOutMode)
+ {
+ if (options.IsStdOutTerminal)
+ throw CArcCmdLineException(kTerminalOutError);
+
+ if (options.Number_for_Percents == k_OutStream_stdout
+ || options.Number_for_Out == k_OutStream_stdout
+ || options.Number_for_Errors == k_OutStream_stdout)
+ throw CArcCmdLineException(kSameTerminalError);
+ }
+
+ if (updateOptions.StdInMode)
+ updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front();
+
+ if (options.Command.CommandType == NCommandType::kRename)
+ if (updateOptions.Commands.Size() != 1)
+ throw CArcCmdLineException("Only one archive can be created with rename command");
+ }
+ else if (options.Command.CommandType == NCommandType::kBenchmark)
+ {
+ options.NumIterations = 1;
+ if (curCommandIndex < numNonSwitchStrings)
+ {
+ if (!StringToUInt32(nonSwitchStrings[curCommandIndex], options.NumIterations))
+ throw CArcCmdLineException("Incorrect Number of benmchmark iterations", nonSwitchStrings[curCommandIndex]);
+ curCommandIndex++;
+ }
+ }
+ else if (options.Command.CommandType == NCommandType::kHash)
+ {
+ options.Censor.AddPathsToCensor(censorPathMode);
+ options.Censor.ExtendExclude();
+
+ CHashOptions &hashOptions = options.HashOptions;
+ hashOptions.PathMode = censorPathMode;
+ hashOptions.Methods = options.HashMethods;
+ if (parser[NKey::kShareForWrite].ThereIs)
+ hashOptions.OpenShareForWrite = true;
+ hashOptions.StdInMode = options.StdInMode;
+ hashOptions.AltStreamsMode = options.AltStreams.Val;
+ }
+ else if (options.Command.CommandType == NCommandType::kInfo)
+ {
+ }
+ else
+ throw 20150919;
+}