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 |
|