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 qCDebug(KFILEMETADATA_LOG) << "Found plugin with metadata:" << extractor.d->m_pluginPath;
65 extractor.setMetaData(plugin.rawData().toVariantMap());
66 m_allExtractors.push_back(std::move(extractor));
67 } else {
68 qCDebug(KFILEMETADATA_LOG) << "Found plugin without metadata:" << extractor.d->m_pluginPath;
69 if (extractor.d->initPlugin() && !extractor.mimetypes().isEmpty()) {
70 m_allExtractors.push_back(std::move(extractor));
71 }
72 }
73 }
74
75 QStringList externalPlugins;
76 const QDir externalPluginDir(QStringLiteral(LIBEXEC_INSTALL_DIR "/kfilemetadata/externalextractors"));
77 qCDebug(KFILEMETADATA_LOG) << "Searching for external extractors:" << externalPluginDir.path();
78 // For external plugins, we look into the directories
79 const QStringList externalPluginEntryList = externalPluginDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
80 for (const QString &externalPlugin : externalPluginEntryList) {
81 if (externalPlugins.contains(externalPlugin)) {
82 qCDebug(KFILEMETADATA_LOG) << "Skipping duplicate - " << externalPluginDir.path() << ":" << externalPlugin;
83 continue;
84 }
85
86 qCDebug(KFILEMETADATA_LOG) << "Adding plugin - " << externalPluginDir.path() << ":" << externalPlugin;
87 externalPlugins << externalPlugin;
88
89 Extractor extractor;
90 auto pluginPath = externalPluginDir.absoluteFilePath(externalPlugin);
91 ExternalExtractor *plugin = new ExternalExtractor(pluginPath);
92 if (plugin && !plugin->mimetypes().isEmpty()) {
93 extractor.setExtractorPlugin(plugin);
94 extractor.setAutoDeletePlugin(Extractor::AutoDeletePlugin);
95 m_allExtractors.push_back(std::move(extractor));
96 }
97 }
98 externalPlugins.clear();
99
100 for (Extractor& extractor : m_allExtractors) {
101 auto pluginProperties = extractor.extractorProperties();
102 if (!pluginProperties.isEmpty()) {
103 auto mimetypeProperties = pluginProperties[QLatin1String("MimeTypes")];
104 const auto mimetypes = mimetypeProperties.toMap().keys();
105 for (const QString &mimetype : mimetypes) {
106 m_mimeExtractors.insert(mimetype, &extractor);
107 }
108 } else if (extractor.d->m_plugin) {
109 const auto mimetypes = extractor.mimetypes();
110 for (const QString &mimetype : mimetypes) {
111 m_mimeExtractors.insert(mimetype, &extractor);
112 }
113 }
114 }
115}
116
117QList<Extractor*> ExtractorCollectionPrivate::getExtractors(const QString& mimetype)
118{
119 QList<Extractor*> extractors = m_mimeExtractors.values(mimetype);
120
121 if (extractors.isEmpty()) {
122 qCDebug(KFILEMETADATA_LOG) << "No extractor for" << mimetype;
123 return extractors;
124 }
125
126 qCDebug(KFILEMETADATA_LOG) << "Fetching extractors for" << mimetype;
127 Extractor* failed = nullptr;
128 for (auto ex : extractors) {
129 if (!ex->d->initPlugin()) {
130 failed = ex;
131 break;
132 }
133 }
134
135 if (!failed) {
136 return extractors;
137 }
138
139 auto it = m_mimeExtractors.begin();
140 while (it != m_mimeExtractors.end()) {
141 if (it.value() == failed) {
142 it = m_mimeExtractors.erase(it);
143 } else {
144 ++it;
145 }
146 }
147 return getExtractors(mimetype);
148}
149
151{
152 QList<Extractor*> plugins = d->getExtractors(mimetype);
153 if (!plugins.isEmpty()) {
154 return plugins;
155 }
156
157 // try to find the best matching more generic extractor by mimetype inheritance
158 QMimeDatabase db;
159 auto type = db.mimeTypeForName(mimetype);
160 const QStringList ancestors = type.allAncestors();
161
162 for (const auto &ancestor : ancestors) {
163 if (ancestor == QLatin1String("application/octet-stream")) {
164 continue;
165 }
166 QList<Extractor*> plugins = d->getExtractors(ancestor);
167 if (!plugins.isEmpty()) {
168 qCDebug(KFILEMETADATA_LOG) << "Using inherited mimetype" << ancestor << "for" << mimetype;
169 return plugins;
170 }
171 }
172
173 return plugins;
174}
QList< Extractor * > fetchExtractors(const QString &mimetype) const
Fetch the extractors which can be used to extract data for the respective file with the given mimetyp...
static QList< KPluginMetaData > findPlugins(const QString &directory, std::function< bool(const KPluginMetaData &)> filter={}, KPluginMetaDataOptions options={})
KIOCORE_EXPORT MimetypeJob * mimetype(const QUrl &url, JobFlags flags=DefaultFlags)
void clear()
bool isEmpty() const const
void push_back(const T &value)
QMimeType mimeTypeForName(const QString &nameOrAlias) const const
typename QHash< Key, T >::iterator insert(const Key &key, const T &value)
QList< T > values(const Key &key) const const
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
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.