5752
+ − 1
#ifndef QUA_ZIPFILE_H
+ − 2
#define QUA_ZIPFILE_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 <QIODevice>
+ − 28
+ − 29
#include "quazip_global.h"
+ − 30
#include "quazip.h"
+ − 31
#include "quazipnewinfo.h"
+ − 32
+ − 33
class QuaZipFilePrivate;
+ − 34
+ − 35
/// A file inside ZIP archive.
+ − 36
/** \class QuaZipFile quazipfile.h <quazip/quazipfile.h>
+ − 37
* This is the most interesting class. Not only it provides C++
+ − 38
* interface to the ZIP/UNZIP package, but also integrates it with Qt by
+ − 39
* subclassing QIODevice. This makes possible to access files inside ZIP
+ − 40
* archive using QTextStream or QDataStream, for example. Actually, this
+ − 41
* is the main purpose of the whole QuaZIP library.
+ − 42
*
+ − 43
* You can either use existing QuaZip instance to create instance of
+ − 44
* this class or pass ZIP archive file name to this class, in which case
+ − 45
* it will create internal QuaZip object. See constructors' descriptions
+ − 46
* for details. Writing is only possible with the existing instance.
+ − 47
*
+ − 48
* Note that due to the underlying library's limitation it is not
+ − 49
* possible to use multiple QuaZipFile instances to open several files
+ − 50
* in the same archive at the same time. If you need to write to
+ − 51
* multiple files in parallel, then you should write to temporary files
+ − 52
* first, then pack them all at once when you have finished writing. If
+ − 53
* you need to read multiple files inside the same archive in parallel,
+ − 54
* you should extract them all into a temporary directory first.
+ − 55
*
+ − 56
* \section quazipfile-sequential Sequential or random-access?
+ − 57
*
+ − 58
* At the first thought, QuaZipFile has fixed size, the start and the
+ − 59
* end and should be therefore considered random-access device. But
+ − 60
* there is one major obstacle to making it random-access: ZIP/UNZIP API
+ − 61
* does not support seek() operation and the only way to implement it is
+ − 62
* through reopening the file and re-reading to the required position,
+ − 63
* but this is prohibitively slow.
+ − 64
*
+ − 65
* Therefore, QuaZipFile is considered to be a sequential device. This
+ − 66
* has advantage of availability of the ungetChar() operation (QIODevice
+ − 67
* does not implement it properly for non-sequential devices unless they
+ − 68
* support seek()). Disadvantage is a somewhat strange behaviour of the
+ − 69
* size() and pos() functions. This should be kept in mind while using
+ − 70
* this class.
+ − 71
*
+ − 72
**/
+ − 73
class QUAZIP_EXPORT QuaZipFile: public QIODevice {
+ − 74
friend class QuaZipFilePrivate;
+ − 75
Q_OBJECT
+ − 76
private:
+ − 77
QuaZipFilePrivate *p;
+ − 78
// these are not supported nor implemented
+ − 79
QuaZipFile(const QuaZipFile& that);
+ − 80
QuaZipFile& operator=(const QuaZipFile& that);
+ − 81
protected:
+ − 82
/// Implementation of the QIODevice::readData().
+ − 83
qint64 readData(char *data, qint64 maxSize);
+ − 84
/// Implementation of the QIODevice::writeData().
+ − 85
qint64 writeData(const char *data, qint64 maxSize);
+ − 86
public:
+ − 87
/// Constructs a QuaZipFile instance.
+ − 88
/** You should use setZipName() and setFileName() or setZip() before
+ − 89
* trying to call open() on the constructed object.
+ − 90
**/
+ − 91
QuaZipFile();
+ − 92
/// Constructs a QuaZipFile instance.
+ − 93
/** \a parent argument specifies this object's parent object.
+ − 94
*
+ − 95
* You should use setZipName() and setFileName() or setZip() before
+ − 96
* trying to call open() on the constructed object.
+ − 97
**/
+ − 98
QuaZipFile(QObject *parent);
+ − 99
/// Constructs a QuaZipFile instance.
+ − 100
/** \a parent argument specifies this object's parent object and \a
+ − 101
* zipName specifies ZIP archive file name.
+ − 102
*
+ − 103
* You should use setFileName() before trying to call open() on the
+ − 104
* constructed object.
+ − 105
*
+ − 106
* QuaZipFile constructed by this constructor can be used for read
+ − 107
* only access. Use QuaZipFile(QuaZip*,QObject*) for writing.
+ − 108
**/
+ − 109
QuaZipFile(const QString& zipName, QObject *parent =NULL);
+ − 110
/// Constructs a QuaZipFile instance.
+ − 111
/** \a parent argument specifies this object's parent object, \a
+ − 112
* zipName specifies ZIP archive file name and \a fileName and \a cs
+ − 113
* specify a name of the file to open inside archive.
+ − 114
*
+ − 115
* QuaZipFile constructed by this constructor can be used for read
+ − 116
* only access. Use QuaZipFile(QuaZip*,QObject*) for writing.
+ − 117
*
+ − 118
* \sa QuaZip::setCurrentFile()
+ − 119
**/
+ − 120
QuaZipFile(const QString& zipName, const QString& fileName,
+ − 121
QuaZip::CaseSensitivity cs =QuaZip::csDefault, QObject *parent =NULL);
+ − 122
/// Constructs a QuaZipFile instance.
+ − 123
/** \a parent argument specifies this object's parent object.
+ − 124
*
+ − 125
* \a zip is the pointer to the existing QuaZip object. This
+ − 126
* QuaZipFile object then can be used to read current file in the
+ − 127
* \a zip or to write to the file inside it.
+ − 128
*
+ − 129
* \warning Using this constructor for reading current file can be
+ − 130
* tricky. Let's take the following example:
+ − 131
* \code
+ − 132
* QuaZip zip("archive.zip");
+ − 133
* zip.open(QuaZip::mdUnzip);
+ − 134
* zip.setCurrentFile("file-in-archive");
+ − 135
* QuaZipFile file(&zip);
+ − 136
* file.open(QIODevice::ReadOnly);
+ − 137
* // ok, now we can read from the file
+ − 138
* file.read(somewhere, some);
+ − 139
* zip.setCurrentFile("another-file-in-archive"); // oops...
+ − 140
* QuaZipFile anotherFile(&zip);
+ − 141
* anotherFile.open(QIODevice::ReadOnly);
+ − 142
* anotherFile.read(somewhere, some); // this is still ok...
+ − 143
* file.read(somewhere, some); // and this is NOT
+ − 144
* \endcode
+ − 145
* So, what exactly happens here? When we change current file in the
+ − 146
* \c zip archive, \c file that references it becomes invalid
+ − 147
* (actually, as far as I understand ZIP/UNZIP sources, it becomes
+ − 148
* closed, but QuaZipFile has no means to detect it).
+ − 149
*
+ − 150
* Summary: do not close \c zip object or change its current file as
+ − 151
* long as QuaZipFile is open. Even better - use another constructors
+ − 152
* which create internal QuaZip instances, one per object, and
+ − 153
* therefore do not cause unnecessary trouble. This constructor may
+ − 154
* be useful, though, if you already have a QuaZip instance and do
+ − 155
* not want to access several files at once. Good example:
+ − 156
* \code
+ − 157
* QuaZip zip("archive.zip");
+ − 158
* zip.open(QuaZip::mdUnzip);
+ − 159
* // first, we need some information about archive itself
+ − 160
* QByteArray comment=zip.getComment();
+ − 161
* // and now we are going to access files inside it
+ − 162
* QuaZipFile file(&zip);
+ − 163
* for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) {
+ − 164
* file.open(QIODevice::ReadOnly);
+ − 165
* // do something cool with file here
+ − 166
* file.close(); // do not forget to close!
+ − 167
* }
+ − 168
* zip.close();
+ − 169
* \endcode
+ − 170
**/
+ − 171
QuaZipFile(QuaZip *zip, QObject *parent =NULL);
+ − 172
/// Destroys a QuaZipFile instance.
+ − 173
/** Closes file if open, destructs internal QuaZip object (if it
+ − 174
* exists and \em is internal, of course).
+ − 175
**/
+ − 176
virtual ~QuaZipFile();
+ − 177
/// Returns the ZIP archive file name.
+ − 178
/** If this object was created by passing QuaZip pointer to the
+ − 179
* constructor, this function will return that QuaZip's file name
+ − 180
* (or null string if that object does not have file name yet).
+ − 181
*
+ − 182
* Otherwise, returns associated ZIP archive file name or null
+ − 183
* string if there are no name set yet.
+ − 184
*
+ − 185
* \sa setZipName() getFileName()
+ − 186
**/
+ − 187
QString getZipName()const;
+ − 188
/// Returns a pointer to the associated QuaZip object.
+ − 189
/** Returns \c NULL if there is no associated QuaZip or it is
+ − 190
* internal (so you will not mess with it).
+ − 191
**/
+ − 192
QuaZip* getZip()const;
+ − 193
/// Returns file name.
+ − 194
/** This function returns file name you passed to this object either
+ − 195
* by using
+ − 196
* QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*)
+ − 197
* or by calling setFileName(). Real name of the file may differ in
+ − 198
* case if you used case-insensitivity.
+ − 199
*
+ − 200
* Returns null string if there is no file name set yet. This is the
+ − 201
* case when this QuaZipFile operates on the existing QuaZip object
+ − 202
* (constructor QuaZipFile(QuaZip*,QObject*) or setZip() was used).
+ − 203
*
+ − 204
* \sa getActualFileName
+ − 205
**/
+ − 206
QString getFileName() const;
+ − 207
/// Returns case sensitivity of the file name.
+ − 208
/** This function returns case sensitivity argument you passed to
+ − 209
* this object either by using
+ − 210
* QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*)
+ − 211
* or by calling setFileName().
+ − 212
*
+ − 213
* Returns unpredictable value if getFileName() returns null string
+ − 214
* (this is the case when you did not used setFileName() or
+ − 215
* constructor above).
+ − 216
*
+ − 217
* \sa getFileName
+ − 218
**/
+ − 219
QuaZip::CaseSensitivity getCaseSensitivity() const;
+ − 220
/// Returns the actual file name in the archive.
+ − 221
/** This is \em not a ZIP archive file name, but a name of file inside
+ − 222
* archive. It is not necessary the same name that you have passed
+ − 223
* to the
+ − 224
* QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*),
+ − 225
* setFileName() or QuaZip::setCurrentFile() - this is the real file
+ − 226
* name inside archive, so it may differ in case if the file name
+ − 227
* search was case-insensitive.
+ − 228
*
+ − 229
* Equivalent to calling getCurrentFileName() on the associated
+ − 230
* QuaZip object. Returns null string if there is no associated
+ − 231
* QuaZip object or if it does not have a current file yet. And this
+ − 232
* is the case if you called setFileName() but did not open the
+ − 233
* file yet. So this is perfectly fine:
+ − 234
* \code
+ − 235
* QuaZipFile file("somezip.zip");
+ − 236
* file.setFileName("somefile");
+ − 237
* QString name=file.getName(); // name=="somefile"
+ − 238
* QString actual=file.getActualFileName(); // actual is null string
+ − 239
* file.open(QIODevice::ReadOnly);
+ − 240
* QString actual=file.getActualFileName(); // actual can be "SoMeFiLe" on Windows
+ − 241
* \endcode
+ − 242
*
+ − 243
* \sa getZipName(), getFileName(), QuaZip::CaseSensitivity
+ − 244
**/
+ − 245
QString getActualFileName()const;
+ − 246
/// Sets the ZIP archive file name.
+ − 247
/** Automatically creates internal QuaZip object and destroys
+ − 248
* previously created internal QuaZip object, if any.
+ − 249
*
+ − 250
* Will do nothing if this file is already open. You must close() it
+ − 251
* first.
+ − 252
**/
+ − 253
void setZipName(const QString& zipName);
+ − 254
/// Returns \c true if the file was opened in raw mode.
+ − 255
/** If the file is not open, the returned value is undefined.
+ − 256
*
+ − 257
* \sa open(OpenMode,int*,int*,bool,const char*)
+ − 258
**/
+ − 259
bool isRaw() const;
+ − 260
/// Binds to the existing QuaZip instance.
+ − 261
/** This function destroys internal QuaZip object, if any, and makes
+ − 262
* this QuaZipFile to use current file in the \a zip object for any
+ − 263
* further operations. See QuaZipFile(QuaZip*,QObject*) for the
+ − 264
* possible pitfalls.
+ − 265
*
+ − 266
* Will do nothing if the file is currently open. You must close()
+ − 267
* it first.
+ − 268
**/
+ − 269
void setZip(QuaZip *zip);
+ − 270
/// Sets the file name.
+ − 271
/** Will do nothing if at least one of the following conditions is
+ − 272
* met:
+ − 273
* - ZIP name has not been set yet (getZipName() returns null
+ − 274
* string).
+ − 275
* - This QuaZipFile is associated with external QuaZip. In this
+ − 276
* case you should call that QuaZip's setCurrentFile() function
+ − 277
* instead!
+ − 278
* - File is already open so setting the name is meaningless.
+ − 279
*
+ − 280
* \sa QuaZip::setCurrentFile
+ − 281
**/
+ − 282
void setFileName(const QString& fileName, QuaZip::CaseSensitivity cs =QuaZip::csDefault);
+ − 283
/// Opens a file for reading.
+ − 284
/** Returns \c true on success, \c false otherwise.
+ − 285
* Call getZipError() to get error code.
+ − 286
*
+ − 287
* \note Since ZIP/UNZIP API provides buffered reading only,
+ − 288
* QuaZipFile does not support unbuffered reading. So do not pass
+ − 289
* QIODevice::Unbuffered flag in \a mode, or open will fail.
+ − 290
**/
+ − 291
virtual bool open(OpenMode mode);
+ − 292
/// Opens a file for reading.
+ − 293
/** \overload
+ − 294
* Argument \a password specifies a password to decrypt the file. If
+ − 295
* it is NULL then this function behaves just like open(OpenMode).
+ − 296
**/
+ − 297
inline bool open(OpenMode mode, const char *password)
+ − 298
{return open(mode, NULL, NULL, false, password);}
+ − 299
/// Opens a file for reading.
+ − 300
/** \overload
+ − 301
* Argument \a password specifies a password to decrypt the file.
+ − 302
*
+ − 303
* An integers pointed by \a method and \a level will receive codes
+ − 304
* of the compression method and level used. See unzip.h.
+ − 305
*
+ − 306
* If raw is \c true then no decompression is performed.
+ − 307
*
+ − 308
* \a method should not be \c NULL. \a level can be \c NULL if you
+ − 309
* don't want to know the compression level.
+ − 310
**/
+ − 311
bool open(OpenMode mode, int *method, int *level, bool raw, const char *password =NULL);
+ − 312
/// Opens a file for writing.
+ − 313
/** \a info argument specifies information about file. It should at
+ − 314
* least specify a correct file name. Also, it is a good idea to
+ − 315
* specify correct timestamp (by default, current time will be
+ − 316
* used). See QuaZipNewInfo.
+ − 317
*
+ − 318
* Arguments \a password and \a crc provide necessary information
+ − 319
* for crypting. Note that you should specify both of them if you
+ − 320
* need crypting. If you do not, pass \c NULL as password, but you
+ − 321
* still need to specify \a crc if you are going to use raw mode
+ − 322
* (see below).
+ − 323
*
+ − 324
* Arguments \a method and \a level specify compression method and
+ − 325
* level.
+ − 326
*
+ − 327
* If \a raw is \c true, no compression is performed. In this case,
+ − 328
* \a crc and uncompressedSize field of the \a info are required.
+ − 329
*
+ − 330
* Arguments \a windowBits, \a memLevel, \a strategy provide zlib
+ − 331
* algorithms tuning. See deflateInit2() in zlib.
+ − 332
**/
+ − 333
bool open(OpenMode mode, const QuaZipNewInfo& info,
+ − 334
const char *password =NULL, quint32 crc =0,
+ − 335
int method =Z_DEFLATED, int level =Z_DEFAULT_COMPRESSION, bool raw =false,
+ − 336
int windowBits =-MAX_WBITS, int memLevel =DEF_MEM_LEVEL, int strategy =Z_DEFAULT_STRATEGY);
+ − 337
/// Returns \c true, but \ref quazipfile-sequential "beware"!
+ − 338
virtual bool isSequential()const;
+ − 339
/// Returns current position in the file.
+ − 340
/** Implementation of the QIODevice::pos(). When reading, this
+ − 341
* function is a wrapper to the ZIP/UNZIP unztell(), therefore it is
+ − 342
* unable to keep track of the ungetChar() calls (which is
+ − 343
* non-virtual and therefore is dangerous to reimplement). So if you
+ − 344
* are using ungetChar() feature of the QIODevice, this function
+ − 345
* reports incorrect value until you get back characters which you
+ − 346
* ungot.
+ − 347
*
+ − 348
* When writing, pos() returns number of bytes already written
+ − 349
* (uncompressed unless you use raw mode).
+ − 350
*
+ − 351
* \note Although
+ − 352
* \ref quazipfile-sequential "QuaZipFile is a sequential device"
+ − 353
* and therefore pos() should always return zero, it does not,
+ − 354
* because it would be misguiding. Keep this in mind.
+ − 355
*
+ − 356
* This function returns -1 if the file or archive is not open.
+ − 357
*
+ − 358
* Error code returned by getZipError() is not affected by this
+ − 359
* function call.
+ − 360
**/
+ − 361
virtual qint64 pos()const;
+ − 362
/// Returns \c true if the end of file was reached.
+ − 363
/** This function returns \c false in the case of error. This means
+ − 364
* that you called this function on either not open file, or a file
+ − 365
* in the not open archive or even on a QuaZipFile instance that
+ − 366
* does not even have QuaZip instance associated. Do not do that
+ − 367
* because there is no means to determine whether \c false is
+ − 368
* returned because of error or because end of file was reached.
+ − 369
* Well, on the other side you may interpret \c false return value
+ − 370
* as "there is no file open to check for end of file and there is
+ − 371
* no end of file therefore".
+ − 372
*
+ − 373
* When writing, this function always returns \c true (because you
+ − 374
* are always writing to the end of file).
+ − 375
*
+ − 376
* Error code returned by getZipError() is not affected by this
+ − 377
* function call.
+ − 378
**/
+ − 379
virtual bool atEnd()const;
+ − 380
/// Returns file size.
+ − 381
/** This function returns csize() if the file is open for reading in
+ − 382
* raw mode, usize() if it is open for reading in normal mode and
+ − 383
* pos() if it is open for writing.
+ − 384
*
+ − 385
* Returns -1 on error, call getZipError() to get error code.
+ − 386
*
+ − 387
* \note This function returns file size despite that
+ − 388
* \ref quazipfile-sequential "QuaZipFile is considered to be sequential device",
+ − 389
* for which size() should return bytesAvailable() instead. But its
+ − 390
* name would be very misguiding otherwise, so just keep in mind
+ − 391
* this inconsistence.
+ − 392
**/
+ − 393
virtual qint64 size()const;
+ − 394
/// Returns compressed file size.
+ − 395
/** Equivalent to calling getFileInfo() and then getting
+ − 396
* compressedSize field, but more convenient and faster.
+ − 397
*
+ − 398
* File must be open for reading before calling this function.
+ − 399
*
+ − 400
* Returns -1 on error, call getZipError() to get error code.
+ − 401
**/
+ − 402
qint64 csize()const;
+ − 403
/// Returns uncompressed file size.
+ − 404
/** Equivalent to calling getFileInfo() and then getting
+ − 405
* uncompressedSize field, but more convenient and faster. See
+ − 406
* getFileInfo() for a warning.
+ − 407
*
+ − 408
* File must be open for reading before calling this function.
+ − 409
*
+ − 410
* Returns -1 on error, call getZipError() to get error code.
+ − 411
**/
+ − 412
qint64 usize()const;
+ − 413
/// Gets information about current file.
+ − 414
/** This function does the same thing as calling
+ − 415
* QuaZip::getCurrentFileInfo() on the associated QuaZip object,
+ − 416
* but you can not call getCurrentFileInfo() if the associated
+ − 417
* QuaZip is internal (because you do not have access to it), while
+ − 418
* you still can call this function in that case.
+ − 419
*
+ − 420
* File must be open for reading before calling this function.
+ − 421
*
+ − 422
* Returns \c false in the case of an error.
+ − 423
**/
+ − 424
bool getFileInfo(QuaZipFileInfo *info);
+ − 425
/// Closes the file.
+ − 426
/** Call getZipError() to determine if the close was successful.
+ − 427
**/
+ − 428
virtual void close();
+ − 429
/// Returns the error code returned by the last ZIP/UNZIP API call.
+ − 430
int getZipError() const;
+ − 431
};
+ − 432
+ − 433
#endif