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