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