1 // Copyright 2014 Idol Software, Inc.
3 // This file is part of Doctor Dump SDK.
5 // Doctor Dump SDK is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "contrib\minizip\zip.h"
23 #include "contrib\minizip\unzip.h"
24 #include "contrib\minizip\iowin32.h"
28 extern "C" voidpf ZCALLBACK
win32_open64_file_funcW(voidpf opaque
,const void* filename
,int mode
);
30 Zip::Zip(LPCWSTR pszFilename
, bool append
)
32 zlib_filefunc_def ffunc
;
33 fill_win32_filefunc(&ffunc
);
35 // Hack used to force Unicode version of CreateFile in ANSI zipOpen2 function
36 ffunc
.zopen_file
= (open_file_func
) win32_open64_file_funcW
;
37 m_zf
= zipOpen2((const char*)pszFilename
, append
? APPEND_STATUS_ADDINZIP
: APPEND_STATUS_CREATE
, NULL
, &ffunc
);
39 m_zf
= zipOpen2((const char*)CW2A(pszFilename
), append
? APPEND_STATUS_ADDINZIP
: APPEND_STATUS_CREATE
, NULL
, &ffunc
);
43 throw runtime_error(append
? "failed to append zip file" : "failed to create zip file");
51 void Zip::AddFile(LPCWSTR pszFilename
, LPCWSTR pszFilenameInZip
, bool* cancel
)
56 HANDLE hFind
= FindFirstFileW(pszFilename
, &ff
);
57 if (hFind
== INVALID_HANDLE_VALUE
)
58 throw runtime_error("file to add to zip not found");
60 if (!pszFilenameInZip
)
62 LPCWSTR slashPos
= wcsrchr(pszFilename
, L
'\\');
64 slashPos
= wcsrchr(pszFilename
, L
'/');
65 pszFilenameInZip
= slashPos
? slashPos
+ 1 : pszFilename
;
69 FileTimeToLocalFileTime(&(ff
.ftLastWriteTime
), &ftLocal
);
70 FileTimeToDosDateTime(&ftLocal
, ((LPWORD
)&zi
.dosDate
)+1, ((LPWORD
)&zi
.dosDate
)+0);
73 int err
= zipOpenNewFileInZip3(m_zf
, CW2A(pszFilenameInZip
), &zi
,
74 NULL
, 0, NULL
, 0, NULL
/* comment*/,
75 Z_DEFLATED
, Z_BEST_COMPRESSION
, 0,
76 -MAX_WBITS
, DEF_MEM_LEVEL
, Z_DEFAULT_STRATEGY
,
80 throw runtime_error("failed to create file in zip");
83 CAtlFile
hFile(CreateFileW(pszFilename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
));
84 if (hFile
== INVALID_HANDLE_VALUE
)
85 throw runtime_error("file to add to zip not found");
89 while (SUCCEEDED(hFile
.Read(buf
, _countof(buf
), dwReaded
)) && dwReaded
!= 0)
91 err
= zipWriteInFileInZip(m_zf
, buf
, dwReaded
);
93 throw runtime_error("failed to write to zip");
94 if (cancel
&& *cancel
)
95 throw std::runtime_error("canceled");
98 if (ZIP_OK
!= zipCloseFileInZip(m_zf
))
99 throw runtime_error("failed to finalize file in zip");
102 static unzFile
Unzip_Open(LPCWSTR pszFilename
)
104 zlib_filefunc_def ffunc
;
105 fill_win32_filefunc(&ffunc
);
106 unzFile uf
= unzOpen2(CW2CT(pszFilename
), &ffunc
);
108 throw runtime_error("failed to open zip file");
112 static CStringW
Unzip_GetCurentFilePath(unzFile uf
, FILETIME
& ftLocal
)
114 unz_file_info file_info
;
116 const int pathLen
= 256;
117 if (UNZ_OK
!= unzGetCurrentFileInfo(uf
, &file_info
, pathA
.GetBuffer(pathLen
), pathLen
, NULL
, 0, NULL
, 0))
118 throw runtime_error("failed to unzGetCurrentFileInfo");
119 pathA
.ReleaseBuffer(-1);
120 DosDateTimeToFileTime((WORD
)(file_info
.dosDate
>>16), (WORD
)file_info
.dosDate
, &ftLocal
);
121 return CStringW(pathA
);
124 static void Unzip_ExtractFile(unzFile uf
, const CStringW
& path
, DWORD flagsAndAttributes
, FILETIME ftLocal
)
128 if (UNZ_OK
!= unzOpenCurrentFilePassword(uf
, NULL
))
129 throw runtime_error("failed to unzOpenCurrentFilePassword");
131 CAtlFile
file(CreateFileW(path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, flagsAndAttributes
, NULL
));
132 if (file
== INVALID_HANDLE_VALUE
)
133 throw runtime_error("failed to CreateFile");
135 vector
<BYTE
> buf(8192);
138 int size
= unzReadCurrentFile(uf
, &buf
[0], (unsigned int)buf
.size());
140 throw runtime_error("failed to unzReadCurrentFile");
144 if (FAILED(file
.Write(&buf
[0], size
)))
145 throw runtime_error("failed to WriteFile");
148 FILETIME ftm
, ftCreate
, ftLastAcc
, ftLastWrite
;
149 GetFileTime(file
, &ftCreate
, &ftLastAcc
, &ftLastWrite
);
150 LocalFileTimeToFileTime(&ftLocal
, &ftm
);
151 SetFileTime(file
, &ftm
, &ftLastAcc
, &ftm
);
153 if (UNZ_OK
!= unzCloseCurrentFile(uf
))
154 throw runtime_error("failed to unzCloseCurrentFile");
162 std::vector
<CStringW
> Unzip::Extract(LPCWSTR pszFilename
, LPCWSTR pszFolder
, std::function
<bool(LPCWSTR filePath
, DWORD
& flagsAndAttributes
)> predicate
)
164 std::vector
<CStringW
> result
;
169 uf
= Unzip_Open(pszFilename
);
172 if (UNZ_OK
!= unzGetGlobalInfo(uf
, &gi
))
173 throw runtime_error("failed to unzGetGlobalInfo");
175 for (uLong i
= 0; i
< gi
.number_entry
; ++i
)
178 CStringW path
= CStringW(pszFolder
) + L
'\\' + Unzip_GetCurentFilePath(uf
, ftLocal
);
180 CStringW filename
= path
.Mid(path
.ReverseFind(L
'\\') + 1);
181 if (filename
.IsEmpty())
183 if (!CreateDirectoryW(path
, NULL
))
184 throw runtime_error("failed to CreateDirectory");
188 DWORD flagsAndAttributes
= FILE_ATTRIBUTE_NORMAL
;
189 if (predicate(path
, flagsAndAttributes
))
191 Unzip_ExtractFile(uf
, path
, flagsAndAttributes
, ftLocal
);
192 result
.push_back(path
);
195 if (i
+ 1 < gi
.number_entry
&& UNZ_OK
!= unzGoToNextFile(uf
))
196 throw runtime_error("failed to unzGoToNextFile");
206 for each (auto file in result
)
212 std::vector
<CStringW
> Unzip::Extract(LPCWSTR pszFilename
, LPCWSTR pszFolder
)
214 return Extract(pszFilename
, pszFolder
, [](LPCWSTR filePath
, DWORD
& flagsAndAttributes
) { return true; });
217 bool DeflateBuffer(const BYTE
* buffer
, size_t bufferLen
, std::vector
<BYTE
>& outBuffer
, const char* dictionary
)
219 z_stream stream
= {};
220 deflateInit(&stream
, Z_BEST_COMPRESSION
);
221 outBuffer
.resize(deflateBound(&stream
, static_cast<uLong
>(bufferLen
)));
223 deflateSetDictionary(&stream
, (const Bytef
*)dictionary
, static_cast<uInt
>(strlen(dictionary
)));
224 stream
.next_in
= (Bytef
*)buffer
;
225 stream
.avail_in
= static_cast<uInt
>(bufferLen
);
226 stream
.next_out
= &outBuffer
[0];
227 stream
.avail_out
= static_cast<uInt
>(outBuffer
.size());
230 switch (deflate(&stream
, Z_FINISH
))
233 outBuffer
.resize(outBuffer
.size() - stream
.avail_out
);
237 stream
.avail_out
+= static_cast<uInt
>(outBuffer
.size());
238 outBuffer
.resize(outBuffer
.size() * 2);
239 stream
.next_out
= &outBuffer
[outBuffer
.size() - stream
.avail_out
];
248 bool InflateBuffer(const BYTE
* buffer
, size_t bufferLen
, std::vector
<BYTE
>& outBuffer
, const char* dictionary
)
250 z_stream stream
= {};
251 stream
.next_in
= (Bytef
*)buffer
;
252 stream
.avail_in
= static_cast<uInt
>(bufferLen
);
253 inflateInit(&stream
);
254 outBuffer
.resize(2*bufferLen
);
255 stream
.next_out
= &outBuffer
[0];
256 stream
.avail_out
= static_cast<uInt
>(outBuffer
.size());
259 switch (inflate(&stream
, 0))
262 if (!dictionary
|| Z_OK
!= inflateSetDictionary(&stream
, (const Bytef
*)dictionary
, static_cast<uInt
>(strlen(dictionary
))))
269 outBuffer
.resize(outBuffer
.size() - stream
.avail_out
);
273 stream
.avail_out
+= static_cast<uInt
>(outBuffer
.size());
274 outBuffer
.resize(outBuffer
.size() * 2);
275 stream
.next_out
= &outBuffer
[outBuffer
.size() - stream
.avail_out
];