KFileMetaData

extractorcollection.cpp
1/*
2 SPDX-FileCopyrightText: 2012 Vishesh Handa <me@vhanda.in>
3 SPDX-FileCopyrightText: 2016 Varun Joshi <varunj.1011@gmail.com>
4
5 SPDX-License-Identifier: LGPL-2.1-or-later
6*/
7
8#include "extractorcollection.h"
9#include "extractor_p.h"
10#include "extractorplugin.h"
11#include "externalextractor.h"
12#include "kfilemetadata_debug.h"
13#include "config-kfilemetadata.h"
14
15#include <KPluginMetaData>
16#include <QCoreApplication>
17#include <QDir>
18#include <QMimeDatabase>
19#include <vector>
20
21using namespace KFileMetaData;
22
23class KFileMetaData::ExtractorCollectionPrivate
24{
25public:
26 QMultiHash<QString, Extractor*> m_mimeExtractors;
27
28 std::vector<Extractor> m_allExtractors;
29
30 void findExtractors();
31 QList<Extractor*> getExtractors(const QString& mimetype);
32};
33
34ExtractorCollection::ExtractorCollection()
35 : d(new ExtractorCollectionPrivate)
36{
37 d->findExtractors();
38}
39
40ExtractorCollection::~ExtractorCollection() = default;
41
42
43QList<Extractor*> ExtractorCollection::allExtractors()
44{
45 QList<Extractor*> plugins;
46 for (auto& ex : d->m_allExtractors) {
47 if (ex.d->initPlugin()) {
48 plugins.push_back(&ex);
49 }
50 }
51 return plugins;
52}
53
54void ExtractorCollectionPrivate::findExtractors()
55{
56 const QList<KPluginMetaData> kfilemetadataPlugins =
57 KPluginMetaData::findPlugins(QStringLiteral("kf6/kfilemetadata"), {}, KPluginMetaData::AllowEmptyMetaData);
58 for (const KPluginMetaData &plugin : kfilemetadataPlugins) {
59 Extractor extractor;
60 extractor.d->m_pluginPath = plugin.fileName();
61 extractor.setAutoDeletePlugin(Extractor::DoNotDeletePlugin);
62
63 if (!plugin.rawData().isEmpty()) {
64 const auto metadataMap = plugin.rawData().toVariantMap();
65 if (!metadataMap.contains(QLatin1String("Name"))) {
66 qCWarning(KFILEMETADATA_LOG) << "Found plugin with invalid metadata (missing Name):" << extractor.d->m_pluginPath;
67 } else if (!metadataMap.contains(QLatin1String("MimeTypes"))) {
68 qCWarning(KFILEMETADATA_LOG) << "Found plugin with invalid metadata (missing MimeTypes):" << extractor.d->m_pluginPath;
69 } else {
70 qCWarning(KFILEMETADATA_LOG) << "Found plugin with metadata:" << extractor.d->m_pluginPath;
71 extractor.setMetaData(metadataMap);
72 m_allExtractors.push_back(std::move(extractor));
73 }
74 } else {
75 qCWarning(KFILEMETADATA_LOG) << "Found plugin without metadata (deprecated):" << extractor.d->m_pluginPath;
76 if (extractor.d->initPlugin() && !extractor.mimetypes().isEmpty()) {
77 m_allExtractors.push_back(std::move(extractor));
78 }
79 }
80 }
81
82 QStringList externalPlugins;
83 const QDir externalPluginDir(QStringLiteral(LIBEXEC_INSTALL_DIR "/kfilemetadata/externalextractors"));
84 qCDebug(KFILEMETADATA_LOG) << "Searching for external extractors:" << externalPluginDir.path();
85 // For external plugins, we look into the directories
86 const QStringList externalPluginEntryList = externalPluginDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
87 for (const QString &externalPlugin : externalPluginEntryList) {
88 if (externalPlugins.contains(externalPlugin)) {
89 qCDebug(KFILEMETADATA_LOG) << "Skipping duplicate - " << externalPluginDir.path() << ":" << externalPlugin;
90 continue;
91 }
92
93 qCDebug(KFILEMETADATA_LOG) << "Adding plugin - " << externalPluginDir.path() << ":" << externalPlugin;
94 externalPlugins << externalPlugin;
95
96 Extractor extractor;
97 auto pluginPath = externalPluginDir.absoluteFilePath(externalPlugin);
98 ExternalExtractor *plugin = new ExternalExtractor(pluginPath);
99 if (plugin && !plugin->mimetypes().isEmpty()) {
100 extractor.setExtractorPlugin(plugin);
101 extractor.setAutoDeletePlugin(Extractor::AutoDeletePlugin);
102 m_allExtractors.push_back(std::move(extractor));
103 }
104 }
105 externalPlugins.clear();
106
107 for (Extractor& extractor : m_allExtractors) {
108 auto pluginProperties = extractor.extractorProperties();
109 if (!pluginProperties.isEmpty()) {
110 auto mimetypeProperties = pluginProperties[QLatin1String("MimeTypes")];
111 if (mimetypeProperties.metaType() != QMetaType(QMetaType::QVariantMap)) {
112 qCWarning(KFILEMETADATA_LOG) << "Invalid MimeTypes property in" << pluginProperties;
113 } else {
114 const auto mimetypes = mimetypeProperties.toMap();
115 for (const auto [mimetype, v] : mimetypes.asKeyValueRange()) {
116 m_mimeExtractors.insert(mimetype, &extractor);
117 }
118 }
119 } else if (extractor.d->m_plugin) {
120 const auto mimetypes = extractor.mimetypes();
121 for (const QString &mimetype : mimetypes) {
122 m_mimeExtractors.insert(mimetype, &extractor);
123 }
124 }
125 }
126}
127
128QList<Extractor*> ExtractorCollectionPrivate::getExtractors(const QString& mimetype)
129{
130 QList<Extractor*> extractors = m_mimeExtractors.values(mimetype);
131
132 if (extractors.isEmpty()) {
133 qCDebug(KFILEMETADATA_LOG) << "No extractor for" << mimetype;
134 return extractors;
135 }
136
137 qCDebug(KFILEMETADATA_LOG) << "Fetching extractors for" << mimetype;
138 Extractor* failed = nullptr;
139 for (auto ex : extractors) {
140 if (!ex->d->initPlugin()) {
141 failed = ex;
142 break;
143 }
144 }
145
146 if (!failed) {
147 return extractors;
148 }
149
150 auto it = m_mimeExtractors.begin();
151 while (it != m_mimeExtractors.end()) {
152 if (it.value() == failed) {
153 it = m_mimeExtractors.erase(it);
154 } else {
155 ++it;
156 }
157 }
158 return getExtractors(mimetype);
159}
160
162{
163 QList<Extractor*> plugins = d->getExtractors(mimetype);
164 if (!plugins.isEmpty()) {
165 return plugins;
166 }
167
168 // try to find the best matching more generic extractor by mimetype inheritance
169 QMimeDatabase db;
170 auto type = db.mimeTypeForName(mimetype);
171 const QStringList ancestors = type.allAncestors();
172
173 for (const auto &ancestor : ancestors) {
174 if (ancestor == QLatin1String("application/octet-stream")) {
175 continue;
176 }
177 QList<Extractor*> plugins = d->getExtractors(ancestor);
178 if (!plugins.isEmpty()) {
179 qCDebug(KFILEMETADATA_LOG) << "Using inherited mimetype" << ancestor << "for" << mimetype;
180 return plugins;
181 }
182 }
183
184 return plugins;
185}
QList< Extractor * > fetchExtractors(const QString &mimetype) const
Fetch the extractors which can be used to extract data for the respective file with the given MIME ty...
static QList< KPluginMetaData > findPlugins(const QString &directory, std::function< bool(const KPluginMetaData &)> filter={}, KPluginMetaDataOptions options={})
The KFileMetaData namespace.
KIOCORE_EXPORT MimetypeJob * mimetype(const QUrl &url, JobFlags flags=DefaultFlags)
void clear()
bool isEmpty() const const
void push_back(parameter_type value)
QMimeType mimeTypeForName(const QString &nameOrAlias) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Feb 21 2025 11:53:46 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.