1370b324cSopenharmony_ci// Main.cpp
2370b324cSopenharmony_ci
3370b324cSopenharmony_ci#include "StdAfx.h"
4370b324cSopenharmony_ci
5370b324cSopenharmony_ci#include "../../../../C/DllSecur.h"
6370b324cSopenharmony_ci
7370b324cSopenharmony_ci#include "../../../Common/MyWindows.h"
8370b324cSopenharmony_ci#include "../../../Common/MyInitGuid.h"
9370b324cSopenharmony_ci
10370b324cSopenharmony_ci#include "../../../Common/CommandLineParser.h"
11370b324cSopenharmony_ci#include "../../../Common/StringConvert.h"
12370b324cSopenharmony_ci#include "../../../Common/TextConfig.h"
13370b324cSopenharmony_ci
14370b324cSopenharmony_ci#include "../../../Windows/DLL.h"
15370b324cSopenharmony_ci#include "../../../Windows/ErrorMsg.h"
16370b324cSopenharmony_ci#include "../../../Windows/FileDir.h"
17370b324cSopenharmony_ci#include "../../../Windows/FileFind.h"
18370b324cSopenharmony_ci#include "../../../Windows/FileIO.h"
19370b324cSopenharmony_ci#include "../../../Windows/FileName.h"
20370b324cSopenharmony_ci#include "../../../Windows/NtCheck.h"
21370b324cSopenharmony_ci#include "../../../Windows/ResourceString.h"
22370b324cSopenharmony_ci
23370b324cSopenharmony_ci#include "../../UI/Explorer/MyMessages.h"
24370b324cSopenharmony_ci
25370b324cSopenharmony_ci#include "ExtractEngine.h"
26370b324cSopenharmony_ci
27370b324cSopenharmony_ci#include "resource.h"
28370b324cSopenharmony_ci
29370b324cSopenharmony_ciusing namespace NWindows;
30370b324cSopenharmony_ciusing namespace NFile;
31370b324cSopenharmony_ciusing namespace NDir;
32370b324cSopenharmony_ci
33370b324cSopenharmony_ciextern
34370b324cSopenharmony_ciHINSTANCE g_hInstance;
35370b324cSopenharmony_ciHINSTANCE g_hInstance;
36370b324cSopenharmony_ci
37370b324cSopenharmony_cistatic CFSTR const kTempDirPrefix = FTEXT("7zS");
38370b324cSopenharmony_ci
39370b324cSopenharmony_ci#define MY_SHELL_EXECUTE
40370b324cSopenharmony_ci
41370b324cSopenharmony_cistatic bool ReadDataString(CFSTR fileName, LPCSTR startID,
42370b324cSopenharmony_ci    LPCSTR endID, AString &stringResult)
43370b324cSopenharmony_ci{
44370b324cSopenharmony_ci  stringResult.Empty();
45370b324cSopenharmony_ci  NIO::CInFile inFile;
46370b324cSopenharmony_ci  if (!inFile.Open(fileName))
47370b324cSopenharmony_ci    return false;
48370b324cSopenharmony_ci  const size_t kBufferSize = (1 << 12);
49370b324cSopenharmony_ci
50370b324cSopenharmony_ci  Byte buffer[kBufferSize];
51370b324cSopenharmony_ci  const unsigned signatureStartSize = MyStringLen(startID);
52370b324cSopenharmony_ci  const unsigned signatureEndSize = MyStringLen(endID);
53370b324cSopenharmony_ci
54370b324cSopenharmony_ci  size_t numBytesPrev = 0;
55370b324cSopenharmony_ci  bool writeMode = false;
56370b324cSopenharmony_ci  UInt64 posTotal = 0;
57370b324cSopenharmony_ci  for (;;)
58370b324cSopenharmony_ci  {
59370b324cSopenharmony_ci    if (posTotal > (1 << 20))
60370b324cSopenharmony_ci      return (stringResult.IsEmpty());
61370b324cSopenharmony_ci    const size_t numReadBytes = kBufferSize - numBytesPrev;
62370b324cSopenharmony_ci    size_t processedSize;
63370b324cSopenharmony_ci    if (!inFile.ReadFull(buffer + numBytesPrev, numReadBytes, processedSize))
64370b324cSopenharmony_ci      return false;
65370b324cSopenharmony_ci    if (processedSize == 0)
66370b324cSopenharmony_ci      return true;
67370b324cSopenharmony_ci    const size_t numBytesInBuffer = numBytesPrev + processedSize;
68370b324cSopenharmony_ci    UInt32 pos = 0;
69370b324cSopenharmony_ci    for (;;)
70370b324cSopenharmony_ci    {
71370b324cSopenharmony_ci      if (writeMode)
72370b324cSopenharmony_ci      {
73370b324cSopenharmony_ci        if (pos + signatureEndSize > numBytesInBuffer)
74370b324cSopenharmony_ci          break;
75370b324cSopenharmony_ci        if (memcmp(buffer + pos, endID, signatureEndSize) == 0)
76370b324cSopenharmony_ci          return true;
77370b324cSopenharmony_ci        const Byte b = buffer[pos];
78370b324cSopenharmony_ci        if (b == 0)
79370b324cSopenharmony_ci          return false;
80370b324cSopenharmony_ci        stringResult += (char)b;
81370b324cSopenharmony_ci        pos++;
82370b324cSopenharmony_ci      }
83370b324cSopenharmony_ci      else
84370b324cSopenharmony_ci      {
85370b324cSopenharmony_ci        if (pos + signatureStartSize > numBytesInBuffer)
86370b324cSopenharmony_ci          break;
87370b324cSopenharmony_ci        if (memcmp(buffer + pos, startID, signatureStartSize) == 0)
88370b324cSopenharmony_ci        {
89370b324cSopenharmony_ci          writeMode = true;
90370b324cSopenharmony_ci          pos += signatureStartSize;
91370b324cSopenharmony_ci        }
92370b324cSopenharmony_ci        else
93370b324cSopenharmony_ci          pos++;
94370b324cSopenharmony_ci      }
95370b324cSopenharmony_ci    }
96370b324cSopenharmony_ci    numBytesPrev = numBytesInBuffer - pos;
97370b324cSopenharmony_ci    posTotal += pos;
98370b324cSopenharmony_ci    memmove(buffer, buffer + pos, numBytesPrev);
99370b324cSopenharmony_ci  }
100370b324cSopenharmony_ci}
101370b324cSopenharmony_ci
102370b324cSopenharmony_cistatic char kStartID[] = { ',','!','@','I','n','s','t','a','l','l','@','!','U','T','F','-','8','!', 0 };
103370b324cSopenharmony_cistatic char kEndID[]   = { ',','!','@','I','n','s','t','a','l','l','E','n','d','@','!', 0 };
104370b324cSopenharmony_ci
105370b324cSopenharmony_cistatic struct CInstallIDInit
106370b324cSopenharmony_ci{
107370b324cSopenharmony_ci  CInstallIDInit()
108370b324cSopenharmony_ci  {
109370b324cSopenharmony_ci    kStartID[0] = ';';
110370b324cSopenharmony_ci    kEndID[0] = ';';
111370b324cSopenharmony_ci  }
112370b324cSopenharmony_ci} g_CInstallIDInit;
113370b324cSopenharmony_ci
114370b324cSopenharmony_ci
115370b324cSopenharmony_ci#if defined(_WIN32) && defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
116370b324cSopenharmony_ci#define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return 1;
117370b324cSopenharmony_ci#endif
118370b324cSopenharmony_ci
119370b324cSopenharmony_cistatic void ShowErrorMessageSpec(const UString &name)
120370b324cSopenharmony_ci{
121370b324cSopenharmony_ci  UString message = NError::MyFormatMessage(::GetLastError());
122370b324cSopenharmony_ci  const int pos = message.Find(L"%1");
123370b324cSopenharmony_ci  if (pos >= 0)
124370b324cSopenharmony_ci  {
125370b324cSopenharmony_ci    message.Delete((unsigned)pos, 2);
126370b324cSopenharmony_ci    message.Insert((unsigned)pos, name);
127370b324cSopenharmony_ci  }
128370b324cSopenharmony_ci  ShowErrorMessage(NULL, message);
129370b324cSopenharmony_ci}
130370b324cSopenharmony_ci
131370b324cSopenharmony_ciint APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
132370b324cSopenharmony_ci    #ifdef UNDER_CE
133370b324cSopenharmony_ci    LPWSTR
134370b324cSopenharmony_ci    #else
135370b324cSopenharmony_ci    LPSTR
136370b324cSopenharmony_ci    #endif
137370b324cSopenharmony_ci    /* lpCmdLine */,int /* nCmdShow */)
138370b324cSopenharmony_ci{
139370b324cSopenharmony_ci  g_hInstance = (HINSTANCE)hInstance;
140370b324cSopenharmony_ci
141370b324cSopenharmony_ci  NT_CHECK
142370b324cSopenharmony_ci
143370b324cSopenharmony_ci  #ifdef _WIN32
144370b324cSopenharmony_ci  LoadSecurityDlls();
145370b324cSopenharmony_ci  #endif
146370b324cSopenharmony_ci
147370b324cSopenharmony_ci  // InitCommonControls();
148370b324cSopenharmony_ci
149370b324cSopenharmony_ci  UString archiveName, switches;
150370b324cSopenharmony_ci  #ifdef MY_SHELL_EXECUTE
151370b324cSopenharmony_ci  UString executeFile, executeParameters;
152370b324cSopenharmony_ci  #endif
153370b324cSopenharmony_ci  NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches);
154370b324cSopenharmony_ci
155370b324cSopenharmony_ci  FString fullPath;
156370b324cSopenharmony_ci  NDLL::MyGetModuleFileName(fullPath);
157370b324cSopenharmony_ci
158370b324cSopenharmony_ci  switches.Trim();
159370b324cSopenharmony_ci  bool assumeYes = false;
160370b324cSopenharmony_ci  if (switches.IsPrefixedBy_Ascii_NoCase("-y"))
161370b324cSopenharmony_ci  {
162370b324cSopenharmony_ci    assumeYes = true;
163370b324cSopenharmony_ci    switches = switches.Ptr(2);
164370b324cSopenharmony_ci    switches.Trim();
165370b324cSopenharmony_ci  }
166370b324cSopenharmony_ci
167370b324cSopenharmony_ci  AString config;
168370b324cSopenharmony_ci  if (!ReadDataString(fullPath, kStartID, kEndID, config))
169370b324cSopenharmony_ci  {
170370b324cSopenharmony_ci    if (!assumeYes)
171370b324cSopenharmony_ci      ShowErrorMessage(L"Can't load config info");
172370b324cSopenharmony_ci    return 1;
173370b324cSopenharmony_ci  }
174370b324cSopenharmony_ci
175370b324cSopenharmony_ci  UString dirPrefix ("." STRING_PATH_SEPARATOR);
176370b324cSopenharmony_ci  UString appLaunched;
177370b324cSopenharmony_ci  bool showProgress = true;
178370b324cSopenharmony_ci  if (!config.IsEmpty())
179370b324cSopenharmony_ci  {
180370b324cSopenharmony_ci    CObjectVector<CTextConfigPair> pairs;
181370b324cSopenharmony_ci    if (!GetTextConfig(config, pairs))
182370b324cSopenharmony_ci    {
183370b324cSopenharmony_ci      if (!assumeYes)
184370b324cSopenharmony_ci        ShowErrorMessage(L"Config failed");
185370b324cSopenharmony_ci      return 1;
186370b324cSopenharmony_ci    }
187370b324cSopenharmony_ci    const UString friendlyName = GetTextConfigValue(pairs, "Title");
188370b324cSopenharmony_ci    const UString installPrompt = GetTextConfigValue(pairs, "BeginPrompt");
189370b324cSopenharmony_ci    const UString progress = GetTextConfigValue(pairs, "Progress");
190370b324cSopenharmony_ci    if (progress.IsEqualTo_Ascii_NoCase("no"))
191370b324cSopenharmony_ci      showProgress = false;
192370b324cSopenharmony_ci    const int index = FindTextConfigItem(pairs, "Directory");
193370b324cSopenharmony_ci    if (index >= 0)
194370b324cSopenharmony_ci      dirPrefix = pairs[index].String;
195370b324cSopenharmony_ci    if (!installPrompt.IsEmpty() && !assumeYes)
196370b324cSopenharmony_ci    {
197370b324cSopenharmony_ci      if (MessageBoxW(NULL, installPrompt, friendlyName, MB_YESNO |
198370b324cSopenharmony_ci          MB_ICONQUESTION) != IDYES)
199370b324cSopenharmony_ci        return 0;
200370b324cSopenharmony_ci    }
201370b324cSopenharmony_ci    appLaunched = GetTextConfigValue(pairs, "RunProgram");
202370b324cSopenharmony_ci
203370b324cSopenharmony_ci    #ifdef MY_SHELL_EXECUTE
204370b324cSopenharmony_ci    executeFile = GetTextConfigValue(pairs, "ExecuteFile");
205370b324cSopenharmony_ci    executeParameters = GetTextConfigValue(pairs, "ExecuteParameters");
206370b324cSopenharmony_ci    #endif
207370b324cSopenharmony_ci  }
208370b324cSopenharmony_ci
209370b324cSopenharmony_ci  CTempDir tempDir;
210370b324cSopenharmony_ci  if (!tempDir.Create(kTempDirPrefix))
211370b324cSopenharmony_ci  {
212370b324cSopenharmony_ci    if (!assumeYes)
213370b324cSopenharmony_ci      ShowErrorMessage(L"Cannot create temp folder archive");
214370b324cSopenharmony_ci    return 1;
215370b324cSopenharmony_ci  }
216370b324cSopenharmony_ci
217370b324cSopenharmony_ci  CCodecs *codecs = new CCodecs;
218370b324cSopenharmony_ci  CMyComPtr<IUnknown> compressCodecsInfo = codecs;
219370b324cSopenharmony_ci  {
220370b324cSopenharmony_ci    const HRESULT result = codecs->Load();
221370b324cSopenharmony_ci    if (result != S_OK)
222370b324cSopenharmony_ci    {
223370b324cSopenharmony_ci      ShowErrorMessage(L"Cannot load codecs");
224370b324cSopenharmony_ci      return 1;
225370b324cSopenharmony_ci    }
226370b324cSopenharmony_ci  }
227370b324cSopenharmony_ci
228370b324cSopenharmony_ci  const FString tempDirPath = tempDir.GetPath();
229370b324cSopenharmony_ci  // tempDirPath = L"M:\\1\\"; // to test low disk space
230370b324cSopenharmony_ci  {
231370b324cSopenharmony_ci    bool isCorrupt = false;
232370b324cSopenharmony_ci    UString errorMessage;
233370b324cSopenharmony_ci    HRESULT result = ExtractArchive(codecs, fullPath, tempDirPath, showProgress,
234370b324cSopenharmony_ci      isCorrupt, errorMessage);
235370b324cSopenharmony_ci
236370b324cSopenharmony_ci    if (result != S_OK)
237370b324cSopenharmony_ci    {
238370b324cSopenharmony_ci      if (!assumeYes)
239370b324cSopenharmony_ci      {
240370b324cSopenharmony_ci        if (result == S_FALSE || isCorrupt)
241370b324cSopenharmony_ci        {
242370b324cSopenharmony_ci          NWindows::MyLoadString(IDS_EXTRACTION_ERROR_MESSAGE, errorMessage);
243370b324cSopenharmony_ci          result = E_FAIL;
244370b324cSopenharmony_ci        }
245370b324cSopenharmony_ci        if (result != E_ABORT)
246370b324cSopenharmony_ci        {
247370b324cSopenharmony_ci          if (errorMessage.IsEmpty())
248370b324cSopenharmony_ci            errorMessage = NError::MyFormatMessage(result);
249370b324cSopenharmony_ci          ::MessageBoxW(NULL, errorMessage, NWindows::MyLoadString(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR);
250370b324cSopenharmony_ci        }
251370b324cSopenharmony_ci      }
252370b324cSopenharmony_ci      return 1;
253370b324cSopenharmony_ci    }
254370b324cSopenharmony_ci  }
255370b324cSopenharmony_ci
256370b324cSopenharmony_ci  #ifndef UNDER_CE
257370b324cSopenharmony_ci  CCurrentDirRestorer currentDirRestorer;
258370b324cSopenharmony_ci  if (!SetCurrentDir(tempDirPath))
259370b324cSopenharmony_ci    return 1;
260370b324cSopenharmony_ci  #endif
261370b324cSopenharmony_ci
262370b324cSopenharmony_ci  HANDLE hProcess = NULL;
263370b324cSopenharmony_ci#ifdef MY_SHELL_EXECUTE
264370b324cSopenharmony_ci  if (!executeFile.IsEmpty())
265370b324cSopenharmony_ci  {
266370b324cSopenharmony_ci    CSysString filePath (GetSystemString(executeFile));
267370b324cSopenharmony_ci    SHELLEXECUTEINFO execInfo;
268370b324cSopenharmony_ci    execInfo.cbSize = sizeof(execInfo);
269370b324cSopenharmony_ci    execInfo.fMask = SEE_MASK_NOCLOSEPROCESS
270370b324cSopenharmony_ci      #ifndef UNDER_CE
271370b324cSopenharmony_ci      | SEE_MASK_FLAG_DDEWAIT
272370b324cSopenharmony_ci      #endif
273370b324cSopenharmony_ci      ;
274370b324cSopenharmony_ci    execInfo.hwnd = NULL;
275370b324cSopenharmony_ci    execInfo.lpVerb = NULL;
276370b324cSopenharmony_ci    execInfo.lpFile = filePath;
277370b324cSopenharmony_ci
278370b324cSopenharmony_ci    if (!switches.IsEmpty())
279370b324cSopenharmony_ci    {
280370b324cSopenharmony_ci      executeParameters.Add_Space_if_NotEmpty();
281370b324cSopenharmony_ci      executeParameters += switches;
282370b324cSopenharmony_ci    }
283370b324cSopenharmony_ci
284370b324cSopenharmony_ci    const CSysString parametersSys (GetSystemString(executeParameters));
285370b324cSopenharmony_ci    if (parametersSys.IsEmpty())
286370b324cSopenharmony_ci      execInfo.lpParameters = NULL;
287370b324cSopenharmony_ci    else
288370b324cSopenharmony_ci      execInfo.lpParameters = parametersSys;
289370b324cSopenharmony_ci
290370b324cSopenharmony_ci    execInfo.lpDirectory = NULL;
291370b324cSopenharmony_ci    execInfo.nShow = SW_SHOWNORMAL;
292370b324cSopenharmony_ci    execInfo.hProcess = NULL;
293370b324cSopenharmony_ci    /* BOOL success = */ ::ShellExecuteEx(&execInfo);
294370b324cSopenharmony_ci    UINT32 result = (UINT32)(UINT_PTR)execInfo.hInstApp;
295370b324cSopenharmony_ci    if (result <= 32)
296370b324cSopenharmony_ci    {
297370b324cSopenharmony_ci      if (!assumeYes)
298370b324cSopenharmony_ci        ShowErrorMessage(L"Cannot open file");
299370b324cSopenharmony_ci      return 1;
300370b324cSopenharmony_ci    }
301370b324cSopenharmony_ci    hProcess = execInfo.hProcess;
302370b324cSopenharmony_ci  }
303370b324cSopenharmony_ci  else
304370b324cSopenharmony_ci#endif
305370b324cSopenharmony_ci  {
306370b324cSopenharmony_ci    if (appLaunched.IsEmpty())
307370b324cSopenharmony_ci    {
308370b324cSopenharmony_ci      appLaunched = L"setup.exe";
309370b324cSopenharmony_ci      if (!NFind::DoesFileExist_FollowLink(us2fs(appLaunched)))
310370b324cSopenharmony_ci      {
311370b324cSopenharmony_ci        if (!assumeYes)
312370b324cSopenharmony_ci          ShowErrorMessage(L"Cannot find setup.exe");
313370b324cSopenharmony_ci        return 1;
314370b324cSopenharmony_ci      }
315370b324cSopenharmony_ci    }
316370b324cSopenharmony_ci
317370b324cSopenharmony_ci    {
318370b324cSopenharmony_ci      FString s2 = tempDirPath;
319370b324cSopenharmony_ci      NName::NormalizeDirPathPrefix(s2);
320370b324cSopenharmony_ci      appLaunched.Replace(L"%%T" WSTRING_PATH_SEPARATOR, fs2us(s2));
321370b324cSopenharmony_ci    }
322370b324cSopenharmony_ci
323370b324cSopenharmony_ci    const UString appNameForError = appLaunched; // actually we need to rtemove parameters also
324370b324cSopenharmony_ci
325370b324cSopenharmony_ci    appLaunched.Replace(L"%%T", fs2us(tempDirPath));
326370b324cSopenharmony_ci
327370b324cSopenharmony_ci    if (!switches.IsEmpty())
328370b324cSopenharmony_ci    {
329370b324cSopenharmony_ci      appLaunched.Add_Space();
330370b324cSopenharmony_ci      appLaunched += switches;
331370b324cSopenharmony_ci    }
332370b324cSopenharmony_ci    STARTUPINFO startupInfo;
333370b324cSopenharmony_ci    startupInfo.cb = sizeof(startupInfo);
334370b324cSopenharmony_ci    startupInfo.lpReserved = NULL;
335370b324cSopenharmony_ci    startupInfo.lpDesktop = NULL;
336370b324cSopenharmony_ci    startupInfo.lpTitle = NULL;
337370b324cSopenharmony_ci    startupInfo.dwFlags = 0;
338370b324cSopenharmony_ci    startupInfo.cbReserved2 = 0;
339370b324cSopenharmony_ci    startupInfo.lpReserved2 = NULL;
340370b324cSopenharmony_ci
341370b324cSopenharmony_ci    PROCESS_INFORMATION processInformation;
342370b324cSopenharmony_ci
343370b324cSopenharmony_ci    const CSysString appLaunchedSys (GetSystemString(dirPrefix + appLaunched));
344370b324cSopenharmony_ci
345370b324cSopenharmony_ci    const BOOL createResult = CreateProcess(NULL,
346370b324cSopenharmony_ci        appLaunchedSys.Ptr_non_const(),
347370b324cSopenharmony_ci        NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */,
348370b324cSopenharmony_ci        &startupInfo, &processInformation);
349370b324cSopenharmony_ci    if (createResult == 0)
350370b324cSopenharmony_ci    {
351370b324cSopenharmony_ci      if (!assumeYes)
352370b324cSopenharmony_ci      {
353370b324cSopenharmony_ci        // we print name of exe file, if error message is
354370b324cSopenharmony_ci        // ERROR_BAD_EXE_FORMAT: "%1 is not a valid Win32 application".
355370b324cSopenharmony_ci        ShowErrorMessageSpec(appNameForError);
356370b324cSopenharmony_ci      }
357370b324cSopenharmony_ci      return 1;
358370b324cSopenharmony_ci    }
359370b324cSopenharmony_ci    ::CloseHandle(processInformation.hThread);
360370b324cSopenharmony_ci    hProcess = processInformation.hProcess;
361370b324cSopenharmony_ci  }
362370b324cSopenharmony_ci  if (hProcess)
363370b324cSopenharmony_ci  {
364370b324cSopenharmony_ci    WaitForSingleObject(hProcess, INFINITE);
365370b324cSopenharmony_ci    ::CloseHandle(hProcess);
366370b324cSopenharmony_ci  }
367370b324cSopenharmony_ci  return 0;
368370b324cSopenharmony_ci}
369