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
21namespace KFileMetaData
22{
23class ExternalExtractorPrivate
24{
25public:
26 QString path;
27 QStringList writeMimetypes;
28 QString mainPath;
29};
30}
31
32using namespace KFileMetaData;
33
34ExternalExtractor::ExternalExtractor(QObject* parent)
35 : ExtractorPlugin(parent),
36 d_ptr(new ExternalExtractorPrivate)
37{
38}
39
40ExternalExtractor::ExternalExtractor(const QString& pluginPath)
41 : ExtractorPlugin(nullptr),
42 d_ptr(new ExternalExtractorPrivate)
43{
44 Q_D(ExternalExtractor);
45
46 d->path = pluginPath;
47
48 QDir pluginDir(pluginPath);
49 QStringList pluginDirContents = pluginDir.entryList(filters: QDir::Files | QDir::NoDotAndDotDot);
50
51 if (!pluginDirContents.contains(QStringLiteral("manifest.json"))) {
52 qCDebug(KFILEMETADATA_LOG) << pluginPath << "does not seem to contain a valid plugin";
53 return;
54 }
55
56 QFile manifest(pluginDir.filePath(QStringLiteral("manifest.json")));
57 manifest.open(flags: QIODevice::ReadOnly);
58 QJsonDocument manifestDoc = QJsonDocument::fromJson(json: manifest.readAll());
59 if (!manifestDoc.isObject()) {
60 qCDebug(KFILEMETADATA_LOG) << "Manifest does not seem to be a valid JSON Object";
61 return;
62 }
63
64 QJsonObject rootObject = manifestDoc.object();
65 const QJsonArray mimetypesArray = rootObject.value(QStringLiteral("mimetypes")).toArray();
66 QStringList mimetypes;
67 mimetypes.reserve(asize: mimetypesArray.count());
68
69 for (const QJsonValue &mimetype : mimetypesArray) {
70 mimetypes << mimetype.toString();
71 }
72
73 d->writeMimetypes.append(l: mimetypes);
74 d->mainPath = pluginDir.absoluteFilePath(fileName: rootObject[QStringLiteral("main")].toString());
75}
76
77ExternalExtractor::~ExternalExtractor() = default;
78
79QStringList ExternalExtractor::mimetypes() const
80{
81 Q_D(const ExternalExtractor);
82
83 return d->writeMimetypes;
84}
85
86void ExternalExtractor::extract(ExtractionResult* result)
87{
88 Q_D(ExternalExtractor);
89
90 QJsonDocument writeData;
91 QJsonObject writeRootObject;
92 QByteArray output;
93 QByteArray errorOutput;
94
95 writeRootObject[QStringLiteral("path")] = QJsonValue(result->inputUrl());
96 writeRootObject[QStringLiteral("mimetype")] = result->inputMimetype();
97 writeData.setObject(writeRootObject);
98
99 QProcess extractorProcess;
100 extractorProcess.start(program: d->mainPath, arguments: QStringList(), mode: QIODevice::ReadWrite);
101 bool started = extractorProcess.waitForStarted();
102 if (!started) {
103 qCWarning(KFILEMETADATA_LOG) << "External extractor" << d->mainPath
104 << "failed to start:" << extractorProcess.errorString();
105 return;
106 }
107
108 extractorProcess.write(data: writeData.toJson());
109 extractorProcess.closeWriteChannel();
110 extractorProcess.waitForFinished();
111
112 output = extractorProcess.readAll();
113 errorOutput = extractorProcess.readAllStandardError();
114
115 if (extractorProcess.exitStatus()) {
116 qCWarning(KFILEMETADATA_LOG) << "External extractor" << d->mainPath
117 << "failed to index" << result->inputUrl() << "-" << errorOutput;
118 return;
119 }
120
121 // now we read in the output (which is a standard json format) into the
122 // ExtractionResult
123
124 QJsonDocument extractorData = QJsonDocument::fromJson(json: output);
125 if (!extractorData.isObject()) {
126 return;
127 }
128 QJsonObject rootObject = extractorData.object();
129 QJsonObject propertiesObject = rootObject[QStringLiteral("properties")].toObject();
130
131 const auto propertiesObjectEnd = propertiesObject.constEnd();
132 auto i = propertiesObject.constBegin();
133 for (; i != propertiesObjectEnd; ++i) {
134 if (i.key() == QStringLiteral("typeInfo")) {
135 TypeInfo info = TypeInfo::fromName(name: i.value().toString());
136 result->addType(type: info.type());
137 continue;
138 }
139
140 // for plaintext extraction
141 if (i.key() == QStringLiteral("text")) {
142 result->append(text: i.value().toString());
143 continue;
144 }
145
146 PropertyInfo info = PropertyInfo::fromName(name: i.key());
147 if (info.name() != i.key()) {
148 continue;
149 }
150 result->add(property: info.property(), value: i.value().toVariant());
151 }
152
153 if (rootObject[QStringLiteral("status")].toString() != QStringLiteral("OK")) {
154 qCDebug(KFILEMETADATA_LOG) << rootObject[QStringLiteral("error")].toString();
155 }
156}
157
158#include "moc_externalextractor.cpp"
159

source code of kfilemetadata/src/externalextractor.cpp