diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index eeb9033..edccdd0 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -1,249 +1,258 @@ find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Test) find_package(PythonInterp) set_package_properties(PythonInterp PROPERTIES DESCRIPTION "Python Interpreter" URL "https://www.python.org" TYPE OPTIONAL PURPOSE "Python interpreter is needed to execute test for external extractors or writers") remove_definitions(-DQT_NO_CAST_FROM_ASCII) configure_file(indexerextractortestsconfig.h.in ${CMAKE_CURRENT_BINARY_DIR}/indexerextractortestsconfig.h @ONLY) set(KfileMetaDataAutotest_SRCS) ecm_qt_declare_logging_category(KfileMetaDataAutotest_SRCS HEADER kfilemetadata_debug.h IDENTIFIER KFILEMETADATA_LOG CATEGORY_NAME kf5.kfilemetadata) # # Test case coverage # set(extractorcoverage_SRCS extractorcoveragetest.cpp ) ecm_add_test(${extractorcoverage_SRCS} TEST_NAME "extractorcoveragetest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData ) # # Full text extraction test # set(indexerextractor_SRCS indexerextractortests.cpp ../src/extractors/plaintextextractor.cpp ) ecm_add_test(${indexerextractor_SRCS} TEST_NAME "indexextractortest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData ) # # Office # if(KF5Archive_FOUND) ecm_add_test(odfextractortest.cpp ../src/extractors/odfextractor.cpp TEST_NAME "odfextractortest" LINK_LIBRARIES Qt5::Test Qt5::Xml KF5::FileMetaData KF5::Archive ) endif() if(KF5Archive_FOUND) ecm_add_test(office2007extractortest.cpp ../src/extractors/office2007extractor.cpp TEST_NAME "officeextractortest" LINK_LIBRARIES Qt5::Test Qt5::Xml KF5::FileMetaData KF5::Archive ) endif() # # Poppler # if(Poppler_Qt5_FOUND) ecm_add_test(popplerextractortest.cpp ../src/extractors/popplerextractor.cpp TEST_NAME "popplerextractortest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData Poppler::Qt5 ) endif() # # EPub # if(EPUB_FOUND) include_directories(${EPUB_INCLUDE_DIR}) ecm_add_test(epubextractortest.cpp ../src/extractors/epubextractor.cpp TEST_NAME "epubextractortest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData ${EPUB_LIBRARIES} ) endif() # # Mobi # if (QMobipocket_FOUND) ecm_add_test(mobiextractortest.cpp ../src/extractors/mobiextractor.cpp TEST_NAME "mobiextractortest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData qmobipocket ) endif() # # Property Info # add_executable(propertyinfotest_bin propertyinfotest.cpp) target_link_libraries(propertyinfotest_bin Qt5::Test KF5::FileMetaData ) ecm_mark_as_test(propertyinfotest_bin) ecm_mark_nongui_executable(propertyinfotest_bin) add_test(NAME propertyinfotest_en COMMAND propertyinfotest_bin) add_test(NAME propertyinfotest_localized COMMAND propertyinfotest_bin "--localized") # # Exiv2 # if(LibExiv2_FOUND) kde_enable_exceptions() ecm_add_test(exiv2extractortest.cpp ../src/extractors/exiv2extractor.cpp TEST_NAME "exiv2extractortest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData LibExiv2::LibExiv2 ) target_include_directories(exiv2extractortest PRIVATE ${CMAKE_BINARY_DIR}/src/extractors) endif() # # FFMPEG # if(FFMPEG_FOUND) kde_enable_exceptions() ecm_add_test(ffmpegextractortest.cpp ../src/extractors/ffmpegextractor.cpp TEST_NAME "ffmpegextractortest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData ${AVCODEC_LIBRARIES} ${AVFORMAT_LIBRARIES} ${AVUTIL_LIBRARIES} ) target_include_directories(ffmpegextractortest SYSTEM PRIVATE ${AVCODEC_INCLUDE_DIRS} ${AVFORMAT_INCLUDE_DIRS} ${AVUTIL_INCLUDE_DIRS}) endif() # # TagLib # if(TAGLIB_FOUND) kde_enable_exceptions() ecm_add_test(taglibextractortest.cpp ../src/extractors/taglibextractor.cpp ${KfileMetaDataAutotest_SRCS} TEST_NAME "taglibextractortest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData ${TAGLIB_LIBRARIES} ) target_include_directories(taglibextractortest SYSTEM PRIVATE ${TAGLIB_INCLUDES}) ecm_add_test(embeddedimagedatatest.cpp TEST_NAME "embeddedimagedatatest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData ${TAGLIB_LIBRARIES} ) target_include_directories(embeddedimagedatatest SYSTEM PRIVATE ${TAGLIB_INCLUDES}) endif() if(PYTHONINTERP_FOUND) configure_file(samplefiles/testexternalextractor/main.py samplefiles/testexternalextractor/main.py) configure_file(samplefiles/testexternalextractor/manifest.json samplefiles/testexternalextractor/manifest.json COPYONLY) ecm_add_test(externalextractortest.cpp ../src/externalextractor.cpp ${KfileMetaDataAutotest_SRCS} TEST_NAME "externalextractortest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData KF5::I18n ) endif() # # Collection # set(extractorcollection_SRCS extractorcollectiontest.cpp ) ecm_add_test(${extractorcollection_SRCS} TEST_NAME "extractorcollectiontest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData ) +set(writercollection_SRCS + writercollectiontest.cpp +) + +ecm_add_test(${writercollection_SRCS} + TEST_NAME "writercollectiontest" + LINK_LIBRARIES Qt5::Test KF5::FileMetaData +) + # # XML # set(xmlextractor_SRCS xmlextractortest.cpp ../src/extractors/xmlextractor.cpp ../src/extractors/dublincoreextractor.cpp ../src/kfilemetadata_debug.cpp ) ecm_add_test(${xmlextractor_SRCS} TEST_NAME "xmlextractortest" LINK_LIBRARIES Qt5::Test Qt5::Xml KF5::FileMetaData ) # # Postscript DSC # set(postscriptdscextractor_SRCS postscriptdscextractortest.cpp ../src/extractors/postscriptdscextractor.cpp ../src/kfilemetadata_debug.cpp ) ecm_add_test(${postscriptdscextractor_SRCS} TEST_NAME "postscriptdscextractortest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData ) # # AppImage # if(libappimage_FOUND AND KF5Config_FOUND AND Qt5Gui_FOUND) ecm_add_test(appimageextractortest.cpp ../src/extractors/appimageextractor.cpp TEST_NAME "appimageextractortest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData KF5::ConfigCore Qt5::Xml Qt5::Gui libappimage ) endif() ################ # Writer tests # ################ # # UserMetaData # if(UNIX) kde_enable_exceptions() ecm_add_test(usermetadatawritertest.cpp ../src/usermetadata.cpp TEST_NAME "usermetadatawritertest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData ) endif() # # TagLib # if(TAGLIB_FOUND) kde_enable_exceptions() ecm_add_test(taglibwritertest.cpp ../src/writers/taglibwriter.cpp ${KfileMetaDataAutotest_SRCS} TEST_NAME "taglibwritertest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData ${TAGLIB_LIBRARIES} ) target_include_directories(taglibwritertest SYSTEM PRIVATE ${TAGLIB_INCLUDES}) endif() if(PYTHONINTERP_FOUND) configure_file(samplefiles/testexternalwriter/main.py samplefiles/testexternalwriter/main.py) configure_file(samplefiles/testexternalwriter/manifest.json samplefiles/testexternalwriter/manifest.json COPYONLY) ecm_add_test(externalwritertest.cpp ../src/externalwriter.cpp ${KfileMetaDataAutotest_SRCS} TEST_NAME "externalwritertest" LINK_LIBRARIES Qt5::Test KF5::FileMetaData KF5::I18n ) endif() diff --git a/autotests/writercollectiontest.cpp b/autotests/writercollectiontest.cpp new file mode 100644 index 0000000..1065a57 --- /dev/null +++ b/autotests/writercollectiontest.cpp @@ -0,0 +1,49 @@ +/* + * This file is part of the KDE KFileMetaData project + * Copyright (C) 2014 Vishesh Handa + * 2017 Igor Poboiko + * 2019 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 +#include +#include + +#include "writercollection.h" + +namespace KFileMetaData { + +class WriterCollectionTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testFetchWriters() + { + QCoreApplication::setLibraryPaths({QCoreApplication::applicationDirPath()}); + WriterCollection collection; + QVERIFY(collection.fetchWriters(QStringLiteral("unknown/mimetype")).isEmpty()); + QVERIFY(!collection.fetchWriters(QStringLiteral("audio/mpeg3")).isEmpty()); + } + +}; + +} + +QTEST_GUILESS_MAIN(KFileMetaData::WriterCollectionTest) + +#include "writercollectiontest.moc" diff --git a/src/writer.cpp b/src/writer.cpp index b2e3bd1..56269bd 100644 --- a/src/writer.cpp +++ b/src/writer.cpp @@ -1,52 +1,60 @@ /* * 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 "writer.h" #include "writer_p.h" #include "writerplugin.h" using namespace KFileMetaData; Writer::Writer() - : d_ptr(new WriterPrivate) + : d(new WriterPrivate) { } Writer::~Writer() { - Q_D(Writer); - delete d->m_plugin; - delete d_ptr; + delete d; } +Writer::Writer(Writer&& other) +{ + d = other.d; + other.d = nullptr; +} + + void Writer::write(const WriteData& data) { - Q_D(Writer); d->m_plugin->write(data); } QStringList Writer::mimetypes() const { - Q_D(const Writer); return d->m_plugin->writeMimetypes(); } + +void Writer::setAutoDeletePlugin(WriterPluginOwnership autoDelete) +{ + d->m_autoDeletePlugin = autoDelete; +} diff --git a/src/writer.h b/src/writer.h index 4a327ef..4e00392 100644 --- a/src/writer.h +++ b/src/writer.h @@ -1,61 +1,68 @@ /* * 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 . * */ #ifndef KFILEMETADTA_WRITER_H #define KFILEMETADTA_WRITER_H #include "kfilemetadata_export.h" #include namespace KFileMetaData { class WriteData; class WriterCollection; /** * \class Writer writer.h */ class KFILEMETADATA_EXPORT Writer { + class WriterPrivate; + + enum WriterPluginOwnership { + AutoDeletePlugin, + DoNotDeletePlugin, + }; + public: + Writer(Writer&&); virtual ~Writer(); void write(const WriteData& data); QStringList mimetypes() const; private: Writer(); Writer(const Writer&); void operator =(const Writer&); - class WriterPrivate; - WriterPrivate *d_ptr; - Q_DECLARE_PRIVATE(Writer) + void setAutoDeletePlugin(WriterPluginOwnership autoDelete); + WriterPrivate *d; friend class WriterCollection; }; } #endif // KFILEMETADTA_WRITER_H diff --git a/src/writer_p.h b/src/writer_p.h index 23ac46b..02e0348 100644 --- a/src/writer_p.h +++ b/src/writer_p.h @@ -1,40 +1,50 @@ /* * 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 . * */ #ifndef KFILEMETADATA_WRITER_P_H #define KFILEMETADATA_WRITER_P_H +#include "writerplugin.h" + namespace KFileMetaData { class WriterPlugin; -class Q_DECL_HIDDEN Writer::WriterPrivate +class Writer::WriterPrivate { public: + ~WriterPrivate() { + if (m_autoDeletePlugin == AutoDeletePlugin) { + delete m_plugin; + } + } + WriterPlugin *m_plugin = nullptr; + + WriterPluginOwnership m_autoDeletePlugin = AutoDeletePlugin; }; } #endif diff --git a/src/writercollection.cpp b/src/writercollection.cpp index a7c1c9b..b12a1cf 100644 --- a/src/writercollection.cpp +++ b/src/writercollection.cpp @@ -1,164 +1,174 @@ /* * 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 using namespace KFileMetaData; class Q_DECL_HIDDEN WriterCollection::WriterCollectionPrivate { public: QHash m_writers; - QList allWriters() const; + std::vector m_allWriters; + + void findWriters(); }; WriterCollection::WriterCollection() - : d_ptr(new WriterCollectionPrivate) + : d(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); - } - } + d->findWriters(); } WriterCollection::~WriterCollection() { - Q_D(WriterCollection); - qDeleteAll(d->m_writers.begin(), d->m_writers.end()); delete d; } - -QList WriterCollection::WriterCollectionPrivate::allWriters() const +void WriterCollection::WriterCollectionPrivate::findWriters() { 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; + Writer writer; + writer.d->m_plugin = plugin; + writer.setAutoDeletePlugin(Writer::DoNotDeletePlugin); - writers << writer; + m_allWriters.push_back(std::move(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; + Writer writer; + writer.d->m_plugin = plugin; + writer.setAutoDeletePlugin(Writer::AutoDeletePlugin); - writers << writer; + m_allWriters.push_back(std::move(writer)); } - return writers; + for (Writer& writer : m_allWriters) { + const QStringList lst = writer.mimetypes(); + for (const QString& type : lst) { + m_writers.insertMulti(type, &writer); + } + } } 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(); + if (!plugins.isEmpty()) { + return plugins; + } + + // try to find the best matching more generic writer by mimetype inheritance + QMimeDatabase db; + auto type = db.mimeTypeForName(mimetype); + const QStringList ancestors = type.allAncestors(); + + for (const auto &ancestor : ancestors) { + if (ancestor == QLatin1String("application/octet-stream")) { + continue; + } + QList plugins = d->m_writers.values(ancestor); + if (!plugins.isEmpty()) { + qCDebug(KFILEMETADATA_LOG) << "Using inherited mimetype" << ancestor << "for" << mimetype; + return plugins; } } return plugins; } diff --git a/src/writercollection.h b/src/writercollection.h index 46a0fd6..7246d64 100644 --- a/src/writercollection.h +++ b/src/writercollection.h @@ -1,53 +1,52 @@ /* * 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 . * */ #ifndef _KFILEMETADTA_WRITERCOLLECTION_H #define _KFILEMETADTA_WRITERCOLLECTION_H #include #include "kfilemetadata_export.h" #include "writer.h" namespace KFileMetaData { /** * \class WriterCollection writercollection.h */ class KFILEMETADATA_EXPORT WriterCollection { public: explicit WriterCollection(); virtual ~WriterCollection(); QList fetchWriters(const QString& mimetype) const; private: class WriterCollectionPrivate; - WriterCollectionPrivate* d_ptr; - Q_DECLARE_PRIVATE(WriterCollection) + WriterCollectionPrivate* d; }; } #endif // _KFILEMETADTA_WRITERCOLLECTION_H diff --git a/src/writers/CMakeLists.txt b/src/writers/CMakeLists.txt index a57c123..8b87035 100644 --- a/src/writers/CMakeLists.txt +++ b/src/writers/CMakeLists.txt @@ -1,14 +1,15 @@ if(TAGLIB_FOUND) add_library(kfilemetadata_taglibwriter MODULE taglibwriter.cpp ${debug_SRCS}) target_include_directories(kfilemetadata_taglibwriter SYSTEM PRIVATE ${TAGLIB_INCLUDES}) target_link_libraries( kfilemetadata_taglibwriter KF5::FileMetaData ${TAGLIB_LIBRARIES} ) + set_target_properties(kfilemetadata_taglibwriter PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/kf5/kfilemetadata/writers") install( TARGETS kfilemetadata_taglibwriter DESTINATION ${PLUGIN_INSTALL_DIR}/kf5/kfilemetadata/writers) endif()