diff options
Diffstat (limited to 'rbutil/rbutilqt/zip/zip.cpp')
-rw-r--r-- | rbutil/rbutilqt/zip/zip.cpp | 2442 |
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 | */ |
218 | Zip::Zip() | 218 | Zip::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 | */ |
226 | Zip::~Zip() | 226 | Zip::~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 | */ |
235 | bool Zip::isOpen() const | 235 | bool 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 | */ |
246 | void Zip::setPassword(const QString& pwd) | 246 | void 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. |
252 | void Zip::clearPassword() | 252 | void 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. |
258 | QString Zip::password() const | 258 | QString 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 | */ |
268 | Zip::ErrorCode Zip::createArchive(const QString& filename, bool overwrite) | 268 | Zip::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 | */ |
294 | Zip::ErrorCode Zip::createArchive(QIODevice* device) | 294 | Zip::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 | */ |
308 | QString Zip::archiveComment() const | 308 | QString 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 | */ |
317 | void Zip::setArchiveComment(const QString& comment) | 317 | void 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 | */ |
333 | Zip::ErrorCode Zip::addDirectory(const QString& path, CompressionOptions options, CompressionLevel level) | 333 | Zip::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 | */ |
342 | Zip::ErrorCode Zip::addDirectory(const QString& path, const QString& root, CompressionLevel level) | 342 | Zip::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 | */ |
351 | Zip::ErrorCode Zip::addDirectoryContents(const QString& path, CompressionLevel level) | 351 | Zip::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 | */ |
360 | Zip::ErrorCode Zip::addDirectoryContents(const QString& path, const QString& root, CompressionLevel level) | 360 | Zip::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 | */ |
376 | Zip::ErrorCode Zip::addDirectory(const QString& path, const QString& root, CompressionOptions options, CompressionLevel level) | 376 | Zip::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 | */ |
467 | Zip::ErrorCode Zip::closeArchive() | 467 | Zip::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 | */ |
477 | QString Zip::formatError(Zip::ErrorCode c) const | 477 | QString 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 |
502 | ZipPrivate::ZipPrivate() | 502 | ZipPrivate::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 |
513 | ZipPrivate::~ZipPrivate() | 513 | ZipPrivate::~ZipPrivate() |
514 | { | 514 | { |
515 | closeArchive(); | 515 | closeArchive(); |
516 | } | 516 | } |
517 | 517 | ||
518 | //! \internal | 518 | //! \internal |
519 | Zip::ErrorCode ZipPrivate::createArchive(QIODevice* dev) | 519 | Zip::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. |
543 | Zip::ErrorCode ZipPrivate::createEntry(const QFileInfo& file, const QString& root, Zip::CompressionLevel level) | 543 | Zip::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 |
924 | int ZipPrivate::decryptByte(quint32 key2) const | 924 | int 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. |
931 | void ZipPrivate::setULong(quint32 v, char* buffer, unsigned int offset) | 931 | void 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. |
940 | void ZipPrivate::initKeys(quint32* keys) const | 940 | void 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. |
957 | void ZipPrivate::updateKeys(quint32* keys, int c) const | 957 | void 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. |
966 | void ZipPrivate::encryptBytes(quint32* keys, char* buffer, qint64 read) | 966 | void 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. |
979 | Zip::CompressionLevel ZipPrivate::detectCompressionByMime(const QString& ext) | 979 | Zip::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 | */ |
1014 | Zip::ErrorCode ZipPrivate::closeArchive() | 1014 | Zip::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 |
1196 | void ZipPrivate::reset() | 1196 | void 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 |
1211 | QString ZipPrivate::extractRoot(const QString& p) | 1211 | QString 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 | } |