KFileMetaData

extractorcollection.cpp
1 /*
2  * Copyright (C) 2012 Vishesh Handa <[email protected]>
3  * Copyright (C) 2016 Varun Joshi <[email protected]>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19  */
20 
21 #include "extractorcollection.h"
22 #include "extractor.h"
23 #include "extractor_p.h"
24 #include "extractorplugin.h"
25 #include "externalextractor.h"
26 #include "kfilemetadata_debug.h"
27 #include "config-kfilemetadata.h"
28 
29 #include <QMimeDatabase>
30 #include <QCoreApplication>
31 #include <QPluginLoader>
32 #include <QDir>
33 #include <vector>
34 
35 using namespace KFileMetaData;
36 
37 class Q_DECL_HIDDEN ExtractorCollection::Private
38 {
39 public:
40  QMultiHash<QString, Extractor*> m_mimeExtractors;
41 
42  std::vector<Extractor> m_allExtractors;
43 
44  void findExtractors();
45  QList<Extractor*> getExtractors(const QString& mimetype);
46 };
47 
48 ExtractorCollection::ExtractorCollection()
49  : d(new Private)
50 {
51  d->findExtractors();
52 }
53 
54 ExtractorCollection::~ExtractorCollection()
55 {
56  delete d;
57 }
58 
59 
60 QList<Extractor*> ExtractorCollection::allExtractors()
61 {
62  QList<Extractor*> plugins;
63  for (auto& ex : d->m_allExtractors) {
64  if (ex.d->initPlugin()) {
65  plugins.push_back(&ex);
66  }
67  }
68  return plugins;
69 }
70 
71 void ExtractorCollection::Private::findExtractors()
72 {
73  QStringList plugins;
74  QStringList externalPlugins;
75 
77  for (const QString& libraryPath : paths) {
78  QString path(libraryPath + QStringLiteral("/kf5/kfilemetadata"));
79  QDir dir(path);
80  qCDebug(KFILEMETADATA_LOG) << "Searching for extractors:" << dir.path();
81 
82  if (!dir.exists()) {
83  continue;
84  }
85 
86  const QStringList entryList = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
87  for (const QString& fileName : entryList) {
88  // Make sure the same plugin is not loaded twice, even if it is
89  // installed in two different locations
90  if (plugins.contains(fileName)) {
91  qCDebug(KFILEMETADATA_LOG) << "Skipping duplicate - " << path << ":" << fileName;
92  continue;
93  }
94 
95  plugins << fileName;
96 
97  Extractor extractor;
98  extractor.setAutoDeletePlugin(Extractor::DoNotDeletePlugin);
99  auto pluginPath = dir.absoluteFilePath(fileName);
100 
101  QPluginLoader loader(pluginPath);
102  auto metadata = loader.metaData().value(QLatin1String("MetaData"));
103  if (metadata.type() == QJsonValue::Object) {
104  qCDebug(KFILEMETADATA_LOG) << "Found plugin with metadata:" << metadata.toObject();
105  auto pluginProperties = metadata.toObject().toVariantMap();
106  extractor.setMetaData(pluginProperties);
107  extractor.d->m_pluginPath = pluginPath;
108  m_allExtractors.push_back(std::move(extractor));
109  } else {
110  qCDebug(KFILEMETADATA_LOG) << "Found plugin without metadata:" << pluginPath;
111  extractor.d->m_pluginPath = pluginPath;
112  if (extractor.d->initPlugin() && !extractor.mimetypes().isEmpty()) {
113  m_allExtractors.push_back(std::move(extractor));
114  }
115  }
116  }
117  }
118  plugins.clear();
119 
120  QDir externalPluginDir(QStringLiteral(LIBEXEC_INSTALL_DIR) + QStringLiteral("/kfilemetadata/externalextractors"));
121  qCDebug(KFILEMETADATA_LOG) << "Searching for external extractors:" << externalPluginDir.path();
122  // For external plugins, we look into the directories
123  const QStringList externalPluginEntryList = externalPluginDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
124  for (const QString& externalPlugin : externalPluginEntryList) {
125  if (externalPlugins.contains(externalPlugin)) {
126  qCDebug(KFILEMETADATA_LOG) << "Skipping duplicate - "
127  << externalPluginDir.path() << ":" << externalPlugin;
128  continue;
129  }
130 
131  qCDebug(KFILEMETADATA_LOG) << "Adding plugin - " << externalPluginDir.path() << ":" << externalPlugin;
132  externalPlugins << externalPlugin;
133 
134  Extractor extractor;
135  auto pluginPath = externalPluginDir.absoluteFilePath(externalPlugin);
136 
137  ExternalExtractor *plugin = new ExternalExtractor(pluginPath);
138  if (plugin && !plugin->mimetypes().isEmpty()) {
139  extractor.setExtractorPlugin(plugin);
140  extractor.setAutoDeletePlugin(Extractor::AutoDeletePlugin);
141  m_allExtractors.push_back(std::move(extractor));
142  }
143  }
144  externalPlugins.clear();
145 
146  for (Extractor& extractor : m_allExtractors) {
147  auto pluginProperties = extractor.extractorProperties();
148  if (!pluginProperties.isEmpty()) {
149  auto mimetypeProperties = pluginProperties[QLatin1String("MimeTypes")];
150  const auto mimetypes = mimetypeProperties.toMap().keys();
151  for (const QString &mimetype : mimetypes) {
152  m_mimeExtractors.insert(mimetype, &extractor);
153  }
154  } else if (extractor.d->m_plugin) {
155  const auto mimetypes = extractor.mimetypes();
156  for (const QString &mimetype : mimetypes) {
157  m_mimeExtractors.insert(mimetype, &extractor);
158  }
159  }
160  }
161 }
162 
163 QList<Extractor*> ExtractorCollection::Private::getExtractors(const QString& mimetype)
164 {
165  QList<Extractor*> extractors = m_mimeExtractors.values(mimetype);
166 
167  if (extractors.isEmpty()) {
168  qCDebug(KFILEMETADATA_LOG) << "No extractor for" << mimetype;
169  return extractors;
170  }
171 
172  qCDebug(KFILEMETADATA_LOG) << "Fetching extractors for" << mimetype;
173  Extractor* failed = nullptr;
174  for (auto ex : extractors) {
175  if (!ex->d->initPlugin()) {
176  failed = ex;
177  break;
178  }
179  }
180 
181  if (!failed) {
182  return extractors;
183  }
184 
185  auto it = m_mimeExtractors.begin();
186  while (it != m_mimeExtractors.end()) {
187  if (it.value() == failed) {
188  it = m_mimeExtractors.erase(it);
189  } else {
190  ++it;
191  }
192  }
193  return getExtractors(mimetype);
194 }
195 
197 {
198  QList<Extractor*> plugins = d->getExtractors(mimetype);
199  if (!plugins.isEmpty()) {
200  return plugins;
201  }
202 
203  // try to find the best matching more generic extractor by mimetype inheritance
204  QMimeDatabase db;
205  auto type = db.mimeTypeForName(mimetype);
206  const QStringList ancestors = type.allAncestors();
207 
208  for (const auto &ancestor : ancestors) {
209  if (ancestor == QLatin1String("application/octet-stream")) {
210  continue;
211  }
212  QList<Extractor*> plugins = d->getExtractors(ancestor);
213  if (!plugins.isEmpty()) {
214  qCDebug(KFILEMETADATA_LOG) << "Using inherited mimetype" << ancestor << "for" << mimetype;
215  return plugins;
216  }
217  }
218 
219  return plugins;
220 }
void clear()
void push_back(const T &value)
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
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...
bool isEmpty() const const
The ExtractorCollection is a helper class which internally loads all the extractor plugins...
QMimeType mimeTypeForName(const QString &nameOrAlias) const const
QStringList libraryPaths()
KIOFILEWIDGETS_EXPORT QString dir(const QString &fileClass)
QString::iterator begin()
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon May 25 2020 23:11:16 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.