File indexing completed on 2024-11-10 04:30:24
0001 /* 0002 This file is part of KDE 0003 0004 SPDX-FileCopyrightText: 1999-2000 Waldo Bastian <bastian@kde.org> 0005 SPDX-FileCopyrightText: 2008 David Faure <faure@kde.org> 0006 0007 SPDX-License-Identifier: MIT 0008 */ 0009 0010 #include "filter.h" 0011 0012 #include <QCoreApplication> 0013 #include <QDebug> 0014 #include <QFile> 0015 #include <QFileInfo> 0016 #include <QMimeDatabase> 0017 #include <QMimeType> 0018 #include <QUrl> 0019 0020 #include <KCompressionDevice> 0021 #include <KFilterBase> 0022 0023 #include "loggingcategory.h" 0024 0025 // Pseudo plugin class to embed meta data 0026 class KIOPluginForMetaData : public QObject 0027 { 0028 Q_OBJECT 0029 Q_PLUGIN_METADATA(IID "org.kde.kio.worker.filter" FILE "filter.json") 0030 }; 0031 0032 extern "C" { 0033 Q_DECL_EXPORT int kdemain(int argc, char **argv); 0034 } 0035 0036 int kdemain(int argc, char **argv) 0037 { 0038 QCoreApplication app(argc, argv); 0039 app.setApplicationName("kio_filter"); 0040 0041 qDebug(KIO_FILTER_DEBUG) << "Starting"; 0042 0043 if (argc != 4) { 0044 fprintf(stderr, "Usage: kio_filter protocol domain-socket1 domain-socket2\n"); 0045 exit(-1); 0046 } 0047 0048 FilterProtocol worker(argv[1], argv[2], argv[3]); 0049 worker.dispatchLoop(); 0050 0051 qDebug(KIO_FILTER_DEBUG) << "Done"; 0052 return 0; 0053 } 0054 0055 FilterProtocol::FilterProtocol(const QByteArray &protocol, const QByteArray &pool, const QByteArray &app) 0056 : KIO::WorkerBase(protocol, pool, app) 0057 , m_protocol(QString::fromLatin1(protocol)) 0058 { 0059 const QString mimetype = (protocol == "zstd") ? QStringLiteral("application/zstd") : QLatin1String("application/x-") + QLatin1String(protocol.constData()); 0060 0061 filter = KCompressionDevice::filterForCompressionType(KCompressionDevice::compressionTypeForMimeType(mimetype)); 0062 Q_ASSERT(filter); 0063 } 0064 0065 KIO::WorkerResult FilterProtocol::get(const QUrl &url) 0066 { 0067 // In the old solution, subURL would be set by setSubURL. 0068 // KDE4: now I simply assume bzip2:/localpath/file.bz2 and set subURL to the local path. 0069 QUrl subURL = url; 0070 subURL.setScheme("file"); 0071 0072 if (subURL.isEmpty()) { 0073 return KIO::WorkerResult::fail(KIO::ERR_NO_SOURCE_PROTOCOL, m_protocol); 0074 } 0075 0076 QFile localFile(url.path()); 0077 if (!localFile.open(QIODevice::ReadOnly)) { 0078 return KIO::WorkerResult::fail(KIO::ERR_CANNOT_READ, m_protocol); 0079 } 0080 0081 if (!filter) { 0082 // TODO better error message 0083 return KIO::WorkerResult::fail(KIO::ERR_INTERNAL, m_protocol); 0084 } 0085 0086 filter->init(QIODevice::ReadOnly); 0087 0088 bool bNeedHeader = true; 0089 bool bNeedMimetype = true; 0090 bool bError = true; 0091 int result; 0092 0093 QByteArray inputBuffer; 0094 inputBuffer.resize(8 * 1024); 0095 QByteArray outputBuffer; 0096 outputBuffer.resize(8 * 1024); // Start with a modest buffer 0097 filter->setOutBuffer(outputBuffer.data(), outputBuffer.size()); 0098 while (true) { 0099 if (filter->inBufferEmpty()) { 0100 result = localFile.read(inputBuffer.data(), inputBuffer.size()); 0101 qDebug(KIO_FILTER_DEBUG) << "requestData: got " << result; 0102 if (result <= 0) { 0103 bError = true; 0104 break; // Unexpected EOF. 0105 } 0106 filter->setInBuffer(inputBuffer.data(), inputBuffer.size()); 0107 } 0108 if (bNeedHeader) { 0109 bError = !filter->readHeader(); 0110 if (bError) 0111 break; 0112 bNeedHeader = false; 0113 } 0114 result = filter->uncompress(); 0115 if ((filter->outBufferAvailable() == 0) || (result == KFilterBase::End)) { 0116 qDebug(KIO_FILTER_DEBUG) << "avail_out = " << filter->outBufferAvailable(); 0117 if (filter->outBufferAvailable() != 0) { 0118 // Discard unused space :-) 0119 outputBuffer.resize(outputBuffer.size() - filter->outBufferAvailable()); 0120 } 0121 if (bNeedMimetype) { 0122 // Can we use the "base" filename? E.g. foo.txt.bz2 0123 const QString extension = QFileInfo(subURL.path()).suffix(); 0124 QMimeDatabase db; 0125 QMimeType mime; 0126 if (extension == "gz" || extension == "bz" || extension == "bz2" || extension == "zst") { 0127 QString baseName = subURL.path(); 0128 baseName.truncate(baseName.length() - extension.length() - 1 /*the dot*/); 0129 qDebug(KIO_FILTER_DEBUG) << "baseName=" << baseName; 0130 mime = db.mimeTypeForFileNameAndData(baseName, outputBuffer); 0131 } else { 0132 mime = db.mimeTypeForData(outputBuffer); 0133 } 0134 qDebug(KIO_FILTER_DEBUG) << "Emitting mimetype " << mime.name(); 0135 mimeType(mime.name()); 0136 bNeedMimetype = false; 0137 } 0138 data(outputBuffer); // Send data 0139 filter->setOutBuffer(outputBuffer.data(), outputBuffer.size()); 0140 if (result == KFilterBase::End) 0141 break; // Finished. 0142 } 0143 if (result != KFilterBase::Ok) { 0144 bError = true; 0145 break; // Error 0146 } 0147 } 0148 0149 if (!bError) { 0150 result = localFile.read(inputBuffer.data(), inputBuffer.size()); 0151 qDebug(KIO_FILTER_DEBUG) << "requestData: got" << result << "(expecting 0)"; 0152 data(QByteArray()); // Send EOF 0153 } 0154 0155 filter->terminate(); 0156 0157 if (bError) { 0158 return KIO::WorkerResult::fail(KIO::ERR_CANNOT_READ, subURL.url()); 0159 } 0160 0161 return KIO::WorkerResult::pass(); 0162 } 0163 0164 #include "filter.moc"