ce188d4d |
1 | /* SfxSetup.c - 7z SFX Setup\r |
2 | 2016-05-16 : Igor Pavlov : Public domain */\r |
3 | \r |
4 | #include "Precomp.h"\r |
5 | \r |
6 | #ifndef UNICODE\r |
7 | #define UNICODE\r |
8 | #endif\r |
9 | \r |
10 | #ifndef _UNICODE\r |
11 | #define _UNICODE\r |
12 | #endif\r |
13 | \r |
14 | #ifdef _CONSOLE\r |
15 | #include <stdio.h>\r |
16 | #endif\r |
17 | \r |
18 | #include "../../7z.h"\r |
19 | #include "../../7zAlloc.h"\r |
20 | #include "../../7zCrc.h"\r |
21 | #include "../../7zFile.h"\r |
22 | #include "../../CpuArch.h"\r |
23 | #include "../../DllSecur.h"\r |
24 | \r |
25 | #define k_EXE_ExtIndex 2\r |
26 | \r |
27 | static const char * const kExts[] =\r |
28 | {\r |
29 | "bat"\r |
30 | , "cmd"\r |
31 | , "exe"\r |
32 | , "inf"\r |
33 | , "msi"\r |
34 | #ifdef UNDER_CE\r |
35 | , "cab"\r |
36 | #endif\r |
37 | , "html"\r |
38 | , "htm"\r |
39 | };\r |
40 | \r |
41 | static const char * const kNames[] =\r |
42 | {\r |
43 | "setup"\r |
44 | , "install"\r |
45 | , "run"\r |
46 | , "start"\r |
47 | };\r |
48 | \r |
49 | static unsigned FindExt(const wchar_t *s, unsigned *extLen)\r |
50 | {\r |
51 | unsigned len = (unsigned)wcslen(s);\r |
52 | unsigned i;\r |
53 | for (i = len; i > 0; i--)\r |
54 | {\r |
55 | if (s[i - 1] == '.')\r |
56 | {\r |
57 | *extLen = len - i;\r |
58 | return i - 1;\r |
59 | }\r |
60 | }\r |
61 | *extLen = 0;\r |
62 | return len;\r |
63 | }\r |
64 | \r |
65 | #define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) -= 0x20 : (c)))\r |
66 | \r |
67 | static unsigned FindItem(const char * const *items, unsigned num, const wchar_t *s, unsigned len)\r |
68 | {\r |
69 | unsigned i;\r |
70 | for (i = 0; i < num; i++)\r |
71 | {\r |
72 | const char *item = items[i];\r |
73 | unsigned itemLen = (unsigned)strlen(item);\r |
74 | unsigned j;\r |
75 | if (len != itemLen)\r |
76 | continue;\r |
77 | for (j = 0; j < len; j++)\r |
78 | {\r |
79 | unsigned c = (Byte)item[j];\r |
80 | if (c != s[j] && MAKE_CHAR_UPPER(c) != s[j])\r |
81 | break;\r |
82 | }\r |
83 | if (j == len)\r |
84 | return i;\r |
85 | }\r |
86 | return i;\r |
87 | }\r |
88 | \r |
89 | #ifdef _CONSOLE\r |
90 | static BOOL WINAPI HandlerRoutine(DWORD ctrlType)\r |
91 | {\r |
92 | UNUSED_VAR(ctrlType);\r |
93 | return TRUE;\r |
94 | }\r |
95 | #endif\r |
96 | \r |
97 | static void PrintErrorMessage(const char *message)\r |
98 | {\r |
99 | #ifdef _CONSOLE\r |
100 | printf("\n7-Zip Error: %s\n", message);\r |
101 | #else\r |
102 | #ifdef UNDER_CE\r |
103 | WCHAR messageW[256 + 4];\r |
104 | unsigned i;\r |
105 | for (i = 0; i < 256 && message[i] != 0; i++)\r |
106 | messageW[i] = message[i];\r |
107 | messageW[i] = 0;\r |
108 | MessageBoxW(0, messageW, L"7-Zip Error", MB_ICONERROR);\r |
109 | #else\r |
110 | MessageBoxA(0, message, "7-Zip Error", MB_ICONERROR);\r |
111 | #endif\r |
112 | #endif\r |
113 | }\r |
114 | \r |
115 | static WRes MyCreateDir(const WCHAR *name)\r |
116 | {\r |
117 | return CreateDirectoryW(name, NULL) ? 0 : GetLastError();\r |
118 | }\r |
119 | \r |
120 | #ifdef UNDER_CE\r |
121 | #define kBufferSize (1 << 13)\r |
122 | #else\r |
123 | #define kBufferSize (1 << 15)\r |
124 | #endif\r |
125 | \r |
126 | #define kSignatureSearchLimit (1 << 22)\r |
127 | \r |
128 | static Bool FindSignature(CSzFile *stream, UInt64 *resPos)\r |
129 | {\r |
130 | Byte buf[kBufferSize];\r |
131 | size_t numPrevBytes = 0;\r |
132 | *resPos = 0;\r |
133 | for (;;)\r |
134 | {\r |
135 | size_t processed, pos;\r |
136 | if (*resPos > kSignatureSearchLimit)\r |
137 | return False;\r |
138 | processed = kBufferSize - numPrevBytes;\r |
139 | if (File_Read(stream, buf + numPrevBytes, &processed) != 0)\r |
140 | return False;\r |
141 | processed += numPrevBytes;\r |
142 | if (processed < k7zStartHeaderSize ||\r |
143 | (processed == k7zStartHeaderSize && numPrevBytes != 0))\r |
144 | return False;\r |
145 | processed -= k7zStartHeaderSize;\r |
146 | for (pos = 0; pos <= processed; pos++)\r |
147 | {\r |
148 | for (; pos <= processed && buf[pos] != '7'; pos++);\r |
149 | if (pos > processed)\r |
150 | break;\r |
151 | if (memcmp(buf + pos, k7zSignature, k7zSignatureSize) == 0)\r |
152 | if (CrcCalc(buf + pos + 12, 20) == GetUi32(buf + pos + 8))\r |
153 | {\r |
154 | *resPos += pos;\r |
155 | return True;\r |
156 | }\r |
157 | }\r |
158 | *resPos += processed;\r |
159 | numPrevBytes = k7zStartHeaderSize;\r |
160 | memmove(buf, buf + processed, k7zStartHeaderSize);\r |
161 | }\r |
162 | }\r |
163 | \r |
164 | static Bool DoesFileOrDirExist(const WCHAR *path)\r |
165 | {\r |
166 | WIN32_FIND_DATAW fd;\r |
167 | HANDLE handle;\r |
168 | handle = FindFirstFileW(path, &fd);\r |
169 | if (handle == INVALID_HANDLE_VALUE)\r |
170 | return False;\r |
171 | FindClose(handle);\r |
172 | return True;\r |
173 | }\r |
174 | \r |
175 | static WRes RemoveDirWithSubItems(WCHAR *path)\r |
176 | {\r |
177 | WIN32_FIND_DATAW fd;\r |
178 | HANDLE handle;\r |
179 | WRes res = 0;\r |
180 | size_t len = wcslen(path);\r |
181 | wcscpy(path + len, L"*");\r |
182 | handle = FindFirstFileW(path, &fd);\r |
183 | path[len] = L'\0';\r |
184 | if (handle == INVALID_HANDLE_VALUE)\r |
185 | return GetLastError();\r |
186 | \r |
187 | for (;;)\r |
188 | {\r |
189 | if (wcscmp(fd.cFileName, L".") != 0 &&\r |
190 | wcscmp(fd.cFileName, L"..") != 0)\r |
191 | {\r |
192 | wcscpy(path + len, fd.cFileName);\r |
193 | if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)\r |
194 | {\r |
195 | wcscat(path, WSTRING_PATH_SEPARATOR);\r |
196 | res = RemoveDirWithSubItems(path);\r |
197 | }\r |
198 | else\r |
199 | {\r |
200 | SetFileAttributesW(path, 0);\r |
201 | if (DeleteFileW(path) == 0)\r |
202 | res = GetLastError();\r |
203 | }\r |
204 | \r |
205 | if (res != 0)\r |
206 | break;\r |
207 | }\r |
208 | \r |
209 | if (!FindNextFileW(handle, &fd))\r |
210 | {\r |
211 | res = GetLastError();\r |
212 | if (res == ERROR_NO_MORE_FILES)\r |
213 | res = 0;\r |
214 | break;\r |
215 | }\r |
216 | }\r |
217 | \r |
218 | path[len] = L'\0';\r |
219 | FindClose(handle);\r |
220 | if (res == 0)\r |
221 | {\r |
222 | if (!RemoveDirectoryW(path))\r |
223 | res = GetLastError();\r |
224 | }\r |
225 | return res;\r |
226 | }\r |
227 | \r |
228 | #ifdef _CONSOLE\r |
229 | int MY_CDECL main()\r |
230 | #else\r |
231 | int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,\r |
232 | #ifdef UNDER_CE\r |
233 | LPWSTR\r |
234 | #else\r |
235 | LPSTR\r |
236 | #endif\r |
237 | lpCmdLine, int nCmdShow)\r |
238 | #endif\r |
239 | {\r |
240 | CFileInStream archiveStream;\r |
241 | CLookToRead lookStream;\r |
242 | CSzArEx db;\r |
243 | SRes res = SZ_OK;\r |
244 | ISzAlloc allocImp;\r |
245 | ISzAlloc allocTempImp;\r |
246 | WCHAR sfxPath[MAX_PATH + 2];\r |
247 | WCHAR path[MAX_PATH * 3 + 2];\r |
248 | #ifndef UNDER_CE\r |
249 | WCHAR workCurDir[MAX_PATH + 32];\r |
250 | #endif\r |
251 | size_t pathLen;\r |
252 | DWORD winRes;\r |
253 | const wchar_t *cmdLineParams;\r |
254 | const char *errorMessage = NULL;\r |
255 | Bool useShellExecute = True;\r |
256 | DWORD exitCode = 0;\r |
257 | \r |
258 | LoadSecurityDlls();\r |
259 | \r |
260 | #ifdef _CONSOLE\r |
261 | SetConsoleCtrlHandler(HandlerRoutine, TRUE);\r |
262 | #else\r |
263 | UNUSED_VAR(hInstance);\r |
264 | UNUSED_VAR(hPrevInstance);\r |
265 | UNUSED_VAR(lpCmdLine);\r |
266 | UNUSED_VAR(nCmdShow);\r |
267 | #endif\r |
268 | \r |
269 | CrcGenerateTable();\r |
270 | \r |
271 | allocImp.Alloc = SzAlloc;\r |
272 | allocImp.Free = SzFree;\r |
273 | \r |
274 | allocTempImp.Alloc = SzAllocTemp;\r |
275 | allocTempImp.Free = SzFreeTemp;\r |
276 | \r |
277 | FileInStream_CreateVTable(&archiveStream);\r |
278 | LookToRead_CreateVTable(&lookStream, False);\r |
279 | \r |
280 | winRes = GetModuleFileNameW(NULL, sfxPath, MAX_PATH);\r |
281 | if (winRes == 0 || winRes > MAX_PATH)\r |
282 | return 1;\r |
283 | {\r |
284 | cmdLineParams = GetCommandLineW();\r |
285 | #ifndef UNDER_CE\r |
286 | {\r |
287 | Bool quoteMode = False;\r |
288 | for (;; cmdLineParams++)\r |
289 | {\r |
290 | wchar_t c = *cmdLineParams;\r |
291 | if (c == L'\"')\r |
292 | quoteMode = !quoteMode;\r |
293 | else if (c == 0 || (c == L' ' && !quoteMode))\r |
294 | break;\r |
295 | }\r |
296 | }\r |
297 | #endif\r |
298 | }\r |
299 | \r |
300 | {\r |
301 | unsigned i;\r |
302 | DWORD d;\r |
303 | winRes = GetTempPathW(MAX_PATH, path);\r |
304 | if (winRes == 0 || winRes > MAX_PATH)\r |
305 | return 1;\r |
306 | pathLen = wcslen(path);\r |
307 | d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId();\r |
308 | \r |
309 | for (i = 0;; i++, d += GetTickCount())\r |
310 | {\r |
311 | if (i >= 100)\r |
312 | {\r |
313 | res = SZ_ERROR_FAIL;\r |
314 | break;\r |
315 | }\r |
316 | wcscpy(path + pathLen, L"7z");\r |
317 | \r |
318 | {\r |
319 | wchar_t *s = path + wcslen(path);\r |
320 | UInt32 value = d;\r |
321 | unsigned k;\r |
322 | for (k = 0; k < 8; k++)\r |
323 | {\r |
324 | unsigned t = value & 0xF;\r |
325 | value >>= 4;\r |
326 | s[7 - k] = (wchar_t)((t < 10) ? ('0' + t) : ('A' + (t - 10)));\r |
327 | }\r |
328 | s[k] = '\0';\r |
329 | }\r |
330 | \r |
331 | if (DoesFileOrDirExist(path))\r |
332 | continue;\r |
333 | if (CreateDirectoryW(path, NULL))\r |
334 | {\r |
335 | wcscat(path, WSTRING_PATH_SEPARATOR);\r |
336 | pathLen = wcslen(path);\r |
337 | break;\r |
338 | }\r |
339 | if (GetLastError() != ERROR_ALREADY_EXISTS)\r |
340 | {\r |
341 | res = SZ_ERROR_FAIL;\r |
342 | break;\r |
343 | }\r |
344 | }\r |
345 | \r |
346 | #ifndef UNDER_CE\r |
347 | wcscpy(workCurDir, path);\r |
348 | #endif\r |
349 | if (res != SZ_OK)\r |
350 | errorMessage = "Can't create temp folder";\r |
351 | }\r |
352 | \r |
353 | if (res != SZ_OK)\r |
354 | {\r |
355 | if (!errorMessage)\r |
356 | errorMessage = "Error";\r |
357 | PrintErrorMessage(errorMessage);\r |
358 | return 1;\r |
359 | }\r |
360 | \r |
361 | if (InFile_OpenW(&archiveStream.file, sfxPath) != 0)\r |
362 | {\r |
363 | errorMessage = "can not open input file";\r |
364 | res = SZ_ERROR_FAIL;\r |
365 | }\r |
366 | else\r |
367 | {\r |
368 | UInt64 pos = 0;\r |
369 | if (!FindSignature(&archiveStream.file, &pos))\r |
370 | res = SZ_ERROR_FAIL;\r |
371 | else if (File_Seek(&archiveStream.file, (Int64 *)&pos, SZ_SEEK_SET) != 0)\r |
372 | res = SZ_ERROR_FAIL;\r |
373 | if (res != 0)\r |
374 | errorMessage = "Can't find 7z archive";\r |
375 | }\r |
376 | \r |
377 | if (res == SZ_OK)\r |
378 | {\r |
379 | lookStream.realStream = &archiveStream.s;\r |
380 | LookToRead_Init(&lookStream);\r |
381 | }\r |
382 | \r |
383 | SzArEx_Init(&db);\r |
384 | if (res == SZ_OK)\r |
385 | {\r |
386 | res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp);\r |
387 | }\r |
388 | \r |
389 | if (res == SZ_OK)\r |
390 | {\r |
391 | UInt32 executeFileIndex = (UInt32)(Int32)-1;\r |
392 | UInt32 minPrice = 1 << 30;\r |
393 | UInt32 i;\r |
394 | UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */\r |
395 | Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */\r |
396 | size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */\r |
397 | \r |
398 | for (i = 0; i < db.NumFiles; i++)\r |
399 | {\r |
400 | size_t offset = 0;\r |
401 | size_t outSizeProcessed = 0;\r |
402 | WCHAR *temp;\r |
403 | \r |
404 | if (SzArEx_GetFileNameUtf16(&db, i, NULL) >= MAX_PATH)\r |
405 | {\r |
406 | res = SZ_ERROR_FAIL;\r |
407 | break;\r |
408 | }\r |
409 | \r |
410 | temp = path + pathLen;\r |
411 | \r |
412 | SzArEx_GetFileNameUtf16(&db, i, temp);\r |
413 | {\r |
414 | res = SzArEx_Extract(&db, &lookStream.s, i,\r |
415 | &blockIndex, &outBuffer, &outBufferSize,\r |
416 | &offset, &outSizeProcessed,\r |
417 | &allocImp, &allocTempImp);\r |
418 | if (res != SZ_OK)\r |
419 | break;\r |
420 | }\r |
421 | {\r |
422 | CSzFile outFile;\r |
423 | size_t processedSize;\r |
424 | size_t j;\r |
425 | size_t nameStartPos = 0;\r |
426 | for (j = 0; temp[j] != 0; j++)\r |
427 | {\r |
428 | if (temp[j] == '/')\r |
429 | {\r |
430 | temp[j] = 0;\r |
431 | MyCreateDir(path);\r |
432 | temp[j] = CHAR_PATH_SEPARATOR;\r |
433 | nameStartPos = j + 1;\r |
434 | }\r |
435 | }\r |
436 | \r |
437 | if (SzArEx_IsDir(&db, i))\r |
438 | {\r |
439 | MyCreateDir(path);\r |
440 | continue;\r |
441 | }\r |
442 | else\r |
443 | {\r |
444 | unsigned extLen;\r |
445 | const WCHAR *name = temp + nameStartPos;\r |
446 | unsigned len = (unsigned)wcslen(name);\r |
447 | unsigned nameLen = FindExt(temp + nameStartPos, &extLen);\r |
448 | unsigned extPrice = FindItem(kExts, sizeof(kExts) / sizeof(kExts[0]), name + len - extLen, extLen);\r |
449 | unsigned namePrice = FindItem(kNames, sizeof(kNames) / sizeof(kNames[0]), name, nameLen);\r |
450 | \r |
451 | unsigned price = namePrice + extPrice * 64 + (nameStartPos == 0 ? 0 : (1 << 12));\r |
452 | if (minPrice > price)\r |
453 | {\r |
454 | minPrice = price;\r |
455 | executeFileIndex = i;\r |
456 | useShellExecute = (extPrice != k_EXE_ExtIndex);\r |
457 | }\r |
458 | \r |
459 | if (DoesFileOrDirExist(path))\r |
460 | {\r |
461 | errorMessage = "Duplicate file";\r |
462 | res = SZ_ERROR_FAIL;\r |
463 | break;\r |
464 | }\r |
465 | if (OutFile_OpenW(&outFile, path))\r |
466 | {\r |
467 | errorMessage = "Can't open output file";\r |
468 | res = SZ_ERROR_FAIL;\r |
469 | break;\r |
470 | }\r |
471 | }\r |
472 | \r |
473 | processedSize = outSizeProcessed;\r |
474 | if (File_Write(&outFile, outBuffer + offset, &processedSize) != 0 || processedSize != outSizeProcessed)\r |
475 | {\r |
476 | errorMessage = "Can't write output file";\r |
477 | res = SZ_ERROR_FAIL;\r |
478 | }\r |
479 | \r |
480 | #ifdef USE_WINDOWS_FILE\r |
481 | if (SzBitWithVals_Check(&db.MTime, i))\r |
482 | {\r |
483 | const CNtfsFileTime *t = db.MTime.Vals + i;\r |
484 | FILETIME mTime;\r |
485 | mTime.dwLowDateTime = t->Low;\r |
486 | mTime.dwHighDateTime = t->High;\r |
487 | SetFileTime(outFile.handle, NULL, NULL, &mTime);\r |
488 | }\r |
489 | #endif\r |
490 | \r |
491 | {\r |
492 | SRes res2 = File_Close(&outFile);\r |
493 | if (res != SZ_OK)\r |
494 | break;\r |
495 | if (res2 != SZ_OK)\r |
496 | {\r |
497 | res = res2;\r |
498 | break;\r |
499 | }\r |
500 | }\r |
501 | #ifdef USE_WINDOWS_FILE\r |
502 | if (SzBitWithVals_Check(&db.Attribs, i))\r |
503 | SetFileAttributesW(path, db.Attribs.Vals[i]);\r |
504 | #endif\r |
505 | }\r |
506 | }\r |
507 | \r |
508 | if (res == SZ_OK)\r |
509 | {\r |
510 | if (executeFileIndex == (UInt32)(Int32)-1)\r |
511 | {\r |
512 | errorMessage = "There is no file to execute";\r |
513 | res = SZ_ERROR_FAIL;\r |
514 | }\r |
515 | else\r |
516 | {\r |
517 | WCHAR *temp = path + pathLen;\r |
518 | UInt32 j;\r |
519 | SzArEx_GetFileNameUtf16(&db, executeFileIndex, temp);\r |
520 | for (j = 0; temp[j] != 0; j++)\r |
521 | if (temp[j] == '/')\r |
522 | temp[j] = CHAR_PATH_SEPARATOR;\r |
523 | }\r |
524 | }\r |
525 | IAlloc_Free(&allocImp, outBuffer);\r |
526 | }\r |
527 | SzArEx_Free(&db, &allocImp);\r |
528 | \r |
529 | File_Close(&archiveStream.file);\r |
530 | \r |
531 | if (res == SZ_OK)\r |
532 | {\r |
533 | HANDLE hProcess = 0;\r |
534 | \r |
535 | #ifndef UNDER_CE\r |
536 | WCHAR oldCurDir[MAX_PATH + 2];\r |
537 | oldCurDir[0] = 0;\r |
538 | {\r |
539 | DWORD needLen = GetCurrentDirectory(MAX_PATH + 1, oldCurDir);\r |
540 | if (needLen == 0 || needLen > MAX_PATH)\r |
541 | oldCurDir[0] = 0;\r |
542 | SetCurrentDirectory(workCurDir);\r |
543 | }\r |
544 | #endif\r |
545 | \r |
546 | if (useShellExecute)\r |
547 | {\r |
548 | SHELLEXECUTEINFO ei;\r |
549 | UINT32 executeRes;\r |
550 | BOOL success;\r |
551 | \r |
552 | memset(&ei, 0, sizeof(ei));\r |
553 | ei.cbSize = sizeof(ei);\r |
554 | ei.lpFile = path;\r |
555 | ei.fMask = SEE_MASK_NOCLOSEPROCESS\r |
556 | #ifndef UNDER_CE\r |
557 | | SEE_MASK_FLAG_DDEWAIT\r |
558 | #endif\r |
559 | /* | SEE_MASK_NO_CONSOLE */\r |
560 | ;\r |
561 | if (wcslen(cmdLineParams) != 0)\r |
562 | ei.lpParameters = cmdLineParams;\r |
563 | ei.nShow = SW_SHOWNORMAL; /* SW_HIDE; */\r |
564 | success = ShellExecuteEx(&ei);\r |
565 | executeRes = (UINT32)(UINT_PTR)ei.hInstApp;\r |
566 | if (!success || (executeRes <= 32 && executeRes != 0)) /* executeRes = 0 in Windows CE */\r |
567 | res = SZ_ERROR_FAIL;\r |
568 | else\r |
569 | hProcess = ei.hProcess;\r |
570 | }\r |
571 | else\r |
572 | {\r |
573 | STARTUPINFOW si;\r |
574 | PROCESS_INFORMATION pi;\r |
575 | WCHAR cmdLine[MAX_PATH * 3];\r |
576 | \r |
577 | wcscpy(cmdLine, path);\r |
578 | wcscat(cmdLine, cmdLineParams);\r |
579 | memset(&si, 0, sizeof(si));\r |
580 | si.cb = sizeof(si);\r |
581 | if (CreateProcessW(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) == 0)\r |
582 | res = SZ_ERROR_FAIL;\r |
583 | else\r |
584 | {\r |
585 | CloseHandle(pi.hThread);\r |
586 | hProcess = pi.hProcess;\r |
587 | }\r |
588 | }\r |
589 | \r |
590 | if (hProcess != 0)\r |
591 | {\r |
592 | WaitForSingleObject(hProcess, INFINITE);\r |
593 | if (!GetExitCodeProcess(hProcess, &exitCode))\r |
594 | exitCode = 1;\r |
595 | CloseHandle(hProcess);\r |
596 | }\r |
597 | \r |
598 | #ifndef UNDER_CE\r |
599 | SetCurrentDirectory(oldCurDir);\r |
600 | #endif\r |
601 | }\r |
602 | \r |
603 | path[pathLen] = L'\0';\r |
604 | RemoveDirWithSubItems(path);\r |
605 | \r |
606 | if (res == SZ_OK)\r |
607 | return (int)exitCode;\r |
608 | \r |
609 | {\r |
610 | if (res == SZ_ERROR_UNSUPPORTED)\r |
611 | errorMessage = "Decoder doesn't support this archive";\r |
612 | else if (res == SZ_ERROR_MEM)\r |
613 | errorMessage = "Can't allocate required memory";\r |
614 | else if (res == SZ_ERROR_CRC)\r |
615 | errorMessage = "CRC error";\r |
616 | else\r |
617 | {\r |
618 | if (!errorMessage)\r |
619 | errorMessage = "ERROR";\r |
620 | }\r |
621 | \r |
622 | if (errorMessage)\r |
623 | PrintErrorMessage(errorMessage);\r |
624 | }\r |
625 | return 1;\r |
626 | }\r |