1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
/*
This file is part of KDE
SPDX-FileCopyrightText: 1999-2000 Waldo Bastian <bastian@kde.org>
SPDX-FileCopyrightText: 2008 David Faure <faure@kde.org>
SPDX-License-Identifier: MIT
*/
#include "filter.h"
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <QMimeDatabase>
#include <QMimeType>
#include <QUrl>
#include <KCompressionDevice>
#include <KFilterBase>
#include "loggingcategory.h"
// Pseudo plugin class to embed meta data
class KIOPluginForMetaData : public QObject
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.kde.kio.worker.filter" FILE "filter.json")
};
extern "C" {
Q_DECL_EXPORT int kdemain(int argc, char **argv);
}
int kdemain(int argc, char **argv)
{
QCoreApplication app(argc, argv);
app.setApplicationName("kio_filter");
qDebug(KIO_FILTER_DEBUG) << "Starting";
if (argc != 4) {
fprintf(stderr, "Usage: kio_filter protocol domain-socket1 domain-socket2\n");
exit(-1);
}
FilterProtocol worker(argv[1], argv[2], argv[3]);
worker.dispatchLoop();
qDebug(KIO_FILTER_DEBUG) << "Done";
return 0;
}
FilterProtocol::FilterProtocol(const QByteArray &protocol, const QByteArray &pool, const QByteArray &app)
: KIO::WorkerBase(protocol, pool, app)
, m_protocol(QString::fromLatin1(protocol))
{
const QString mimetype = (protocol == "zstd") ? QStringLiteral("application/zstd") : QLatin1String("application/x-") + QLatin1String(protocol.constData());
filter = KCompressionDevice::filterForCompressionType(KCompressionDevice::compressionTypeForMimeType(mimetype));
Q_ASSERT(filter);
}
KIO::WorkerResult FilterProtocol::get(const QUrl &url)
{
// In the old solution, subURL would be set by setSubURL.
// KDE4: now I simply assume bzip2:/localpath/file.bz2 and set subURL to the local path.
QUrl subURL = url;
subURL.setScheme("file");
if (subURL.isEmpty()) {
return KIO::WorkerResult::fail(KIO::ERR_NO_SOURCE_PROTOCOL, m_protocol);
}
QFile localFile(url.path());
if (!localFile.open(QIODevice::ReadOnly)) {
return KIO::WorkerResult::fail(KIO::ERR_CANNOT_READ, m_protocol);
}
if (!filter) {
// TODO better error message
return KIO::WorkerResult::fail(KIO::ERR_INTERNAL, m_protocol);
}
filter->init(QIODevice::ReadOnly);
bool bNeedHeader = true;
bool bNeedMimetype = true;
bool bError = true;
int result;
QByteArray inputBuffer;
inputBuffer.resize(8 * 1024);
QByteArray outputBuffer;
outputBuffer.resize(8 * 1024); // Start with a modest buffer
filter->setOutBuffer(outputBuffer.data(), outputBuffer.size());
while (true) {
if (filter->inBufferEmpty()) {
result = localFile.read(inputBuffer.data(), inputBuffer.size());
qDebug(KIO_FILTER_DEBUG) << "requestData: got " << result;
if (result <= 0) {
bError = true;
break; // Unexpected EOF.
}
filter->setInBuffer(inputBuffer.data(), inputBuffer.size());
}
if (bNeedHeader) {
bError = !filter->readHeader();
if (bError)
break;
bNeedHeader = false;
}
result = filter->uncompress();
if ((filter->outBufferAvailable() == 0) || (result == KFilterBase::End)) {
qDebug(KIO_FILTER_DEBUG) << "avail_out = " << filter->outBufferAvailable();
if (filter->outBufferAvailable() != 0) {
// Discard unused space :-)
outputBuffer.resize(outputBuffer.size() - filter->outBufferAvailable());
}
if (bNeedMimetype) {
// Can we use the "base" filename? E.g. foo.txt.bz2
const QString extension = QFileInfo(subURL.path()).suffix();
QMimeDatabase db;
QMimeType mime;
if (extension == "gz" || extension == "bz" || extension == "bz2" || extension == "zst") {
QString baseName = subURL.path();
baseName.truncate(baseName.length() - extension.length() - 1 /*the dot*/);
qDebug(KIO_FILTER_DEBUG) << "baseName=" << baseName;
mime = db.mimeTypeForFileNameAndData(baseName, outputBuffer);
} else {
mime = db.mimeTypeForData(outputBuffer);
}
qDebug(KIO_FILTER_DEBUG) << "Emitting mimetype " << mime.name();
mimeType(mime.name());
bNeedMimetype = false;
}
data(outputBuffer); // Send data
filter->setOutBuffer(outputBuffer.data(), outputBuffer.size());
if (result == KFilterBase::End)
break; // Finished.
}
if (result != KFilterBase::Ok) {
bError = true;
break; // Error
}
}
if (!bError) {
result = localFile.read(inputBuffer.data(), inputBuffer.size());
qDebug(KIO_FILTER_DEBUG) << "requestData: got" << result << "(expecting 0)";
data(QByteArray()); // Send EOF
}
filter->terminate();
if (bError) {
return KIO::WorkerResult::fail(KIO::ERR_CANNOT_READ, subURL.url());
}
return KIO::WorkerResult::pass();
}
#include "filter.moc"
#include "moc_filter.cpp"
|