KFileMetaData

externalextractor.cpp
1 /*
2  This file is part of the KFileMetaData project
3  SPDX-FileCopyrightText: 2016 Varun Joshi <[email protected]>
4  SPDX-FileCopyrightText: 2015 Boudhayan Gupta <[email protected]>
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 
23 namespace KFileMetaData
24 {
25 class ExternalExtractorPrivate
26 {
27 public:
28  QString path;
29  QStringList writeMimetypes;
30  QString mainPath;
31 };
32 }
33 
34 using namespace KFileMetaData;
35 
36 ExternalExtractor::ExternalExtractor(QObject* parent)
37  : ExtractorPlugin(parent),
38  d_ptr(new ExternalExtractorPrivate)
39 {
40 }
41 
42 ExternalExtractor::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 
79 ExternalExtractor::~ExternalExtractor() = default;
80 
81 QStringList ExternalExtractor::mimetypes() const
82 {
83  Q_D(const ExternalExtractor);
84 
85  return d->writeMimetypes;
86 }
87 
88 void 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 }
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode)
QString errorString() const const
virtual void addType(Type::Type type)=0
This function is called by the plugins.
QJsonObject object() const const
Property::Property property() const
The enumeration which represents this property.
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
The ExtractionResult class is where all the data extracted by the indexer is saved....
bool waitForFinished(int msecs)
QString inputMimetype() const
The input mimetype.
T value() const const
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
QJsonObject::const_iterator constEnd() const const
QString inputUrl() const
The input url which the plugins will use to locate the file.
KIOCORE_EXPORT MimetypeJob * mimetype(const QUrl &url, JobFlags flags=DefaultFlags)
void reserve(int alloc)
char * toString(const T &value)
QProcess::ExitStatus exitStatus() const const
bool waitForStarted(int msecs)
virtual QVariant rootObject()
static PropertyInfo fromName(const QString &name)
Construct a PropertyInfo from the internal property name.
bool isObject() const const
QString name() const
The internal unique name used to refer to the property.
QJsonObject::const_iterator constBegin() const const
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...
QByteArray readAllStandardError()
int count() const const
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...
QByteArray toJson() const const
void setObject(const QJsonObject &object)
The ExtractorPlugin is the base class for all file metadata extractors. It is responsible for extract...
QByteArray readAll()
void closeWriteChannel()
Q_D(Todo)
qint64 write(const char *data, qint64 maxSize)
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Fri May 27 2022 03:47:54 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.