diff options
Diffstat (limited to 'rbutil/rbutilqt/quazip/quazip.cpp')
-rw-r--r-- | rbutil/rbutilqt/quazip/quazip.cpp | 723 |
1 files changed, 613 insertions, 110 deletions
diff --git a/rbutil/rbutilqt/quazip/quazip.cpp b/rbutil/rbutilqt/quazip/quazip.cpp index 3f7314a433..e3623c76e3 100644 --- a/rbutil/rbutilqt/quazip/quazip.cpp +++ b/rbutil/rbutilqt/quazip/quazip.cpp | |||
@@ -1,94 +1,321 @@ | |||
1 | /* | 1 | /* |
2 | -- A kind of "standard" GPL license statement -- | 2 | Copyright (C) 2005-2014 Sergey A. Tachenov |
3 | QuaZIP - a Qt/C++ wrapper for the ZIP/UNZIP package | 3 | |
4 | Copyright (C) 2005-2007 Sergey A. Tachenov | 4 | This file is part of QuaZIP. |
5 | 5 | ||
6 | This program is free software; you can redistribute it and/or modify it | 6 | QuaZIP is free software: you can redistribute it and/or modify |
7 | under the terms of the GNU General Public License as published by the | 7 | it under the terms of the GNU Lesser General Public License as published by |
8 | Free Software Foundation; either version 2 of the License, or (at your | 8 | the Free Software Foundation, either version 2.1 of the License, or |
9 | option) any later version. | 9 | (at your option) any later version. |
10 | 10 | ||
11 | This program is distributed in the hope that it will be useful, but | 11 | QuaZIP is distributed in the hope that it will be useful, |
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | Public License for more details. | 14 | GNU Lesser General Public License for more details. |
15 | 15 | ||
16 | You should have received a copy of the GNU General Public License along | 16 | You should have received a copy of the GNU Lesser General Public License |
17 | with this program; if not, write to the Free Software Foundation, Inc., | 17 | along with QuaZIP. If not, see <http://www.gnu.org/licenses/>. |
18 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | |
19 | 19 | See COPYING file for the full LGPL text. | |
20 | -- A kind of "standard" GPL license statement ends here -- | 20 | |
21 | 21 | Original ZIP package is copyrighted by Gilles Vollant, see | |
22 | See COPYING file for GPL. | 22 | quazip/(un)zip.h files for details, basically it's zlib license. |
23 | |||
24 | You are also permitted to use QuaZIP under the terms of LGPL (see | ||
25 | COPYING.LGPL). You are free to choose either license, but please note | ||
26 | that QuaZIP makes use of Qt, which is not licensed under LGPL. So if | ||
27 | you are using Open Source edition of Qt, you therefore MUST use GPL for | ||
28 | your code based on QuaZIP, since it would be also based on Qt in this | ||
29 | case. If you are Qt commercial license owner, then you are free to use | ||
30 | QuaZIP as long as you respect either GPL or LGPL for QuaZIP code. | ||
31 | **/ | 23 | **/ |
32 | 24 | ||
33 | #include <QFile> | 25 | #include <QFile> |
26 | #include <QFlags> | ||
27 | #include <QHash> | ||
34 | 28 | ||
35 | #include "quazip.h" | 29 | #include "quazip.h" |
36 | 30 | ||
31 | /// All the internal stuff for the QuaZip class. | ||
32 | /** | ||
33 | \internal | ||
34 | |||
35 | This class keeps all the private stuff for the QuaZip class so it can | ||
36 | be changed without breaking binary compatibility, according to the | ||
37 | Pimpl idiom. | ||
38 | */ | ||
39 | class QuaZipPrivate { | ||
40 | friend class QuaZip; | ||
41 | private: | ||
42 | /// The pointer to the corresponding QuaZip instance. | ||
43 | QuaZip *q; | ||
44 | /// The codec for file names. | ||
45 | QTextCodec *fileNameCodec; | ||
46 | /// The codec for comments. | ||
47 | QTextCodec *commentCodec; | ||
48 | /// The archive file name. | ||
49 | QString zipName; | ||
50 | /// The device to access the archive. | ||
51 | QIODevice *ioDevice; | ||
52 | /// The global comment. | ||
53 | QString comment; | ||
54 | /// The open mode. | ||
55 | QuaZip::Mode mode; | ||
56 | union { | ||
57 | /// The internal handle for UNZIP modes. | ||
58 | unzFile unzFile_f; | ||
59 | /// The internal handle for ZIP modes. | ||
60 | zipFile zipFile_f; | ||
61 | }; | ||
62 | /// Whether a current file is set. | ||
63 | bool hasCurrentFile_f; | ||
64 | /// The last error. | ||
65 | int zipError; | ||
66 | /// Whether \ref QuaZip::setDataDescriptorWritingEnabled() "the data descriptor writing mode" is enabled. | ||
67 | bool dataDescriptorWritingEnabled; | ||
68 | /// The zip64 mode. | ||
69 | bool zip64; | ||
70 | /// The auto-close flag. | ||
71 | bool autoClose; | ||
72 | inline QTextCodec *getDefaultFileNameCodec() | ||
73 | { | ||
74 | if (defaultFileNameCodec == NULL) { | ||
75 | return QTextCodec::codecForLocale(); | ||
76 | } else { | ||
77 | return defaultFileNameCodec; | ||
78 | } | ||
79 | } | ||
80 | /// The constructor for the corresponding QuaZip constructor. | ||
81 | inline QuaZipPrivate(QuaZip *q): | ||
82 | q(q), | ||
83 | fileNameCodec(getDefaultFileNameCodec()), | ||
84 | commentCodec(QTextCodec::codecForLocale()), | ||
85 | ioDevice(NULL), | ||
86 | mode(QuaZip::mdNotOpen), | ||
87 | hasCurrentFile_f(false), | ||
88 | zipError(UNZ_OK), | ||
89 | dataDescriptorWritingEnabled(true), | ||
90 | zip64(false), | ||
91 | autoClose(true) | ||
92 | { | ||
93 | lastMappedDirectoryEntry.num_of_file = 0; | ||
94 | lastMappedDirectoryEntry.pos_in_zip_directory = 0; | ||
95 | } | ||
96 | /// The constructor for the corresponding QuaZip constructor. | ||
97 | inline QuaZipPrivate(QuaZip *q, const QString &zipName): | ||
98 | q(q), | ||
99 | fileNameCodec(getDefaultFileNameCodec()), | ||
100 | commentCodec(QTextCodec::codecForLocale()), | ||
101 | zipName(zipName), | ||
102 | ioDevice(NULL), | ||
103 | mode(QuaZip::mdNotOpen), | ||
104 | hasCurrentFile_f(false), | ||
105 | zipError(UNZ_OK), | ||
106 | dataDescriptorWritingEnabled(true), | ||
107 | zip64(false), | ||
108 | autoClose(true) | ||
109 | { | ||
110 | lastMappedDirectoryEntry.num_of_file = 0; | ||
111 | lastMappedDirectoryEntry.pos_in_zip_directory = 0; | ||
112 | } | ||
113 | /// The constructor for the corresponding QuaZip constructor. | ||
114 | inline QuaZipPrivate(QuaZip *q, QIODevice *ioDevice): | ||
115 | q(q), | ||
116 | fileNameCodec(getDefaultFileNameCodec()), | ||
117 | commentCodec(QTextCodec::codecForLocale()), | ||
118 | ioDevice(ioDevice), | ||
119 | mode(QuaZip::mdNotOpen), | ||
120 | hasCurrentFile_f(false), | ||
121 | zipError(UNZ_OK), | ||
122 | dataDescriptorWritingEnabled(true), | ||
123 | zip64(false), | ||
124 | autoClose(true) | ||
125 | { | ||
126 | lastMappedDirectoryEntry.num_of_file = 0; | ||
127 | lastMappedDirectoryEntry.pos_in_zip_directory = 0; | ||
128 | } | ||
129 | /// Returns either a list of file names or a list of QuaZipFileInfo. | ||
130 | template<typename TFileInfo> | ||
131 | bool getFileInfoList(QList<TFileInfo> *result) const; | ||
132 | |||
133 | /// Stores map of filenames and file locations for unzipping | ||
134 | inline void clearDirectoryMap(); | ||
135 | inline void addCurrentFileToDirectoryMap(const QString &fileName); | ||
136 | bool goToFirstUnmappedFile(); | ||
137 | QHash<QString, unz64_file_pos> directoryCaseSensitive; | ||
138 | QHash<QString, unz64_file_pos> directoryCaseInsensitive; | ||
139 | unz64_file_pos lastMappedDirectoryEntry; | ||
140 | static QTextCodec *defaultFileNameCodec; | ||
141 | }; | ||
142 | |||
143 | QTextCodec *QuaZipPrivate::defaultFileNameCodec = NULL; | ||
144 | |||
145 | void QuaZipPrivate::clearDirectoryMap() | ||
146 | { | ||
147 | directoryCaseInsensitive.clear(); | ||
148 | directoryCaseSensitive.clear(); | ||
149 | lastMappedDirectoryEntry.num_of_file = 0; | ||
150 | lastMappedDirectoryEntry.pos_in_zip_directory = 0; | ||
151 | } | ||
152 | |||
153 | void QuaZipPrivate::addCurrentFileToDirectoryMap(const QString &fileName) | ||
154 | { | ||
155 | if (!hasCurrentFile_f || fileName.isEmpty()) { | ||
156 | return; | ||
157 | } | ||
158 | // Adds current file to filename map as fileName | ||
159 | unz64_file_pos fileDirectoryPos; | ||
160 | unzGetFilePos64(unzFile_f, &fileDirectoryPos); | ||
161 | directoryCaseSensitive.insert(fileName, fileDirectoryPos); | ||
162 | // Only add lowercase to directory map if not already there | ||
163 | // ensures only map the first one seen | ||
164 | QString lower = fileName.toLower(); | ||
165 | if (!directoryCaseInsensitive.contains(lower)) | ||
166 | directoryCaseInsensitive.insert(lower, fileDirectoryPos); | ||
167 | // Mark last one | ||
168 | if (fileDirectoryPos.pos_in_zip_directory > lastMappedDirectoryEntry.pos_in_zip_directory) | ||
169 | lastMappedDirectoryEntry = fileDirectoryPos; | ||
170 | } | ||
171 | |||
172 | bool QuaZipPrivate::goToFirstUnmappedFile() | ||
173 | { | ||
174 | zipError = UNZ_OK; | ||
175 | if (mode != QuaZip::mdUnzip) { | ||
176 | qWarning("QuaZipPrivate::goToNextUnmappedFile(): ZIP is not open in mdUnzip mode"); | ||
177 | return false; | ||
178 | } | ||
179 | // If not mapped anything, go to beginning | ||
180 | if (lastMappedDirectoryEntry.pos_in_zip_directory == 0) { | ||
181 | unzGoToFirstFile(unzFile_f); | ||
182 | } else { | ||
183 | // Goto the last one mapped, plus one | ||
184 | unzGoToFilePos64(unzFile_f, &lastMappedDirectoryEntry); | ||
185 | unzGoToNextFile(unzFile_f); | ||
186 | } | ||
187 | hasCurrentFile_f=zipError==UNZ_OK; | ||
188 | if(zipError==UNZ_END_OF_LIST_OF_FILE) | ||
189 | zipError=UNZ_OK; | ||
190 | return hasCurrentFile_f; | ||
191 | } | ||
192 | |||
37 | QuaZip::QuaZip(): | 193 | QuaZip::QuaZip(): |
38 | fileNameCodec(QTextCodec::codecForLocale()), | 194 | p(new QuaZipPrivate(this)) |
39 | commentCodec(QTextCodec::codecForLocale()), | ||
40 | mode(mdNotOpen), hasCurrentFile_f(false), zipError(UNZ_OK) | ||
41 | { | 195 | { |
42 | } | 196 | } |
43 | 197 | ||
44 | QuaZip::QuaZip(const QString& zipName): | 198 | QuaZip::QuaZip(const QString& zipName): |
45 | fileNameCodec(QTextCodec::codecForLocale()), | 199 | p(new QuaZipPrivate(this, zipName)) |
46 | commentCodec(QTextCodec::codecForLocale()), | 200 | { |
47 | zipName(zipName), | 201 | } |
48 | mode(mdNotOpen), hasCurrentFile_f(false), zipError(UNZ_OK) | 202 | |
203 | QuaZip::QuaZip(QIODevice *ioDevice): | ||
204 | p(new QuaZipPrivate(this, ioDevice)) | ||
49 | { | 205 | { |
50 | } | 206 | } |
51 | 207 | ||
52 | QuaZip::~QuaZip() | 208 | QuaZip::~QuaZip() |
53 | { | 209 | { |
54 | if(isOpen()) close(); | 210 | if(isOpen()) |
211 | close(); | ||
212 | delete p; | ||
55 | } | 213 | } |
56 | 214 | ||
57 | bool QuaZip::open(Mode mode, zlib_filefunc_def* ioApi) | 215 | bool QuaZip::open(Mode mode, zlib_filefunc_def* ioApi) |
58 | { | 216 | { |
59 | zipError=UNZ_OK; | 217 | p->zipError=UNZ_OK; |
60 | if(isOpen()) { | 218 | if(isOpen()) { |
61 | qWarning("QuaZip::open(): ZIP already opened"); | 219 | qWarning("QuaZip::open(): ZIP already opened"); |
62 | return false; | 220 | return false; |
63 | } | 221 | } |
222 | QIODevice *ioDevice = p->ioDevice; | ||
223 | if (ioDevice == NULL) { | ||
224 | if (p->zipName.isEmpty()) { | ||
225 | qWarning("QuaZip::open(): set either ZIP file name or IO device first"); | ||
226 | return false; | ||
227 | } else { | ||
228 | ioDevice = new QFile(p->zipName); | ||
229 | } | ||
230 | } | ||
231 | unsigned flags = 0; | ||
64 | switch(mode) { | 232 | switch(mode) { |
65 | case mdUnzip: | 233 | case mdUnzip: |
66 | unzFile_f=unzOpen2(QFile::encodeName(zipName).constData(), ioApi); | 234 | if (ioApi == NULL) { |
67 | if(unzFile_f!=NULL) { | 235 | if (p->autoClose) |
68 | this->mode=mode; | 236 | flags |= UNZ_AUTO_CLOSE; |
237 | p->unzFile_f=unzOpenInternal(ioDevice, NULL, 1, flags); | ||
238 | } else { | ||
239 | // QuaZIP pre-zip64 compatibility mode | ||
240 | p->unzFile_f=unzOpen2(ioDevice, ioApi); | ||
241 | if (p->unzFile_f != NULL) { | ||
242 | if (p->autoClose) { | ||
243 | unzSetFlags(p->unzFile_f, UNZ_AUTO_CLOSE); | ||
244 | } else { | ||
245 | unzClearFlags(p->unzFile_f, UNZ_AUTO_CLOSE); | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | if(p->unzFile_f!=NULL) { | ||
250 | if (ioDevice->isSequential()) { | ||
251 | unzClose(p->unzFile_f); | ||
252 | if (!p->zipName.isEmpty()) | ||
253 | delete ioDevice; | ||
254 | qWarning("QuaZip::open(): " | ||
255 | "only mdCreate can be used with " | ||
256 | "sequential devices"); | ||
257 | return false; | ||
258 | } | ||
259 | p->mode=mode; | ||
260 | p->ioDevice = ioDevice; | ||
69 | return true; | 261 | return true; |
70 | } else { | 262 | } else { |
71 | zipError=UNZ_OPENERROR; | 263 | p->zipError=UNZ_OPENERROR; |
264 | if (!p->zipName.isEmpty()) | ||
265 | delete ioDevice; | ||
72 | return false; | 266 | return false; |
73 | } | 267 | } |
74 | case mdCreate: | 268 | case mdCreate: |
75 | case mdAppend: | 269 | case mdAppend: |
76 | case mdAdd: | 270 | case mdAdd: |
77 | zipFile_f=zipOpen2(QFile::encodeName(zipName).constData(), | 271 | if (ioApi == NULL) { |
78 | mode==mdCreate?APPEND_STATUS_CREATE: | 272 | if (p->autoClose) |
79 | mode==mdAppend?APPEND_STATUS_CREATEAFTER: | 273 | flags |= ZIP_AUTO_CLOSE; |
80 | APPEND_STATUS_ADDINZIP, | 274 | if (p->dataDescriptorWritingEnabled) |
81 | NULL, | 275 | flags |= ZIP_WRITE_DATA_DESCRIPTOR; |
82 | ioApi); | 276 | p->zipFile_f=zipOpen3(ioDevice, |
83 | if(zipFile_f!=NULL) { | 277 | mode==mdCreate?APPEND_STATUS_CREATE: |
84 | this->mode=mode; | 278 | mode==mdAppend?APPEND_STATUS_CREATEAFTER: |
279 | APPEND_STATUS_ADDINZIP, | ||
280 | NULL, NULL, flags); | ||
281 | } else { | ||
282 | // QuaZIP pre-zip64 compatibility mode | ||
283 | p->zipFile_f=zipOpen2(ioDevice, | ||
284 | mode==mdCreate?APPEND_STATUS_CREATE: | ||
285 | mode==mdAppend?APPEND_STATUS_CREATEAFTER: | ||
286 | APPEND_STATUS_ADDINZIP, | ||
287 | NULL, | ||
288 | ioApi); | ||
289 | if (p->zipFile_f != NULL) { | ||
290 | zipSetFlags(p->zipFile_f, flags); | ||
291 | } | ||
292 | } | ||
293 | if(p->zipFile_f!=NULL) { | ||
294 | if (ioDevice->isSequential()) { | ||
295 | if (mode != mdCreate) { | ||
296 | zipClose(p->zipFile_f, NULL); | ||
297 | qWarning("QuaZip::open(): " | ||
298 | "only mdCreate can be used with " | ||
299 | "sequential devices"); | ||
300 | if (!p->zipName.isEmpty()) | ||
301 | delete ioDevice; | ||
302 | return false; | ||
303 | } | ||
304 | zipSetFlags(p->zipFile_f, ZIP_SEQUENTIAL); | ||
305 | } | ||
306 | p->mode=mode; | ||
307 | p->ioDevice = ioDevice; | ||
85 | return true; | 308 | return true; |
86 | } else { | 309 | } else { |
87 | zipError=UNZ_OPENERROR; | 310 | p->zipError=UNZ_OPENERROR; |
311 | if (!p->zipName.isEmpty()) | ||
312 | delete ioDevice; | ||
88 | return false; | 313 | return false; |
89 | } | 314 | } |
90 | default: | 315 | default: |
91 | qWarning("QuaZip::open(): unknown mode: %d", (int)mode); | 316 | qWarning("QuaZip::open(): unknown mode: %d", (int)mode); |
317 | if (!p->zipName.isEmpty()) | ||
318 | delete ioDevice; | ||
92 | return false; | 319 | return false; |
93 | break; | 320 | break; |
94 | } | 321 | } |
@@ -96,24 +323,33 @@ bool QuaZip::open(Mode mode, zlib_filefunc_def* ioApi) | |||
96 | 323 | ||
97 | void QuaZip::close() | 324 | void QuaZip::close() |
98 | { | 325 | { |
99 | zipError=UNZ_OK; | 326 | p->zipError=UNZ_OK; |
100 | switch(mode) { | 327 | switch(p->mode) { |
101 | case mdNotOpen: | 328 | case mdNotOpen: |
102 | qWarning("QuaZip::close(): ZIP is not open"); | 329 | qWarning("QuaZip::close(): ZIP is not open"); |
103 | return; | 330 | return; |
104 | case mdUnzip: | 331 | case mdUnzip: |
105 | zipError=unzClose(unzFile_f); | 332 | p->zipError=unzClose(p->unzFile_f); |
106 | break; | 333 | break; |
107 | case mdCreate: | 334 | case mdCreate: |
108 | case mdAppend: | 335 | case mdAppend: |
109 | case mdAdd: | 336 | case mdAdd: |
110 | zipError=zipClose(zipFile_f, commentCodec->fromUnicode(comment).constData()); | 337 | p->zipError=zipClose(p->zipFile_f, |
338 | p->comment.isNull() ? NULL | ||
339 | : p->commentCodec->fromUnicode(p->comment).constData()); | ||
111 | break; | 340 | break; |
112 | default: | 341 | default: |
113 | qWarning("QuaZip::close(): unknown mode: %d", (int)mode); | 342 | qWarning("QuaZip::close(): unknown mode: %d", (int)p->mode); |
114 | return; | 343 | return; |
115 | } | 344 | } |
116 | if(zipError==UNZ_OK) mode=mdNotOpen; | 345 | // opened by name, need to delete the internal IO device |
346 | if (!p->zipName.isEmpty()) { | ||
347 | delete p->ioDevice; | ||
348 | p->ioDevice = NULL; | ||
349 | } | ||
350 | p->clearDirectoryMap(); | ||
351 | if(p->zipError==UNZ_OK) | ||
352 | p->mode=mdNotOpen; | ||
117 | } | 353 | } |
118 | 354 | ||
119 | void QuaZip::setZipName(const QString& zipName) | 355 | void QuaZip::setZipName(const QString& zipName) |
@@ -122,129 +358,171 @@ void QuaZip::setZipName(const QString& zipName) | |||
122 | qWarning("QuaZip::setZipName(): ZIP is already open!"); | 358 | qWarning("QuaZip::setZipName(): ZIP is already open!"); |
123 | return; | 359 | return; |
124 | } | 360 | } |
125 | this->zipName=zipName; | 361 | p->zipName=zipName; |
362 | p->ioDevice = NULL; | ||
363 | } | ||
364 | |||
365 | void QuaZip::setIoDevice(QIODevice *ioDevice) | ||
366 | { | ||
367 | if(isOpen()) { | ||
368 | qWarning("QuaZip::setIoDevice(): ZIP is already open!"); | ||
369 | return; | ||
370 | } | ||
371 | p->ioDevice = ioDevice; | ||
372 | p->zipName = QString(); | ||
126 | } | 373 | } |
127 | 374 | ||
128 | int QuaZip::getEntriesCount()const | 375 | int QuaZip::getEntriesCount()const |
129 | { | 376 | { |
130 | QuaZip *fakeThis=(QuaZip*)this; // non-const | 377 | QuaZip *fakeThis=(QuaZip*)this; // non-const |
131 | fakeThis->zipError=UNZ_OK; | 378 | fakeThis->p->zipError=UNZ_OK; |
132 | if(mode!=mdUnzip) { | 379 | if(p->mode!=mdUnzip) { |
133 | qWarning("QuaZip::getEntriesCount(): ZIP is not open in mdUnzip mode"); | 380 | qWarning("QuaZip::getEntriesCount(): ZIP is not open in mdUnzip mode"); |
134 | return -1; | 381 | return -1; |
135 | } | 382 | } |
136 | unz_global_info globalInfo; | 383 | unz_global_info64 globalInfo; |
137 | if((fakeThis->zipError=unzGetGlobalInfo(unzFile_f, &globalInfo))!=UNZ_OK) | 384 | if((fakeThis->p->zipError=unzGetGlobalInfo64(p->unzFile_f, &globalInfo))!=UNZ_OK) |
138 | return zipError; | 385 | return p->zipError; |
139 | return (int)globalInfo.number_entry; | 386 | return (int)globalInfo.number_entry; |
140 | } | 387 | } |
141 | 388 | ||
142 | QString QuaZip::getComment()const | 389 | QString QuaZip::getComment()const |
143 | { | 390 | { |
144 | QuaZip *fakeThis=(QuaZip*)this; // non-const | 391 | QuaZip *fakeThis=(QuaZip*)this; // non-const |
145 | fakeThis->zipError=UNZ_OK; | 392 | fakeThis->p->zipError=UNZ_OK; |
146 | if(mode!=mdUnzip) { | 393 | if(p->mode!=mdUnzip) { |
147 | qWarning("QuaZip::getComment(): ZIP is not open in mdUnzip mode"); | 394 | qWarning("QuaZip::getComment(): ZIP is not open in mdUnzip mode"); |
148 | return QString(); | 395 | return QString(); |
149 | } | 396 | } |
150 | unz_global_info globalInfo; | 397 | unz_global_info64 globalInfo; |
151 | QByteArray comment; | 398 | QByteArray comment; |
152 | if((fakeThis->zipError=unzGetGlobalInfo(unzFile_f, &globalInfo))!=UNZ_OK) | 399 | if((fakeThis->p->zipError=unzGetGlobalInfo64(p->unzFile_f, &globalInfo))!=UNZ_OK) |
153 | return QString(); | 400 | return QString(); |
154 | comment.resize(globalInfo.size_comment); | 401 | comment.resize(globalInfo.size_comment); |
155 | if((fakeThis->zipError=unzGetGlobalComment(unzFile_f, comment.data(), comment.size()))!=UNZ_OK) | 402 | if((fakeThis->p->zipError=unzGetGlobalComment(p->unzFile_f, comment.data(), comment.size())) < 0) |
156 | return QString(); | 403 | return QString(); |
157 | return commentCodec->toUnicode(comment); | 404 | fakeThis->p->zipError = UNZ_OK; |
405 | return p->commentCodec->toUnicode(comment); | ||
158 | } | 406 | } |
159 | 407 | ||
160 | bool QuaZip::setCurrentFile(const QString& fileName, CaseSensitivity cs) | 408 | bool QuaZip::setCurrentFile(const QString& fileName, CaseSensitivity cs) |
161 | { | 409 | { |
162 | zipError=UNZ_OK; | 410 | p->zipError=UNZ_OK; |
163 | if(mode!=mdUnzip) { | 411 | if(p->mode!=mdUnzip) { |
164 | qWarning("QuaZip::setCurrentFile(): ZIP is not open in mdUnzip mode"); | 412 | qWarning("QuaZip::setCurrentFile(): ZIP is not open in mdUnzip mode"); |
165 | return false; | 413 | return false; |
166 | } | 414 | } |
167 | if(fileName.isNull()) { | 415 | if(fileName.isEmpty()) { |
168 | hasCurrentFile_f=false; | 416 | p->hasCurrentFile_f=false; |
169 | return true; | 417 | return true; |
170 | } | 418 | } |
171 | // Unicode-aware reimplementation of the unzLocateFile function | 419 | // Unicode-aware reimplementation of the unzLocateFile function |
172 | if(unzFile_f==NULL) { | 420 | if(p->unzFile_f==NULL) { |
173 | zipError=UNZ_PARAMERROR; | 421 | p->zipError=UNZ_PARAMERROR; |
174 | return false; | 422 | return false; |
175 | } | 423 | } |
176 | if(fileName.length()>MAX_FILE_NAME_LENGTH) { | 424 | if(fileName.length()>MAX_FILE_NAME_LENGTH) { |
177 | zipError=UNZ_PARAMERROR; | 425 | p->zipError=UNZ_PARAMERROR; |
178 | return false; | 426 | return false; |
179 | } | 427 | } |
180 | bool sens; | 428 | // Find the file by name |
181 | if(cs==csDefault) { | 429 | bool sens = convertCaseSensitivity(cs) == Qt::CaseSensitive; |
182 | #ifdef Q_WS_WIN | ||
183 | sens=false; | ||
184 | #else | ||
185 | sens=true; | ||
186 | #endif | ||
187 | } else sens=cs==csSensitive; | ||
188 | QString lower, current; | 430 | QString lower, current; |
189 | if(!sens) lower=fileName.toLower(); | 431 | if(!sens) lower=fileName.toLower(); |
190 | hasCurrentFile_f=false; | 432 | p->hasCurrentFile_f=false; |
191 | for(bool more=goToFirstFile(); more; more=goToNextFile()) { | 433 | |
434 | // Check the appropriate Map | ||
435 | unz64_file_pos fileDirPos; | ||
436 | fileDirPos.pos_in_zip_directory = 0; | ||
437 | if (sens) { | ||
438 | if (p->directoryCaseSensitive.contains(fileName)) | ||
439 | fileDirPos = p->directoryCaseSensitive.value(fileName); | ||
440 | } else { | ||
441 | if (p->directoryCaseInsensitive.contains(lower)) | ||
442 | fileDirPos = p->directoryCaseInsensitive.value(lower); | ||
443 | } | ||
444 | |||
445 | if (fileDirPos.pos_in_zip_directory != 0) { | ||
446 | p->zipError = unzGoToFilePos64(p->unzFile_f, &fileDirPos); | ||
447 | p->hasCurrentFile_f = p->zipError == UNZ_OK; | ||
448 | } | ||
449 | |||
450 | if (p->hasCurrentFile_f) | ||
451 | return p->hasCurrentFile_f; | ||
452 | |||
453 | // Not mapped yet, start from where we have got to so far | ||
454 | for(bool more=p->goToFirstUnmappedFile(); more; more=goToNextFile()) { | ||
192 | current=getCurrentFileName(); | 455 | current=getCurrentFileName(); |
193 | if(current.isNull()) return false; | 456 | if(current.isEmpty()) return false; |
194 | if(sens) { | 457 | if(sens) { |
195 | if(current==fileName) break; | 458 | if(current==fileName) break; |
196 | } else { | 459 | } else { |
197 | if(current.toLower()==lower) break; | 460 | if(current.toLower()==lower) break; |
198 | } | 461 | } |
199 | } | 462 | } |
200 | return hasCurrentFile_f; | 463 | return p->hasCurrentFile_f; |
201 | } | 464 | } |
202 | 465 | ||
203 | bool QuaZip::goToFirstFile() | 466 | bool QuaZip::goToFirstFile() |
204 | { | 467 | { |
205 | zipError=UNZ_OK; | 468 | p->zipError=UNZ_OK; |
206 | if(mode!=mdUnzip) { | 469 | if(p->mode!=mdUnzip) { |
207 | qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); | 470 | qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); |
208 | return false; | 471 | return false; |
209 | } | 472 | } |
210 | zipError=unzGoToFirstFile(unzFile_f); | 473 | p->zipError=unzGoToFirstFile(p->unzFile_f); |
211 | hasCurrentFile_f=zipError==UNZ_OK; | 474 | p->hasCurrentFile_f=p->zipError==UNZ_OK; |
212 | return hasCurrentFile_f; | 475 | return p->hasCurrentFile_f; |
213 | } | 476 | } |
214 | 477 | ||
215 | bool QuaZip::goToNextFile() | 478 | bool QuaZip::goToNextFile() |
216 | { | 479 | { |
217 | zipError=UNZ_OK; | 480 | p->zipError=UNZ_OK; |
218 | if(mode!=mdUnzip) { | 481 | if(p->mode!=mdUnzip) { |
219 | qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); | 482 | qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); |
220 | return false; | 483 | return false; |
221 | } | 484 | } |
222 | zipError=unzGoToNextFile(unzFile_f); | 485 | p->zipError=unzGoToNextFile(p->unzFile_f); |
223 | hasCurrentFile_f=zipError==UNZ_OK; | 486 | p->hasCurrentFile_f=p->zipError==UNZ_OK; |
224 | if(zipError==UNZ_END_OF_LIST_OF_FILE) zipError=UNZ_OK; | 487 | if(p->zipError==UNZ_END_OF_LIST_OF_FILE) |
225 | return hasCurrentFile_f; | 488 | p->zipError=UNZ_OK; |
489 | return p->hasCurrentFile_f; | ||
226 | } | 490 | } |
227 | 491 | ||
228 | bool QuaZip::getCurrentFileInfo(QuaZipFileInfo *info)const | 492 | bool QuaZip::getCurrentFileInfo(QuaZipFileInfo *info)const |
229 | { | 493 | { |
494 | QuaZipFileInfo64 info64; | ||
495 | if (info == NULL) { // Very unlikely because of the overloads | ||
496 | return false; | ||
497 | } | ||
498 | if (getCurrentFileInfo(&info64)) { | ||
499 | info64.toQuaZipFileInfo(*info); | ||
500 | return true; | ||
501 | } else { | ||
502 | return false; | ||
503 | } | ||
504 | } | ||
505 | |||
506 | bool QuaZip::getCurrentFileInfo(QuaZipFileInfo64 *info)const | ||
507 | { | ||
230 | QuaZip *fakeThis=(QuaZip*)this; // non-const | 508 | QuaZip *fakeThis=(QuaZip*)this; // non-const |
231 | fakeThis->zipError=UNZ_OK; | 509 | fakeThis->p->zipError=UNZ_OK; |
232 | if(mode!=mdUnzip) { | 510 | if(p->mode!=mdUnzip) { |
233 | qWarning("QuaZip::getCurrentFileInfo(): ZIP is not open in mdUnzip mode"); | 511 | qWarning("QuaZip::getCurrentFileInfo(): ZIP is not open in mdUnzip mode"); |
234 | return false; | 512 | return false; |
235 | } | 513 | } |
236 | unz_file_info info_z; | 514 | unz_file_info64 info_z; |
237 | QByteArray fileName; | 515 | QByteArray fileName; |
238 | QByteArray extra; | 516 | QByteArray extra; |
239 | QByteArray comment; | 517 | QByteArray comment; |
240 | if(info==NULL) return false; | 518 | if(info==NULL) return false; |
241 | if(!isOpen()||!hasCurrentFile()) return false; | 519 | if(!isOpen()||!hasCurrentFile()) return false; |
242 | if((fakeThis->zipError=unzGetCurrentFileInfo(unzFile_f, &info_z, NULL, 0, NULL, 0, NULL, 0))!=UNZ_OK) | 520 | if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, &info_z, NULL, 0, NULL, 0, NULL, 0))!=UNZ_OK) |
243 | return false; | 521 | return false; |
244 | fileName.resize(info_z.size_filename); | 522 | fileName.resize(info_z.size_filename); |
245 | extra.resize(info_z.size_file_extra); | 523 | extra.resize(info_z.size_file_extra); |
246 | comment.resize(info_z.size_file_comment); | 524 | comment.resize(info_z.size_file_comment); |
247 | if((fakeThis->zipError=unzGetCurrentFileInfo(unzFile_f, NULL, | 525 | if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, NULL, |
248 | fileName.data(), fileName.size(), | 526 | fileName.data(), fileName.size(), |
249 | extra.data(), extra.size(), | 527 | extra.data(), extra.size(), |
250 | comment.data(), comment.size()))!=UNZ_OK) | 528 | comment.data(), comment.size()))!=UNZ_OK) |
@@ -259,27 +537,252 @@ bool QuaZip::getCurrentFileInfo(QuaZipFileInfo *info)const | |||
259 | info->diskNumberStart=info_z.disk_num_start; | 537 | info->diskNumberStart=info_z.disk_num_start; |
260 | info->internalAttr=info_z.internal_fa; | 538 | info->internalAttr=info_z.internal_fa; |
261 | info->externalAttr=info_z.external_fa; | 539 | info->externalAttr=info_z.external_fa; |
262 | info->name=fileNameCodec->toUnicode(fileName); | 540 | info->name=p->fileNameCodec->toUnicode(fileName); |
263 | info->comment=commentCodec->toUnicode(comment); | 541 | info->comment=p->commentCodec->toUnicode(comment); |
264 | info->extra=extra; | 542 | info->extra=extra; |
265 | info->dateTime=QDateTime( | 543 | info->dateTime=QDateTime( |
266 | QDate(info_z.tmu_date.tm_year, info_z.tmu_date.tm_mon+1, info_z.tmu_date.tm_mday), | 544 | QDate(info_z.tmu_date.tm_year, info_z.tmu_date.tm_mon+1, info_z.tmu_date.tm_mday), |
267 | QTime(info_z.tmu_date.tm_hour, info_z.tmu_date.tm_min, info_z.tmu_date.tm_sec)); | 545 | QTime(info_z.tmu_date.tm_hour, info_z.tmu_date.tm_min, info_z.tmu_date.tm_sec)); |
546 | // Add to directory map | ||
547 | p->addCurrentFileToDirectoryMap(info->name); | ||
268 | return true; | 548 | return true; |
269 | } | 549 | } |
270 | 550 | ||
271 | QString QuaZip::getCurrentFileName()const | 551 | QString QuaZip::getCurrentFileName()const |
272 | { | 552 | { |
273 | QuaZip *fakeThis=(QuaZip*)this; // non-const | 553 | QuaZip *fakeThis=(QuaZip*)this; // non-const |
274 | fakeThis->zipError=UNZ_OK; | 554 | fakeThis->p->zipError=UNZ_OK; |
275 | if(mode!=mdUnzip) { | 555 | if(p->mode!=mdUnzip) { |
276 | qWarning("QuaZip::getCurrentFileName(): ZIP is not open in mdUnzip mode"); | 556 | qWarning("QuaZip::getCurrentFileName(): ZIP is not open in mdUnzip mode"); |
277 | return QString(); | 557 | return QString(); |
278 | } | 558 | } |
279 | if(!isOpen()||!hasCurrentFile()) return QString(); | 559 | if(!isOpen()||!hasCurrentFile()) return QString(); |
280 | QByteArray fileName(MAX_FILE_NAME_LENGTH, 0); | 560 | QByteArray fileName(MAX_FILE_NAME_LENGTH, 0); |
281 | if((fakeThis->zipError=unzGetCurrentFileInfo(unzFile_f, NULL, fileName.data(), fileName.size(), | 561 | if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, NULL, fileName.data(), fileName.size(), |
282 | NULL, 0, NULL, 0))!=UNZ_OK) | 562 | NULL, 0, NULL, 0))!=UNZ_OK) |
283 | return QString(); | 563 | return QString(); |
284 | return fileNameCodec->toUnicode(fileName.constData()); | 564 | QString result = p->fileNameCodec->toUnicode(fileName.constData()); |
565 | if (result.isEmpty()) | ||
566 | return result; | ||
567 | // Add to directory map | ||
568 | p->addCurrentFileToDirectoryMap(result); | ||
569 | return result; | ||
570 | } | ||
571 | |||
572 | void QuaZip::setFileNameCodec(QTextCodec *fileNameCodec) | ||
573 | { | ||
574 | p->fileNameCodec=fileNameCodec; | ||
575 | } | ||
576 | |||
577 | void QuaZip::setFileNameCodec(const char *fileNameCodecName) | ||
578 | { | ||
579 | p->fileNameCodec=QTextCodec::codecForName(fileNameCodecName); | ||
580 | } | ||
581 | |||
582 | QTextCodec *QuaZip::getFileNameCodec()const | ||
583 | { | ||
584 | return p->fileNameCodec; | ||
585 | } | ||
586 | |||
587 | void QuaZip::setCommentCodec(QTextCodec *commentCodec) | ||
588 | { | ||
589 | p->commentCodec=commentCodec; | ||
590 | } | ||
591 | |||
592 | void QuaZip::setCommentCodec(const char *commentCodecName) | ||
593 | { | ||
594 | p->commentCodec=QTextCodec::codecForName(commentCodecName); | ||
595 | } | ||
596 | |||
597 | QTextCodec *QuaZip::getCommentCodec()const | ||
598 | { | ||
599 | return p->commentCodec; | ||
600 | } | ||
601 | |||
602 | QString QuaZip::getZipName() const | ||
603 | { | ||
604 | return p->zipName; | ||
605 | } | ||
606 | |||
607 | QIODevice *QuaZip::getIoDevice() const | ||
608 | { | ||
609 | if (!p->zipName.isEmpty()) // opened by name, using an internal QIODevice | ||
610 | return NULL; | ||
611 | return p->ioDevice; | ||
612 | } | ||
613 | |||
614 | QuaZip::Mode QuaZip::getMode()const | ||
615 | { | ||
616 | return p->mode; | ||
617 | } | ||
618 | |||
619 | bool QuaZip::isOpen()const | ||
620 | { | ||
621 | return p->mode!=mdNotOpen; | ||
622 | } | ||
623 | |||
624 | int QuaZip::getZipError() const | ||
625 | { | ||
626 | return p->zipError; | ||
627 | } | ||
628 | |||
629 | void QuaZip::setComment(const QString& comment) | ||
630 | { | ||
631 | p->comment=comment; | ||
632 | } | ||
633 | |||
634 | bool QuaZip::hasCurrentFile()const | ||
635 | { | ||
636 | return p->hasCurrentFile_f; | ||
637 | } | ||
638 | |||
639 | unzFile QuaZip::getUnzFile() | ||
640 | { | ||
641 | return p->unzFile_f; | ||
642 | } | ||
643 | |||
644 | zipFile QuaZip::getZipFile() | ||
645 | { | ||
646 | return p->zipFile_f; | ||
647 | } | ||
648 | |||
649 | void QuaZip::setDataDescriptorWritingEnabled(bool enabled) | ||
650 | { | ||
651 | p->dataDescriptorWritingEnabled = enabled; | ||
652 | } | ||
653 | |||
654 | bool QuaZip::isDataDescriptorWritingEnabled() const | ||
655 | { | ||
656 | return p->dataDescriptorWritingEnabled; | ||
657 | } | ||
658 | |||
659 | template<typename TFileInfo> | ||
660 | TFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok); | ||
661 | |||
662 | template<> | ||
663 | QuaZipFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok) | ||
664 | { | ||
665 | QuaZipFileInfo info; | ||
666 | *ok = zip->getCurrentFileInfo(&info); | ||
667 | return info; | ||
668 | } | ||
669 | |||
670 | template<> | ||
671 | QuaZipFileInfo64 QuaZip_getFileInfo(QuaZip *zip, bool *ok) | ||
672 | { | ||
673 | QuaZipFileInfo64 info; | ||
674 | *ok = zip->getCurrentFileInfo(&info); | ||
675 | return info; | ||
676 | } | ||
677 | |||
678 | template<> | ||
679 | QString QuaZip_getFileInfo(QuaZip *zip, bool *ok) | ||
680 | { | ||
681 | QString name = zip->getCurrentFileName(); | ||
682 | *ok = !name.isEmpty(); | ||
683 | return name; | ||
684 | } | ||
685 | |||
686 | template<typename TFileInfo> | ||
687 | bool QuaZipPrivate::getFileInfoList(QList<TFileInfo> *result) const | ||
688 | { | ||
689 | QuaZipPrivate *fakeThis=const_cast<QuaZipPrivate*>(this); | ||
690 | fakeThis->zipError=UNZ_OK; | ||
691 | if (mode!=QuaZip::mdUnzip) { | ||
692 | qWarning("QuaZip::getFileNameList/getFileInfoList(): " | ||
693 | "ZIP is not open in mdUnzip mode"); | ||
694 | return false; | ||
695 | } | ||
696 | QString currentFile; | ||
697 | if (q->hasCurrentFile()) { | ||
698 | currentFile = q->getCurrentFileName(); | ||
699 | } | ||
700 | if (q->goToFirstFile()) { | ||
701 | do { | ||
702 | bool ok; | ||
703 | result->append(QuaZip_getFileInfo<TFileInfo>(q, &ok)); | ||
704 | if (!ok) | ||
705 | return false; | ||
706 | } while (q->goToNextFile()); | ||
707 | } | ||
708 | if (zipError != UNZ_OK) | ||
709 | return false; | ||
710 | if (currentFile.isEmpty()) { | ||
711 | if (!q->goToFirstFile()) | ||
712 | return false; | ||
713 | } else { | ||
714 | if (!q->setCurrentFile(currentFile)) | ||
715 | return false; | ||
716 | } | ||
717 | return true; | ||
718 | } | ||
719 | |||
720 | QStringList QuaZip::getFileNameList() const | ||
721 | { | ||
722 | QStringList list; | ||
723 | if (p->getFileInfoList(&list)) | ||
724 | return list; | ||
725 | else | ||
726 | return QStringList(); | ||
727 | } | ||
728 | |||
729 | QList<QuaZipFileInfo> QuaZip::getFileInfoList() const | ||
730 | { | ||
731 | QList<QuaZipFileInfo> list; | ||
732 | if (p->getFileInfoList(&list)) | ||
733 | return list; | ||
734 | else | ||
735 | return QList<QuaZipFileInfo>(); | ||
736 | } | ||
737 | |||
738 | QList<QuaZipFileInfo64> QuaZip::getFileInfoList64() const | ||
739 | { | ||
740 | QList<QuaZipFileInfo64> list; | ||
741 | if (p->getFileInfoList(&list)) | ||
742 | return list; | ||
743 | else | ||
744 | return QList<QuaZipFileInfo64>(); | ||
745 | } | ||
746 | |||
747 | Qt::CaseSensitivity QuaZip::convertCaseSensitivity(QuaZip::CaseSensitivity cs) | ||
748 | { | ||
749 | if (cs == csDefault) { | ||
750 | #ifdef Q_WS_WIN | ||
751 | return Qt::CaseInsensitive; | ||
752 | #else | ||
753 | return Qt::CaseSensitive; | ||
754 | #endif | ||
755 | } else { | ||
756 | return cs == csSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; | ||
757 | } | ||
758 | } | ||
759 | |||
760 | void QuaZip::setDefaultFileNameCodec(QTextCodec *codec) | ||
761 | { | ||
762 | QuaZipPrivate::defaultFileNameCodec = codec; | ||
763 | } | ||
764 | |||
765 | void QuaZip::setDefaultFileNameCodec(const char *codecName) | ||
766 | { | ||
767 | setDefaultFileNameCodec(QTextCodec::codecForName(codecName)); | ||
768 | } | ||
769 | |||
770 | void QuaZip::setZip64Enabled(bool zip64) | ||
771 | { | ||
772 | p->zip64 = zip64; | ||
773 | } | ||
774 | |||
775 | bool QuaZip::isZip64Enabled() const | ||
776 | { | ||
777 | return p->zip64; | ||
778 | } | ||
779 | |||
780 | bool QuaZip::isAutoClose() const | ||
781 | { | ||
782 | return p->autoClose; | ||
783 | } | ||
784 | |||
785 | void QuaZip::setAutoClose(bool autoClose) const | ||
786 | { | ||
787 | p->autoClose = autoClose; | ||
285 | } | 788 | } |