Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / Bundles / SFXSetup / Main.cpp
1 // Main.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include "Common/MyInitGuid.h"\r
6 \r
7 #include "Common/CommandLineParser.h"\r
8 #include "Common/StringConvert.h"\r
9 #include "Common/TextConfig.h"\r
10 \r
11 #include "Windows/DLL.h"\r
12 #include "Windows/FileDir.h"\r
13 #include "Windows/FileFind.h"\r
14 #include "Windows/FileIO.h"\r
15 #include "Windows/NtCheck.h"\r
16 #include "Windows/ResourceString.h"\r
17 \r
18 #include "../../UI/Explorer/MyMessages.h"\r
19 \r
20 #include "ExtractEngine.h"\r
21 \r
22 #include "resource.h"\r
23 \r
24 using namespace NWindows;\r
25 \r
26 HINSTANCE g_hInstance;\r
27 \r
28 static LPCTSTR kTempDirPrefix = TEXT("7zS");\r
29 \r
30 #define _SHELL_EXECUTE\r
31 \r
32 static bool ReadDataString(LPCWSTR fileName, LPCSTR startID,\r
33     LPCSTR endID, AString &stringResult)\r
34 {\r
35   stringResult.Empty();\r
36   NFile::NIO::CInFile inFile;\r
37   if (!inFile.Open(fileName))\r
38     return false;\r
39   const int kBufferSize = (1 << 12);\r
40 \r
41   Byte buffer[kBufferSize];\r
42   int signatureStartSize = MyStringLen(startID);\r
43   int signatureEndSize = MyStringLen(endID);\r
44   \r
45   UInt32 numBytesPrev = 0;\r
46   bool writeMode = false;\r
47   UInt64 posTotal = 0;\r
48   for (;;)\r
49   {\r
50     if (posTotal > (1 << 20))\r
51       return (stringResult.IsEmpty());\r
52     UInt32 numReadBytes = kBufferSize - numBytesPrev;\r
53     UInt32 processedSize;\r
54     if (!inFile.Read(buffer + numBytesPrev, numReadBytes, processedSize))\r
55       return false;\r
56     if (processedSize == 0)\r
57       return true;\r
58     UInt32 numBytesInBuffer = numBytesPrev + processedSize;\r
59     UInt32 pos = 0;\r
60     for (;;)\r
61     {\r
62       if (writeMode)\r
63       {\r
64         if (pos > numBytesInBuffer - signatureEndSize)\r
65           break;\r
66         if (memcmp(buffer + pos, endID, signatureEndSize) == 0)\r
67           return true;\r
68         char b = buffer[pos];\r
69         if (b == 0)\r
70           return false;\r
71         stringResult += b;\r
72         pos++;\r
73       }\r
74       else\r
75       {\r
76         if (pos > numBytesInBuffer - signatureStartSize)\r
77           break;\r
78         if (memcmp(buffer + pos, startID, signatureStartSize) == 0)\r
79         {\r
80           writeMode = true;\r
81           pos += signatureStartSize;\r
82         }\r
83         else\r
84           pos++;\r
85       }\r
86     }\r
87     numBytesPrev = numBytesInBuffer - pos;\r
88     posTotal += pos;\r
89     memmove(buffer, buffer + pos, numBytesPrev);\r
90   }\r
91 }\r
92 \r
93 static char kStartID[] = ",!@Install@!UTF-8!";\r
94 static char kEndID[] = ",!@InstallEnd@!";\r
95 \r
96 class CInstallIDInit\r
97 {\r
98 public:\r
99   CInstallIDInit()\r
100   {\r
101     kStartID[0] = ';';\r
102     kEndID[0] = ';';\r
103   };\r
104 } g_CInstallIDInit;\r
105 \r
106 \r
107 #ifndef UNDER_CE\r
108 class CCurrentDirRestorer\r
109 {\r
110   CSysString m_CurrentDirectory;\r
111 public:\r
112   CCurrentDirRestorer() { NFile::NDirectory::MyGetCurrentDirectory(m_CurrentDirectory); }\r
113   ~CCurrentDirRestorer() { RestoreDirectory();}\r
114   bool RestoreDirectory() { return BOOLToBool(::SetCurrentDirectory(m_CurrentDirectory)); }\r
115 };\r
116 #endif\r
117 \r
118 #define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return 1;\r
119 \r
120 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,\r
121     #ifdef UNDER_CE\r
122     LPWSTR\r
123     #else\r
124     LPSTR\r
125     #endif\r
126     /* lpCmdLine */,int /* nCmdShow */)\r
127 {\r
128   g_hInstance = (HINSTANCE)hInstance;\r
129 \r
130   NT_CHECK\r
131 \r
132   // InitCommonControls();\r
133 \r
134   UString archiveName, switches;\r
135   #ifdef _SHELL_EXECUTE\r
136   UString executeFile, executeParameters;\r
137   #endif\r
138   NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches);\r
139 \r
140   UString fullPath;\r
141   NDLL::MyGetModuleFileName(g_hInstance, fullPath);\r
142 \r
143   switches.Trim();\r
144   bool assumeYes = false;\r
145   if (switches.Left(2).CompareNoCase(UString(L"-y")) == 0)\r
146   {\r
147     assumeYes = true;\r
148     switches = switches.Mid(2);\r
149     switches.Trim();\r
150   }\r
151 \r
152   AString config;\r
153   if (!ReadDataString(fullPath, kStartID, kEndID, config))\r
154   {\r
155     if (!assumeYes)\r
156       ShowErrorMessage(L"Can't load config info");\r
157     return 1;\r
158   }\r
159 \r
160   UString dirPrefix = L"." WSTRING_PATH_SEPARATOR;\r
161   UString appLaunched;\r
162   bool showProgress = true;\r
163   if (!config.IsEmpty())\r
164   {\r
165     CObjectVector<CTextConfigPair> pairs;\r
166     if (!GetTextConfig(config, pairs))\r
167     {\r
168       if (!assumeYes)\r
169         ShowErrorMessage(L"Config failed");\r
170       return 1;\r
171     }\r
172     UString friendlyName = GetTextConfigValue(pairs, L"Title");\r
173     UString installPrompt = GetTextConfigValue(pairs, L"BeginPrompt");\r
174     UString progress = GetTextConfigValue(pairs, L"Progress");\r
175     if (progress.CompareNoCase(L"no") == 0)\r
176       showProgress = false;\r
177     int index = FindTextConfigItem(pairs, L"Directory");\r
178     if (index >= 0)\r
179       dirPrefix = pairs[index].String;\r
180     if (!installPrompt.IsEmpty() && !assumeYes)\r
181     {\r
182       if (MessageBoxW(0, installPrompt, friendlyName, MB_YESNO |\r
183           MB_ICONQUESTION) != IDYES)\r
184         return 0;\r
185     }\r
186     appLaunched = GetTextConfigValue(pairs, L"RunProgram");\r
187     \r
188     #ifdef _SHELL_EXECUTE\r
189     executeFile = GetTextConfigValue(pairs, L"ExecuteFile");\r
190     executeParameters = GetTextConfigValue(pairs, L"ExecuteParameters") + switches;\r
191     #endif\r
192   }\r
193 \r
194   NFile::NDirectory::CTempDirectory tempDir;\r
195   if (!tempDir.Create(kTempDirPrefix))\r
196   {\r
197     if (!assumeYes)\r
198       ShowErrorMessage(L"Can not create temp folder archive");\r
199     return 1;\r
200   }\r
201 \r
202   CCodecs *codecs = new CCodecs;\r
203   CMyComPtr<IUnknown> compressCodecsInfo = codecs;\r
204   HRESULT result = codecs->Load();\r
205   if (result != S_OK)\r
206   {\r
207     ShowErrorMessage(L"Can not load codecs");\r
208     return 1;\r
209   }\r
210 \r
211   UString tempDirPath = GetUnicodeString(tempDir.GetPath());\r
212   {\r
213     bool isCorrupt = false;\r
214     UString errorMessage;\r
215     HRESULT result = ExtractArchive(codecs, fullPath, tempDirPath, showProgress,\r
216       isCorrupt, errorMessage);\r
217     \r
218     if (result != S_OK)\r
219     {\r
220       if (!assumeYes)\r
221       {\r
222         if (result == S_FALSE || isCorrupt)\r
223         {\r
224           errorMessage = NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_MESSAGE);\r
225           result = E_FAIL;\r
226         }\r
227         if (result != E_ABORT && !errorMessage.IsEmpty())\r
228           ::MessageBoxW(0, errorMessage, NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR);\r
229       }\r
230       return 1;\r
231     }\r
232   }\r
233 \r
234   #ifndef UNDER_CE\r
235   CCurrentDirRestorer currentDirRestorer;\r
236   if (!SetCurrentDirectory(tempDir.GetPath()))\r
237     return 1;\r
238   #endif\r
239   \r
240   HANDLE hProcess = 0;\r
241 #ifdef _SHELL_EXECUTE\r
242   if (!executeFile.IsEmpty())\r
243   {\r
244     CSysString filePath = GetSystemString(executeFile);\r
245     SHELLEXECUTEINFO execInfo;\r
246     execInfo.cbSize = sizeof(execInfo);\r
247     execInfo.fMask = SEE_MASK_NOCLOSEPROCESS\r
248       #ifndef UNDER_CE\r
249       | SEE_MASK_FLAG_DDEWAIT\r
250       #endif\r
251       ;\r
252     execInfo.hwnd = NULL;\r
253     execInfo.lpVerb = NULL;\r
254     execInfo.lpFile = filePath;\r
255 \r
256     if (!switches.IsEmpty())\r
257       executeParameters += switches;\r
258 \r
259     CSysString parametersSys = GetSystemString(executeParameters);\r
260     if (parametersSys.IsEmpty())\r
261       execInfo.lpParameters = NULL;\r
262     else\r
263       execInfo.lpParameters = parametersSys;\r
264 \r
265     execInfo.lpDirectory = NULL;\r
266     execInfo.nShow = SW_SHOWNORMAL;\r
267     execInfo.hProcess = 0;\r
268     /* BOOL success = */ ::ShellExecuteEx(&execInfo);\r
269     UINT32 result = (UINT32)(UINT_PTR)execInfo.hInstApp;\r
270     if(result <= 32)\r
271     {\r
272       if (!assumeYes)\r
273         ShowErrorMessage(L"Can not open file");\r
274       return 1;\r
275     }\r
276     hProcess = execInfo.hProcess;\r
277   }\r
278   else\r
279 #endif\r
280   {\r
281     if (appLaunched.IsEmpty())\r
282     {\r
283       appLaunched = L"setup.exe";\r
284       if (!NFile::NFind::DoesFileExist(GetSystemString(appLaunched)))\r
285       {\r
286         if (!assumeYes)\r
287           ShowErrorMessage(L"Can not find setup.exe");\r
288         return 1;\r
289       }\r
290     }\r
291     \r
292     {\r
293       UString s2 = tempDirPath;\r
294       NFile::NName::NormalizeDirPathPrefix(s2);\r
295       appLaunched.Replace(L"%%T" WSTRING_PATH_SEPARATOR, s2);\r
296     }\r
297     \r
298     appLaunched.Replace(L"%%T", tempDirPath);\r
299 \r
300     if (!switches.IsEmpty())\r
301     {\r
302       appLaunched += L' ';\r
303       appLaunched += switches;\r
304     }\r
305     STARTUPINFO startupInfo;\r
306     startupInfo.cb = sizeof(startupInfo);\r
307     startupInfo.lpReserved = 0;\r
308     startupInfo.lpDesktop = 0;\r
309     startupInfo.lpTitle = 0;\r
310     startupInfo.dwFlags = 0;\r
311     startupInfo.cbReserved2 = 0;\r
312     startupInfo.lpReserved2 = 0;\r
313     \r
314     PROCESS_INFORMATION processInformation;\r
315     \r
316     CSysString appLaunchedSys = GetSystemString(dirPrefix + appLaunched);\r
317     \r
318     BOOL createResult = CreateProcess(NULL, (LPTSTR)(LPCTSTR)appLaunchedSys,\r
319       NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */,\r
320       &startupInfo, &processInformation);\r
321     if (createResult == 0)\r
322     {\r
323       if (!assumeYes)\r
324         ShowLastErrorMessage();\r
325       return 1;\r
326     }\r
327     ::CloseHandle(processInformation.hThread);\r
328     hProcess = processInformation.hProcess;\r
329   }\r
330   if (hProcess != 0)\r
331   {\r
332     WaitForSingleObject(hProcess, INFINITE);\r
333     ::CloseHandle(hProcess);\r
334   }\r
335   return 0;\r
336 }\r