mirror of
https://github.com/holub/mame
synced 2025-06-24 05:17:04 +03:00
1701 lines
45 KiB
C++
1701 lines
45 KiB
C++
// 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 Z7_LARGE_PAGES
|
|
#include "../../../../C/Alloc.h"
|
|
#endif
|
|
|
|
#include "../../../Common/IntToString.h"
|
|
#include "../../../Common/ListFileUtils.h"
|
|
#include "../../../Common/StringConvert.h"
|
|
#include "../../../Common/StringToInt.h"
|
|
|
|
#include "../../../Windows/ErrorMsg.h"
|
|
#include "../../../Windows/FileDir.h"
|
|
#include "../../../Windows/FileName.h"
|
|
#include "../../../Windows/System.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;
|
|
|
|
#ifdef Z7_LARGE_PAGES
|
|
extern
|
|
bool g_LargePagesMode;
|
|
bool g_LargePagesMode = false;
|
|
#endif
|
|
|
|
/*
|
|
#ifdef ENV_HAVE_LSTAT
|
|
EXTERN_C_BEGIN
|
|
extern int global_use_lstat;
|
|
EXTERN_C_END
|
|
#endif
|
|
*/
|
|
|
|
#ifdef UNDER_CE
|
|
|
|
#define MY_IS_TERMINAL(x) false;
|
|
|
|
#else
|
|
|
|
// #define MY_isatty_fileno(x) (isatty(fileno(x)))
|
|
// #define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0);
|
|
static inline bool MY_IS_TERMINAL(FILE *x)
|
|
{
|
|
return (
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
|
_isatty(_fileno(x))
|
|
#else
|
|
isatty(fileno(x))
|
|
#endif
|
|
!= 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;
|
|
}
|
|
|
|
|
|
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,
|
|
// kHashGenFile,
|
|
kHashDir,
|
|
|
|
kStdIn,
|
|
kStdOut,
|
|
|
|
kLargePages,
|
|
kListfileCharSet,
|
|
kConsoleCharSet,
|
|
kTechMode,
|
|
kListFields,
|
|
|
|
kPreserveATime,
|
|
kShareForWrite,
|
|
kStopAfterOpenError,
|
|
kCaseSensitive,
|
|
kArcNameMode,
|
|
|
|
kUseSlashMark,
|
|
kDisableWildcardParsing,
|
|
kElimDup,
|
|
kFullPathMode,
|
|
|
|
kHardLinks,
|
|
kSymLinks_AllowDangerous,
|
|
kSymLinks,
|
|
kNtSecurity,
|
|
|
|
kStoreOwnerId,
|
|
kStoreOwnerName,
|
|
|
|
kZoneFile,
|
|
kAltStreams,
|
|
kReplaceColonForAltStream,
|
|
kWriteToAltStreamIfColon,
|
|
|
|
kNameTrailReplace,
|
|
|
|
kDeleteAfterCompressing,
|
|
kSetArcMTime
|
|
|
|
#ifndef Z7_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 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
|
|
#define kImmediateNameID '!'
|
|
#ifdef _WIN32
|
|
#define kMapNameID '#'
|
|
#endif
|
|
#define kFileListID '@'
|
|
|
|
static const Byte kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
|
|
static const Byte 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
|
|
};
|
|
|
|
|
|
|
|
#define SWFRM_3(t, mu, mi) t, mu, mi, NULL
|
|
|
|
#define SWFRM_1(t) SWFRM_3(t, false, 0)
|
|
#define SWFRM_SIMPLE SWFRM_1(NSwitchType::kSimple)
|
|
#define SWFRM_MINUS SWFRM_1(NSwitchType::kMinus)
|
|
#define SWFRM_STRING SWFRM_1(NSwitchType::kString)
|
|
|
|
#define SWFRM_STRING_SINGL(mi) SWFRM_3(NSwitchType::kString, false, mi)
|
|
#define SWFRM_STRING_MULT(mi) SWFRM_3(NSwitchType::kString, true, mi)
|
|
|
|
|
|
static const CSwitchForm kSwitchForms[] =
|
|
{
|
|
{ "?", SWFRM_SIMPLE },
|
|
{ "h", SWFRM_SIMPLE },
|
|
{ "-help", SWFRM_SIMPLE },
|
|
|
|
{ "ba", SWFRM_SIMPLE },
|
|
{ "bd", SWFRM_SIMPLE },
|
|
{ "bt", SWFRM_SIMPLE },
|
|
{ "bb", SWFRM_STRING_SINGL(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", SWFRM_SIMPLE },
|
|
|
|
{ "ad", SWFRM_SIMPLE },
|
|
{ "ao", NSwitchType::kChar, false, 1, kOverwritePostCharSet},
|
|
|
|
{ "t", SWFRM_STRING_SINGL(1) },
|
|
{ "stx", SWFRM_STRING_MULT(1) },
|
|
|
|
{ "m", SWFRM_STRING_MULT(1) },
|
|
{ "o", SWFRM_STRING_SINGL(1) },
|
|
{ "w", SWFRM_STRING },
|
|
|
|
{ "i", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
|
|
{ "x", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
|
|
{ "ai", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
|
|
{ "ax", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
|
|
{ "an", SWFRM_SIMPLE },
|
|
|
|
{ "u", SWFRM_STRING_MULT(1) },
|
|
{ "v", SWFRM_STRING_MULT(1) },
|
|
{ "r", NSwitchType::kChar, false, 0, kRecursedPostCharSet },
|
|
|
|
{ "stm", SWFRM_STRING },
|
|
{ "sfx", SWFRM_STRING },
|
|
{ "seml", SWFRM_STRING_SINGL(0) },
|
|
{ "scrc", SWFRM_STRING_MULT(0) },
|
|
// { "scrf", SWFRM_STRING_SINGL(1) },
|
|
{ "shd", SWFRM_STRING_SINGL(1) },
|
|
|
|
{ "si", SWFRM_STRING },
|
|
{ "so", SWFRM_SIMPLE },
|
|
|
|
{ "slp", SWFRM_STRING },
|
|
{ "scs", SWFRM_STRING },
|
|
{ "scc", SWFRM_STRING },
|
|
{ "slt", SWFRM_SIMPLE },
|
|
{ "slf", SWFRM_STRING_SINGL(1) },
|
|
|
|
{ "ssp", SWFRM_SIMPLE },
|
|
{ "ssw", SWFRM_SIMPLE },
|
|
{ "sse", SWFRM_SIMPLE },
|
|
{ "ssc", SWFRM_MINUS },
|
|
{ "sa", NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet },
|
|
|
|
{ "spm", SWFRM_STRING_SINGL(0) },
|
|
{ "spd", SWFRM_SIMPLE },
|
|
{ "spe", SWFRM_MINUS },
|
|
{ "spf", SWFRM_STRING_SINGL(0) },
|
|
|
|
{ "snh", SWFRM_MINUS },
|
|
{ "snld", SWFRM_MINUS },
|
|
{ "snl", SWFRM_MINUS },
|
|
{ "sni", SWFRM_SIMPLE },
|
|
|
|
{ "snoi", SWFRM_MINUS },
|
|
{ "snon", SWFRM_MINUS },
|
|
|
|
{ "snz", SWFRM_STRING_SINGL(0) },
|
|
{ "sns", SWFRM_MINUS },
|
|
{ "snr", SWFRM_SIMPLE },
|
|
{ "snc", SWFRM_SIMPLE },
|
|
|
|
{ "snt", SWFRM_MINUS },
|
|
|
|
{ "sdel", SWFRM_SIMPLE },
|
|
{ "stl", SWFRM_SIMPLE }
|
|
|
|
#ifndef Z7_NO_CRYPTO
|
|
, { "p", SWFRM_STRING }
|
|
#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 ((int)CommandType)
|
|
{
|
|
case NCommandType::kTest:
|
|
case NCommandType::kExtract:
|
|
case NCommandType::kExtractFull:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
NExtract::NPathMode::EEnum CArcCommand::GetPathMode() const
|
|
{
|
|
switch ((int)CommandType)
|
|
{
|
|
case NCommandType::kTest:
|
|
case NCommandType::kExtractFull:
|
|
return NExtract::NPathMode::kFullPaths;
|
|
default:
|
|
return NExtract::NPathMode::kNoPaths;
|
|
}
|
|
}
|
|
|
|
bool CArcCommand::IsFromUpdateGroup() const
|
|
{
|
|
switch ((int)CommandType)
|
|
{
|
|
case NCommandType::kAdd:
|
|
case NCommandType::kUpdate:
|
|
case NCommandType::kDelete:
|
|
case NCommandType::kRename:
|
|
return true;
|
|
default:
|
|
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
|
|
|
|
struct CNameOption
|
|
{
|
|
bool Include;
|
|
bool WildcardMatching;
|
|
Byte MarkMode;
|
|
NRecursedType::EEnum RecursedType;
|
|
|
|
CNameOption():
|
|
Include(true),
|
|
WildcardMatching(true),
|
|
MarkMode(NWildcard::kMark_FileOrDir),
|
|
RecursedType(NRecursedType::kNonRecursed)
|
|
{}
|
|
};
|
|
|
|
|
|
static void AddNameToCensor(NWildcard::CCensor &censor,
|
|
const CNameOption &nop, const UString &name)
|
|
{
|
|
bool recursed = false;
|
|
|
|
switch ((int)nop.RecursedType)
|
|
{
|
|
case NRecursedType::kWildcardOnlyRecursed:
|
|
recursed = DoesNameContainWildcard(name);
|
|
break;
|
|
case NRecursedType::kRecursed:
|
|
recursed = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
NWildcard::CCensorPathProps props;
|
|
props.Recursive = recursed;
|
|
props.WildcardMatching = nop.WildcardMatching;
|
|
props.MarkMode = nop.MarkMode;
|
|
censor.AddPreItem(nop.Include, name, props);
|
|
}
|
|
|
|
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,
|
|
const CNameOption &nop, LPCWSTR fileName, UInt32 codePage)
|
|
{
|
|
UStringVector names;
|
|
/*
|
|
if (!NFind::DoesFileExist_FollowLink(us2fs(fileName)))
|
|
throw CArcCmdLineException(kCannotFindListFile, fileName);
|
|
*/
|
|
DWORD lastError = 0;
|
|
if (!ReadNamesFromListFile2(us2fs(fileName), names, codePage, lastError))
|
|
{
|
|
if (lastError != 0)
|
|
{
|
|
UString m;
|
|
m = "The file operation error for listfile";
|
|
m.Add_LF();
|
|
m += NError::MyFormatMessage(lastError);
|
|
throw CArcCmdLineException(m, fileName);
|
|
}
|
|
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], nop.RecursedType, nop.WildcardMatching);
|
|
}
|
|
}
|
|
else
|
|
FOR_VECTOR (i, names)
|
|
AddNameToCensor(censor, nop, names[i]);
|
|
}
|
|
|
|
static void AddToCensorFromNonSwitchesStrings(
|
|
CObjectVector<CRenamePair> *renamePairs,
|
|
unsigned startIndex,
|
|
NWildcard::CCensor &censor,
|
|
const UStringVector &nonSwitchStrings,
|
|
int stopSwitchIndex,
|
|
const CNameOption &nop,
|
|
bool thereAreSwitchIncludes, UInt32 codePage)
|
|
{
|
|
// another default
|
|
if ((renamePairs || nonSwitchStrings.Size() == startIndex) && !thereAreSwitchIncludes)
|
|
{
|
|
/* for rename command: -i switch sets the mask for archive item reading.
|
|
if (thereAreSwitchIncludes), { we don't use UniversalWildcard. }
|
|
also for non-rename command: we set UniversalWildcard, only if there are no nonSwitches. */
|
|
// we use default fileds in (CNameOption) for UniversalWildcard.
|
|
CNameOption nop2;
|
|
// recursive mode is not important for UniversalWildcard (*)
|
|
// nop2.RecursedType = nop.RecursedType; // we don't need it
|
|
/*
|
|
nop2.RecursedType = NRecursedType::kNonRecursed;
|
|
nop2.Include = true;
|
|
nop2.WildcardMatching = true;
|
|
nop2.MarkMode = NWildcard::kMark_FileOrDir;
|
|
*/
|
|
AddNameToCensor(censor, nop2, UString(kUniversalWildcard));
|
|
}
|
|
|
|
int oldIndex = -1;
|
|
|
|
if (stopSwitchIndex < 0)
|
|
stopSwitchIndex = (int)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, nop, s.Ptr(1), codePage);
|
|
else if (renamePairs)
|
|
{
|
|
if (oldIndex == -1)
|
|
oldIndex = (int)i;
|
|
else
|
|
{
|
|
// NRecursedType::EEnum type is used for global wildcard (-i! switches)
|
|
AddRenamePair(renamePairs, nonSwitchStrings[(unsigned)oldIndex], s, NRecursedType::kNonRecursed, nop.WildcardMatching);
|
|
// AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, type);
|
|
oldIndex = -1;
|
|
}
|
|
}
|
|
else
|
|
AddNameToCensor(censor, nop, s);
|
|
}
|
|
|
|
if (oldIndex != -1)
|
|
{
|
|
throw CArcCmdLineException("There is no second file name for rename pair:", nonSwitchStrings[(unsigned)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,
|
|
const CNameOption &nop)
|
|
{
|
|
UString s (s2);
|
|
int pos = s.Find(L':');
|
|
if (pos < 0)
|
|
return k_IncorrectMapCommand;
|
|
int pos2 = s.Find(L':', (unsigned)(pos + 1));
|
|
if (pos2 < 0)
|
|
return k_IncorrectMapCommand;
|
|
|
|
CEventSetEnd eventSetEnd((const wchar_t *)s + (unsigned)(pos2 + 1));
|
|
s.DeleteFrom((unsigned)pos2);
|
|
UInt32 size;
|
|
if (!StringToUInt32(s.Ptr((unsigned)(pos + 1)), size)
|
|
|| size < sizeof(wchar_t)
|
|
|| size > ((UInt32)1 << 31)
|
|
|| size % sizeof(wchar_t) != 0)
|
|
return "Unsupported Map data size";
|
|
|
|
s.DeleteFrom((unsigned)pos);
|
|
CFileMapping map;
|
|
if (map.Open(FILE_MAP_READ, GetSystemString(s)) != 0)
|
|
return "Cannot 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, nop, name);
|
|
name.Empty();
|
|
}
|
|
else
|
|
name += c;
|
|
}
|
|
if (!name.IsEmpty())
|
|
return "Map data error";
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#endif
|
|
|
|
static void AddSwitchWildcardsToCensor(
|
|
NWildcard::CCensor &censor,
|
|
const UStringVector &strings,
|
|
const CNameOption &nop,
|
|
UInt32 codePage)
|
|
{
|
|
const char *errorMessage = NULL;
|
|
unsigned i;
|
|
for (i = 0; i < strings.Size(); i++)
|
|
{
|
|
const UString &name = strings[i];
|
|
unsigned pos = 0;
|
|
|
|
if (name.Len() < kSomeCludePostStringMinSize)
|
|
{
|
|
errorMessage = "Too short switch";
|
|
break;
|
|
}
|
|
|
|
if (!nop.Include)
|
|
{
|
|
if (name.IsEqualTo_Ascii_NoCase("td"))
|
|
{
|
|
censor.ExcludeDirItems = true;
|
|
continue;
|
|
}
|
|
if (name.IsEqualTo_Ascii_NoCase("tf"))
|
|
{
|
|
censor.ExcludeFileItems = true;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
CNameOption nop2 = nop;
|
|
|
|
bool type_WasUsed = false;
|
|
bool recursed_WasUsed = false;
|
|
bool matching_WasUsed = false;
|
|
bool error = false;
|
|
|
|
for (;;)
|
|
{
|
|
wchar_t c = ::MyCharLower_Ascii(name[pos]);
|
|
if (c == kRecursedIDChar)
|
|
{
|
|
if (recursed_WasUsed)
|
|
{
|
|
error = true;
|
|
break;
|
|
}
|
|
recursed_WasUsed = true;
|
|
pos++;
|
|
c = name[pos];
|
|
int index = -1;
|
|
if (c <= 0x7F)
|
|
index = FindCharPosInString(kRecursedPostCharSet, (char)c);
|
|
nop2.RecursedType = GetRecursedTypeFromIndex(index);
|
|
if (index >= 0)
|
|
{
|
|
pos++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (c == 'w')
|
|
{
|
|
if (matching_WasUsed)
|
|
{
|
|
error = true;
|
|
break;
|
|
}
|
|
matching_WasUsed = true;
|
|
nop2.WildcardMatching = true;
|
|
pos++;
|
|
if (name[pos] == '-')
|
|
{
|
|
nop2.WildcardMatching = false;
|
|
pos++;
|
|
}
|
|
}
|
|
else if (c == 'm')
|
|
{
|
|
if (type_WasUsed)
|
|
{
|
|
error = true;
|
|
break;
|
|
}
|
|
type_WasUsed = true;
|
|
pos++;
|
|
nop2.MarkMode = NWildcard::kMark_StrictFile;
|
|
c = name[pos];
|
|
if (c == '-')
|
|
{
|
|
nop2.MarkMode = NWildcard::kMark_FileOrDir;
|
|
pos++;
|
|
}
|
|
else if (c == '2')
|
|
{
|
|
nop2.MarkMode = NWildcard::kMark_StrictFile_IfWildcard;
|
|
pos++;
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (error)
|
|
{
|
|
errorMessage = "inorrect switch";
|
|
break;
|
|
}
|
|
|
|
if (name.Len() < pos + kSomeCludeAfterRecursedPostStringMinSize)
|
|
{
|
|
errorMessage = "Too short switch";
|
|
break;
|
|
}
|
|
|
|
const UString tail = name.Ptr(pos + 1);
|
|
|
|
const wchar_t c = name[pos];
|
|
|
|
if (c == kImmediateNameID)
|
|
AddNameToCensor(censor, nop2, tail);
|
|
else if (c == kFileListID)
|
|
AddToCensorFromListFile(NULL, censor, nop2, tail, codePage);
|
|
#ifdef _WIN32
|
|
else if (c == kMapNameID)
|
|
{
|
|
errorMessage = ParseMapWithPaths(censor, tail, nop2);
|
|
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 >= (wchar_t)('0' + kNumUpdatePairActions))
|
|
return false;
|
|
unsigned actionPos = (unsigned)(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 ((int)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))
|
|
throw CArcCmdLineException("Incorrect volume size:", sv[i]);
|
|
if (i == sv.Size() - 1 && size == 0)
|
|
throw CArcCmdLineException("zero size last volume is not allowed");
|
|
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((unsigned)(index + 1));
|
|
prop.Name.DeleteFrom((unsigned)index);
|
|
}
|
|
properties.Add(prop);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static inline void SetStreamMode(const CSwitchResult &sw, unsigned &res)
|
|
{
|
|
if (sw.ThereIs)
|
|
res = (unsigned)sw.PostCharIndex;
|
|
}
|
|
|
|
|
|
#if defined(_WIN32) && !defined(UNDER_CE)
|
|
static void PrintHex(UString &s, UInt64 v)
|
|
{
|
|
char temp[32];
|
|
ConvertUInt64ToHex(v, temp);
|
|
s += temp;
|
|
}
|
|
#endif
|
|
|
|
|
|
void CArcCmdLineParser::Parse1(const UStringVector &commandStrings,
|
|
CArcCmdLineOptions &options)
|
|
{
|
|
Parse1Log.Empty();
|
|
if (!parser.ParseStrings(kSwitchForms, Z7_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;
|
|
if (parser[NKey::kListFields].ThereIs)
|
|
{
|
|
const UString &s = parser[NKey::kListFields].PostStrings[0];
|
|
options.ListFields = GetAnsiString(s);
|
|
}
|
|
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)
|
|
{
|
|
options.CaseSensitive =
|
|
g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus;
|
|
options.CaseSensitive_Change = true;
|
|
}
|
|
|
|
|
|
#if defined(_WIN32) && !defined(UNDER_CE)
|
|
NSecurity::EnablePrivilege_SymLink();
|
|
#endif
|
|
|
|
// options.LargePages = false;
|
|
|
|
if (parser[NKey::kLargePages].ThereIs)
|
|
{
|
|
UInt32 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 Z7_LARGE_PAGES
|
|
if (slp >
|
|
#if defined(_WIN32) && !defined(UNDER_CE)
|
|
(unsigned)NSecurity::Get_LargePages_RiskLevel()
|
|
#else
|
|
0
|
|
#endif
|
|
)
|
|
{
|
|
#ifdef _WIN32 // change it !
|
|
SetLargePageSize();
|
|
#endif
|
|
// 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())
|
|
{
|
|
AString a;
|
|
a.SetFromWStr_if_Ascii(s);
|
|
Parse1Log += "Set process affinity mask: ";
|
|
|
|
#ifdef _WIN32
|
|
|
|
UInt64 v = 0;
|
|
{
|
|
const char *end;
|
|
v = ConvertHexStringToUInt64(a, &end);
|
|
if (*end != 0)
|
|
a.Empty();
|
|
}
|
|
if (a.IsEmpty())
|
|
throw CArcCmdLineException("Unsupported switch postfix -stm", s);
|
|
|
|
{
|
|
#ifndef _WIN64
|
|
if (v >= ((UInt64)1 << 32))
|
|
throw CArcCmdLineException("unsupported value -stm", s);
|
|
#endif
|
|
{
|
|
PrintHex(Parse1Log, v);
|
|
if (!SetProcessAffinityMask(GetCurrentProcess(), (DWORD_PTR)v))
|
|
{
|
|
DWORD lastError = GetLastError();
|
|
Parse1Log += " : ERROR : ";
|
|
Parse1Log += NError::MyFormatMessage(lastError);
|
|
}
|
|
}
|
|
}
|
|
|
|
#else // _WIN32
|
|
|
|
{
|
|
Parse1Log += a;
|
|
NSystem::CProcessAffinity aff;
|
|
aff.CpuZero();
|
|
for (unsigned i = 0; i < a.Len(); i++)
|
|
{
|
|
char c = a[i];
|
|
unsigned v;
|
|
if (c >= '0' && c <= '9') v = (unsigned)(c - '0');
|
|
else if (c >= 'A' && c <= 'F') v = 10 + (unsigned)(c - 'A');
|
|
else if (c >= 'a' && c <= 'f') v = 10 + (unsigned)(c - 'a');
|
|
else
|
|
throw CArcCmdLineException("Unsupported switch postfix -stm", s);
|
|
for (unsigned k = 0; k < 4; k++)
|
|
{
|
|
const unsigned cpu = (a.Len() - 1 - i) * 4 + k;
|
|
if (v & ((unsigned)1 << k))
|
|
aff.CpuSet(cpu);
|
|
}
|
|
}
|
|
|
|
if (!aff.SetProcAffinity())
|
|
{
|
|
DWORD lastError = GetLastError();
|
|
Parse1Log += " : ERROR : ";
|
|
Parse1Log += NError::MyFormatMessage(lastError);
|
|
}
|
|
}
|
|
#endif // _WIN32
|
|
|
|
Parse1Log.Add_LF();
|
|
}
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
struct CCodePagePair
|
|
{
|
|
const char *Name;
|
|
UInt32 CodePage;
|
|
};
|
|
|
|
static const unsigned kNumByteOnlyCodePages = 3;
|
|
|
|
static const CCodePagePair g_CodePagePairs[] =
|
|
{
|
|
{ "utf-8", CP_UTF8 },
|
|
{ "win", CP_ACP },
|
|
{ "dos", CP_OEMCP },
|
|
{ "utf-16le", Z7_WIN_CP_UTF16 },
|
|
{ "utf-16be", Z7_WIN_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();
|
|
const unsigned num = byteOnlyCodePages ? kNumByteOnlyCodePages : Z7_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 (Int32)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::kHashGenFile].ThereIs)
|
|
{
|
|
const UString &s = parser[NKey::kHashGenFile].PostStrings[0];
|
|
for (unsigned i = 0 ; i < s.Len();)
|
|
{
|
|
const wchar_t c = s[i++];
|
|
if (!options.HashOptions.ParseFlagCharOption(c, true))
|
|
{
|
|
if (c != '=')
|
|
throw CArcCmdLineException("Unsupported hash mode switch:", s);
|
|
options.HashOptions.HashFilePath = s.Ptr(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
if (parser[NKey::kHashDir].ThereIs)
|
|
options.ExtractOptions.HashDir = parser[NKey::kHashDir].PostStrings[0];
|
|
|
|
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;
|
|
|
|
CNameOption nop;
|
|
|
|
if (parser[NKey::kRecursed].ThereIs)
|
|
nop.RecursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex);
|
|
|
|
if (parser[NKey::kDisableWildcardParsing].ThereIs)
|
|
nop.WildcardMatching = false;
|
|
|
|
if (parser[NKey::kUseSlashMark].ThereIs)
|
|
{
|
|
const UString &s = parser[NKey::kUseSlashMark].PostStrings[0];
|
|
if (s.IsEmpty())
|
|
nop.MarkMode = NWildcard::kMark_StrictFile;
|
|
else if (s.IsEqualTo_Ascii_NoCase("-"))
|
|
nop.MarkMode = NWildcard::kMark_FileOrDir;
|
|
else if (s.IsEqualTo_Ascii_NoCase("2"))
|
|
nop.MarkMode = NWildcard::kMark_StrictFile_IfWildcard;
|
|
else
|
|
throw CArcCmdLineException("Unsupported -spm:", s);
|
|
}
|
|
|
|
|
|
options.ConsoleCodePage = FindCharset(parser, NKey::kConsoleCharSet, true, -1);
|
|
|
|
UInt32 codePage = (UInt32)FindCharset(parser, NKey::kListfileCharSet, false, CP_UTF8);
|
|
|
|
bool thereAreSwitchIncludes = false;
|
|
|
|
if (parser[NKey::kInclude].ThereIs)
|
|
{
|
|
thereAreSwitchIncludes = true;
|
|
nop.Include = true;
|
|
AddSwitchWildcardsToCensor(options.Censor,
|
|
parser[NKey::kInclude].PostStrings, nop, codePage);
|
|
}
|
|
|
|
if (parser[NKey::kExclude].ThereIs)
|
|
{
|
|
nop.Include = false;
|
|
AddSwitchWildcardsToCensor(options.Censor,
|
|
parser[NKey::kExclude].PostStrings, nop, 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;
|
|
|
|
const bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
|
|
const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList;
|
|
const 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
|
|
}
|
|
|
|
nop.Include = true;
|
|
AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL,
|
|
curCommandIndex, options.Censor,
|
|
nonSwitchStrings, parser.StopSwitchIndex,
|
|
nop,
|
|
thereAreSwitchIncludes, codePage);
|
|
|
|
options.YesToAll = parser[NKey::kYes].ThereIs;
|
|
|
|
|
|
#ifndef Z7_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);
|
|
|
|
SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId);
|
|
SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName);
|
|
|
|
CBoolPair symLinks_AllowDangerous;
|
|
SetBoolPair(parser, NKey::kSymLinks_AllowDangerous, symLinks_AllowDangerous);
|
|
|
|
|
|
/*
|
|
bool supportSymLink = options.SymLinks.Val;
|
|
|
|
if (!options.SymLinks.Def)
|
|
{
|
|
if (isExtractOrList)
|
|
supportSymLink = true;
|
|
else
|
|
supportSymLink = false;
|
|
}
|
|
|
|
#ifdef ENV_HAVE_LSTAT
|
|
if (supportSymLink)
|
|
global_use_lstat = 1;
|
|
else
|
|
global_use_lstat = 0;
|
|
#endif
|
|
*/
|
|
|
|
|
|
if (isExtractOrList)
|
|
{
|
|
CExtractOptionsBase &eo = options.ExtractOptions;
|
|
|
|
eo.ExcludeDirItems = options.Censor.ExcludeDirItems;
|
|
eo.ExcludeFileItems = options.Censor.ExcludeFileItems;
|
|
|
|
{
|
|
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.SymLinks_AllowDangerous = symLinks_AllowDangerous;
|
|
|
|
nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs;
|
|
nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs;
|
|
|
|
nt.ExtractOwner = options.StoreOwnerId.Val; // StoreOwnerName
|
|
|
|
if (parser[NKey::kPreserveATime].ThereIs)
|
|
nt.PreserveATime = true;
|
|
if (parser[NKey::kShareForWrite].ThereIs)
|
|
nt.OpenShareForWrite = true;
|
|
}
|
|
|
|
if (parser[NKey::kZoneFile].ThereIs)
|
|
{
|
|
eo.ZoneMode = NExtract::NZoneIdMode::kAll;
|
|
const UString &s = parser[NKey::kZoneFile].PostStrings[0];
|
|
if (!s.IsEmpty())
|
|
{
|
|
if (s == L"0") eo.ZoneMode = NExtract::NZoneIdMode::kNone;
|
|
else if (s == L"1") eo.ZoneMode = NExtract::NZoneIdMode::kAll;
|
|
else if (s == L"2") eo.ZoneMode = NExtract::NZoneIdMode::kOffice;
|
|
else
|
|
throw CArcCmdLineException("Unsupported -snz:", s);
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
CNameOption nopArc;
|
|
// nopArc.RecursedType = NRecursedType::kNonRecursed; // default: we don't want recursing for archives, if -r specified
|
|
// is it OK, external switches can disable WildcardMatching and MarcMode for arc.
|
|
nopArc.WildcardMatching = nop.WildcardMatching;
|
|
nopArc.MarkMode = nop.MarkMode;
|
|
|
|
if (parser[NKey::kArInclude].ThereIs)
|
|
{
|
|
nopArc.Include = true;
|
|
AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, nopArc, codePage);
|
|
}
|
|
if (parser[NKey::kArExclude].ThereIs)
|
|
{
|
|
nopArc.Include = false;
|
|
AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, nopArc, codePage);
|
|
}
|
|
|
|
if (thereIsArchiveName)
|
|
{
|
|
nopArc.Include = true;
|
|
AddNameToCensor(arcCensor, nopArc, options.ArchiveName);
|
|
}
|
|
|
|
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]);
|
|
#ifdef _WIN32
|
|
NFile::NName::NormalizeDirSeparators(eo.OutputDir);
|
|
#endif
|
|
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::kPreserveATime].ThereIs)
|
|
updateOptions.PreserveATime = true;
|
|
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.StoreOwnerId = options.StoreOwnerId;
|
|
updateOptions.StoreOwnerName = options.StoreOwnerName;
|
|
|
|
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;
|
|
options.NumIterations_Defined = false;
|
|
if (curCommandIndex < numNonSwitchStrings)
|
|
{
|
|
if (!StringToUInt32(nonSwitchStrings[curCommandIndex], options.NumIterations))
|
|
throw CArcCmdLineException("Incorrect number of benchmark iterations", nonSwitchStrings[curCommandIndex]);
|
|
curCommandIndex++;
|
|
options.NumIterations_Defined = true;
|
|
}
|
|
}
|
|
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;
|
|
// hashOptions.HashFilePath = options.HashFilePath;
|
|
if (parser[NKey::kPreserveATime].ThereIs)
|
|
hashOptions.PreserveATime = true;
|
|
if (parser[NKey::kShareForWrite].ThereIs)
|
|
hashOptions.OpenShareForWrite = true;
|
|
hashOptions.StdInMode = options.StdInMode;
|
|
hashOptions.AltStreamsMode = options.AltStreams.Val;
|
|
hashOptions.SymLinks = options.SymLinks;
|
|
}
|
|
else if (options.Command.CommandType == NCommandType::kInfo)
|
|
{
|
|
}
|
|
else
|
|
throw 20150919;
|
|
}
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
static AString g_ModuleDirPrefix;
|
|
|
|
void Set_ModuleDirPrefix_From_ProgArg0(const char *s);
|
|
void Set_ModuleDirPrefix_From_ProgArg0(const char *s)
|
|
{
|
|
AString a (s);
|
|
int sep = a.ReverseFind_PathSepar();
|
|
a.DeleteFrom((unsigned)(sep + 1));
|
|
g_ModuleDirPrefix = a;
|
|
}
|
|
|
|
namespace NWindows {
|
|
namespace NDLL {
|
|
|
|
FString GetModuleDirPrefix();
|
|
FString GetModuleDirPrefix()
|
|
{
|
|
FString s;
|
|
|
|
s = fas2fs(g_ModuleDirPrefix);
|
|
if (s.IsEmpty())
|
|
s = FTEXT(".") FSTRING_PATH_SEPARATOR;
|
|
return s;
|
|
/*
|
|
setenv("_7ZIP_HOME_DIR", "/test/", 0);
|
|
const char *home = getenv("_7ZIP_HOME_DIR");
|
|
if (home)
|
|
s = home;
|
|
else
|
|
s = FTEXT(".") FSTRING_PATH_SEPARATOR;
|
|
return s;
|
|
*/
|
|
}
|
|
|
|
}}
|
|
|
|
#endif // ! _WIN32
|