diff --git a/src/embeddedimagedata.cpp b/src/embeddedimagedata.cpp index d62f765..cea2b05 100644 --- a/src/embeddedimagedata.cpp +++ b/src/embeddedimagedata.cpp @@ -1,290 +1,289 @@ /* * Copyright (C) 2018 Alexander Stippich * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "embeddedimagedata.h" // Taglib includes #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KFileMetaData; class Q_DECL_HIDDEN EmbeddedImageData::Private { public: QMimeDatabase mMimeDatabase; QByteArray getFrontCover(const QString &fileUrl, const QString &mimeType) const; QByteArray getFrontCoverFromID3(TagLib::ID3v2::Tag* Id3Tags) const; QByteArray getFrontCoverFromFlacPicture(TagLib::List lstPic) const; QByteArray getFrontCoverFromMp4(TagLib::MP4::Tag* mp4Tags) const; QByteArray getFrontCoverFromApe(TagLib::APE::Tag* apeTags) const; QByteArray getFrontCoverFromAsf(TagLib::ASF::Tag* asfTags) const; static const QStringList mMimetypes; }; const QStringList EmbeddedImageData::Private::mMimetypes = { QStringLiteral("audio/flac"), QStringLiteral("audio/mp4"), QStringLiteral("audio/mpeg"), QStringLiteral("audio/mpeg3"), QStringLiteral("audio/ogg"), QStringLiteral("audio/opus"), QStringLiteral("audio/speex"), QStringLiteral("audio/wav"), QStringLiteral("audio/x-aiff"), QStringLiteral("audio/x-ape"), QStringLiteral("audio/x-mpeg"), QStringLiteral("audio/x-ms-wma"), QStringLiteral("audio/x-musepack"), QStringLiteral("audio/x-opus+ogg"), QStringLiteral("audio/x-speex"), QStringLiteral("audio/x-vorbis+ogg"), QStringLiteral("audio/x-wav"), QStringLiteral("audio/x-wavpack"), }; EmbeddedImageData::EmbeddedImageData() : d(std::unique_ptr(new Private())) { } EmbeddedImageData::~EmbeddedImageData() = default; QStringList EmbeddedImageData::mimeTypes() const { return d->mMimetypes; } QMap EmbeddedImageData::imageData(const QString &fileUrl, const EmbeddedImageData::ImageTypes types) const { QMap imageData; const auto &fileMimeType = d->mMimeDatabase.mimeTypeForFile(fileUrl); if (fileMimeType.name().startsWith(QLatin1String("audio/"))) { if (types & EmbeddedImageData::FrontCover) { imageData.insert(EmbeddedImageData::FrontCover, d->getFrontCover(fileUrl, fileMimeType.name())); } } return imageData; } QByteArray EmbeddedImageData::Private::getFrontCover(const QString &fileUrl, const QString &mimeType) const { TagLib::FileStream stream(fileUrl.toUtf8().constData(), true); if (!stream.isOpen()) { qWarning() << "Unable to open file readonly: " << fileUrl; return QByteArray(); } if ((mimeType == QLatin1String("audio/mpeg")) || (mimeType == QLatin1String("audio/mpeg3")) || (mimeType == QLatin1String("audio/x-mpeg"))) { // Handling multiple tags in mpeg files. TagLib::MPEG::File mpegFile(&stream, TagLib::ID3v2::FrameFactory::instance(), true); if (mpegFile.ID3v2Tag()) { return getFrontCoverFromID3(mpegFile.ID3v2Tag()); } } else if (mimeType == QLatin1String("audio/x-aiff")) { TagLib::RIFF::AIFF::File aiffFile(&stream, true); if (aiffFile.hasID3v2Tag()) { return getFrontCoverFromID3(aiffFile.tag()); } } else if ((mimeType == QLatin1String("audio/wav")) || (mimeType == QLatin1String("audio/x-wav"))) { TagLib::RIFF::WAV::File wavFile(&stream, true); if (wavFile.hasID3v2Tag()) { return getFrontCoverFromID3(wavFile.ID3v2Tag()); } } else if (mimeType == QLatin1String("audio/mp4")) { TagLib::MP4::File mp4File(&stream, true); if (mp4File.tag()) { return getFrontCoverFromMp4(mp4File.tag()); } } else if (mimeType == QLatin1String("audio/x-musepack")) { TagLib::MPC::File mpcFile(&stream, true); if (mpcFile.APETag()) { return getFrontCoverFromApe(mpcFile.APETag()); } } else if (mimeType == QLatin1String("audio/x-ape")) { TagLib::APE::File apeFile(&stream, true); if (apeFile.hasAPETag()) { return getFrontCoverFromApe(apeFile.APETag()); } } else if (mimeType == QLatin1String("audio/x-wavpack")) { TagLib::WavPack::File wavpackFile(&stream, true); if (wavpackFile.hasAPETag()) { return getFrontCoverFromApe(wavpackFile.APETag()); } } else if (mimeType == QLatin1String("audio/x-ms-wma")) { TagLib::ASF::File asfFile(&stream, true); TagLib::ASF::Tag* asfTags = dynamic_cast(asfFile.tag()); if (asfTags) { return getFrontCoverFromAsf(asfTags); } } else if (mimeType == QLatin1String("audio/flac")) { TagLib::FLAC::File flacFile(&stream, TagLib::ID3v2::FrameFactory::instance(), true); return getFrontCoverFromFlacPicture(flacFile.pictureList()); } else if ((mimeType == QLatin1String("audio/ogg")) || (mimeType == QLatin1String("audio/x-vorbis+ogg"))) { TagLib::Ogg::Vorbis::File oggFile(&stream, true); if (oggFile.tag()) { return getFrontCoverFromFlacPicture(oggFile.tag()->pictureList()); } } else if ((mimeType == QLatin1String("audio/opus")) || (mimeType == QLatin1String("audio/x-opus+ogg"))) { TagLib::Ogg::Opus::File opusFile(&stream, true); if (opusFile.tag()) { return getFrontCoverFromFlacPicture(opusFile.tag()->pictureList()); } } else if (mimeType == QLatin1String("audio/speex") || mimeType == QLatin1String("audio/x-speex")) { TagLib::Ogg::Speex::File speexFile(&stream, true); if (speexFile.tag()) { return getFrontCoverFromFlacPicture(speexFile.tag()->pictureList()); } } return QByteArray(); } QByteArray EmbeddedImageData::Private::getFrontCoverFromID3(TagLib::ID3v2::Tag* Id3Tags) const { TagLib::ID3v2::FrameList lstID3v2; // Attached Front Picture. lstID3v2 = Id3Tags->frameListMap()["APIC"]; for (const auto& frame : qAsConst(lstID3v2)) { const auto *frontCoverFrame = static_cast(frame); if (frontCoverFrame->type() == frontCoverFrame->FrontCover) { return QByteArray(frontCoverFrame->picture().data(), frontCoverFrame->picture().size()); } } return QByteArray(); } QByteArray EmbeddedImageData::Private::getFrontCoverFromFlacPicture(TagLib::List lstPic) const { for (const auto &picture : qAsConst(lstPic)) { if (picture->type() == picture->FrontCover) { return QByteArray(picture->data().data(), picture->data().size()); } } return QByteArray(); } QByteArray EmbeddedImageData::Private::getFrontCoverFromMp4(TagLib::MP4::Tag* mp4Tags) const { TagLib::MP4::Item coverArtItem = mp4Tags->item("covr"); if (coverArtItem.isValid()) { TagLib::MP4::CoverArtList coverArtList = coverArtItem.toCoverArtList(); TagLib::MP4::CoverArt& frontCover = coverArtList.front(); return QByteArray(frontCover.data().data(), frontCover.data().size()); } return QByteArray(); } QByteArray EmbeddedImageData::Private::getFrontCoverFromApe(TagLib::APE::Tag* apeTags) const { TagLib::APE::ItemListMap lstApe = apeTags->itemListMap(); TagLib::APE::ItemListMap::ConstIterator itApe; /* The cover art tag for APEv2 tags starts with the filename as string * with zero termination followed by the actual picture data */ itApe = lstApe.find("COVER ART (FRONT)"); if (itApe != lstApe.end()) { TagLib::ByteVector pictureData = (*itApe).second.binaryData(); int position = pictureData.find('\0'); if (position >= 0) { position += 1; return QByteArray(pictureData.data() + position, pictureData.size() - position); } } return QByteArray(); } QByteArray EmbeddedImageData::Private::getFrontCoverFromAsf(TagLib::ASF::Tag* asfTags) const { TagLib::ASF::AttributeList lstASF = asfTags->attribute("WM/Picture"); for (const auto& attribute : qAsConst(lstASF)) { TagLib::ASF::Picture picture = attribute.toPicture(); if (picture.type() == TagLib::ASF::Picture::FrontCover) { TagLib::ByteVector pictureData = picture.picture(); return QByteArray(pictureData.data(), pictureData.size()); } } return QByteArray(); } diff --git a/src/externalextractor.cpp b/src/externalextractor.cpp index b31c2a9..50b4f2b 100644 --- a/src/externalextractor.cpp +++ b/src/externalextractor.cpp @@ -1,175 +1,174 @@ /* * This file is part of the KFileMetaData project * Copyright (C) 2016 Varun Joshi * Copyright (C) 2015 Boudhayan Gupta * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include "externalextractor.h" #include "kfilemetadata_debug.h" +#include "properties.h" +#include "propertyinfo.h" +#include "typeinfo.h" #include #include #include #include #include -#include "properties.h" -#include "propertyinfo.h" -#include "typeinfo.h" - #define EXTRACTOR_TIMEOUT_MS 30000 using namespace KFileMetaData; class Q_DECL_HIDDEN ExternalExtractor::ExternalExtractorPrivate { public: QString path; QStringList writeMimetypes; QString mainPath; }; ExternalExtractor::ExternalExtractor(QObject* parent) : ExtractorPlugin(parent), d_ptr(new ExternalExtractorPrivate) { } ExternalExtractor::ExternalExtractor(const QString& pluginPath) : ExtractorPlugin(nullptr), d_ptr(new ExternalExtractorPrivate) { Q_D(ExternalExtractor); d->path = pluginPath; QDir pluginDir(pluginPath); QStringList pluginDirContents = pluginDir.entryList(QDir::Files | QDir::NoDotAndDotDot); if (!pluginDirContents.contains(QStringLiteral("manifest.json"))) { qCDebug(KFILEMETADATA_LOG) << pluginPath << "does not seem to contain a valid plugin"; return; } QFile manifest(pluginDir.filePath(QStringLiteral("manifest.json"))); manifest.open(QIODevice::ReadOnly); QJsonDocument manifestDoc = QJsonDocument::fromJson(manifest.readAll()); if (!manifestDoc.isObject()) { qCDebug(KFILEMETADATA_LOG) << "Manifest does not seem to be a valid JSON Object"; return; } QJsonObject rootObject = manifestDoc.object(); const QJsonArray mimetypesArray = rootObject.value(QStringLiteral("mimetypes")).toArray(); QStringList mimetypes; mimetypes.reserve(mimetypesArray.count()); for (const QVariant &mimetype : mimetypesArray) { mimetypes << mimetype.toString(); } d->writeMimetypes.append(mimetypes); d->mainPath = pluginDir.filePath(rootObject[QStringLiteral("main")].toString()); } ExternalExtractor::~ExternalExtractor() { delete d_ptr; } QStringList ExternalExtractor::mimetypes() const { Q_D(const ExternalExtractor); return d->writeMimetypes; } void ExternalExtractor::extract(ExtractionResult* result) { Q_D(ExternalExtractor); QJsonDocument writeData; QJsonObject writeRootObject; QByteArray output; QByteArray errorOutput; writeRootObject[QStringLiteral("path")] = QJsonValue(result->inputUrl()); writeRootObject[QStringLiteral("mimetype")] = result->inputMimetype(); writeData.setObject(writeRootObject); QProcess extractorProcess; extractorProcess.start(d->mainPath, QStringList(), QIODevice::ReadWrite); bool started = extractorProcess.waitForStarted(); if (!started) { qCWarning(KFILEMETADATA_LOG) << "External extractor" << d->mainPath << "failed to start:" << extractorProcess.errorString(); return; } extractorProcess.write(writeData.toJson()); extractorProcess.closeWriteChannel(); extractorProcess.waitForFinished(EXTRACTOR_TIMEOUT_MS); output = extractorProcess.readAll(); errorOutput = extractorProcess.readAllStandardError(); if (extractorProcess.exitStatus()) { qCWarning(KFILEMETADATA_LOG) << "External extractor" << d->mainPath << "failed to index" << result->inputUrl() << "-" << errorOutput; return; } // now we read in the output (which is a standard json format) into the // ExtractionResult QJsonDocument extractorData = QJsonDocument::fromJson(output); if (!extractorData.isObject()) { return; } QJsonObject rootObject = extractorData.object(); QJsonObject propertiesObject = rootObject[QStringLiteral("properties")].toObject(); const auto propertiesObjectEnd = propertiesObject.constEnd(); auto i = propertiesObject.constBegin(); for (; i != propertiesObjectEnd; ++i) { if (i.key() == QStringLiteral("typeInfo")) { TypeInfo info = TypeInfo::fromName(propertiesObject.value(i.key()).toString()); result->addType(info.type()); continue; } // for plaintext extraction if (i.key() == QStringLiteral("text")) { result->append(propertiesObject.value(i.key()).toString(QStringLiteral(""))); continue; } PropertyInfo info = PropertyInfo::fromName(i.key()); if (info.name() != i.key()) { continue; } result->add(info.property(), i.value().toVariant()); } if (rootObject[QStringLiteral("status")].toString() != QStringLiteral("OK")) { qCDebug(KFILEMETADATA_LOG) << rootObject[QStringLiteral("error")].toString(); } } diff --git a/src/externalwriter.cpp b/src/externalwriter.cpp index 19cb093..7b6b149 100644 --- a/src/externalwriter.cpp +++ b/src/externalwriter.cpp @@ -1,149 +1,148 @@ /* * This file is part of the KFileMetaData project * Copyright (C) 2016 Varun Joshi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ + +#include "externalwriter.h" +#include "properties.h" +#include "propertyinfo.h" #include "kfilemetadata_debug.h" #include #include #include #include #include - #include -#include "externalwriter.h" -#include "properties.h" -#include "propertyinfo.h" - #define WRITER_TIMEOUT_MS 30000 using namespace KFileMetaData; class Q_DECL_HIDDEN ExternalWriter::ExternalWriterPrivate { public: QString path; QStringList writeMimetypes; QString mainPath; }; ExternalWriter::ExternalWriter(QObject* parent) : WriterPlugin(parent), d_ptr(new ExternalWriterPrivate) { } ExternalWriter::~ExternalWriter() { delete d_ptr; } ExternalWriter::ExternalWriter(const QString& pluginPath) : WriterPlugin(new QObject()), d_ptr(new ExternalWriterPrivate) { Q_D(ExternalWriter); d->path = pluginPath; QDir pluginDir(pluginPath); QStringList pluginDirContents = pluginDir.entryList(); if (!pluginDirContents.contains(QStringLiteral("manifest.json"))) { qCDebug(KFILEMETADATA_LOG) << "Path does not seem to contain a valid plugin"; return; } QFile manifest(pluginDir.filePath(QStringLiteral("manifest.json"))); manifest.open(QIODevice::ReadOnly); QJsonDocument manifestDoc = QJsonDocument::fromJson(manifest.readAll()); if (!manifestDoc.isObject()) { qCDebug(KFILEMETADATA_LOG) << "Manifest does not seem to be a valid JSON Object"; return; } QJsonObject rootObject = manifestDoc.object(); const QJsonArray mimetypesArray = rootObject.value(QStringLiteral("mimetypes")).toArray(); QStringList mimetypes; for (const QVariant &mimetype : mimetypesArray) { mimetypes << mimetype.toString(); } d->writeMimetypes.append(mimetypes); d->mainPath = pluginDir.filePath(rootObject[QStringLiteral("main")].toString()); } QStringList ExternalWriter::writeMimetypes() const { Q_D(const ExternalWriter); return d->writeMimetypes; } void ExternalWriter::write(const WriteData& data) { Q_D(ExternalWriter); QJsonDocument writeData; QJsonObject rootObject; QJsonObject propertiesObject; QByteArray output; QByteArray errorOutput; const QMap properties = data.getAllProperties(); QMap::const_iterator i = properties.constBegin(); while (i != properties.constEnd()) { PropertyInfo propertyInfo(i.key()); propertiesObject[propertyInfo.name()] = QJsonValue::fromVariant(properties[i.key()]); } rootObject[QStringLiteral("path")] = QJsonValue(data.inputUrl()); rootObject[QStringLiteral("mimetype")] = data.inputMimetype(); rootObject[QStringLiteral("properties")] = propertiesObject; writeData.setObject(rootObject); QProcess writerProcess; writerProcess.start(d->mainPath, QStringList(), QIODevice::ReadWrite); writerProcess.write(writeData.toJson()); writerProcess.closeWriteChannel(); writerProcess.waitForFinished(WRITER_TIMEOUT_MS); errorOutput = writerProcess.readAllStandardError(); if (writerProcess.exitStatus()) { qCDebug(KFILEMETADATA_LOG) << "Something went wrong while trying to write data"; qCDebug(KFILEMETADATA_LOG) << errorOutput; return; } output = writerProcess.readAll(); QJsonDocument writerExitData = QJsonDocument::fromJson(output); if (!writerExitData.isObject()) { return; } QJsonObject outputRootObject = writerExitData.object(); if (outputRootObject[QStringLiteral("status")].toString() != QStringLiteral("OK")) { qCDebug(KFILEMETADATA_LOG) << outputRootObject[QStringLiteral("error")].toString(); qCDebug(KFILEMETADATA_LOG) << errorOutput; } } diff --git a/src/extractorcollection.cpp b/src/extractorcollection.cpp index ffc29a7..5b93267 100644 --- a/src/extractorcollection.cpp +++ b/src/extractorcollection.cpp @@ -1,221 +1,220 @@ /* * Copyright (C) 2012 Vishesh Handa * Copyright (C) 2016 Varun Joshi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ +#include "extractorcollection.h" #include "extractor.h" #include "extractor_p.h" #include "extractorplugin.h" -#include "extractorcollection.h" #include "externalextractor.h" #include "kfilemetadata_debug.h" +#include "config-kfilemetadata.h" #include #include #include #include #include -#include "config-kfilemetadata.h" - using namespace KFileMetaData; class Q_DECL_HIDDEN ExtractorCollection::Private { public: QHash m_mimeExtractors; std::vector m_allExtractors; void findExtractors(); QList getExtractors(const QString& mimetype); }; ExtractorCollection::ExtractorCollection() : d(new Private) { d->findExtractors(); } ExtractorCollection::~ExtractorCollection() { delete d; } QList ExtractorCollection::allExtractors() { QList plugins; for (auto& ex : d->m_allExtractors) { if (ex.d->initPlugin()) { plugins.push_back(&ex); } } return plugins; } void ExtractorCollection::Private::findExtractors() { QStringList plugins; QStringList externalPlugins; const QStringList paths = QCoreApplication::libraryPaths(); for (const QString& libraryPath : paths) { QString path(libraryPath + QStringLiteral("/kf5/kfilemetadata")); QDir dir(path); qCDebug(KFILEMETADATA_LOG) << "Searching for extractors:" << dir.path(); if (!dir.exists()) { continue; } const QStringList entryList = dir.entryList(QDir::Files | QDir::NoDotAndDotDot); for (const QString& fileName : entryList) { // Make sure the same plugin is not loaded twice, even if it is // installed in two different locations if (plugins.contains(fileName)) { qCDebug(KFILEMETADATA_LOG) << "Skipping duplicate - " << path << ":" << fileName; continue; } plugins << fileName; Extractor extractor; extractor.setAutoDeletePlugin(Extractor::DoNotDeletePlugin); auto pluginPath = dir.absoluteFilePath(fileName); QPluginLoader loader(pluginPath); auto metadata = loader.metaData().value(QLatin1String("MetaData")); if (metadata.type() == QJsonValue::Object) { qCDebug(KFILEMETADATA_LOG) << "Found plugin with metadata:" << metadata.toObject(); auto pluginProperties = metadata.toObject().toVariantMap(); extractor.setMetaData(pluginProperties); extractor.d->m_pluginPath = pluginPath; m_allExtractors.push_back(std::move(extractor)); } else { qCDebug(KFILEMETADATA_LOG) << "Found plugin without metadata:" << pluginPath; extractor.d->m_pluginPath = pluginPath; if (extractor.d->initPlugin() && !extractor.mimetypes().isEmpty()) { m_allExtractors.push_back(std::move(extractor)); } } } } plugins.clear(); QDir externalPluginDir(QStringLiteral(LIBEXEC_INSTALL_DIR) + QStringLiteral("/kfilemetadata/externalextractors")); qCDebug(KFILEMETADATA_LOG) << "Searching for external extractors:" << externalPluginDir.path(); // For external plugins, we look into the directories const QStringList externalPluginEntryList = externalPluginDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); for (const QString& externalPlugin : externalPluginEntryList) { if (externalPlugins.contains(externalPlugin)) { qCDebug(KFILEMETADATA_LOG) << "Skipping duplicate - " << externalPluginDir.path() << ":" << externalPlugin; continue; } qCDebug(KFILEMETADATA_LOG) << "Adding plugin - " << externalPluginDir.path() << ":" << externalPlugin; externalPlugins << externalPlugin; Extractor extractor; auto pluginPath = externalPluginDir.absoluteFilePath(externalPlugin); ExternalExtractor *plugin = new ExternalExtractor(pluginPath); if (plugin && !plugin->mimetypes().isEmpty()) { extractor.setExtractorPlugin(plugin); extractor.setAutoDeletePlugin(Extractor::AutoDeletePlugin); m_allExtractors.push_back(std::move(extractor)); } } externalPlugins.clear(); for (Extractor& extractor : m_allExtractors) { auto pluginProperties = extractor.extractorProperties(); if (!pluginProperties.isEmpty()) { auto mimetypeProperties = pluginProperties[QLatin1String("MimeTypes")]; const auto mimetypes = mimetypeProperties.toMap().keys(); for (QString mimetype : mimetypes) { m_mimeExtractors.insertMulti(mimetype, &extractor); } } else if (extractor.d->m_plugin) { const auto mimetypes = extractor.mimetypes(); for (QString mimetype : mimetypes) { m_mimeExtractors.insertMulti(mimetype, &extractor); } } } } QList ExtractorCollection::Private::getExtractors(const QString& mimetype) { QList extractors = m_mimeExtractors.values(mimetype); if (extractors.isEmpty()) { qCDebug(KFILEMETADATA_LOG) << "No extractor for" << mimetype; return extractors; } qCDebug(KFILEMETADATA_LOG) << "Fetching extractors for" << mimetype; Extractor* failed = nullptr; for (auto ex : extractors) { if (!ex->d->initPlugin()) { failed = ex; break; } } if (!failed) { return extractors; } auto it = m_mimeExtractors.begin(); while (it != m_mimeExtractors.end()) { if (it.value() == failed) { it = m_mimeExtractors.erase(it); } else { ++it; } } return getExtractors(mimetype); } QList ExtractorCollection::fetchExtractors(const QString& mimetype) const { QList plugins = d->getExtractors(mimetype); if (!plugins.isEmpty()) { return plugins; } // try to find the best matching more generic extractor by mimetype inheritance QMimeDatabase db; auto type = db.mimeTypeForName(mimetype); const QStringList ancestors = type.allAncestors(); for (auto ancestor : ancestors) { if (ancestor == QLatin1String("application/octet-stream")) { continue; } QList plugins = d->getExtractors(ancestor); if (!plugins.isEmpty()) { qCDebug(KFILEMETADATA_LOG) << "Using inherited mimetype" << ancestor << "for" << mimetype; return plugins; } } return plugins; } diff --git a/src/writedata.cpp b/src/writedata.cpp index df42294..c1c88e2 100644 --- a/src/writedata.cpp +++ b/src/writedata.cpp @@ -1,95 +1,95 @@ /* * This file is part of the KFileMetaData project * Copyright (C) 2016 Varun Joshi * Copyright (C) 2016 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ -#include - #include "writedata.h" +#include + using namespace KFileMetaData; class Q_DECL_HIDDEN WriteData::WriteDataPrivate { public: QString url; QString mimetype; PropertyMap properties; }; WriteData::WriteData(const QString& url, const QString& mimetype) : d_ptr(new WriteDataPrivate) { Q_D(WriteData); d->url = url; d->mimetype = mimetype; if (mimetype.isEmpty()) { d->mimetype = QMimeDatabase().mimeTypeForFile(url).name(); } } WriteData::WriteData(const WriteData& rhs) : d_ptr(new WriteDataPrivate(*rhs.d_ptr)) { } WriteData& WriteData::operator=(const WriteData& rhs) { *d_ptr = *rhs.d_ptr; return *this; } bool WriteData::operator==(const WriteData& rhs) const { Q_D(const WriteData); return d->properties == rhs.d_ptr->properties; } void WriteData::add(Property::Property property, const QVariant& value) { Q_D(WriteData); d->properties.insertMulti(property, value); } WriteData::~WriteData() { delete d_ptr; } QString WriteData::inputUrl() const { Q_D(const WriteData); return d->url; } QString WriteData::inputMimetype() const { Q_D(const WriteData); return d->mimetype; } PropertyMap WriteData::getAllProperties() const { Q_D(const WriteData); return d->properties; } diff --git a/src/writercollection.cpp b/src/writercollection.cpp index 8ee96fc..4acd219 100644 --- a/src/writercollection.cpp +++ b/src/writercollection.cpp @@ -1,168 +1,165 @@ /* * This file is part of the KFileMetaData project * Copyright (C) 2016 Varun Joshi * Copyright (C) 2016 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ +#include "writercollection.h" +#include "writer.h" +#include "writer_p.h" +#include "writerplugin.h" +#include "externalwriter.h" #include "kfilemetadata_debug.h" +#include "config-kfilemetadata.h" #include #include #include - #include -#include "writer.h" -#include "writer_p.h" -#include "writerplugin.h" -#include "writercollection.h" -#include "externalwriter.h" - -#include "config-kfilemetadata.h" - using namespace KFileMetaData; class Q_DECL_HIDDEN WriterCollection::WriterCollectionPrivate { public: QHash m_writers; QList allWriters() const; }; WriterCollection::WriterCollection() : d_ptr(new WriterCollectionPrivate) { Q_D(WriterCollection); const QList all = d->allWriters(); for (Writer* writer : all) { const QStringList lst = writer->mimetypes(); for (const QString& type : lst) { d->m_writers.insertMulti(type, writer); } } } WriterCollection::~WriterCollection() { Q_D(WriterCollection); qDeleteAll(d->m_writers.begin(), d->m_writers.end()); delete d; } QList WriterCollection::WriterCollectionPrivate::allWriters() const { QStringList plugins; QStringList pluginPaths; QStringList externalPlugins; QStringList externalPluginPaths; const QStringList paths = QCoreApplication::libraryPaths(); for (const QString& libraryPath : paths) { QString path(libraryPath + QStringLiteral("/kf5/kfilemetadata/writers")); QDir dir(path); if (!dir.exists()) { continue; } const QStringList entryList = dir.entryList(QDir::Files | QDir::NoDotAndDotDot); for (const QString& fileName : entryList) { // Make sure the same plugin is not loaded twice, even if it // installed in two different locations if (plugins.contains(fileName)) continue; plugins << fileName; pluginPaths << dir.absoluteFilePath(fileName); } } plugins.clear(); QDir externalPluginDir(QStringLiteral(LIBEXEC_INSTALL_DIR) + QStringLiteral("/kfilemetadata/writers/externalwriters")); // For external plugins, we look into the directories const QStringList externalPluginEntryList = externalPluginDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); for (const QString& externalPlugin : externalPluginEntryList) { if (externalPlugins.contains(externalPlugin)) continue; externalPlugins << externalPlugin; externalPluginPaths << externalPluginDir.absoluteFilePath(externalPlugin); } externalPlugins.clear(); QList writers; for (const QString& pluginPath : qAsConst(pluginPaths)) { QPluginLoader loader(pluginPath); if (!loader.load()) { qCWarning(KFILEMETADATA_LOG) << "Could not create Writer: " << pluginPath; qCWarning(KFILEMETADATA_LOG) << loader.errorString(); continue; } QObject* obj = loader.instance(); if (obj) { WriterPlugin* plugin = qobject_cast(obj); if (plugin) { Writer* writer = new Writer; writer->d_ptr->m_plugin = plugin; writers << writer; } else { qCDebug(KFILEMETADATA_LOG) << "Plugin could not be converted to a WriterPlugin"; qCDebug(KFILEMETADATA_LOG) << pluginPath; } } else { qCDebug(KFILEMETADATA_LOG) << "Plugin could not create instance" << pluginPath; } } for (const QString& externalPluginPath : qAsConst(externalPluginPaths)) { ExternalWriter *plugin = new ExternalWriter(externalPluginPath); Writer* writer = new Writer; writer->d_ptr->m_plugin = plugin; writers << writer; } return writers; } QList WriterCollection::fetchWriters(const QString& mimetype) const { Q_D(const WriterCollection); QList plugins = d->m_writers.values(mimetype); if (plugins.isEmpty()) { auto it = d->m_writers.constBegin(); for (; it != d->m_writers.constEnd(); ++it) { if (mimetype.startsWith(it.key())) plugins << it.value(); } } return plugins; }