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