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