summaryrefslogtreecommitdiff
path: root/plugins/PluginUpdater/src/unzipfile.cpp
blob: ed4e045e701e534a832d9447226ea85783d311e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
Copyright (C) 2012 George Hazan

This is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this file; see the file license.txt. If
not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/

#include "common.h"

extern "C"
{
	#include "Minizip\unzip.h"

	void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def);
}

static void PrepareFileName(TCHAR *dest, size_t destSize, const TCHAR *ptszPath, const TCHAR *ptszFileName)
{
	mir_sntprintf(dest, destSize, _T("%s\\%s"), ptszPath, ptszFileName);
	for (TCHAR *p = dest; *p; ++p)
		if (*p == '/')
			*p = '\\'; 
	CreatePathToFileT(dest);
}

bool extractCurrentFile(unzFile uf, const TCHAR *ptszOldFileName, TCHAR *ptszDestPath, TCHAR *ptszBackPath)
{
	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;

	if (!opts.bUpdateIcons && !_strnicmp(filename, "Icons/", 6))
		return true;

	TCHAR tszDestFile[MAX_PATH], tszBackFile[MAX_PATH];
	TCHAR *ptszNewName = mir_utf8decodeT(filename);
	if (ptszNewName == NULL)
		ptszNewName = mir_a2t(filename);

	if ( !(file_info.external_fa & FILE_ATTRIBUTE_DIRECTORY)) {
		err = unzOpenCurrentFile(uf);
		if (err != UNZ_OK)
			return false;

		TCHAR tszOldName[MAX_PATH], *p = _tcschr(ptszNewName, '/');
		if (p != NULL) {
			*p = 0;
			mir_sntprintf(tszOldName, SIZEOF(tszOldName), _T("%s\\%s"), ptszNewName, ptszOldFileName);
			*p = '\\';
		}
		else _tcscpy(tszOldName, ptszOldFileName);

		PrepareFileName(tszDestFile, SIZEOF(tszDestFile), ptszDestPath, tszOldName);
		PrepareFileName(tszBackFile, SIZEOF(tszBackFile), ptszBackPath, tszOldName);

		DeleteFile(tszBackFile);
		MoveFile(tszDestFile, tszBackFile);

		PrepareFileName(tszDestFile, SIZEOF(tszDestFile), ptszDestPath, ptszNewName);
		HANDLE hFile = CreateFile(tszDestFile, GENERIC_WRITE, FILE_SHARE_WRITE, 0, 
			CREATE_ALWAYS, file_info.external_fa, 0);

		if (hFile != INVALID_HANDLE_VALUE) {
			while (true) {
				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 */
		}
	}
	mir_free(ptszNewName);
	return true;
}

bool unzip(const TCHAR *ptszOldFileName, const TCHAR *ptszZipFile, TCHAR *ptszDestPath, TCHAR *ptszBackPath)
{
	bool bResult = true;

	zlib_filefunc64_def ffunc;
	fill_fopen64_filefunc(&ffunc);
	
	unzFile uf = unzOpen2_64(ptszZipFile, &ffunc);
	if (uf) {
		do {
			if ( !extractCurrentFile(uf, ptszOldFileName, ptszDestPath, ptszBackPath))
				bResult = false;
		}
			while (unzGoToNextFile(uf) == UNZ_OK);
		unzClose(uf);
	}

	return bResult;
}