blob: 89467723f14ce2bd2109d809bf1c860ce3dbac03 [file] [log] [blame]
// Main.cpp
#include "StdAfx.h"
#if defined( _WIN32) && defined( _7ZIP_LARGE_PAGES)
#include "../../../../C/Alloc.h"
#endif
#include "Common/MyInitGuid.h"
#include "Common/CommandLineParser.h"
#include "Common/IntToString.h"
#include "Common/MyException.h"
#include "Common/StdOutStream.h"
#include "Common/StringConvert.h"
#include "Common/StringToInt.h"
#include "Windows/Error.h"
#ifdef _WIN32
#include "Windows/MemoryLock.h"
#endif
#include "../Common/ArchiveCommandLine.h"
#include "../Common/ExitCode.h"
#include "../Common/Extract.h"
#ifdef EXTERNAL_CODECS
#include "../Common/LoadCodecs.h"
#endif
#include "BenchCon.h"
#include "ExtractCallbackConsole.h"
#include "List.h"
#include "OpenCallbackConsole.h"
#include "UpdateCallbackConsole.h"
#include "../../MyVersion.h"
using namespace NWindows;
using namespace NFile;
using namespace NCommandLineParser;
HINSTANCE g_hInstance = 0;
extern CStdOutStream *g_StdStream;
static const char *kCopyrightString = "\n7-Zip"
#ifndef EXTERNAL_CODECS
" (A)"
#endif
#ifdef _WIN64
" [64]"
#endif
" " MY_VERSION_COPYRIGHT_DATE "\n";
static const char *kHelpString =
"\nUsage: 7z"
#ifdef _NO_CRYPTO
"r"
#else
#ifndef EXTERNAL_CODECS
"a"
#endif
#endif
" <command> [<switches>...] <archive_name> [<file_names>...]\n"
" [<@listfiles...>]\n"
"\n"
"<Commands>\n"
" a: Add files to archive\n"
" b: Benchmark\n"
" d: Delete files from archive\n"
" e: Extract files from archive (without using directory names)\n"
" l: List contents of archive\n"
// " l[a|t][f]: List contents of archive\n"
// " a - with Additional fields\n"
// " t - with all fields\n"
// " f - with Full pathnames\n"
" t: Test integrity of archive\n"
" u: Update files to archive\n"
" x: eXtract files with full paths\n"
"<Switches>\n"
" -ai[r[-|0]]{@listfile|!wildcard}: Include archives\n"
" -ax[r[-|0]]{@listfile|!wildcard}: eXclude archives\n"
" -bd: Disable percentage indicator\n"
" -i[r[-|0]]{@listfile|!wildcard}: Include filenames\n"
" -m{Parameters}: set compression Method\n"
" -o{Directory}: set Output directory\n"
#ifndef _NO_CRYPTO
" -p{Password}: set Password\n"
#endif
" -r[-|0]: Recurse subdirectories\n"
" -scs{UTF-8 | WIN | DOS}: set charset for list files\n"
" -sfx[{name}]: Create SFX archive\n"
" -si[{name}]: read data from stdin\n"
" -slt: show technical information for l (List) command\n"
" -so: write data to stdout\n"
" -ssc[-]: set sensitive case mode\n"
" -ssw: compress shared files\n"
" -t{Type}: Set type of archive\n"
" -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName]: Update options\n"
" -v{Size}[b|k|m|g]: Create volumes\n"
" -w[{path}]: assign Work directory. Empty path means a temporary directory\n"
" -x[r[-|0]]]{@listfile|!wildcard}: eXclude filenames\n"
" -y: assume Yes on all queries\n";
// ---------------------------
// exception messages
static const char *kEverythingIsOk = "Everything is Ok";
static const char *kUserErrorMessage = "Incorrect command line";
static const char *kNoFormats = "7-Zip cannot find the code that works with archives.";
static const char *kUnsupportedArcTypeMessage = "Unsupported archive type";
static const wchar_t *kDefaultSfxModule = L"7zCon.sfx";
static void ShowMessageAndThrowException(CStdOutStream &s, LPCSTR message, NExitCode::EEnum code)
{
s << message << endl;
throw code;
}
static void PrintHelpAndExit(CStdOutStream &s)
{
s << kHelpString;
ShowMessageAndThrowException(s, kUserErrorMessage, NExitCode::kUserError);
}
#ifndef _WIN32
static void GetArguments(int numArgs, const char *args[], UStringVector &parts)
{
parts.Clear();
for (int i = 0; i < numArgs; i++)
{
UString s = MultiByteToUnicodeString(args[i]);
parts.Add(s);
}
}
#endif
static void ShowCopyrightAndHelp(CStdOutStream &s, bool needHelp)
{
s << kCopyrightString;
// s << "# CPUs: " << (UInt64)NWindows::NSystem::GetNumberOfProcessors() << "\n";
if (needHelp)
s << kHelpString;
}
#ifdef EXTERNAL_CODECS
static void PrintString(CStdOutStream &stdStream, const AString &s, int size)
{
int len = s.Length();
stdStream << s;
for (int i = len; i < size; i++)
stdStream << ' ';
}
#endif
static void PrintString(CStdOutStream &stdStream, const UString &s, int size)
{
int len = s.Length();
stdStream << s;
for (int i = len; i < size; i++)
stdStream << ' ';
}
static inline char GetHex(Byte value)
{
return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
}
int Main2(
#ifndef _WIN32
int numArgs, const char *args[]
#endif
)
{
#if defined(_WIN32) && !defined(UNDER_CE)
SetFileApisToOEM();
#endif
UStringVector commandStrings;
#ifdef _WIN32
NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
#else
GetArguments(numArgs, args, commandStrings);
#endif
if (commandStrings.Size() == 1)
{
ShowCopyrightAndHelp(g_StdOut, true);
return 0;
}
commandStrings.Delete(0);
CArchiveCommandLineOptions options;
CArchiveCommandLineParser parser;
parser.Parse1(commandStrings, options);
if (options.HelpMode)
{
ShowCopyrightAndHelp(g_StdOut, true);
return 0;
}
#if defined(_WIN32) && defined(_7ZIP_LARGE_PAGES)
if (options.LargePages)
{
SetLargePageSize();
NSecurity::EnableLockMemoryPrivilege();
}
#endif
CStdOutStream &stdStream = options.StdOutMode ? g_StdErr : g_StdOut;
g_StdStream = &stdStream;
if (options.EnableHeaders)
ShowCopyrightAndHelp(stdStream, false);
parser.Parse2(options);
CCodecs *codecs = new CCodecs;
CMyComPtr<
#ifdef EXTERNAL_CODECS
ICompressCodecsInfo
#else
IUnknown
#endif
> compressCodecsInfo = codecs;
HRESULT result = codecs->Load();
if (result != S_OK)
throw CSystemException(result);
bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
if (codecs->Formats.Size() == 0 &&
(isExtractGroupCommand ||
options.Command.CommandType == NCommandType::kList ||
options.Command.IsFromUpdateGroup()))
throw kNoFormats;
CIntVector formatIndices;
if (!codecs->FindFormatForArchiveType(options.ArcType, formatIndices))
throw kUnsupportedArcTypeMessage;
if (options.Command.CommandType == NCommandType::kInfo)
{
stdStream << endl << "Formats:" << endl;
int i;
for (i = 0; i < codecs->Formats.Size(); i++)
{
const CArcInfoEx &arc = codecs->Formats[i];
#ifdef EXTERNAL_CODECS
if (arc.LibIndex >= 0)
{
char s[16];
ConvertUInt32ToString(arc.LibIndex, s);
PrintString(stdStream, s, 2);
}
else
#endif
stdStream << " ";
stdStream << ' ';
stdStream << (char)(arc.UpdateEnabled ? 'C' : ' ');
stdStream << (char)(arc.KeepName ? 'K' : ' ');
stdStream << " ";
PrintString(stdStream, arc.Name, 6);
stdStream << " ";
UString s;
for (int t = 0; t < arc.Exts.Size(); t++)
{
const CArcExtInfo &ext = arc.Exts[t];
s += ext.Ext;
if (!ext.AddExt.IsEmpty())
{
s += L" (";
s += ext.AddExt;
s += L')';
}
s += L' ';
}
PrintString(stdStream, s, 14);
stdStream << " ";
const CByteBuffer &sig = arc.StartSignature;
for (size_t j = 0; j < sig.GetCapacity(); j++)
{
Byte b = sig[j];
if (b > 0x20 && b < 0x80)
{
stdStream << (char)b;
}
else
{
stdStream << GetHex((Byte)((b >> 4) & 0xF));
stdStream << GetHex((Byte)(b & 0xF));
}
stdStream << ' ';
}
stdStream << endl;
}
stdStream << endl << "Codecs:" << endl;
#ifdef EXTERNAL_CODECS
UInt32 numMethods;
if (codecs->GetNumberOfMethods(&numMethods) == S_OK)
for (UInt32 j = 0; j < numMethods; j++)
{
int libIndex = codecs->GetCodecLibIndex(j);
if (libIndex >= 0)
{
char s[16];
ConvertUInt32ToString(libIndex, s);
PrintString(stdStream, s, 2);
}
else
stdStream << " ";
stdStream << ' ';
stdStream << (char)(codecs->GetCodecEncoderIsAssigned(j) ? 'C' : ' ');
UInt64 id;
stdStream << " ";
HRESULT res = codecs->GetCodecId(j, id);
if (res != S_OK)
id = (UInt64)(Int64)-1;
char s[32];
ConvertUInt64ToString(id, s, 16);
PrintString(stdStream, s, 8);
stdStream << " ";
PrintString(stdStream, codecs->GetCodecName(j), 11);
stdStream << endl;
/*
if (res != S_OK)
throw "incorrect Codec ID";
*/
}
#endif
return S_OK;
}
else if (options.Command.CommandType == NCommandType::kBenchmark)
{
if (options.Method.CompareNoCase(L"CRC") == 0)
{
HRESULT res = CrcBenchCon((FILE *)stdStream, options.NumIterations, options.NumThreads, options.DictionarySize);
if (res != S_OK)
{
if (res == S_FALSE)
{
stdStream << "\nCRC Error\n";
return NExitCode::kFatalError;
}
throw CSystemException(res);
}
}
else
{
HRESULT res;
#ifdef EXTERNAL_CODECS
CObjectVector<CCodecInfoEx> externalCodecs;
res = LoadExternalCodecs(compressCodecsInfo, externalCodecs);
if (res != S_OK)
throw CSystemException(res);
#endif
res = LzmaBenchCon(
#ifdef EXTERNAL_CODECS
compressCodecsInfo, &externalCodecs,
#endif
(FILE *)stdStream, options.NumIterations, options.NumThreads, options.DictionarySize);
if (res != S_OK)
{
if (res == S_FALSE)
{
stdStream << "\nDecoding Error\n";
return NExitCode::kFatalError;
}
throw CSystemException(res);
}
}
}
else if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kList)
{
if (isExtractGroupCommand)
{
CExtractCallbackConsole *ecs = new CExtractCallbackConsole;
CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
ecs->OutStream = &stdStream;
#ifndef _NO_CRYPTO
ecs->PasswordIsDefined = options.PasswordEnabled;
ecs->Password = options.Password;
#endif
ecs->Init();
COpenCallbackConsole openCallback;
openCallback.OutStream = &stdStream;
#ifndef _NO_CRYPTO
openCallback.PasswordIsDefined = options.PasswordEnabled;
openCallback.Password = options.Password;
#endif
CExtractOptions eo;
eo.StdInMode = options.StdInMode;
eo.StdOutMode = options.StdOutMode;
eo.PathMode = options.Command.GetPathMode();
eo.TestMode = options.Command.IsTestMode();
eo.OverwriteMode = options.OverwriteMode;
eo.OutputDir = options.OutputDir;
eo.YesToAll = options.YesToAll;
eo.CalcCrc = options.CalcCrc;
#if !defined(_7ZIP_ST) && !defined(_SFX)
eo.Properties = options.ExtractProperties;
#endif
UString errorMessage;
CDecompressStat stat;
HRESULT result = DecompressArchives(
codecs,
formatIndices,
options.ArchivePathsSorted,
options.ArchivePathsFullSorted,
options.WildcardCensor.Pairs.Front().Head,
eo, &openCallback, ecs, errorMessage, stat);
if (!errorMessage.IsEmpty())
{
stdStream << endl << "Error: " << errorMessage;
if (result == S_OK)
result = E_FAIL;
}
stdStream << endl;
if (ecs->NumArchives > 1)
stdStream << "Archives: " << ecs->NumArchives << endl;
if (ecs->NumArchiveErrors != 0 || ecs->NumFileErrors != 0)
{
if (ecs->NumArchives > 1)
{
stdStream << endl;
if (ecs->NumArchiveErrors != 0)
stdStream << "Archive Errors: " << ecs->NumArchiveErrors << endl;
if (ecs->NumFileErrors != 0)
stdStream << "Sub items Errors: " << ecs->NumFileErrors << endl;
}
if (result != S_OK)
throw CSystemException(result);
return NExitCode::kFatalError;
}
if (result != S_OK)
throw CSystemException(result);
if (stat.NumFolders != 0)
stdStream << "Folders: " << stat.NumFolders << endl;
if (stat.NumFiles != 1 || stat.NumFolders != 0)
stdStream << "Files: " << stat.NumFiles << endl;
stdStream
<< "Size: " << stat.UnpackSize << endl
<< "Compressed: " << stat.PackSize << endl;
if (options.CalcCrc)
{
char s[16];
ConvertUInt32ToHexWithZeros(stat.CrcSum, s);
stdStream << "CRC: " << s << endl;
}
}
else
{
UInt64 numErrors = 0;
HRESULT result = ListArchives(
codecs,
formatIndices,
options.StdInMode,
options.ArchivePathsSorted,
options.ArchivePathsFullSorted,
options.WildcardCensor.Pairs.Front().Head,
options.EnableHeaders,
options.TechMode,
#ifndef _NO_CRYPTO
options.PasswordEnabled,
options.Password,
#endif
numErrors);
if (numErrors > 0)
{
g_StdOut << endl << "Errors: " << numErrors;
return NExitCode::kFatalError;
}
if (result != S_OK)
throw CSystemException(result);
}
}
else if (options.Command.IsFromUpdateGroup())
{
CUpdateOptions &uo = options.UpdateOptions;
if (uo.SfxMode && uo.SfxModule.IsEmpty())
uo.SfxModule = kDefaultSfxModule;
COpenCallbackConsole openCallback;
openCallback.OutStream = &stdStream;
#ifndef _NO_CRYPTO
bool passwordIsDefined =
options.PasswordEnabled && !options.Password.IsEmpty();
openCallback.PasswordIsDefined = passwordIsDefined;
openCallback.Password = options.Password;
#endif
CUpdateCallbackConsole callback;
callback.EnablePercents = options.EnablePercents;
#ifndef _NO_CRYPTO
callback.PasswordIsDefined = passwordIsDefined;
callback.AskPassword = options.PasswordEnabled && options.Password.IsEmpty();
callback.Password = options.Password;
#endif
callback.StdOutMode = uo.StdOutMode;
callback.Init(&stdStream);
CUpdateErrorInfo errorInfo;
if (!uo.Init(codecs, formatIndices, options.ArchiveName))
throw kUnsupportedArcTypeMessage;
HRESULT result = UpdateArchive(codecs,
options.WildcardCensor, uo,
errorInfo, &openCallback, &callback);
int exitCode = NExitCode::kSuccess;
if (callback.CantFindFiles.Size() > 0)
{
stdStream << endl;
stdStream << "WARNINGS for files:" << endl << endl;
int numErrors = callback.CantFindFiles.Size();
for (int i = 0; i < numErrors; i++)
{
stdStream << callback.CantFindFiles[i] << " : ";
stdStream << NError::MyFormatMessageW(callback.CantFindCodes[i]) << endl;
}
stdStream << "----------------" << endl;
stdStream << "WARNING: Cannot find " << numErrors << " file";
if (numErrors > 1)
stdStream << "s";
stdStream << endl;
exitCode = NExitCode::kWarning;
}
if (result != S_OK)
{
UString message;
if (!errorInfo.Message.IsEmpty())
{
message += errorInfo.Message;
message += L"\n";
}
if (!errorInfo.FileName.IsEmpty())
{
message += errorInfo.FileName;
message += L"\n";
}
if (!errorInfo.FileName2.IsEmpty())
{
message += errorInfo.FileName2;
message += L"\n";
}
if (errorInfo.SystemError != 0)
{
message += NError::MyFormatMessageW(errorInfo.SystemError);
message += L"\n";
}
if (!message.IsEmpty())
stdStream << L"\nError:\n" << message;
throw CSystemException(result);
}
int numErrors = callback.FailedFiles.Size();
if (numErrors == 0)
{
if (callback.CantFindFiles.Size() == 0)
stdStream << kEverythingIsOk << endl;
}
else
{
stdStream << endl;
stdStream << "WARNINGS for files:" << endl << endl;
for (int i = 0; i < numErrors; i++)
{
stdStream << callback.FailedFiles[i] << " : ";
stdStream << NError::MyFormatMessageW(callback.FailedCodes[i]) << endl;
}
stdStream << "----------------" << endl;
stdStream << "WARNING: Cannot open " << numErrors << " file";
if (numErrors > 1)
stdStream << "s";
stdStream << endl;
exitCode = NExitCode::kWarning;
}
return exitCode;
}
else
PrintHelpAndExit(stdStream);
return 0;
}