xref: /aosp_15_r20/external/lzma/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // Main.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../../C/DllSecur.h"
6 
7 #include "../../../Common/MyWindows.h"
8 #include "../../../Common/MyInitGuid.h"
9 
10 #include "../../../Common/CommandLineParser.h"
11 #include "../../../Common/StringConvert.h"
12 #include "../../../Common/TextConfig.h"
13 
14 #include "../../../Windows/DLL.h"
15 #include "../../../Windows/ErrorMsg.h"
16 #include "../../../Windows/FileDir.h"
17 #include "../../../Windows/FileFind.h"
18 #include "../../../Windows/FileIO.h"
19 #include "../../../Windows/FileName.h"
20 #include "../../../Windows/NtCheck.h"
21 #include "../../../Windows/ResourceString.h"
22 
23 #include "../../UI/Explorer/MyMessages.h"
24 
25 #include "ExtractEngine.h"
26 
27 #include "resource.h"
28 
29 using namespace NWindows;
30 using namespace NFile;
31 using namespace NDir;
32 
33 extern
34 HINSTANCE g_hInstance;
35 HINSTANCE g_hInstance;
36 extern
37 bool g_DisableUserQuestions;
38 bool g_DisableUserQuestions;
39 
40 static CFSTR const kTempDirPrefix = FTEXT("7zS");
41 
42 #define MY_SHELL_EXECUTE
43 
ReadDataString(CFSTR fileName,LPCSTR startID,LPCSTR endID,AString & stringResult)44 static bool ReadDataString(CFSTR fileName, LPCSTR startID,
45     LPCSTR endID, AString &stringResult)
46 {
47   stringResult.Empty();
48   NIO::CInFile inFile;
49   if (!inFile.Open(fileName))
50     return false;
51   const size_t kBufferSize = (1 << 12);
52 
53   Byte buffer[kBufferSize];
54   const unsigned signatureStartSize = MyStringLen(startID);
55   const unsigned signatureEndSize = MyStringLen(endID);
56 
57   size_t numBytesPrev = 0;
58   bool writeMode = false;
59   UInt64 posTotal = 0;
60   for (;;)
61   {
62     if (posTotal > (1 << 20))
63       return (stringResult.IsEmpty());
64     const size_t numReadBytes = kBufferSize - numBytesPrev;
65     size_t processedSize;
66     if (!inFile.ReadFull(buffer + numBytesPrev, numReadBytes, processedSize))
67       return false;
68     if (processedSize == 0)
69       return true;
70     const size_t numBytesInBuffer = numBytesPrev + processedSize;
71     UInt32 pos = 0;
72     for (;;)
73     {
74       if (writeMode)
75       {
76         if (pos + signatureEndSize > numBytesInBuffer)
77           break;
78         if (memcmp(buffer + pos, endID, signatureEndSize) == 0)
79           return true;
80         const Byte b = buffer[pos];
81         if (b == 0)
82           return false;
83         stringResult += (char)b;
84         pos++;
85       }
86       else
87       {
88         if (pos + signatureStartSize > numBytesInBuffer)
89           break;
90         if (memcmp(buffer + pos, startID, signatureStartSize) == 0)
91         {
92           writeMode = true;
93           pos += signatureStartSize;
94         }
95         else
96           pos++;
97       }
98     }
99     numBytesPrev = numBytesInBuffer - pos;
100     posTotal += pos;
101     memmove(buffer, buffer + pos, numBytesPrev);
102   }
103 }
104 
105 static char kStartID[] = { ',','!','@','I','n','s','t','a','l','l','@','!','U','T','F','-','8','!', 0 };
106 static char kEndID[]   = { ',','!','@','I','n','s','t','a','l','l','E','n','d','@','!', 0 };
107 
108 static struct CInstallIDInit
109 {
CInstallIDInitCInstallIDInit110   CInstallIDInit()
111   {
112     kStartID[0] = ';';
113     kEndID[0] = ';';
114   }
115 } g_CInstallIDInit;
116 
117 
118 #if defined(_WIN32) && defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
119 #define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return 1;
120 #endif
121 
ShowErrorMessageSpec(const UString & name)122 static void ShowErrorMessageSpec(const UString &name)
123 {
124   UString message = NError::MyFormatMessage(::GetLastError());
125   const int pos = message.Find(L"%1");
126   if (pos >= 0)
127   {
128     message.Delete((unsigned)pos, 2);
129     message.Insert((unsigned)pos, name);
130   }
131   ShowErrorMessage(NULL, message);
132 }
133 
WinMain(HINSTANCE hInstance,HINSTANCE,LPWSTR,int)134 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
135     #ifdef UNDER_CE
136     LPWSTR
137     #else
138     LPSTR
139     #endif
140     /* lpCmdLine */,int /* nCmdShow */)
141 {
142   g_hInstance = (HINSTANCE)hInstance;
143 
144   NT_CHECK
145 
146   #ifdef _WIN32
147   LoadSecurityDlls();
148   #endif
149 
150   // InitCommonControls();
151 
152   UString archiveName, switches;
153   #ifdef MY_SHELL_EXECUTE
154   UString executeFile, executeParameters;
155   #endif
156   NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches);
157 
158   FString fullPath;
159   NDLL::MyGetModuleFileName(fullPath);
160 
161   switches.Trim();
162   bool assumeYes = false;
163   if (switches.IsPrefixedBy_Ascii_NoCase("-y"))
164   {
165     assumeYes = true;
166     switches = switches.Ptr(2);
167     switches.Trim();
168   }
169 
170   AString config;
171   if (!ReadDataString(fullPath, kStartID, kEndID, config))
172   {
173     if (!assumeYes)
174       ShowErrorMessage(L"Can't load config info");
175     return 1;
176   }
177 
178   UString dirPrefix ("." STRING_PATH_SEPARATOR);
179   UString appLaunched;
180   bool showProgress = true;
181   if (!config.IsEmpty())
182   {
183     CObjectVector<CTextConfigPair> pairs;
184     if (!GetTextConfig(config, pairs))
185     {
186       if (!assumeYes)
187         ShowErrorMessage(L"Config failed");
188       return 1;
189     }
190     const UString friendlyName = GetTextConfigValue(pairs, "Title");
191     const UString installPrompt = GetTextConfigValue(pairs, "BeginPrompt");
192     const UString progress = GetTextConfigValue(pairs, "Progress");
193     if (progress.IsEqualTo_Ascii_NoCase("no"))
194       showProgress = false;
195     const int index = FindTextConfigItem(pairs, "Directory");
196     if (index >= 0)
197       dirPrefix = pairs[index].String;
198     if (!installPrompt.IsEmpty() && !assumeYes)
199     {
200       if (MessageBoxW(NULL, installPrompt, friendlyName, MB_YESNO |
201           MB_ICONQUESTION) != IDYES)
202         return 0;
203     }
204     appLaunched = GetTextConfigValue(pairs, "RunProgram");
205 
206     #ifdef MY_SHELL_EXECUTE
207     executeFile = GetTextConfigValue(pairs, "ExecuteFile");
208     executeParameters = GetTextConfigValue(pairs, "ExecuteParameters");
209     #endif
210   }
211 
212   CTempDir tempDir;
213   if (!tempDir.Create(kTempDirPrefix))
214   {
215     if (!assumeYes)
216       ShowErrorMessage(L"Cannot create temp folder archive");
217     return 1;
218   }
219 
220   CCodecs *codecs = new CCodecs;
221   CMyComPtr<IUnknown> compressCodecsInfo = codecs;
222   {
223     const HRESULT result = codecs->Load();
224     if (result != S_OK)
225     {
226       ShowErrorMessage(L"Cannot load codecs");
227       return 1;
228     }
229   }
230 
231   const FString tempDirPath = tempDir.GetPath();
232   // tempDirPath = L"M:\\1\\"; // to test low disk space
233   {
234     bool isCorrupt = false;
235     UString errorMessage;
236     HRESULT result = ExtractArchive(codecs, fullPath, tempDirPath, showProgress,
237       isCorrupt, errorMessage);
238 
239     if (result != S_OK)
240     {
241       if (!assumeYes)
242       {
243         if (result == S_FALSE || isCorrupt)
244         {
245           NWindows::MyLoadString(IDS_EXTRACTION_ERROR_MESSAGE, errorMessage);
246           result = E_FAIL;
247         }
248         if (result != E_ABORT)
249         {
250           if (errorMessage.IsEmpty())
251             errorMessage = NError::MyFormatMessage(result);
252           ::MessageBoxW(NULL, errorMessage, NWindows::MyLoadString(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR);
253         }
254       }
255       return 1;
256     }
257   }
258 
259   #ifndef UNDER_CE
260   CCurrentDirRestorer currentDirRestorer;
261   if (!SetCurrentDir(tempDirPath))
262     return 1;
263   #endif
264 
265   HANDLE hProcess = NULL;
266 #ifdef MY_SHELL_EXECUTE
267   if (!executeFile.IsEmpty())
268   {
269     CSysString filePath (GetSystemString(executeFile));
270     SHELLEXECUTEINFO execInfo;
271     execInfo.cbSize = sizeof(execInfo);
272     execInfo.fMask = SEE_MASK_NOCLOSEPROCESS
273       #ifndef UNDER_CE
274       | SEE_MASK_FLAG_DDEWAIT
275       #endif
276       ;
277     execInfo.hwnd = NULL;
278     execInfo.lpVerb = NULL;
279     execInfo.lpFile = filePath;
280 
281     if (!switches.IsEmpty())
282     {
283       executeParameters.Add_Space_if_NotEmpty();
284       executeParameters += switches;
285     }
286 
287     const CSysString parametersSys (GetSystemString(executeParameters));
288     if (parametersSys.IsEmpty())
289       execInfo.lpParameters = NULL;
290     else
291       execInfo.lpParameters = parametersSys;
292 
293     execInfo.lpDirectory = NULL;
294     execInfo.nShow = SW_SHOWNORMAL;
295     execInfo.hProcess = NULL;
296     /* BOOL success = */ ::ShellExecuteEx(&execInfo);
297     UINT32 result = (UINT32)(UINT_PTR)execInfo.hInstApp;
298     if (result <= 32)
299     {
300       if (!assumeYes)
301         ShowErrorMessage(L"Cannot open file");
302       return 1;
303     }
304     hProcess = execInfo.hProcess;
305   }
306   else
307 #endif
308   {
309     if (appLaunched.IsEmpty())
310     {
311       appLaunched = L"setup.exe";
312       if (!NFind::DoesFileExist_FollowLink(us2fs(appLaunched)))
313       {
314         if (!assumeYes)
315           ShowErrorMessage(L"Cannot find setup.exe");
316         return 1;
317       }
318     }
319 
320     {
321       FString s2 = tempDirPath;
322       NName::NormalizeDirPathPrefix(s2);
323       appLaunched.Replace(L"%%T" WSTRING_PATH_SEPARATOR, fs2us(s2));
324     }
325 
326     const UString appNameForError = appLaunched; // actually we need to rtemove parameters also
327 
328     appLaunched.Replace(L"%%T", fs2us(tempDirPath));
329 
330     if (!switches.IsEmpty())
331     {
332       appLaunched.Add_Space();
333       appLaunched += switches;
334     }
335     STARTUPINFO startupInfo;
336     startupInfo.cb = sizeof(startupInfo);
337     startupInfo.lpReserved = NULL;
338     startupInfo.lpDesktop = NULL;
339     startupInfo.lpTitle = NULL;
340     startupInfo.dwFlags = 0;
341     startupInfo.cbReserved2 = 0;
342     startupInfo.lpReserved2 = NULL;
343 
344     PROCESS_INFORMATION processInformation;
345 
346     const CSysString appLaunchedSys (GetSystemString(dirPrefix + appLaunched));
347 
348     const BOOL createResult = CreateProcess(NULL,
349         appLaunchedSys.Ptr_non_const(),
350         NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */,
351         &startupInfo, &processInformation);
352     if (createResult == 0)
353     {
354       if (!assumeYes)
355       {
356         // we print name of exe file, if error message is
357         // ERROR_BAD_EXE_FORMAT: "%1 is not a valid Win32 application".
358         ShowErrorMessageSpec(appNameForError);
359       }
360       return 1;
361     }
362     ::CloseHandle(processInformation.hThread);
363     hProcess = processInformation.hProcess;
364   }
365   if (hProcess)
366   {
367     WaitForSingleObject(hProcess, INFINITE);
368     ::CloseHandle(hProcess);
369   }
370   return 0;
371 }
372