diff options
author | Nicolas Pennequin <nicolas.pennequin@free.fr> | 2008-05-11 17:21:14 +0000 |
---|---|---|
committer | Nicolas Pennequin <nicolas.pennequin@free.fr> | 2008-05-11 17:21:14 +0000 |
commit | 9c54187678281077b8700c1c107f54a0b40d7050 (patch) | |
tree | b07061b11477bfbdfddaa52bee43f4993167dbc0 /rbutil/rbutilqt/zip | |
parent | 850c4f98baecf3d3c28e916927d15d3bbd0cd502 (diff) | |
download | rockbox-9c54187678281077b8700c1c107f54a0b40d7050.tar.gz rockbox-9c54187678281077b8700c1c107f54a0b40d7050.zip |
Set svn:eol-style on files from the rbutil directory and its subdirectories.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17462 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'rbutil/rbutilqt/zip')
-rw-r--r-- | rbutil/rbutilqt/zip/unzip.cpp | 2720 | ||||
-rw-r--r-- | rbutil/rbutilqt/zip/unzip.h | 288 | ||||
-rw-r--r-- | rbutil/rbutilqt/zip/unzip_p.h | 224 | ||||
-rw-r--r-- | rbutil/rbutilqt/zip/zip.cpp | 2442 | ||||
-rw-r--r-- | rbutil/rbutilqt/zip/zip.h | 230 | ||||
-rw-r--r-- | rbutil/rbutilqt/zip/zip_p.h | 186 | ||||
-rw-r--r-- | rbutil/rbutilqt/zip/zipentry_p.h | 156 |
7 files changed, 3123 insertions, 3123 deletions
diff --git a/rbutil/rbutilqt/zip/unzip.cpp b/rbutil/rbutilqt/zip/unzip.cpp index 3cc385ab36..d49529bad9 100644 --- a/rbutil/rbutilqt/zip/unzip.cpp +++ b/rbutil/rbutilqt/zip/unzip.cpp | |||
@@ -1,1360 +1,1360 @@ | |||
1 | /**************************************************************************** | 1 | /**************************************************************************** |
2 | ** Filename: unzip.cpp | 2 | ** Filename: unzip.cpp |
3 | ** Last updated [dd/mm/yyyy]: 28/01/2007 | 3 | ** Last updated [dd/mm/yyyy]: 28/01/2007 |
4 | ** | 4 | ** |
5 | ** pkzip 2.0 decompression. | 5 | ** pkzip 2.0 decompression. |
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 "unzip.h" | 28 | #include "unzip.h" |
29 | #include "unzip_p.h" | 29 | #include "unzip_p.h" |
30 | #include "zipentry_p.h" | 30 | #include "zipentry_p.h" |
31 | 31 | ||
32 | #include <QString> | 32 | #include <QString> |
33 | #include <QStringList> | 33 | #include <QStringList> |
34 | #include <QDir> | 34 | #include <QDir> |
35 | #include <QFile> | 35 | #include <QFile> |
36 | #include <QCoreApplication> | 36 | #include <QCoreApplication> |
37 | 37 | ||
38 | // You can remove this #include if you replace the qDebug() statements. | 38 | // You can remove this #include if you replace the qDebug() statements. |
39 | #include <QtDebug> | 39 | #include <QtDebug> |
40 | 40 | ||
41 | /*! | 41 | /*! |
42 | \class UnZip unzip.h | 42 | \class UnZip unzip.h |
43 | 43 | ||
44 | \brief PKZip 2.0 file decompression. | 44 | \brief PKZip 2.0 file decompression. |
45 | Compatibility with later versions is not ensured as they may use | 45 | Compatibility with later versions is not ensured as they may use |
46 | unsupported compression algorithms. | 46 | unsupported compression algorithms. |
47 | Versions after 2.7 may have an incompatible header format and thus be | 47 | Versions after 2.7 may have an incompatible header format and thus be |
48 | completely incompatible. | 48 | completely incompatible. |
49 | */ | 49 | */ |
50 | 50 | ||
51 | /*! \enum UnZip::ErrorCode The result of a decompression operation. | 51 | /*! \enum UnZip::ErrorCode The result of a decompression operation. |
52 | \value UnZip::Ok No error occurred. | 52 | \value UnZip::Ok No error occurred. |
53 | \value UnZip::ZlibInit Failed to init or load the zlib library. | 53 | \value UnZip::ZlibInit Failed to init or load the zlib library. |
54 | \value UnZip::ZlibError The zlib library returned some error. | 54 | \value UnZip::ZlibError The zlib library returned some error. |
55 | \value UnZip::OpenFailed Unable to create or open a device. | 55 | \value UnZip::OpenFailed Unable to create or open a device. |
56 | \value UnZip::PartiallyCorrupted Corrupted zip archive - some files could be extracted. | 56 | \value UnZip::PartiallyCorrupted Corrupted zip archive - some files could be extracted. |
57 | \value UnZip::Corrupted Corrupted or invalid zip archive. | 57 | \value UnZip::Corrupted Corrupted or invalid zip archive. |
58 | \value UnZip::WrongPassword Unable to decrypt a password protected file. | 58 | \value UnZip::WrongPassword Unable to decrypt a password protected file. |
59 | \value UnZip::NoOpenArchive No archive has been opened yet. | 59 | \value UnZip::NoOpenArchive No archive has been opened yet. |
60 | \value UnZip::FileNotFound Unable to find the requested file in the archive. | 60 | \value UnZip::FileNotFound Unable to find the requested file in the archive. |
61 | \value UnZip::ReadFailed Reading of a file failed. | 61 | \value UnZip::ReadFailed Reading of a file failed. |
62 | \value UnZip::WriteFailed Writing of a file failed. | 62 | \value UnZip::WriteFailed Writing of a file failed. |
63 | \value UnZip::SeekFailed Seek failed. | 63 | \value UnZip::SeekFailed Seek failed. |
64 | \value UnZip::CreateDirFailed Could not create a directory. | 64 | \value UnZip::CreateDirFailed Could not create a directory. |
65 | \value UnZip::InvalidDevice A null device has been passed as parameter. | 65 | \value UnZip::InvalidDevice A null device has been passed as parameter. |
66 | \value UnZip::InvalidArchive This is not a valid (or supported) ZIP archive. | 66 | \value UnZip::InvalidArchive This is not a valid (or supported) ZIP archive. |
67 | \value UnZip::HeaderConsistencyError Local header record info does not match with the central directory record info. The archive may be corrupted. | 67 | \value UnZip::HeaderConsistencyError Local header record info does not match with the central directory record info. The archive may be corrupted. |
68 | 68 | ||
69 | \value UnZip::Skip Internal use only. | 69 | \value UnZip::Skip Internal use only. |
70 | \value UnZip::SkipAll Internal use only. | 70 | \value UnZip::SkipAll Internal use only. |
71 | */ | 71 | */ |
72 | 72 | ||
73 | /*! \enum UnZip::ExtractionOptions Some options for the file extraction methods. | 73 | /*! \enum UnZip::ExtractionOptions Some options for the file extraction methods. |
74 | \value UnZip::ExtractPaths Default. Does not ignore the path of the zipped files. | 74 | \value UnZip::ExtractPaths Default. Does not ignore the path of the zipped files. |
75 | \value UnZip::SkipPaths Default. Ignores the path of the zipped files and extracts them all to the same root directory. | 75 | \value UnZip::SkipPaths Default. Ignores the path of the zipped files and extracts them all to the same root directory. |
76 | */ | 76 | */ |
77 | 77 | ||
78 | //! Local header size (excluding signature, excluding variable length fields) | 78 | //! Local header size (excluding signature, excluding variable length fields) |
79 | #define UNZIP_LOCAL_HEADER_SIZE 26 | 79 | #define UNZIP_LOCAL_HEADER_SIZE 26 |
80 | //! Central Directory file entry size (excluding signature, excluding variable length fields) | 80 | //! Central Directory file entry size (excluding signature, excluding variable length fields) |
81 | #define UNZIP_CD_ENTRY_SIZE_NS 42 | 81 | #define UNZIP_CD_ENTRY_SIZE_NS 42 |
82 | //! Data descriptor size (excluding signature) | 82 | //! Data descriptor size (excluding signature) |
83 | #define UNZIP_DD_SIZE 12 | 83 | #define UNZIP_DD_SIZE 12 |
84 | //! End Of Central Directory size (including signature, excluding variable length fields) | 84 | //! End Of Central Directory size (including signature, excluding variable length fields) |
85 | #define UNZIP_EOCD_SIZE 22 | 85 | #define UNZIP_EOCD_SIZE 22 |
86 | //! Local header entry encryption header size | 86 | //! Local header entry encryption header size |
87 | #define UNZIP_LOCAL_ENC_HEADER_SIZE 12 | 87 | #define UNZIP_LOCAL_ENC_HEADER_SIZE 12 |
88 | 88 | ||
89 | // Some offsets inside a CD record (excluding signature) | 89 | // Some offsets inside a CD record (excluding signature) |
90 | #define UNZIP_CD_OFF_VERSION 0 | 90 | #define UNZIP_CD_OFF_VERSION 0 |
91 | #define UNZIP_CD_OFF_GPFLAG 4 | 91 | #define UNZIP_CD_OFF_GPFLAG 4 |
92 | #define UNZIP_CD_OFF_CMETHOD 6 | 92 | #define UNZIP_CD_OFF_CMETHOD 6 |
93 | #define UNZIP_CD_OFF_MODT 8 | 93 | #define UNZIP_CD_OFF_MODT 8 |
94 | #define UNZIP_CD_OFF_MODD 10 | 94 | #define UNZIP_CD_OFF_MODD 10 |
95 | #define UNZIP_CD_OFF_CRC32 12 | 95 | #define UNZIP_CD_OFF_CRC32 12 |
96 | #define UNZIP_CD_OFF_CSIZE 16 | 96 | #define UNZIP_CD_OFF_CSIZE 16 |
97 | #define UNZIP_CD_OFF_USIZE 20 | 97 | #define UNZIP_CD_OFF_USIZE 20 |
98 | #define UNZIP_CD_OFF_NAMELEN 24 | 98 | #define UNZIP_CD_OFF_NAMELEN 24 |
99 | #define UNZIP_CD_OFF_XLEN 26 | 99 | #define UNZIP_CD_OFF_XLEN 26 |
100 | #define UNZIP_CD_OFF_COMMLEN 28 | 100 | #define UNZIP_CD_OFF_COMMLEN 28 |
101 | #define UNZIP_CD_OFF_LHOFFSET 38 | 101 | #define UNZIP_CD_OFF_LHOFFSET 38 |
102 | 102 | ||
103 | // Some offsets inside a local header record (excluding signature) | 103 | // Some offsets inside a local header record (excluding signature) |
104 | #define UNZIP_LH_OFF_VERSION 0 | 104 | #define UNZIP_LH_OFF_VERSION 0 |
105 | #define UNZIP_LH_OFF_GPFLAG 2 | 105 | #define UNZIP_LH_OFF_GPFLAG 2 |
106 | #define UNZIP_LH_OFF_CMETHOD 4 | 106 | #define UNZIP_LH_OFF_CMETHOD 4 |
107 | #define UNZIP_LH_OFF_MODT 6 | 107 | #define UNZIP_LH_OFF_MODT 6 |
108 | #define UNZIP_LH_OFF_MODD 8 | 108 | #define UNZIP_LH_OFF_MODD 8 |
109 | #define UNZIP_LH_OFF_CRC32 10 | 109 | #define UNZIP_LH_OFF_CRC32 10 |
110 | #define UNZIP_LH_OFF_CSIZE 14 | 110 | #define UNZIP_LH_OFF_CSIZE 14 |
111 | #define UNZIP_LH_OFF_USIZE 18 | 111 | #define UNZIP_LH_OFF_USIZE 18 |
112 | #define UNZIP_LH_OFF_NAMELEN 22 | 112 | #define UNZIP_LH_OFF_NAMELEN 22 |
113 | #define UNZIP_LH_OFF_XLEN 24 | 113 | #define UNZIP_LH_OFF_XLEN 24 |
114 | 114 | ||
115 | // Some offsets inside a data descriptor record (excluding signature) | 115 | // Some offsets inside a data descriptor record (excluding signature) |
116 | #define UNZIP_DD_OFF_CRC32 0 | 116 | #define UNZIP_DD_OFF_CRC32 0 |
117 | #define UNZIP_DD_OFF_CSIZE 4 | 117 | #define UNZIP_DD_OFF_CSIZE 4 |
118 | #define UNZIP_DD_OFF_USIZE 8 | 118 | #define UNZIP_DD_OFF_USIZE 8 |
119 | 119 | ||
120 | // Some offsets inside a EOCD record | 120 | // Some offsets inside a EOCD record |
121 | #define UNZIP_EOCD_OFF_ENTRIES 6 | 121 | #define UNZIP_EOCD_OFF_ENTRIES 6 |
122 | #define UNZIP_EOCD_OFF_CDOFF 12 | 122 | #define UNZIP_EOCD_OFF_CDOFF 12 |
123 | #define UNZIP_EOCD_OFF_COMMLEN 16 | 123 | #define UNZIP_EOCD_OFF_COMMLEN 16 |
124 | 124 | ||
125 | /*! | 125 | /*! |
126 | Max version handled by this API. | 126 | Max version handled by this API. |
127 | 0x1B = 2.7 --> full compatibility only up to version 2.0 (0x14) | 127 | 0x1B = 2.7 --> full compatibility only up to version 2.0 (0x14) |
128 | versions from 2.1 to 2.7 may use unsupported compression methods | 128 | versions from 2.1 to 2.7 may use unsupported compression methods |
129 | versions after 2.7 may have an incompatible header format | 129 | versions after 2.7 may have an incompatible header format |
130 | */ | 130 | */ |
131 | #define UNZIP_VERSION 0x1B | 131 | #define UNZIP_VERSION 0x1B |
132 | //! Full compatibility granted until this version | 132 | //! Full compatibility granted until this version |
133 | #define UNZIP_VERSION_STRICT 0x14 | 133 | #define UNZIP_VERSION_STRICT 0x14 |
134 | 134 | ||
135 | //! CRC32 routine | 135 | //! CRC32 routine |
136 | #define CRC32(c, b) crcTable[((int)c^b) & 0xff] ^ (c >> 8) | 136 | #define CRC32(c, b) crcTable[((int)c^b) & 0xff] ^ (c >> 8) |
137 | 137 | ||
138 | //! Checks if some file has been already extracted. | 138 | //! Checks if some file has been already extracted. |
139 | #define UNZIP_CHECK_FOR_VALID_DATA \ | 139 | #define UNZIP_CHECK_FOR_VALID_DATA \ |
140 | {\ | 140 | {\ |
141 | if (headers != 0)\ | 141 | if (headers != 0)\ |
142 | {\ | 142 | {\ |
143 | qDebug() << "Corrupted zip archive. Some files might be extracted.";\ | 143 | qDebug() << "Corrupted zip archive. Some files might be extracted.";\ |
144 | ec = headers->size() != 0 ? UnZip::PartiallyCorrupted : UnZip::Corrupted;\ | 144 | ec = headers->size() != 0 ? UnZip::PartiallyCorrupted : UnZip::Corrupted;\ |
145 | break;\ | 145 | break;\ |
146 | }\ | 146 | }\ |
147 | else\ | 147 | else\ |
148 | {\ | 148 | {\ |
149 | delete device;\ | 149 | delete device;\ |
150 | device = 0;\ | 150 | device = 0;\ |
151 | qDebug() << "Corrupted or invalid zip archive";\ | 151 | qDebug() << "Corrupted or invalid zip archive";\ |
152 | ec = UnZip::Corrupted;\ | 152 | ec = UnZip::Corrupted;\ |
153 | break;\ | 153 | break;\ |
154 | }\ | 154 | }\ |
155 | } | 155 | } |
156 | 156 | ||
157 | 157 | ||
158 | /************************************************************************ | 158 | /************************************************************************ |
159 | Public interface | 159 | Public interface |
160 | *************************************************************************/ | 160 | *************************************************************************/ |
161 | 161 | ||
162 | /*! | 162 | /*! |
163 | Creates a new Zip file decompressor. | 163 | Creates a new Zip file decompressor. |
164 | */ | 164 | */ |
165 | UnZip::UnZip() | 165 | UnZip::UnZip() |
166 | { | 166 | { |
167 | d = new UnzipPrivate; | 167 | d = new UnzipPrivate; |
168 | } | 168 | } |
169 | 169 | ||
170 | /*! | 170 | /*! |
171 | Closes any open archive and releases used resources. | 171 | Closes any open archive and releases used resources. |
172 | */ | 172 | */ |
173 | UnZip::~UnZip() | 173 | UnZip::~UnZip() |
174 | { | 174 | { |
175 | closeArchive(); | 175 | closeArchive(); |
176 | delete d; | 176 | delete d; |
177 | } | 177 | } |
178 | 178 | ||
179 | /*! | 179 | /*! |
180 | Returns true if there is an open archive. | 180 | Returns true if there is an open archive. |
181 | */ | 181 | */ |
182 | bool UnZip::isOpen() const | 182 | bool UnZip::isOpen() const |
183 | { | 183 | { |
184 | return d->device != 0; | 184 | return d->device != 0; |
185 | } | 185 | } |
186 | 186 | ||
187 | /*! | 187 | /*! |
188 | Opens a zip archive and reads the files list. Closes any previously opened archive. | 188 | Opens a zip archive and reads the files list. Closes any previously opened archive. |
189 | */ | 189 | */ |
190 | UnZip::ErrorCode UnZip::openArchive(const QString& filename) | 190 | UnZip::ErrorCode UnZip::openArchive(const QString& filename) |
191 | { | 191 | { |
192 | QFile* file = new QFile(filename); | 192 | QFile* file = new QFile(filename); |
193 | 193 | ||
194 | if (!file->exists()) { | 194 | if (!file->exists()) { |
195 | delete file; | 195 | delete file; |
196 | return UnZip::FileNotFound; | 196 | return UnZip::FileNotFound; |
197 | } | 197 | } |
198 | 198 | ||
199 | if (!file->open(QIODevice::ReadOnly)) { | 199 | if (!file->open(QIODevice::ReadOnly)) { |
200 | delete file; | 200 | delete file; |
201 | return UnZip::OpenFailed; | 201 | return UnZip::OpenFailed; |
202 | } | 202 | } |
203 | 203 | ||
204 | return openArchive(file); | 204 | return openArchive(file); |
205 | } | 205 | } |
206 | 206 | ||
207 | /*! | 207 | /*! |
208 | Opens a zip archive and reads the entries list. | 208 | Opens a zip archive and reads the entries list. |
209 | Closes any previously opened archive. | 209 | Closes any previously opened archive. |
210 | \warning The class takes ownership of the device so don't delete it! | 210 | \warning The class takes ownership of the device so don't delete it! |
211 | */ | 211 | */ |
212 | UnZip::ErrorCode UnZip::openArchive(QIODevice* device) | 212 | UnZip::ErrorCode UnZip::openArchive(QIODevice* device) |
213 | { | 213 | { |
214 | if (device == 0) | 214 | if (device == 0) |
215 | { | 215 | { |
216 | qDebug() << "Invalid device."; | 216 | qDebug() << "Invalid device."; |
217 | return UnZip::InvalidDevice; | 217 | return UnZip::InvalidDevice; |
218 | } | 218 | } |
219 | 219 | ||
220 | return d->openArchive(device); | 220 | return d->openArchive(device); |
221 | } | 221 | } |
222 | 222 | ||
223 | /*! | 223 | /*! |
224 | Closes the archive and releases all the used resources (like cached passwords). | 224 | Closes the archive and releases all the used resources (like cached passwords). |
225 | */ | 225 | */ |
226 | void UnZip::closeArchive() | 226 | void UnZip::closeArchive() |
227 | { | 227 | { |
228 | d->closeArchive(); | 228 | d->closeArchive(); |
229 | } | 229 | } |
230 | 230 | ||
231 | QString UnZip::archiveComment() const | 231 | QString UnZip::archiveComment() const |
232 | { | 232 | { |
233 | if (d->device == 0) | 233 | if (d->device == 0) |
234 | return QString(); | 234 | return QString(); |
235 | return d->comment; | 235 | return d->comment; |
236 | } | 236 | } |
237 | 237 | ||
238 | /*! | 238 | /*! |
239 | Returns a locale translated error string for a given error code. | 239 | Returns a locale translated error string for a given error code. |
240 | */ | 240 | */ |
241 | QString UnZip::formatError(UnZip::ErrorCode c) const | 241 | QString UnZip::formatError(UnZip::ErrorCode c) const |
242 | { | 242 | { |
243 | switch (c) | 243 | switch (c) |
244 | { | 244 | { |
245 | case Ok: return QCoreApplication::translate("UnZip", "ZIP operation completed successfully."); break; | 245 | case Ok: return QCoreApplication::translate("UnZip", "ZIP operation completed successfully."); break; |
246 | case ZlibInit: return QCoreApplication::translate("UnZip", "Failed to initialize or load zlib library."); break; | 246 | case ZlibInit: return QCoreApplication::translate("UnZip", "Failed to initialize or load zlib library."); break; |
247 | case ZlibError: return QCoreApplication::translate("UnZip", "zlib library error."); break; | 247 | case ZlibError: return QCoreApplication::translate("UnZip", "zlib library error."); break; |
248 | case OpenFailed: return QCoreApplication::translate("UnZip", "Unable to create or open file."); break; | 248 | case OpenFailed: return QCoreApplication::translate("UnZip", "Unable to create or open file."); break; |
249 | case PartiallyCorrupted: return QCoreApplication::translate("UnZip", "Partially corrupted archive. Some files might be extracted."); break; | 249 | case PartiallyCorrupted: return QCoreApplication::translate("UnZip", "Partially corrupted archive. Some files might be extracted."); break; |
250 | case Corrupted: return QCoreApplication::translate("UnZip", "Corrupted archive."); break; | 250 | case Corrupted: return QCoreApplication::translate("UnZip", "Corrupted archive."); break; |
251 | case WrongPassword: return QCoreApplication::translate("UnZip", "Wrong password."); break; | 251 | case WrongPassword: return QCoreApplication::translate("UnZip", "Wrong password."); break; |
252 | case NoOpenArchive: return QCoreApplication::translate("UnZip", "No archive has been created yet."); break; | 252 | case NoOpenArchive: return QCoreApplication::translate("UnZip", "No archive has been created yet."); break; |
253 | case FileNotFound: return QCoreApplication::translate("UnZip", "File or directory does not exist."); break; | 253 | case FileNotFound: return QCoreApplication::translate("UnZip", "File or directory does not exist."); break; |
254 | case ReadFailed: return QCoreApplication::translate("UnZip", "File read error."); break; | 254 | case ReadFailed: return QCoreApplication::translate("UnZip", "File read error."); break; |
255 | case WriteFailed: return QCoreApplication::translate("UnZip", "File write error."); break; | 255 | case WriteFailed: return QCoreApplication::translate("UnZip", "File write error."); break; |
256 | case SeekFailed: return QCoreApplication::translate("UnZip", "File seek error."); break; | 256 | case SeekFailed: return QCoreApplication::translate("UnZip", "File seek error."); break; |
257 | case CreateDirFailed: return QCoreApplication::translate("UnZip", "Unable to create a directory."); break; | 257 | case CreateDirFailed: return QCoreApplication::translate("UnZip", "Unable to create a directory."); break; |
258 | case InvalidDevice: return QCoreApplication::translate("UnZip", "Invalid device."); break; | 258 | case InvalidDevice: return QCoreApplication::translate("UnZip", "Invalid device."); break; |
259 | case InvalidArchive: return QCoreApplication::translate("UnZip", "Invalid or incompatible zip archive."); break; | 259 | case InvalidArchive: return QCoreApplication::translate("UnZip", "Invalid or incompatible zip archive."); break; |
260 | case HeaderConsistencyError: return QCoreApplication::translate("UnZip", "Inconsistent headers. Archive might be corrupted."); break; | 260 | case HeaderConsistencyError: return QCoreApplication::translate("UnZip", "Inconsistent headers. Archive might be corrupted."); break; |
261 | default: ; | 261 | default: ; |
262 | } | 262 | } |
263 | 263 | ||
264 | return QCoreApplication::translate("UnZip", "Unknown error."); | 264 | return QCoreApplication::translate("UnZip", "Unknown error."); |
265 | } | 265 | } |
266 | 266 | ||
267 | /*! | 267 | /*! |
268 | Returns true if the archive contains a file with the given path and name. | 268 | Returns true if the archive contains a file with the given path and name. |
269 | */ | 269 | */ |
270 | bool UnZip::contains(const QString& file) const | 270 | bool UnZip::contains(const QString& file) const |
271 | { | 271 | { |
272 | if (d->headers == 0) | 272 | if (d->headers == 0) |
273 | return false; | 273 | return false; |
274 | 274 | ||
275 | return d->headers->contains(file); | 275 | return d->headers->contains(file); |
276 | } | 276 | } |
277 | 277 | ||
278 | /*! | 278 | /*! |
279 | Returns complete paths of files and directories in this archive. | 279 | Returns complete paths of files and directories in this archive. |
280 | */ | 280 | */ |
281 | QStringList UnZip::fileList() const | 281 | QStringList UnZip::fileList() const |
282 | { | 282 | { |
283 | return d->headers == 0 ? QStringList() : d->headers->keys(); | 283 | return d->headers == 0 ? QStringList() : d->headers->keys(); |
284 | } | 284 | } |
285 | 285 | ||
286 | /*! | 286 | /*! |
287 | Returns information for each (correctly parsed) entry of this archive. | 287 | Returns information for each (correctly parsed) entry of this archive. |
288 | */ | 288 | */ |
289 | QList<UnZip::ZipEntry> UnZip::entryList() const | 289 | QList<UnZip::ZipEntry> UnZip::entryList() const |
290 | { | 290 | { |
291 | QList<UnZip::ZipEntry> list; | 291 | QList<UnZip::ZipEntry> list; |
292 | 292 | ||
293 | if (d->headers != 0) | 293 | if (d->headers != 0) |
294 | { | 294 | { |
295 | for (QMap<QString,ZipEntryP*>::ConstIterator it = d->headers->constBegin(); it != d->headers->constEnd(); ++it) | 295 | for (QMap<QString,ZipEntryP*>::ConstIterator it = d->headers->constBegin(); it != d->headers->constEnd(); ++it) |
296 | { | 296 | { |
297 | const ZipEntryP* entry = it.value(); | 297 | const ZipEntryP* entry = it.value(); |
298 | Q_ASSERT(entry != 0); | 298 | Q_ASSERT(entry != 0); |
299 | 299 | ||
300 | ZipEntry z; | 300 | ZipEntry z; |
301 | 301 | ||
302 | z.filename = it.key(); | 302 | z.filename = it.key(); |
303 | if (!entry->comment.isEmpty()) | 303 | if (!entry->comment.isEmpty()) |
304 | z.comment = entry->comment; | 304 | z.comment = entry->comment; |
305 | z.compressedSize = entry->szComp; | 305 | z.compressedSize = entry->szComp; |
306 | z.uncompressedSize = entry->szUncomp; | 306 | z.uncompressedSize = entry->szUncomp; |
307 | z.crc32 = entry->crc; | 307 | z.crc32 = entry->crc; |
308 | z.lastModified = d->convertDateTime(entry->modDate, entry->modTime); | 308 | z.lastModified = d->convertDateTime(entry->modDate, entry->modTime); |
309 | 309 | ||
310 | z.compression = entry->compMethod == 0 ? NoCompression : entry->compMethod == 8 ? Deflated : UnknownCompression; | 310 | z.compression = entry->compMethod == 0 ? NoCompression : entry->compMethod == 8 ? Deflated : UnknownCompression; |
311 | z.type = z.filename.endsWith("/") ? Directory : File; | 311 | z.type = z.filename.endsWith("/") ? Directory : File; |
312 | 312 | ||
313 | z.encrypted = entry->isEncrypted(); | 313 | z.encrypted = entry->isEncrypted(); |
314 | 314 | ||
315 | list.append(z); | 315 | list.append(z); |
316 | } | 316 | } |
317 | } | 317 | } |
318 | 318 | ||
319 | return list; | 319 | return list; |
320 | } | 320 | } |
321 | 321 | ||
322 | /*! | 322 | /*! |
323 | Extracts the whole archive to a directory. | 323 | Extracts the whole archive to a directory. |
324 | */ | 324 | */ |
325 | UnZip::ErrorCode UnZip::extractAll(const QString& dirname, ExtractionOptions options) | 325 | UnZip::ErrorCode UnZip::extractAll(const QString& dirname, ExtractionOptions options) |
326 | { | 326 | { |
327 | return extractAll(QDir(dirname), options); | 327 | return extractAll(QDir(dirname), options); |
328 | } | 328 | } |
329 | 329 | ||
330 | /*! | 330 | /*! |
331 | Extracts the whole archive to a directory. | 331 | Extracts the whole archive to a directory. |
332 | */ | 332 | */ |
333 | UnZip::ErrorCode UnZip::extractAll(const QDir& dir, ExtractionOptions options) | 333 | UnZip::ErrorCode UnZip::extractAll(const QDir& dir, ExtractionOptions options) |
334 | { | 334 | { |
335 | // this should only happen if we didn't call openArchive() yet | 335 | // this should only happen if we didn't call openArchive() yet |
336 | if (d->device == 0) | 336 | if (d->device == 0) |
337 | return NoOpenArchive; | 337 | return NoOpenArchive; |
338 | 338 | ||
339 | if (d->headers == 0) | 339 | if (d->headers == 0) |
340 | return Ok; | 340 | return Ok; |
341 | 341 | ||
342 | bool end = false; | 342 | bool end = false; |
343 | for (QMap<QString,ZipEntryP*>::Iterator itr = d->headers->begin(); itr != d->headers->end(); ++itr) | 343 | for (QMap<QString,ZipEntryP*>::Iterator itr = d->headers->begin(); itr != d->headers->end(); ++itr) |
344 | { | 344 | { |
345 | ZipEntryP* entry = itr.value(); | 345 | ZipEntryP* entry = itr.value(); |
346 | Q_ASSERT(entry != 0); | 346 | Q_ASSERT(entry != 0); |
347 | 347 | ||
348 | if ((entry->isEncrypted()) && d->skipAllEncrypted) | 348 | if ((entry->isEncrypted()) && d->skipAllEncrypted) |
349 | continue; | 349 | continue; |
350 | 350 | ||
351 | switch (d->extractFile(itr.key(), *entry, dir, options)) | 351 | switch (d->extractFile(itr.key(), *entry, dir, options)) |
352 | { | 352 | { |
353 | case Corrupted: | 353 | case Corrupted: |
354 | qDebug() << "Removing corrupted entry" << itr.key(); | 354 | qDebug() << "Removing corrupted entry" << itr.key(); |
355 | d->headers->erase(itr++); | 355 | d->headers->erase(itr++); |
356 | if (itr == d->headers->end()) | 356 | if (itr == d->headers->end()) |
357 | end = true; | 357 | end = true; |
358 | break; | 358 | break; |
359 | case CreateDirFailed: | 359 | case CreateDirFailed: |
360 | break; | 360 | break; |
361 | case Skip: | 361 | case Skip: |
362 | break; | 362 | break; |
363 | case SkipAll: | 363 | case SkipAll: |
364 | d->skipAllEncrypted = true; | 364 | d->skipAllEncrypted = true; |
365 | break; | 365 | break; |
366 | default: | 366 | default: |
367 | ; | 367 | ; |
368 | } | 368 | } |
369 | 369 | ||
370 | if (end) | 370 | if (end) |
371 | break; | 371 | break; |
372 | } | 372 | } |
373 | 373 | ||
374 | return Ok; | 374 | return Ok; |
375 | } | 375 | } |
376 | 376 | ||
377 | /*! | 377 | /*! |
378 | Extracts a single file to a directory. | 378 | Extracts a single file to a directory. |
379 | */ | 379 | */ |
380 | UnZip::ErrorCode UnZip::extractFile(const QString& filename, const QString& dirname, ExtractionOptions options) | 380 | UnZip::ErrorCode UnZip::extractFile(const QString& filename, const QString& dirname, ExtractionOptions options) |
381 | { | 381 | { |
382 | return extractFile(filename, QDir(dirname), options); | 382 | return extractFile(filename, QDir(dirname), options); |
383 | } | 383 | } |
384 | 384 | ||
385 | /*! | 385 | /*! |
386 | Extracts a single file to a directory. | 386 | Extracts a single file to a directory. |
387 | */ | 387 | */ |
388 | UnZip::ErrorCode UnZip::extractFile(const QString& filename, const QDir& dir, ExtractionOptions options) | 388 | UnZip::ErrorCode UnZip::extractFile(const QString& filename, const QDir& dir, ExtractionOptions options) |
389 | { | 389 | { |
390 | QMap<QString,ZipEntryP*>::Iterator itr = d->headers->find(filename); | 390 | QMap<QString,ZipEntryP*>::Iterator itr = d->headers->find(filename); |
391 | if (itr != d->headers->end()) | 391 | if (itr != d->headers->end()) |
392 | { | 392 | { |
393 | ZipEntryP* entry = itr.value(); | 393 | ZipEntryP* entry = itr.value(); |
394 | Q_ASSERT(entry != 0); | 394 | Q_ASSERT(entry != 0); |
395 | return d->extractFile(itr.key(), *entry, dir, options); | 395 | return d->extractFile(itr.key(), *entry, dir, options); |
396 | } | 396 | } |
397 | 397 | ||
398 | return FileNotFound; | 398 | return FileNotFound; |
399 | } | 399 | } |
400 | 400 | ||
401 | /*! | 401 | /*! |
402 | Extracts a single file to a directory. | 402 | Extracts a single file to a directory. |
403 | */ | 403 | */ |
404 | UnZip::ErrorCode UnZip::extractFile(const QString& filename, QIODevice* dev, ExtractionOptions options) | 404 | UnZip::ErrorCode UnZip::extractFile(const QString& filename, QIODevice* dev, ExtractionOptions options) |
405 | { | 405 | { |
406 | if (dev == 0) | 406 | if (dev == 0) |
407 | return InvalidDevice; | 407 | return InvalidDevice; |
408 | 408 | ||
409 | QMap<QString,ZipEntryP*>::Iterator itr = d->headers->find(filename); | 409 | QMap<QString,ZipEntryP*>::Iterator itr = d->headers->find(filename); |
410 | if (itr != d->headers->end()) { | 410 | if (itr != d->headers->end()) { |
411 | ZipEntryP* entry = itr.value(); | 411 | ZipEntryP* entry = itr.value(); |
412 | Q_ASSERT(entry != 0); | 412 | Q_ASSERT(entry != 0); |
413 | return d->extractFile(itr.key(), *entry, dev, options); | 413 | return d->extractFile(itr.key(), *entry, dev, options); |
414 | } | 414 | } |
415 | 415 | ||
416 | return FileNotFound; | 416 | return FileNotFound; |
417 | } | 417 | } |
418 | 418 | ||
419 | /*! | 419 | /*! |
420 | Extracts a list of files. | 420 | Extracts a list of files. |
421 | Stops extraction at the first error (but continues if a file does not exist in the archive). | 421 | Stops extraction at the first error (but continues if a file does not exist in the archive). |
422 | */ | 422 | */ |
423 | UnZip::ErrorCode UnZip::extractFiles(const QStringList& filenames, const QString& dirname, ExtractionOptions options) | 423 | UnZip::ErrorCode UnZip::extractFiles(const QStringList& filenames, const QString& dirname, ExtractionOptions options) |
424 | { | 424 | { |
425 | QDir dir(dirname); | 425 | QDir dir(dirname); |
426 | ErrorCode ec; | 426 | ErrorCode ec; |
427 | 427 | ||
428 | for (QStringList::ConstIterator itr = filenames.constBegin(); itr != filenames.constEnd(); ++itr) | 428 | for (QStringList::ConstIterator itr = filenames.constBegin(); itr != filenames.constEnd(); ++itr) |
429 | { | 429 | { |
430 | ec = extractFile(*itr, dir, options); | 430 | ec = extractFile(*itr, dir, options); |
431 | if (ec == FileNotFound) | 431 | if (ec == FileNotFound) |
432 | continue; | 432 | continue; |
433 | if (ec != Ok) | 433 | if (ec != Ok) |
434 | return ec; | 434 | return ec; |
435 | } | 435 | } |
436 | 436 | ||
437 | return Ok; | 437 | return Ok; |
438 | } | 438 | } |
439 | 439 | ||
440 | /*! | 440 | /*! |
441 | Extracts a list of files. | 441 | Extracts a list of files. |
442 | Stops extraction at the first error (but continues if a file does not exist in the archive). | 442 | Stops extraction at the first error (but continues if a file does not exist in the archive). |
443 | */ | 443 | */ |
444 | UnZip::ErrorCode UnZip::extractFiles(const QStringList& filenames, const QDir& dir, ExtractionOptions options) | 444 | UnZip::ErrorCode UnZip::extractFiles(const QStringList& filenames, const QDir& dir, ExtractionOptions options) |
445 | { | 445 | { |
446 | ErrorCode ec; | 446 | ErrorCode ec; |
447 | 447 | ||
448 | for (QStringList::ConstIterator itr = filenames.constBegin(); itr != filenames.constEnd(); ++itr) | 448 | for (QStringList::ConstIterator itr = filenames.constBegin(); itr != filenames.constEnd(); ++itr) |
449 | { | 449 | { |
450 | ec = extractFile(*itr, dir, options); | 450 | ec = extractFile(*itr, dir, options); |
451 | if (ec == FileNotFound) | 451 | if (ec == FileNotFound) |
452 | continue; | 452 | continue; |
453 | if (ec != Ok) | 453 | if (ec != Ok) |
454 | return ec; | 454 | return ec; |
455 | } | 455 | } |
456 | 456 | ||
457 | return Ok; | 457 | return Ok; |
458 | } | 458 | } |
459 | 459 | ||
460 | /*! | 460 | /*! |
461 | Remove/replace this method to add your own password retrieval routine. | 461 | Remove/replace this method to add your own password retrieval routine. |
462 | */ | 462 | */ |
463 | void UnZip::setPassword(const QString& pwd) | 463 | void UnZip::setPassword(const QString& pwd) |
464 | { | 464 | { |
465 | d->password = pwd; | 465 | d->password = pwd; |
466 | } | 466 | } |
467 | 467 | ||
468 | /*! | 468 | /*! |
469 | ZipEntry constructor - initialize data. Type is set to File. | 469 | ZipEntry constructor - initialize data. Type is set to File. |
470 | */ | 470 | */ |
471 | UnZip::ZipEntry::ZipEntry() | 471 | UnZip::ZipEntry::ZipEntry() |
472 | { | 472 | { |
473 | compressedSize = uncompressedSize = crc32 = 0; | 473 | compressedSize = uncompressedSize = crc32 = 0; |
474 | compression = NoCompression; | 474 | compression = NoCompression; |
475 | type = File; | 475 | type = File; |
476 | encrypted = false; | 476 | encrypted = false; |
477 | } | 477 | } |
478 | 478 | ||
479 | 479 | ||
480 | /************************************************************************ | 480 | /************************************************************************ |
481 | Private interface | 481 | Private interface |
482 | *************************************************************************/ | 482 | *************************************************************************/ |
483 | 483 | ||
484 | //! \internal | 484 | //! \internal |
485 | UnzipPrivate::UnzipPrivate() | 485 | UnzipPrivate::UnzipPrivate() |
486 | { | 486 | { |
487 | skipAllEncrypted = false; | 487 | skipAllEncrypted = false; |
488 | headers = 0; | 488 | headers = 0; |
489 | device = 0; | 489 | device = 0; |
490 | 490 | ||
491 | uBuffer = (unsigned char*) buffer1; | 491 | uBuffer = (unsigned char*) buffer1; |
492 | crcTable = (quint32*) get_crc_table(); | 492 | crcTable = (quint32*) get_crc_table(); |
493 | 493 | ||
494 | cdOffset = eocdOffset = 0; | 494 | cdOffset = eocdOffset = 0; |
495 | cdEntryCount = 0; | 495 | cdEntryCount = 0; |
496 | unsupportedEntryCount = 0; | 496 | unsupportedEntryCount = 0; |
497 | } | 497 | } |
498 | 498 | ||
499 | //! \internal Parses a Zip archive. | 499 | //! \internal Parses a Zip archive. |
500 | UnZip::ErrorCode UnzipPrivate::openArchive(QIODevice* dev) | 500 | UnZip::ErrorCode UnzipPrivate::openArchive(QIODevice* dev) |
501 | { | 501 | { |
502 | Q_ASSERT(dev != 0); | 502 | Q_ASSERT(dev != 0); |
503 | 503 | ||
504 | if (device != 0) | 504 | if (device != 0) |
505 | closeArchive(); | 505 | closeArchive(); |
506 | 506 | ||
507 | device = dev; | 507 | device = dev; |
508 | 508 | ||
509 | if (!(device->isOpen() || device->open(QIODevice::ReadOnly))) | 509 | if (!(device->isOpen() || device->open(QIODevice::ReadOnly))) |
510 | { | 510 | { |
511 | delete device; | 511 | delete device; |
512 | device = 0; | 512 | device = 0; |
513 | 513 | ||
514 | qDebug() << "Unable to open device for reading"; | 514 | qDebug() << "Unable to open device for reading"; |
515 | return UnZip::OpenFailed; | 515 | return UnZip::OpenFailed; |
516 | } | 516 | } |
517 | 517 | ||
518 | UnZip::ErrorCode ec; | 518 | UnZip::ErrorCode ec; |
519 | 519 | ||
520 | ec = seekToCentralDirectory(); | 520 | ec = seekToCentralDirectory(); |
521 | if (ec != UnZip::Ok) | 521 | if (ec != UnZip::Ok) |
522 | { | 522 | { |
523 | closeArchive(); | 523 | closeArchive(); |
524 | return ec; | 524 | return ec; |
525 | } | 525 | } |
526 | 526 | ||
527 | //! \todo Ignore CD entry count? CD may be corrupted. | 527 | //! \todo Ignore CD entry count? CD may be corrupted. |
528 | if (cdEntryCount == 0) | 528 | if (cdEntryCount == 0) |
529 | { | 529 | { |
530 | return UnZip::Ok; | 530 | return UnZip::Ok; |
531 | } | 531 | } |
532 | 532 | ||
533 | bool continueParsing = true; | 533 | bool continueParsing = true; |
534 | 534 | ||
535 | while (continueParsing) | 535 | while (continueParsing) |
536 | { | 536 | { |
537 | if (device->read(buffer1, 4) != 4) | 537 | if (device->read(buffer1, 4) != 4) |
538 | UNZIP_CHECK_FOR_VALID_DATA | 538 | UNZIP_CHECK_FOR_VALID_DATA |
539 | 539 | ||
540 | if (! (buffer1[0] == 'P' && buffer1[1] == 'K' && buffer1[2] == 0x01 && buffer1[3] == 0x02) ) | 540 | if (! (buffer1[0] == 'P' && buffer1[1] == 'K' && buffer1[2] == 0x01 && buffer1[3] == 0x02) ) |
541 | break; | 541 | break; |
542 | 542 | ||
543 | if ( (ec = parseCentralDirectoryRecord()) != UnZip::Ok ) | 543 | if ( (ec = parseCentralDirectoryRecord()) != UnZip::Ok ) |
544 | break; | 544 | break; |
545 | } | 545 | } |
546 | 546 | ||
547 | if (ec != UnZip::Ok) | 547 | if (ec != UnZip::Ok) |
548 | closeArchive(); | 548 | closeArchive(); |
549 | 549 | ||
550 | return ec; | 550 | return ec; |
551 | } | 551 | } |
552 | 552 | ||
553 | /* | 553 | /* |
554 | \internal Parses a local header record and makes some consistency check | 554 | \internal Parses a local header record and makes some consistency check |
555 | with the information stored in the Central Directory record for this entry | 555 | with the information stored in the Central Directory record for this entry |
556 | that has been previously parsed. | 556 | that has been previously parsed. |
557 | \todo Optional consistency check (as a ExtractionOptions flag) | 557 | \todo Optional consistency check (as a ExtractionOptions flag) |
558 | 558 | ||
559 | local file header signature 4 bytes (0x04034b50) | 559 | local file header signature 4 bytes (0x04034b50) |
560 | version needed to extract 2 bytes | 560 | version needed to extract 2 bytes |
561 | general purpose bit flag 2 bytes | 561 | general purpose bit flag 2 bytes |
562 | compression method 2 bytes | 562 | compression method 2 bytes |
563 | last mod file time 2 bytes | 563 | last mod file time 2 bytes |
564 | last mod file date 2 bytes | 564 | last mod file date 2 bytes |
565 | crc-32 4 bytes | 565 | crc-32 4 bytes |
566 | compressed size 4 bytes | 566 | compressed size 4 bytes |
567 | uncompressed size 4 bytes | 567 | uncompressed size 4 bytes |
568 | file name length 2 bytes | 568 | file name length 2 bytes |
569 | extra field length 2 bytes | 569 | extra field length 2 bytes |
570 | 570 | ||
571 | file name (variable size) | 571 | file name (variable size) |
572 | extra field (variable size) | 572 | extra field (variable size) |
573 | */ | 573 | */ |
574 | UnZip::ErrorCode UnzipPrivate::parseLocalHeaderRecord(const QString& path, ZipEntryP& entry) | 574 | UnZip::ErrorCode UnzipPrivate::parseLocalHeaderRecord(const QString& path, ZipEntryP& entry) |
575 | { | 575 | { |
576 | if (!device->seek(entry.lhOffset)) | 576 | if (!device->seek(entry.lhOffset)) |
577 | return UnZip::SeekFailed; | 577 | return UnZip::SeekFailed; |
578 | 578 | ||
579 | // Test signature | 579 | // Test signature |
580 | if (device->read(buffer1, 4) != 4) | 580 | if (device->read(buffer1, 4) != 4) |
581 | return UnZip::ReadFailed; | 581 | return UnZip::ReadFailed; |
582 | 582 | ||
583 | if ((buffer1[0] != 'P') || (buffer1[1] != 'K') || (buffer1[2] != 0x03) || (buffer1[3] != 0x04)) | 583 | if ((buffer1[0] != 'P') || (buffer1[1] != 'K') || (buffer1[2] != 0x03) || (buffer1[3] != 0x04)) |
584 | return UnZip::InvalidArchive; | 584 | return UnZip::InvalidArchive; |
585 | 585 | ||
586 | if (device->read(buffer1, UNZIP_LOCAL_HEADER_SIZE) != UNZIP_LOCAL_HEADER_SIZE) | 586 | if (device->read(buffer1, UNZIP_LOCAL_HEADER_SIZE) != UNZIP_LOCAL_HEADER_SIZE) |
587 | return UnZip::ReadFailed; | 587 | return UnZip::ReadFailed; |
588 | 588 | ||
589 | /* | 589 | /* |
590 | Check 3rd general purpose bit flag. | 590 | Check 3rd general purpose bit flag. |
591 | 591 | ||
592 | "bit 3: If this bit is set, the fields crc-32, compressed size | 592 | "bit 3: If this bit is set, the fields crc-32, compressed size |
593 | and uncompressed size are set to zero in the local | 593 | and uncompressed size are set to zero in the local |
594 | header. The correct values are put in the data descriptor | 594 | header. The correct values are put in the data descriptor |
595 | immediately following the compressed data." | 595 | immediately following the compressed data." |
596 | */ | 596 | */ |
597 | bool hasDataDescriptor = entry.hasDataDescriptor(); | 597 | bool hasDataDescriptor = entry.hasDataDescriptor(); |
598 | 598 | ||
599 | bool checkFailed = false; | 599 | bool checkFailed = false; |
600 | 600 | ||
601 | if (!checkFailed) | 601 | if (!checkFailed) |
602 | checkFailed = entry.compMethod != getUShort(uBuffer, UNZIP_LH_OFF_CMETHOD); | 602 | checkFailed = entry.compMethod != getUShort(uBuffer, UNZIP_LH_OFF_CMETHOD); |
603 | if (!checkFailed) | 603 | if (!checkFailed) |
604 | checkFailed = entry.gpFlag[0] != uBuffer[UNZIP_LH_OFF_GPFLAG]; | 604 | checkFailed = entry.gpFlag[0] != uBuffer[UNZIP_LH_OFF_GPFLAG]; |
605 | if (!checkFailed) | 605 | if (!checkFailed) |
606 | checkFailed = entry.gpFlag[1] != uBuffer[UNZIP_LH_OFF_GPFLAG + 1]; | 606 | checkFailed = entry.gpFlag[1] != uBuffer[UNZIP_LH_OFF_GPFLAG + 1]; |
607 | if (!checkFailed) | 607 | if (!checkFailed) |
608 | checkFailed = entry.modTime[0] != uBuffer[UNZIP_LH_OFF_MODT]; | 608 | checkFailed = entry.modTime[0] != uBuffer[UNZIP_LH_OFF_MODT]; |
609 | if (!checkFailed) | 609 | if (!checkFailed) |
610 | checkFailed = entry.modTime[1] != uBuffer[UNZIP_LH_OFF_MODT + 1]; | 610 | checkFailed = entry.modTime[1] != uBuffer[UNZIP_LH_OFF_MODT + 1]; |
611 | if (!checkFailed) | 611 | if (!checkFailed) |
612 | checkFailed = entry.modDate[0] != uBuffer[UNZIP_LH_OFF_MODD]; | 612 | checkFailed = entry.modDate[0] != uBuffer[UNZIP_LH_OFF_MODD]; |
613 | if (!checkFailed) | 613 | if (!checkFailed) |
614 | checkFailed = entry.modDate[1] != uBuffer[UNZIP_LH_OFF_MODD + 1]; | 614 | checkFailed = entry.modDate[1] != uBuffer[UNZIP_LH_OFF_MODD + 1]; |
615 | if (!hasDataDescriptor) | 615 | if (!hasDataDescriptor) |
616 | { | 616 | { |
617 | if (!checkFailed) | 617 | if (!checkFailed) |
618 | checkFailed = entry.crc != getULong(uBuffer, UNZIP_LH_OFF_CRC32); | 618 | checkFailed = entry.crc != getULong(uBuffer, UNZIP_LH_OFF_CRC32); |
619 | if (!checkFailed) | 619 | if (!checkFailed) |
620 | checkFailed = entry.szComp != getULong(uBuffer, UNZIP_LH_OFF_CSIZE); | 620 | checkFailed = entry.szComp != getULong(uBuffer, UNZIP_LH_OFF_CSIZE); |
621 | if (!checkFailed) | 621 | if (!checkFailed) |
622 | checkFailed = entry.szUncomp != getULong(uBuffer, UNZIP_LH_OFF_USIZE); | 622 | checkFailed = entry.szUncomp != getULong(uBuffer, UNZIP_LH_OFF_USIZE); |
623 | } | 623 | } |
624 | 624 | ||
625 | if (checkFailed) | 625 | if (checkFailed) |
626 | return UnZip::HeaderConsistencyError; | 626 | return UnZip::HeaderConsistencyError; |
627 | 627 | ||
628 | // Check filename | 628 | // Check filename |
629 | quint16 szName = getUShort(uBuffer, UNZIP_LH_OFF_NAMELEN); | 629 | quint16 szName = getUShort(uBuffer, UNZIP_LH_OFF_NAMELEN); |
630 | if (szName == 0) | 630 | if (szName == 0) |
631 | return UnZip::HeaderConsistencyError; | 631 | return UnZip::HeaderConsistencyError; |
632 | 632 | ||
633 | if (device->read(buffer2, szName) != szName) | 633 | if (device->read(buffer2, szName) != szName) |
634 | return UnZip::ReadFailed; | 634 | return UnZip::ReadFailed; |
635 | 635 | ||
636 | QString filename = QString::fromAscii(buffer2, szName); | 636 | QString filename = QString::fromAscii(buffer2, szName); |
637 | if (filename != path) | 637 | if (filename != path) |
638 | { | 638 | { |
639 | qDebug() << "Filename in local header mismatches."; | 639 | qDebug() << "Filename in local header mismatches."; |
640 | return UnZip::HeaderConsistencyError; | 640 | return UnZip::HeaderConsistencyError; |
641 | } | 641 | } |
642 | 642 | ||
643 | // Skip extra field | 643 | // Skip extra field |
644 | quint16 szExtra = getUShort(uBuffer, UNZIP_LH_OFF_XLEN); | 644 | quint16 szExtra = getUShort(uBuffer, UNZIP_LH_OFF_XLEN); |
645 | if (szExtra != 0) | 645 | if (szExtra != 0) |
646 | { | 646 | { |
647 | if (!device->seek(device->pos() + szExtra)) | 647 | if (!device->seek(device->pos() + szExtra)) |
648 | return UnZip::SeekFailed; | 648 | return UnZip::SeekFailed; |
649 | } | 649 | } |
650 | 650 | ||
651 | entry.dataOffset = device->pos(); | 651 | entry.dataOffset = device->pos(); |
652 | 652 | ||
653 | if (hasDataDescriptor) | 653 | if (hasDataDescriptor) |
654 | { | 654 | { |
655 | /* | 655 | /* |
656 | The data descriptor has this OPTIONAL signature: PK\7\8 | 656 | The data descriptor has this OPTIONAL signature: PK\7\8 |
657 | We try to skip the compressed data relying on the size set in the | 657 | We try to skip the compressed data relying on the size set in the |
658 | Central Directory record. | 658 | Central Directory record. |
659 | */ | 659 | */ |
660 | if (!device->seek(device->pos() + entry.szComp)) | 660 | if (!device->seek(device->pos() + entry.szComp)) |
661 | return UnZip::SeekFailed; | 661 | return UnZip::SeekFailed; |
662 | 662 | ||
663 | // Read 4 bytes and check if there is a data descriptor signature | 663 | // Read 4 bytes and check if there is a data descriptor signature |
664 | if (device->read(buffer2, 4) != 4) | 664 | if (device->read(buffer2, 4) != 4) |
665 | return UnZip::ReadFailed; | 665 | return UnZip::ReadFailed; |
666 | 666 | ||
667 | bool hasSignature = buffer2[0] == 'P' && buffer2[1] == 'K' && buffer2[2] == 0x07 && buffer2[3] == 0x08; | 667 | bool hasSignature = buffer2[0] == 'P' && buffer2[1] == 'K' && buffer2[2] == 0x07 && buffer2[3] == 0x08; |
668 | if (hasSignature) | 668 | if (hasSignature) |
669 | { | 669 | { |
670 | if (device->read(buffer2, UNZIP_DD_SIZE) != UNZIP_DD_SIZE) | 670 | if (device->read(buffer2, UNZIP_DD_SIZE) != UNZIP_DD_SIZE) |
671 | return UnZip::ReadFailed; | 671 | return UnZip::ReadFailed; |
672 | } | 672 | } |
673 | else | 673 | else |
674 | { | 674 | { |
675 | if (device->read(buffer2 + 4, UNZIP_DD_SIZE - 4) != UNZIP_DD_SIZE - 4) | 675 | if (device->read(buffer2 + 4, UNZIP_DD_SIZE - 4) != UNZIP_DD_SIZE - 4) |
676 | return UnZip::ReadFailed; | 676 | return UnZip::ReadFailed; |
677 | } | 677 | } |
678 | 678 | ||
679 | // DD: crc, compressed size, uncompressed size | 679 | // DD: crc, compressed size, uncompressed size |
680 | if ( | 680 | if ( |
681 | entry.crc != getULong((unsigned char*)buffer2, UNZIP_DD_OFF_CRC32) || | 681 | entry.crc != getULong((unsigned char*)buffer2, UNZIP_DD_OFF_CRC32) || |
682 | entry.szComp != getULong((unsigned char*)buffer2, UNZIP_DD_OFF_CSIZE) || | 682 | entry.szComp != getULong((unsigned char*)buffer2, UNZIP_DD_OFF_CSIZE) || |
683 | entry.szUncomp != getULong((unsigned char*)buffer2, UNZIP_DD_OFF_USIZE) | 683 | entry.szUncomp != getULong((unsigned char*)buffer2, UNZIP_DD_OFF_USIZE) |
684 | ) | 684 | ) |
685 | return UnZip::HeaderConsistencyError; | 685 | return UnZip::HeaderConsistencyError; |
686 | } | 686 | } |
687 | 687 | ||
688 | return UnZip::Ok; | 688 | return UnZip::Ok; |
689 | } | 689 | } |
690 | 690 | ||
691 | /*! \internal Attempts to find the start of the central directory record. | 691 | /*! \internal Attempts to find the start of the central directory record. |
692 | 692 | ||
693 | We seek the file back until we reach the "End Of Central Directory" | 693 | We seek the file back until we reach the "End Of Central Directory" |
694 | signature PK\5\6. | 694 | signature PK\5\6. |
695 | 695 | ||
696 | end of central dir signature 4 bytes (0x06054b50) | 696 | end of central dir signature 4 bytes (0x06054b50) |
697 | number of this disk 2 bytes | 697 | number of this disk 2 bytes |
698 | number of the disk with the | 698 | number of the disk with the |
699 | start of the central directory 2 bytes | 699 | start of the central directory 2 bytes |
700 | total number of entries in the | 700 | total number of entries in the |
701 | central directory on this disk 2 bytes | 701 | central directory on this disk 2 bytes |
702 | total number of entries in | 702 | total number of entries in |
703 | the central directory 2 bytes | 703 | the central directory 2 bytes |
704 | size of the central directory 4 bytes | 704 | size of the central directory 4 bytes |
705 | offset of start of central | 705 | offset of start of central |
706 | directory with respect to | 706 | directory with respect to |
707 | the starting disk number 4 bytes | 707 | the starting disk number 4 bytes |
708 | .ZIP file comment length 2 bytes | 708 | .ZIP file comment length 2 bytes |
709 | --- SIZE UNTIL HERE: UNZIP_EOCD_SIZE --- | 709 | --- SIZE UNTIL HERE: UNZIP_EOCD_SIZE --- |
710 | .ZIP file comment (variable size) | 710 | .ZIP file comment (variable size) |
711 | */ | 711 | */ |
712 | UnZip::ErrorCode UnzipPrivate::seekToCentralDirectory() | 712 | UnZip::ErrorCode UnzipPrivate::seekToCentralDirectory() |
713 | { | 713 | { |
714 | qint64 length = device->size(); | 714 | qint64 length = device->size(); |
715 | qint64 offset = length - UNZIP_EOCD_SIZE; | 715 | qint64 offset = length - UNZIP_EOCD_SIZE; |
716 | 716 | ||
717 | if (length < UNZIP_EOCD_SIZE) | 717 | if (length < UNZIP_EOCD_SIZE) |
718 | return UnZip::InvalidArchive; | 718 | return UnZip::InvalidArchive; |
719 | 719 | ||
720 | if (!device->seek( offset )) | 720 | if (!device->seek( offset )) |
721 | return UnZip::SeekFailed; | 721 | return UnZip::SeekFailed; |
722 | 722 | ||
723 | if (device->read(buffer1, UNZIP_EOCD_SIZE) != UNZIP_EOCD_SIZE) | 723 | if (device->read(buffer1, UNZIP_EOCD_SIZE) != UNZIP_EOCD_SIZE) |
724 | return UnZip::ReadFailed; | 724 | return UnZip::ReadFailed; |
725 | 725 | ||
726 | bool eocdFound = (buffer1[0] == 'P' && buffer1[1] == 'K' && buffer1[2] == 0x05 && buffer1[3] == 0x06); | 726 | bool eocdFound = (buffer1[0] == 'P' && buffer1[1] == 'K' && buffer1[2] == 0x05 && buffer1[3] == 0x06); |
727 | 727 | ||
728 | if (eocdFound) | 728 | if (eocdFound) |
729 | { | 729 | { |
730 | // Zip file has no comment (the only variable length field in the EOCD record) | 730 | // Zip file has no comment (the only variable length field in the EOCD record) |
731 | eocdOffset = offset; | 731 | eocdOffset = offset; |
732 | } | 732 | } |
733 | else | 733 | else |
734 | { | 734 | { |
735 | qint64 read; | 735 | qint64 read; |
736 | char* p = 0; | 736 | char* p = 0; |
737 | 737 | ||
738 | offset -= UNZIP_EOCD_SIZE; | 738 | offset -= UNZIP_EOCD_SIZE; |
739 | 739 | ||
740 | if (offset <= 0) | 740 | if (offset <= 0) |
741 | return UnZip::InvalidArchive; | 741 | return UnZip::InvalidArchive; |
742 | 742 | ||
743 | if (!device->seek( offset )) | 743 | if (!device->seek( offset )) |
744 | return UnZip::SeekFailed; | 744 | return UnZip::SeekFailed; |
745 | 745 | ||
746 | while ((read = device->read(buffer1, UNZIP_EOCD_SIZE)) >= 0) | 746 | while ((read = device->read(buffer1, UNZIP_EOCD_SIZE)) >= 0) |
747 | { | 747 | { |
748 | if ( (p = strstr(buffer1, "PK\5\6")) != 0) | 748 | if ( (p = strstr(buffer1, "PK\5\6")) != 0) |
749 | { | 749 | { |
750 | // Seek to the start of the EOCD record so we can read it fully | 750 | // Seek to the start of the EOCD record so we can read it fully |
751 | // Yes... we could simply read the missing bytes and append them to the buffer | 751 | // Yes... we could simply read the missing bytes and append them to the buffer |
752 | // but this is far easier so heck it! | 752 | // but this is far easier so heck it! |
753 | device->seek( offset + (p - buffer1) ); | 753 | device->seek( offset + (p - buffer1) ); |
754 | eocdFound = true; | 754 | eocdFound = true; |
755 | eocdOffset = offset + (p - buffer1); | 755 | eocdOffset = offset + (p - buffer1); |
756 | 756 | ||
757 | // Read EOCD record | 757 | // Read EOCD record |
758 | if (device->read(buffer1, UNZIP_EOCD_SIZE) != UNZIP_EOCD_SIZE) | 758 | if (device->read(buffer1, UNZIP_EOCD_SIZE) != UNZIP_EOCD_SIZE) |
759 | return UnZip::ReadFailed; | 759 | return UnZip::ReadFailed; |
760 | 760 | ||
761 | break; | 761 | break; |
762 | } | 762 | } |
763 | 763 | ||
764 | offset -= UNZIP_EOCD_SIZE; | 764 | offset -= UNZIP_EOCD_SIZE; |
765 | if (offset <= 0) | 765 | if (offset <= 0) |
766 | return UnZip::InvalidArchive; | 766 | return UnZip::InvalidArchive; |
767 | 767 | ||
768 | if (!device->seek( offset )) | 768 | if (!device->seek( offset )) |
769 | return UnZip::SeekFailed; | 769 | return UnZip::SeekFailed; |
770 | } | 770 | } |
771 | } | 771 | } |
772 | 772 | ||
773 | if (!eocdFound) | 773 | if (!eocdFound) |
774 | return UnZip::InvalidArchive; | 774 | return UnZip::InvalidArchive; |
775 | 775 | ||
776 | // Parse EOCD to locate CD offset | 776 | // Parse EOCD to locate CD offset |
777 | offset = getULong((const unsigned char*)buffer1, UNZIP_EOCD_OFF_CDOFF + 4); | 777 | offset = getULong((const unsigned char*)buffer1, UNZIP_EOCD_OFF_CDOFF + 4); |
778 | 778 | ||
779 | cdOffset = offset; | 779 | cdOffset = offset; |
780 | 780 | ||
781 | cdEntryCount = getUShort((const unsigned char*)buffer1, UNZIP_EOCD_OFF_ENTRIES + 4); | 781 | cdEntryCount = getUShort((const unsigned char*)buffer1, UNZIP_EOCD_OFF_ENTRIES + 4); |
782 | 782 | ||
783 | quint16 commentLength = getUShort((const unsigned char*)buffer1, UNZIP_EOCD_OFF_COMMLEN + 4); | 783 | quint16 commentLength = getUShort((const unsigned char*)buffer1, UNZIP_EOCD_OFF_COMMLEN + 4); |
784 | if (commentLength != 0) | 784 | if (commentLength != 0) |
785 | { | 785 | { |
786 | QByteArray c = device->read(commentLength); | 786 | QByteArray c = device->read(commentLength); |
787 | if (c.count() != commentLength) | 787 | if (c.count() != commentLength) |
788 | return UnZip::ReadFailed; | 788 | return UnZip::ReadFailed; |
789 | 789 | ||
790 | comment = c; | 790 | comment = c; |
791 | } | 791 | } |
792 | 792 | ||
793 | // Seek to the start of the CD record | 793 | // Seek to the start of the CD record |
794 | if (!device->seek( cdOffset )) | 794 | if (!device->seek( cdOffset )) |
795 | return UnZip::SeekFailed; | 795 | return UnZip::SeekFailed; |
796 | 796 | ||
797 | return UnZip::Ok; | 797 | return UnZip::Ok; |
798 | } | 798 | } |
799 | 799 | ||
800 | /*! | 800 | /*! |
801 | \internal Parses a central directory record. | 801 | \internal Parses a central directory record. |
802 | 802 | ||
803 | Central Directory record structure: | 803 | Central Directory record structure: |
804 | 804 | ||
805 | [file header 1] | 805 | [file header 1] |
806 | . | 806 | . |
807 | . | 807 | . |
808 | . | 808 | . |
809 | [file header n] | 809 | [file header n] |
810 | [digital signature] // PKZip 6.2 or later only | 810 | [digital signature] // PKZip 6.2 or later only |
811 | 811 | ||
812 | File header: | 812 | File header: |
813 | 813 | ||
814 | central file header signature 4 bytes (0x02014b50) | 814 | central file header signature 4 bytes (0x02014b50) |
815 | version made by 2 bytes | 815 | version made by 2 bytes |
816 | version needed to extract 2 bytes | 816 | version needed to extract 2 bytes |
817 | general purpose bit flag 2 bytes | 817 | general purpose bit flag 2 bytes |
818 | compression method 2 bytes | 818 | compression method 2 bytes |
819 | last mod file time 2 bytes | 819 | last mod file time 2 bytes |
820 | last mod file date 2 bytes | 820 | last mod file date 2 bytes |
821 | crc-32 4 bytes | 821 | crc-32 4 bytes |
822 | compressed size 4 bytes | 822 | compressed size 4 bytes |
823 | uncompressed size 4 bytes | 823 | uncompressed size 4 bytes |
824 | file name length 2 bytes | 824 | file name length 2 bytes |
825 | extra field length 2 bytes | 825 | extra field length 2 bytes |
826 | file comment length 2 bytes | 826 | file comment length 2 bytes |
827 | disk number start 2 bytes | 827 | disk number start 2 bytes |
828 | internal file attributes 2 bytes | 828 | internal file attributes 2 bytes |
829 | external file attributes 4 bytes | 829 | external file attributes 4 bytes |
830 | relative offset of local header 4 bytes | 830 | relative offset of local header 4 bytes |
831 | 831 | ||
832 | file name (variable size) | 832 | file name (variable size) |
833 | extra field (variable size) | 833 | extra field (variable size) |
834 | file comment (variable size) | 834 | file comment (variable size) |
835 | */ | 835 | */ |
836 | UnZip::ErrorCode UnzipPrivate::parseCentralDirectoryRecord() | 836 | UnZip::ErrorCode UnzipPrivate::parseCentralDirectoryRecord() |
837 | { | 837 | { |
838 | // Read CD record | 838 | // Read CD record |
839 | if (device->read(buffer1, UNZIP_CD_ENTRY_SIZE_NS) != UNZIP_CD_ENTRY_SIZE_NS) | 839 | if (device->read(buffer1, UNZIP_CD_ENTRY_SIZE_NS) != UNZIP_CD_ENTRY_SIZE_NS) |
840 | return UnZip::ReadFailed; | 840 | return UnZip::ReadFailed; |
841 | 841 | ||
842 | bool skipEntry = false; | 842 | bool skipEntry = false; |
843 | 843 | ||
844 | // Get compression type so we can skip non compatible algorithms | 844 | // Get compression type so we can skip non compatible algorithms |
845 | quint16 compMethod = getUShort(uBuffer, UNZIP_CD_OFF_CMETHOD); | 845 | quint16 compMethod = getUShort(uBuffer, UNZIP_CD_OFF_CMETHOD); |
846 | 846 | ||
847 | // Get variable size fields length so we can skip the whole record | 847 | // Get variable size fields length so we can skip the whole record |
848 | // if necessary | 848 | // if necessary |
849 | quint16 szName = getUShort(uBuffer, UNZIP_CD_OFF_NAMELEN); | 849 | quint16 szName = getUShort(uBuffer, UNZIP_CD_OFF_NAMELEN); |
850 | quint16 szExtra = getUShort(uBuffer, UNZIP_CD_OFF_XLEN); | 850 | quint16 szExtra = getUShort(uBuffer, UNZIP_CD_OFF_XLEN); |
851 | quint16 szComment = getUShort(uBuffer, UNZIP_CD_OFF_COMMLEN); | 851 | quint16 szComment = getUShort(uBuffer, UNZIP_CD_OFF_COMMLEN); |
852 | 852 | ||
853 | quint32 skipLength = szName + szExtra + szComment; | 853 | quint32 skipLength = szName + szExtra + szComment; |
854 | 854 | ||
855 | UnZip::ErrorCode ec = UnZip::Ok; | 855 | UnZip::ErrorCode ec = UnZip::Ok; |
856 | 856 | ||
857 | if ((compMethod != 0) && (compMethod != 8)) | 857 | if ((compMethod != 0) && (compMethod != 8)) |
858 | { | 858 | { |
859 | qDebug() << "Unsupported compression method. Skipping file."; | 859 | qDebug() << "Unsupported compression method. Skipping file."; |
860 | skipEntry = true; | 860 | skipEntry = true; |
861 | } | 861 | } |
862 | 862 | ||
863 | // Header parsing may be a problem if version is bigger than UNZIP_VERSION | 863 | // Header parsing may be a problem if version is bigger than UNZIP_VERSION |
864 | if (!skipEntry && buffer1[UNZIP_CD_OFF_VERSION] > UNZIP_VERSION) | 864 | if (!skipEntry && buffer1[UNZIP_CD_OFF_VERSION] > UNZIP_VERSION) |
865 | { | 865 | { |
866 | qDebug() << "Unsupported PKZip version. Skipping file."; | 866 | qDebug() << "Unsupported PKZip version. Skipping file."; |
867 | skipEntry = true; | 867 | skipEntry = true; |
868 | } | 868 | } |
869 | 869 | ||
870 | if (!skipEntry && szName == 0) | 870 | if (!skipEntry && szName == 0) |
871 | { | 871 | { |
872 | qDebug() << "Skipping file with no name."; | 872 | qDebug() << "Skipping file with no name."; |
873 | skipEntry = true; | 873 | skipEntry = true; |
874 | } | 874 | } |
875 | 875 | ||
876 | if (!skipEntry && device->read(buffer2, szName) != szName) | 876 | if (!skipEntry && device->read(buffer2, szName) != szName) |
877 | { | 877 | { |
878 | ec = UnZip::ReadFailed; | 878 | ec = UnZip::ReadFailed; |
879 | skipEntry = true; | 879 | skipEntry = true; |
880 | } | 880 | } |
881 | 881 | ||
882 | if (skipEntry) | 882 | if (skipEntry) |
883 | { | 883 | { |
884 | if (ec == UnZip::Ok) | 884 | if (ec == UnZip::Ok) |
885 | { | 885 | { |
886 | if (!device->seek( device->pos() + skipLength )) | 886 | if (!device->seek( device->pos() + skipLength )) |
887 | ec = UnZip::SeekFailed; | 887 | ec = UnZip::SeekFailed; |
888 | 888 | ||
889 | unsupportedEntryCount++; | 889 | unsupportedEntryCount++; |
890 | } | 890 | } |
891 | 891 | ||
892 | return ec; | 892 | return ec; |
893 | } | 893 | } |
894 | 894 | ||
895 | QString filename = QString::fromAscii(buffer2, szName); | 895 | QString filename = QString::fromAscii(buffer2, szName); |
896 | 896 | ||
897 | ZipEntryP* h = new ZipEntryP; | 897 | ZipEntryP* h = new ZipEntryP; |
898 | h->compMethod = compMethod; | 898 | h->compMethod = compMethod; |
899 | 899 | ||
900 | h->gpFlag[0] = buffer1[UNZIP_CD_OFF_GPFLAG]; | 900 | h->gpFlag[0] = buffer1[UNZIP_CD_OFF_GPFLAG]; |
901 | h->gpFlag[1] = buffer1[UNZIP_CD_OFF_GPFLAG + 1]; | 901 | h->gpFlag[1] = buffer1[UNZIP_CD_OFF_GPFLAG + 1]; |
902 | 902 | ||
903 | h->modTime[0] = buffer1[UNZIP_CD_OFF_MODT]; | 903 | h->modTime[0] = buffer1[UNZIP_CD_OFF_MODT]; |
904 | h->modTime[1] = buffer1[UNZIP_CD_OFF_MODT + 1]; | 904 | h->modTime[1] = buffer1[UNZIP_CD_OFF_MODT + 1]; |
905 | 905 | ||
906 | h->modDate[0] = buffer1[UNZIP_CD_OFF_MODD]; | 906 | h->modDate[0] = buffer1[UNZIP_CD_OFF_MODD]; |
907 | h->modDate[1] = buffer1[UNZIP_CD_OFF_MODD + 1]; | 907 | h->modDate[1] = buffer1[UNZIP_CD_OFF_MODD + 1]; |
908 | 908 | ||
909 | h->crc = getULong(uBuffer, UNZIP_CD_OFF_CRC32); | 909 | h->crc = getULong(uBuffer, UNZIP_CD_OFF_CRC32); |
910 | h->szComp = getULong(uBuffer, UNZIP_CD_OFF_CSIZE); | 910 | h->szComp = getULong(uBuffer, UNZIP_CD_OFF_CSIZE); |
911 | h->szUncomp = getULong(uBuffer, UNZIP_CD_OFF_USIZE); | 911 | h->szUncomp = getULong(uBuffer, UNZIP_CD_OFF_USIZE); |
912 | 912 | ||
913 | // Skip extra field (if any) | 913 | // Skip extra field (if any) |
914 | if (szExtra != 0) | 914 | if (szExtra != 0) |
915 | { | 915 | { |
916 | if (!device->seek( device->pos() + szExtra )) | 916 | if (!device->seek( device->pos() + szExtra )) |
917 | { | 917 | { |
918 | delete h; | 918 | delete h; |
919 | return UnZip::SeekFailed; | 919 | return UnZip::SeekFailed; |
920 | } | 920 | } |
921 | } | 921 | } |
922 | 922 | ||
923 | // Read comment field (if any) | 923 | // Read comment field (if any) |
924 | if (szComment != 0) | 924 | if (szComment != 0) |
925 | { | 925 | { |
926 | if (device->read(buffer2, szComment) != szComment) | 926 | if (device->read(buffer2, szComment) != szComment) |
927 | { | 927 | { |
928 | delete h; | 928 | delete h; |
929 | return UnZip::ReadFailed; | 929 | return UnZip::ReadFailed; |
930 | } | 930 | } |
931 | 931 | ||
932 | h->comment = QString::fromAscii(buffer2, szComment); | 932 | h->comment = QString::fromAscii(buffer2, szComment); |
933 | } | 933 | } |
934 | 934 | ||
935 | h->lhOffset = getULong(uBuffer, UNZIP_CD_OFF_LHOFFSET); | 935 | h->lhOffset = getULong(uBuffer, UNZIP_CD_OFF_LHOFFSET); |
936 | 936 | ||
937 | if (headers == 0) | 937 | if (headers == 0) |
938 | headers = new QMap<QString, ZipEntryP*>(); | 938 | headers = new QMap<QString, ZipEntryP*>(); |
939 | headers->insert(filename, h); | 939 | headers->insert(filename, h); |
940 | 940 | ||
941 | return UnZip::Ok; | 941 | return UnZip::Ok; |
942 | } | 942 | } |
943 | 943 | ||
944 | //! \internal Closes the archive and resets the internal status. | 944 | //! \internal Closes the archive and resets the internal status. |
945 | void UnzipPrivate::closeArchive() | 945 | void UnzipPrivate::closeArchive() |
946 | { | 946 | { |
947 | if (device == 0) | 947 | if (device == 0) |
948 | return; | 948 | return; |
949 | 949 | ||
950 | skipAllEncrypted = false; | 950 | skipAllEncrypted = false; |
951 | 951 | ||
952 | if (headers != 0) | 952 | if (headers != 0) |
953 | { | 953 | { |
954 | qDeleteAll(*headers); | 954 | qDeleteAll(*headers); |
955 | delete headers; | 955 | delete headers; |
956 | headers = 0; | 956 | headers = 0; |
957 | } | 957 | } |
958 | 958 | ||
959 | delete device; device = 0; | 959 | delete device; device = 0; |
960 | 960 | ||
961 | cdOffset = eocdOffset = 0; | 961 | cdOffset = eocdOffset = 0; |
962 | cdEntryCount = 0; | 962 | cdEntryCount = 0; |
963 | unsupportedEntryCount = 0; | 963 | unsupportedEntryCount = 0; |
964 | 964 | ||
965 | comment.clear(); | 965 | comment.clear(); |
966 | } | 966 | } |
967 | 967 | ||
968 | //! \internal | 968 | //! \internal |
969 | UnZip::ErrorCode UnzipPrivate::extractFile(const QString& path, ZipEntryP& entry, const QDir& dir, UnZip::ExtractionOptions options) | 969 | UnZip::ErrorCode UnzipPrivate::extractFile(const QString& path, ZipEntryP& entry, const QDir& dir, UnZip::ExtractionOptions options) |
970 | { | 970 | { |
971 | QString name(path); | 971 | QString name(path); |
972 | QString dirname; | 972 | QString dirname; |
973 | QString directory; | 973 | QString directory; |
974 | 974 | ||
975 | int pos = name.lastIndexOf('/'); | 975 | int pos = name.lastIndexOf('/'); |
976 | 976 | ||
977 | // This entry is for a directory | 977 | // This entry is for a directory |
978 | if (pos == name.length() - 1) | 978 | if (pos == name.length() - 1) |
979 | { | 979 | { |
980 | if (options.testFlag(UnZip::SkipPaths)) | 980 | if (options.testFlag(UnZip::SkipPaths)) |
981 | return UnZip::Ok; | 981 | return UnZip::Ok; |
982 | 982 | ||
983 | directory = QString("%1/%2").arg(dir.absolutePath()).arg(QDir::cleanPath(name)); | 983 | directory = QString("%1/%2").arg(dir.absolutePath()).arg(QDir::cleanPath(name)); |
984 | if (!createDirectory(directory)) | 984 | if (!createDirectory(directory)) |
985 | { | 985 | { |
986 | qDebug() << QString("Unable to create directory: %1").arg(directory); | 986 | qDebug() << QString("Unable to create directory: %1").arg(directory); |
987 | return UnZip::CreateDirFailed; | 987 | return UnZip::CreateDirFailed; |
988 | } | 988 | } |
989 | 989 | ||
990 | return UnZip::Ok; | 990 | return UnZip::Ok; |
991 | } | 991 | } |
992 | 992 | ||
993 | // Extract path from entry | 993 | // Extract path from entry |
994 | if (pos > 0) | 994 | if (pos > 0) |
995 | { | 995 | { |
996 | // get directory part | 996 | // get directory part |
997 | dirname = name.left(pos); | 997 | dirname = name.left(pos); |
998 | if (options.testFlag(UnZip::SkipPaths)) | 998 | if (options.testFlag(UnZip::SkipPaths)) |
999 | { | 999 | { |
1000 | directory = dir.absolutePath(); | 1000 | directory = dir.absolutePath(); |
1001 | } | 1001 | } |
1002 | else | 1002 | else |
1003 | { | 1003 | { |
1004 | directory = QString("%1/%2").arg(dir.absolutePath()).arg(QDir::cleanPath(dirname)); | 1004 | directory = QString("%1/%2").arg(dir.absolutePath()).arg(QDir::cleanPath(dirname)); |
1005 | if (!createDirectory(directory)) | 1005 | if (!createDirectory(directory)) |
1006 | { | 1006 | { |
1007 | qDebug() << QString("Unable to create directory: %1").arg(directory); | 1007 | qDebug() << QString("Unable to create directory: %1").arg(directory); |
1008 | return UnZip::CreateDirFailed; | 1008 | return UnZip::CreateDirFailed; |
1009 | } | 1009 | } |
1010 | } | 1010 | } |
1011 | name = name.right(name.length() - pos - 1); | 1011 | name = name.right(name.length() - pos - 1); |
1012 | } else directory = dir.absolutePath(); | 1012 | } else directory = dir.absolutePath(); |
1013 | 1013 | ||
1014 | name = QString("%1/%2").arg(directory).arg(name); | 1014 | name = QString("%1/%2").arg(directory).arg(name); |
1015 | 1015 | ||
1016 | QFile outFile(name); | 1016 | QFile outFile(name); |
1017 | 1017 | ||
1018 | if (!outFile.open(QIODevice::WriteOnly)) | 1018 | if (!outFile.open(QIODevice::WriteOnly)) |
1019 | { | 1019 | { |
1020 | qDebug() << QString("Unable to open %1 for writing").arg(name); | 1020 | qDebug() << QString("Unable to open %1 for writing").arg(name); |
1021 | return UnZip::OpenFailed; | 1021 | return UnZip::OpenFailed; |
1022 | } | 1022 | } |
1023 | 1023 | ||
1024 | //! \todo Set creation/last_modified date/time | 1024 | //! \todo Set creation/last_modified date/time |
1025 | 1025 | ||
1026 | UnZip::ErrorCode ec = extractFile(path, entry, &outFile, options); | 1026 | UnZip::ErrorCode ec = extractFile(path, entry, &outFile, options); |
1027 | 1027 | ||
1028 | outFile.close(); | 1028 | outFile.close(); |
1029 | 1029 | ||
1030 | if (ec != UnZip::Ok) | 1030 | if (ec != UnZip::Ok) |
1031 | { | 1031 | { |
1032 | if (!outFile.remove()) | 1032 | if (!outFile.remove()) |
1033 | qDebug() << QString("Unable to remove corrupted file: %1").arg(name); | 1033 | qDebug() << QString("Unable to remove corrupted file: %1").arg(name); |
1034 | } | 1034 | } |
1035 | 1035 | ||
1036 | return ec; | 1036 | return ec; |
1037 | } | 1037 | } |
1038 | 1038 | ||
1039 | //! \internal | 1039 | //! \internal |
1040 | UnZip::ErrorCode UnzipPrivate::extractFile(const QString& path, ZipEntryP& entry, QIODevice* dev, UnZip::ExtractionOptions options) | 1040 | UnZip::ErrorCode UnzipPrivate::extractFile(const QString& path, ZipEntryP& entry, QIODevice* dev, UnZip::ExtractionOptions options) |
1041 | { | 1041 | { |
1042 | Q_UNUSED(options); | 1042 | Q_UNUSED(options); |
1043 | Q_ASSERT(dev != 0); | 1043 | Q_ASSERT(dev != 0); |
1044 | 1044 | ||
1045 | if (!entry.lhEntryChecked) | 1045 | if (!entry.lhEntryChecked) |
1046 | { | 1046 | { |
1047 | UnZip::ErrorCode ec = parseLocalHeaderRecord(path, entry); | 1047 | UnZip::ErrorCode ec = parseLocalHeaderRecord(path, entry); |
1048 | entry.lhEntryChecked = true; | 1048 | entry.lhEntryChecked = true; |
1049 | 1049 | ||
1050 | if (ec != UnZip::Ok) | 1050 | if (ec != UnZip::Ok) |
1051 | return ec; | 1051 | return ec; |
1052 | } | 1052 | } |
1053 | 1053 | ||
1054 | if (!device->seek(entry.dataOffset)) | 1054 | if (!device->seek(entry.dataOffset)) |
1055 | return UnZip::SeekFailed; | 1055 | return UnZip::SeekFailed; |
1056 | 1056 | ||
1057 | // Encryption keys | 1057 | // Encryption keys |
1058 | quint32 keys[3]; | 1058 | quint32 keys[3]; |
1059 | 1059 | ||
1060 | if (entry.isEncrypted()) | 1060 | if (entry.isEncrypted()) |
1061 | { | 1061 | { |
1062 | UnZip::ErrorCode e = testPassword(keys, path, entry); | 1062 | UnZip::ErrorCode e = testPassword(keys, path, entry); |
1063 | if (e != UnZip::Ok) | 1063 | if (e != UnZip::Ok) |
1064 | { | 1064 | { |
1065 | qDebug() << QString("Unable to decrypt %1").arg(path); | 1065 | qDebug() << QString("Unable to decrypt %1").arg(path); |
1066 | return e; | 1066 | return e; |
1067 | }//! Encryption header size | 1067 | }//! Encryption header size |
1068 | entry.szComp -= UNZIP_LOCAL_ENC_HEADER_SIZE; // remove encryption header size | 1068 | entry.szComp -= UNZIP_LOCAL_ENC_HEADER_SIZE; // remove encryption header size |
1069 | } | 1069 | } |
1070 | 1070 | ||
1071 | if (entry.szComp == 0) | 1071 | if (entry.szComp == 0) |
1072 | { | 1072 | { |
1073 | if (entry.crc != 0) | 1073 | if (entry.crc != 0) |
1074 | return UnZip::Corrupted; | 1074 | return UnZip::Corrupted; |
1075 | 1075 | ||
1076 | return UnZip::Ok; | 1076 | return UnZip::Ok; |
1077 | } | 1077 | } |
1078 | 1078 | ||
1079 | uInt rep = entry.szComp / UNZIP_READ_BUFFER; | 1079 | uInt rep = entry.szComp / UNZIP_READ_BUFFER; |
1080 | uInt rem = entry.szComp % UNZIP_READ_BUFFER; | 1080 | uInt rem = entry.szComp % UNZIP_READ_BUFFER; |
1081 | uInt cur = 0; | 1081 | uInt cur = 0; |
1082 | 1082 | ||
1083 | // extract data | 1083 | // extract data |
1084 | qint64 read; | 1084 | qint64 read; |
1085 | quint64 tot = 0; | 1085 | quint64 tot = 0; |
1086 | 1086 | ||
1087 | quint32 myCRC = crc32(0L, Z_NULL, 0); | 1087 | quint32 myCRC = crc32(0L, Z_NULL, 0); |
1088 | 1088 | ||
1089 | if (entry.compMethod == 0) | 1089 | if (entry.compMethod == 0) |
1090 | { | 1090 | { |
1091 | while ( (read = device->read(buffer1, cur < rep ? UNZIP_READ_BUFFER : rem)) > 0 ) | 1091 | while ( (read = device->read(buffer1, cur < rep ? UNZIP_READ_BUFFER : rem)) > 0 ) |
1092 | { | 1092 | { |
1093 | if (entry.isEncrypted()) | 1093 | if (entry.isEncrypted()) |
1094 | decryptBytes(keys, buffer1, read); | 1094 | decryptBytes(keys, buffer1, read); |
1095 | 1095 | ||
1096 | myCRC = crc32(myCRC, uBuffer, read); | 1096 | myCRC = crc32(myCRC, uBuffer, read); |
1097 | 1097 | ||
1098 | if (dev->write(buffer1, read) != read) | 1098 | if (dev->write(buffer1, read) != read) |
1099 | return UnZip::WriteFailed; | 1099 | return UnZip::WriteFailed; |
1100 | 1100 | ||
1101 | cur++; | 1101 | cur++; |
1102 | tot += read; | 1102 | tot += read; |
1103 | 1103 | ||
1104 | if (tot == entry.szComp) | 1104 | if (tot == entry.szComp) |
1105 | break; | 1105 | break; |
1106 | } | 1106 | } |
1107 | 1107 | ||
1108 | if (read < 0) | 1108 | if (read < 0) |
1109 | return UnZip::ReadFailed; | 1109 | return UnZip::ReadFailed; |
1110 | } | 1110 | } |
1111 | else if (entry.compMethod == 8) | 1111 | else if (entry.compMethod == 8) |
1112 | { | 1112 | { |
1113 | /* Allocate inflate state */ | 1113 | /* Allocate inflate state */ |
1114 | z_stream zstr; | 1114 | z_stream zstr; |
1115 | zstr.zalloc = Z_NULL; | 1115 | zstr.zalloc = Z_NULL; |
1116 | zstr.zfree = Z_NULL; | 1116 | zstr.zfree = Z_NULL; |
1117 | zstr.opaque = Z_NULL; | 1117 | zstr.opaque = Z_NULL; |
1118 | zstr.next_in = Z_NULL; | 1118 | zstr.next_in = Z_NULL; |
1119 | zstr.avail_in = 0; | 1119 | zstr.avail_in = 0; |
1120 | 1120 | ||
1121 | int zret; | 1121 | int zret; |
1122 | 1122 | ||
1123 | // Use inflateInit2 with negative windowBits to get raw decompression | 1123 | // Use inflateInit2 with negative windowBits to get raw decompression |
1124 | if ( (zret = inflateInit2_(&zstr, -MAX_WBITS, ZLIB_VERSION, sizeof(z_stream))) != Z_OK ) | 1124 | if ( (zret = inflateInit2_(&zstr, -MAX_WBITS, ZLIB_VERSION, sizeof(z_stream))) != Z_OK ) |
1125 | return UnZip::ZlibError; | 1125 | return UnZip::ZlibError; |
1126 | 1126 | ||
1127 | int szDecomp; | 1127 | int szDecomp; |
1128 | 1128 | ||
1129 | // Decompress until deflate stream ends or end of file | 1129 | // Decompress until deflate stream ends or end of file |
1130 | do | 1130 | do |
1131 | { | 1131 | { |
1132 | read = device->read(buffer1, cur < rep ? UNZIP_READ_BUFFER : rem); | 1132 | read = device->read(buffer1, cur < rep ? UNZIP_READ_BUFFER : rem); |
1133 | if (read == 0) | 1133 | if (read == 0) |
1134 | break; | 1134 | break; |
1135 | if (read < 0) | 1135 | if (read < 0) |
1136 | { | 1136 | { |
1137 | (void)inflateEnd(&zstr); | 1137 | (void)inflateEnd(&zstr); |
1138 | return UnZip::ReadFailed; | 1138 | return UnZip::ReadFailed; |
1139 | } | 1139 | } |
1140 | 1140 | ||
1141 | if (entry.isEncrypted()) | 1141 | if (entry.isEncrypted()) |
1142 | decryptBytes(keys, buffer1, read); | 1142 | decryptBytes(keys, buffer1, read); |
1143 | 1143 | ||
1144 | cur++; | 1144 | cur++; |
1145 | tot += read; | 1145 | tot += read; |
1146 | 1146 | ||
1147 | zstr.avail_in = (uInt) read; | 1147 | zstr.avail_in = (uInt) read; |
1148 | zstr.next_in = (Bytef*) buffer1; | 1148 | zstr.next_in = (Bytef*) buffer1; |
1149 | 1149 | ||
1150 | 1150 | ||
1151 | // Run inflate() on input until output buffer not full | 1151 | // Run inflate() on input until output buffer not full |
1152 | do { | 1152 | do { |
1153 | zstr.avail_out = UNZIP_READ_BUFFER; | 1153 | zstr.avail_out = UNZIP_READ_BUFFER; |
1154 | zstr.next_out = (Bytef*) buffer2;; | 1154 | zstr.next_out = (Bytef*) buffer2;; |
1155 | 1155 | ||
1156 | zret = inflate(&zstr, Z_NO_FLUSH); | 1156 | zret = inflate(&zstr, Z_NO_FLUSH); |
1157 | 1157 | ||
1158 | switch (zret) { | 1158 | switch (zret) { |
1159 | case Z_NEED_DICT: | 1159 | case Z_NEED_DICT: |
1160 | case Z_DATA_ERROR: | 1160 | case Z_DATA_ERROR: |
1161 | case Z_MEM_ERROR: | 1161 | case Z_MEM_ERROR: |
1162 | inflateEnd(&zstr); | 1162 | inflateEnd(&zstr); |
1163 | return UnZip::WriteFailed; | 1163 | return UnZip::WriteFailed; |
1164 | default: | 1164 | default: |
1165 | ; | 1165 | ; |
1166 | } | 1166 | } |
1167 | 1167 | ||
1168 | szDecomp = UNZIP_READ_BUFFER - zstr.avail_out; | 1168 | szDecomp = UNZIP_READ_BUFFER - zstr.avail_out; |
1169 | if (dev->write(buffer2, szDecomp) != szDecomp) | 1169 | if (dev->write(buffer2, szDecomp) != szDecomp) |
1170 | { | 1170 | { |
1171 | inflateEnd(&zstr); | 1171 | inflateEnd(&zstr); |
1172 | return UnZip::ZlibError; | 1172 | return UnZip::ZlibError; |
1173 | } | 1173 | } |
1174 | 1174 | ||
1175 | myCRC = crc32(myCRC, (const Bytef*) buffer2, szDecomp); | 1175 | myCRC = crc32(myCRC, (const Bytef*) buffer2, szDecomp); |
1176 | 1176 | ||
1177 | } while (zstr.avail_out == 0); | 1177 | } while (zstr.avail_out == 0); |
1178 | 1178 | ||
1179 | } | 1179 | } |
1180 | while (zret != Z_STREAM_END); | 1180 | while (zret != Z_STREAM_END); |
1181 | 1181 | ||
1182 | inflateEnd(&zstr); | 1182 | inflateEnd(&zstr); |
1183 | } | 1183 | } |
1184 | 1184 | ||
1185 | if (myCRC != entry.crc) | 1185 | if (myCRC != entry.crc) |
1186 | return UnZip::Corrupted; | 1186 | return UnZip::Corrupted; |
1187 | 1187 | ||
1188 | return UnZip::Ok; | 1188 | return UnZip::Ok; |
1189 | } | 1189 | } |
1190 | 1190 | ||
1191 | //! \internal Creates a new directory and all the needed parent directories. | 1191 | //! \internal Creates a new directory and all the needed parent directories. |
1192 | bool UnzipPrivate::createDirectory(const QString& path) | 1192 | bool UnzipPrivate::createDirectory(const QString& path) |
1193 | { | 1193 | { |
1194 | QDir d(path); | 1194 | QDir d(path); |
1195 | if (!d.exists()) | 1195 | if (!d.exists()) |
1196 | { | 1196 | { |
1197 | int sep = path.lastIndexOf("/"); | 1197 | int sep = path.lastIndexOf("/"); |
1198 | if (sep <= 0) return true; | 1198 | if (sep <= 0) return true; |
1199 | 1199 | ||
1200 | if (!createDirectory(path.left(sep))) | 1200 | if (!createDirectory(path.left(sep))) |
1201 | return false; | 1201 | return false; |
1202 | 1202 | ||
1203 | if (!d.mkdir(path)) | 1203 | if (!d.mkdir(path)) |
1204 | { | 1204 | { |
1205 | qDebug() << QString("Unable to create directory: %1").arg(path); | 1205 | qDebug() << QString("Unable to create directory: %1").arg(path); |
1206 | return false; | 1206 | return false; |
1207 | } | 1207 | } |
1208 | } | 1208 | } |
1209 | 1209 | ||
1210 | return true; | 1210 | return true; |
1211 | } | 1211 | } |
1212 | 1212 | ||
1213 | /*! | 1213 | /*! |
1214 | \internal Reads an quint32 (4 bytes) from a byte array starting at given offset. | 1214 | \internal Reads an quint32 (4 bytes) from a byte array starting at given offset. |
1215 | */ | 1215 | */ |
1216 | quint32 UnzipPrivate::getULong(const unsigned char* data, quint32 offset) const | 1216 | quint32 UnzipPrivate::getULong(const unsigned char* data, quint32 offset) const |
1217 | { | 1217 | { |
1218 | quint32 res = (quint32) data[offset]; | 1218 | quint32 res = (quint32) data[offset]; |
1219 | res |= (((quint32)data[offset+1]) << 8); | 1219 | res |= (((quint32)data[offset+1]) << 8); |
1220 | res |= (((quint32)data[offset+2]) << 16); | 1220 | res |= (((quint32)data[offset+2]) << 16); |
1221 | res |= (((quint32)data[offset+3]) << 24); | 1221 | res |= (((quint32)data[offset+3]) << 24); |
1222 | 1222 | ||
1223 | return res; | 1223 | return res; |
1224 | } | 1224 | } |
1225 | 1225 | ||
1226 | /*! | 1226 | /*! |
1227 | \internal Reads an quint64 (8 bytes) from a byte array starting at given offset. | 1227 | \internal Reads an quint64 (8 bytes) from a byte array starting at given offset. |
1228 | */ | 1228 | */ |
1229 | quint64 UnzipPrivate::getULLong(const unsigned char* data, quint32 offset) const | 1229 | quint64 UnzipPrivate::getULLong(const unsigned char* data, quint32 offset) const |
1230 | { | 1230 | { |
1231 | quint64 res = (quint64) data[offset]; | 1231 | quint64 res = (quint64) data[offset]; |
1232 | res |= (((quint64)data[offset+1]) << 8); | 1232 | res |= (((quint64)data[offset+1]) << 8); |
1233 | res |= (((quint64)data[offset+2]) << 16); | 1233 | res |= (((quint64)data[offset+2]) << 16); |
1234 | res |= (((quint64)data[offset+3]) << 24); | 1234 | res |= (((quint64)data[offset+3]) << 24); |
1235 | res |= (((quint64)data[offset+1]) << 32); | 1235 | res |= (((quint64)data[offset+1]) << 32); |
1236 | res |= (((quint64)data[offset+2]) << 40); | 1236 | res |= (((quint64)data[offset+2]) << 40); |
1237 | res |= (((quint64)data[offset+3]) << 48); | 1237 | res |= (((quint64)data[offset+3]) << 48); |
1238 | res |= (((quint64)data[offset+3]) << 56); | 1238 | res |= (((quint64)data[offset+3]) << 56); |
1239 | 1239 | ||
1240 | return res; | 1240 | return res; |
1241 | } | 1241 | } |
1242 | 1242 | ||
1243 | /*! | 1243 | /*! |
1244 | \internal Reads an quint16 (2 bytes) from a byte array starting at given offset. | 1244 | \internal Reads an quint16 (2 bytes) from a byte array starting at given offset. |
1245 | */ | 1245 | */ |
1246 | quint16 UnzipPrivate::getUShort(const unsigned char* data, quint32 offset) const | 1246 | quint16 UnzipPrivate::getUShort(const unsigned char* data, quint32 offset) const |
1247 | { | 1247 | { |
1248 | return (quint16) data[offset] | (((quint16)data[offset+1]) << 8); | 1248 | return (quint16) data[offset] | (((quint16)data[offset+1]) << 8); |
1249 | } | 1249 | } |
1250 | 1250 | ||
1251 | /*! | 1251 | /*! |
1252 | \internal Return the next byte in the pseudo-random sequence | 1252 | \internal Return the next byte in the pseudo-random sequence |
1253 | */ | 1253 | */ |
1254 | int UnzipPrivate::decryptByte(quint32 key2) const | 1254 | int UnzipPrivate::decryptByte(quint32 key2) const |
1255 | { | 1255 | { |
1256 | quint16 temp = ((quint16)(key2) & 0xffff) | 2; | 1256 | quint16 temp = ((quint16)(key2) & 0xffff) | 2; |
1257 | return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); | 1257 | return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); |
1258 | } | 1258 | } |
1259 | 1259 | ||
1260 | /*! | 1260 | /*! |
1261 | \internal Update the encryption keys with the next byte of plain text | 1261 | \internal Update the encryption keys with the next byte of plain text |
1262 | */ | 1262 | */ |
1263 | void UnzipPrivate::updateKeys(quint32* keys, int c) const | 1263 | void UnzipPrivate::updateKeys(quint32* keys, int c) const |
1264 | { | 1264 | { |
1265 | keys[0] = CRC32(keys[0], c); | 1265 | keys[0] = CRC32(keys[0], c); |
1266 | keys[1] += keys[0] & 0xff; | 1266 | keys[1] += keys[0] & 0xff; |
1267 | keys[1] = keys[1] * 134775813L + 1; | 1267 | keys[1] = keys[1] * 134775813L + 1; |
1268 | keys[2] = CRC32(keys[2], ((int)keys[1]) >> 24); | 1268 | keys[2] = CRC32(keys[2], ((int)keys[1]) >> 24); |
1269 | } | 1269 | } |
1270 | 1270 | ||
1271 | /*! | 1271 | /*! |
1272 | \internal Initialize the encryption keys and the random header according to | 1272 | \internal Initialize the encryption keys and the random header according to |
1273 | the given password. | 1273 | the given password. |
1274 | */ | 1274 | */ |
1275 | void UnzipPrivate::initKeys(const QString& pwd, quint32* keys) const | 1275 | void UnzipPrivate::initKeys(const QString& pwd, quint32* keys) const |
1276 | { | 1276 | { |
1277 | keys[0] = 305419896L; | 1277 | keys[0] = 305419896L; |
1278 | keys[1] = 591751049L; | 1278 | keys[1] = 591751049L; |
1279 | keys[2] = 878082192L; | 1279 | keys[2] = 878082192L; |
1280 | 1280 | ||
1281 | QByteArray pwdBytes = pwd.toAscii(); | 1281 | QByteArray pwdBytes = pwd.toAscii(); |
1282 | int sz = pwdBytes.size(); | 1282 | int sz = pwdBytes.size(); |
1283 | const char* ascii = pwdBytes.data(); | 1283 | const char* ascii = pwdBytes.data(); |
1284 | 1284 | ||
1285 | for (int i=0; i<sz; ++i) | 1285 | for (int i=0; i<sz; ++i) |
1286 | updateKeys(keys, (int)ascii[i]); | 1286 | updateKeys(keys, (int)ascii[i]); |
1287 | } | 1287 | } |
1288 | 1288 | ||
1289 | /*! | 1289 | /*! |
1290 | \internal Attempts to test a password without actually extracting a file. | 1290 | \internal Attempts to test a password without actually extracting a file. |
1291 | The \p file parameter can be used in the user interface or for debugging purposes | 1291 | The \p file parameter can be used in the user interface or for debugging purposes |
1292 | as it is the name of the encrypted file for wich the password is being tested. | 1292 | as it is the name of the encrypted file for wich the password is being tested. |
1293 | */ | 1293 | */ |
1294 | UnZip::ErrorCode UnzipPrivate::testPassword(quint32* keys, const QString& file, const ZipEntryP& header) | 1294 | UnZip::ErrorCode UnzipPrivate::testPassword(quint32* keys, const QString& file, const ZipEntryP& header) |
1295 | { | 1295 | { |
1296 | Q_UNUSED(file); | 1296 | Q_UNUSED(file); |
1297 | 1297 | ||
1298 | // read encryption keys | 1298 | // read encryption keys |
1299 | if (device->read(buffer1, 12) != 12) | 1299 | if (device->read(buffer1, 12) != 12) |
1300 | return UnZip::Corrupted; | 1300 | return UnZip::Corrupted; |
1301 | 1301 | ||
1302 | // Replace this code if you want to i.e. call some dialog and ask the user for a password | 1302 | // Replace this code if you want to i.e. call some dialog and ask the user for a password |
1303 | initKeys(password, keys); | 1303 | initKeys(password, keys); |
1304 | if (testKeys(header, keys)) | 1304 | if (testKeys(header, keys)) |
1305 | return UnZip::Ok; | 1305 | return UnZip::Ok; |
1306 | 1306 | ||
1307 | return UnZip::Skip; | 1307 | return UnZip::Skip; |
1308 | } | 1308 | } |
1309 | 1309 | ||
1310 | /*! | 1310 | /*! |
1311 | \internal Tests a set of keys on the encryption header. | 1311 | \internal Tests a set of keys on the encryption header. |
1312 | */ | 1312 | */ |
1313 | bool UnzipPrivate::testKeys(const ZipEntryP& header, quint32* keys) | 1313 | bool UnzipPrivate::testKeys(const ZipEntryP& header, quint32* keys) |
1314 | { | 1314 | { |
1315 | char lastByte; | 1315 | char lastByte; |
1316 | 1316 | ||
1317 | // decrypt encryption header | 1317 | // decrypt encryption header |
1318 | for (int i=0; i<11; ++i) | 1318 | for (int i=0; i<11; ++i) |
1319 | updateKeys(keys, lastByte = buffer1[i] ^ decryptByte(keys[2])); | 1319 | updateKeys(keys, lastByte = buffer1[i] ^ decryptByte(keys[2])); |
1320 | updateKeys(keys, lastByte = buffer1[11] ^ decryptByte(keys[2])); | 1320 | updateKeys(keys, lastByte = buffer1[11] ^ decryptByte(keys[2])); |
1321 | 1321 | ||
1322 | // if there is an extended header (bit in the gp flag) buffer[11] is a byte from the file time | 1322 | // if there is an extended header (bit in the gp flag) buffer[11] is a byte from the file time |
1323 | // with no extended header we have to check the crc high-order byte | 1323 | // with no extended header we have to check the crc high-order byte |
1324 | char c = ((header.gpFlag[0] & 0x08) == 8) ? header.modTime[1] : header.crc >> 24; | 1324 | char c = ((header.gpFlag[0] & 0x08) == 8) ? header.modTime[1] : header.crc >> 24; |
1325 | 1325 | ||
1326 | return (lastByte == c); | 1326 | return (lastByte == c); |
1327 | } | 1327 | } |
1328 | 1328 | ||
1329 | /*! | 1329 | /*! |
1330 | \internal Decrypts an array of bytes long \p read. | 1330 | \internal Decrypts an array of bytes long \p read. |
1331 | */ | 1331 | */ |
1332 | void UnzipPrivate::decryptBytes(quint32* keys, char* buffer, qint64 read) | 1332 | void UnzipPrivate::decryptBytes(quint32* keys, char* buffer, qint64 read) |
1333 | { | 1333 | { |
1334 | for (int i=0; i<(int)read; ++i) | 1334 | for (int i=0; i<(int)read; ++i) |
1335 | updateKeys(keys, buffer[i] ^= decryptByte(keys[2])); | 1335 | updateKeys(keys, buffer[i] ^= decryptByte(keys[2])); |
1336 | } | 1336 | } |
1337 | 1337 | ||
1338 | /*! | 1338 | /*! |
1339 | \internal Converts date and time values from ZIP format to a QDateTime object. | 1339 | \internal Converts date and time values from ZIP format to a QDateTime object. |
1340 | */ | 1340 | */ |
1341 | QDateTime UnzipPrivate::convertDateTime(const unsigned char date[2], const unsigned char time[2]) const | 1341 | QDateTime UnzipPrivate::convertDateTime(const unsigned char date[2], const unsigned char time[2]) const |
1342 | { | 1342 | { |
1343 | QDateTime dt; | 1343 | QDateTime dt; |
1344 | 1344 | ||
1345 | // Usual PKZip low-byte to high-byte order | 1345 | // Usual PKZip low-byte to high-byte order |
1346 | 1346 | ||
1347 | // Date: 7 bits = years from 1980, 4 bits = month, 5 bits = day | 1347 | // Date: 7 bits = years from 1980, 4 bits = month, 5 bits = day |
1348 | quint16 year = (date[1] >> 1) & 127; | 1348 | quint16 year = (date[1] >> 1) & 127; |
1349 | quint16 month = ((date[1] << 3) & 14) | ((date[0] >> 5) & 7); | 1349 | quint16 month = ((date[1] << 3) & 14) | ((date[0] >> 5) & 7); |
1350 | quint16 day = date[0] & 31; | 1350 | quint16 day = date[0] & 31; |
1351 | 1351 | ||
1352 | // Time: 5 bits hour, 6 bits minutes, 5 bits seconds with a 2sec precision | 1352 | // Time: 5 bits hour, 6 bits minutes, 5 bits seconds with a 2sec precision |
1353 | quint16 hour = (time[1] >> 3) & 31; | 1353 | quint16 hour = (time[1] >> 3) & 31; |
1354 | quint16 minutes = ((time[1] << 3) & 56) | ((time[0] >> 5) & 7); | 1354 | quint16 minutes = ((time[1] << 3) & 56) | ((time[0] >> 5) & 7); |
1355 | quint16 seconds = (time[0] & 31) * 2; | 1355 | quint16 seconds = (time[0] & 31) * 2; |
1356 | 1356 | ||
1357 | dt.setDate(QDate(1980 + year, month, day)); | 1357 | dt.setDate(QDate(1980 + year, month, day)); |
1358 | dt.setTime(QTime(hour, minutes, seconds)); | 1358 | dt.setTime(QTime(hour, minutes, seconds)); |
1359 | return dt; | 1359 | return dt; |
1360 | } | 1360 | } |
diff --git a/rbutil/rbutilqt/zip/unzip.h b/rbutil/rbutilqt/zip/unzip.h index a48fbe8724..e480541716 100644 --- a/rbutil/rbutilqt/zip/unzip.h +++ b/rbutil/rbutilqt/zip/unzip.h | |||
@@ -1,144 +1,144 @@ | |||
1 | /**************************************************************************** | 1 | /**************************************************************************** |
2 | ** Filename: unzip.h | 2 | ** Filename: unzip.h |
3 | ** Last updated [dd/mm/yyyy]: 28/01/2007 | 3 | ** Last updated [dd/mm/yyyy]: 28/01/2007 |
4 | ** | 4 | ** |
5 | ** pkzip 2.0 decompression. | 5 | ** pkzip 2.0 decompression. |
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 | #ifndef OSDAB_UNZIP__H | 28 | #ifndef OSDAB_UNZIP__H |
29 | #define OSDAB_UNZIP__H | 29 | #define OSDAB_UNZIP__H |
30 | 30 | ||
31 | #include <QtGlobal> | 31 | #include <QtGlobal> |
32 | #include <QMap> | 32 | #include <QMap> |
33 | #include <QDateTime> | 33 | #include <QDateTime> |
34 | 34 | ||
35 | #include <zlib/zlib.h> | 35 | #include <zlib/zlib.h> |
36 | 36 | ||
37 | class UnzipPrivate; | 37 | class UnzipPrivate; |
38 | class QIODevice; | 38 | class QIODevice; |
39 | class QFile; | 39 | class QFile; |
40 | class QDir; | 40 | class QDir; |
41 | class QStringList; | 41 | class QStringList; |
42 | class QString; | 42 | class QString; |
43 | 43 | ||
44 | 44 | ||
45 | class UnZip | 45 | class UnZip |
46 | { | 46 | { |
47 | public: | 47 | public: |
48 | enum ErrorCode | 48 | enum ErrorCode |
49 | { | 49 | { |
50 | Ok, | 50 | Ok, |
51 | ZlibInit, | 51 | ZlibInit, |
52 | ZlibError, | 52 | ZlibError, |
53 | OpenFailed, | 53 | OpenFailed, |
54 | PartiallyCorrupted, | 54 | PartiallyCorrupted, |
55 | Corrupted, | 55 | Corrupted, |
56 | WrongPassword, | 56 | WrongPassword, |
57 | NoOpenArchive, | 57 | NoOpenArchive, |
58 | FileNotFound, | 58 | FileNotFound, |
59 | ReadFailed, | 59 | ReadFailed, |
60 | WriteFailed, | 60 | WriteFailed, |
61 | SeekFailed, | 61 | SeekFailed, |
62 | CreateDirFailed, | 62 | CreateDirFailed, |
63 | InvalidDevice, | 63 | InvalidDevice, |
64 | InvalidArchive, | 64 | InvalidArchive, |
65 | HeaderConsistencyError, | 65 | HeaderConsistencyError, |
66 | 66 | ||
67 | Skip, SkipAll // internal use only | 67 | Skip, SkipAll // internal use only |
68 | }; | 68 | }; |
69 | 69 | ||
70 | enum ExtractionOption | 70 | enum ExtractionOption |
71 | { | 71 | { |
72 | //! Extracts paths (default) | 72 | //! Extracts paths (default) |
73 | ExtractPaths = 0x0001, | 73 | ExtractPaths = 0x0001, |
74 | //! Ignores paths and extracts all the files to the same directory | 74 | //! Ignores paths and extracts all the files to the same directory |
75 | SkipPaths = 0x0002 | 75 | SkipPaths = 0x0002 |
76 | }; | 76 | }; |
77 | Q_DECLARE_FLAGS(ExtractionOptions, ExtractionOption) | 77 | Q_DECLARE_FLAGS(ExtractionOptions, ExtractionOption) |
78 | 78 | ||
79 | enum CompressionMethod | 79 | enum CompressionMethod |
80 | { | 80 | { |
81 | NoCompression, Deflated, UnknownCompression | 81 | NoCompression, Deflated, UnknownCompression |
82 | }; | 82 | }; |
83 | 83 | ||
84 | enum FileType | 84 | enum FileType |
85 | { | 85 | { |
86 | File, Directory | 86 | File, Directory |
87 | }; | 87 | }; |
88 | 88 | ||
89 | typedef struct ZipEntry | 89 | typedef struct ZipEntry |
90 | { | 90 | { |
91 | ZipEntry(); | 91 | ZipEntry(); |
92 | 92 | ||
93 | QString filename; | 93 | QString filename; |
94 | QString comment; | 94 | QString comment; |
95 | 95 | ||
96 | quint32 compressedSize; | 96 | quint32 compressedSize; |
97 | quint32 uncompressedSize; | 97 | quint32 uncompressedSize; |
98 | quint32 crc32; | 98 | quint32 crc32; |
99 | 99 | ||
100 | QDateTime lastModified; | 100 | QDateTime lastModified; |
101 | 101 | ||
102 | CompressionMethod compression; | 102 | CompressionMethod compression; |
103 | FileType type; | 103 | FileType type; |
104 | 104 | ||
105 | bool encrypted; | 105 | bool encrypted; |
106 | }; | 106 | }; |
107 | 107 | ||
108 | UnZip(); | 108 | UnZip(); |
109 | virtual ~UnZip(); | 109 | virtual ~UnZip(); |
110 | 110 | ||
111 | bool isOpen() const; | 111 | bool isOpen() const; |
112 | 112 | ||
113 | ErrorCode openArchive(const QString& filename); | 113 | ErrorCode openArchive(const QString& filename); |
114 | ErrorCode openArchive(QIODevice* device); | 114 | ErrorCode openArchive(QIODevice* device); |
115 | void closeArchive(); | 115 | void closeArchive(); |
116 | 116 | ||
117 | QString archiveComment() const; | 117 | QString archiveComment() const; |
118 | 118 | ||
119 | QString formatError(UnZip::ErrorCode c) const; | 119 | QString formatError(UnZip::ErrorCode c) const; |
120 | 120 | ||
121 | bool contains(const QString& file) const; | 121 | bool contains(const QString& file) const; |
122 | 122 | ||
123 | QStringList fileList() const; | 123 | QStringList fileList() const; |
124 | QList<ZipEntry> entryList() const; | 124 | QList<ZipEntry> entryList() const; |
125 | 125 | ||
126 | ErrorCode extractAll(const QString& dirname, ExtractionOptions options = ExtractPaths); | 126 | ErrorCode extractAll(const QString& dirname, ExtractionOptions options = ExtractPaths); |
127 | ErrorCode extractAll(const QDir& dir, ExtractionOptions options = ExtractPaths); | 127 | ErrorCode extractAll(const QDir& dir, ExtractionOptions options = ExtractPaths); |
128 | 128 | ||
129 | ErrorCode extractFile(const QString& filename, const QString& dirname, ExtractionOptions options = ExtractPaths); | 129 | ErrorCode extractFile(const QString& filename, const QString& dirname, ExtractionOptions options = ExtractPaths); |
130 | ErrorCode extractFile(const QString& filename, const QDir& dir, ExtractionOptions options = ExtractPaths); | 130 | ErrorCode extractFile(const QString& filename, const QDir& dir, ExtractionOptions options = ExtractPaths); |
131 | ErrorCode extractFile(const QString& filename, QIODevice* device, ExtractionOptions options = ExtractPaths); | 131 | ErrorCode extractFile(const QString& filename, QIODevice* device, ExtractionOptions options = ExtractPaths); |
132 | 132 | ||
133 | ErrorCode extractFiles(const QStringList& filenames, const QString& dirname, ExtractionOptions options = ExtractPaths); | 133 | ErrorCode extractFiles(const QStringList& filenames, const QString& dirname, ExtractionOptions options = ExtractPaths); |
134 | ErrorCode extractFiles(const QStringList& filenames, const QDir& dir, ExtractionOptions options = ExtractPaths); | 134 | ErrorCode extractFiles(const QStringList& filenames, const QDir& dir, ExtractionOptions options = ExtractPaths); |
135 | 135 | ||
136 | void setPassword(const QString& pwd); | 136 | void setPassword(const QString& pwd); |
137 | 137 | ||
138 | private: | 138 | private: |
139 | UnzipPrivate* d; | 139 | UnzipPrivate* d; |
140 | }; | 140 | }; |
141 | 141 | ||
142 | Q_DECLARE_OPERATORS_FOR_FLAGS(UnZip::ExtractionOptions) | 142 | Q_DECLARE_OPERATORS_FOR_FLAGS(UnZip::ExtractionOptions) |
143 | 143 | ||
144 | #endif // OSDAB_UNZIP__H | 144 | #endif // OSDAB_UNZIP__H |
diff --git a/rbutil/rbutilqt/zip/unzip_p.h b/rbutil/rbutilqt/zip/unzip_p.h index c05ac67b47..c0ea11b7bf 100644 --- a/rbutil/rbutilqt/zip/unzip_p.h +++ b/rbutil/rbutilqt/zip/unzip_p.h | |||
@@ -1,112 +1,112 @@ | |||
1 | /**************************************************************************** | 1 | /**************************************************************************** |
2 | ** Filename: unzip_p.h | 2 | ** Filename: unzip_p.h |
3 | ** Last updated [dd/mm/yyyy]: 28/01/2007 | 3 | ** Last updated [dd/mm/yyyy]: 28/01/2007 |
4 | ** | 4 | ** |
5 | ** pkzip 2.0 decompression. | 5 | ** pkzip 2.0 decompression. |
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 | // | 28 | // |
29 | // W A R N I N G | 29 | // W A R N I N G |
30 | // ------------- | 30 | // ------------- |
31 | // | 31 | // |
32 | // This file is not part of the Zip/UnZip API. It exists purely as an | 32 | // This file is not part of the Zip/UnZip API. It exists purely as an |
33 | // implementation detail. This header file may change from version to | 33 | // implementation detail. This header file may change from version to |
34 | // version without notice, or even be removed. | 34 | // version without notice, or even be removed. |
35 | // | 35 | // |
36 | // We mean it. | 36 | // We mean it. |
37 | // | 37 | // |
38 | 38 | ||
39 | #ifndef OSDAB_UNZIP_P__H | 39 | #ifndef OSDAB_UNZIP_P__H |
40 | #define OSDAB_UNZIP_P__H | 40 | #define OSDAB_UNZIP_P__H |
41 | 41 | ||
42 | #include "unzip.h" | 42 | #include "unzip.h" |
43 | #include "zipentry_p.h" | 43 | #include "zipentry_p.h" |
44 | 44 | ||
45 | #include <QtGlobal> | 45 | #include <QtGlobal> |
46 | 46 | ||
47 | // zLib authors suggest using larger buffers (128K or 256K) for (de)compression (especially for inflate()) | 47 | // zLib authors suggest using larger buffers (128K or 256K) for (de)compression (especially for inflate()) |
48 | // we use a 256K buffer here - if you want to use this code on a pre-iceage mainframe please change it ;) | 48 | // we use a 256K buffer here - if you want to use this code on a pre-iceage mainframe please change it ;) |
49 | #define UNZIP_READ_BUFFER (256*1024) | 49 | #define UNZIP_READ_BUFFER (256*1024) |
50 | 50 | ||
51 | class UnzipPrivate | 51 | class UnzipPrivate |
52 | { | 52 | { |
53 | public: | 53 | public: |
54 | UnzipPrivate(); | 54 | UnzipPrivate(); |
55 | 55 | ||
56 | // Replace this with whatever else you use to store/retrieve the password. | 56 | // Replace this with whatever else you use to store/retrieve the password. |
57 | QString password; | 57 | QString password; |
58 | 58 | ||
59 | bool skipAllEncrypted; | 59 | bool skipAllEncrypted; |
60 | 60 | ||
61 | QMap<QString,ZipEntryP*>* headers; | 61 | QMap<QString,ZipEntryP*>* headers; |
62 | 62 | ||
63 | QIODevice* device; | 63 | QIODevice* device; |
64 | 64 | ||
65 | char buffer1[UNZIP_READ_BUFFER]; | 65 | char buffer1[UNZIP_READ_BUFFER]; |
66 | char buffer2[UNZIP_READ_BUFFER]; | 66 | char buffer2[UNZIP_READ_BUFFER]; |
67 | 67 | ||
68 | unsigned char* uBuffer; | 68 | unsigned char* uBuffer; |
69 | const quint32* crcTable; | 69 | const quint32* crcTable; |
70 | 70 | ||
71 | // Central Directory (CD) offset | 71 | // Central Directory (CD) offset |
72 | quint32 cdOffset; | 72 | quint32 cdOffset; |
73 | // End of Central Directory (EOCD) offset | 73 | // End of Central Directory (EOCD) offset |
74 | quint32 eocdOffset; | 74 | quint32 eocdOffset; |
75 | 75 | ||
76 | // Number of entries in the Central Directory (as to the EOCD record) | 76 | // Number of entries in the Central Directory (as to the EOCD record) |
77 | quint16 cdEntryCount; | 77 | quint16 cdEntryCount; |
78 | 78 | ||
79 | // The number of detected entries that have been skipped because of a non compatible format | 79 | // The number of detected entries that have been skipped because of a non compatible format |
80 | quint16 unsupportedEntryCount; | 80 | quint16 unsupportedEntryCount; |
81 | 81 | ||
82 | QString comment; | 82 | QString comment; |
83 | 83 | ||
84 | UnZip::ErrorCode openArchive(QIODevice* device); | 84 | UnZip::ErrorCode openArchive(QIODevice* device); |
85 | 85 | ||
86 | UnZip::ErrorCode seekToCentralDirectory(); | 86 | UnZip::ErrorCode seekToCentralDirectory(); |
87 | UnZip::ErrorCode parseCentralDirectoryRecord(); | 87 | UnZip::ErrorCode parseCentralDirectoryRecord(); |
88 | UnZip::ErrorCode parseLocalHeaderRecord(const QString& path, ZipEntryP& entry); | 88 | UnZip::ErrorCode parseLocalHeaderRecord(const QString& path, ZipEntryP& entry); |
89 | 89 | ||
90 | void closeArchive(); | 90 | void closeArchive(); |
91 | 91 | ||
92 | UnZip::ErrorCode extractFile(const QString& path, ZipEntryP& entry, const QDir& dir, UnZip::ExtractionOptions options); | 92 | UnZip::ErrorCode extractFile(const QString& path, ZipEntryP& entry, const QDir& dir, UnZip::ExtractionOptions options); |
93 | UnZip::ErrorCode extractFile(const QString& path, ZipEntryP& entry, QIODevice* device, UnZip::ExtractionOptions options); | 93 | UnZip::ErrorCode extractFile(const QString& path, ZipEntryP& entry, QIODevice* device, UnZip::ExtractionOptions options); |
94 | 94 | ||
95 | UnZip::ErrorCode testPassword(quint32* keys, const QString& file, const ZipEntryP& header); | 95 | UnZip::ErrorCode testPassword(quint32* keys, const QString& file, const ZipEntryP& header); |
96 | bool testKeys(const ZipEntryP& header, quint32* keys); | 96 | bool testKeys(const ZipEntryP& header, quint32* keys); |
97 | 97 | ||
98 | bool createDirectory(const QString& path); | 98 | bool createDirectory(const QString& path); |
99 | 99 | ||
100 | inline void decryptBytes(quint32* keys, char* buffer, qint64 read); | 100 | inline void decryptBytes(quint32* keys, char* buffer, qint64 read); |
101 | 101 | ||
102 | inline quint32 getULong(const unsigned char* data, quint32 offset) const; | 102 | inline quint32 getULong(const unsigned char* data, quint32 offset) const; |
103 | inline quint64 getULLong(const unsigned char* data, quint32 offset) const; | 103 | inline quint64 getULLong(const unsigned char* data, quint32 offset) const; |
104 | inline quint16 getUShort(const unsigned char* data, quint32 offset) const; | 104 | inline quint16 getUShort(const unsigned char* data, quint32 offset) const; |
105 | inline int decryptByte(quint32 key2) const; | 105 | inline int decryptByte(quint32 key2) const; |
106 | inline void updateKeys(quint32* keys, int c) const; | 106 | inline void updateKeys(quint32* keys, int c) const; |
107 | inline void initKeys(const QString& pwd, quint32* keys) const; | 107 | inline void initKeys(const QString& pwd, quint32* keys) const; |
108 | 108 | ||
109 | inline QDateTime convertDateTime(const unsigned char date[2], const unsigned char time[2]) const; | 109 | inline QDateTime convertDateTime(const unsigned char date[2], const unsigned char time[2]) const; |
110 | }; | 110 | }; |
111 | 111 | ||
112 | #endif // OSDAB_UNZIP_P__H | 112 | #endif // OSDAB_UNZIP_P__H |
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 | } |
diff --git a/rbutil/rbutilqt/zip/zip.h b/rbutil/rbutilqt/zip/zip.h index 44fdd08b5f..8f82f1738a 100644 --- a/rbutil/rbutilqt/zip/zip.h +++ b/rbutil/rbutilqt/zip/zip.h | |||
@@ -1,115 +1,115 @@ | |||
1 | /**************************************************************************** | 1 | /**************************************************************************** |
2 | ** Filename: zip.h | 2 | ** Filename: zip.h |
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 | #ifndef OSDAB_ZIP__H | 28 | #ifndef OSDAB_ZIP__H |
29 | #define OSDAB_ZIP__H | 29 | #define OSDAB_ZIP__H |
30 | 30 | ||
31 | #include <QtGlobal> | 31 | #include <QtGlobal> |
32 | #include <QMap> | 32 | #include <QMap> |
33 | 33 | ||
34 | #include <zlib/zlib.h> | 34 | #include <zlib/zlib.h> |
35 | 35 | ||
36 | class ZipPrivate; | 36 | class ZipPrivate; |
37 | 37 | ||
38 | class QIODevice; | 38 | class QIODevice; |
39 | class QFile; | 39 | class QFile; |
40 | class QDir; | 40 | class QDir; |
41 | class QStringList; | 41 | class QStringList; |
42 | class QString; | 42 | class QString; |
43 | 43 | ||
44 | 44 | ||
45 | class Zip | 45 | class Zip |
46 | { | 46 | { |
47 | public: | 47 | public: |
48 | enum ErrorCode | 48 | enum ErrorCode |
49 | { | 49 | { |
50 | Ok, | 50 | Ok, |
51 | ZlibInit, | 51 | ZlibInit, |
52 | ZlibError, | 52 | ZlibError, |
53 | FileExists, | 53 | FileExists, |
54 | OpenFailed, | 54 | OpenFailed, |
55 | NoOpenArchive, | 55 | NoOpenArchive, |
56 | FileNotFound, | 56 | FileNotFound, |
57 | ReadFailed, | 57 | ReadFailed, |
58 | WriteFailed, | 58 | WriteFailed, |
59 | SeekFailed | 59 | SeekFailed |
60 | }; | 60 | }; |
61 | 61 | ||
62 | enum CompressionLevel | 62 | enum CompressionLevel |
63 | { | 63 | { |
64 | Store, | 64 | Store, |
65 | Deflate1 = 1, Deflate2, Deflate3, Deflate4, | 65 | Deflate1 = 1, Deflate2, Deflate3, Deflate4, |
66 | Deflate5, Deflate6, Deflate7, Deflate8, Deflate9, | 66 | Deflate5, Deflate6, Deflate7, Deflate8, Deflate9, |
67 | AutoCPU, AutoMIME, AutoFull | 67 | AutoCPU, AutoMIME, AutoFull |
68 | }; | 68 | }; |
69 | 69 | ||
70 | enum CompressionOption | 70 | enum CompressionOption |
71 | { | 71 | { |
72 | //! Does not preserve absolute paths in the zip file when adding a file/directory (default) | 72 | //! Does not preserve absolute paths in the zip file when adding a file/directory (default) |
73 | RelativePaths = 0x0001, | 73 | RelativePaths = 0x0001, |
74 | //! Preserve absolute paths | 74 | //! Preserve absolute paths |
75 | AbsolutePaths = 0x0002, | 75 | AbsolutePaths = 0x0002, |
76 | //! Do not store paths. All the files are put in the (evtl. user defined) root of the zip file | 76 | //! Do not store paths. All the files are put in the (evtl. user defined) root of the zip file |
77 | IgnorePaths = 0x0004 | 77 | IgnorePaths = 0x0004 |
78 | }; | 78 | }; |
79 | Q_DECLARE_FLAGS(CompressionOptions, CompressionOption) | 79 | Q_DECLARE_FLAGS(CompressionOptions, CompressionOption) |
80 | 80 | ||
81 | Zip(); | 81 | Zip(); |
82 | virtual ~Zip(); | 82 | virtual ~Zip(); |
83 | 83 | ||
84 | bool isOpen() const; | 84 | bool isOpen() const; |
85 | 85 | ||
86 | void setPassword(const QString& pwd); | 86 | void setPassword(const QString& pwd); |
87 | void clearPassword(); | 87 | void clearPassword(); |
88 | QString password() const; | 88 | QString password() const; |
89 | 89 | ||
90 | ErrorCode createArchive(const QString& file, bool overwrite = true); | 90 | ErrorCode createArchive(const QString& file, bool overwrite = true); |
91 | ErrorCode createArchive(QIODevice* device); | 91 | ErrorCode createArchive(QIODevice* device); |
92 | 92 | ||
93 | QString archiveComment() const; | 93 | QString archiveComment() const; |
94 | void setArchiveComment(const QString& comment); | 94 | void setArchiveComment(const QString& comment); |
95 | 95 | ||
96 | ErrorCode addDirectoryContents(const QString& path, CompressionLevel level = AutoFull); | 96 | ErrorCode addDirectoryContents(const QString& path, CompressionLevel level = AutoFull); |
97 | ErrorCode addDirectoryContents(const QString& path, const QString& root, CompressionLevel level = AutoFull); | 97 | ErrorCode addDirectoryContents(const QString& path, const QString& root, CompressionLevel level = AutoFull); |
98 | 98 | ||
99 | ErrorCode addDirectory(const QString& path, CompressionOptions options = RelativePaths, CompressionLevel level = AutoFull); | 99 | ErrorCode addDirectory(const QString& path, CompressionOptions options = RelativePaths, CompressionLevel level = AutoFull); |
100 | ErrorCode addDirectory(const QString& path, const QString& root, CompressionLevel level = AutoFull); | 100 | ErrorCode addDirectory(const QString& path, const QString& root, CompressionLevel level = AutoFull); |
101 | ErrorCode addDirectory(const QString& path, const QString& root, CompressionOptions options = RelativePaths, CompressionLevel level = AutoFull); | 101 | ErrorCode addDirectory(const QString& path, const QString& root, CompressionOptions options = RelativePaths, CompressionLevel level = AutoFull); |
102 | 102 | ||
103 | ErrorCode closeArchive(); | 103 | ErrorCode closeArchive(); |
104 | 104 | ||
105 | QString formatError(ErrorCode c) const; | 105 | QString formatError(ErrorCode c) const; |
106 | 106 | ||
107 | virtual void progress() {} | 107 | virtual void progress() {} |
108 | 108 | ||
109 | private: | 109 | private: |
110 | ZipPrivate* d; | 110 | ZipPrivate* d; |
111 | }; | 111 | }; |
112 | 112 | ||
113 | Q_DECLARE_OPERATORS_FOR_FLAGS(Zip::CompressionOptions) | 113 | Q_DECLARE_OPERATORS_FOR_FLAGS(Zip::CompressionOptions) |
114 | 114 | ||
115 | #endif // OSDAB_ZIP__H | 115 | #endif // OSDAB_ZIP__H |
diff --git a/rbutil/rbutilqt/zip/zip_p.h b/rbutil/rbutilqt/zip/zip_p.h index b3c45ac7b8..8c57f99225 100644 --- a/rbutil/rbutilqt/zip/zip_p.h +++ b/rbutil/rbutilqt/zip/zip_p.h | |||
@@ -1,93 +1,93 @@ | |||
1 | /**************************************************************************** | 1 | /**************************************************************************** |
2 | ** Filename: zip_p.h | 2 | ** Filename: zip_p.h |
3 | ** Last updated [dd/mm/yyyy]: 28/01/2007 | 3 | ** Last updated [dd/mm/yyyy]: 28/01/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 | // | 28 | // |
29 | // W A R N I N G | 29 | // W A R N I N G |
30 | // ------------- | 30 | // ------------- |
31 | // | 31 | // |
32 | // This file is not part of the Zip/UnZip API. It exists purely as an | 32 | // This file is not part of the Zip/UnZip API. It exists purely as an |
33 | // implementation detail. This header file may change from version to | 33 | // implementation detail. This header file may change from version to |
34 | // version without notice, or even be removed. | 34 | // version without notice, or even be removed. |
35 | // | 35 | // |
36 | // We mean it. | 36 | // We mean it. |
37 | // | 37 | // |
38 | 38 | ||
39 | #ifndef OSDAB_ZIP_P__H | 39 | #ifndef OSDAB_ZIP_P__H |
40 | #define OSDAB_ZIP_P__H | 40 | #define OSDAB_ZIP_P__H |
41 | 41 | ||
42 | #include "zip.h" | 42 | #include "zip.h" |
43 | #include "zipentry_p.h" | 43 | #include "zipentry_p.h" |
44 | 44 | ||
45 | #include <QtGlobal> | 45 | #include <QtGlobal> |
46 | #include <QFileInfo> | 46 | #include <QFileInfo> |
47 | 47 | ||
48 | /*! | 48 | /*! |
49 | zLib authors suggest using larger buffers (128K or 256K) for (de)compression (especially for inflate()) | 49 | zLib authors suggest using larger buffers (128K or 256K) for (de)compression (especially for inflate()) |
50 | we use a 256K buffer here - if you want to use this code on a pre-iceage mainframe please change it ;) | 50 | we use a 256K buffer here - if you want to use this code on a pre-iceage mainframe please change it ;) |
51 | */ | 51 | */ |
52 | #define ZIP_READ_BUFFER (256*1024) | 52 | #define ZIP_READ_BUFFER (256*1024) |
53 | 53 | ||
54 | class ZipPrivate | 54 | class ZipPrivate |
55 | { | 55 | { |
56 | public: | 56 | public: |
57 | ZipPrivate(); | 57 | ZipPrivate(); |
58 | virtual ~ZipPrivate(); | 58 | virtual ~ZipPrivate(); |
59 | 59 | ||
60 | QMap<QString,ZipEntryP*>* headers; | 60 | QMap<QString,ZipEntryP*>* headers; |
61 | 61 | ||
62 | QIODevice* device; | 62 | QIODevice* device; |
63 | 63 | ||
64 | char buffer1[ZIP_READ_BUFFER]; | 64 | char buffer1[ZIP_READ_BUFFER]; |
65 | char buffer2[ZIP_READ_BUFFER]; | 65 | char buffer2[ZIP_READ_BUFFER]; |
66 | 66 | ||
67 | unsigned char* uBuffer; | 67 | unsigned char* uBuffer; |
68 | 68 | ||
69 | const quint32* crcTable; | 69 | const quint32* crcTable; |
70 | 70 | ||
71 | QString comment; | 71 | QString comment; |
72 | QString password; | 72 | QString password; |
73 | 73 | ||
74 | Zip::ErrorCode createArchive(QIODevice* device); | 74 | Zip::ErrorCode createArchive(QIODevice* device); |
75 | Zip::ErrorCode closeArchive(); | 75 | Zip::ErrorCode closeArchive(); |
76 | void reset(); | 76 | void reset(); |
77 | 77 | ||
78 | bool zLibInit(); | 78 | bool zLibInit(); |
79 | 79 | ||
80 | Zip::ErrorCode createEntry(const QFileInfo& file, const QString& root, Zip::CompressionLevel level); | 80 | Zip::ErrorCode createEntry(const QFileInfo& file, const QString& root, Zip::CompressionLevel level); |
81 | Zip::CompressionLevel detectCompressionByMime(const QString& ext); | 81 | Zip::CompressionLevel detectCompressionByMime(const QString& ext); |
82 | 82 | ||
83 | inline void encryptBytes(quint32* keys, char* buffer, qint64 read); | 83 | inline void encryptBytes(quint32* keys, char* buffer, qint64 read); |
84 | 84 | ||
85 | inline void setULong(quint32 v, char* buffer, unsigned int offset); | 85 | inline void setULong(quint32 v, char* buffer, unsigned int offset); |
86 | inline void updateKeys(quint32* keys, int c) const; | 86 | inline void updateKeys(quint32* keys, int c) const; |
87 | inline void initKeys(quint32* keys) const; | 87 | inline void initKeys(quint32* keys) const; |
88 | inline int decryptByte(quint32 key2) const; | 88 | inline int decryptByte(quint32 key2) const; |
89 | 89 | ||
90 | inline QString extractRoot(const QString& p); | 90 | inline QString extractRoot(const QString& p); |
91 | }; | 91 | }; |
92 | 92 | ||
93 | #endif // OSDAB_ZIP_P__H | 93 | #endif // OSDAB_ZIP_P__H |
diff --git a/rbutil/rbutilqt/zip/zipentry_p.h b/rbutil/rbutilqt/zip/zipentry_p.h index a201d0ac6e..dfdcf174d0 100644 --- a/rbutil/rbutilqt/zip/zipentry_p.h +++ b/rbutil/rbutilqt/zip/zipentry_p.h | |||
@@ -1,78 +1,78 @@ | |||
1 | /**************************************************************************** | 1 | /**************************************************************************** |
2 | ** Filename: ZipEntryP.h | 2 | ** Filename: ZipEntryP.h |
3 | ** Last updated [dd/mm/yyyy]: 28/01/2007 | 3 | ** Last updated [dd/mm/yyyy]: 28/01/2007 |
4 | ** | 4 | ** |
5 | ** Wrapper for a ZIP local header. | 5 | ** Wrapper for a ZIP local header. |
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 | // | 28 | // |
29 | // W A R N I N G | 29 | // W A R N I N G |
30 | // ------------- | 30 | // ------------- |
31 | // | 31 | // |
32 | // This file is not part of the Zip/UnZip API. It exists purely as an | 32 | // This file is not part of the Zip/UnZip API. It exists purely as an |
33 | // implementation detail. This header file may change from version to | 33 | // implementation detail. This header file may change from version to |
34 | // version without notice, or even be removed. | 34 | // version without notice, or even be removed. |
35 | // | 35 | // |
36 | // We mean it. | 36 | // We mean it. |
37 | // | 37 | // |
38 | 38 | ||
39 | #ifndef OSDAB_ZIPENTRY_P__H | 39 | #ifndef OSDAB_ZIPENTRY_P__H |
40 | #define OSDAB_ZIPENTRY_P__H | 40 | #define OSDAB_ZIPENTRY_P__H |
41 | 41 | ||
42 | #include <QtGlobal> | 42 | #include <QtGlobal> |
43 | #include <QString> | 43 | #include <QString> |
44 | 44 | ||
45 | class ZipEntryP | 45 | class ZipEntryP |
46 | { | 46 | { |
47 | public: | 47 | public: |
48 | ZipEntryP() | 48 | ZipEntryP() |
49 | { | 49 | { |
50 | lhOffset = 0; | 50 | lhOffset = 0; |
51 | dataOffset = 0; | 51 | dataOffset = 0; |
52 | gpFlag[0] = gpFlag[1] = 0; | 52 | gpFlag[0] = gpFlag[1] = 0; |
53 | compMethod = 0; | 53 | compMethod = 0; |
54 | modTime[0] = modTime[1] = 0; | 54 | modTime[0] = modTime[1] = 0; |
55 | modDate[0] = modDate[1] = 0; | 55 | modDate[0] = modDate[1] = 0; |
56 | crc = 0; | 56 | crc = 0; |
57 | szComp = szUncomp = 0; | 57 | szComp = szUncomp = 0; |
58 | lhEntryChecked = false; | 58 | lhEntryChecked = false; |
59 | } | 59 | } |
60 | 60 | ||
61 | quint32 lhOffset; // Offset of the local header record for this entry | 61 | quint32 lhOffset; // Offset of the local header record for this entry |
62 | quint32 dataOffset; // Offset of the file data for this entry | 62 | quint32 dataOffset; // Offset of the file data for this entry |
63 | unsigned char gpFlag[2]; // General purpose flag | 63 | unsigned char gpFlag[2]; // General purpose flag |
64 | quint16 compMethod; // Compression method | 64 | quint16 compMethod; // Compression method |
65 | unsigned char modTime[2]; // Last modified time | 65 | unsigned char modTime[2]; // Last modified time |
66 | unsigned char modDate[2]; // Last modified date | 66 | unsigned char modDate[2]; // Last modified date |
67 | quint32 crc; // CRC32 | 67 | quint32 crc; // CRC32 |
68 | quint32 szComp; // Compressed file size | 68 | quint32 szComp; // Compressed file size |
69 | quint32 szUncomp; // Uncompressed file size | 69 | quint32 szUncomp; // Uncompressed file size |
70 | QString comment; // File comment | 70 | QString comment; // File comment |
71 | 71 | ||
72 | bool lhEntryChecked; // Is true if the local header record for this entry has been parsed | 72 | bool lhEntryChecked; // Is true if the local header record for this entry has been parsed |
73 | 73 | ||
74 | inline bool isEncrypted() const { return gpFlag[0] & 0x01; } | 74 | inline bool isEncrypted() const { return gpFlag[0] & 0x01; } |
75 | inline bool hasDataDescriptor() const { return gpFlag[0] & 0x08; } | 75 | inline bool hasDataDescriptor() const { return gpFlag[0] & 0x08; } |
76 | }; | 76 | }; |
77 | 77 | ||
78 | #endif // OSDAB_ZIPENTRY_P__H | 78 | #endif // OSDAB_ZIPENTRY_P__H |