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