summaryrefslogtreecommitdiff
path: root/updater/unzipfile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'updater/unzipfile.cpp')
-rw-r--r--updater/unzipfile.cpp176
1 files changed, 102 insertions, 74 deletions
diff --git a/updater/unzipfile.cpp b/updater/unzipfile.cpp
index 1128698..a449ceb 100644
--- a/updater/unzipfile.cpp
+++ b/updater/unzipfile.cpp
@@ -1,76 +1,104 @@
#include "common.h"
#include "utils.h"
-
-#include <unzip.h>
-#include <iowin32.h>
-
-bool extractCurrentFile(unzFile uf, TCHAR *path)
-{
- int err = UNZ_OK;
- unz_file_info64 file_info;
- char filename_inzip[MAX_PATH];
- char buf[8192];
-
- err = unzGetCurrentFileInfo64(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, buf,sizeof(buf));
- if (err != UNZ_OK) return false;
-
- err = unzOpenCurrentFile(uf);
- if (err != UNZ_OK) return false;
-
- TCHAR save_file[MAX_PATH];
- TCHAR* p = mir_utf8decodeT(filename_inzip);
- mir_sntprintf(save_file, SIZEOF(save_file), _T("%s\\%s"), path, p);
- mir_free(p);
-
- for (p = save_file; *p; ++p) if (*p == '/') *p = '\\';
-
- p = _tcsrchr(save_file, '\\'); if (p) *p = 0;
- CreatePath(save_file);
- if (p) *p = '\\';
-
- HANDLE hFile = CreateFile(save_file, GENERIC_WRITE, FILE_SHARE_WRITE, 0,
- CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
-
- if (hFile != INVALID_HANDLE_VALUE)
- {
- for (;;)
- {
- err = unzReadCurrentFile(uf, buf, sizeof(buf));
- if (err <= 0) break;
-
- DWORD bytes;
- if (!WriteFile(hFile, buf, err, &bytes, FALSE))
- {
- err = UNZ_ERRNO;
- break;
- }
- }
-
- FILETIME ftLocal, ftCreate, ftLastAcc, ftLastWrite;
- GetFileTime(hFile, &ftCreate, &ftLastAcc, &ftLastWrite);
- DosDateTimeToFileTime(HIWORD(file_info.dosDate), LOWORD(file_info.dosDate), &ftLocal);
- LocalFileTimeToFileTime(&ftLocal, &ftLastWrite);
- SetFileTime(hFile, &ftCreate, &ftLastAcc, &ftLastWrite);
-
- CloseHandle(hFile);
-
- unzCloseCurrentFile(uf); /* don't lose the error */
- }
- return true;
-}
-
-void unzip_file(TCHAR* zipfile, TCHAR* dest)
-{
- zlib_filefunc64_def ffunc;
- fill_win32_filefunc64(&ffunc);
-
- unzFile uf = unzOpen2_64(zipfile, &ffunc);
- if (uf)
- {
- do {
- extractCurrentFile(uf, dest);
- }
- while (unzGoToNextFile(uf) == UNZ_OK);
- unzClose(uf);
- }
-}
+
+#include <unzip.h>
+#include <iowin32.h>
+
+bool extractCurrentFile(unzFile uf, TCHAR *path)
+{
+ int err = UNZ_OK;
+ unz_file_info64 file_info;
+ char filename[MAX_PATH];
+ char buf[8192];
+
+ err = unzGetCurrentFileInfo64(uf, &file_info, filename, sizeof(filename), buf, sizeof(buf), NULL, 0);
+ if (err != UNZ_OK) return false;
+
+ // Get Unicode file name for InfoZip style archives, otherwise assume PKZip/WinZip style
+ if (file_info.size_file_extra)
+ {
+ char *p = buf;
+ unsigned long size = min(file_info.size_file_extra, sizeof(buf));
+ while (size > 0)
+ {
+ unsigned short id = *(unsigned short*)p;
+ unsigned len = *(unsigned short*)(p + 2);
+
+ if (size < (len + 4)) break;
+
+ if (id == 0x7075 && len > 5 && (len - 5) < sizeof(filename) && *(p + 4) == 1)
+ {
+ memcpy(filename, p + 9, len - 5);
+ filename[len - 5] = 0;
+ break;
+ }
+ size -= len + 4;
+ p += len + 4;
+ }
+ }
+
+ TCHAR save_file[MAX_PATH];
+ TCHAR* p = mir_utf8decodeT(filename);
+ if (p == NULL) p = mir_a2t(filename);
+ mir_sntprintf(save_file, SIZEOF(save_file), _T("%s\\%s"), path, p);
+ mir_free(p);
+
+ for (p = save_file; *p; ++p) if (*p == '/') *p = '\\';
+
+ if (file_info.external_fa & FILE_ATTRIBUTE_DIRECTORY)
+ CreatePath(save_file);
+ else
+ {
+ err = unzOpenCurrentFile(uf);
+ if (err != UNZ_OK) return false;
+
+ p = _tcsrchr(save_file, '\\'); if (p) *p = 0;
+ CreatePath(save_file);
+ if (p) *p = '\\';
+
+ HANDLE hFile = CreateFile(save_file, GENERIC_WRITE, FILE_SHARE_WRITE, 0,
+ CREATE_ALWAYS, file_info.external_fa, 0);
+
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ for (;;)
+ {
+ err = unzReadCurrentFile(uf, buf, sizeof(buf));
+ if (err <= 0) break;
+
+ DWORD bytes;
+ if (!WriteFile(hFile, buf, err, &bytes, FALSE))
+ {
+ err = UNZ_ERRNO;
+ break;
+ }
+ }
+
+ FILETIME ftLocal, ftCreate, ftLastAcc, ftLastWrite;
+ GetFileTime(hFile, &ftCreate, &ftLastAcc, &ftLastWrite);
+ DosDateTimeToFileTime(HIWORD(file_info.dosDate), LOWORD(file_info.dosDate), &ftLocal);
+ LocalFileTimeToFileTime(&ftLocal, &ftLastWrite);
+ SetFileTime(hFile, &ftCreate, &ftLastAcc, &ftLastWrite);
+
+ CloseHandle(hFile);
+ unzCloseCurrentFile(uf); /* don't lose the error */
+ }
+ }
+ return true;
+}
+
+void unzip_file(TCHAR* zipfile, TCHAR* dest)
+{
+ zlib_filefunc64_def ffunc;
+ fill_win32_filefunc64(&ffunc);
+
+ unzFile uf = unzOpen2_64(zipfile, &ffunc);
+ if (uf)
+ {
+ do {
+ extractCurrentFile(uf, dest);
+ }
+ while (unzGoToNextFile(uf) == UNZ_OK);
+ unzClose(uf);
+ }
+}