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