// Main.cpp #include "StdAfx.h" #include #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/StringConvert.h" #include "../../../Common/StringToInt.h" #include "../../../Windows/ErrorMsg.h" #ifdef _WIN32 #include "../../../Windows/MemoryLock.h" #endif #ifndef _7ZIP_ST #include "../../../Windows/Synchronization.h" #endif #include "../../../Windows/TimeUtils.h" #include "../Common/ArchiveCommandLine.h" #include "../Common/ExitCode.h" #include "../Common/Extract.h" #ifdef EXTERNAL_CODECS #include "../Common/LoadCodecs.h" #endif #include "BenchCon.h" #include "ConsoleClose.h" #include "ExtractCallbackConsole.h" #include "List.h" #include "OpenCallbackConsole.h" #include "UpdateCallbackConsole.h" #include "HashCon.h" #ifdef PROG_VARIANT_R #include "../../../../C/7zVersion.h" #else #include "../../MyVersion.h" #endif using namespace NWindows; using namespace NFile; using namespace NCommandLineParser; #ifdef _WIN32 HINSTANCE g_hInstance = 0; #endif extern CStdOutStream *g_StdStream; static const char *kCopyrightString = "\n7-Zip" #ifndef EXTERNAL_CODECS #ifdef PROG_VARIANT_R " (r)" #else " (a)" #endif #endif #ifdef _WIN64 " [64]" #endif " " MY_VERSION_COPYRIGHT_DATE "\n"; static const char *kHelpString = "\nUsage: 7z" #ifndef EXTERNAL_CODECS #ifdef PROG_VARIANT_R "r" #else "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" " h : Calculate hash values for files\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" " rn : Rename files in archive\n" " t : Test integrity of archive\n" " u : Update files to archive\n" " x : eXtract files with full paths\n" "\n" " -- : Stop switches parsing\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|UTF-16LE|UTF-16BE|WIN|DOS|{id}} : 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 char *kUnsupportedUpdateArcType = "Can't create archive for that type"; static CFSTR kDefaultSfxModule = FTEXT("7zCon.sfx"); static void ShowMessageAndThrowException(CStdOutStream &s, LPCSTR message, NExitCode::EEnum code) { s << endl << "Error: " << message << endl; throw code; } #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.Len(); for (int i = len; i < size; i++) stdStream << ' '; stdStream << s; } static void PrintUInt32(CStdOutStream &stdStream, UInt32 val, int size) { char s[16]; ConvertUInt32ToString(val, s); PrintString(stdStream, s, size); } static void PrintLibIndex(CStdOutStream &stdStream, int libIndex) { if (libIndex >= 0) PrintUInt32(stdStream, libIndex, 2); else stdStream << " "; stdStream << ' '; } #endif static void PrintString(CStdOutStream &stdStream, const UString &s, int size) { int len = s.Len(); stdStream << s; for (int i = len; i < size; i++) stdStream << ' '; } static inline char GetHex(unsigned val) { return (char)((val < 10) ? ('0' + val) : ('A' + (val - 10))); } static int WarningsCheck(HRESULT result, const CCallbackConsoleBase &callback, const CErrorInfo &errorInfo, CStdOutStream &stdStream) { int exitCode = NExitCode::kSuccess; if (callback.CantFindFiles.Size() > 0) { stdStream << endl; stdStream << "WARNINGS for files:" << endl << endl; unsigned numErrors = callback.CantFindFiles.Size(); for (unsigned i = 0; i < numErrors; i++) { stdStream << callback.CantFindFiles[i] << " : "; stdStream << NError::MyFormatMessage(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 += fs2us(errorInfo.FileName); message += L"\n"; } if (!errorInfo.FileName2.IsEmpty()) { message += fs2us(errorInfo.FileName2); message += L"\n"; } if (errorInfo.SystemError != 0) { message += NError::MyFormatMessage(errorInfo.SystemError); message += L"\n"; } if (!message.IsEmpty()) stdStream << L"\nError:\n" << message; // we will work with (result) later // throw CSystemException(result); return NExitCode::kFatalError; } unsigned 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 (unsigned i = 0; i < numErrors; i++) { stdStream << callback.FailedFiles[i] << " : "; stdStream << NError::MyFormatMessage(callback.FailedCodes[i]) << endl; } stdStream << "----------------" << endl; stdStream << "WARNING: Cannot open " << numErrors << " file"; if (numErrors > 1) stdStream << "s"; stdStream << endl; exitCode = NExitCode::kWarning; } return exitCode; } static void ThrowException_if_Error(HRESULT res) { if (res != S_OK) throw CSystemException(res); } static void PrintNum(UInt64 val, unsigned numDigits, char c = ' ') { char temp[64]; char *p = temp + 32; ConvertUInt64ToString(val, p); unsigned len = MyStringLen(p); for (; len < numDigits; len++) *--p = c; *g_StdStream << p; } static void PrintTime(const char *s, UInt64 val, UInt64 total) { *g_StdStream << endl << s << " Time ="; const UInt32 kFreq = 10000000; UInt64 sec = val / kFreq; PrintNum(sec, 6); *g_StdStream << '.'; UInt32 ms = (UInt32)(val - (sec * kFreq)) / (kFreq / 1000); PrintNum(ms, 3, '0'); while (val > ((UInt64)1 << 56)) { val >>= 1; total >>= 1; } UInt64 percent = 0; if (total != 0) percent = val * 100 / total; *g_StdStream << " ="; PrintNum(percent, 5); *g_StdStream << '%'; } #ifndef UNDER_CE #define SHIFT_SIZE_VALUE(x, num) (((x) + (1 << (num)) - 1) >> (num)) static void PrintMemUsage(const char *s, UInt64 val) { *g_StdStream << " " << s << " Memory ="; PrintNum(SHIFT_SIZE_VALUE(val, 20), 7); *g_StdStream << " MB"; } EXTERN_C_BEGIN typedef BOOL (WINAPI *Func_GetProcessMemoryInfo)(HANDLE Process, PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb); EXTERN_C_END #endif static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; } static void PrintStat() { FILETIME creationTimeFT, exitTimeFT, kernelTimeFT, userTimeFT; if (! #ifdef UNDER_CE ::GetThreadTimes(::GetCurrentThread() #else // NT 3.5 ::GetProcessTimes(::GetCurrentProcess() #endif , &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT)) return; FILETIME curTimeFT; NTime::GetCurUtcFileTime(curTimeFT); #ifndef UNDER_CE PROCESS_MEMORY_COUNTERS m; memset(&m, 0, sizeof(m)); BOOL memDefined = FALSE; { /* NT 4.0: GetProcessMemoryInfo() in Psapi.dll Win7: new function K32GetProcessMemoryInfo() in kernel32.dll It's faster to call kernel32.dll code than Psapi.dll code GetProcessMemoryInfo() requires Psapi.lib Psapi.lib in SDK7+ can link to K32GetProcessMemoryInfo in kernel32.dll The program with K32GetProcessMemoryInfo will not work on systems before Win7 // memDefined = GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m)); */ Func_GetProcessMemoryInfo my_GetProcessMemoryInfo = (Func_GetProcessMemoryInfo) ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "K32GetProcessMemoryInfo"); if (!my_GetProcessMemoryInfo) { HMODULE lib = LoadLibraryW(L"Psapi.dll"); if (lib) my_GetProcessMemoryInfo = (Func_GetProcessMemoryInfo)::GetProcAddress(lib, "GetProcessMemoryInfo"); } if (my_GetProcessMemoryInfo) memDefined = my_GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m)); // FreeLibrary(lib); } #endif UInt64 curTime = GetTime64(curTimeFT); UInt64 creationTime = GetTime64(creationTimeFT); UInt64 kernelTime = GetTime64(kernelTimeFT); UInt64 userTime = GetTime64(userTimeFT); UInt64 totalTime = curTime - creationTime; PrintTime("Kernel ", kernelTime, totalTime); PrintTime("User ", userTime, totalTime); PrintTime("Process", kernelTime + userTime, totalTime); #ifndef UNDER_CE if (memDefined) PrintMemUsage("Virtual ", m.PeakPagefileUsage); #endif PrintTime("Global ", totalTime, totalTime); #ifndef UNDER_CE if (memDefined) PrintMemUsage("Physical", m.PeakWorkingSetSize); #endif *g_StdStream << endl; } 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); CArcCmdLineOptions options; CArcCmdLineParser parser; parser.Parse1(commandStrings, options); if (options.HelpMode) { ShowCopyrightAndHelp(g_StdOut, true); return 0; } #if defined(_WIN32) && !defined(UNDER_CE) NSecurity::EnablePrivilege_SymLink(); #endif #ifdef _7ZIP_LARGE_PAGES if (options.LargePages) { SetLargePageSize(); #if defined(_WIN32) && !defined(UNDER_CE) NSecurity::EnablePrivilege_LockMemory(); #endif } #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; #ifdef EXTERNAL_CODECS CExternalCodecs __externalCodecs; __externalCodecs.GetCodecs = codecs; __externalCodecs.GetHashers = codecs; #else CMyComPtr compressCodecsInfo = codecs; #endif codecs->CaseSensitiveChange = options.CaseSensitiveChange; codecs->CaseSensitive = options.CaseSensitive; ThrowException_if_Error(codecs->Load()); bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); if (codecs->Formats.Size() == 0 && (isExtractGroupCommand || options.Command.CommandType == NCommandType::kList || options.Command.IsFromUpdateGroup())) throw kNoFormats; CObjectVector types; if (!ParseOpenTypes(*codecs, options.ArcType, types)) throw kUnsupportedArcTypeMessage; CIntVector excludedFormats; FOR_VECTOR (k, options.ExcludedArcTypes) { CIntVector tempIndices; if (!codecs->FindFormatForArchiveType(options.ExcludedArcTypes[k], tempIndices) || tempIndices.Size() != 1) throw kUnsupportedArcTypeMessage; excludedFormats.AddToUniqueSorted(tempIndices[0]); // excludedFormats.Sort(); } #ifdef EXTERNAL_CODECS if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kHash || options.Command.CommandType == NCommandType::kBenchmark) ThrowException_if_Error(__externalCodecs.LoadCodecs()); #endif int retCode = NExitCode::kSuccess; HRESULT hresultMain = S_OK; bool showStat = true; if (!options.EnableHeaders || options.TechMode) showStat = false; if (options.Command.CommandType == NCommandType::kInfo) { unsigned i; #ifdef EXTERNAL_CODECS stdStream << endl << "Libs:" << endl; for (i = 0; i < codecs->Libs.Size(); i++) { PrintLibIndex(stdStream, i); stdStream << ' ' << codecs->Libs[i].Path << endl; } #endif stdStream << endl << "Formats:" << endl; const char *kArcFlags = "KSNFMGOPBELH"; const unsigned kNumArcFlags = (unsigned)strlen(kArcFlags); for (i = 0; i < codecs->Formats.Size(); i++) { const CArcInfoEx &arc = codecs->Formats[i]; #ifdef EXTERNAL_CODECS PrintLibIndex(stdStream, arc.LibIndex); #else stdStream << " "; #endif stdStream << (char)(arc.UpdateEnabled ? 'C' : ' '); for (unsigned b = 0; b < kNumArcFlags; b++) { stdStream << (char) ((arc.Flags & ((UInt32)1 << b)) != 0 ? kArcFlags[b] : ' '); } stdStream << ' '; PrintString(stdStream, arc.Name, 8); stdStream << ' '; UString s; FOR_VECTOR (t, arc.Exts) { if (t != 0) s += L' '; const CArcExtInfo &ext = arc.Exts[t]; s += ext.Ext; if (!ext.AddExt.IsEmpty()) { s += L" ("; s += ext.AddExt; s += L')'; } } PrintString(stdStream, s, 13); stdStream << ' '; if (arc.SignatureOffset != 0) stdStream << "offset=" << arc.SignatureOffset << ' '; FOR_VECTOR(si, arc.Signatures) { if (si != 0) stdStream << " || "; const CByteBuffer &sig = arc.Signatures[si]; for (size_t j = 0; j < sig.Size(); j++) { if (j != 0) stdStream << ' '; Byte b = sig[j]; if (b > 0x20 && b < 0x80) { stdStream << (char)b; } else { stdStream << GetHex((b >> 4) & 0xF); stdStream << GetHex(b & 0xF); } } } stdStream << endl; } #ifdef EXTERNAL_CODECS stdStream << endl << "Codecs:" << endl << "Lib ID Name" << endl; UInt32 numMethods; if (codecs->GetNumberOfMethods(&numMethods) == S_OK) for (UInt32 j = 0; j < numMethods; j++) { PrintLibIndex(stdStream, codecs->GetCodecLibIndex(j)); 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]; ConvertUInt64ToHex(id, s); PrintString(stdStream, s, 8); stdStream << " " << codecs->GetCodecName(j) << endl; } stdStream << endl << "Hashers:" << endl << " L Size ID Name" << endl; numMethods = codecs->GetNumHashers(); for (UInt32 j = 0; j < numMethods; j++) { PrintLibIndex(stdStream, codecs->GetHasherLibIndex(j)); PrintUInt32(stdStream, codecs->GetHasherDigestSize(j), 4); stdStream << ' '; char s[32]; ConvertUInt64ToHex(codecs->GetHasherId(j), s); PrintString(stdStream, s, 6); stdStream << " " << codecs->GetHasherName(j) << endl; } #endif } else if (options.Command.CommandType == NCommandType::kBenchmark) { hresultMain = BenchCon(EXTERNAL_CODECS_VARS options.Properties, options.NumIterations, (FILE *)stdStream); if (hresultMain == S_FALSE) { stdStream << "\nDecoding Error\n"; retCode = NExitCode::kFatalError; hresultMain = S_OK; } } 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; (CExtractOptionsBase &)eo = options.ExtractOptions; eo.StdInMode = options.StdInMode; eo.StdOutMode = options.StdOutMode; eo.YesToAll = options.YesToAll; eo.TestMode = options.Command.IsTestCommand(); #ifndef _SFX eo.Properties = options.Properties; #endif UString errorMessage; CDecompressStat stat; CHashBundle hb; IHashCalc *hashCalc = NULL; if (!options.HashMethods.IsEmpty()) { hashCalc = &hb; ThrowException_if_Error(hb.SetMethods(EXTERNAL_CODECS_VARS options.HashMethods)); hb.Init(); } hresultMain = Extract( codecs, types, excludedFormats, options.ArchivePathsSorted, options.ArchivePathsFullSorted, options.Censor.Pairs.Front().Head, eo, &openCallback, ecs, hashCalc, errorMessage, stat); if (!errorMessage.IsEmpty()) { stdStream << endl << "Error: " << errorMessage; if (hresultMain == S_OK) hresultMain = E_FAIL; } stdStream << endl; if (ecs->NumTryArcs > 1) { stdStream << "Archives: " << ecs->NumTryArcs << endl; stdStream << "OK archives: " << ecs->NumOkArcs << endl; } bool isError = false; if (ecs->NumCantOpenArcs != 0) { isError = true; stdStream << "Can't open as archive: " << ecs->NumCantOpenArcs << endl; } if (ecs->NumArcsWithError != 0) { isError = true; stdStream << "Archives with Errors: " << ecs->NumArcsWithError << endl; } if (ecs->NumArcsWithWarnings != 0) stdStream << "Archives with Warnings: " << ecs->NumArcsWithWarnings << endl; if (ecs->NumOpenArcWarnings != 0) { stdStream << endl; if (ecs->NumOpenArcWarnings != 0) stdStream << "Warnings: " << ecs->NumOpenArcWarnings << endl; } if (ecs->NumOpenArcErrors != 0) { isError = true; stdStream << endl; if (ecs->NumOpenArcErrors != 0) stdStream << "Open Errors: " << ecs->NumOpenArcErrors << endl; } if (isError) retCode = NExitCode::kFatalError; if (ecs->NumArcsWithError != 0 || ecs->NumFileErrors != 0) { // if (ecs->NumArchives > 1) { stdStream << endl; if (ecs->NumFileErrors != 0) stdStream << "Sub items Errors: " << ecs->NumFileErrors << endl; } } else if (hresultMain == S_OK) { if (stat.NumFolders != 0) stdStream << "Folders: " << stat.NumFolders << endl; if (stat.NumFiles != 1 || stat.NumFolders != 0 || stat.NumAltStreams != 0) stdStream << "Files: " << stat.NumFiles << endl; if (stat.NumAltStreams != 0) { stdStream << "Alternate Streams: " << stat.NumAltStreams << endl; stdStream << "Alternate Streams Size: " << stat.AltStreams_UnpackSize << endl; } stdStream << "Size: " << stat.UnpackSize << endl << "Compressed: " << stat.PackSize << endl; if (hashCalc) PrintHashStat(stdStream, hb); } } else { UInt64 numErrors = 0; UInt64 numWarnings = 0; // options.ExtractNtOptions.StoreAltStreams = true, if -sns[-] is not definmed hresultMain = ListArchives( codecs, types, excludedFormats, options.StdInMode, options.ArchivePathsSorted, options.ArchivePathsFullSorted, options.ExtractOptions.NtOptions.AltStreams.Val, options.AltStreams.Val, // we don't want to show AltStreams by default options.Censor.Pairs.Front().Head, options.EnableHeaders, options.TechMode, #ifndef _NO_CRYPTO options.PasswordEnabled, options.Password, #endif &options.Properties, numErrors, numWarnings); if (options.EnableHeaders) if (numWarnings > 0) g_StdOut << endl << "Warnings: " << numWarnings << endl; if (numErrors > 0) { if (options.EnableHeaders) g_StdOut << endl << "Errors: " << numErrors << endl; retCode = NExitCode::kFatalError; } } } 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, types, options.ArchiveName)) throw kUnsupportedUpdateArcType; */ hresultMain = UpdateArchive(codecs, types, options.ArchiveName, options.Censor, uo, errorInfo, &openCallback, &callback, true); retCode = WarningsCheck(hresultMain, callback, errorInfo, stdStream); } else if (options.Command.CommandType == NCommandType::kHash) { const CHashOptions &uo = options.HashOptions; CHashCallbackConsole callback; callback.EnablePercents = options.EnablePercents; callback.Init(&stdStream); UString errorInfoString; hresultMain = HashCalc(EXTERNAL_CODECS_VARS options.Censor, uo, errorInfoString, &callback); CErrorInfo errorInfo; errorInfo.Message = errorInfoString; retCode = WarningsCheck(hresultMain, callback, errorInfo, stdStream); } else ShowMessageAndThrowException(stdStream, kUserErrorMessage, NExitCode::kUserError); if (showStat) PrintStat(); ThrowException_if_Error(hresultMain); return retCode; }