summaryrefslogtreecommitdiff
path: root/rbutil/rbutilqt/zip/zip.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'rbutil/rbutilqt/zip/zip.cpp')
-rw-r--r--rbutil/rbutilqt/zip/zip.cpp2442
1 files changed, 1221 insertions, 1221 deletions
diff --git a/rbutil/rbutilqt/zip/zip.cpp b/rbutil/rbutilqt/zip/zip.cpp
index ac1eaaea0b..6732278fe6 100644
--- a/rbutil/rbutilqt/zip/zip.cpp
+++ b/rbutil/rbutilqt/zip/zip.cpp
@@ -1,1221 +1,1221 @@
1/**************************************************************************** 1/****************************************************************************
2** Filename: zip.cpp 2** Filename: zip.cpp
3** Last updated [dd/mm/yyyy]: 01/02/2007 3** Last updated [dd/mm/yyyy]: 01/02/2007
4** 4**
5** pkzip 2.0 file compression. 5** pkzip 2.0 file compression.
6** 6**
7** Some of the code has been inspired by other open source projects, 7** Some of the code has been inspired by other open source projects,
8** (mainly Info-Zip and Gilles Vollant's minizip). 8** (mainly Info-Zip and Gilles Vollant's minizip).
9** Compression and decompression actually uses the zlib library. 9** Compression and decompression actually uses the zlib library.
10** 10**
11** Copyright (C) 2007 Angius Fabrizio. All rights reserved. 11** Copyright (C) 2007 Angius Fabrizio. All rights reserved.
12** 12**
13** This file is part of the OSDaB project (http://osdab.sourceforge.net/). 13** This file is part of the OSDaB project (http://osdab.sourceforge.net/).
14** 14**
15** This file may be distributed and/or modified under the terms of the 15** This file may be distributed and/or modified under the terms of the
16** GNU General Public License version 2 as published by the Free Software 16** GNU General Public License version 2 as published by the Free Software
17** Foundation and appearing in the file LICENSE.GPL included in the 17** Foundation and appearing in the file LICENSE.GPL included in the
18** packaging of this file. 18** packaging of this file.
19** 19**
20** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 20** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
21** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 21** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22** 22**
23** See the file LICENSE.GPL that came with this software distribution or 23** See the file LICENSE.GPL that came with this software distribution or
24** visit http://www.gnu.org/copyleft/gpl.html for GPL licensing information. 24** visit http://www.gnu.org/copyleft/gpl.html for GPL licensing information.
25** 25**
26**********************************************************************/ 26**********************************************************************/
27 27
28#include "zip.h" 28#include "zip.h"
29#include "zip_p.h" 29#include "zip_p.h"
30#include "zipentry_p.h" 30#include "zipentry_p.h"
31 31
32// we only use this to seed the random number generator 32// we only use this to seed the random number generator
33#include <time.h> 33#include <time.h>
34 34
35#include <QMap> 35#include <QMap>
36#include <QString> 36#include <QString>
37#include <QStringList> 37#include <QStringList>
38#include <QDir> 38#include <QDir>
39#include <QFile> 39#include <QFile>
40#include <QDateTime> 40#include <QDateTime>
41#include <QCoreApplication> 41#include <QCoreApplication>
42 42
43// You can remove this #include if you replace the qDebug() statements. 43// You can remove this #include if you replace the qDebug() statements.
44#include <QtDebug> 44#include <QtDebug>
45 45
46//! Local header size (including signature, excluding variable length fields) 46//! Local header size (including signature, excluding variable length fields)
47#define ZIP_LOCAL_HEADER_SIZE 30 47#define ZIP_LOCAL_HEADER_SIZE 30
48//! Encryption header size 48//! Encryption header size
49#define ZIP_LOCAL_ENC_HEADER_SIZE 12 49#define ZIP_LOCAL_ENC_HEADER_SIZE 12
50//! Data descriptor size (signature included) 50//! Data descriptor size (signature included)
51#define ZIP_DD_SIZE_WS 16 51#define ZIP_DD_SIZE_WS 16
52//! Central Directory record size (signature included) 52//! Central Directory record size (signature included)
53#define ZIP_CD_SIZE 46 53#define ZIP_CD_SIZE 46
54//! End of Central Directory record size (signature included) 54//! End of Central Directory record size (signature included)
55#define ZIP_EOCD_SIZE 22 55#define ZIP_EOCD_SIZE 22
56 56
57// Some offsets inside a local header record (signature included) 57// Some offsets inside a local header record (signature included)
58#define ZIP_LH_OFF_VERS 4 58#define ZIP_LH_OFF_VERS 4
59#define ZIP_LH_OFF_GPFLAG 6 59#define ZIP_LH_OFF_GPFLAG 6
60#define ZIP_LH_OFF_CMET 8 60#define ZIP_LH_OFF_CMET 8
61#define ZIP_LH_OFF_MODT 10 61#define ZIP_LH_OFF_MODT 10
62#define ZIP_LH_OFF_MODD 12 62#define ZIP_LH_OFF_MODD 12
63#define ZIP_LH_OFF_CRC 14 63#define ZIP_LH_OFF_CRC 14
64#define ZIP_LH_OFF_CSIZE 18 64#define ZIP_LH_OFF_CSIZE 18
65#define ZIP_LH_OFF_USIZE 22 65#define ZIP_LH_OFF_USIZE 22
66#define ZIP_LH_OFF_NAMELEN 26 66#define ZIP_LH_OFF_NAMELEN 26
67#define ZIP_LH_OFF_XLEN 28 67#define ZIP_LH_OFF_XLEN 28
68 68
69// Some offsets inside a data descriptor record (including signature) 69// Some offsets inside a data descriptor record (including signature)
70#define ZIP_DD_OFF_CRC32 4 70#define ZIP_DD_OFF_CRC32 4
71#define ZIP_DD_OFF_CSIZE 8 71#define ZIP_DD_OFF_CSIZE 8
72#define ZIP_DD_OFF_USIZE 12 72#define ZIP_DD_OFF_USIZE 12
73 73
74// Some offsets inside a Central Directory record (including signature) 74// Some offsets inside a Central Directory record (including signature)
75#define ZIP_CD_OFF_MADEBY 4 75#define ZIP_CD_OFF_MADEBY 4
76#define ZIP_CD_OFF_VERSION 6 76#define ZIP_CD_OFF_VERSION 6
77#define ZIP_CD_OFF_GPFLAG 8 77#define ZIP_CD_OFF_GPFLAG 8
78#define ZIP_CD_OFF_CMET 10 78#define ZIP_CD_OFF_CMET 10
79#define ZIP_CD_OFF_MODT 12 79#define ZIP_CD_OFF_MODT 12
80#define ZIP_CD_OFF_MODD 14 80#define ZIP_CD_OFF_MODD 14
81#define ZIP_CD_OFF_CRC 16 81#define ZIP_CD_OFF_CRC 16
82#define ZIP_CD_OFF_CSIZE 20 82#define ZIP_CD_OFF_CSIZE 20
83#define ZIP_CD_OFF_USIZE 24 83#define ZIP_CD_OFF_USIZE 24
84#define ZIP_CD_OFF_NAMELEN 28 84#define ZIP_CD_OFF_NAMELEN 28
85#define ZIP_CD_OFF_XLEN 30 85#define ZIP_CD_OFF_XLEN 30
86#define ZIP_CD_OFF_COMMLEN 32 86#define ZIP_CD_OFF_COMMLEN 32
87#define ZIP_CD_OFF_DISKSTART 34 87#define ZIP_CD_OFF_DISKSTART 34
88#define ZIP_CD_OFF_IATTR 36 88#define ZIP_CD_OFF_IATTR 36
89#define ZIP_CD_OFF_EATTR 38 89#define ZIP_CD_OFF_EATTR 38
90#define ZIP_CD_OFF_LHOFF 42 90#define ZIP_CD_OFF_LHOFF 42
91 91
92// Some offsets inside a EOCD record (including signature) 92// Some offsets inside a EOCD record (including signature)
93#define ZIP_EOCD_OFF_DISKNUM 4 93#define ZIP_EOCD_OFF_DISKNUM 4
94#define ZIP_EOCD_OFF_CDDISKNUM 6 94#define ZIP_EOCD_OFF_CDDISKNUM 6
95#define ZIP_EOCD_OFF_ENTRIES 8 95#define ZIP_EOCD_OFF_ENTRIES 8
96#define ZIP_EOCD_OFF_CDENTRIES 10 96#define ZIP_EOCD_OFF_CDENTRIES 10
97#define ZIP_EOCD_OFF_CDSIZE 12 97#define ZIP_EOCD_OFF_CDSIZE 12
98#define ZIP_EOCD_OFF_CDOFF 16 98#define ZIP_EOCD_OFF_CDOFF 16
99#define ZIP_EOCD_OFF_COMMLEN 20 99#define ZIP_EOCD_OFF_COMMLEN 20
100 100
101//! PKZip version for archives created by this API 101//! PKZip version for archives created by this API
102#define ZIP_VERSION 0x14 102#define ZIP_VERSION 0x14
103 103
104//! Do not store very small files as the compression headers overhead would be to big 104//! Do not store very small files as the compression headers overhead would be to big
105#define ZIP_COMPRESSION_THRESHOLD 60 105#define ZIP_COMPRESSION_THRESHOLD 60
106 106
107//! This macro updates a one-char-only CRC; it's the Info-Zip macro re-adapted 107//! This macro updates a one-char-only CRC; it's the Info-Zip macro re-adapted
108#define CRC32(c, b) crcTable[((int)c^b) & 0xff] ^ (c >> 8) 108#define CRC32(c, b) crcTable[((int)c^b) & 0xff] ^ (c >> 8)
109 109
110/*! 110/*!
111 \class Zip zip.h 111 \class Zip zip.h
112 112
113 \brief Zip file compression. 113 \brief Zip file compression.
114 114
115 Some quick usage examples. 115 Some quick usage examples.
116 116
117 \verbatim 117 \verbatim
118 Suppose you have this directory structure: 118 Suppose you have this directory structure:
119 119
120 /root/dir1/ 120 /root/dir1/
121 /root/dir1/file1.1 121 /root/dir1/file1.1
122 /root/dir1/file1.2 122 /root/dir1/file1.2
123 /root/dir1/dir1.1/ 123 /root/dir1/dir1.1/
124 /root/dir1/dir1.2/file1.2.1 124 /root/dir1/dir1.2/file1.2.1
125 125
126 EXAMPLE 1: 126 EXAMPLE 1:
127 myZipInstance.addDirectory("/root/dir1"); 127 myZipInstance.addDirectory("/root/dir1");
128 128
129 RESULT: 129 RESULT:
130 Beheaves like any common zip software and creates a zip file with this structure: 130 Beheaves like any common zip software and creates a zip file with this structure:
131 131
132 dir1/ 132 dir1/
133 dir1/file1.1 133 dir1/file1.1
134 dir1/file1.2 134 dir1/file1.2
135 dir1/dir1.1/ 135 dir1/dir1.1/
136 dir1/dir1.2/file1.2.1 136 dir1/dir1.2/file1.2.1
137 137
138 EXAMPLE 2: 138 EXAMPLE 2:
139 myZipInstance.addDirectory("/root/dir1", "myRoot/myFolder"); 139 myZipInstance.addDirectory("/root/dir1", "myRoot/myFolder");
140 140
141 RESULT: 141 RESULT:
142 Adds a custom root to the paths and creates a zip file with this structure: 142 Adds a custom root to the paths and creates a zip file with this structure:
143 143
144 myRoot/myFolder/dir1/ 144 myRoot/myFolder/dir1/
145 myRoot/myFolder/dir1/file1.1 145 myRoot/myFolder/dir1/file1.1
146 myRoot/myFolder/dir1/file1.2 146 myRoot/myFolder/dir1/file1.2
147 myRoot/myFolder/dir1/dir1.1/ 147 myRoot/myFolder/dir1/dir1.1/
148 myRoot/myFolder/dir1/dir1.2/file1.2.1 148 myRoot/myFolder/dir1/dir1.2/file1.2.1
149 149
150 EXAMPLE 3: 150 EXAMPLE 3:
151 myZipInstance.addDirectory("/root/dir1", Zip::AbsolutePaths); 151 myZipInstance.addDirectory("/root/dir1", Zip::AbsolutePaths);
152 152
153 NOTE: 153 NOTE:
154 Same as calling addDirectory(SOME_PATH, PARENT_PATH_of_SOME_PATH). 154 Same as calling addDirectory(SOME_PATH, PARENT_PATH_of_SOME_PATH).
155 155
156 RESULT: 156 RESULT:
157 Preserves absolute paths and creates a zip file with this structure: 157 Preserves absolute paths and creates a zip file with this structure:
158 158
159 /root/dir1/ 159 /root/dir1/
160 /root/dir1/file1.1 160 /root/dir1/file1.1
161 /root/dir1/file1.2 161 /root/dir1/file1.2
162 /root/dir1/dir1.1/ 162 /root/dir1/dir1.1/
163 /root/dir1/dir1.2/file1.2.1 163 /root/dir1/dir1.2/file1.2.1
164 164
165 EXAMPLE 4: 165 EXAMPLE 4:
166 myZipInstance.setPassword("hellopass"); 166 myZipInstance.setPassword("hellopass");
167 myZipInstance.addDirectory("/root/dir1", "/"); 167 myZipInstance.addDirectory("/root/dir1", "/");
168 168
169 RESULT: 169 RESULT:
170 Adds and encrypts the files in /root/dir1, creating the following zip structure: 170 Adds and encrypts the files in /root/dir1, creating the following zip structure:
171 171
172 /dir1/ 172 /dir1/
173 /dir1/file1.1 173 /dir1/file1.1
174 /dir1/file1.2 174 /dir1/file1.2
175 /dir1/dir1.1/ 175 /dir1/dir1.1/
176 /dir1/dir1.2/file1.2.1 176 /dir1/dir1.2/file1.2.1
177 177
178 \endverbatim 178 \endverbatim
179*/ 179*/
180 180
181/*! \enum Zip::ErrorCode The result of a compression operation. 181/*! \enum Zip::ErrorCode The result of a compression operation.
182 \value Zip::Ok No error occurred. 182 \value Zip::Ok No error occurred.
183 \value Zip::ZlibInit Failed to init or load the zlib library. 183 \value Zip::ZlibInit Failed to init or load the zlib library.
184 \value Zip::ZlibError The zlib library returned some error. 184 \value Zip::ZlibError The zlib library returned some error.
185 \value Zip::FileExists The file already exists and will not be overwritten. 185 \value Zip::FileExists The file already exists and will not be overwritten.
186 \value Zip::OpenFailed Unable to create or open a device. 186 \value Zip::OpenFailed Unable to create or open a device.
187 \value Zip::NoOpenArchive CreateArchive() has not been called yet. 187 \value Zip::NoOpenArchive CreateArchive() has not been called yet.
188 \value Zip::FileNotFound File or directory does not exist. 188 \value Zip::FileNotFound File or directory does not exist.
189 \value Zip::ReadFailed Reading of a file failed. 189 \value Zip::ReadFailed Reading of a file failed.
190 \value Zip::WriteFailed Writing of a file failed. 190 \value Zip::WriteFailed Writing of a file failed.
191 \value Zip::SeekFailed Seek failed. 191 \value Zip::SeekFailed Seek failed.
192*/ 192*/
193 193
194/*! \enum Zip::CompressionLevel Returns the result of a decompression operation. 194/*! \enum Zip::CompressionLevel Returns the result of a decompression operation.
195 \value Zip::Store No compression. 195 \value Zip::Store No compression.
196 \value Zip::Deflate1 Deflate compression level 1(lowest compression). 196 \value Zip::Deflate1 Deflate compression level 1(lowest compression).
197 \value Zip::Deflate1 Deflate compression level 2. 197 \value Zip::Deflate1 Deflate compression level 2.
198 \value Zip::Deflate1 Deflate compression level 3. 198 \value Zip::Deflate1 Deflate compression level 3.
199 \value Zip::Deflate1 Deflate compression level 4. 199 \value Zip::Deflate1 Deflate compression level 4.
200 \value Zip::Deflate1 Deflate compression level 5. 200 \value Zip::Deflate1 Deflate compression level 5.
201 \value Zip::Deflate1 Deflate compression level 6. 201 \value Zip::Deflate1 Deflate compression level 6.
202 \value Zip::Deflate1 Deflate compression level 7. 202 \value Zip::Deflate1 Deflate compression level 7.
203 \value Zip::Deflate1 Deflate compression level 8. 203 \value Zip::Deflate1 Deflate compression level 8.
204 \value Zip::Deflate1 Deflate compression level 9 (maximum compression). 204 \value Zip::Deflate1 Deflate compression level 9 (maximum compression).
205 \value Zip::AutoCPU Adapt compression level to CPU speed (faster CPU => better compression). 205 \value Zip::AutoCPU Adapt compression level to CPU speed (faster CPU => better compression).
206 \value Zip::AutoMIME Adapt compression level to MIME type of the file being compressed. 206 \value Zip::AutoMIME Adapt compression level to MIME type of the file being compressed.
207 \value Zip::AutoFull Use both CPU and MIME type detection. 207 \value Zip::AutoFull Use both CPU and MIME type detection.
208*/ 208*/
209 209
210 210
211/************************************************************************ 211/************************************************************************
212 Public interface 212 Public interface
213*************************************************************************/ 213*************************************************************************/
214 214
215/*! 215/*!
216 Creates a new Zip file compressor. 216 Creates a new Zip file compressor.
217*/ 217*/
218Zip::Zip() 218Zip::Zip()
219{ 219{
220 d = new ZipPrivate; 220 d = new ZipPrivate;
221} 221}
222 222
223/*! 223/*!
224 Closes any open archive and releases used resources. 224 Closes any open archive and releases used resources.
225*/ 225*/
226Zip::~Zip() 226Zip::~Zip()
227{ 227{
228 closeArchive(); 228 closeArchive();
229 delete d; 229 delete d;
230} 230}
231 231
232/*! 232/*!
233 Returns true if there is an open archive. 233 Returns true if there is an open archive.
234*/ 234*/
235bool Zip::isOpen() const 235bool Zip::isOpen() const
236{ 236{
237 return d->device != 0; 237 return d->device != 0;
238} 238}
239 239
240/*! 240/*!
241 Sets the password to be used for the next files being added! 241 Sets the password to be used for the next files being added!
242 Files added before calling this method will use the previously 242 Files added before calling this method will use the previously
243 set password (if any). 243 set password (if any).
244 Closing the archive won't clear the password! 244 Closing the archive won't clear the password!
245*/ 245*/
246void Zip::setPassword(const QString& pwd) 246void Zip::setPassword(const QString& pwd)
247{ 247{
248 d->password = pwd; 248 d->password = pwd;
249} 249}
250 250
251//! Convenience method, clears the current password. 251//! Convenience method, clears the current password.
252void Zip::clearPassword() 252void Zip::clearPassword()
253{ 253{
254 d->password.clear(); 254 d->password.clear();
255} 255}
256 256
257//! Returns the currently used password. 257//! Returns the currently used password.
258QString Zip::password() const 258QString Zip::password() const
259{ 259{
260 return d->password; 260 return d->password;
261} 261}
262 262
263/*! 263/*!
264 Attempts to create a new Zip archive. If \p overwrite is true and the file 264 Attempts to create a new Zip archive. If \p overwrite is true and the file
265 already exist it will be overwritten. 265 already exist it will be overwritten.
266 Any open archive will be closed. 266 Any open archive will be closed.
267 */ 267 */
268Zip::ErrorCode Zip::createArchive(const QString& filename, bool overwrite) 268Zip::ErrorCode Zip::createArchive(const QString& filename, bool overwrite)
269{ 269{
270 QFile* file = new QFile(filename); 270 QFile* file = new QFile(filename);
271 271
272 if (file->exists() && !overwrite) { 272 if (file->exists() && !overwrite) {
273 delete file; 273 delete file;
274 return Zip::FileExists; 274 return Zip::FileExists;
275 } 275 }
276 276
277 if (!file->open(QIODevice::WriteOnly)) { 277 if (!file->open(QIODevice::WriteOnly)) {
278 delete file; 278 delete file;
279 return Zip::OpenFailed; 279 return Zip::OpenFailed;
280 } 280 }
281 281
282 Zip::ErrorCode ec = createArchive(file); 282 Zip::ErrorCode ec = createArchive(file);
283 if (ec != Zip::Ok) { 283 if (ec != Zip::Ok) {
284 file->remove(); 284 file->remove();
285 } 285 }
286 286
287 return ec; 287 return ec;
288} 288}
289 289
290/*! 290/*!
291 Attempts to create a new Zip archive. If there is another open archive this will be closed. 291 Attempts to create a new Zip archive. If there is another open archive this will be closed.
292 \warning The class takes ownership of the device! 292 \warning The class takes ownership of the device!
293 */ 293 */
294Zip::ErrorCode Zip::createArchive(QIODevice* device) 294Zip::ErrorCode Zip::createArchive(QIODevice* device)
295{ 295{
296 if (device == 0) 296 if (device == 0)
297 { 297 {
298 qDebug() << "Invalid device."; 298 qDebug() << "Invalid device.";
299 return Zip::OpenFailed; 299 return Zip::OpenFailed;
300 } 300 }
301 301
302 return d->createArchive(device); 302 return d->createArchive(device);
303} 303}
304 304
305/*! 305/*!
306 Returns the current archive comment. 306 Returns the current archive comment.
307*/ 307*/
308QString Zip::archiveComment() const 308QString Zip::archiveComment() const
309{ 309{
310 return d->comment; 310 return d->comment;
311} 311}
312 312
313/*! 313/*!
314 Sets the comment for this archive. Note: createArchive() should have been 314 Sets the comment for this archive. Note: createArchive() should have been
315 called before. 315 called before.
316*/ 316*/
317void Zip::setArchiveComment(const QString& comment) 317void Zip::setArchiveComment(const QString& comment)
318{ 318{
319 if (d->device != 0) 319 if (d->device != 0)
320 d->comment = comment; 320 d->comment = comment;
321} 321}
322 322
323/*! 323/*!
324 Convenience method, same as calling 324 Convenience method, same as calling
325 Zip::addDirectory(const QString&,const QString&,CompressionLevel) 325 Zip::addDirectory(const QString&,const QString&,CompressionLevel)
326 with an empty \p root parameter (or with the parent directory of \p path if the 326 with an empty \p root parameter (or with the parent directory of \p path if the
327 AbsolutePaths options is set). 327 AbsolutePaths options is set).
328 328
329 The ExtractionOptions are checked in the order they are defined in the zip.h heaser file. 329 The ExtractionOptions are checked in the order they are defined in the zip.h heaser file.
330 This means that the last one overwrites the previous one (if some conflict occurs), i.e. 330 This means that the last one overwrites the previous one (if some conflict occurs), i.e.
331 Zip::IgnorePaths | Zip::AbsolutePaths would be interpreted as Zip::IgnorePaths. 331 Zip::IgnorePaths | Zip::AbsolutePaths would be interpreted as Zip::IgnorePaths.
332 */ 332 */
333Zip::ErrorCode Zip::addDirectory(const QString& path, CompressionOptions options, CompressionLevel level) 333Zip::ErrorCode Zip::addDirectory(const QString& path, CompressionOptions options, CompressionLevel level)
334{ 334{
335 return addDirectory(path, QString(), options, level); 335 return addDirectory(path, QString(), options, level);
336} 336}
337 337
338/*! 338/*!
339 Convenience method, same as calling Zip::addDirectory(const QString&,const QString&,CompressionOptions,CompressionLevel) 339 Convenience method, same as calling Zip::addDirectory(const QString&,const QString&,CompressionOptions,CompressionLevel)
340 with the Zip::RelativePaths flag as compression option. 340 with the Zip::RelativePaths flag as compression option.
341 */ 341 */
342Zip::ErrorCode Zip::addDirectory(const QString& path, const QString& root, CompressionLevel level) 342Zip::ErrorCode Zip::addDirectory(const QString& path, const QString& root, CompressionLevel level)
343{ 343{
344 return addDirectory(path, root, Zip::RelativePaths, level); 344 return addDirectory(path, root, Zip::RelativePaths, level);
345} 345}
346 346
347/*! 347/*!
348 Convenience method, same as calling Zip::addDirectory(const QString&,const QString&,CompressionOptions,CompressionLevel) 348 Convenience method, same as calling Zip::addDirectory(const QString&,const QString&,CompressionOptions,CompressionLevel)
349 with the Zip::IgnorePaths flag as compression option and an empty \p root parameter. 349 with the Zip::IgnorePaths flag as compression option and an empty \p root parameter.
350*/ 350*/
351Zip::ErrorCode Zip::addDirectoryContents(const QString& path, CompressionLevel level) 351Zip::ErrorCode Zip::addDirectoryContents(const QString& path, CompressionLevel level)
352{ 352{
353 return addDirectory(path, QString(), IgnorePaths, level); 353 return addDirectory(path, QString(), IgnorePaths, level);
354} 354}
355 355
356/*! 356/*!
357 Convenience method, same as calling Zip::addDirectory(const QString&,const QString&,CompressionOptions,CompressionLevel) 357 Convenience method, same as calling Zip::addDirectory(const QString&,const QString&,CompressionOptions,CompressionLevel)
358 with the Zip::IgnorePaths flag as compression option. 358 with the Zip::IgnorePaths flag as compression option.
359*/ 359*/
360Zip::ErrorCode Zip::addDirectoryContents(const QString& path, const QString& root, CompressionLevel level) 360Zip::ErrorCode Zip::addDirectoryContents(const QString& path, const QString& root, CompressionLevel level)
361{ 361{
362 return addDirectory(path, root, IgnorePaths, level); 362 return addDirectory(path, root, IgnorePaths, level);
363} 363}
364 364
365/*! 365/*!
366 Recursively adds files contained in \p dir to the archive, using \p root as name for the root folder. 366 Recursively adds files contained in \p dir to the archive, using \p root as name for the root folder.
367 Stops adding files if some error occurs. 367 Stops adding files if some error occurs.
368 368
369 The ExtractionOptions are checked in the order they are defined in the zip.h heaser file. 369 The ExtractionOptions are checked in the order they are defined in the zip.h heaser file.
370 This means that the last one overwrites the previous one (if some conflict occurs), i.e. 370 This means that the last one overwrites the previous one (if some conflict occurs), i.e.
371 Zip::IgnorePaths | Zip::AbsolutePaths would be interpreted as Zip::IgnorePaths. 371 Zip::IgnorePaths | Zip::AbsolutePaths would be interpreted as Zip::IgnorePaths.
372 372
373 The \p root parameter is ignored with the Zip::IgnorePaths parameter and used as path prefix (a trailing / 373 The \p root parameter is ignored with the Zip::IgnorePaths parameter and used as path prefix (a trailing /
374 is always added as directory separator!) otherwise (even with Zip::AbsolutePaths set!). 374 is always added as directory separator!) otherwise (even with Zip::AbsolutePaths set!).
375*/ 375*/
376Zip::ErrorCode Zip::addDirectory(const QString& path, const QString& root, CompressionOptions options, CompressionLevel level) 376Zip::ErrorCode Zip::addDirectory(const QString& path, const QString& root, CompressionOptions options, CompressionLevel level)
377{ 377{
378 // qDebug() << QString("addDir(path=%1, root=%2)").arg(path, root); 378 // qDebug() << QString("addDir(path=%1, root=%2)").arg(path, root);
379 379
380 // Bad boy didn't call createArchive() yet :) 380 // Bad boy didn't call createArchive() yet :)
381 if (d->device == 0) 381 if (d->device == 0)
382 return Zip::NoOpenArchive; 382 return Zip::NoOpenArchive;
383 383
384 QDir dir(path); 384 QDir dir(path);
385 if (!dir.exists()) 385 if (!dir.exists())
386 return Zip::FileNotFound; 386 return Zip::FileNotFound;
387 387
388 // Remove any trailing separator 388 // Remove any trailing separator
389 QString actualRoot = root.trimmed(); 389 QString actualRoot = root.trimmed();
390 390
391 // Preserve Unix root 391 // Preserve Unix root
392 if (actualRoot != "/") 392 if (actualRoot != "/")
393 { 393 {
394 while (actualRoot.endsWith("/") || actualRoot.endsWith("\\")) 394 while (actualRoot.endsWith("/") || actualRoot.endsWith("\\"))
395 actualRoot.truncate(actualRoot.length() - 1); 395 actualRoot.truncate(actualRoot.length() - 1);
396 } 396 }
397 397
398 // QDir::cleanPath() fixes some issues with QDir::dirName() 398 // QDir::cleanPath() fixes some issues with QDir::dirName()
399 QFileInfo current(QDir::cleanPath(path)); 399 QFileInfo current(QDir::cleanPath(path));
400 400
401 if (!actualRoot.isEmpty() && actualRoot != "/") 401 if (!actualRoot.isEmpty() && actualRoot != "/")
402 actualRoot.append("/"); 402 actualRoot.append("/");
403 403
404 /* This part is quite confusing and needs some test or check */ 404 /* This part is quite confusing and needs some test or check */
405 /* An attempt to compress the / root directory evtl. using a root prefix should be a good test */ 405 /* An attempt to compress the / root directory evtl. using a root prefix should be a good test */
406 if (options.testFlag(AbsolutePaths) && !options.testFlag(IgnorePaths)) 406 if (options.testFlag(AbsolutePaths) && !options.testFlag(IgnorePaths))
407 { 407 {
408 QString absolutePath = d->extractRoot(path); 408 QString absolutePath = d->extractRoot(path);
409 if (!absolutePath.isEmpty() && absolutePath != "/") 409 if (!absolutePath.isEmpty() && absolutePath != "/")
410 absolutePath.append("/"); 410 absolutePath.append("/");
411 actualRoot.append(absolutePath); 411 actualRoot.append(absolutePath);
412 } 412 }
413 413
414 if (!options.testFlag(IgnorePaths)) 414 if (!options.testFlag(IgnorePaths))
415 { 415 {
416 actualRoot = actualRoot.append(QDir(current.absoluteFilePath()).dirName()); 416 actualRoot = actualRoot.append(QDir(current.absoluteFilePath()).dirName());
417 actualRoot.append("/"); 417 actualRoot.append("/");
418 } 418 }
419 419
420 // actualRoot now contains the path of the file relative to the zip archive 420 // actualRoot now contains the path of the file relative to the zip archive
421 // with a trailing / 421 // with a trailing /
422 422
423 QFileInfoList list = dir.entryInfoList( 423 QFileInfoList list = dir.entryInfoList(
424 QDir::Files | 424 QDir::Files |
425 QDir::Dirs | 425 QDir::Dirs |
426 QDir::NoDotAndDotDot | 426 QDir::NoDotAndDotDot |
427 QDir::NoSymLinks); 427 QDir::NoSymLinks);
428 428
429 ErrorCode ec = Zip::Ok; 429 ErrorCode ec = Zip::Ok;
430 bool filesAdded = false; 430 bool filesAdded = false;
431 431
432 CompressionOptions recursionOptions; 432 CompressionOptions recursionOptions;
433 if (options.testFlag(IgnorePaths)) 433 if (options.testFlag(IgnorePaths))
434 recursionOptions |= IgnorePaths; 434 recursionOptions |= IgnorePaths;
435 else recursionOptions |= RelativePaths; 435 else recursionOptions |= RelativePaths;
436 436
437 for (int i = 0; i < list.size() && ec == Zip::Ok; ++i) 437 for (int i = 0; i < list.size() && ec == Zip::Ok; ++i)
438 { 438 {
439 QFileInfo info = list.at(i); 439 QFileInfo info = list.at(i);
440 440
441 if (info.isDir()) 441 if (info.isDir())
442 { 442 {
443 // Recursion :) 443 // Recursion :)
444 progress(); 444 progress();
445 ec = addDirectory(info.absoluteFilePath(), actualRoot, recursionOptions, level); 445 ec = addDirectory(info.absoluteFilePath(), actualRoot, recursionOptions, level);
446 } 446 }
447 else 447 else
448 { 448 {
449 progress(); 449 progress();
450 ec = d->createEntry(info, actualRoot, level); 450 ec = d->createEntry(info, actualRoot, level);
451 filesAdded = true; 451 filesAdded = true;
452 } 452 }
453 } 453 }
454 454
455 455
456 // We need an explicit record for this dir 456 // We need an explicit record for this dir
457 // Non-empty directories don't need it because they have a path component in the filename 457 // Non-empty directories don't need it because they have a path component in the filename
458 if (!filesAdded && !options.testFlag(IgnorePaths)) 458 if (!filesAdded && !options.testFlag(IgnorePaths))
459 ec = d->createEntry(current, actualRoot, level); 459 ec = d->createEntry(current, actualRoot, level);
460 460
461 return ec; 461 return ec;
462} 462}
463 463
464/*! 464/*!
465 Closes the archive and writes any pending data. 465 Closes the archive and writes any pending data.
466*/ 466*/
467Zip::ErrorCode Zip::closeArchive() 467Zip::ErrorCode Zip::closeArchive()
468{ 468{
469 Zip::ErrorCode ec = d->closeArchive(); 469 Zip::ErrorCode ec = d->closeArchive();
470 d->reset(); 470 d->reset();
471 return ec; 471 return ec;
472} 472}
473 473
474/*! 474/*!
475 Returns a locale translated error string for a given error code. 475 Returns a locale translated error string for a given error code.
476*/ 476*/
477QString Zip::formatError(Zip::ErrorCode c) const 477QString Zip::formatError(Zip::ErrorCode c) const
478{ 478{
479 switch (c) 479 switch (c)
480 { 480 {
481 case Ok: return QCoreApplication::translate("Zip", "ZIP operation completed successfully."); break; 481 case Ok: return QCoreApplication::translate("Zip", "ZIP operation completed successfully."); break;
482 case ZlibInit: return QCoreApplication::translate("Zip", "Failed to initialize or load zlib library."); break; 482 case ZlibInit: return QCoreApplication::translate("Zip", "Failed to initialize or load zlib library."); break;
483 case ZlibError: return QCoreApplication::translate("Zip", "zlib library error."); break; 483 case ZlibError: return QCoreApplication::translate("Zip", "zlib library error."); break;
484 case OpenFailed: return QCoreApplication::translate("Zip", "Unable to create or open file."); break; 484 case OpenFailed: return QCoreApplication::translate("Zip", "Unable to create or open file."); break;
485 case NoOpenArchive: return QCoreApplication::translate("Zip", "No archive has been created yet."); break; 485 case NoOpenArchive: return QCoreApplication::translate("Zip", "No archive has been created yet."); break;
486 case FileNotFound: return QCoreApplication::translate("Zip", "File or directory does not exist."); break; 486 case FileNotFound: return QCoreApplication::translate("Zip", "File or directory does not exist."); break;
487 case ReadFailed: return QCoreApplication::translate("Zip", "File read error."); break; 487 case ReadFailed: return QCoreApplication::translate("Zip", "File read error."); break;
488 case WriteFailed: return QCoreApplication::translate("Zip", "File write error."); break; 488 case WriteFailed: return QCoreApplication::translate("Zip", "File write error."); break;
489 case SeekFailed: return QCoreApplication::translate("Zip", "File seek error."); break; 489 case SeekFailed: return QCoreApplication::translate("Zip", "File seek error."); break;
490 default: ; 490 default: ;
491 } 491 }
492 492
493 return QCoreApplication::translate("Zip", "Unknown error."); 493 return QCoreApplication::translate("Zip", "Unknown error.");
494} 494}
495 495
496 496
497/************************************************************************ 497/************************************************************************
498 Private interface 498 Private interface
499*************************************************************************/ 499*************************************************************************/
500 500
501//! \internal 501//! \internal
502ZipPrivate::ZipPrivate() 502ZipPrivate::ZipPrivate()
503{ 503{
504 headers = 0; 504 headers = 0;
505 device = 0; 505 device = 0;
506 506
507 // keep an unsigned pointer so we avoid to over bloat the code with casts 507 // keep an unsigned pointer so we avoid to over bloat the code with casts
508 uBuffer = (unsigned char*) buffer1; 508 uBuffer = (unsigned char*) buffer1;
509 crcTable = (quint32*) get_crc_table(); 509 crcTable = (quint32*) get_crc_table();
510} 510}
511 511
512//! \internal 512//! \internal
513ZipPrivate::~ZipPrivate() 513ZipPrivate::~ZipPrivate()
514{ 514{
515 closeArchive(); 515 closeArchive();
516} 516}
517 517
518//! \internal 518//! \internal
519Zip::ErrorCode ZipPrivate::createArchive(QIODevice* dev) 519Zip::ErrorCode ZipPrivate::createArchive(QIODevice* dev)
520{ 520{
521 Q_ASSERT(dev != 0); 521 Q_ASSERT(dev != 0);
522 522
523 if (device != 0) 523 if (device != 0)
524 closeArchive(); 524 closeArchive();
525 525
526 device = dev; 526 device = dev;
527 527
528 if (!device->isOpen()) 528 if (!device->isOpen())
529 { 529 {
530 if (!device->open(QIODevice::ReadOnly)) { 530 if (!device->open(QIODevice::ReadOnly)) {
531 delete device; 531 delete device;
532 device = 0; 532 device = 0;
533 qDebug() << "Unable to open device for writing."; 533 qDebug() << "Unable to open device for writing.";
534 return Zip::OpenFailed; 534 return Zip::OpenFailed;
535 } 535 }
536 } 536 }
537 537
538 headers = new QMap<QString,ZipEntryP*>; 538 headers = new QMap<QString,ZipEntryP*>;
539 return Zip::Ok; 539 return Zip::Ok;
540} 540}
541 541
542//! \internal Writes a new entry in the zip file. 542//! \internal Writes a new entry in the zip file.
543Zip::ErrorCode ZipPrivate::createEntry(const QFileInfo& file, const QString& root, Zip::CompressionLevel level) 543Zip::ErrorCode ZipPrivate::createEntry(const QFileInfo& file, const QString& root, Zip::CompressionLevel level)
544{ 544{
545 //! \todo Automatic level detection (cpu, extension & file size) 545 //! \todo Automatic level detection (cpu, extension & file size)
546 546
547 // Directories and very small files are always stored 547 // Directories and very small files are always stored
548 // (small files would get bigger due to the compression headers overhead) 548 // (small files would get bigger due to the compression headers overhead)
549 549
550 // Need this for zlib 550 // Need this for zlib
551 bool isPNGFile = false; 551 bool isPNGFile = false;
552 bool dirOnly = file.isDir(); 552 bool dirOnly = file.isDir();
553 553
554 QString entryName = root; 554 QString entryName = root;
555 555
556 // Directory entry 556 // Directory entry
557 if (dirOnly) 557 if (dirOnly)
558 level = Zip::Store; 558 level = Zip::Store;
559 else 559 else
560 { 560 {
561 entryName.append(file.fileName()); 561 entryName.append(file.fileName());
562 562
563 QString ext = file.completeSuffix().toLower(); 563 QString ext = file.completeSuffix().toLower();
564 isPNGFile = ext == "png"; 564 isPNGFile = ext == "png";
565 565
566 if (file.size() < ZIP_COMPRESSION_THRESHOLD) 566 if (file.size() < ZIP_COMPRESSION_THRESHOLD)
567 level = Zip::Store; 567 level = Zip::Store;
568 else 568 else
569 switch (level) 569 switch (level)
570 { 570 {
571 case Zip::AutoCPU: 571 case Zip::AutoCPU:
572 level = Zip::Deflate5; 572 level = Zip::Deflate5;
573 break; 573 break;
574 case Zip::AutoMIME: 574 case Zip::AutoMIME:
575 level = detectCompressionByMime(ext); 575 level = detectCompressionByMime(ext);
576 break; 576 break;
577 case Zip::AutoFull: 577 case Zip::AutoFull:
578 level = detectCompressionByMime(ext); 578 level = detectCompressionByMime(ext);
579 break; 579 break;
580 default: 580 default:
581 ; 581 ;
582 } 582 }
583 } 583 }
584 584
585 // entryName contains the path as it should be written 585 // entryName contains the path as it should be written
586 // in the zip file records 586 // in the zip file records
587 // qDebug() << QString("addDir(file=%1, root=%2, entry=%3)").arg(file.absoluteFilePath(), root, entryName); 587 // qDebug() << QString("addDir(file=%1, root=%2, entry=%3)").arg(file.absoluteFilePath(), root, entryName);
588 588
589 // create header and store it to write a central directory later 589 // create header and store it to write a central directory later
590 ZipEntryP* h = new ZipEntryP; 590 ZipEntryP* h = new ZipEntryP;
591 591
592 h->compMethod = (level == Zip::Store) ? 0 : 0x0008; 592 h->compMethod = (level == Zip::Store) ? 0 : 0x0008;
593 593
594 // Set encryption bit and set the data descriptor bit 594 // Set encryption bit and set the data descriptor bit
595 // so we can use mod time instead of crc for password check 595 // so we can use mod time instead of crc for password check
596 bool encrypt = !dirOnly && !password.isEmpty(); 596 bool encrypt = !dirOnly && !password.isEmpty();
597 if (encrypt) 597 if (encrypt)
598 h->gpFlag[0] |= 9; 598 h->gpFlag[0] |= 9;
599 599
600 QDateTime dt = file.lastModified(); 600 QDateTime dt = file.lastModified();
601 QDate d = dt.date(); 601 QDate d = dt.date();
602 h->modDate[1] = ((d.year() - 1980) << 1) & 254; 602 h->modDate[1] = ((d.year() - 1980) << 1) & 254;
603 h->modDate[1] |= ((d.month() >> 3) & 1); 603 h->modDate[1] |= ((d.month() >> 3) & 1);
604 h->modDate[0] = ((d.month() & 7) << 5) & 224; 604 h->modDate[0] = ((d.month() & 7) << 5) & 224;
605 h->modDate[0] |= d.day(); 605 h->modDate[0] |= d.day();
606 606
607 QTime t = dt.time(); 607 QTime t = dt.time();
608 h->modTime[1] = (t.hour() << 3) & 248; 608 h->modTime[1] = (t.hour() << 3) & 248;
609 h->modTime[1] |= ((t.minute() >> 3) & 7); 609 h->modTime[1] |= ((t.minute() >> 3) & 7);
610 h->modTime[0] = ((t.minute() & 7) << 5) & 224; 610 h->modTime[0] = ((t.minute() & 7) << 5) & 224;
611 h->modTime[0] |= t.second() / 2; 611 h->modTime[0] |= t.second() / 2;
612 612
613 h->szUncomp = dirOnly ? 0 : file.size(); 613 h->szUncomp = dirOnly ? 0 : file.size();
614 614
615 // **** Write local file header **** 615 // **** Write local file header ****
616 616
617 // signature 617 // signature
618 buffer1[0] = 'P'; buffer1[1] = 'K'; 618 buffer1[0] = 'P'; buffer1[1] = 'K';
619 buffer1[2] = 0x3; buffer1[3] = 0x4; 619 buffer1[2] = 0x3; buffer1[3] = 0x4;
620 620
621 // version needed to extract 621 // version needed to extract
622 buffer1[ZIP_LH_OFF_VERS] = ZIP_VERSION; 622 buffer1[ZIP_LH_OFF_VERS] = ZIP_VERSION;
623 buffer1[ZIP_LH_OFF_VERS + 1] = 0; 623 buffer1[ZIP_LH_OFF_VERS + 1] = 0;
624 624
625 // general purpose flag 625 // general purpose flag
626 buffer1[ZIP_LH_OFF_GPFLAG] = h->gpFlag[0]; 626 buffer1[ZIP_LH_OFF_GPFLAG] = h->gpFlag[0];
627 buffer1[ZIP_LH_OFF_GPFLAG + 1] = h->gpFlag[1]; 627 buffer1[ZIP_LH_OFF_GPFLAG + 1] = h->gpFlag[1];
628 628
629 // compression method 629 // compression method
630 buffer1[ZIP_LH_OFF_CMET] = h->compMethod & 0xFF; 630 buffer1[ZIP_LH_OFF_CMET] = h->compMethod & 0xFF;
631 buffer1[ZIP_LH_OFF_CMET + 1] = (h->compMethod>>8) & 0xFF; 631 buffer1[ZIP_LH_OFF_CMET + 1] = (h->compMethod>>8) & 0xFF;
632 632
633 // last mod file time 633 // last mod file time
634 buffer1[ZIP_LH_OFF_MODT] = h->modTime[0]; 634 buffer1[ZIP_LH_OFF_MODT] = h->modTime[0];
635 buffer1[ZIP_LH_OFF_MODT + 1] = h->modTime[1]; 635 buffer1[ZIP_LH_OFF_MODT + 1] = h->modTime[1];
636 636
637 // last mod file date 637 // last mod file date
638 buffer1[ZIP_LH_OFF_MODD] = h->modDate[0]; 638 buffer1[ZIP_LH_OFF_MODD] = h->modDate[0];
639 buffer1[ZIP_LH_OFF_MODD + 1] = h->modDate[1]; 639 buffer1[ZIP_LH_OFF_MODD + 1] = h->modDate[1];
640 640
641 // skip crc (4bytes) [14,15,16,17] 641 // skip crc (4bytes) [14,15,16,17]
642 642
643 // skip compressed size but include evtl. encryption header (4bytes: [18,19,20,21]) 643 // skip compressed size but include evtl. encryption header (4bytes: [18,19,20,21])
644 buffer1[ZIP_LH_OFF_CSIZE] = 644 buffer1[ZIP_LH_OFF_CSIZE] =
645 buffer1[ZIP_LH_OFF_CSIZE + 1] = 645 buffer1[ZIP_LH_OFF_CSIZE + 1] =
646 buffer1[ZIP_LH_OFF_CSIZE + 2] = 646 buffer1[ZIP_LH_OFF_CSIZE + 2] =
647 buffer1[ZIP_LH_OFF_CSIZE + 3] = 0; 647 buffer1[ZIP_LH_OFF_CSIZE + 3] = 0;
648 648
649 h->szComp = encrypt ? ZIP_LOCAL_ENC_HEADER_SIZE : 0; 649 h->szComp = encrypt ? ZIP_LOCAL_ENC_HEADER_SIZE : 0;
650 650
651 // uncompressed size [22,23,24,25] 651 // uncompressed size [22,23,24,25]
652 setULong(h->szUncomp, buffer1, ZIP_LH_OFF_USIZE); 652 setULong(h->szUncomp, buffer1, ZIP_LH_OFF_USIZE);
653 653
654 // filename length 654 // filename length
655 QByteArray entryNameBytes = entryName.toAscii(); 655 QByteArray entryNameBytes = entryName.toAscii();
656 int sz = entryNameBytes.size(); 656 int sz = entryNameBytes.size();
657 657
658 buffer1[ZIP_LH_OFF_NAMELEN] = sz & 0xFF; 658 buffer1[ZIP_LH_OFF_NAMELEN] = sz & 0xFF;
659 buffer1[ZIP_LH_OFF_NAMELEN + 1] = (sz >> 8) & 0xFF; 659 buffer1[ZIP_LH_OFF_NAMELEN + 1] = (sz >> 8) & 0xFF;
660 660
661 // extra field length 661 // extra field length
662 buffer1[ZIP_LH_OFF_XLEN] = buffer1[ZIP_LH_OFF_XLEN + 1] = 0; 662 buffer1[ZIP_LH_OFF_XLEN] = buffer1[ZIP_LH_OFF_XLEN + 1] = 0;
663 663
664 // Store offset to write crc and compressed size 664 // Store offset to write crc and compressed size
665 h->lhOffset = device->pos(); 665 h->lhOffset = device->pos();
666 quint32 crcOffset = h->lhOffset + ZIP_LH_OFF_CRC; 666 quint32 crcOffset = h->lhOffset + ZIP_LH_OFF_CRC;
667 667
668 if (device->write(buffer1, ZIP_LOCAL_HEADER_SIZE) != ZIP_LOCAL_HEADER_SIZE) 668 if (device->write(buffer1, ZIP_LOCAL_HEADER_SIZE) != ZIP_LOCAL_HEADER_SIZE)
669 { 669 {
670 delete h; 670 delete h;
671 return Zip::WriteFailed; 671 return Zip::WriteFailed;
672 } 672 }
673 673
674 // Write out filename 674 // Write out filename
675 if (device->write(entryNameBytes) != sz) 675 if (device->write(entryNameBytes) != sz)
676 { 676 {
677 delete h; 677 delete h;
678 return Zip::WriteFailed; 678 return Zip::WriteFailed;
679 } 679 }
680 680
681 // Encryption keys 681 // Encryption keys
682 quint32 keys[3] = { 0, 0, 0 }; 682 quint32 keys[3] = { 0, 0, 0 };
683 683
684 if (encrypt) 684 if (encrypt)
685 { 685 {
686 // **** encryption header **** 686 // **** encryption header ****
687 687
688 // XOR with PI to ensure better random numbers 688 // XOR with PI to ensure better random numbers
689 // with poorly implemented rand() as suggested by Info-Zip 689 // with poorly implemented rand() as suggested by Info-Zip
690 srand(time(NULL) ^ 3141592654UL); 690 srand(time(NULL) ^ 3141592654UL);
691 int randByte; 691 int randByte;
692 692
693 initKeys(keys); 693 initKeys(keys);
694 for (int i=0; i<10; ++i) 694 for (int i=0; i<10; ++i)
695 { 695 {
696 randByte = (rand() >> 7) & 0xff; 696 randByte = (rand() >> 7) & 0xff;
697 buffer1[i] = decryptByte(keys[2]) ^ randByte; 697 buffer1[i] = decryptByte(keys[2]) ^ randByte;
698 updateKeys(keys, randByte); 698 updateKeys(keys, randByte);
699 } 699 }
700 700
701 // Encrypt encryption header 701 // Encrypt encryption header
702 initKeys(keys); 702 initKeys(keys);
703 for (int i=0; i<10; ++i) 703 for (int i=0; i<10; ++i)
704 { 704 {
705 randByte = decryptByte(keys[2]); 705 randByte = decryptByte(keys[2]);
706 updateKeys(keys, buffer1[i]); 706 updateKeys(keys, buffer1[i]);
707 buffer1[i] ^= randByte; 707 buffer1[i] ^= randByte;
708 } 708 }
709 709
710 // We don't know the CRC at this time, so we use the modification time 710 // We don't know the CRC at this time, so we use the modification time
711 // as the last two bytes 711 // as the last two bytes
712 randByte = decryptByte(keys[2]); 712 randByte = decryptByte(keys[2]);
713 updateKeys(keys, h->modTime[0]); 713 updateKeys(keys, h->modTime[0]);
714 buffer1[10] ^= randByte; 714 buffer1[10] ^= randByte;
715 715
716 randByte = decryptByte(keys[2]); 716 randByte = decryptByte(keys[2]);
717 updateKeys(keys, h->modTime[1]); 717 updateKeys(keys, h->modTime[1]);
718 buffer1[11] ^= randByte; 718 buffer1[11] ^= randByte;
719 719
720 // Write out encryption header 720 // Write out encryption header
721 if (device->write(buffer1, ZIP_LOCAL_ENC_HEADER_SIZE) != ZIP_LOCAL_ENC_HEADER_SIZE) 721 if (device->write(buffer1, ZIP_LOCAL_ENC_HEADER_SIZE) != ZIP_LOCAL_ENC_HEADER_SIZE)
722 { 722 {
723 delete h; 723 delete h;
724 return Zip::WriteFailed; 724 return Zip::WriteFailed;
725 } 725 }
726 } 726 }
727 727
728 qint64 written = 0; 728 qint64 written = 0;
729 quint32 crc = crc32(0L, Z_NULL, 0); 729 quint32 crc = crc32(0L, Z_NULL, 0);
730 730
731 if (!dirOnly) 731 if (!dirOnly)
732 { 732 {
733 QFile actualFile(file.absoluteFilePath()); 733 QFile actualFile(file.absoluteFilePath());
734 if (!actualFile.open(QIODevice::ReadOnly)) 734 if (!actualFile.open(QIODevice::ReadOnly))
735 { 735 {
736 qDebug() << QString("An error occurred while opening %1").arg(file.absoluteFilePath()); 736 qDebug() << QString("An error occurred while opening %1").arg(file.absoluteFilePath());
737 return Zip::OpenFailed; 737 return Zip::OpenFailed;
738 } 738 }
739 739
740 // Write file data 740 // Write file data
741 qint64 read = 0; 741 qint64 read = 0;
742 qint64 totRead = 0; 742 qint64 totRead = 0;
743 qint64 toRead = actualFile.size(); 743 qint64 toRead = actualFile.size();
744 744
745 if (level == Zip::Store) 745 if (level == Zip::Store)
746 { 746 {
747 while ( (read = actualFile.read(buffer1, ZIP_READ_BUFFER)) > 0 ) 747 while ( (read = actualFile.read(buffer1, ZIP_READ_BUFFER)) > 0 )
748 { 748 {
749 crc = crc32(crc, uBuffer, read); 749 crc = crc32(crc, uBuffer, read);
750 750
751 if (password != 0) 751 if (password != 0)
752 encryptBytes(keys, buffer1, read); 752 encryptBytes(keys, buffer1, read);
753 753
754 if ( (written = device->write(buffer1, read)) != read ) 754 if ( (written = device->write(buffer1, read)) != read )
755 { 755 {
756 actualFile.close(); 756 actualFile.close();
757 delete h; 757 delete h;
758 return Zip::WriteFailed; 758 return Zip::WriteFailed;
759 } 759 }
760 } 760 }
761 } 761 }
762 else 762 else
763 { 763 {
764 z_stream zstr; 764 z_stream zstr;
765 765
766 // Initialize zalloc, zfree and opaque before calling the init function 766 // Initialize zalloc, zfree and opaque before calling the init function
767 zstr.zalloc = Z_NULL; 767 zstr.zalloc = Z_NULL;
768 zstr.zfree = Z_NULL; 768 zstr.zfree = Z_NULL;
769 zstr.opaque = Z_NULL; 769 zstr.opaque = Z_NULL;
770 770
771 int zret; 771 int zret;
772 772
773 // Use deflateInit2 with negative windowBits to get raw compression 773 // Use deflateInit2 with negative windowBits to get raw compression
774 if ((zret = deflateInit2_( 774 if ((zret = deflateInit2_(
775 &zstr, 775 &zstr,
776 (int)level, 776 (int)level,
777 Z_DEFLATED, 777 Z_DEFLATED,
778 -MAX_WBITS, 778 -MAX_WBITS,
779 8, 779 8,
780 isPNGFile ? Z_RLE : Z_DEFAULT_STRATEGY, 780 isPNGFile ? Z_RLE : Z_DEFAULT_STRATEGY,
781 ZLIB_VERSION, 781 ZLIB_VERSION,
782 sizeof(z_stream) 782 sizeof(z_stream)
783 )) != Z_OK ) 783 )) != Z_OK )
784 { 784 {
785 actualFile.close(); 785 actualFile.close();
786 qDebug() << "Could not initialize zlib for compression"; 786 qDebug() << "Could not initialize zlib for compression";
787 delete h; 787 delete h;
788 return Zip::ZlibError; 788 return Zip::ZlibError;
789 } 789 }
790 790
791 qint64 compressed; 791 qint64 compressed;
792 792
793 int flush = Z_NO_FLUSH; 793 int flush = Z_NO_FLUSH;
794 794
795 do 795 do
796 { 796 {
797 read = actualFile.read(buffer1, ZIP_READ_BUFFER); 797 read = actualFile.read(buffer1, ZIP_READ_BUFFER);
798 totRead += read; 798 totRead += read;
799 799
800 if (read == 0) 800 if (read == 0)
801 break; 801 break;
802 if (read < 0) 802 if (read < 0)
803 { 803 {
804 actualFile.close(); 804 actualFile.close();
805 deflateEnd(&zstr); 805 deflateEnd(&zstr);
806 qDebug() << QString("Error while reading %1").arg(file.absoluteFilePath()); 806 qDebug() << QString("Error while reading %1").arg(file.absoluteFilePath());
807 delete h; 807 delete h;
808 return Zip::ReadFailed; 808 return Zip::ReadFailed;
809 } 809 }
810 810
811 crc = crc32(crc, uBuffer, read); 811 crc = crc32(crc, uBuffer, read);
812 812
813 zstr.next_in = (Bytef*) buffer1; 813 zstr.next_in = (Bytef*) buffer1;
814 zstr.avail_in = (uInt)read; 814 zstr.avail_in = (uInt)read;
815 815
816 // Tell zlib if this is the last chunk we want to encode 816 // Tell zlib if this is the last chunk we want to encode
817 // by setting the flush parameter to Z_FINISH 817 // by setting the flush parameter to Z_FINISH
818 flush = (totRead == toRead) ? Z_FINISH : Z_NO_FLUSH; 818 flush = (totRead == toRead) ? Z_FINISH : Z_NO_FLUSH;
819 819
820 // Run deflate() on input until output buffer not full 820 // Run deflate() on input until output buffer not full
821 // finish compression if all of source has been read in 821 // finish compression if all of source has been read in
822 do 822 do
823 { 823 {
824 zstr.next_out = (Bytef*) buffer2; 824 zstr.next_out = (Bytef*) buffer2;
825 zstr.avail_out = ZIP_READ_BUFFER; 825 zstr.avail_out = ZIP_READ_BUFFER;
826 826
827 zret = deflate(&zstr, flush); 827 zret = deflate(&zstr, flush);
828 // State not clobbered 828 // State not clobbered
829 Q_ASSERT(zret != Z_STREAM_ERROR); 829 Q_ASSERT(zret != Z_STREAM_ERROR);
830 830
831 // Write compressed data to file and empty buffer 831 // Write compressed data to file and empty buffer
832 compressed = ZIP_READ_BUFFER - zstr.avail_out; 832 compressed = ZIP_READ_BUFFER - zstr.avail_out;
833 833
834 if (password != 0) 834 if (password != 0)
835 encryptBytes(keys, buffer2, compressed); 835 encryptBytes(keys, buffer2, compressed);
836 836
837 if (device->write(buffer2, compressed) != compressed) 837 if (device->write(buffer2, compressed) != compressed)
838 { 838 {
839 deflateEnd(&zstr); 839 deflateEnd(&zstr);
840 actualFile.close(); 840 actualFile.close();
841 qDebug() << QString("Error while writing %1").arg(file.absoluteFilePath()); 841 qDebug() << QString("Error while writing %1").arg(file.absoluteFilePath());
842 delete h; 842 delete h;
843 return Zip::WriteFailed; 843 return Zip::WriteFailed;
844 } 844 }
845 845
846 written += compressed; 846 written += compressed;
847 847
848 } while (zstr.avail_out == 0); 848 } while (zstr.avail_out == 0);
849 849
850 // All input will be used 850 // All input will be used
851 Q_ASSERT(zstr.avail_in == 0); 851 Q_ASSERT(zstr.avail_in == 0);
852 852
853 } while (flush != Z_FINISH); 853 } while (flush != Z_FINISH);
854 854
855 // Stream will be complete 855 // Stream will be complete
856 Q_ASSERT(zret == Z_STREAM_END); 856 Q_ASSERT(zret == Z_STREAM_END);
857 857
858 deflateEnd(&zstr); 858 deflateEnd(&zstr);
859 859
860 } // if (level != STORE) 860 } // if (level != STORE)
861 861
862 actualFile.close(); 862 actualFile.close();
863 } 863 }
864 864
865 // Store end of entry offset 865 // Store end of entry offset
866 quint32 current = device->pos(); 866 quint32 current = device->pos();
867 867
868 // Update crc and compressed size in local header 868 // Update crc and compressed size in local header
869 if (!device->seek(crcOffset)) 869 if (!device->seek(crcOffset))
870 { 870 {
871 delete h; 871 delete h;
872 return Zip::SeekFailed; 872 return Zip::SeekFailed;
873 } 873 }
874 874
875 h->crc = dirOnly ? 0 : crc; 875 h->crc = dirOnly ? 0 : crc;
876 h->szComp += written; 876 h->szComp += written;
877 877
878 setULong(h->crc, buffer1, 0); 878 setULong(h->crc, buffer1, 0);
879 setULong(h->szComp, buffer1, 4); 879 setULong(h->szComp, buffer1, 4);
880 if ( device->write(buffer1, 8) != 8) 880 if ( device->write(buffer1, 8) != 8)
881 { 881 {
882 delete h; 882 delete h;
883 return Zip::WriteFailed; 883 return Zip::WriteFailed;
884 } 884 }
885 885
886 // Seek to end of entry 886 // Seek to end of entry
887 if (!device->seek(current)) 887 if (!device->seek(current))
888 { 888 {
889 delete h; 889 delete h;
890 return Zip::SeekFailed; 890 return Zip::SeekFailed;
891 } 891 }
892 892
893 if ((h->gpFlag[0] & 8) == 8) 893 if ((h->gpFlag[0] & 8) == 8)
894 { 894 {
895 // Write data descriptor 895 // Write data descriptor
896 896
897 // Signature: PK\7\8 897 // Signature: PK\7\8
898 buffer1[0] = 'P'; 898 buffer1[0] = 'P';
899 buffer1[1] = 'K'; 899 buffer1[1] = 'K';
900 buffer1[2] = 0x07; 900 buffer1[2] = 0x07;
901 buffer1[3] = 0x08; 901 buffer1[3] = 0x08;
902 902
903 // CRC 903 // CRC
904 setULong(h->crc, buffer1, ZIP_DD_OFF_CRC32); 904 setULong(h->crc, buffer1, ZIP_DD_OFF_CRC32);
905 905
906 // Compressed size 906 // Compressed size
907 setULong(h->szComp, buffer1, ZIP_DD_OFF_CSIZE); 907 setULong(h->szComp, buffer1, ZIP_DD_OFF_CSIZE);
908 908
909 // Uncompressed size 909 // Uncompressed size
910 setULong(h->szUncomp, buffer1, ZIP_DD_OFF_USIZE); 910 setULong(h->szUncomp, buffer1, ZIP_DD_OFF_USIZE);
911 911
912 if (device->write(buffer1, ZIP_DD_SIZE_WS) != ZIP_DD_SIZE_WS) 912 if (device->write(buffer1, ZIP_DD_SIZE_WS) != ZIP_DD_SIZE_WS)
913 { 913 {
914 delete h; 914 delete h;
915 return Zip::WriteFailed; 915 return Zip::WriteFailed;
916 } 916 }
917 } 917 }
918 918
919 headers->insert(entryName, h); 919 headers->insert(entryName, h);
920 return Zip::Ok; 920 return Zip::Ok;
921} 921}
922 922
923//! \internal 923//! \internal
924int ZipPrivate::decryptByte(quint32 key2) const 924int ZipPrivate::decryptByte(quint32 key2) const
925{ 925{
926 quint16 temp = ((quint16)(key2) & 0xffff) | 2; 926 quint16 temp = ((quint16)(key2) & 0xffff) | 2;
927 return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); 927 return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
928} 928}
929 929
930//! \internal Writes an quint32 (4 bytes) to a byte array at given offset. 930//! \internal Writes an quint32 (4 bytes) to a byte array at given offset.
931void ZipPrivate::setULong(quint32 v, char* buffer, unsigned int offset) 931void ZipPrivate::setULong(quint32 v, char* buffer, unsigned int offset)
932{ 932{
933 buffer[offset+3] = ((v >> 24) & 0xFF); 933 buffer[offset+3] = ((v >> 24) & 0xFF);
934 buffer[offset+2] = ((v >> 16) & 0xFF); 934 buffer[offset+2] = ((v >> 16) & 0xFF);
935 buffer[offset+1] = ((v >> 8) & 0xFF); 935 buffer[offset+1] = ((v >> 8) & 0xFF);
936 buffer[offset] = (v & 0xFF); 936 buffer[offset] = (v & 0xFF);
937} 937}
938 938
939//! \internal Initializes decryption keys using a password. 939//! \internal Initializes decryption keys using a password.
940void ZipPrivate::initKeys(quint32* keys) const 940void ZipPrivate::initKeys(quint32* keys) const
941{ 941{
942 // Encryption keys initialization constants are taken from the 942 // Encryption keys initialization constants are taken from the
943 // PKZip file format specification docs 943 // PKZip file format specification docs
944 keys[0] = 305419896L; 944 keys[0] = 305419896L;
945 keys[1] = 591751049L; 945 keys[1] = 591751049L;
946 keys[2] = 878082192L; 946 keys[2] = 878082192L;
947 947
948 QByteArray pwdBytes = password.toAscii(); 948 QByteArray pwdBytes = password.toAscii();
949 int sz = pwdBytes.size(); 949 int sz = pwdBytes.size();
950 const char* ascii = pwdBytes.data(); 950 const char* ascii = pwdBytes.data();
951 951
952 for (int i=0; i<sz; ++i) 952 for (int i=0; i<sz; ++i)
953 updateKeys(keys, (int)ascii[i]); 953 updateKeys(keys, (int)ascii[i]);
954} 954}
955 955
956//! \internal Updates encryption keys. 956//! \internal Updates encryption keys.
957void ZipPrivate::updateKeys(quint32* keys, int c) const 957void ZipPrivate::updateKeys(quint32* keys, int c) const
958{ 958{
959 keys[0] = CRC32(keys[0], c); 959 keys[0] = CRC32(keys[0], c);
960 keys[1] += keys[0] & 0xff; 960 keys[1] += keys[0] & 0xff;
961 keys[1] = keys[1] * 134775813L + 1; 961 keys[1] = keys[1] * 134775813L + 1;
962 keys[2] = CRC32(keys[2], ((int)keys[1]) >> 24); 962 keys[2] = CRC32(keys[2], ((int)keys[1]) >> 24);
963} 963}
964 964
965//! \internal Encrypts a byte array. 965//! \internal Encrypts a byte array.
966void ZipPrivate::encryptBytes(quint32* keys, char* buffer, qint64 read) 966void ZipPrivate::encryptBytes(quint32* keys, char* buffer, qint64 read)
967{ 967{
968 char t; 968 char t;
969 969
970 for (int i=0; i<(int)read; ++i) 970 for (int i=0; i<(int)read; ++i)
971 { 971 {
972 t = buffer[i]; 972 t = buffer[i];
973 buffer[i] ^= decryptByte(keys[2]); 973 buffer[i] ^= decryptByte(keys[2]);
974 updateKeys(keys, t); 974 updateKeys(keys, t);
975 } 975 }
976} 976}
977 977
978//! \internal Detects the best compression level for a given file extension. 978//! \internal Detects the best compression level for a given file extension.
979Zip::CompressionLevel ZipPrivate::detectCompressionByMime(const QString& ext) 979Zip::CompressionLevel ZipPrivate::detectCompressionByMime(const QString& ext)
980{ 980{
981 // files really hard to compress 981 // files really hard to compress
982 if ((ext == "png") || 982 if ((ext == "png") ||
983 (ext == "jpg") || 983 (ext == "jpg") ||
984 (ext == "jpeg") || 984 (ext == "jpeg") ||
985 (ext == "mp3") || 985 (ext == "mp3") ||
986 (ext == "ogg") || 986 (ext == "ogg") ||
987 (ext == "ogm") || 987 (ext == "ogm") ||
988 (ext == "avi") || 988 (ext == "avi") ||
989 (ext == "mov") || 989 (ext == "mov") ||
990 (ext == "rm") || 990 (ext == "rm") ||
991 (ext == "ra") || 991 (ext == "ra") ||
992 (ext == "zip") || 992 (ext == "zip") ||
993 (ext == "rar") || 993 (ext == "rar") ||
994 (ext == "bz2") || 994 (ext == "bz2") ||
995 (ext == "gz") || 995 (ext == "gz") ||
996 (ext == "7z") || 996 (ext == "7z") ||
997 (ext == "z") || 997 (ext == "z") ||
998 (ext == "jar") 998 (ext == "jar")
999 ) return Zip::Store; 999 ) return Zip::Store;
1000 1000
1001 // files slow and hard to compress 1001 // files slow and hard to compress
1002 if ((ext == "exe") || 1002 if ((ext == "exe") ||
1003 (ext == "bin") || 1003 (ext == "bin") ||
1004 (ext == "rpm") || 1004 (ext == "rpm") ||
1005 (ext == "deb") 1005 (ext == "deb")
1006 ) return Zip::Deflate2; 1006 ) return Zip::Deflate2;
1007 1007
1008 return Zip::Deflate9; 1008 return Zip::Deflate9;
1009} 1009}
1010 1010
1011/*! 1011/*!
1012 Closes the current archive and writes out pending data. 1012 Closes the current archive and writes out pending data.
1013*/ 1013*/
1014Zip::ErrorCode ZipPrivate::closeArchive() 1014Zip::ErrorCode ZipPrivate::closeArchive()
1015{ 1015{
1016 // Close current archive by writing out central directory 1016 // Close current archive by writing out central directory
1017 // and free up resources 1017 // and free up resources
1018 1018
1019 if (device == 0) 1019 if (device == 0)
1020 return Zip::Ok; 1020 return Zip::Ok;
1021 1021
1022 if (headers == 0) 1022 if (headers == 0)
1023 return Zip::Ok; 1023 return Zip::Ok;
1024 1024
1025 const ZipEntryP* h; 1025 const ZipEntryP* h;
1026 1026
1027 unsigned int sz; 1027 unsigned int sz;
1028 quint32 szCentralDir = 0; 1028 quint32 szCentralDir = 0;
1029 quint32 offCentralDir = device->pos(); 1029 quint32 offCentralDir = device->pos();
1030 1030
1031 for (QMap<QString,ZipEntryP*>::ConstIterator itr = headers->constBegin(); itr != headers->constEnd(); ++itr) 1031 for (QMap<QString,ZipEntryP*>::ConstIterator itr = headers->constBegin(); itr != headers->constEnd(); ++itr)
1032 { 1032 {
1033 h = itr.value(); 1033 h = itr.value();
1034 1034
1035 // signature 1035 // signature
1036 buffer1[0] = 'P'; 1036 buffer1[0] = 'P';
1037 buffer1[1] = 'K'; 1037 buffer1[1] = 'K';
1038 buffer1[2] = 0x01; 1038 buffer1[2] = 0x01;
1039 buffer1[3] = 0x02; 1039 buffer1[3] = 0x02;
1040 1040
1041 // version made by (currently only MS-DOS/FAT - no symlinks or other stuff supported) 1041 // version made by (currently only MS-DOS/FAT - no symlinks or other stuff supported)
1042 buffer1[ZIP_CD_OFF_MADEBY] = buffer1[ZIP_CD_OFF_MADEBY + 1] = 0; 1042 buffer1[ZIP_CD_OFF_MADEBY] = buffer1[ZIP_CD_OFF_MADEBY + 1] = 0;
1043 1043
1044 // version needed to extract 1044 // version needed to extract
1045 buffer1[ZIP_CD_OFF_VERSION] = ZIP_VERSION; 1045 buffer1[ZIP_CD_OFF_VERSION] = ZIP_VERSION;
1046 buffer1[ZIP_CD_OFF_VERSION + 1] = 0; 1046 buffer1[ZIP_CD_OFF_VERSION + 1] = 0;
1047 1047
1048 // general purpose flag 1048 // general purpose flag
1049 buffer1[ZIP_CD_OFF_GPFLAG] = h->gpFlag[0]; 1049 buffer1[ZIP_CD_OFF_GPFLAG] = h->gpFlag[0];
1050 buffer1[ZIP_CD_OFF_GPFLAG + 1] = h->gpFlag[1]; 1050 buffer1[ZIP_CD_OFF_GPFLAG + 1] = h->gpFlag[1];
1051 1051
1052 // compression method 1052 // compression method
1053 buffer1[ZIP_CD_OFF_CMET] = h->compMethod & 0xFF; 1053 buffer1[ZIP_CD_OFF_CMET] = h->compMethod & 0xFF;
1054 buffer1[ZIP_CD_OFF_CMET + 1] = (h->compMethod >> 8) & 0xFF; 1054 buffer1[ZIP_CD_OFF_CMET + 1] = (h->compMethod >> 8) & 0xFF;
1055 1055
1056 // last mod file time 1056 // last mod file time
1057 buffer1[ZIP_CD_OFF_MODT] = h->modTime[0]; 1057 buffer1[ZIP_CD_OFF_MODT] = h->modTime[0];
1058 buffer1[ZIP_CD_OFF_MODT + 1] = h->modTime[1]; 1058 buffer1[ZIP_CD_OFF_MODT + 1] = h->modTime[1];
1059 1059
1060 // last mod file date 1060 // last mod file date
1061 buffer1[ZIP_CD_OFF_MODD] = h->modDate[0]; 1061 buffer1[ZIP_CD_OFF_MODD] = h->modDate[0];
1062 buffer1[ZIP_CD_OFF_MODD + 1] = h->modDate[1]; 1062 buffer1[ZIP_CD_OFF_MODD + 1] = h->modDate[1];
1063 1063
1064 // crc (4bytes) [16,17,18,19] 1064 // crc (4bytes) [16,17,18,19]
1065 setULong(h->crc, buffer1, ZIP_CD_OFF_CRC); 1065 setULong(h->crc, buffer1, ZIP_CD_OFF_CRC);
1066 1066
1067 // compressed size (4bytes: [20,21,22,23]) 1067 // compressed size (4bytes: [20,21,22,23])
1068 setULong(h->szComp, buffer1, ZIP_CD_OFF_CSIZE); 1068 setULong(h->szComp, buffer1, ZIP_CD_OFF_CSIZE);
1069 1069
1070 // uncompressed size [24,25,26,27] 1070 // uncompressed size [24,25,26,27]
1071 setULong(h->szUncomp, buffer1, ZIP_CD_OFF_USIZE); 1071 setULong(h->szUncomp, buffer1, ZIP_CD_OFF_USIZE);
1072 1072
1073 // filename 1073 // filename
1074 QByteArray fileNameBytes = itr.key().toAscii(); 1074 QByteArray fileNameBytes = itr.key().toAscii();
1075 sz = fileNameBytes.size(); 1075 sz = fileNameBytes.size();
1076 buffer1[ZIP_CD_OFF_NAMELEN] = sz & 0xFF; 1076 buffer1[ZIP_CD_OFF_NAMELEN] = sz & 0xFF;
1077 buffer1[ZIP_CD_OFF_NAMELEN + 1] = (sz >> 8) & 0xFF; 1077 buffer1[ZIP_CD_OFF_NAMELEN + 1] = (sz >> 8) & 0xFF;
1078 1078
1079 // extra field length 1079 // extra field length
1080 buffer1[ZIP_CD_OFF_XLEN] = buffer1[ZIP_CD_OFF_XLEN + 1] = 0; 1080 buffer1[ZIP_CD_OFF_XLEN] = buffer1[ZIP_CD_OFF_XLEN + 1] = 0;
1081 1081
1082 // file comment length 1082 // file comment length
1083 buffer1[ZIP_CD_OFF_COMMLEN] = buffer1[ZIP_CD_OFF_COMMLEN + 1] = 0; 1083 buffer1[ZIP_CD_OFF_COMMLEN] = buffer1[ZIP_CD_OFF_COMMLEN + 1] = 0;
1084 1084
1085 // disk number start 1085 // disk number start
1086 buffer1[ZIP_CD_OFF_DISKSTART] = buffer1[ZIP_CD_OFF_DISKSTART + 1] = 0; 1086 buffer1[ZIP_CD_OFF_DISKSTART] = buffer1[ZIP_CD_OFF_DISKSTART + 1] = 0;
1087 1087
1088 // internal file attributes 1088 // internal file attributes
1089 buffer1[ZIP_CD_OFF_IATTR] = buffer1[ZIP_CD_OFF_IATTR + 1] = 0; 1089 buffer1[ZIP_CD_OFF_IATTR] = buffer1[ZIP_CD_OFF_IATTR + 1] = 0;
1090 1090
1091 // external file attributes 1091 // external file attributes
1092 buffer1[ZIP_CD_OFF_EATTR] = 1092 buffer1[ZIP_CD_OFF_EATTR] =
1093 buffer1[ZIP_CD_OFF_EATTR + 1] = 1093 buffer1[ZIP_CD_OFF_EATTR + 1] =
1094 buffer1[ZIP_CD_OFF_EATTR + 2] = 1094 buffer1[ZIP_CD_OFF_EATTR + 2] =
1095 buffer1[ZIP_CD_OFF_EATTR + 3] = 0; 1095 buffer1[ZIP_CD_OFF_EATTR + 3] = 0;
1096 1096
1097 // relative offset of local header [42->45] 1097 // relative offset of local header [42->45]
1098 setULong(h->lhOffset, buffer1, ZIP_CD_OFF_LHOFF); 1098 setULong(h->lhOffset, buffer1, ZIP_CD_OFF_LHOFF);
1099 1099
1100 if (device->write(buffer1, ZIP_CD_SIZE) != ZIP_CD_SIZE) 1100 if (device->write(buffer1, ZIP_CD_SIZE) != ZIP_CD_SIZE)
1101 { 1101 {
1102 //! \todo See if we can detect QFile objects using the Qt Meta Object System 1102 //! \todo See if we can detect QFile objects using the Qt Meta Object System
1103 /* 1103 /*
1104 if (!device->remove()) 1104 if (!device->remove())
1105 qDebug() << tr("Unable to delete corrupted archive: %1").arg(device->fileName()); 1105 qDebug() << tr("Unable to delete corrupted archive: %1").arg(device->fileName());
1106 */ 1106 */
1107 return Zip::WriteFailed; 1107 return Zip::WriteFailed;
1108 } 1108 }
1109 1109
1110 // Write out filename 1110 // Write out filename
1111 if ((unsigned int)device->write(fileNameBytes) != sz) 1111 if ((unsigned int)device->write(fileNameBytes) != sz)
1112 { 1112 {
1113 //! \todo SAME AS ABOVE: See if we can detect QFile objects using the Qt Meta Object System 1113 //! \todo SAME AS ABOVE: See if we can detect QFile objects using the Qt Meta Object System
1114 /* 1114 /*
1115 if (!device->remove()) 1115 if (!device->remove())
1116 qDebug() << tr("Unable to delete corrupted archive: %1").arg(device->fileName()); 1116 qDebug() << tr("Unable to delete corrupted archive: %1").arg(device->fileName());
1117 */ 1117 */
1118 return Zip::WriteFailed; 1118 return Zip::WriteFailed;
1119 } 1119 }
1120 1120
1121 szCentralDir += (ZIP_CD_SIZE + sz); 1121 szCentralDir += (ZIP_CD_SIZE + sz);
1122 1122
1123 } // central dir headers loop 1123 } // central dir headers loop
1124 1124
1125 1125
1126 // Write end of central directory 1126 // Write end of central directory
1127 1127
1128 // signature 1128 // signature
1129 buffer1[0] = 'P'; 1129 buffer1[0] = 'P';
1130 buffer1[1] = 'K'; 1130 buffer1[1] = 'K';
1131 buffer1[2] = 0x05; 1131 buffer1[2] = 0x05;
1132 buffer1[3] = 0x06; 1132 buffer1[3] = 0x06;
1133 1133
1134 // number of this disk 1134 // number of this disk
1135 buffer1[ZIP_EOCD_OFF_DISKNUM] = buffer1[ZIP_EOCD_OFF_DISKNUM + 1] = 0; 1135 buffer1[ZIP_EOCD_OFF_DISKNUM] = buffer1[ZIP_EOCD_OFF_DISKNUM + 1] = 0;
1136 1136
1137 // number of disk with central directory 1137 // number of disk with central directory
1138 buffer1[ZIP_EOCD_OFF_CDDISKNUM] = buffer1[ZIP_EOCD_OFF_CDDISKNUM + 1] = 0; 1138 buffer1[ZIP_EOCD_OFF_CDDISKNUM] = buffer1[ZIP_EOCD_OFF_CDDISKNUM + 1] = 0;
1139 1139
1140 // number of entries in this disk 1140 // number of entries in this disk
1141 sz = headers->count(); 1141 sz = headers->count();
1142 buffer1[ZIP_EOCD_OFF_ENTRIES] = sz & 0xFF; 1142 buffer1[ZIP_EOCD_OFF_ENTRIES] = sz & 0xFF;
1143 buffer1[ZIP_EOCD_OFF_ENTRIES + 1] = (sz >> 8) & 0xFF; 1143 buffer1[ZIP_EOCD_OFF_ENTRIES + 1] = (sz >> 8) & 0xFF;
1144 1144
1145 // total number of entries 1145 // total number of entries
1146 buffer1[ZIP_EOCD_OFF_CDENTRIES] = buffer1[ZIP_EOCD_OFF_ENTRIES]; 1146 buffer1[ZIP_EOCD_OFF_CDENTRIES] = buffer1[ZIP_EOCD_OFF_ENTRIES];
1147 buffer1[ZIP_EOCD_OFF_CDENTRIES + 1] = buffer1[ZIP_EOCD_OFF_ENTRIES + 1]; 1147 buffer1[ZIP_EOCD_OFF_CDENTRIES + 1] = buffer1[ZIP_EOCD_OFF_ENTRIES + 1];
1148 1148
1149 // size of central directory [12->15] 1149 // size of central directory [12->15]
1150 setULong(szCentralDir, buffer1, ZIP_EOCD_OFF_CDSIZE); 1150 setULong(szCentralDir, buffer1, ZIP_EOCD_OFF_CDSIZE);
1151 1151
1152 // central dir offset [16->19] 1152 // central dir offset [16->19]
1153 setULong(offCentralDir, buffer1, ZIP_EOCD_OFF_CDOFF); 1153 setULong(offCentralDir, buffer1, ZIP_EOCD_OFF_CDOFF);
1154 1154
1155 // ZIP file comment length 1155 // ZIP file comment length
1156 QByteArray commentBytes = comment.toAscii(); 1156 QByteArray commentBytes = comment.toAscii();
1157 quint16 commentLength = commentBytes.size(); 1157 quint16 commentLength = commentBytes.size();
1158 1158
1159 if (commentLength == 0) 1159 if (commentLength == 0)
1160 { 1160 {
1161 buffer1[ZIP_EOCD_OFF_COMMLEN] = buffer1[ZIP_EOCD_OFF_COMMLEN + 1] = 0; 1161 buffer1[ZIP_EOCD_OFF_COMMLEN] = buffer1[ZIP_EOCD_OFF_COMMLEN + 1] = 0;
1162 } 1162 }
1163 else 1163 else
1164 { 1164 {
1165 buffer1[ZIP_EOCD_OFF_COMMLEN] = commentLength & 0xFF; 1165 buffer1[ZIP_EOCD_OFF_COMMLEN] = commentLength & 0xFF;
1166 buffer1[ZIP_EOCD_OFF_COMMLEN + 1] = (commentLength >> 8) & 0xFF; 1166 buffer1[ZIP_EOCD_OFF_COMMLEN + 1] = (commentLength >> 8) & 0xFF;
1167 } 1167 }
1168 1168
1169 if (device->write(buffer1, ZIP_EOCD_SIZE) != ZIP_EOCD_SIZE) 1169 if (device->write(buffer1, ZIP_EOCD_SIZE) != ZIP_EOCD_SIZE)
1170 { 1170 {
1171 //! \todo SAME AS ABOVE: See if we can detect QFile objects using the Qt Meta Object System 1171 //! \todo SAME AS ABOVE: See if we can detect QFile objects using the Qt Meta Object System
1172 /* 1172 /*
1173 if (!device->remove()) 1173 if (!device->remove())
1174 qDebug() << tr("Unable to delete corrupted archive: %1").arg(device->fileName()); 1174 qDebug() << tr("Unable to delete corrupted archive: %1").arg(device->fileName());
1175 */ 1175 */
1176 return Zip::WriteFailed; 1176 return Zip::WriteFailed;
1177 } 1177 }
1178 1178
1179 if (commentLength != 0) 1179 if (commentLength != 0)
1180 { 1180 {
1181 if ((unsigned int)device->write(commentBytes) != commentLength) 1181 if ((unsigned int)device->write(commentBytes) != commentLength)
1182 { 1182 {
1183 //! \todo SAME AS ABOVE: See if we can detect QFile objects using the Qt Meta Object System 1183 //! \todo SAME AS ABOVE: See if we can detect QFile objects using the Qt Meta Object System
1184 /* 1184 /*
1185 if (!device->remove()) 1185 if (!device->remove())
1186 qDebug() << tr("Unable to delete corrupted archive: %1").arg(device->fileName()); 1186 qDebug() << tr("Unable to delete corrupted archive: %1").arg(device->fileName());
1187 */ 1187 */
1188 return Zip::WriteFailed; 1188 return Zip::WriteFailed;
1189 } 1189 }
1190 } 1190 }
1191 1191
1192 return Zip::Ok; 1192 return Zip::Ok;
1193} 1193}
1194 1194
1195//! \internal 1195//! \internal
1196void ZipPrivate::reset() 1196void ZipPrivate::reset()
1197{ 1197{
1198 comment.clear(); 1198 comment.clear();
1199 1199
1200 if (headers != 0) 1200 if (headers != 0)
1201 { 1201 {
1202 qDeleteAll(*headers); 1202 qDeleteAll(*headers);
1203 delete headers; 1203 delete headers;
1204 headers = 0; 1204 headers = 0;
1205 } 1205 }
1206 1206
1207 delete device; device = 0; 1207 delete device; device = 0;
1208} 1208}
1209 1209
1210//! \internal Returns the path of the parent directory 1210//! \internal Returns the path of the parent directory
1211QString ZipPrivate::extractRoot(const QString& p) 1211QString ZipPrivate::extractRoot(const QString& p)
1212{ 1212{
1213 QDir d(QDir::cleanPath(p)); 1213 QDir d(QDir::cleanPath(p));
1214 if (!d.exists()) 1214 if (!d.exists())
1215 return QString(); 1215 return QString();
1216 1216
1217 if (!d.cdUp()) 1217 if (!d.cdUp())
1218 return QString(); 1218 return QString();
1219 1219
1220 return d.absolutePath(); 1220 return d.absolutePath();
1221} 1221}