Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qzip.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qzipreader_p.h"
5#include "qzipwriter_p.h"
6
7#include <qdatetime.h>
8#include <qendian.h>
9#include <qdebug.h>
10#include <qdir.h>
11
12#include <memory>
13
14#include <zlib.h>
15
16// Zip standard version for archives handled by this API
17// (actually, the only basic support of this version is implemented but it is enough for now)
18#define ZIP_VERSION 20
19
20#if 0
21#define ZDEBUG qDebug
22#else
23#define ZDEBUG if (0) qDebug
24#endif
25
27
28static inline uint readUInt(const uchar *data)
29{
30 return (data[0]) + (data[1]<<8) + (data[2]<<16) + (data[3]<<24);
31}
32
33static inline ushort readUShort(const uchar *data)
34{
35 return (data[0]) + (data[1]<<8);
36}
37
38static inline void writeUInt(uchar *data, uint i)
39{
40 data[0] = i & 0xff;
41 data[1] = (i>>8) & 0xff;
42 data[2] = (i>>16) & 0xff;
43 data[3] = (i>>24) & 0xff;
44}
45
46static inline void writeUShort(uchar *data, ushort i)
47{
48 data[0] = i & 0xff;
49 data[1] = (i>>8) & 0xff;
50}
51
52static inline void copyUInt(uchar *dest, const uchar *src)
53{
54 dest[0] = src[0];
55 dest[1] = src[1];
56 dest[2] = src[2];
57 dest[3] = src[3];
58}
59
60static inline void copyUShort(uchar *dest, const uchar *src)
61{
62 dest[0] = src[0];
63 dest[1] = src[1];
64}
65
66static void writeMSDosDate(uchar *dest, const QDateTime& dt)
67{
68 if (dt.isValid()) {
70 (dt.time().hour() << 11) // 5 bit hour
71 | (dt.time().minute() << 5) // 6 bit minute
72 | (dt.time().second() >> 1); // 5 bit double seconds
73
74 dest[0] = time & 0xff;
75 dest[1] = time >> 8;
76
78 ((dt.date().year() - 1980) << 9) // 7 bit year 1980-based
79 | (dt.date().month() << 5) // 4 bit month
80 | (dt.date().day()); // 5 bit day
81
82 dest[2] = char(date);
83 dest[3] = char(date >> 8);
84 } else {
85 dest[0] = 0;
86 dest[1] = 0;
87 dest[2] = 0;
88 dest[3] = 0;
89 }
90}
91
92static int inflate(Bytef *dest, ulong *destLen, const Bytef *source, ulong sourceLen)
93{
94 z_stream stream;
95 int err;
96
97 stream.next_in = const_cast<Bytef*>(source);
98 stream.avail_in = (uInt)sourceLen;
99 if ((uLong)stream.avail_in != sourceLen)
100 return Z_BUF_ERROR;
101
102 stream.next_out = dest;
103 stream.avail_out = (uInt)*destLen;
104 if ((uLong)stream.avail_out != *destLen)
105 return Z_BUF_ERROR;
106
107 stream.zalloc = (alloc_func)nullptr;
108 stream.zfree = (free_func)nullptr;
109
110 err = inflateInit2(&stream, -MAX_WBITS);
111 if (err != Z_OK)
112 return err;
113
114 err = inflate(&stream, Z_FINISH);
115 if (err != Z_STREAM_END) {
116 inflateEnd(&stream);
117 if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
118 return Z_DATA_ERROR;
119 return err;
120 }
121 *destLen = stream.total_out;
122
123 err = inflateEnd(&stream);
124 return err;
125}
126
127static int deflate (Bytef *dest, ulong *destLen, const Bytef *source, ulong sourceLen)
128{
129 z_stream stream;
130 int err;
131
132 stream.next_in = const_cast<Bytef*>(source);
133 stream.avail_in = (uInt)sourceLen;
134 stream.next_out = dest;
135 stream.avail_out = (uInt)*destLen;
136 if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
137
138 stream.zalloc = (alloc_func)nullptr;
139 stream.zfree = (free_func)nullptr;
140 stream.opaque = (voidpf)nullptr;
141
142 err = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
143 if (err != Z_OK) return err;
144
145 err = deflate(&stream, Z_FINISH);
146 if (err != Z_STREAM_END) {
147 deflateEnd(&stream);
148 return err == Z_OK ? Z_BUF_ERROR : err;
149 }
150 *destLen = stream.total_out;
151
152 err = deflateEnd(&stream);
153 return err;
154}
155
156
158enum {
159 Dir = 0x10, // FILE_ATTRIBUTE_DIRECTORY
160 File = 0x80, // FILE_ATTRIBUTE_NORMAL
161 TypeMask = 0x90,
162
163 ReadOnly = 0x01, // FILE_ATTRIBUTE_READONLY
164 PermMask = 0x01
166}
167
169enum {
170 Dir = 0040000, // __S_IFDIR
171 File = 0100000, // __S_IFREG
172 SymLink = 0120000, // __S_IFLNK
173 TypeMask = 0170000, // __S_IFMT
174
175 ReadUser = 0400, // __S_IRUSR
176 WriteUser = 0200, // __S_IWUSR
177 ExeUser = 0100, // __S_IXUSR
178 ReadGroup = 0040, // __S_IRGRP
179 WriteGroup = 0020, // __S_IWGRP
180 ExeGroup = 0010, // __S_IXGRP
181 ReadOther = 0004, // __S_IROTH
182 WriteOther = 0002, // __S_IWOTH
183 ExeOther = 0001, // __S_IXOTH
184 PermMask = 0777
186}
187
211
235
237{
238 uint dosDate = readUInt(src);
239 quint64 uDate;
240 uDate = (quint64)(dosDate >> 16);
241 uint tm_mday = (uDate & 0x1f);
242 uint tm_mon = ((uDate & 0x1E0) >> 5);
243 uint tm_year = (((uDate & 0x0FE00) >> 9) + 1980);
244 uint tm_hour = ((dosDate & 0xF800) >> 11);
245 uint tm_min = ((dosDate & 0x7E0) >> 5);
246 uint tm_sec = ((dosDate & 0x1f) << 1);
247
248 return QDateTime(QDate(tm_year, tm_mon, tm_mday), QTime(tm_hour, tm_min, tm_sec));
249}
250
251// for details, see http://www.pkware.com/documents/casestudies/APPNOTE.TXT
252
253enum HostOS {
256 HostVMS = 2, // VAX/VMS
259 HostAtari = 5, // what if it's a minix filesystem? [cjh]
260 HostHPFS = 6, // filesystem used by OS/2 (and NT 3.x)
264 HostTOPS20 = 10, // pkzip 2.50 NTFS
265 HostNTFS = 11, // filesystem used by Windows NT
266 HostQDOS = 12, // SMS/QDOS
267 HostAcorn = 13, // Archimedes Acorn RISC OS
268 HostVFAT = 14, // filesystem used by Windows 95, NT
270 HostBeOS = 16, // hybrid POSIX/database filesystem
273 HostOSX = 19
276
288
315
330
338
359
372
381
383{
384public:
387 {
388 }
389
391 {
392 if (ownDevice)
393 delete device;
394 }
395
397
401 QList<FileHeader> fileHeaders;
404};
405
407{
408 QZipReader::FileInfo fileInfo;
410 quint32 mode = readUInt(header.h.external_file_attributes);
411 const HostOS hostOS = HostOS(readUShort(header.h.version_made) >> 8);
412 switch (hostOS) {
413 case HostUnix:
414 mode = (mode >> 16) & 0xffff;
417 fileInfo.isSymLink = true;
418 break;
420 fileInfo.isDir = true;
421 break;
423 default: // ### just for the case; should we warn?
424 fileInfo.isFile = true;
425 break;
426 }
428 break;
429 case HostFAT:
430 case HostNTFS:
431 case HostHPFS:
432 case HostVFAT:
435 fileInfo.isDir = true;
436 break;
438 default:
439 fileInfo.isFile = true;
440 break;
441 }
445 if (fileInfo.isDir)
447 break;
448 default:
449 qWarning("QZip: Zip entry format at %d is not supported.", index);
450 return fileInfo; // we don't support anything else
451 }
452
453 ushort general_purpose_bits = readUShort(header.h.general_purpose_bits);
454 // if bit 11 is set, the filename and comment fields must be encoded using UTF-8
455 const bool inUtf8 = (general_purpose_bits & Utf8Names) != 0;
456 fileInfo.filePath = inUtf8 ? QString::fromUtf8(header.file_name) : QString::fromLocal8Bit(header.file_name);
457 fileInfo.crc = readUInt(header.h.crc_32);
458 fileInfo.size = readUInt(header.h.uncompressed_size);
459 fileInfo.lastModified = readMSDosDate(header.h.last_mod_file);
460
461 // fix the file path, if broken (convert separators, eat leading and trailing ones)
462 fileInfo.filePath = QDir::fromNativeSeparators(fileInfo.filePath);
463 QStringView filePathRef(fileInfo.filePath);
464 while (filePathRef.startsWith(u'.') || filePathRef.startsWith(u'/'))
465 filePathRef = filePathRef.mid(1);
466 while (filePathRef.endsWith(u'/'))
467 filePathRef.chop(1);
468
469 fileInfo.filePath = filePathRef.toString();
470 return fileInfo;
471}
472
474{
475public:
478 {
479 }
480
481 void scanFiles();
482
484};
485
487{
488public:
490 : QZipPrivate(device, ownDev),
492 permissions(QFile::ReadOwner | QFile::WriteOwner),
493 compressionPolicy(QZipWriter::AlwaysCompress)
494 {
495 }
496
498 QFile::Permissions permissions;
500
502
504};
505
507{
509 writeUInt(h.signature, 0x04034b50);
510 copyUShort(h.version_needed, ch.version_needed);
511 copyUShort(h.general_purpose_bits, ch.general_purpose_bits);
512 copyUShort(h.compression_method, ch.compression_method);
513 copyUInt(h.last_mod_file, ch.last_mod_file);
514 copyUInt(h.crc_32, ch.crc_32);
515 copyUInt(h.compressed_size, ch.compressed_size);
516 copyUInt(h.uncompressed_size, ch.uncompressed_size);
517 copyUShort(h.file_name_length, ch.file_name_length);
518 copyUShort(h.extra_field_length, ch.extra_field_length);
519 return h;
520}
521
523{
524 if (!dirtyFileTree)
525 return;
526
527 if (! (device->isOpen() || device->open(QIODevice::ReadOnly))) {
529 return;
530 }
531
532 if ((device->openMode() & QIODevice::ReadOnly) == 0) { // only read the index from readable files.
534 return;
535 }
536
537 dirtyFileTree = false;
538 uchar tmp[4];
539 device->read((char *)tmp, 4);
540 if (readUInt(tmp) != 0x04034b50) {
541 qWarning("QZip: not a zip file!");
542 return;
543 }
544
545 // find EndOfDirectory header
546 int i = 0;
547 int start_of_directory = -1;
548 int num_dir_entries = 0;
549 EndOfDirectory eod;
550 while (start_of_directory == -1) {
551 const int pos = device->size() - int(sizeof(EndOfDirectory)) - i;
552 if (pos < 0 || i > 65535) {
553 qWarning("QZip: EndOfDirectory not found");
554 return;
555 }
556
557 device->seek(pos);
558 device->read((char *)&eod, sizeof(EndOfDirectory));
559 if (readUInt(eod.signature) == 0x06054b50)
560 break;
561 ++i;
562 }
563
564 // have the eod
565 start_of_directory = readUInt(eod.dir_start_offset);
566 num_dir_entries = readUShort(eod.num_dir_entries);
567 ZDEBUG("start_of_directory at %d, num_dir_entries=%d", start_of_directory, num_dir_entries);
568 int comment_length = readUShort(eod.comment_length);
569 if (comment_length != i)
570 qWarning("QZip: failed to parse zip file.");
571 comment = device->read(qMin(comment_length, i));
572
573
575 for (i = 0; i < num_dir_entries; ++i) {
577 int read = device->read((char *) &header.h, sizeof(CentralFileHeader));
578 if (read < (int)sizeof(CentralFileHeader)) {
579 qWarning("QZip: Failed to read complete header, index may be incomplete");
580 break;
581 }
582 if (readUInt(header.h.signature) != 0x02014b50) {
583 qWarning("QZip: invalid header signature, index may be incomplete");
584 break;
585 }
586
587 int l = readUShort(header.h.file_name_length);
588 header.file_name = device->read(l);
589 if (header.file_name.size() != l) {
590 qWarning("QZip: Failed to read filename from zip index, index may be incomplete");
591 break;
592 }
593 l = readUShort(header.h.extra_field_length);
594 header.extra_field = device->read(l);
595 if (header.extra_field.size() != l) {
596 qWarning("QZip: Failed to read extra field in zip file, skipping file, index may be incomplete");
597 break;
598 }
599 l = readUShort(header.h.file_comment_length);
600 header.file_comment = device->read(l);
601 if (header.file_comment.size() != l) {
602 qWarning("QZip: Failed to read read file comment, index may be incomplete");
603 break;
604 }
605
606 ZDEBUG("found file '%s'", header.file_name.data());
608 }
609}
610
611void QZipWriterPrivate::addEntry(EntryType type, const QString &fileName, const QByteArray &contents/*, QFile::Permissions permissions, QZip::Method m*/)
612{
613#ifndef NDEBUG
614 static const char *const entryTypes[] = {
615 "directory",
616 "file ",
617 "symlink " };
618 ZDEBUG() << "adding" << entryTypes[type] <<":" << fileName.toUtf8().data() << (type == 2 ? QByteArray(" -> " + contents).constData() : "");
619#endif
620
621 if (! (device->isOpen() || device->open(QIODevice::WriteOnly))) {
623 return;
624 }
626
627 // don't compress small files
630 if (contents.size() < 64)
631 compression = QZipWriter::NeverCompress;
632 else
633 compression = QZipWriter::AlwaysCompress;
634 }
635
637 memset(&header.h, 0, sizeof(CentralFileHeader));
638 writeUInt(header.h.signature, 0x02014b50);
639
640 writeUShort(header.h.version_needed, ZIP_VERSION);
641 writeUInt(header.h.uncompressed_size, contents.size());
644 if (compression == QZipWriter::AlwaysCompress) {
645 writeUShort(header.h.compression_method, CompressionMethodDeflated);
646
647 ulong len = contents.size();
648 // shamelessly copied form zlib
649 len += (len >> 12) + (len >> 14) + 11;
650 int res;
651 do {
652 data.resize(len);
653 res = deflate((uchar*)data.data(), &len, (const uchar*)contents.constData(), contents.size());
654
655 switch (res) {
656 case Z_OK:
657 data.resize(len);
658 break;
659 case Z_MEM_ERROR:
660 qWarning("QZip: Z_MEM_ERROR: Not enough memory to compress file, skipping");
661 data.resize(0);
662 break;
663 case Z_BUF_ERROR:
664 len *= 2;
665 break;
666 }
667 } while (res == Z_BUF_ERROR);
668 }
669// TODO add a check if data.length() > contents.length(). Then try to store the original and revert the compression method to be uncompressed
670 writeUInt(header.h.compressed_size, data.size());
671 uint crc_32 = ::crc32(0, nullptr, 0);
672 crc_32 = ::crc32(crc_32, (const uchar *)contents.constData(), contents.size());
673 writeUInt(header.h.crc_32, crc_32);
674
675 // if bit 11 is set, the filename and comment fields must be encoded using UTF-8
676 ushort general_purpose_bits = Utf8Names; // always use utf-8
677 writeUShort(header.h.general_purpose_bits, general_purpose_bits);
678
679 const bool inUtf8 = (general_purpose_bits & Utf8Names) != 0;
680 header.file_name = inUtf8 ? fileName.toUtf8() : fileName.toLocal8Bit();
681 if (header.file_name.size() > 0xffff) {
682 qWarning("QZip: Filename is too long, chopping it to 65535 bytes");
683 header.file_name = header.file_name.left(0xffff); // ### don't break the utf-8 sequence, if any
684 }
685 if (header.file_comment.size() + header.file_name.size() > 0xffff) {
686 qWarning("QZip: File comment is too long, chopping it to 65535 bytes");
687 header.file_comment.truncate(0xffff - header.file_name.size()); // ### don't break the utf-8 sequence, if any
688 }
689 writeUShort(header.h.file_name_length, header.file_name.size());
690 //h.extra_field_length[2];
691
692 writeUShort(header.h.version_made, HostUnix << 8);
693 //uchar internal_file_attributes[2];
694 //uchar external_file_attributes[4];
696 switch (type) {
697 case Symlink:
699 break;
700 case Directory:
702 break;
703 case File:
705 break;
706 default:
707 Q_UNREACHABLE();
708 break;
709 }
710 writeUInt(header.h.external_file_attributes, mode << 16);
711 writeUInt(header.h.offset_local_header, start_of_directory);
712
713
715
717 device->write((const char *)&h, sizeof(LocalFileHeader));
718 device->write(header.file_name);
719 device->write(data);
721 dirtyFileTree = true;
722}
723
725
786QZipReader::QZipReader(const QString &archive, QIODevice::OpenMode mode)
787{
788 auto f = std::make_unique<QFile>(archive);
789 const bool result = f->open(mode);
791 const QFileDevice::FileError error = f->error();
792 if (result && error == QFile::NoError) {
793 status = NoError;
794 } else {
795 if (error == QFile::ReadError)
797 else if (error == QFile::OpenError)
799 else if (error == QFile::PermissionsError)
801 else
803 }
804
805 d = new QZipReaderPrivate(f.get(), /*ownDevice=*/true);
806 Q_UNUSED(f.release());
807 d->status = status;
808}
809
820
825{
826 close();
827 delete d;
828}
829
834{
835 return d->device;
836}
837
842{
843 return d->device->isReadable();
844}
845
850{
851 QFile *f = qobject_cast<QFile*> (d->device);
852 if (f == nullptr)
853 return true;
854 return f->exists();
855}
856
860QList<QZipReader::FileInfo> QZipReader::fileInfoList() const
861{
862 d->scanFiles();
863 QList<FileInfo> files;
864 const int numFileHeaders = d->fileHeaders.size();
865 files.reserve(numFileHeaders);
866 for (int i = 0; i < numFileHeaders; ++i)
867 files.append(d->fillFileInfo(i));
868 return files;
869
870}
871
876{
877 d->scanFiles();
878 return d->fileHeaders.size();
879}
880
889{
890 d->scanFiles();
891 if (index >= 0 && index < d->fileHeaders.size())
892 return d->fillFileInfo(index);
893 return QZipReader::FileInfo();
894}
895
900{
901 d->scanFiles();
902 int i;
903 for (i = 0; i < d->fileHeaders.size(); ++i) {
905 break;
906 }
907 if (i == d->fileHeaders.size())
908 return QByteArray();
909
911
912 ushort version_needed = readUShort(header.h.version_needed);
913 if (version_needed > ZIP_VERSION) {
914 qWarning("QZip: .ZIP specification version %d implementationis needed to extract the data.", version_needed);
915 return QByteArray();
916 }
917
918 ushort general_purpose_bits = readUShort(header.h.general_purpose_bits);
919 int compressed_size = readUInt(header.h.compressed_size);
920 int uncompressed_size = readUInt(header.h.uncompressed_size);
921 int start = readUInt(header.h.offset_local_header);
922 //qDebug("uncompressing file %d: local header at %d", i, start);
923
924 d->device->seek(start);
926 d->device->read((char *)&lh, sizeof(LocalFileHeader));
927 uint skip = readUShort(lh.file_name_length) + readUShort(lh.extra_field_length);
928 d->device->seek(d->device->pos() + skip);
929
930 int compression_method = readUShort(lh.compression_method);
931 //qDebug("file=%s: compressed_size=%d, uncompressed_size=%d", fileName.toLocal8Bit().data(), compressed_size, uncompressed_size);
932
933 if ((general_purpose_bits & Encrypted) != 0) {
934 qWarning("QZip: Unsupported encryption method is needed to extract the data.");
935 return QByteArray();
936 }
937
938 //qDebug("file at %lld", d->device->pos());
939 QByteArray compressed = d->device->read(compressed_size);
940 if (compression_method == CompressionMethodStored) {
941 // no compression
942 compressed.truncate(uncompressed_size);
943 return compressed;
944 } else if (compression_method == CompressionMethodDeflated) {
945 // Deflate
946 //qDebug("compressed=%d", compressed.size());
947 compressed.truncate(compressed_size);
948 QByteArray baunzip;
949 ulong len = qMax(uncompressed_size, 1);
950 int res;
951 do {
952 baunzip.resize(len);
953 res = inflate((uchar*)baunzip.data(), &len,
954 (const uchar*)compressed.constData(), compressed_size);
955
956 switch (res) {
957 case Z_OK:
958 if ((int)len != baunzip.size())
959 baunzip.resize(len);
960 break;
961 case Z_MEM_ERROR:
962 qWarning("QZip: Z_MEM_ERROR: Not enough memory");
963 break;
964 case Z_BUF_ERROR:
965 len *= 2;
966 break;
967 case Z_DATA_ERROR:
968 qWarning("QZip: Z_DATA_ERROR: Input data is corrupted");
969 break;
970 }
971 } while (res == Z_BUF_ERROR);
972 return baunzip;
973 }
974
975 qWarning("QZip: Unsupported compression method %d is needed to extract the data.", compression_method);
976 return QByteArray();
977}
978
984bool QZipReader::extractAll(const QString &destinationDir) const
985{
986 QDir baseDir(destinationDir);
987
988 // create directories first
989 const QList<FileInfo> allFiles = fileInfoList();
990 bool foundDirs = false;
991 bool hasDirs = false;
992 for (const FileInfo &fi : allFiles) {
993 const QString absPath = destinationDir + QDir::separator() + fi.filePath;
994 if (fi.isDir) {
995 foundDirs = true;
996 if (!baseDir.mkpath(fi.filePath))
997 return false;
998 if (!QFile::setPermissions(absPath, fi.permissions))
999 return false;
1000 } else if (!hasDirs && fi.filePath.contains(u"/")) {
1001 // filePath does not have leading or trailing '/', so if we find
1002 // one, than the file path contains directories.
1003 hasDirs = true;
1004 }
1005 }
1006
1007 // Some zip archives can be broken in the sense that they do not report
1008 // separate entries for directories, only for files. In this case we
1009 // need to recreate directory structure based on the file paths.
1010 if (hasDirs && !foundDirs) {
1011 for (const FileInfo &fi : allFiles) {
1012 const auto dirPath = fi.filePath.left(fi.filePath.lastIndexOf(u"/"));
1013 if (!baseDir.mkpath(dirPath))
1014 return false;
1015 // We will leave the directory permissions default in this case,
1016 // because setting dir permissions based on file is incorrect
1017 }
1018 }
1019
1020 // set up symlinks
1021 for (const FileInfo &fi : allFiles) {
1022 const QString absPath = destinationDir + QDir::separator() + fi.filePath;
1023 if (fi.isSymLink) {
1025 if (destination.isEmpty())
1026 return false;
1027 QFileInfo linkFi(absPath);
1028 if (!QFile::exists(linkFi.absolutePath()))
1029 QDir::root().mkpath(linkFi.absolutePath());
1030 if (!QFile::link(destination, absPath))
1031 return false;
1032 /* cannot change permission of links
1033 if (!QFile::setPermissions(absPath, fi.permissions))
1034 return false;
1035 */
1036 }
1037 }
1038
1039 for (const FileInfo &fi : allFiles) {
1040 const QString absPath = destinationDir + QDir::separator() + fi.filePath;
1041 if (fi.isFile) {
1042 QFile f(absPath);
1043 if (!f.open(QIODevice::WriteOnly))
1044 return false;
1045 f.write(fileData(fi.filePath));
1046 f.setPermissions(fi.permissions);
1047 f.close();
1048 }
1049 }
1050
1051 return true;
1052}
1053
1071{
1072 return d->status;
1073}
1074
1079{
1080 d->device->close();
1081}
1082
1084
1103QZipWriter::QZipWriter(const QString &fileName, QIODevice::OpenMode mode)
1104{
1105 auto f = std::make_unique<QFile>(fileName);
1107 if (f->open(mode) && f->error() == QFile::NoError)
1109 else {
1110 if (f->error() == QFile::WriteError)
1112 else if (f->error() == QFile::OpenError)
1114 else if (f->error() == QFile::PermissionsError)
1116 else
1118 }
1119
1120 d = new QZipWriterPrivate(f.get(), /*ownDevice=*/true);
1121 Q_UNUSED(f.release());
1122 d->status = status;
1123}
1124
1131 : d(new QZipWriterPrivate(device, /*ownDevice=*/false))
1132{
1134}
1135
1137{
1138 close();
1139 delete d;
1140}
1141
1146{
1147 return d->device;
1148}
1149
1154{
1155 return d->device->isWritable();
1156}
1157
1162{
1163 QFile *f = qobject_cast<QFile*> (d->device);
1164 if (f == nullptr)
1165 return true;
1166 return f->exists();
1167}
1168
1186{
1187 return d->status;
1188}
1189
1210
1220
1229void QZipWriter::setCreationPermissions(QFile::Permissions permissions)
1230{
1231 d->permissions = permissions;
1232}
1233
1240QFile::Permissions QZipWriter::creationPermissions() const
1241{
1242 return d->permissions;
1243}
1244
1261
1270{
1272 QIODevice::OpenMode mode = device->openMode();
1273 bool opened = false;
1274 if ((mode & QIODevice::ReadOnly) == 0) {
1275 opened = true;
1277 d->status = FileOpenError;
1278 return;
1279 }
1280 }
1282 if (opened)
1283 device->close();
1284}
1285
1291{
1293 // separator is mandatory
1294 if (!name.endsWith(u'/'))
1295 name.append(u'/');
1297}
1298
1308
1313{
1314 if (!(d->device->openMode() & QIODevice::WriteOnly)) {
1315 d->device->close();
1316 return;
1317 }
1318
1319 //qDebug("QZip::close writing directory, %d entries", d->fileHeaders.size());
1321 // write new directory
1322 for (int i = 0; i < d->fileHeaders.size(); ++i) {
1323 const FileHeader &header = d->fileHeaders.at(i);
1324 d->device->write((const char *)&header.h, sizeof(CentralFileHeader));
1325 d->device->write(header.file_name);
1326 d->device->write(header.extra_field);
1327 d->device->write(header.file_comment);
1328 }
1329 int dir_size = d->device->pos() - d->start_of_directory;
1330 // write end of directory
1331 EndOfDirectory eod;
1332 memset(&eod, 0, sizeof(EndOfDirectory));
1333 writeUInt(eod.signature, 0x06054b50);
1334 //uchar this_disk[2];
1335 //uchar start_of_directory_disk[2];
1336 writeUShort(eod.num_dir_entries_this_disk, d->fileHeaders.size());
1337 writeUShort(eod.num_dir_entries, d->fileHeaders.size());
1338 writeUInt(eod.directory_size, dir_size);
1339 writeUInt(eod.dir_start_offset, d->start_of_directory);
1340 writeUShort(eod.comment_length, d->comment.size());
1341
1342 d->device->write((const char *)&eod, sizeof(EndOfDirectory));
1343 d->device->write(d->comment);
1344 d->device->close();
1345}
1346
IOBluetoothDevice * device
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
void truncate(qsizetype pos)
Truncates the byte array at index position pos.
\inmodule QtCore\reentrant
Definition qdatetime.h:283
static QDateTime currentDateTime()
This is an overloaded member function, provided for convenience. It differs from the above function o...
\inmodule QtCore \reentrant
Definition qdatetime.h:29
\inmodule QtCore
Definition qdir.h:20
static QString fromNativeSeparators(const QString &pathName)
Definition qdir.cpp:962
static QDir root()
Returns the root directory.
Definition qdir.h:224
static QChar separator()
Returns the native directory separator: "/" under Unix and "\\" under Windows.
Definition qdir.h:209
FileError
This enum describes the errors that may be returned by the error() function.
Definition qfiledevice.h:39
\inmodule QtCore
Definition qfile.h:93
bool setPermissions(Permissions permissionSpec) override
Sets the permissions for the file to the permissions specified.
Definition qfile.cpp:1159
bool link(const QString &newName)
Creates a link named linkName that points to the file currently specified by fileName().
Definition qfile.cpp:720
static QByteArray encodeName(const QString &fileName)
Converts fileName to an 8-bit encoding that you can use in native APIs.
Definition qfile.h:158
static QString decodeName(const QByteArray &localFileName)
This does the reverse of QFile::encodeName() using localFileName.
Definition qfile.h:162
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qfile.cpp:351
\inmodule QtCore \reentrant
Definition qiodevice.h:34
virtual bool open(QIODeviceBase::OpenMode mode)
Opens the device and sets its OpenMode to mode.
virtual qint64 size() const
For open random-access devices, this function returns the size of the device.
virtual qint64 pos() const
For random-access devices, this function returns the position that data is written to or read from.
bool isOpen() const
Returns true if the device is open; otherwise returns false.
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
bool isReadable() const
Returns true if data can be read from the device; otherwise returns false.
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
QIODeviceBase::OpenMode openMode() const
Returns the mode in which the device has been opened; i.e.
bool isWritable() const
Returns true if data can be written to the device; otherwise returns false.
virtual void close()
First emits aboutToClose(), then closes the device and sets its OpenMode to NotOpen.
virtual bool seek(qint64 pos)
For random-access devices, this function sets the current position to pos, returning true on success,...
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read.
qsizetype size() const noexcept
Definition qlist.h:397
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void append(parameter_type t)
Definition qlist.h:458
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5949
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
\inmodule QtCore \reentrant
Definition qdatetime.h:215
QIODevice * device
Definition qzip.cpp:398
QZipReader::FileInfo fillFileInfo(int index) const
Definition qzip.cpp:406
~QZipPrivate()
Definition qzip.cpp:390
QByteArray comment
Definition qzip.cpp:402
uint start_of_directory
Definition qzip.cpp:403
QZipPrivate(QIODevice *device, bool ownDev)
Definition qzip.cpp:385
bool ownDevice
Definition qzip.cpp:399
bool dirtyFileTree
Definition qzip.cpp:400
QList< FileHeader > fileHeaders
Definition qzip.cpp:401
void scanFiles()
Definition qzip.cpp:522
QZipReader::Status status
Definition qzip.cpp:483
QZipReaderPrivate(QIODevice *device, bool ownDev)
Definition qzip.cpp:476
\variable QZipReader::FileInfo::filePath The full filepath inside the archive.
FileInfo entryInfoAt(int index) const
Returns a FileInfo of an entry in the zipfile.
Definition qzip.cpp:888
QList< FileInfo > fileInfoList() const
Returns the list of files the archive contains.
Definition qzip.cpp:860
void close()
Close the zip file.
Definition qzip.cpp:1078
QIODevice * device() const
Returns device used for reading zip archive.
Definition qzip.cpp:833
bool exists() const
Returns true if the file exists; otherwise returns false.
Definition qzip.cpp:849
QZipReader(const QString &fileName, QIODevice::OpenMode mode=QIODevice::ReadOnly)
Create a new zip archive that operates on the fileName.
Definition qzip.cpp:786
bool isReadable() const
Returns true if the user can read the file; otherwise returns false.
Definition qzip.cpp:841
~QZipReader()
Destructor.
Definition qzip.cpp:824
Status status() const
Returns a status code indicating the first error that was met by QZipReader, or QZipReader::NoError i...
Definition qzip.cpp:1070
Status
The following status values are possible:
@ FilePermissionsError
QByteArray fileData(const QString &fileName) const
Fetch the file contents from the zip archive and return the uncompressed bytes.
Definition qzip.cpp:899
bool extractAll(const QString &destinationDir) const
Extracts the full contents of the zip file into destinationDir on the local filesystem.
Definition qzip.cpp:984
int count() const
Return the number of items in the zip archive.
Definition qzip.cpp:875
void addEntry(EntryType type, const QString &fileName, const QByteArray &contents)
Definition qzip.cpp:611
QFile::Permissions permissions
Definition qzip.cpp:498
QZipWriterPrivate(QIODevice *device, bool ownDev)
Definition qzip.cpp:489
QZipWriter::Status status
Definition qzip.cpp:497
QZipWriter::CompressionPolicy compressionPolicy
Definition qzip.cpp:499
the QZipWriter class provides a way to create a new zip archive.
void addDirectory(const QString &dirName)
Create a new directory in the archive with the specified dirName and the permissions;.
Definition qzip.cpp:1290
QIODevice * device() const
Returns device used for writing zip archive.
Definition qzip.cpp:1145
void setCreationPermissions(QFile::Permissions permissions)
Sets the permissions that will be used for newly added files.
Definition qzip.cpp:1229
void addFile(const QString &fileName, const QByteArray &data)
Add a file to the archive with data as the file contents.
Definition qzip.cpp:1257
bool isWritable() const
Returns true if the user can write to the archive; otherwise returns false.
Definition qzip.cpp:1153
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:1103
void close()
Closes the zip file.
Definition qzip.cpp:1312
QFile::Permissions creationPermissions() const
Returns the currently set creation permissions.
Definition qzip.cpp:1240
void setCompressionPolicy(CompressionPolicy policy)
Sets the policy for compressing newly added files to the new policy.
Definition qzip.cpp:1206
Status status() const
Returns a status code indicating the first error that was met by QZipWriter, or QZipWriter::NoError i...
Definition qzip.cpp:1185
Status
The following status values are possible:
@ FilePermissionsError
CompressionPolicy
\value AlwaysCompress A file that is added is compressed.
~QZipWriter()
Definition qzip.cpp:1136
bool exists() const
Returns true if the file exists; otherwise returns false.
Definition qzip.cpp:1161
CompressionPolicy compressionPolicy() const
Returns the currently set compression policy.
Definition qzip.cpp:1216
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:1304
QDate date
[1]
Combined button and popup list for selecting options.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char * destination
DBusConnection const char DBusError * error
static QString header(const QString &name)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLStreamKHR stream
#define qWarning
Definition qlogging.h:166
return ret
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLenum mode
GLuint index
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLenum src
GLenum type
GLuint start
GLuint name
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
GLuint res
GLuint64EXT * result
[6]
GLenum GLsizei len
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
@ NoError
Definition main.cpp:34
#define Q_UNUSED(x)
@ Q_PRIMITIVE_TYPE
Definition qtypeinfo.h:157
@ Q_RELOCATABLE_TYPE
Definition qtypeinfo.h:158
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
Definition qtypeinfo.h:180
unsigned int quint32
Definition qtypes.h:50
unsigned char uchar
Definition qtypes.h:32
unsigned short quint16
Definition qtypes.h:48
unsigned long ulong
Definition qtypes.h:35
unsigned long long quint64
Definition qtypes.h:61
unsigned int uint
Definition qtypes.h:34
unsigned short ushort
Definition qtypes.h:33
ReturnedValue read(const char *data)
#define ZIP_VERSION
Definition qzip.cpp:18
static QFile::Permissions modeToPermissions(quint32 mode)
Definition qzip.cpp:188
static void copyUShort(uchar *dest, const uchar *src)
Definition qzip.cpp:60
static QT_BEGIN_NAMESPACE uint readUInt(const uchar *data)
Definition qzip.cpp:28
static void copyUInt(uchar *dest, const uchar *src)
Definition qzip.cpp:52
CompressionMethod
Definition qzip.cpp:289
@ CompressionMethodReduced1
Definition qzip.cpp:292
@ CompressionMethodReduced4
Definition qzip.cpp:295
@ CompressionMethodReduced3
Definition qzip.cpp:294
@ CompressionMethodJpeg
Definition qzip.cpp:309
@ CompressionMethodPPMd
Definition qzip.cpp:311
@ CompressionMethodDeflated
Definition qzip.cpp:298
@ CompressionMethodPKImploding
Definition qzip.cpp:300
@ CompressionMethodShrunk
Definition qzip.cpp:291
@ CompressionMethodReduced2
Definition qzip.cpp:293
@ CompressionMethodTerse
Definition qzip.cpp:306
@ CompressionMethodStored
Definition qzip.cpp:290
@ CompressionMethodReservedTokenizing
Definition qzip.cpp:297
@ CompressionMethodDeflated64
Definition qzip.cpp:299
@ CompressionMethodLZMA
Definition qzip.cpp:304
@ CompressionMethodWavPack
Definition qzip.cpp:310
@ CompressionMethodImploded
Definition qzip.cpp:296
@ CompressionMethodBZip2
Definition qzip.cpp:302
@ CompressionMethodWzAES
Definition qzip.cpp:312
@ CompressionMethodLz77
Definition qzip.cpp:307
static void writeUInt(uchar *data, uint i)
Definition qzip.cpp:38
static QDateTime readMSDosDate(const uchar *src)
Definition qzip.cpp:236
#define ZDEBUG
Definition qzip.cpp:23
static void writeMSDosDate(uchar *dest, const QDateTime &dt)
Definition qzip.cpp:66
static LocalFileHeader toLocalHeader(const CentralFileHeader &ch)
Definition qzip.cpp:506
HostOS
Definition qzip.cpp:253
@ HostOS400
Definition qzip.cpp:272
@ HostBeOS
Definition qzip.cpp:270
@ HostMVS
Definition qzip.cpp:269
@ HostZ_System
Definition qzip.cpp:262
@ HostOSX
Definition qzip.cpp:273
@ HostVFAT
Definition qzip.cpp:268
@ HostQDOS
Definition qzip.cpp:266
@ HostTOPS20
Definition qzip.cpp:264
@ HostAcorn
Definition qzip.cpp:267
@ HostHPFS
Definition qzip.cpp:260
@ HostMac
Definition qzip.cpp:261
@ HostAMIGA
Definition qzip.cpp:255
@ HostVM_CMS
Definition qzip.cpp:258
@ HostTandem
Definition qzip.cpp:271
@ HostUnix
Definition qzip.cpp:257
@ HostAtari
Definition qzip.cpp:259
@ HostVMS
Definition qzip.cpp:256
@ HostNTFS
Definition qzip.cpp:265
@ HostFAT
Definition qzip.cpp:254
@ HostCPM
Definition qzip.cpp:263
static quint32 permissionsToMode(QFile::Permissions perms)
Definition qzip.cpp:212
static void writeUShort(uchar *data, ushort i)
Definition qzip.cpp:46
GeneralPurposeFlag
Definition qzip.cpp:277
@ HasDataDescriptor
Definition qzip.cpp:281
@ PatchedData
Definition qzip.cpp:282
@ Utf8Names
Definition qzip.cpp:284
@ StrongEncrypted
Definition qzip.cpp:283
@ AlgTune1
Definition qzip.cpp:279
@ CentralDirectoryEncrypted
Definition qzip.cpp:285
@ AlgTune2
Definition qzip.cpp:280
@ Encrypted
Definition qzip.cpp:278
static int inflate(Bytef *dest, ulong *destLen, const Bytef *source, ulong sourceLen)
Definition qzip.cpp:92
static int deflate(Bytef *dest, ulong *destLen, const Bytef *source, ulong sourceLen)
Definition qzip.cpp:127
static ushort readUShort(const uchar *data)
Definition qzip.cpp:33
QByteArray compressed
QStringList files
[8]
QSizePolicy policy
uchar external_file_attributes[4]
Definition qzip.cpp:355
uchar extra_field_length[2]
Definition qzip.cpp:351
uchar compression_method[2]
Definition qzip.cpp:345
uchar uncompressed_size[4]
Definition qzip.cpp:349
uchar compressed_size[4]
Definition qzip.cpp:348
uchar file_comment_length[2]
Definition qzip.cpp:352
uchar disk_start[2]
Definition qzip.cpp:353
uchar crc_32[4]
Definition qzip.cpp:347
uchar version_needed[2]
Definition qzip.cpp:343
uchar version_made[2]
Definition qzip.cpp:342
uchar general_purpose_bits[2]
Definition qzip.cpp:344
uchar last_mod_file[4]
Definition qzip.cpp:346
uchar file_name_length[2]
Definition qzip.cpp:350
uchar offset_local_header[4]
Definition qzip.cpp:356
uchar signature[4]
Definition qzip.cpp:341
uchar internal_file_attributes[2]
Definition qzip.cpp:354
uchar uncompressed_size[4]
Definition qzip.cpp:335
uchar crc_32[4]
Definition qzip.cpp:333
uchar compressed_size[4]
Definition qzip.cpp:334
uchar start_of_directory_disk[2]
Definition qzip.cpp:364
uchar num_dir_entries[2]
Definition qzip.cpp:366
uchar signature[4]
Definition qzip.cpp:362
uchar directory_size[4]
Definition qzip.cpp:367
uchar this_disk[2]
Definition qzip.cpp:363
uchar dir_start_offset[4]
Definition qzip.cpp:368
uchar comment_length[2]
Definition qzip.cpp:369
uchar num_dir_entries_this_disk[2]
Definition qzip.cpp:365
QByteArray extra_field
Definition qzip.cpp:377
QByteArray file_name
Definition qzip.cpp:376
CentralFileHeader h
Definition qzip.cpp:375
QByteArray file_comment
Definition qzip.cpp:378
uchar file_name_length[2]
Definition qzip.cpp:326
uchar compression_method[2]
Definition qzip.cpp:321
uchar general_purpose_bits[2]
Definition qzip.cpp:320
uchar crc_32[4]
Definition qzip.cpp:323
uchar signature[4]
Definition qzip.cpp:318
uchar extra_field_length[2]
Definition qzip.cpp:327
uchar version_needed[2]
Definition qzip.cpp:319
uchar last_mod_file[4]
Definition qzip.cpp:322
uchar compressed_size[4]
Definition qzip.cpp:324
uchar uncompressed_size[4]
Definition qzip.cpp:325
QFile::Permissions permissions