|
1 #ifndef QUA_ZIP_H |
|
2 #define QUA_ZIP_H |
|
3 |
|
4 /* |
|
5 Copyright (C) 2005-2011 Sergey A. Tachenov |
|
6 |
|
7 This program is free software; you can redistribute it and/or modify it |
|
8 under the terms of the GNU Lesser General Public License as published by |
|
9 the Free Software Foundation; either version 2 of the License, or (at |
|
10 your option) any later version. |
|
11 |
|
12 This program is distributed in the hope that it will be useful, but |
|
13 WITHOUT ANY WARRANTY; without even the implied warranty of |
|
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
|
15 General Public License for more details. |
|
16 |
|
17 You should have received a copy of the GNU Lesser General Public License |
|
18 along with this program; if not, write to the Free Software Foundation, |
|
19 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
20 |
|
21 See COPYING file for the full LGPL text. |
|
22 |
|
23 Original ZIP package is copyrighted by Gilles Vollant, see |
|
24 quazip/(un)zip.h files for details, basically it's zlib license. |
|
25 **/ |
|
26 |
|
27 #include <QString> |
|
28 #include <QTextCodec> |
|
29 |
|
30 #include "zip.h" |
|
31 #include "unzip.h" |
|
32 |
|
33 #include "quazip_global.h" |
|
34 #include "quazipfileinfo.h" |
|
35 |
|
36 // just in case it will be defined in the later versions of the ZIP/UNZIP |
|
37 #ifndef UNZ_OPENERROR |
|
38 // define additional error code |
|
39 #define UNZ_OPENERROR -1000 |
|
40 #endif |
|
41 |
|
42 class QuaZipPrivate; |
|
43 |
|
44 /// ZIP archive. |
|
45 /** \class QuaZip quazip.h <quazip/quazip.h> |
|
46 * This class implements basic interface to the ZIP archive. It can be |
|
47 * used to read table contents of the ZIP archive and retreiving |
|
48 * information about the files inside it. |
|
49 * |
|
50 * You can also use this class to open files inside archive by passing |
|
51 * pointer to the instance of this class to the constructor of the |
|
52 * QuaZipFile class. But see QuaZipFile::QuaZipFile(QuaZip*, QObject*) |
|
53 * for the possible pitfalls. |
|
54 * |
|
55 * This class is indended to provide interface to the ZIP subpackage of |
|
56 * the ZIP/UNZIP package as well as to the UNZIP subpackage. But |
|
57 * currently it supports only UNZIP. |
|
58 * |
|
59 * The use of this class is simple - just create instance using |
|
60 * constructor, then set ZIP archive file name using setFile() function |
|
61 * (if you did not passed the name to the constructor), then open() and |
|
62 * then use different functions to work with it! Well, if you are |
|
63 * paranoid, you may also wish to call close before destructing the |
|
64 * instance, to check for errors on close. |
|
65 * |
|
66 * You may also use getUnzFile() and getZipFile() functions to get the |
|
67 * ZIP archive handle and use it with ZIP/UNZIP package API directly. |
|
68 * |
|
69 * This class supports localized file names inside ZIP archive, but you |
|
70 * have to set up proper codec with setCodec() function. By default, |
|
71 * locale codec will be used, which is probably ok for UNIX systems, but |
|
72 * will almost certainly fail with ZIP archives created in Windows. This |
|
73 * is because Windows ZIP programs have strange habit of using DOS |
|
74 * encoding for file names in ZIP archives. For example, ZIP archive |
|
75 * with cyrillic names created in Windows will have file names in \c |
|
76 * IBM866 encoding instead of \c WINDOWS-1251. I think that calling one |
|
77 * function is not much trouble, but for true platform independency it |
|
78 * would be nice to have some mechanism for file name encoding auto |
|
79 * detection using locale information. Does anyone know a good way to do |
|
80 * it? |
|
81 **/ |
|
82 class QUAZIP_EXPORT QuaZip { |
|
83 friend class QuaZipPrivate; |
|
84 public: |
|
85 /// Useful constants. |
|
86 enum Constants { |
|
87 MAX_FILE_NAME_LENGTH=256 /**< Maximum file name length. Taken from |
|
88 \c UNZ_MAXFILENAMEINZIP constant in |
|
89 unzip.c. */ |
|
90 }; |
|
91 /// Open mode of the ZIP file. |
|
92 enum Mode { |
|
93 mdNotOpen, ///< ZIP file is not open. This is the initial mode. |
|
94 mdUnzip, ///< ZIP file is open for reading files inside it. |
|
95 mdCreate, ///< ZIP file was created with open() call. |
|
96 mdAppend, /**< ZIP file was opened in append mode. This refers to |
|
97 * \c APPEND_STATUS_CREATEAFTER mode in ZIP/UNZIP package |
|
98 * and means that zip is appended to some existing file |
|
99 * what is useful when that file contains |
|
100 * self-extractor code. This is obviously \em not what |
|
101 * you whant to use to add files to the existing ZIP |
|
102 * archive. |
|
103 **/ |
|
104 mdAdd ///< ZIP file was opened for adding files in the archive. |
|
105 }; |
|
106 /// Case sensitivity for the file names. |
|
107 /** This is what you specify when accessing files in the archive. |
|
108 * Works perfectly fine with any characters thanks to Qt's great |
|
109 * unicode support. This is different from ZIP/UNZIP API, where |
|
110 * only US-ASCII characters was supported. |
|
111 **/ |
|
112 enum CaseSensitivity { |
|
113 csDefault=0, ///< Default for platform. Case sensitive for UNIX, not for Windows. |
|
114 csSensitive=1, ///< Case sensitive. |
|
115 csInsensitive=2 ///< Case insensitive. |
|
116 }; |
|
117 private: |
|
118 QuaZipPrivate *p; |
|
119 // not (and will not be) implemented |
|
120 QuaZip(const QuaZip& that); |
|
121 // not (and will not be) implemented |
|
122 QuaZip& operator=(const QuaZip& that); |
|
123 public: |
|
124 /// Constructs QuaZip object. |
|
125 /** Call setName() before opening constructed object. */ |
|
126 QuaZip(); |
|
127 /// Constructs QuaZip object associated with ZIP file \a zipName. |
|
128 QuaZip(const QString& zipName); |
|
129 /// Constructs QuaZip object associated with ZIP file represented by \a ioDevice. |
|
130 /** The IO device must be seekable, otherwise an error will occur when opening. */ |
|
131 QuaZip(QIODevice *ioDevice); |
|
132 /// Destroys QuaZip object. |
|
133 /** Calls close() if necessary. */ |
|
134 ~QuaZip(); |
|
135 /// Opens ZIP file. |
|
136 /** |
|
137 * Argument \a mode specifies open mode of the ZIP archive. See Mode |
|
138 * for details. Note that there is zipOpen2() function in the |
|
139 * ZIP/UNZIP API which accepts \a globalcomment argument, but it |
|
140 * does not use it anywhere, so this open() function does not have this |
|
141 * argument. See setComment() if you need to set global comment. |
|
142 * |
|
143 * If the ZIP file is accessed via explicitly set QIODevice, then |
|
144 * this device is opened in the necessary mode. If the device was |
|
145 * already opened by some other means, then the behaviour is defined by |
|
146 * the device implementation, but generally it is not a very good |
|
147 * idea. For example, QFile will at least issue a warning. |
|
148 * |
|
149 * \return \c true if successful, \c false otherwise. |
|
150 * |
|
151 * \note ZIP/UNZIP API open calls do not return error code - they |
|
152 * just return \c NULL indicating an error. But to make things |
|
153 * easier, quazip.h header defines additional error code \c |
|
154 * UNZ_ERROROPEN and getZipError() will return it if the open call |
|
155 * of the ZIP/UNZIP API returns \c NULL. |
|
156 * |
|
157 * Argument \a ioApi specifies IO function set for ZIP/UNZIP |
|
158 * package to use. See unzip.h, zip.h and ioapi.h for details. Note |
|
159 * that IO API for QuaZip is different from the original package. |
|
160 * The file path argument was changed to be of type \c voidpf, and |
|
161 * QuaZip passes a QIODevice pointer there. This QIODevice is either |
|
162 * set explicitly via setIoDevice() or the QuaZip(QIODevice*) |
|
163 * constructor, or it is created internally when opening the archive |
|
164 * by its file name. The default API (qioapi.cpp) just delegates |
|
165 * everything to the QIODevice API. Not only this allows to use a |
|
166 * QIODevice instead of file name, but also has a nice side effect |
|
167 * of raising the file size limit from 2G to 4G. |
|
168 * |
|
169 * In short: just forget about the \a ioApi argument and you'll be |
|
170 * fine. |
|
171 **/ |
|
172 bool open(Mode mode, zlib_filefunc_def *ioApi =NULL); |
|
173 /// Closes ZIP file. |
|
174 /** Call getZipError() to determine if the close was successful. The |
|
175 * underlying QIODevice is also closed, regardless of whether it was |
|
176 * set explicitly or not. */ |
|
177 void close(); |
|
178 /// Sets the codec used to encode/decode file names inside archive. |
|
179 /** This is necessary to access files in the ZIP archive created |
|
180 * under Windows with non-latin characters in file names. For |
|
181 * example, file names with cyrillic letters will be in \c IBM866 |
|
182 * encoding. |
|
183 **/ |
|
184 void setFileNameCodec(QTextCodec *fileNameCodec); |
|
185 /// Sets the codec used to encode/decode file names inside archive. |
|
186 /** \overload |
|
187 * Equivalent to calling setFileNameCodec(QTextCodec::codecForName(codecName)); |
|
188 **/ |
|
189 void setFileNameCodec(const char *fileNameCodecName); |
|
190 /// Returns the codec used to encode/decode comments inside archive. |
|
191 QTextCodec* getFileNameCodec() const; |
|
192 /// Sets the codec used to encode/decode comments inside archive. |
|
193 /** This codec defaults to locale codec, which is probably ok. |
|
194 **/ |
|
195 void setCommentCodec(QTextCodec *commentCodec); |
|
196 /// Sets the codec used to encode/decode comments inside archive. |
|
197 /** \overload |
|
198 * Equivalent to calling setCommentCodec(QTextCodec::codecForName(codecName)); |
|
199 **/ |
|
200 void setCommentCodec(const char *commentCodecName); |
|
201 /// Returns the codec used to encode/decode comments inside archive. |
|
202 QTextCodec* getCommentCodec() const; |
|
203 /// Returns the name of the ZIP file. |
|
204 /** Returns null string if no ZIP file name has been set, for |
|
205 * example when the QuaZip instance is set up to use a QIODevice |
|
206 * instead. |
|
207 * \sa setZipName(), setIoDevice(), getIoDevice() |
|
208 **/ |
|
209 QString getZipName() const; |
|
210 /// Sets the name of the ZIP file. |
|
211 /** Does nothing if the ZIP file is open. |
|
212 * |
|
213 * Does not reset error code returned by getZipError(). |
|
214 * \sa setIoDevice(), getIoDevice(), getZipName() |
|
215 **/ |
|
216 void setZipName(const QString& zipName); |
|
217 /// Returns the device representing this ZIP file. |
|
218 /** Returns null string if no device has been set explicitly, for |
|
219 * example when opening a ZIP file by name. |
|
220 * \sa setIoDevice(), getZipName(), setZipName() |
|
221 **/ |
|
222 QIODevice *getIoDevice() const; |
|
223 /// Sets the device representing the ZIP file. |
|
224 /** Does nothing if the ZIP file is open. |
|
225 * |
|
226 * Does not reset error code returned by getZipError(). |
|
227 * \sa getIoDevice(), getZipName(), setZipName() |
|
228 **/ |
|
229 void setIoDevice(QIODevice *ioDevice); |
|
230 /// Returns the mode in which ZIP file was opened. |
|
231 Mode getMode() const; |
|
232 /// Returns \c true if ZIP file is open, \c false otherwise. |
|
233 bool isOpen() const; |
|
234 /// Returns the error code of the last operation. |
|
235 /** Returns \c UNZ_OK if the last operation was successful. |
|
236 * |
|
237 * Error code resets to \c UNZ_OK every time you call any function |
|
238 * that accesses something inside ZIP archive, even if it is \c |
|
239 * const (like getEntriesCount()). open() and close() calls reset |
|
240 * error code too. See documentation for the specific functions for |
|
241 * details on error detection. |
|
242 **/ |
|
243 int getZipError() const; |
|
244 /// Returns number of the entries in the ZIP central directory. |
|
245 /** Returns negative error code in the case of error. The same error |
|
246 * code will be returned by subsequent getZipError() call. |
|
247 **/ |
|
248 int getEntriesCount() const; |
|
249 /// Returns global comment in the ZIP file. |
|
250 QString getComment() const; |
|
251 /// Sets global comment in the ZIP file. |
|
252 /** Comment will be written to the archive on close operation. |
|
253 * |
|
254 * \sa open() |
|
255 **/ |
|
256 void setComment(const QString& comment); |
|
257 /// Sets the current file to the first file in the archive. |
|
258 /** Returns \c true on success, \c false otherwise. Call |
|
259 * getZipError() to get the error code. |
|
260 **/ |
|
261 bool goToFirstFile(); |
|
262 /// Sets the current file to the next file in the archive. |
|
263 /** Returns \c true on success, \c false otherwise. Call |
|
264 * getZipError() to determine if there was an error. |
|
265 * |
|
266 * Should be used only in QuaZip::mdUnzip mode. |
|
267 * |
|
268 * \note If the end of file was reached, getZipError() will return |
|
269 * \c UNZ_OK instead of \c UNZ_END_OF_LIST_OF_FILE. This is to make |
|
270 * things like this easier: |
|
271 * \code |
|
272 * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { |
|
273 * // do something |
|
274 * } |
|
275 * if(zip.getZipError()==UNZ_OK) { |
|
276 * // ok, there was no error |
|
277 * } |
|
278 * \endcode |
|
279 **/ |
|
280 bool goToNextFile(); |
|
281 /// Sets current file by its name. |
|
282 /** Returns \c true if successful, \c false otherwise. Argument \a |
|
283 * cs specifies case sensitivity of the file name. Call |
|
284 * getZipError() in the case of a failure to get error code. |
|
285 * |
|
286 * This is not a wrapper to unzLocateFile() function. That is |
|
287 * because I had to implement locale-specific case-insensitive |
|
288 * comparison. |
|
289 * |
|
290 * Here are the differences from the original implementation: |
|
291 * |
|
292 * - If the file was not found, error code is \c UNZ_OK, not \c |
|
293 * UNZ_END_OF_LIST_OF_FILE (see also goToNextFile()). |
|
294 * - If this function fails, it unsets the current file rather than |
|
295 * resetting it back to what it was before the call. |
|
296 * |
|
297 * If \a fileName is null string then this function unsets the |
|
298 * current file and return \c true. Note that you should close the |
|
299 * file first if it is open! See |
|
300 * QuaZipFile::QuaZipFile(QuaZip*,QObject*) for the details. |
|
301 * |
|
302 * Should be used only in QuaZip::mdUnzip mode. |
|
303 * |
|
304 * \sa setFileNameCodec(), CaseSensitivity |
|
305 **/ |
|
306 bool setCurrentFile(const QString& fileName, CaseSensitivity cs =csDefault); |
|
307 /// Returns \c true if the current file has been set. |
|
308 bool hasCurrentFile() const; |
|
309 /// Retrieves information about the current file. |
|
310 /** Fills the structure pointed by \a info. Returns \c true on |
|
311 * success, \c false otherwise. In the latter case structure pointed |
|
312 * by \a info remains untouched. If there was an error, |
|
313 * getZipError() returns error code. |
|
314 * |
|
315 * Should be used only in QuaZip::mdUnzip mode. |
|
316 * |
|
317 * Does nothing and returns \c false in any of the following cases. |
|
318 * - ZIP is not open; |
|
319 * - ZIP does not have current file; |
|
320 * - \a info is \c NULL; |
|
321 * |
|
322 * In all these cases getZipError() returns \c UNZ_OK since there |
|
323 * is no ZIP/UNZIP API call. |
|
324 **/ |
|
325 bool getCurrentFileInfo(QuaZipFileInfo* info)const; |
|
326 /// Returns the current file name. |
|
327 /** Equivalent to calling getCurrentFileInfo() and then getting \c |
|
328 * name field of the QuaZipFileInfo structure, but faster and more |
|
329 * convenient. |
|
330 * |
|
331 * Should be used only in QuaZip::mdUnzip mode. |
|
332 **/ |
|
333 QString getCurrentFileName()const; |
|
334 /// Returns \c unzFile handle. |
|
335 /** You can use this handle to directly call UNZIP part of the |
|
336 * ZIP/UNZIP package functions (see unzip.h). |
|
337 * |
|
338 * \warning When using the handle returned by this function, please |
|
339 * keep in mind that QuaZip class is unable to detect any changes |
|
340 * you make in the ZIP file state (e. g. changing current file, or |
|
341 * closing the handle). So please do not do anything with this |
|
342 * handle that is possible to do with the functions of this class. |
|
343 * Or at least return the handle in the original state before |
|
344 * calling some another function of this class (including implicit |
|
345 * destructor calls and calls from the QuaZipFile objects that refer |
|
346 * to this QuaZip instance!). So if you have changed the current |
|
347 * file in the ZIP archive - then change it back or you may |
|
348 * experience some strange behavior or even crashes. |
|
349 **/ |
|
350 unzFile getUnzFile(); |
|
351 /// Returns \c zipFile handle. |
|
352 /** You can use this handle to directly call ZIP part of the |
|
353 * ZIP/UNZIP package functions (see zip.h). Warnings about the |
|
354 * getUnzFile() function also apply to this function. |
|
355 **/ |
|
356 zipFile getZipFile(); |
|
357 }; |
|
358 |
|
359 #endif |