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