Qt 4.8
qzip.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <qglobal.h>
43 
44 #ifndef QT_NO_TEXTODFWRITER
45 
46 #include "qzipreader_p.h"
47 #include "qzipwriter_p.h"
48 #include <qdatetime.h>
49 #include <qplatformdefs.h>
50 #include <qendian.h>
51 #include <qdebug.h>
52 #include <qdir.h>
53 
54 #include <zlib.h>
55 
56 #if defined(Q_OS_WIN)
57 # undef S_IFREG
58 # define S_IFREG 0100000
59 # ifndef S_IFDIR
60 # define S_IFDIR 0040000
61 # endif
62 # ifndef S_ISDIR
63 # define S_ISDIR(x) ((x) & S_IFDIR) > 0
64 # endif
65 # ifndef S_ISREG
66 # define S_ISREG(x) ((x) & 0170000) == S_IFREG
67 # endif
68 # define S_IFLNK 020000
69 # define S_ISLNK(x) ((x) & S_IFLNK) > 0
70 # ifndef S_IRUSR
71 # define S_IRUSR 0400
72 # endif
73 # ifndef S_IWUSR
74 # define S_IWUSR 0200
75 # endif
76 # ifndef S_IXUSR
77 # define S_IXUSR 0100
78 # endif
79 # define S_IRGRP 0040
80 # define S_IWGRP 0020
81 # define S_IXGRP 0010
82 # define S_IROTH 0004
83 # define S_IWOTH 0002
84 # define S_IXOTH 0001
85 #endif
86 
87 #if 0
88 #define ZDEBUG qDebug
89 #else
90 #define ZDEBUG if (0) qDebug
91 #endif
92 
94 
95 static inline uint readUInt(const uchar *data)
96 {
97  return (data[0]) + (data[1]<<8) + (data[2]<<16) + (data[3]<<24);
98 }
99 
100 static inline ushort readUShort(const uchar *data)
101 {
102  return (data[0]) + (data[1]<<8);
103 }
104 
105 static inline void writeUInt(uchar *data, uint i)
106 {
107  data[0] = i & 0xff;
108  data[1] = (i>>8) & 0xff;
109  data[2] = (i>>16) & 0xff;
110  data[3] = (i>>24) & 0xff;
111 }
112 
113 static inline void writeUShort(uchar *data, ushort i)
114 {
115  data[0] = i & 0xff;
116  data[1] = (i>>8) & 0xff;
117 }
118 
119 static inline void copyUInt(uchar *dest, const uchar *src)
120 {
121  dest[0] = src[0];
122  dest[1] = src[1];
123  dest[2] = src[2];
124  dest[3] = src[3];
125 }
126 
127 static inline void copyUShort(uchar *dest, const uchar *src)
128 {
129  dest[0] = src[0];
130  dest[1] = src[1];
131 }
132 
133 static void writeMSDosDate(uchar *dest, const QDateTime& dt)
134 {
135  if (dt.isValid()) {
136  quint16 time =
137  (dt.time().hour() << 11) // 5 bit hour
138  | (dt.time().minute() << 5) // 6 bit minute
139  | (dt.time().second() >> 1); // 5 bit double seconds
140 
141  dest[0] = time & 0xff;
142  dest[1] = time >> 8;
143 
144  quint16 date =
145  ((dt.date().year() - 1980) << 9) // 7 bit year 1980-based
146  | (dt.date().month() << 5) // 4 bit month
147  | (dt.date().day()); // 5 bit day
148 
149  dest[2] = char(date);
150  dest[3] = char(date >> 8);
151  } else {
152  dest[0] = 0;
153  dest[1] = 0;
154  dest[2] = 0;
155  dest[3] = 0;
156  }
157 }
158 
159 static quint32 permissionsToMode(QFile::Permissions perms)
160 {
161  quint32 mode = 0;
162  if (perms & QFile::ReadOwner)
163  mode |= S_IRUSR;
164  if (perms & QFile::WriteOwner)
165  mode |= S_IWUSR;
166  if (perms & QFile::ExeOwner)
167  mode |= S_IXUSR;
168  if (perms & QFile::ReadUser)
169  mode |= S_IRUSR;
170  if (perms & QFile::WriteUser)
171  mode |= S_IWUSR;
172  if (perms & QFile::ExeUser)
173  mode |= S_IXUSR;
174  if (perms & QFile::ReadGroup)
175  mode |= S_IRGRP;
176  if (perms & QFile::WriteGroup)
177  mode |= S_IWGRP;
178  if (perms & QFile::ExeGroup)
179  mode |= S_IXGRP;
180  if (perms & QFile::ReadOther)
181  mode |= S_IROTH;
182  if (perms & QFile::WriteOther)
183  mode |= S_IWOTH;
184  if (perms & QFile::ExeOther)
185  mode |= S_IXOTH;
186  return mode;
187 }
188 
189 static int inflate(Bytef *dest, ulong *destLen, const Bytef *source, ulong sourceLen)
190 {
191  z_stream stream;
192  int err;
193 
194  stream.next_in = (Bytef*)source;
195  stream.avail_in = (uInt)sourceLen;
196  if ((uLong)stream.avail_in != sourceLen)
197  return Z_BUF_ERROR;
198 
199  stream.next_out = dest;
200  stream.avail_out = (uInt)*destLen;
201  if ((uLong)stream.avail_out != *destLen)
202  return Z_BUF_ERROR;
203 
204  stream.zalloc = (alloc_func)0;
205  stream.zfree = (free_func)0;
206 
207  err = inflateInit2(&stream, -MAX_WBITS);
208  if (err != Z_OK)
209  return err;
210 
211  err = inflate(&stream, Z_FINISH);
212  if (err != Z_STREAM_END) {
213  inflateEnd(&stream);
214  if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
215  return Z_DATA_ERROR;
216  return err;
217  }
218  *destLen = stream.total_out;
219 
220  err = inflateEnd(&stream);
221  return err;
222 }
223 
224 static int deflate (Bytef *dest, ulong *destLen, const Bytef *source, ulong sourceLen)
225 {
226  z_stream stream;
227  int err;
228 
229  stream.next_in = (Bytef*)source;
230  stream.avail_in = (uInt)sourceLen;
231  stream.next_out = dest;
232  stream.avail_out = (uInt)*destLen;
233  if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
234 
235  stream.zalloc = (alloc_func)0;
236  stream.zfree = (free_func)0;
237  stream.opaque = (voidpf)0;
238 
239  err = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
240  if (err != Z_OK) return err;
241 
242  err = deflate(&stream, Z_FINISH);
243  if (err != Z_STREAM_END) {
244  deflateEnd(&stream);
245  return err == Z_OK ? Z_BUF_ERROR : err;
246  }
247  *destLen = stream.total_out;
248 
249  err = deflateEnd(&stream);
250  return err;
251 }
252 
253 static QFile::Permissions modeToPermissions(quint32 mode)
254 {
255  QFile::Permissions ret;
256  if (mode & S_IRUSR)
257  ret |= QFile::ReadOwner;
258  if (mode & S_IWUSR)
259  ret |= QFile::WriteOwner;
260  if (mode & S_IXUSR)
261  ret |= QFile::ExeOwner;
262  if (mode & S_IRUSR)
263  ret |= QFile::ReadUser;
264  if (mode & S_IWUSR)
265  ret |= QFile::WriteUser;
266  if (mode & S_IXUSR)
267  ret |= QFile::ExeUser;
268  if (mode & S_IRGRP)
269  ret |= QFile::ReadGroup;
270  if (mode & S_IWGRP)
271  ret |= QFile::WriteGroup;
272  if (mode & S_IXGRP)
273  ret |= QFile::ExeGroup;
274  if (mode & S_IROTH)
275  ret |= QFile::ReadOther;
276  if (mode & S_IWOTH)
277  ret |= QFile::WriteOther;
278  if (mode & S_IXOTH)
279  ret |= QFile::ExeOther;
280  return ret;
281 }
282 
283 static QDateTime readMSDosDate(const uchar *src)
284 {
285  uint dosDate = readUInt(src);
286  quint64 uDate;
287  uDate = (quint64)(dosDate >> 16);
288  uint tm_mday = (uDate & 0x1f);
289  uint tm_mon = ((uDate & 0x1E0) >> 5);
290  uint tm_year = (((uDate & 0x0FE00) >> 9) + 1980);
291  uint tm_hour = ((dosDate & 0xF800) >> 11);
292  uint tm_min = ((dosDate & 0x7E0) >> 5);
293  uint tm_sec = ((dosDate & 0x1f) << 1);
294 
295  return QDateTime(QDate(tm_year, tm_mon, tm_mday), QTime(tm_hour, tm_min, tm_sec));
296 }
297 
299 {
300  uchar signature[4]; // 0x04034b50
310 };
311 
313 {
317 };
318 
320 {
321  uchar signature[4]; // 0x02014b50
322  uchar version_made[2];
332  uchar file_comment_length[2];
333  uchar disk_start[2];
334  uchar internal_file_attributes[2];
335  uchar external_file_attributes[4];
336  uchar offset_local_header[4];
337  LocalFileHeader toLocalHeader() const;
338 };
339 
341 {
342  uchar signature[4]; // 0x06054b50
343  uchar this_disk[2];
344  uchar start_of_directory_disk[2];
345  uchar num_dir_entries_this_disk[2];
346  uchar num_dir_entries[2];
347  uchar directory_size[4];
348  uchar dir_start_offset[4];
349  uchar comment_length[2];
350 };
351 
353 {
358 };
359 
361  : isDir(false), isFile(false), isSymLink(false), crc32(0), size(0)
362 {
363 }
364 
366 {
367 }
368 
370 {
371  operator=(other);
372 }
373 
375 {
376  filePath = other.filePath;
377  isDir = other.isDir;
378  isFile = other.isFile;
379  isSymLink = other.isSymLink;
380  permissions = other.permissions;
381  crc32 = other.crc32;
382  size = other.size;
383  lastModified = other.lastModified;
384  return *this;
385 }
386 
388 {
389  return isDir || isFile || isSymLink;
390 }
391 
393 {
394 public:
395  QZipPrivate(QIODevice *device, bool ownDev)
396  : device(device), ownDevice(ownDev), dirtyFileTree(true), start_of_directory(0)
397  {
398  }
399 
401  {
402  if (ownDevice)
403  delete device;
404  }
405 
406  void fillFileInfo(int index, QZipReader::FileInfo &fileInfo) const;
407 
409  bool ownDevice;
414 };
415 
417 {
418  FileHeader header = fileHeaders.at(index);
419  fileInfo.filePath = QString::fromLocal8Bit(header.file_name);
420  const quint32 mode = (qFromLittleEndian<quint32>(&header.h.external_file_attributes[0]) >> 16) & 0xFFFF;
421  fileInfo.isDir = S_ISDIR(mode);
422  fileInfo.isFile = S_ISREG(mode);
423  fileInfo.isSymLink = S_ISLNK(mode);
424  fileInfo.permissions = modeToPermissions(mode);
425  fileInfo.crc32 = readUInt(header.h.crc_32);
426  fileInfo.size = readUInt(header.h.uncompressed_size);
427  fileInfo.lastModified = readMSDosDate(header.h.last_mod_file);
428 }
429 
431 {
432 public:
434  : QZipPrivate(device, ownDev), status(QZipReader::NoError)
435  {
436  }
437 
438  void scanFiles();
439 
441 };
442 
444 {
445 public:
447  : QZipPrivate(device, ownDev),
449  permissions(QFile::ReadOwner | QFile::WriteOwner),
450  compressionPolicy(QZipWriter::AlwaysCompress)
451  {
452  }
453 
455  QFile::Permissions permissions;
457 
458  enum EntryType { Directory, File, Symlink };
459 
460  void addEntry(EntryType type, const QString &fileName, const QByteArray &contents);
461 };
462 
464 {
465  LocalFileHeader h;
466  writeUInt(h.signature, 0x04034b50);
467  copyUShort(h.version_needed, version_needed);
468  copyUShort(h.general_purpose_bits, general_purpose_bits);
469  copyUShort(h.compression_method, compression_method);
470  copyUInt(h.last_mod_file, last_mod_file);
471  copyUInt(h.crc_32, crc_32);
472  copyUInt(h.compressed_size, compressed_size);
473  copyUInt(h.uncompressed_size, uncompressed_size);
474  copyUShort(h.file_name_length, file_name_length);
475  copyUShort(h.extra_field_length, extra_field_length);
476  return h;
477 }
478 
480 {
481  if (!dirtyFileTree)
482  return;
483 
484  if (! (device->isOpen() || device->open(QIODevice::ReadOnly))) {
486  return;
487  }
488 
489  if ((device->openMode() & QIODevice::ReadOnly) == 0) { // only read the index from readable files.
491  return;
492  }
493 
494  dirtyFileTree = false;
495  uchar tmp[4];
496  device->read((char *)tmp, 4);
497  if (readUInt(tmp) != 0x04034b50) {
498  qWarning() << "QZip: not a zip file!";
499  return;
500  }
501 
502  // find EndOfDirectory header
503  int i = 0;
504  int start_of_directory = -1;
505  int num_dir_entries = 0;
506  EndOfDirectory eod;
507  while (start_of_directory == -1) {
508  int pos = device->size() - sizeof(EndOfDirectory) - i;
509  if (pos < 0 || i > 65535) {
510  qWarning() << "QZip: EndOfDirectory not found";
511  return;
512  }
513 
514  device->seek(pos);
515  device->read((char *)&eod, sizeof(EndOfDirectory));
516  if (readUInt(eod.signature) == 0x06054b50)
517  break;
518  ++i;
519  }
520 
521  // have the eod
522  start_of_directory = readUInt(eod.dir_start_offset);
523  num_dir_entries = readUShort(eod.num_dir_entries);
524  ZDEBUG("start_of_directory at %d, num_dir_entries=%d", start_of_directory, num_dir_entries);
525  int comment_length = readUShort(eod.comment_length);
526  if (comment_length != i)
527  qWarning() << "QZip: failed to parse zip file.";
528  comment = device->read(qMin(comment_length, i));
529 
530 
531  device->seek(start_of_directory);
532  for (i = 0; i < num_dir_entries; ++i) {
533  FileHeader header;
534  int read = device->read((char *) &header.h, sizeof(CentralFileHeader));
535  if (read < (int)sizeof(CentralFileHeader)) {
536  qWarning() << "QZip: Failed to read complete header, index may be incomplete";
537  break;
538  }
539  if (readUInt(header.h.signature) != 0x02014b50) {
540  qWarning() << "QZip: invalid header signature, index may be incomplete";
541  break;
542  }
543 
544  int l = readUShort(header.h.file_name_length);
545  header.file_name = device->read(l);
546  if (header.file_name.length() != l) {
547  qWarning() << "QZip: Failed to read filename from zip index, index may be incomplete";
548  break;
549  }
550  l = readUShort(header.h.extra_field_length);
551  header.extra_field = device->read(l);
552  if (header.extra_field.length() != l) {
553  qWarning() << "QZip: Failed to read extra field in zip file, skipping file, index may be incomplete";
554  break;
555  }
556  l = readUShort(header.h.file_comment_length);
557  header.file_comment = device->read(l);
558  if (header.file_comment.length() != l) {
559  qWarning() << "QZip: Failed to read read file comment, index may be incomplete";
560  break;
561  }
562 
563  ZDEBUG("found file '%s'", header.file_name.data());
564  fileHeaders.append(header);
565  }
566 }
567 
568 void QZipWriterPrivate::addEntry(EntryType type, const QString &fileName, const QByteArray &contents/*, QFile::Permissions permissions, QZip::Method m*/)
569 {
570 #ifndef NDEBUG
571  static const char *entryTypes[] = {
572  "directory",
573  "file ",
574  "symlink " };
575  ZDEBUG() << "adding" << entryTypes[type] <<":" << fileName.toUtf8().data() << (type == 2 ? QByteArray(" -> " + contents).constData() : "");
576 #endif
577 
578  if (! (device->isOpen() || device->open(QIODevice::WriteOnly))) {
580  return;
581  }
582  device->seek(start_of_directory);
583 
584  // don't compress small files
585  QZipWriter::CompressionPolicy compression = compressionPolicy;
586  if (compressionPolicy == QZipWriter::AutoCompress) {
587  if (contents.length() < 64)
588  compression = QZipWriter::NeverCompress;
589  else
590  compression = QZipWriter::AlwaysCompress;
591  }
592 
593  FileHeader header;
594  memset(&header.h, 0, sizeof(CentralFileHeader));
595  writeUInt(header.h.signature, 0x02014b50);
596 
597  writeUShort(header.h.version_needed, 0x14);
598  writeUInt(header.h.uncompressed_size, contents.length());
600  QByteArray data = contents;
601  if (compression == QZipWriter::AlwaysCompress) {
602  writeUShort(header.h.compression_method, 8);
603 
604  ulong len = contents.length();
605  // shamelessly copied form zlib
606  len += (len >> 12) + (len >> 14) + 11;
607  int res;
608  do {
609  data.resize(len);
610  res = deflate((uchar*)data.data(), &len, (const uchar*)contents.constData(), contents.length());
611 
612  switch (res) {
613  case Z_OK:
614  data.resize(len);
615  break;
616  case Z_MEM_ERROR:
617  qWarning("QZip: Z_MEM_ERROR: Not enough memory to compress file, skipping");
618  data.resize(0);
619  break;
620  case Z_BUF_ERROR:
621  len *= 2;
622  break;
623  }
624  } while (res == Z_BUF_ERROR);
625  }
626 // TODO add a check if data.length() > contents.length(). Then try to store the original and revert the compression method to be uncompressed
627  writeUInt(header.h.compressed_size, data.length());
628  uint crc_32 = ::crc32(0, 0, 0);
629  crc_32 = ::crc32(crc_32, (const uchar *)contents.constData(), contents.length());
630  writeUInt(header.h.crc_32, crc_32);
631 
632  header.file_name = fileName.toLocal8Bit();
633  if (header.file_name.size() > 0xffff) {
634  qWarning("QZip: Filename too long, chopping it to 65535 characters");
635  header.file_name = header.file_name.left(0xffff);
636  }
637  writeUShort(header.h.file_name_length, header.file_name.length());
638  //h.extra_field_length[2];
639 
640  writeUShort(header.h.version_made, 3 << 8);
641  //uchar internal_file_attributes[2];
642  //uchar external_file_attributes[4];
644  switch (type) {
645  case File: mode |= S_IFREG; break;
646  case Directory: mode |= S_IFDIR; break;
647  case Symlink: mode |= S_IFLNK; break;
648  }
649  writeUInt(header.h.external_file_attributes, mode << 16);
650  writeUInt(header.h.offset_local_header, start_of_directory);
651 
652 
653  fileHeaders.append(header);
654 
655  LocalFileHeader h = header.h.toLocalHeader();
656  device->write((const char *)&h, sizeof(LocalFileHeader));
657  device->write(header.file_name);
658  device->write(data);
659  start_of_directory = device->pos();
660  dirtyFileTree = true;
661 }
662 
664 
758 QZipReader::QZipReader(const QString &archive, QIODevice::OpenMode mode)
759 {
760  QScopedPointer<QFile> f(new QFile(archive));
761  f->open(mode);
763  if (f->error() == QFile::NoError)
764  status = NoError;
765  else {
766  if (f->error() == QFile::ReadError)
767  status = FileReadError;
768  else if (f->error() == QFile::OpenError)
769  status = FileOpenError;
770  else if (f->error() == QFile::PermissionsError)
771  status = FilePermissionsError;
772  else
773  status = FileError;
774  }
775 
776  d = new QZipReaderPrivate(f.data(), /*ownDevice=*/true);
777  f.take();
778  d->status = status;
779 }
780 
787  : d(new QZipReaderPrivate(device, /*ownDevice=*/false))
788 {
789  Q_ASSERT(device);
790 }
791 
796 {
797  close();
798  delete d;
799 }
800 
805 {
806  return d->device;
807 }
808 
813 {
814  return d->device->isReadable();
815 }
816 
820 bool QZipReader::exists() const
821 {
822  QFile *f = qobject_cast<QFile*> (d->device);
823  if (f == 0)
824  return true;
825  return f->exists();
826 }
827 
832 {
833  d->scanFiles();
835  for (int i = 0; i < d->fileHeaders.size(); ++i) {
837  d->fillFileInfo(i, fi);
838  files.append(fi);
839  }
840  return files;
841 
842 }
843 
847 int QZipReader::count() const
848 {
849  d->scanFiles();
850  return d->fileHeaders.count();
851 }
852 
861 {
862  d->scanFiles();
864  if (index >= 0 && index < d->fileHeaders.count())
865  d->fillFileInfo(index, fi);
866  return fi;
867 }
868 
873 {
874  d->scanFiles();
875  int i;
876  for (i = 0; i < d->fileHeaders.size(); ++i) {
877  if (QString::fromLocal8Bit(d->fileHeaders.at(i).file_name) == fileName)
878  break;
879  }
880  if (i == d->fileHeaders.size())
881  return QByteArray();
882 
883  FileHeader header = d->fileHeaders.at(i);
884 
885  int compressed_size = readUInt(header.h.compressed_size);
886  int uncompressed_size = readUInt(header.h.uncompressed_size);
887  int start = readUInt(header.h.offset_local_header);
888  //qDebug("uncompressing file %d: local header at %d", i, start);
889 
890  d->device->seek(start);
891  LocalFileHeader lh;
892  d->device->read((char *)&lh, sizeof(LocalFileHeader));
893  uint skip = readUShort(lh.file_name_length) + readUShort(lh.extra_field_length);
894  d->device->seek(d->device->pos() + skip);
895 
896  int compression_method = readUShort(lh.compression_method);
897  //qDebug("file=%s: compressed_size=%d, uncompressed_size=%d", fileName.toLocal8Bit().data(), compressed_size, uncompressed_size);
898 
899  //qDebug("file at %lld", d->device->pos());
900  QByteArray compressed = d->device->read(compressed_size);
901  if (compression_method == 0) {
902  // no compression
903  compressed.truncate(uncompressed_size);
904  return compressed;
905  } else if (compression_method == 8) {
906  // Deflate
907  //qDebug("compressed=%d", compressed.size());
908  compressed.truncate(compressed_size);
909  QByteArray baunzip;
910  ulong len = qMax(uncompressed_size, 1);
911  int res;
912  do {
913  baunzip.resize(len);
914  res = inflate((uchar*)baunzip.data(), &len,
915  (uchar*)compressed.constData(), compressed_size);
916 
917  switch (res) {
918  case Z_OK:
919  if ((int)len != baunzip.size())
920  baunzip.resize(len);
921  break;
922  case Z_MEM_ERROR:
923  qWarning("QZip: Z_MEM_ERROR: Not enough memory");
924  break;
925  case Z_BUF_ERROR:
926  len *= 2;
927  break;
928  case Z_DATA_ERROR:
929  qWarning("QZip: Z_DATA_ERROR: Input data is corrupted");
930  break;
931  }
932  } while (res == Z_BUF_ERROR);
933  return baunzip;
934  }
935  qWarning() << "QZip: Unknown compression method";
936  return QByteArray();
937 }
938 
944 bool QZipReader::extractAll(const QString &destinationDir) const
945 {
946  QDir baseDir(destinationDir);
947 
948  // create directories first
949  QList<FileInfo> allFiles = fileInfoList();
950  foreach (FileInfo fi, allFiles) {
951  const QString absPath = destinationDir + QDir::separator() + fi.filePath;
952  if (fi.isDir) {
953  if (!baseDir.mkpath(fi.filePath))
954  return false;
955  if (!QFile::setPermissions(absPath, fi.permissions))
956  return false;
957  }
958  }
959 
960  // set up symlinks
961  foreach (FileInfo fi, allFiles) {
962  const QString absPath = destinationDir + QDir::separator() + fi.filePath;
963  if (fi.isSymLink) {
964  QString destination = QFile::decodeName(fileData(fi.filePath));
965  if (destination.isEmpty())
966  return false;
967  QFileInfo linkFi(absPath);
968  if (!QFile::exists(linkFi.absolutePath()))
969  QDir::root().mkpath(linkFi.absolutePath());
970  if (!QFile::link(destination, absPath))
971  return false;
972  /* cannot change permission of links
973  if (!QFile::setPermissions(absPath, fi.permissions))
974  return false;
975  */
976  }
977  }
978 
979  foreach (FileInfo fi, allFiles) {
980  const QString absPath = destinationDir + QDir::separator() + fi.filePath;
981  if (fi.isFile) {
982  QFile f(absPath);
983  if (!f.open(QIODevice::WriteOnly))
984  return false;
985  f.write(fileData(fi.filePath));
987  f.close();
988  }
989  }
990 
991  return true;
992 }
993 
1014 {
1015  return d->status;
1016 }
1017 
1022 {
1023  d->device->close();
1024 }
1025 
1027 
1049 QZipWriter::QZipWriter(const QString &fileName, QIODevice::OpenMode mode)
1050 {
1051  QScopedPointer<QFile> f(new QFile(fileName));
1052  f->open(mode);
1054  if (f->error() == QFile::NoError)
1055  status = QZipWriter::NoError;
1056  else {
1057  if (f->error() == QFile::WriteError)
1058  status = QZipWriter::FileWriteError;
1059  else if (f->error() == QFile::OpenError)
1060  status = QZipWriter::FileOpenError;
1061  else if (f->error() == QFile::PermissionsError)
1063  else
1064  status = QZipWriter::FileError;
1065  }
1066 
1067  d = new QZipWriterPrivate(f.data(), /*ownDevice=*/true);
1068  f.take();
1069  d->status = status;
1070 }
1071 
1078  : d(new QZipWriterPrivate(device, /*ownDevice=*/false))
1079 {
1080  Q_ASSERT(device);
1081 }
1082 
1084 {
1085  close();
1086  delete d;
1087 }
1088 
1093 {
1094  return d->device;
1095 }
1096 
1101 {
1102  return d->device->isWritable();
1103 }
1104 
1109 {
1110  QFile *f = qobject_cast<QFile*> (d->device);
1111  if (f == 0)
1112  return true;
1113  return f->exists();
1114 }
1115 
1136 {
1137  return d->status;
1138 }
1139 
1157 {
1158  d->compressionPolicy = policy;
1159 }
1160 
1167 {
1168  return d->compressionPolicy;
1169 }
1170 
1179 void QZipWriter::setCreationPermissions(QFile::Permissions permissions)
1180 {
1181  d->permissions = permissions;
1182 }
1183 
1190 QFile::Permissions QZipWriter::creationPermissions() const
1191 {
1192  return d->permissions;
1193 }
1194 
1208 {
1210 }
1211 
1220 {
1221  Q_ASSERT(device);
1222  QIODevice::OpenMode mode = device->openMode();
1223  bool opened = false;
1224  if ((mode & QIODevice::ReadOnly) == 0) {
1225  opened = true;
1226  if (! device->open(QIODevice::ReadOnly)) {
1227  d->status = FileOpenError;
1228  return;
1229  }
1230  }
1232  if (opened)
1233  device->close();
1234 }
1235 
1240 void QZipWriter::addDirectory(const QString &dirName)
1241 {
1243  // separator is mandatory
1244  if (!name.endsWith(QLatin1Char('/')))
1245  name.append(QLatin1Char('/'));
1247 }
1248 
1254 void QZipWriter::addSymLink(const QString &fileName, const QString &destination)
1255 {
1257 }
1258 
1263 {
1264  if (!(d->device->openMode() & QIODevice::WriteOnly)) {
1265  d->device->close();
1266  return;
1267  }
1268 
1269  //qDebug("QZip::close writing directory, %d entries", d->fileHeaders.size());
1271  // write new directory
1272  for (int i = 0; i < d->fileHeaders.size(); ++i) {
1273  const FileHeader &header = d->fileHeaders.at(i);
1274  d->device->write((const char *)&header.h, sizeof(CentralFileHeader));
1275  d->device->write(header.file_name);
1276  d->device->write(header.extra_field);
1277  d->device->write(header.file_comment);
1278  }
1279  int dir_size = d->device->pos() - d->start_of_directory;
1280  // write end of directory
1281  EndOfDirectory eod;
1282  memset(&eod, 0, sizeof(EndOfDirectory));
1283  writeUInt(eod.signature, 0x06054b50);
1284  //uchar this_disk[2];
1285  //uchar start_of_directory_disk[2];
1288  writeUInt(eod.directory_size, dir_size);
1291 
1292  d->device->write((const char *)&eod, sizeof(EndOfDirectory));
1293  d->device->write(d->comment);
1294  d->device->close();
1295 }
1296 
1298 
1299 #endif // QT_NO_TEXTODFWRITER
QZipReaderPrivate(QIODevice *device, bool ownDev)
Definition: qzip.cpp:433
uchar extra_field_length[2]
Definition: qzip.cpp:331
The QDir class provides access to directory structures and their contents.
Definition: qdir.h:58
T qobject_cast(QObject *object)
Definition: qobject.h:375
Status status() const
Returns a status code indicating the first error that was met by QZipReader, or QZipReader::NoError i...
Definition: qzip.cpp:1013
#define S_IWOTH
Definition: qzip.cpp:83
bool mkpath(const QString &dirPath) const
Creates the directory path dirPath.
Definition: qdir.cpp:1477
uchar dir_start_offset[4]
Definition: qzip.cpp:348
Status status() const
Returns a status code indicating the first error that was met by QZipWriter, or QZipWriter::NoError i...
Definition: qzip.cpp:1135
QIODevice * device() const
Returns device used for reading zip archive.
Definition: qzip.cpp:804
virtual qint64 size() const
For open random-access devices, this function returns the size of the device.
Definition: qiodevice.cpp:642
bool isWritable() const
Returns true if the user can write to the archive; otherwise returns false.
Definition: qzip.cpp:1100
static QString fromLocal8Bit(const char *, int size=-1)
Returns a QString initialized with the first size characters of the 8-bit string str.
Definition: qstring.cpp:4245
int type
Definition: qmetatype.cpp:239
void truncate(int pos)
Truncates the byte array at index position pos.
#define S_IRGRP
Definition: qzip.cpp:79
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
#define S_IXGRP
Definition: qzip.cpp:81
void fillFileInfo(int index, QZipReader::FileInfo &fileInfo) const
Definition: qzip.cpp:416
#define S_IFLNK
Definition: qzip.cpp:68
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
static int deflate(Bytef *dest, ulong *destLen, const Bytef *source, ulong sourceLen)
Definition: qzip.cpp:224
bool isReadable() const
Returns true if data can be read from the device; otherwise returns false.
Definition: qiodevice.cpp:544
bool isWritable() const
Returns true if data can be written to the device; otherwise returns false.
Definition: qiodevice.cpp:558
bool exists() const
Returns true if the file exists; otherwise returns false.
Definition: qzip.cpp:820
virtual void close()
First emits aboutToClose(), then closes the device and sets its OpenMode to NotOpen.
Definition: qiodevice.cpp:590
T * data() const
Returns the value of the pointer referenced by this object.
void addEntry(EntryType type, const QString &fileName, const QByteArray &contents)
Definition: qzip.cpp:568
uchar general_purpose_bits[2]
Definition: qzip.cpp:302
bool isValid() const
Definition: qzip.cpp:387
uchar crc_32[4]
Definition: qzip.cpp:327
bool open(OpenMode flags)
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition: qfile.cpp:1064
QByteArray extra_field
Definition: qzip.cpp:356
uchar file_name_length[2]
Definition: qzip.cpp:330
uchar version_needed[2]
Definition: qzip.cpp:323
QByteArray toUtf8() const Q_REQUIRED_RESULT
Returns a UTF-8 representation of the string as a QByteArray.
Definition: qstring.cpp:4074
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
Status
The following status values are possible:
Definition: qzipreader_p.h:104
#define S_IRUSR
Definition: qzip.cpp:71
T * take()
Returns the value of the pointer referenced by this object.
#define S_IXUSR
Definition: qzip.cpp:77
int month() const
Returns the number corresponding to the month of this date, using the following convention: ...
Definition: qdatetime.cpp:382
virtual qint64 pos() const
For random-access devices, this function returns the position that data is written to or read from...
Definition: qiodevice.cpp:624
CompressionPolicy compressionPolicy() const
Returns the currently set compression policy.
Definition: qzip.cpp:1166
uchar external_file_attributes[4]
Definition: qzip.cpp:335
#define S_IFREG
Definition: qzip.cpp:58
uchar last_mod_file[4]
Definition: qzip.cpp:326
void scanFiles()
Definition: qzip.cpp:479
int day() const
Returns the day of the month (1 to 31) of this date.
Definition: qdatetime.cpp:395
bool isValid() const
Returns true if both the date and the time are valid; otherwise returns false.
Definition: qdatetime.cpp:2346
The QDate class provides date functions.
Definition: qdatetime.h:55
uchar compression_method[2]
Definition: qzip.cpp:325
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
#define ZDEBUG
Definition: qzip.cpp:90
uint isFile
A boolean type, if it is one this entry is a file.
Definition: qzipreader_p.h:88
QDateTime lastModified
Definition: qzipreader_p.h:93
QString filePath
The full filepath inside the archive.
Definition: qzipreader_p.h:86
The QString class provides a Unicode character string.
Definition: qstring.h:83
void addDirectory(const QString &dirName)
Create a new directory in the archive with the specified dirName and the permissions;.
Definition: qzip.cpp:1240
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
static QChar separator()
Returns the native directory separator: "/" under Unix (including Mac OS X) and "\\" under Windows...
Definition: qdir.cpp:1831
QByteArray fileData(const QString &fileName) const
Fetch the file contents from the zip archive and return the uncompressed bytes.
Definition: qzip.cpp:872
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
static uint readUInt(const uchar *data)
Definition: qzip.cpp:95
The QScopedPointer class stores a pointer to a dynamically allocated object, and deletes it upon dest...
static QString decodeName(const QByteArray &localFileName)
This does the reverse of QFile::encodeName() using localFileName.
Definition: qfile.cpp:552
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read...
Definition: qiodevice.cpp:791
bool exists() const
Returns true if the file specified by fileName() exists; otherwise returns false. ...
Definition: qfile.cpp:626
uchar uncompressed_size[4]
Definition: qzip.cpp:307
uchar signature[4]
Definition: qzip.cpp:342
void addFile(const QString &fileName, const QByteArray &data)
Add a file to the archive with data as the file contents.
Definition: qzip.cpp:1207
unsigned char uchar
Definition: qglobal.h:994
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
Represents one entry in the zip table of contents.
Definition: qzipreader_p.h:79
QZipWriterPrivate * d
Definition: qzipwriter_p.h:109
QFile::Permissions creationPermissions() const
Returns the currently set creation permissions.
Definition: qzip.cpp:1190
the QZipReader class provides a way to inspect the contents of a zip archive and extract individual f...
Definition: qzipreader_p.h:66
The QTime class provides clock time functions.
Definition: qdatetime.h:148
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
void setCompressionPolicy(CompressionPolicy policy)
Sets the policy for compressing newly added files to the new policy.
Definition: qzip.cpp:1156
static void copyUShort(uchar *dest, const uchar *src)
Definition: qzip.cpp:127
bool isOpen() const
Returns true if the device is open; otherwise returns false.
Definition: qiodevice.cpp:530
static FILE * stream
QZipReader::Status status
Definition: qzip.cpp:440
unsigned __int64 quint64
Definition: qglobal.h:943
QFile::Permissions permissions
Definition: qzipreader_p.h:90
uchar extra_field_length[2]
Definition: qzip.cpp:309
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
static ushort readUShort(const uchar *data)
Definition: qzip.cpp:100
uchar version_made[2]
Definition: qzip.cpp:322
uchar offset_local_header[4]
Definition: qzip.cpp:336
QZipWriter::Status status
Definition: qzip.cpp:454
#define S_IXOTH
Definition: qzip.cpp:84
const char * name
QZipReader(const QString &fileName, QIODevice::OpenMode mode=QIODevice::ReadOnly)
Create a new zip archive that operates on the fileName.
Definition: qzip.cpp:758
bool exists() const
Returns true if the file exists; otherwise returns false.
Definition: qzip.cpp:1108
CentralFileHeader h
Definition: qzip.cpp:354
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
QZipWriterPrivate(QIODevice *device, bool ownDev)
Definition: qzip.cpp:446
QFile::Permissions permissions
Definition: qzip.cpp:455
bool ownDevice
Definition: qzip.cpp:409
uchar signature[4]
Definition: qzip.cpp:321
unsigned short quint16
Definition: qglobal.h:936
Q_CORE_EXPORT void qWarning(const char *,...)
quint32 qFromLittleEndian< quint32 >(const uchar *src)
Definition: qendian.h:148
qint64 size
The total size of the unpacked content.
Definition: qzipreader_p.h:92
int second() const
Returns the second part (0 to 59) of the time.
Definition: qdatetime.cpp:1600
QList< FileInfo > fileInfoList() const
Returns the list of files the archive contains.
Definition: qzip.cpp:831
#define S_IROTH
Definition: qzip.cpp:82
static const char * data(const QByteArray &arr)
unsigned int uint
Definition: qglobal.h:996
uchar compression_method[2]
Definition: qzip.cpp:303
uchar uncompressed_size[4]
Definition: qzip.cpp:329
~QZipWriter()
Definition: qzip.cpp:1083
#define S_ISREG(x)
Definition: qzip.cpp:66
uint isSymLink
A boolean type, if it is one this entry is symbolic link.
Definition: qzipreader_p.h:89
uchar compressed_size[4]
Definition: qzip.cpp:306
uchar last_mod_file[4]
Definition: qzip.cpp:304
QByteArray left(int len) const
Returns a byte array that contains the leftmost len bytes of this byte array.
int minute() const
Returns the minute part (0 to 59) of the time.
Definition: qdatetime.cpp:1589
unsigned long ulong
Definition: qglobal.h:997
static QFile::Permissions modeToPermissions(quint32 mode)
Definition: qzip.cpp:253
QIODevice * device() const
Returns device used for writing zip archive.
Definition: qzip.cpp:1092
QByteArray toLocal8Bit() const Q_REQUIRED_RESULT
Returns the local 8-bit representation of the string as a QByteArray.
Definition: qstring.cpp:4049
uchar directory_size[4]
Definition: qzip.cpp:347
static int inflate(Bytef *dest, ulong *destLen, const Bytef *source, ulong sourceLen)
Definition: qzip.cpp:189
QList< FileHeader > fileHeaders
Definition: qzip.cpp:411
int length() const
Same as size().
Definition: qbytearray.h:356
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
QDate date() const
Returns the date part of the datetime.
Definition: qdatetime.cpp:2357
uchar signature[4]
Definition: qzip.cpp:300
uint crc32
The calculated checksum as a crc32 type.
Definition: qzipreader_p.h:91
~QZipPrivate()
Definition: qzip.cpp:400
static void writeMSDosDate(uchar *dest, const QDateTime &dt)
Definition: qzip.cpp:133
QByteArray file_name
Definition: qzip.cpp:355
QString & append(QChar c)
Definition: qstring.cpp:1777
bool isReadable() const
Returns true if the user can read the file; otherwise returns false.
Definition: qzip.cpp:812
Status
The following status values are possible:
Definition: qzipwriter_p.h:77
The QDateTime class provides date and time functions.
Definition: qdatetime.h:216
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:65
void addSymLink(const QString &fileName, const QString &destination)
Create a new symbolic link in the archive with the specified dirName and the permissions; A symbolic ...
Definition: qzip.cpp:1254
bool extractAll(const QString &destinationDir) const
Extracts the full contents of the zip file into destinationDir on the local filesystem.
Definition: qzip.cpp:944
#define S_ISDIR(x)
Definition: qzip.cpp:63
QZipPrivate(QIODevice *device, bool ownDev)
Definition: qzip.cpp:395
OpenMode openMode() const
Returns the mode in which the device has been opened; i.e.
Definition: qiodevice.cpp:465
unsigned short ushort
Definition: qglobal.h:995
QZipWriter::CompressionPolicy compressionPolicy
Definition: qzip.cpp:456
static void writeUShort(uchar *data, ushort i)
Definition: qzip.cpp:113
uchar compressed_size[4]
Definition: qzip.cpp:328
void close()
Close the zip file.
Definition: qzip.cpp:1021
void resize(int size)
Sets the size of the byte array to size bytes.
uchar comment_length[2]
Definition: qzip.cpp:349
void setCreationPermissions(QFile::Permissions permissions)
Sets the permissions that will be used for newly added files.
Definition: qzip.cpp:1179
unsigned int quint32
Definition: qglobal.h:938
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
~QZipReader()
Desctructor.
Definition: qzip.cpp:795
bool setPermissions(Permissions permissionSpec)
Sets the permissions for the file to the permissions specified.
Definition: qfile.cpp:1605
static QDateTime currentDateTime()
Returns the current datetime, as reported by the system clock, in the local time zone.
Definition: qdatetime.cpp:3138
QFactoryLoader * l
QByteArray readAll()
Reads all available data from the device, and returns it as a QByteArray.
Definition: qiodevice.cpp:1025
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
static QDateTime readMSDosDate(const uchar *src)
Definition: qzip.cpp:283
virtual bool open(OpenMode mode)
Opens the device and sets its OpenMode to mode.
Definition: qiodevice.cpp:570
quint16 index
void close()
Closes the zip file.
Definition: qzip.cpp:1262
QByteArray file_comment
Definition: qzip.cpp:357
QZipWriter(const QString &fileName, QIODevice::OpenMode mode=(QIODevice::WriteOnly|QIODevice::Truncate))
Create a new zip archive that operates on the archive filename.
Definition: qzip.cpp:1049
LocalFileHeader toLocalHeader() const
Definition: qzip.cpp:463
static QByteArray encodeName(const QString &fileName)
By default, this function converts fileName to the local 8-bit encoding determined by the user&#39;s loca...
Definition: qfile.cpp:528
uchar crc_32[4]
Definition: qzip.cpp:305
int year() const
Returns the year of this date.
Definition: qdatetime.cpp:353
#define S_IWGRP
Definition: qzip.cpp:80
QTime time() const
Returns the time part of the datetime.
Definition: qdatetime.cpp:2368
QIODevice * device
Definition: qzip.cpp:408
uchar version_needed[2]
Definition: qzip.cpp:301
static QString fromNativeSeparators(const QString &pathName)
Returns pathName using &#39;/&#39; as file separator.
Definition: qdir.cpp:848
int count() const
Return the number of items in the zip archive.
Definition: qzip.cpp:847
QZipReaderPrivate * d
Definition: qzipreader_p.h:117
FileError error() const
Returns the file error status.
Definition: qfile.cpp:1984
bool dirtyFileTree
Definition: qzip.cpp:410
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
Definition: qiodevice.cpp:1342
uchar file_name_length[2]
Definition: qzip.cpp:308
uint isDir
A boolean type indicating if the entry is a directory.
Definition: qzipreader_p.h:87
#define S_ISLNK(x)
Definition: qzip.cpp:69
#define S_IFDIR
Definition: qzip.cpp:60
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition: qstring.cpp:3796
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:60
static quint32 permissionsToMode(QFile::Permissions perms)
Definition: qzip.cpp:159
uchar file_comment_length[2]
Definition: qzip.cpp:332
the QZipWriter class provides a way to create a new zip archive.
Definition: qzipwriter_p.h:64
QByteArray comment
Definition: qzip.cpp:412
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:66
virtual void close()
Calls QFile::flush() and closes the file.
Definition: qfile.cpp:1680
virtual bool seek(qint64 pos)
For random-access devices, this function sets the current position to pos, returning true on success...
Definition: qiodevice.cpp:659
static QString fileName(const QString &fileUrl)
FileInfo & operator=(const FileInfo &other)
Definition: qzip.cpp:374
QString absolutePath() const
Returns a file&#39;s path absolute path.
Definition: qfileinfo.cpp:577
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
uint start_of_directory
Definition: qzip.cpp:413
FileInfo entryInfoAt(int index) const
Returns a FileInfo of an entry in the zipfile.
Definition: qzip.cpp:860
static QDir root()
Returns the root directory.
Definition: qdir.h:214
uchar num_dir_entries_this_disk[2]
Definition: qzip.cpp:345
bool link(const QString &newName)
Creates a link named linkName that points to the file currently specified by fileName().
Definition: qfile.cpp:877
int hour() const
Returns the hour part (0 to 23) of the time.
Definition: qdatetime.cpp:1578
#define S_IWUSR
Definition: qzip.cpp:74
static void copyUInt(uchar *dest, const uchar *src)
Definition: qzip.cpp:119
static void writeUInt(uchar *data, uint i)
Definition: qzip.cpp:105
uchar num_dir_entries[2]
Definition: qzip.cpp:346