Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QZipReader extractAll issue
Qt 6.11 is out! See what's new in the release blog

QZipReader extractAll issue

Scheduled Pinned Locked Moved Solved General and Desktop
5 Posts 2 Posters 2.2k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Cobra91151C Offline
    Cobra91151C Offline
    Cobra91151
    wrote on last edited by
    #1

    Hello!

    I am using the old Qt - QZipReader class to unzip some zip file. It decompresses successfully only files. When zip file contains the directories with content, it displays this QIODevice::write issue:

    QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\7zr.exe"): device not open
    QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\aria2c.exe"): device not open
    QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\convert.sh"): device not open
    QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\convert_config_linux"): device not open
    QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\convert_config_macos"): device not open
    QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\convert_ve_plugin"): device not open
    QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\test5\qt-unified-windows-x86-3.1.1-online.exe"): device not open
    QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\uup-converter-wimlib.7z"): device not open
    QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\test\yM37erm8.jpg"): device not open
    QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\test\yNFatJN.jpg"): device not open
    

    Code:

    #if defined(Q_OS_WIN)
    #  undef S_IFREG
    #  define S_IFREG 0100000
    #  ifndef S_ISDIR
    #    define S_ISDIR(x) ((x) & S_IFDIR) > 0
    #  endif
    #  ifndef S_ISREG
    #    define S_ISREG(x) ((x) & 0170000) == S_IFREG
    #  endif
    #  define S_IFLNK 020000
    #  define S_ISLNK(x) ((x) & S_IFLNK) > 0
    #  ifndef S_IRUSR
    #    define S_IRUSR 0400
    #  endif
    #  ifndef S_IWUSR
    #    define S_IWUSR 0200
    #  endif
    #  ifndef S_IXUSR
    #    define S_IXUSR 0100
    #  endif
    #  define S_IRGRP 0040
    #  define S_IWGRP 0020
    #  define S_IXGRP 0010
    #  define S_IROTH 0004
    #  define S_IWOTH 0002
    #  define S_IXOTH 0001
    #endif
    
    bool QZipReader::extractAll(const QString &destinationDir) const
        {
            QDir baseDir(destinationDir);
            // create directories first
            const QVector<FileInfo> allFiles = fileInfoList();
        //    for (FileInfo fi : allFiles) {
        //        if (fi.isDir) {
        //            const QString absPath = QDir::toNativeSeparators(QString("%1/%2").arg(destinationDir, fi.filePath));
        
        //            if (!baseDir.mkpath(fi.filePath)) {
        //                return false;
        //            }
        //            if (!QFile::setPermissions(absPath, fi.permissions)) {
        //                return false;
        //            }
        //        }
        //    }
        
        //    // set up symlinks
        //    for (FileInfo fi : allFiles) {
        //        const QString absPath = QDir::toNativeSeparators(QString("%1/%2").arg(destinationDir, fi.filePath));
        //        if (fi.isSymLink) {
        //            QString destination = QFile::decodeName(fileData(fi.filePath));
        //            if (destination.isEmpty())
        //                return false;
        //            QFileInfo linkFi(absPath);
        //            if (!QFile::exists(linkFi.absolutePath()))
        //                QDir::root().mkpath(linkFi.absolutePath());
        //            if (!QFile::link(destination, absPath))
        //                return false;
        //            /* cannot change permission of links
        //            if (!QFile::setPermissions(absPath, fi.permissions))
        //                return false;
        //            */
        //        }
        //    }
        
            for (FileInfo fi : allFiles) {
                if (!baseDir.exists()) {
                    baseDir.mkpath(destinationDir);
                }
        
                const QString absPath = QDir::toNativeSeparators(QString("%1/%2").arg(destinationDir, fi.filePath));
        
                if (fi.isDir) {
                    baseDir.mkpath(absPath);
                }
        
                if (fi.isFile) {
                    QFile f(absPath);
        
                    if (!f.isOpen()) {
                        f.open(QIODevice::WriteOnly);
                    }
        
                    f.write(fileData(fi.filePath));
                    f.setPermissions(fi.permissions);
                    f.close();
                }
            }
        
            return true;
        }
    
    QVector<QZipReader::FileInfo> QZipReader::fileInfoList() const
    {
        d->scanFiles();
        QVector<QZipReader::FileInfo> files;
    
        for (int i = 0; i < d->fileHeaders.size(); ++i) {
            QZipReader::FileInfo fi;
            d->fillFileInfo(i, fi);
            files.append(fi);
        }
    
        return files;
    }
    
    void QZipReaderPrivate::scanFiles()
    {
        if (!dirtyFileTree) {
            return;
        }
    
        if (!(device->isOpen() || device->open(QIODevice::ReadOnly))) {
            status = QZipReader::FileOpenError;
            return;
        }
    
        if ((device->openMode() & QIODevice::ReadOnly) == 0) { // only read the index from readable files.
            status = QZipReader::FileReadError;
            return;
        }
    
        dirtyFileTree = false;
        uchar tmp[4];
        device->read((char *)tmp, 4);
    
        if (readUInt(tmp) != 0x04034b50) {
            qWarning() << "QZip: not a zip file!";
            return;
        }
    
        // find EndOfDirectory header    
        int i = 0;
        int start_of_directory = -1;
        int num_dir_entries = 0;
        EndOfDirectory eod;
        while (start_of_directory == -1) {
          const int pos = device->size() - static_cast<int>(sizeof(EndOfDirectory)) - i;
    
          if (pos < 0 || i > 65535) {
              qWarning() << "QZip: EndOfDirectory not found";
              return;
          }
    
          device->seek(pos);
          device->read((char *)&eod, sizeof(EndOfDirectory));
    
          if (readUInt(eod.signature) == 0x06054b50) {
              //start_of_directory = pos;
              break;
          }
    
          ++i;
        }
    
        // have the eod
        start_of_directory = readUInt(eod.dir_start_offset);
        num_dir_entries = readUShort(eod.num_dir_entries);
        //qDebug() << "start_of_directory at: " << start_of_directory << " | num_dir_entries: " << num_dir_entries;
        int comment_length = readUShort(eod.comment_length);
    
        if (comment_length != i) {
            qWarning() << "QZip: failed to parse zip file.";
        }
    
        comment = device->read(qMin(comment_length, i));
    
        device->seek(start_of_directory);
    
        for (i = 0; i < num_dir_entries; ++i) {
            FileHeader header;
            int read = device->read((char *) &header.h, sizeof(CentralFileHeader));
    
            if (read < (int)sizeof(CentralFileHeader)) {
                qWarning() << "QZip: Failed to read complete header, index may be incomplete";
                break;
            }
    
            if (readUInt(header.h.signature) != 0x02014b50) {
                qWarning() << "QZip: invalid header signature, index may be incomplete";
                break;
            }
    
            int l = readUShort(header.h.file_name_length);
            header.file_name = device->read(l);
    
            if (header.file_name.length() != l) {
                qWarning() << "QZip: Failed to read filename from zip index, index may be incomplete";
                break;
            }
    
            l = readUShort(header.h.extra_field_length);
            header.extra_field = device->read(l);
    
            if (header.extra_field.length() != l) {
                qWarning() << "QZip: Failed to read extra field in zip file, skipping file, index may be incomplete";
                break;
            }
    
            l = readUShort(header.h.file_comment_length);
            header.file_comment = device->read(l);
    
            if (header.file_comment.length() != l) {
                qWarning() << "QZip: Failed to read read file comment, index may be incomplete";
                break;
            }
    
            qDebug() << "Found file: " << header.file_name.data();
            fileHeaders.append(header);
        }
    }
    
    void QZipPrivate::fillFileInfo(int index, QZipReader::FileInfo &fileInfo) const
    {
        FileHeader header = fileHeaders.at(index);
        fileInfo.filePath = QString::fromLocal8Bit(header.file_name);
        const quint32 mode = (qFromLittleEndian<quint32>(&header.h.external_file_attributes[0]) >> 16) & 0xFFFF;
        fileInfo.isDir = S_ISDIR(mode);
        fileInfo.isFile = S_ISREG(mode);
    
        qDebug() << "Mode: " << mode;
        qDebug() << "fileInfo.filePath: " << fileInfo.filePath << " isFile: " << fileInfo.isFile << " isDir: " << fileInfo.isDir;
    
        fileInfo.isSymLink = S_ISLNK(mode);
        fileInfo.permissions = modeToPermissions(mode);
        fileInfo.size = readUInt(header.h.uncompressed_size);
        fileInfo.lastModified = readMSDosDate(header.h.last_mod_file);
    }
    

    Console app:

    #include <QCoreApplication>
    #include <QDir>
    #include <QDebug>
    #include "qzipreader.h"
    
    int main(int argc, char *argv[])
    {
        QCoreApplication app(argc, argv);
        qDebug() << "This is a QZip test..." << endl;
        QString zipFileName = "C:\\Users\\cobra\\Downloads\\22610.1_amd64_en-us_professional_00fb7ba0_convert.zip";
        QString outputDirPath = "C:\\Users\\cobra\\Downloads\\Output";
        QZipReader qZip(zipFileName);
        bool isExtracted = qZip.extractAll(outputDirPath);
        qDebug() << "isExtracted: " << isExtracted;
        qZip.close();
        system("Pause");
        return 0;
    }
    

    I have checked that everything in zip file is treated as files even directories with content, which leads to this QIODevice::write issue. The fileInfo.isDir returns false (0). Any ideas how to fix it? I can share more Qt code if needed. Thank you.

    1 Reply Last reply
    0
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      I wonder why e.g. QFile::open() returns a boolean and noone checks it just to wonder why it doesn't work later on...

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      Cobra91151C 2 Replies Last reply
      2
      • Christian EhrlicherC Christian Ehrlicher

        I wonder why e.g. QFile::open() returns a boolean and noone checks it just to wonder why it doesn't work later on...

        Cobra91151C Offline
        Cobra91151C Offline
        Cobra91151
        wrote on last edited by Cobra91151
        #3

        @Christian-Ehrlicher

        Because it contains the directory which is not created in the local file system. For example: uup_download_linux.sh is successfully extracted but then goes the directory with a file: \files\7zr.exe and it leads to this error. I need something to check for directories to create it in the file system before it extracts these files or extract the directory with a content at once. Thanks.

        Zip content:
        Zip_file_content.gif

        This issue could be here - fillFileInfo method:

        const quint32 mode = (qFromLittleEndian<quint32>(&header.h.external_file_attributes[0]) >> 16) & 0xFFFF;
        fileInfo.isDir = S_ISDIR(mode);
        

        The directories are always false.

        1 Reply Last reply
        0
        • Christian EhrlicherC Christian Ehrlicher

          I wonder why e.g. QFile::open() returns a boolean and noone checks it just to wonder why it doesn't work later on...

          Cobra91151C Offline
          Cobra91151C Offline
          Cobra91151
          wrote on last edited by
          #4

          @Christian-Ehrlicher

          I think, I got it :) I will reply a bit later. Thank you very much.

          1 Reply Last reply
          0
          • Cobra91151C Offline
            Cobra91151C Offline
            Cobra91151
            wrote on last edited by
            #5

            @Christian-Ehrlicher

            So, I have fixed it by adding this line: baseDir.mkpath(QFileInfo(absPath).absoluteDir().path());

            Code:

            bool QZipReader::extractAll(const QString &destinationDir) const
            {
                QDir baseDir(destinationDir);
            
                if (!baseDir.exists()) {
                    baseDir.mkpath(destinationDir);
                }
            
                const QVector<FileInfo> allFiles = fileInfoList();
            
                for (FileInfo fi : allFiles) {
                     const QString absPath = QDir::toNativeSeparators(QString("%1/%2").arg(destinationDir, fi.filePath));
                     baseDir.mkpath(QFileInfo(absPath).absoluteDir().path());
            
                     if (fi.isFile) {
                         QFile f(absPath);
            
                         if (!f.isOpen()) {
                             f.open(QIODevice::WriteOnly);
                         }
            
                         f.write(fileData(fi.filePath));
                         f.setPermissions(fi.permissions);
                         f.close();
                     }
                }
            
                return true;
            }
            

            Now, it creates all directories and extracts files. The issue is resolved. Thank you.

            1 Reply Last reply
            1

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved