diff --git a/CMakeLists.txt b/CMakeLists.txt index 304792d..5ec10db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,159 +1,159 @@ cmake_minimum_required(VERSION 3.5) set(KF5_VERSION "5.57.0") # handled by release scripts set(KF5_DEP_VERSION "5.56.0") # handled by release scripts project(KFileMetaData VERSION ${KF5_VERSION}) include(FeatureSummary) find_package(ECM 5.56.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${ECM_MODULE_PATH}) include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) include(ECMAddTests) include(GenerateExportHeader) include(ECMSetupVersion) include(ECMGenerateHeaders) include(ECMAddQch) include(ECMQtDeclareLoggingCategory) include(CheckStructHasMember) option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") ecm_setup_version(PROJECT VARIABLE_PREFIX KFILEMETADATA PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5FileMetaDataConfigVersion.cmake" SOVERSION 3) # Dependencies set(REQUIRED_QT_VERSION 5.10.0) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG COMPONENTS Gui) set_package_properties(Qt5Gui PROPERTIES DESCRIPTION "Qt 5: Gui component" TYPE OPTIONAL PURPOSE "Qt5::Gui is needed to build the AppImage extractor") find_package(Qt5 ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE COMPONENTS Xml) find_package(KF5 ${KF5_DEP_VERSION} COMPONENTS Archive) set_package_properties(KF5Archive PROPERTIES DESCRIPTION "KDE Frameworks 5: Archive Framework" URL "https://download.kde.org/stable/frameworks/" TYPE OPTIONAL PURPOSE "Archive is needed to build ODF and OOXML 2007 extractors") find_package(KF5 ${KF5_DEP_VERSION} COMPONENTS CoreAddons) set_package_properties(KF5CoreAddons PROPERTIES DESCRIPTION "KDE Frameworks 5: Core Addons Framework" URL "https://download.kde.org/stable/frameworks/" TYPE REQUIRED PURPOSE "Needed for the formatting of properties for display purposes") find_package(KF5 ${KF5_DEP_VERSION} COMPONENTS Config) set_package_properties(KF5Config PROPERTIES DESCRIPTION "KDE Frameworks 5: Config Framework" URL "https://download.kde.org/stable/frameworks/" TYPE OPTIONAL PURPOSE "Config is needed to build the AppImage extractor") find_package(KF5 ${KF5_DEP_VERSION} REQUIRED COMPONENTS I18n) find_package(Poppler 0.12.1 COMPONENTS Qt5) set_package_properties(Poppler PROPERTIES DESCRIPTION "A PDF rendering library" URL "https://poppler.freedesktop.org/" TYPE OPTIONAL PURPOSE "Support for PDF files") find_package(Taglib 1.11.1) set_package_properties(Taglib PROPERTIES DESCRIPTION "Id3 tag reader" URL "https://taglib.org/" TYPE OPTIONAL PURPOSE "Support for music metadata") find_package(LibExiv2 0.21) set_package_properties(LibExiv2 PROPERTIES TYPE OPTIONAL PURPOSE "Support for image metadata") find_package(FFmpeg 57.48 COMPONENTS AVCODEC) find_package(FFmpeg 57.40 COMPONENTS AVFORMAT) find_package(FFmpeg 55.27 COMPONENTS AVUTIL) set_package_properties(FFmpeg PROPERTIES DESCRIPTION "Video Tag reader" URL "https://ffmpeg.org/" TYPE OPTIONAL PURPOSE "Support for video metadata") if (FFmpeg_AVFORMAT_FOUND) set(CMAKE_REQUIRED_INCLUDES ${AVCODEC_INCLUDE_DIRS}) CHECK_STRUCT_HAS_MEMBER(AVStream codecpar "stdint.h;libavformat/avformat.h" HAVE_AVSTREAM_CODECPAR LANGUAGE CXX) endif() find_package(EPub) set_package_properties(EPub PROPERTIES DESCRIPTION "Ebook epub reader" URL "https://sourceforge.net/projects/ebook-tools/" TYPE OPTIONAL PURPOSE "Support for epub metadata") find_package(CatDoc) set_package_properties(CatDoc PROPERTIES DESCRIPTION "catdoc executable" URL "https://www.wagner.pp.ru/~vitus/software/catdoc/" TYPE RUNTIME PURPOSE "Extract text from office 98 files - RUNTIME dependency") if ( CMAKE_SYSTEM_NAME MATCHES "Linux" ) find_package(Xattr) set_package_properties(Xattr PROPERTIES DESCRIPTION "library libattr " URL "https://savannah.nongnu.org/projects/attr" TYPE REQUIRED PURPOSE "Extended attribute shared library") endif() #find_package(QMobipocket) #set_package_properties(QMobipocket PROPERTIES DESCRIPTION "Mobipocket epub reader" # URL "https://projects.kde.org/projects/kde/kdegraphics/kdegraphics-mobipocket" # TYPE OPTIONAL PURPOSE "Support for mobi metadata") find_package(libappimage 0.1.10 CONFIG) set_package_properties(libappimage PROPERTIES DESCRIPTION "Core library of the AppImage project" URL "https://github.com/AppImage/libappimage" TYPE OPTIONAL PURPOSE "Needed to build the AppImage extractor" ) add_definitions(-DTRANSLATION_DOMAIN=\"kfilemetadata5\") - +add_definitions(-DQT_NO_FOREACH) add_subdirectory(src) if (BUILD_TESTING) add_subdirectory(autotests) add_subdirectory(tests) endif() # Config files set(CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/KF5FileMetaData") if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") ki18n_install(po) endif() if (BUILD_QCH) ecm_install_qch_export( TARGETS KF5FileMetaData_QCH FILE KF5FileMetaDataQchTargets.cmake DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5FileMetaDataQchTargets.cmake\")") endif() include(CMakePackageConfigHelpers) configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KF5FileMetaDataConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5FileMetaDataConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5FileMetaDataConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5FileMetaDataConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT devel ) # contains list of debug categories, for kdebugsettings install(FILES kfilemetadata.categories DESTINATION ${KDE_INSTALL_CONFDIR}) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/externalextractor.cpp b/src/externalextractor.cpp index 553e926..b31c2a9 100644 --- a/src/externalextractor.cpp +++ b/src/externalextractor.cpp @@ -1,173 +1,175 @@ /* * 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 #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(); - Q_FOREACH(const auto &key, propertiesObject.keys()) { - if (key == QStringLiteral("typeInfo")) { - TypeInfo info = TypeInfo::fromName(propertiesObject.value(key).toString()); + 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 (key == QStringLiteral("text")) { - result->append(propertiesObject.value(key).toString(QStringLiteral(""))); + if (i.key() == QStringLiteral("text")) { + result->append(propertiesObject.value(i.key()).toString(QStringLiteral(""))); continue; } - PropertyInfo info = PropertyInfo::fromName(key); - if (info.name() != key) { + PropertyInfo info = PropertyInfo::fromName(i.key()); + if (info.name() != i.key()) { continue; } - result->add(info.property(), propertiesObject.value(key).toVariant()); + 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 3b029f0..19cb093 100644 --- a/src/externalwriter.cpp +++ b/src/externalwriter.cpp @@ -1,149 +1,149 @@ /* * 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 "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(); - QJsonArray mimetypesArray = rootObject.value(QStringLiteral("mimetypes")).toArray(); + const QJsonArray mimetypesArray = rootObject.value(QStringLiteral("mimetypes")).toArray(); QStringList mimetypes; - Q_FOREACH(const QVariant &mimetype, mimetypesArray) { + 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; - QMap properties = data.getAllProperties(); - const auto &propertiesKeys = properties.keys(); + const QMap properties = data.getAllProperties(); - Q_FOREACH(const Property::Property &property, propertiesKeys) { - PropertyInfo propertyInfo(property); - propertiesObject[propertyInfo.name()] = QJsonValue::fromVariant(properties[property]); + 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/extractorplugin.cpp b/src/extractorplugin.cpp index 00e4227..b4bd868 100644 --- a/src/extractorplugin.cpp +++ b/src/extractorplugin.cpp @@ -1,145 +1,145 @@ /* Copyright (C) 2012 Vishesh Handa Copyright (C) 2012 Jörg Ehrichs 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 "extractorplugin.h" #include using namespace KFileMetaData; ExtractorPlugin::ExtractorPlugin(QObject* parent): QObject(parent) { } ExtractorPlugin::~ExtractorPlugin() { } // // Helper functions // QDateTime ExtractorPlugin::dateTimeFromString(const QString& dateString) { QDateTime dateTime; if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("yyyy-MM-dd")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("dd-MM-yyyy")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("yyyy-MM")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("MM-yyyy")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("yyyy.MM.dd")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("dd.MM.yyyy")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("dd MMMM yyyy")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("MM.yyyy")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("yyyy.MM")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("yyyy")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("yy")); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, Qt::ISODate); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("dddd d MMM yyyy h':'mm':'ss AP")); dateTime.setTimeSpec(Qt::LocalTime); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, QStringLiteral("yyyy:MM:dd hh:mm:ss")); dateTime.setTimeSpec(Qt::LocalTime); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, Qt::SystemLocaleDate); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, Qt::SystemLocaleShortDate); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { dateTime = QDateTime::fromString(dateString, Qt::SystemLocaleLongDate); dateTime.setTimeSpec(Qt::UTC); } if (!dateTime.isValid()) { qWarning() << "Could not determine correct datetime format from:" << dateString; return QDateTime(); } return dateTime; } QStringList ExtractorPlugin::contactsFromString(const QString& string) { QString cleanedString = string; cleanedString = cleanedString.remove(QLatin1Char('{')); cleanedString = cleanedString.remove(QLatin1Char('}')); QStringList contactStrings = string.split(QLatin1Char(','), QString::SkipEmptyParts); if (contactStrings.size() == 1) contactStrings = string.split(QLatin1Char(';'), QString::SkipEmptyParts); if (contactStrings.size() == 1) contactStrings = string.split(QStringLiteral(" ft "), QString::SkipEmptyParts); if (contactStrings.size() == 1) contactStrings = string.split(QStringLiteral(" feat. "), QString::SkipEmptyParts); if (contactStrings.size() == 1) contactStrings = string.split(QStringLiteral(" feat "), QString::SkipEmptyParts); QStringList list; list.reserve(contactStrings.count()); - foreach(const QString& contactName, contactStrings) { + for (const QString& contactName : qAsConst(contactStrings)) { list << contactName.trimmed(); } return list; } diff --git a/src/extractors/office2007extractor.cpp b/src/extractors/office2007extractor.cpp index 10ea544..f777814 100644 --- a/src/extractors/office2007extractor.cpp +++ b/src/extractors/office2007extractor.cpp @@ -1,294 +1,294 @@ /* Copyright (C) 2013 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) 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 "office2007extractor.h" #include #include #include #include using namespace KFileMetaData; Office2007Extractor::Office2007Extractor(QObject* parent) : ExtractorPlugin(parent) { } const QStringList supportedMimeTypes = { QStringLiteral("application/vnd.openxmlformats-officedocument.wordprocessingml.document"), QStringLiteral("application/vnd.openxmlformats-officedocument.presentationml.presentation"), QStringLiteral("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"), }; QStringList Office2007Extractor::mimetypes() const { return supportedMimeTypes; } void Office2007Extractor::extract(ExtractionResult* result) { KZip zip(result->inputUrl()); if (!zip.open(QIODevice::ReadOnly)) { qWarning() << "Document is not a valid ZIP archive"; return; } const KArchiveDirectory* rootDir = zip.directory(); if (!rootDir) { qWarning() << "Invalid document structure (main directory is missing)"; return; } const QStringList rootEntries = rootDir->entries(); if (!rootEntries.contains(QStringLiteral("docProps"))) { qWarning() << "Invalid document structure (docProps is missing)"; return; } const KArchiveEntry* docPropEntry = rootDir->entry(QStringLiteral("docProps")); if (!docPropEntry->isDirectory()) { qWarning() << "Invalid document structure (docProps is not a directory)"; return; } const KArchiveDirectory* docPropDirectory = dynamic_cast(docPropEntry); const QStringList docPropsEntries = docPropDirectory->entries(); if (docPropsEntries.contains(QStringLiteral("core.xml"))) { QDomDocument coreDoc(QStringLiteral("core")); const KArchiveFile* file = static_cast(docPropDirectory->entry(QStringLiteral("core.xml"))); coreDoc.setContent(file->data()); QDomElement docElem = coreDoc.documentElement(); QDomElement elem = docElem.firstChildElement(QStringLiteral("dc:description")); if (!elem.isNull()) { QString str = elem.text(); if (!str.isEmpty()) { result->add(Property::Description, str); } } elem = docElem.firstChildElement(QStringLiteral("dc:subject")); if (!elem.isNull()) { QString str = elem.text(); if (!str.isEmpty()) { result->add(Property::Subject, str); } } elem = docElem.firstChildElement(QStringLiteral("dc:title")); if (!elem.isNull()) { QString str = elem.text(); if (!str.isEmpty()) { result->add(Property::Title, str); } } elem = docElem.firstChildElement(QStringLiteral("dc:creator")); if (!elem.isNull()) { QString str = elem.text(); if (!str.isEmpty()) { result->add(Property::Author, str); } } elem = docElem.firstChildElement(QStringLiteral("dc:language")); if (!elem.isNull()) { QString str = elem.text(); if (!str.isEmpty()) { result->add(Property::Language, str); } } elem = docElem.firstChildElement(QStringLiteral("dcterms:created")); if (!elem.isNull()) { QString str = elem.text(); QDateTime dt = dateTimeFromString(str); if (!dt.isNull()) { result->add(Property::CreationDate, dt); } } elem = docElem.firstChildElement(QStringLiteral("cp:keywords")); if (!elem.isNull()) { QString str = elem.text(); if (!str.isEmpty()) { result->add(Property::Keywords, str); } } } if (docPropsEntries.contains(QStringLiteral("app.xml"))) { QDomDocument appDoc(QStringLiteral("app")); const KArchiveFile* file = static_cast(docPropDirectory->entry(QStringLiteral("app.xml"))); appDoc.setContent(file->data()); QDomElement docElem = appDoc.documentElement(); // According to the ontologies only Documents can have a wordCount and pageCount const QString mimeType = result->inputMimetype(); if (mimeType == QLatin1String("application/vnd.openxmlformats-officedocument.wordprocessingml.document")) { QDomElement elem = docElem.firstChildElement(QStringLiteral("Pages")); if (!elem.isNull()) { bool ok = false; int pageCount = elem.text().toInt(&ok); if (ok) { result->add(Property::PageCount, pageCount); } } elem = docElem.firstChildElement(QStringLiteral("Words")); if (!elem.isNull()) { bool ok = false; int wordCount = elem.text().toInt(&ok); if (ok) { result->add(Property::WordCount, wordCount); } } } QDomElement elem = docElem.firstChildElement(QStringLiteral("Application")); if (!elem.isNull()) { QString app = elem.text(); if (!app.isEmpty()) { result->add(Property::Generator, app); } } } // // Plain Text // bool extractPlainText = (result->inputFlags() & ExtractionResult::ExtractPlainText); if (rootEntries.contains(QStringLiteral("word"))) { result->addType(Type::Document); if (!extractPlainText) return; const KArchiveEntry* wordEntry = rootDir->entry(QStringLiteral("word")); if (!wordEntry->isDirectory()) { qWarning() << "Invalid document structure (word is not a directory)"; return; } const KArchiveDirectory* wordDirectory = dynamic_cast(wordEntry); const QStringList wordEntries = wordDirectory->entries(); if (wordEntries.contains(QStringLiteral("document.xml"))) { const KArchiveFile* file = static_cast(wordDirectory->entry(QStringLiteral("document.xml"))); extractTextWithTag(file->createDevice(), QStringLiteral("w:t"), result); } } else if (rootEntries.contains(QStringLiteral("xl"))) { result->addType(Type::Document); result->addType(Type::Spreadsheet); if (!extractPlainText) return; const KArchiveEntry* xlEntry = rootDir->entry(QStringLiteral("xl")); if (!xlEntry->isDirectory()) { qWarning() << "Invalid document structure (xl is not a directory)"; return; } const KArchiveDirectory* xlDirectory = dynamic_cast(xlEntry); extractTextFromFiles(xlDirectory, result); } else if (rootEntries.contains(QStringLiteral("ppt"))) { result->addType(Type::Document); result->addType(Type::Presentation); if (!extractPlainText) return; const KArchiveEntry* pptEntry = rootDir->entry(QStringLiteral("ppt")); if (!pptEntry->isDirectory()) { qWarning() << "Invalid document structure (ppt is not a directory)"; return; } const KArchiveDirectory* pptDirectory = dynamic_cast(pptEntry); extractTextFromFiles(pptDirectory, result); } } void Office2007Extractor::extractAllText(QIODevice* device, ExtractionResult* result) { QXmlStreamReader xml(device); while (!xml.atEnd()) { xml.readNext(); if (xml.isCharacters()) { QString str = xml.text().toString(); result->append(str); } if (xml.isEndDocument() || xml.hasError()) break; } } void Office2007Extractor::extractTextFromFiles(const KArchiveDirectory* archiveDir, ExtractionResult* result) { const QStringList entries = archiveDir->entries(); - foreach(const QString & entryName, entries) { + for (const QString & entryName : entries) { const KArchiveEntry* entry = archiveDir->entry(entryName); if (entry->isDirectory()) { const KArchiveDirectory* subDir = dynamic_cast(entry); extractTextFromFiles(subDir, result); continue; } if (!entryName.endsWith(QLatin1String(".xml"))) continue; const KArchiveFile* file = static_cast(entry); extractAllText(file->createDevice(), result); } } void Office2007Extractor::extractTextWithTag(QIODevice* device, const QString& tag, ExtractionResult* result) { QXmlStreamReader xml(device); while (!xml.atEnd()) { xml.readNext(); if (xml.qualifiedName().startsWith(tag) && xml.isStartElement()) { QString str = xml.readElementText(QXmlStreamReader::IncludeChildElements); if (!str.isEmpty()) { result->append(str); } } if (xml.isEndDocument() || xml.hasError()) break; } } diff --git a/src/writercollection.cpp b/src/writercollection.cpp index 163f801..8ee96fc 100644 --- a/src/writercollection.cpp +++ b/src/writercollection.cpp @@ -1,167 +1,168 @@ /* * 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 "kfilemetadata_debug.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(); - foreach (Writer* writer, all) { - foreach (const QString& type, writer->mimetypes()) { + 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(); - Q_FOREACH (const QString& libraryPath, paths) { + 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; - Q_FOREACH (const QString& pluginPath, pluginPaths) { + 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; } } - Q_FOREACH (const QString& externalPluginPath, externalPluginPaths) { + 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; } diff --git a/tests/dump.cpp b/tests/dump.cpp index 8600bd2..ab58f5d 100644 --- a/tests/dump.cpp +++ b/tests/dump.cpp @@ -1,76 +1,76 @@ /* * Copyright (C) 2014 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 #include #include #include #include #include "extractor.h" #include "extractorcollection.h" #include "propertyinfo.h" #include "simpleextractionresult.h" #include int main(int argc, char** argv) { QCoreApplication app(argc, argv); QCommandLineParser parser; parser.addPositionalArgument(QStringLiteral("filename"), QStringLiteral("File to process")); parser.process(app); if (parser.positionalArguments().size() != 1) { qDebug() << "Only one argument is accepted"; parser.showHelp(1); } QString url = QFileInfo(parser.positionalArguments().at(0)).absoluteFilePath(); QMimeDatabase mimeDb; QString mimetype = mimeDb.mimeTypeForFile(url).name(); KFileMetaData::ExtractorCollection extractors; QList exList = extractors.fetchExtractors(mimetype); QTextStream out(stdout); out << url << " " << mimetype << "\n\n"; - Q_FOREACH (KFileMetaData::Extractor* ex, exList) { + for (KFileMetaData::Extractor* ex : qAsConst(exList)) { KFileMetaData::SimpleExtractionResult result(url, mimetype, KFileMetaData::ExtractionResult::ExtractMetaData); ex->extract(&result); out << "Extractor For: " << ex->mimetypes().join(QLatin1Char(' ')) << "\n"; KFileMetaData::PropertyMap properties = result.properties(); KFileMetaData::PropertyMap::const_iterator it = properties.constBegin(); for (; it != properties.constEnd(); it++) { out << KFileMetaData::PropertyInfo(it.key()).displayName() << " --> " << it.value().toString() << " (" << it.value().typeName() << ")\n"; } out << "-------------\n"; } return 0; }