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