Home | History | Annotate | Download | only in SFXCon
      1 // Main.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "../../../../C/CpuArch.h"
      6 
      7 #include "../../../Common/MyWindows.h"
      8 
      9 #include "../../../Common/MyInitGuid.h"
     10 
     11 #include "../../../Common/CommandLineParser.h"
     12 #include "../../../Common/MyException.h"
     13 
     14 #ifdef _WIN32
     15 #include "../../../Windows/DLL.h"
     16 #include "../../../Windows/FileDir.h"
     17 #endif
     18 #include "../../../Windows/FileName.h"
     19 
     20 #include "../../UI/Common/ExitCode.h"
     21 #include "../../UI/Common/Extract.h"
     22 
     23 #include "../../UI/Console/ExtractCallbackConsole.h"
     24 #include "../../UI/Console/List.h"
     25 #include "../../UI/Console/OpenCallbackConsole.h"
     26 
     27 #include "../../MyVersion.h"
     28 
     29 #include "../../../../C/DllSecur.h"
     30 
     31 using namespace NWindows;
     32 using namespace NFile;
     33 using namespace NDir;
     34 using namespace NCommandLineParser;
     35 
     36 #ifdef _WIN32
     37 HINSTANCE g_hInstance = 0;
     38 #endif
     39 int g_CodePage = -1;
     40 extern CStdOutStream *g_StdStream;
     41 
     42 static const char * const kCopyrightString =
     43 "\n7-Zip SFX " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n";
     44 
     45 static const int kNumSwitches = 6;
     46 
     47 namespace NKey {
     48 enum Enum
     49 {
     50   kHelp1 = 0,
     51   kHelp2,
     52   kDisablePercents,
     53   kYes,
     54   kPassword,
     55   kOutputDir
     56 };
     57 
     58 }
     59 
     60 namespace NRecursedType {
     61 enum EEnum
     62 {
     63   kRecursed,
     64   kWildcardOnlyRecursed,
     65   kNonRecursed
     66 };
     67 }
     68 /*
     69 static const char kRecursedIDChar = 'R';
     70 
     71 namespace NRecursedPostCharIndex {
     72   enum EEnum
     73   {
     74     kWildcardRecursionOnly = 0,
     75     kNoRecursion = 1
     76   };
     77 }
     78 
     79 static const char kFileListID = '@';
     80 static const char kImmediateNameID = '!';
     81 
     82 static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
     83 static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be
     84 */
     85 static const CSwitchForm kSwitchForms[kNumSwitches] =
     86 {
     87   { "?",  NSwitchType::kSimple },
     88   { "H",  NSwitchType::kSimple },
     89   { "BD", NSwitchType::kSimple },
     90   { "Y",  NSwitchType::kSimple },
     91   { "P",  NSwitchType::kString, false, 1 },
     92   { "O",  NSwitchType::kString, false, 1 },
     93 };
     94 
     95 static const int kNumCommandForms = 3;
     96 
     97 static const NRecursedType::EEnum kCommandRecursedDefault[kNumCommandForms] =
     98 {
     99   NRecursedType::kRecursed
    100 };
    101 
    102 // static const bool kTestExtractRecursedDefault = true;
    103 // static const bool kAddRecursedDefault = false;
    104 
    105 static const char * const kUniversalWildcard = "*";
    106 static const int kCommandIndex = 0;
    107 
    108 static const char * const kHelpString =
    109     "\nUsage: 7zSFX [<command>] [<switches>...] [<file_name>...]\n"
    110     "\n"
    111     "<Commands>\n"
    112     // "  l: List contents of archive\n"
    113     "  t: Test integrity of archive\n"
    114     "  x: eXtract files with full pathname (default)\n"
    115     "<Switches>\n"
    116     // "  -bd Disable percentage indicator\n"
    117     "  -o{Directory}: set Output directory\n"
    118     "  -p{Password}: set Password\n"
    119     "  -y: assume Yes on all queries\n";
    120 
    121 
    122 // ---------------------------
    123 // exception messages
    124 
    125 static const char * const kUserErrorMessage  = "Incorrect command line"; // NExitCode::kUserError
    126 // static const char * const kIncorrectListFile = "Incorrect wildcard in listfile";
    127 static const char * const kIncorrectWildcardInCommandLine  = "Incorrect wildcard in command line";
    128 
    129 // static const CSysString kFileIsNotArchiveMessageBefore = "File \"";
    130 // static const CSysString kFileIsNotArchiveMessageAfter = "\" is not archive";
    131 
    132 // static const char * const kProcessArchiveMessage = " archive: ";
    133 
    134 static const char * const kCantFindSFX = " cannot find sfx";
    135 
    136 namespace NCommandType
    137 {
    138   enum EEnum
    139   {
    140     kTest = 0,
    141     kFullExtract,
    142     kList
    143   };
    144 }
    145 
    146 static const char *g_Commands = "txl";
    147 
    148 struct CArchiveCommand
    149 {
    150   NCommandType::EEnum CommandType;
    151 
    152   NRecursedType::EEnum DefaultRecursedType() const;
    153 };
    154 
    155 bool ParseArchiveCommand(const UString &commandString, CArchiveCommand &command)
    156 {
    157   UString s = commandString;
    158   s.MakeLower_Ascii();
    159   if (s.Len() != 1)
    160     return false;
    161   if (s[0] >= 0x80)
    162     return false;
    163   int index = FindCharPosInString(g_Commands, (char)s[0]);
    164   if (index < 0)
    165     return false;
    166   command.CommandType = (NCommandType::EEnum)index;
    167   return true;
    168 }
    169 
    170 NRecursedType::EEnum CArchiveCommand::DefaultRecursedType() const
    171 {
    172   return kCommandRecursedDefault[CommandType];
    173 }
    174 
    175 void PrintHelp(void)
    176 {
    177   g_StdOut << kHelpString;
    178 }
    179 
    180 static void ShowMessageAndThrowException(const char *message, NExitCode::EEnum code)
    181 {
    182   g_StdOut << message << endl;
    183   throw code;
    184 }
    185 
    186 static void PrintHelpAndExit() // yyy
    187 {
    188   PrintHelp();
    189   ShowMessageAndThrowException(kUserErrorMessage, NExitCode::kUserError);
    190 }
    191 
    192 // ------------------------------------------------------------------
    193 // filenames functions
    194 
    195 static bool AddNameToCensor(NWildcard::CCensor &wildcardCensor,
    196     const UString &name, bool include, NRecursedType::EEnum type)
    197 {
    198   /*
    199   if (!IsWildcardFilePathLegal(name))
    200     return false;
    201   */
    202   bool isWildcard = DoesNameContainWildcard(name);
    203   bool recursed = false;
    204 
    205   switch (type)
    206   {
    207     case NRecursedType::kWildcardOnlyRecursed:
    208       recursed = isWildcard;
    209       break;
    210     case NRecursedType::kRecursed:
    211       recursed = true;
    212       break;
    213     case NRecursedType::kNonRecursed:
    214       recursed = false;
    215       break;
    216   }
    217   wildcardCensor.AddPreItem(include, name, recursed, true);
    218   return true;
    219 }
    220 
    221 void AddCommandLineWildcardToCensor(NWildcard::CCensor &wildcardCensor,
    222     const UString &name, bool include, NRecursedType::EEnum type)
    223 {
    224   if (!AddNameToCensor(wildcardCensor, name, include, type))
    225     ShowMessageAndThrowException(kIncorrectWildcardInCommandLine, NExitCode::kUserError);
    226 }
    227 
    228 
    229 #ifndef _WIN32
    230 static void GetArguments(int numArgs, const char *args[], UStringVector &parts)
    231 {
    232   parts.Clear();
    233   for (int i = 0; i < numArgs; i++)
    234   {
    235     UString s = MultiByteToUnicodeString(args[i]);
    236     parts.Add(s);
    237   }
    238 }
    239 #endif
    240 
    241 int Main2(
    242   #ifndef _WIN32
    243   int numArgs, const char *args[]
    244   #endif
    245 )
    246 {
    247   #ifdef _WIN32
    248   // do we need load Security DLLs for console program?
    249   LoadSecurityDlls();
    250   #endif
    251 
    252   #if defined(_WIN32) && !defined(UNDER_CE)
    253   SetFileApisToOEM();
    254   #endif
    255 
    256   g_StdOut << kCopyrightString;
    257 
    258   UStringVector commandStrings;
    259   #ifdef _WIN32
    260   NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
    261   #else
    262   GetArguments(numArgs, args, commandStrings);
    263   #endif
    264 
    265   #ifdef _WIN32
    266 
    267   FString arcPath;
    268   {
    269     FString path;
    270     NDLL::MyGetModuleFileName(path);
    271     if (!MyGetFullPathName(path, arcPath))
    272     {
    273       g_StdOut << "GetFullPathName Error";
    274       return NExitCode::kFatalError;
    275     }
    276   }
    277 
    278   #else
    279 
    280   UString arcPath = commandStrings.Front();
    281 
    282   #endif
    283 
    284   #ifndef UNDER_CE
    285   if (commandStrings.Size() > 0)
    286     commandStrings.Delete(0);
    287   #endif
    288 
    289   NCommandLineParser::CParser parser;
    290 
    291   try
    292   {
    293     if (!parser.ParseStrings(kSwitchForms, kNumSwitches, commandStrings))
    294     {
    295       g_StdOut << "Command line error:" << endl
    296           << parser.ErrorMessage << endl
    297           << parser.ErrorLine << endl;
    298       return NExitCode::kUserError;
    299     }
    300   }
    301   catch(...)
    302   {
    303     PrintHelpAndExit();
    304   }
    305 
    306   if (parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
    307   {
    308     PrintHelp();
    309     return 0;
    310   }
    311 
    312   const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
    313 
    314   unsigned curCommandIndex = 0;
    315 
    316   CArchiveCommand command;
    317   if (nonSwitchStrings.IsEmpty())
    318     command.CommandType = NCommandType::kFullExtract;
    319   else
    320   {
    321     const UString &cmd = nonSwitchStrings[curCommandIndex];
    322     if (!ParseArchiveCommand(cmd, command))
    323     {
    324       g_StdOut << "ERROR: Unknown command:" << endl << cmd << endl;
    325       return NExitCode::kUserError;
    326     }
    327     curCommandIndex = 1;
    328   }
    329 
    330 
    331   NRecursedType::EEnum recursedType;
    332   recursedType = command.DefaultRecursedType();
    333 
    334   NWildcard::CCensor wildcardCensor;
    335 
    336   {
    337     if (nonSwitchStrings.Size() == curCommandIndex)
    338       AddCommandLineWildcardToCensor(wildcardCensor, (UString)kUniversalWildcard, true, recursedType);
    339     for (; curCommandIndex < nonSwitchStrings.Size(); curCommandIndex++)
    340     {
    341       const UString &s = nonSwitchStrings[curCommandIndex];
    342       if (s.IsEmpty())
    343         throw "Empty file path";
    344       AddCommandLineWildcardToCensor(wildcardCensor, s, true, recursedType);
    345     }
    346   }
    347 
    348   bool yesToAll = parser[NKey::kYes].ThereIs;
    349 
    350   // NExtractMode::EEnum extractMode;
    351   // bool isExtractGroupCommand = command.IsFromExtractGroup(extractMode);
    352 
    353   bool passwordEnabled = parser[NKey::kPassword].ThereIs;
    354 
    355   UString password;
    356   if (passwordEnabled)
    357     password = parser[NKey::kPassword].PostStrings[0];
    358 
    359   if (!NFind::DoesFileExist(arcPath))
    360     throw kCantFindSFX;
    361 
    362   FString outputDir;
    363   if (parser[NKey::kOutputDir].ThereIs)
    364   {
    365     outputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]);
    366     NName::NormalizeDirPathPrefix(outputDir);
    367   }
    368 
    369 
    370   wildcardCensor.AddPathsToCensor(NWildcard::k_RelatPath);
    371 
    372   {
    373     UStringVector v1, v2;
    374     v1.Add(fs2us(arcPath));
    375     v2.Add(fs2us(arcPath));
    376     const NWildcard::CCensorNode &wildcardCensorHead =
    377       wildcardCensor.Pairs.Front().Head;
    378 
    379     CCodecs *codecs = new CCodecs;
    380     CMyComPtr<
    381       #ifdef EXTERNAL_CODECS
    382       ICompressCodecsInfo
    383       #else
    384       IUnknown
    385       #endif
    386       > compressCodecsInfo = codecs;
    387     {
    388       HRESULT result = codecs->Load();
    389       if (result != S_OK)
    390         throw CSystemException(result);
    391     }
    392 
    393     if (command.CommandType != NCommandType::kList)
    394     {
    395       CExtractCallbackConsole *ecs = new CExtractCallbackConsole;
    396       CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
    397       ecs->Init(g_StdStream, &g_StdErr, g_StdStream);
    398 
    399       #ifndef _NO_CRYPTO
    400       ecs->PasswordIsDefined = passwordEnabled;
    401       ecs->Password = password;
    402       #endif
    403 
    404       /*
    405       COpenCallbackConsole openCallback;
    406       openCallback.Init(g_StdStream, g_StdStream);
    407 
    408       #ifndef _NO_CRYPTO
    409       openCallback.PasswordIsDefined = passwordEnabled;
    410       openCallback.Password = password;
    411       #endif
    412       */
    413 
    414       CExtractOptions eo;
    415       eo.StdOutMode = false;
    416       eo.YesToAll = yesToAll;
    417       eo.TestMode = command.CommandType == NCommandType::kTest;
    418       eo.PathMode = NExtract::NPathMode::kFullPaths;
    419       eo.OverwriteMode = yesToAll ?
    420           NExtract::NOverwriteMode::kOverwrite :
    421           NExtract::NOverwriteMode::kAsk;
    422       eo.OutputDir = outputDir;
    423 
    424       UString errorMessage;
    425       CDecompressStat stat;
    426       HRESULT result = Extract(
    427           codecs, CObjectVector<COpenType>(), CIntVector(),
    428           v1, v2,
    429           wildcardCensorHead,
    430           eo, ecs, ecs,
    431           // NULL, // hash
    432           errorMessage, stat);
    433       if (!errorMessage.IsEmpty())
    434       {
    435         (*g_StdStream) << endl << "Error: " << errorMessage;;
    436         if (result == S_OK)
    437           result = E_FAIL;
    438       }
    439 
    440       if (ecs->NumArcsWithError != 0 || ecs->NumFileErrors != 0)
    441       {
    442         if (ecs->NumArcsWithError != 0)
    443           (*g_StdStream) << endl << "Archive Errors" << endl;
    444         if (ecs->NumFileErrors != 0)
    445           (*g_StdStream) << endl << "Sub items Errors: " << ecs->NumFileErrors << endl;
    446         return NExitCode::kFatalError;
    447       }
    448       if (result != S_OK)
    449         throw CSystemException(result);
    450     }
    451     else
    452     {
    453       throw CSystemException(E_NOTIMPL);
    454 
    455       /*
    456       UInt64 numErrors = 0;
    457       UInt64 numWarnings = 0;
    458       HRESULT result = ListArchives(
    459           codecs, CObjectVector<COpenType>(), CIntVector(),
    460           false, // stdInMode
    461           v1, v2,
    462           true, // processAltStreams
    463           false, // showAltStreams
    464           wildcardCensorHead,
    465           true, // enableHeaders
    466           false, // techMode
    467           #ifndef _NO_CRYPTO
    468           passwordEnabled, password,
    469           #endif
    470           numErrors, numWarnings);
    471       if (numErrors > 0)
    472       {
    473         g_StdOut << endl << "Errors: " << numErrors;
    474         return NExitCode::kFatalError;
    475       }
    476       if (result != S_OK)
    477         throw CSystemException(result);
    478       */
    479     }
    480   }
    481   return 0;
    482 }
    483