82static int deflate (Bytef *dest, ulong *destLen,
const Bytef *source, ulong sourceLen)
87 stream.next_in =
const_cast<Bytef*>(source);
88 stream.avail_in = (uInt)sourceLen;
89 stream.next_out = dest;
90 stream.avail_out = (uInt)*destLen;
91 if ((uLong)stream.avail_out != *destLen)
return Z_BUF_ERROR;
93 stream.zalloc = (alloc_func)
nullptr;
94 stream.zfree = (free_func)
nullptr;
95 stream.opaque = (voidpf)
nullptr;
97 err = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
98 if (err != Z_OK)
return err;
100 err = deflate(&stream, Z_FINISH);
101 if (err != Z_STREAM_END) {
103 return err == Z_OK ? Z_BUF_ERROR : err;
105 *destLen = stream.total_out;
107 err = deflateEnd(&stream);
343 writeUInt(h.signature, 0x04034b50);
344 copyUShort(h.version_needed, ch.version_needed);
345 copyUShort(h.general_purpose_bits, ch.general_purpose_bits);
346 copyUShort(h.compression_method, ch.compression_method);
347 copyUInt(h.last_mod_file, ch.last_mod_file);
348 copyUInt(h.crc_32, ch.crc_32);
349 copyUInt(h.compressed_size, ch.compressed_size);
350 copyUInt(h.uncompressed_size, ch.uncompressed_size);
351 copyUShort(h.file_name_length, ch.file_name_length);
352 copyUShort(h.extra_field_length, ch.extra_field_length);
359 static const char *
const entryTypes[] = {
363 ZDEBUG() <<
"adding" << entryTypes[type] <<
":" << fileName.toUtf8().data() << (type == 2 ? QByteArray(
" -> " + contents).constData() :
"");
366 if (! (device->isOpen() || device->open(QIODevice::WriteOnly))) {
367 status = QZipWriter::FileOpenError;
370 device->seek(start_of_directory);
373 QZipWriter::CompressionPolicy compression = compressionPolicy;
374 if (compressionPolicy == QZipWriter::AutoCompress) {
375 if (contents.size() < 64)
376 compression = QZipWriter::NeverCompress;
378 compression = QZipWriter::AlwaysCompress;
383 writeUInt(header.h.signature, 0x02014b50);
386 writeUInt(header.h.uncompressed_size, contents.size());
387 writeMSDosDate(header.h.last_mod_file, QDateTime::currentDateTime());
388 QByteArray data = contents;
389 if (compression == QZipWriter::AlwaysCompress) {
392 ulong len = contents.size();
394 len += (len >> 12) + (len >> 14) + 11;
398 res = deflate((uchar*)data.data(), &len, (
const uchar*)contents.constData(), contents.size());
405 qWarning(
"QZip: Z_MEM_ERROR: Not enough memory to compress file, skipping");
412 }
while (res == Z_BUF_ERROR);
415 writeUInt(header.h.compressed_size, data.size());
416 uint crc_32 = ::crc32(0,
nullptr, 0);
417 crc_32 = ::crc32(crc_32, (
const uchar *)contents.constData(), contents.size());
418 writeUInt(header.h.crc_32, crc_32);
422 writeUShort(header.h.general_purpose_bits, general_purpose_bits);
424 const bool inUtf8 = (general_purpose_bits &
Utf8Names) != 0;
425 header.file_name = inUtf8 ? fileName.toUtf8() : fileName.toLocal8Bit();
426 if (header.file_name.size() > 0xffff) {
427 qWarning(
"QZip: Filename is too long, chopping it to 65535 bytes");
428 header.file_name = header.file_name.left(0xffff);
430 if (header.file_comment.size() + header.file_name.size() > 0xffff) {
431 qWarning(
"QZip: File comment is too long, chopping it to 65535 bytes");
432 header.file_comment.truncate(0xffff - header.file_name.size());
434 writeUShort(header.h.file_name_length, header.file_name.size());
437 writeUShort(header.h.version_made,
HostUnix << 8);
440 quint32 mode = permissionsToMode(permissions);
455 writeUInt(header.h.external_file_attributes, mode << 16);
456 writeUInt(header.h.offset_local_header, start_of_directory);
459 fileHeaders.append(header);
462 device->write((
const char *)&h,
sizeof(LocalFileHeader));
463 device->write(header.file_name);
465 start_of_directory = device->pos();
466 dirtyFileTree =
true;
489QZipWriter::QZipWriter(
const QString &fileName, QIODevice::OpenMode mode)
491 auto f = std::make_unique<QFile>(fileName);
492 QZipWriter::Status status;
493 if (f->open(mode) && f->error() == QFile::NoError)
494 status = QZipWriter::NoError;
496 if (f->error() == QFile::WriteError)
497 status = QZipWriter::FileWriteError;
498 else if (f->error() == QFile::OpenError)
499 status = QZipWriter::FileOpenError;
500 else if (f->error() == QFile::PermissionsError)
501 status = QZipWriter::FilePermissionsError;
503 status = QZipWriter::FileError;
506 d =
new QZipWriterPrivate(f.get(),
true);
507 Q_UNUSED(f.release());
655void QZipWriter::addFile(
const QString &fileName, QIODevice *device)
658 QIODevice::OpenMode mode = device->openMode();
660 if ((mode & QIODevice::ReadOnly) == 0) {
662 if (! device->open(QIODevice::ReadOnly)) {
663 d->status = FileOpenError;
667 d->addEntry(QZipWriterPrivate::File, QDir::fromNativeSeparators(fileName), device->readAll());
698void QZipWriter::close()
700 if (!(d->device->openMode() & QIODevice::WriteOnly)) {
706 d->device->seek(d->start_of_directory);
708 for (
int i = 0; i < d->fileHeaders.size(); ++i) {
709 const FileHeader &header = d->fileHeaders.at(i);
710 d->device->write((
const char *)&header.h,
sizeof(CentralFileHeader));
711 d->device->write(header.file_name);
712 d->device->write(header.extra_field);
713 d->device->write(header.file_comment);
715 int dir_size = d->device->pos() - d->start_of_directory;
718 memset(&eod, 0,
sizeof(EndOfDirectory));
719 writeUInt(eod.signature, 0x06054b50);
722 writeUShort(eod.num_dir_entries_this_disk, d->fileHeaders.size());
723 writeUShort(eod.num_dir_entries, d->fileHeaders.size());
724 writeUInt(eod.directory_size, dir_size);
725 writeUInt(eod.dir_start_offset, d->start_of_directory);
726 writeUShort(eod.comment_length, d->comment.size());
728 d->device->write((
const char *)&eod,
sizeof(EndOfDirectory));
729 d->device->write(d->comment);