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

QZipReader extractAll issue

Scheduled Pinned Locked Moved Solved General and Desktop
5 Posts 2 Posters 1.7k 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 Online
      Christian EhrlicherC Online
      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