// 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 " [...] [...]\n" " [<@listfiles...>]\n" "\n" "\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" "\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 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 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; }