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
25using namespace NWindows;
26using namespace NFile;
27using namespace NDir;
28using namespace NCommandLineParser;
29
30#ifdef _WIN32
31HINSTANCE g_hInstance = 0;
32#endif
33int g_CodePage = -1;
34extern CStdOutStream *g_StdStream;
35
36static const char *kCopyrightString =
37"\n7-Zip SFX " MY_VERSION_COPYRIGHT_DATE "\n";
38
39static const int kNumSwitches = 6;
40
41namespace NKey {
42enum Enum
43{
44  kHelp1 = 0,
45  kHelp2,
46  kDisablePercents,
47  kYes,
48  kPassword,
49  kOutputDir
50};
51
52}
53
54namespace NRecursedType {
55enum EEnum
56{
57  kRecursed,
58  kWildcardOnlyRecursed,
59  kNonRecursed
60};
61}
62/*
63static const char kRecursedIDChar = 'R';
64static const wchar_t *kRecursedPostCharSet = L"0-";
65
66namespace NRecursedPostCharIndex {
67  enum EEnum
68  {
69    kWildcardRecursionOnly = 0,
70    kNoRecursion = 1
71  };
72}
73
74static const char kFileListID = '@';
75static const char kImmediateNameID = '!';
76
77static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
78static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be
79*/
80static 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
90static const int kNumCommandForms = 3;
91
92static const NRecursedType::EEnum kCommandRecursedDefault[kNumCommandForms] =
93{
94  NRecursedType::kRecursed
95};
96
97// static const bool kTestExtractRecursedDefault = true;
98// static const bool kAddRecursedDefault = false;
99
100static const wchar_t *kUniversalWildcard = L"*";
101static const int kCommandIndex = 0;
102
103static 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
120static const char *kUserErrorMessage  = "Incorrect command line"; // NExitCode::kUserError
121// static const char *kIncorrectListFile = "Incorrect wildcard in listfile";
122static 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
129static const char *kCantFindSFX = " cannot find sfx";
130
131namespace NCommandType
132{
133  enum EEnum
134  {
135    kTest = 0,
136    kFullExtract,
137    kList
138  };
139}
140
141static const char *g_Commands = "txl";
142
143struct CArchiveCommand
144{
145  NCommandType::EEnum CommandType;
146
147  NRecursedType::EEnum DefaultRecursedType() const;
148};
149
150bool 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
165NRecursedType::EEnum CArchiveCommand::DefaultRecursedType() const
166{
167  return kCommandRecursedDefault[CommandType];
168}
169
170void PrintHelp(void)
171{
172  g_StdOut << kHelpString;
173}
174
175static void ShowMessageAndThrowException(const char *message, NExitCode::EEnum code)
176{
177  g_StdOut << message << endl;
178  throw code;
179}
180
181static void PrintHelpAndExit() // yyy
182{
183  PrintHelp();
184  ShowMessageAndThrowException(kUserErrorMessage, NExitCode::kUserError);
185}
186
187// ------------------------------------------------------------------
188// filenames functions
189
190static 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
216void 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
223void 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
232static 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
243int 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