File indexing completed on 2025-01-05 04:37:29

0001 /*
0002     SPDX-FileCopyrightText: 2009 Joris Guisson <joris.guisson@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "extractfilejob.h"
0008 #include <KIO/Global>
0009 #include <QFile>
0010 #include <QThread>
0011 
0012 namespace bt
0013 {
0014 class ExtractFileThread : public QThread
0015 {
0016 public:
0017     ExtractFileThread(QIODevice *in_dev, QIODevice *out_dev)
0018         : in_dev(in_dev)
0019         , out_dev(out_dev)
0020         , canceled(false)
0021     {
0022     }
0023 
0024     ~ExtractFileThread() override
0025     {
0026         delete in_dev;
0027         delete out_dev;
0028     }
0029 
0030     void run() override
0031     {
0032         char buf[4096];
0033         qint64 ret = 0;
0034         while ((ret = in_dev->read(buf, 4096)) != 0 && !canceled) {
0035             out_dev->write(buf, ret);
0036         }
0037     }
0038 
0039     QIODevice *in_dev;
0040     QIODevice *out_dev;
0041     bool canceled;
0042 };
0043 
0044 ExtractFileJob::ExtractFileJob(KArchive *archive, const QString &path, const QString &dest)
0045     : archive(archive)
0046     , path(path)
0047     , dest(dest)
0048     , extract_thread(nullptr)
0049 {
0050 }
0051 
0052 ExtractFileJob::~ExtractFileJob()
0053 {
0054     delete archive;
0055 }
0056 
0057 void ExtractFileJob::start()
0058 {
0059     // first find the file in the archive
0060     QStringList path_components = path.split(QLatin1Char('/'), Qt::SkipEmptyParts);
0061     const KArchiveDirectory *dir = archive->directory();
0062     for (int i = 0; i < path_components.count(); i++) {
0063         // if we can't find it give back an error
0064         QString pc = path_components.at(i);
0065         if (!dir->entries().contains(pc)) {
0066             setError(KIO::ERR_DOES_NOT_EXIST);
0067             emitResult();
0068             return;
0069         }
0070 
0071         const KArchiveEntry *e = dir->entry(pc);
0072         if (i < path_components.count() - 1) {
0073             // if we are not the last entry in the path, e must be a directory
0074             if (!e->isDirectory()) {
0075                 setError(KIO::ERR_DOES_NOT_EXIST);
0076                 emitResult();
0077                 return;
0078             }
0079 
0080             dir = (const KArchiveDirectory *)e;
0081         } else {
0082             // last in the path, must be a file
0083             if (!e->isFile()) {
0084                 setError(KIO::ERR_DOES_NOT_EXIST);
0085                 emitResult();
0086                 return;
0087             }
0088 
0089             // create a device to read the file and start a thread to do the reading
0090             KArchiveFile *file = (KArchiveFile *)e;
0091             QFile *out_dev = new QFile(dest);
0092             if (!out_dev->open(QIODevice::WriteOnly)) {
0093                 delete out_dev;
0094                 setError(KIO::ERR_CANNOT_OPEN_FOR_WRITING);
0095                 emitResult();
0096                 return;
0097             }
0098 
0099             QIODevice *in_dev = file->createDevice();
0100             extract_thread = new ExtractFileThread(in_dev, out_dev);
0101             connect(extract_thread, &ExtractFileThread::finished, this, &ExtractFileJob::extractThreadDone, Qt::QueuedConnection);
0102             extract_thread->start();
0103         }
0104     }
0105 }
0106 
0107 void ExtractFileJob::kill(bool quietly)
0108 {
0109     if (extract_thread) {
0110         extract_thread->canceled = true;
0111         extract_thread->wait();
0112         delete extract_thread;
0113         extract_thread = nullptr;
0114     }
0115     setError(KIO::ERR_USER_CANCELED);
0116     if (!quietly)
0117         emitResult();
0118 }
0119 
0120 void ExtractFileJob::extractThreadDone()
0121 {
0122     extract_thread->wait();
0123     delete extract_thread;
0124     extract_thread = nullptr;
0125     setError(0);
0126     emitResult();
0127 }
0128 
0129 }