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