KFileMetaData

externalextractor.cpp
1/*
2 This file is part of the KFileMetaData project
3 SPDX-FileCopyrightText: 2016 Varun Joshi <varunj.1011@gmail.com>
4 SPDX-FileCopyrightText: 2015 Boudhayan Gupta <bgupta@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7*/
8
9#include "externalextractor.h"
10#include "kfilemetadata_debug.h"
11#include "properties.h"
12#include "propertyinfo.h"
13#include "typeinfo.h"
14
15#include <QDir>
16#include <QProcess>
17#include <QJsonDocument>
18#include <QJsonObject>
19#include <QJsonArray>
20
21#define EXTRACTOR_TIMEOUT_MS 30000
22
23namespace KFileMetaData
24{
25class ExternalExtractorPrivate
26{
27public:
28 QString path;
29 QStringList writeMimetypes;
30 QString mainPath;
31};
32}
33
34using namespace KFileMetaData;
35
36ExternalExtractor::ExternalExtractor(QObject* parent)
37 : ExtractorPlugin(parent),
38 d_ptr(new ExternalExtractorPrivate)
39{
40}
41
42ExternalExtractor::ExternalExtractor(const QString& pluginPath)
43 : ExtractorPlugin(nullptr),
44 d_ptr(new ExternalExtractorPrivate)
45{
46 Q_D(ExternalExtractor);
47
48 d->path = pluginPath;
49
50 QDir pluginDir(pluginPath);
51 QStringList pluginDirContents = pluginDir.entryList(QDir::Files | QDir::NoDotAndDotDot);
52
53 if (!pluginDirContents.contains(QStringLiteral("manifest.json"))) {
54 qCDebug(KFILEMETADATA_LOG) << pluginPath << "does not seem to contain a valid plugin";
55 return;
56 }
57
58 QFile manifest(pluginDir.filePath(QStringLiteral("manifest.json")));
59 manifest.open(QIODevice::ReadOnly);
60 QJsonDocument manifestDoc = QJsonDocument::fromJson(manifest.readAll());
61 if (!manifestDoc.isObject()) {
62 qCDebug(KFILEMETADATA_LOG) << "Manifest does not seem to be a valid JSON Object";
63 return;
64 }
65
66 QJsonObject rootObject = manifestDoc.object();
67 const QJsonArray mimetypesArray = rootObject.value(QStringLiteral("mimetypes")).toArray();
68 QStringList mimetypes;
69 mimetypes.reserve(mimetypesArray.count());
70
71 for (const QJsonValue &mimetype : mimetypesArray) {
72 mimetypes << mimetype.toString();
73 }
74
75 d->writeMimetypes.append(mimetypes);
76 d->mainPath = pluginDir.absoluteFilePath(rootObject[QStringLiteral("main")].toString());
77}
78
79ExternalExtractor::~ExternalExtractor() = default;
80
81QStringList ExternalExtractor::mimetypes() const
82{
83 Q_D(const ExternalExtractor);
84
85 return d->writeMimetypes;
86}
87
88void ExternalExtractor::extract(ExtractionResult* result)
89{
90 Q_D(ExternalExtractor);
91
92 QJsonDocument writeData;
93 QJsonObject writeRootObject;
94 QByteArray output;
95 QByteArray errorOutput;
96
97 writeRootObject[QStringLiteral("path")] = QJsonValue(result->inputUrl());
98 writeRootObject[QStringLiteral("mimetype")] = result->inputMimetype();
99 writeData.setObject(writeRootObject);
100
101 QProcess extractorProcess;
102 extractorProcess.start(d->mainPath, QStringList(), QIODevice::ReadWrite);
103 bool started = extractorProcess.waitForStarted();
104 if (!started) {
105 qCWarning(KFILEMETADATA_LOG) << "External extractor" << d->mainPath
106 << "failed to start:" << extractorProcess.errorString();
107 return;
108 }
109
110 extractorProcess.write(writeData.toJson());
111 extractorProcess.closeWriteChannel();
112 extractorProcess.waitForFinished(EXTRACTOR_TIMEOUT_MS);
113
114 output = extractorProcess.readAll();
115 errorOutput = extractorProcess.readAllStandardError();
116
117 if (extractorProcess.exitStatus()) {
118 qCWarning(KFILEMETADATA_LOG) << "External extractor" << d->mainPath
119 << "failed to index" << result->inputUrl() << "-" << errorOutput;
120 return;
121 }
122
123 // now we read in the output (which is a standard json format) into the
124 // ExtractionResult
125
126 QJsonDocument extractorData = QJsonDocument::fromJson(output);
127 if (!extractorData.isObject()) {
128 return;
129 }
130 QJsonObject rootObject = extractorData.object();
131 QJsonObject propertiesObject = rootObject[QStringLiteral("properties")].toObject();
132
133 const auto propertiesObjectEnd = propertiesObject.constEnd();
134 auto i = propertiesObject.constBegin();
135 for (; i != propertiesObjectEnd; ++i) {
136 if (i.key() == QStringLiteral("typeInfo")) {
137 TypeInfo info = TypeInfo::fromName(i.value().toString());
138 result->addType(info.type());
139 continue;
140 }
141
142 // for plaintext extraction
143 if (i.key() == QStringLiteral("text")) {
144 result->append(i.value().toString());
145 continue;
146 }
147
148 PropertyInfo info = PropertyInfo::fromName(i.key());
149 if (info.name() != i.key()) {
150 continue;
151 }
152 result->add(info.property(), i.value().toVariant());
153 }
154
155 if (rootObject[QStringLiteral("status")].toString() != QStringLiteral("OK")) {
156 qCDebug(KFILEMETADATA_LOG) << rootObject[QStringLiteral("error")].toString();
157 }
158}
159
160#include "moc_externalextractor.cpp"
The ExtractionResult class is where all the data extracted by the indexer is saved.
QString inputUrl() const
The input url which the plugins will use to locate the file.
virtual void addType(Type::Type type)=0
This function is called by the plugins.
QString inputMimetype() const
The input mimetype.
virtual void add(Property::Property property, const QVariant &value)=0
This function is called by the plugins when they wish to add a key value pair which should be indexed...
virtual void append(const QString &text)=0
This function is called by plugins when they wish for some plain text to be indexed without any prope...
The ExtractorPlugin is the base class for all file metadata extractors.
The PropertyInfo class can be used to obtain extra information about any property.
QString name() const
The internal unique name used to refer to the property.
Property::Property property() const
The enumeration which represents this property.
static PropertyInfo fromName(const QString &name)
Construct a PropertyInfo from the internal property name.
char * toString(const EngineQuery &query)
KIOCORE_EXPORT MimetypeJob * mimetype(const QUrl &url, JobFlags flags=DefaultFlags)
<KFileMetaData/Properties>
QString errorString() const const
QByteArray readAll()
qint64 write(const char *data, qint64 maxSize)
int count() const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
bool isObject() const const
QJsonObject object() const const
void setObject(const QJsonObject &object)
QByteArray toJson() const const
QJsonObject::const_iterator constBegin() const const
QJsonObject::const_iterator constEnd() const const
QJsonValue value(const QString &key) const const
QJsonArray toArray() const const
void reserve(int alloc)
void closeWriteChannel()
QProcess::ExitStatus exitStatus() const const
QByteArray readAllStandardError()
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode)
bool waitForFinished(int msecs)
bool waitForStarted(int msecs)
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:44:24 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.