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 
ParseArchiveCommand(const UString & commandString,CArchiveCommand & command)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 
DefaultRecursedType() const169 NRecursedType::EEnum CArchiveCommand::DefaultRecursedType() const
170 {
171   return kCommandRecursedDefault[CommandType];
172 }
173 
PrintHelp(void)174 void PrintHelp(void)
175 {
176   g_StdOut << kHelpString;
177 }
178 
ShowMessageAndThrowException(const char * message,NExitCode::EEnum code)179 static void ShowMessageAndThrowException(const char *message, NExitCode::EEnum code)
180 {
181   g_StdOut << message << endl;
182   throw code;
183 }
184 
PrintHelpAndExit()185 static void PrintHelpAndExit() // yyy
186 {
187   PrintHelp();
188   ShowMessageAndThrowException(kUserErrorMessage, NExitCode::kUserError);
189 }
190 
191 // ------------------------------------------------------------------
192 // filenames functions
193 
AddNameToCensor(NWildcard::CCensor & wildcardCensor,const UString & name,bool include,NRecursedType::EEnum type)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 
AddCommandLineWildcardToCensor(NWildcard::CCensor & wildcardCensor,const UString & name,bool include,NRecursedType::EEnum type)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
GetArguments(int numArgs,const char * args[],UStringVector & parts)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 
Main2(int numArgs,const char * args[])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