diff --git a/autotests/appimageextractortest.cpp b/autotests/appimageextractortest.cpp index 3cac3cc..f4a1e59 100644 --- a/autotests/appimageextractortest.cpp +++ b/autotests/appimageextractortest.cpp @@ -1,68 +1,55 @@ /* - * Copyright (C) 2019 Friedrich W. H. Kossebau - * - * 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 - * - */ + SPDX-FileCopyrightText: 2019 Friedrich W. H. Kossebau + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "appimageextractortest.h" // Qt #include #include "simpleextractionresult.h" #include "indexerextractortestsconfig.h" #include "extractors/appimageextractor.h" using namespace KFileMetaData; QString AppImageExtractorTest::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + fileName; } /* The test.AppImage got created by: wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage chmod +x linuxdeploy-x86_64.AppImage ./linuxdeploy-x86_64.AppImage --appdir AppDir --output appimage --executable=/usr/bin/echo --desktop-file=appimagetest.desktop --icon-file=/usr/share/icons/oxygen/base/16x16/apps/kde.png mkdir AppDir/usr/share/metainfo/ cp org.kde.kfilemetadata.appimagetest.appdata.xml AppDir/usr/share/metainfo/ ./linuxdeploy-x86_64.AppImage --appdir AppDir --output appimage mv Test_Desktop_Name-x86_64.AppImage test.AppImage To edit the appdata.xml & desktop file, run ./test.AppImage --appimage-extract to get the files. Use linuxdeploy to create the appimage then again. */ void AppImageExtractorTest::test() { AppImageExtractor plugin{this}; SimpleExtractionResult result(testFilePath(QStringLiteral("test.AppImage")), QStringLiteral("application/vnd.appimage")); plugin.extract(&result); QCOMPARE(result.types().size(), 0); QCOMPARE(result.properties().value(Property::Author), QVariant(QStringLiteral("Konqi"))); QCOMPARE(result.properties().value(Property::Title), QVariant(QStringLiteral("Test Desktop Name"))); QCOMPARE(result.properties().value(Property::Comment), QVariant(QStringLiteral("Test Desktop Comment"))); QCOMPARE(result.properties().value(Property::Description), QVariant(QStringLiteral("Test description line 1.\nTest description line 2."))); QCOMPARE(result.properties().value(Property::License), QVariant(QStringLiteral("GPL-2.0"))); } QTEST_GUILESS_MAIN(AppImageExtractorTest) diff --git a/autotests/appimageextractortest.h b/autotests/appimageextractortest.h index 57104b4..8a5b6eb 100644 --- a/autotests/appimageextractortest.h +++ b/autotests/appimageextractortest.h @@ -1,35 +1,22 @@ /* - * Copyright (C) 2019 Friedrich W. H. Kossebau - * - * 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 - * + SPDX-FileCopyrightText: 2019 Friedrich W. H. Kossebau + + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef APPIMAGEEXTRACTORTEST_H #define APPIMAGEEXTRACTORTEST_H #include class AppImageExtractorTest : public QObject { Q_OBJECT private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void test(); }; #endif diff --git a/autotests/embeddedimagedatatest.cpp b/autotests/embeddedimagedatatest.cpp index 3fa8857..60d7871 100644 --- a/autotests/embeddedimagedatatest.cpp +++ b/autotests/embeddedimagedatatest.cpp @@ -1,189 +1,176 @@ /* - * EmbeddedImageData tests. - * - * 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 - * - */ + EmbeddedImageData tests. + + SPDX-FileCopyrightText: 2018 Alexander Stippich + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "embeddedimagedatatest.h" #include "embeddedimagedata.h" #include "indexerextractortestsconfig.h" #include #include #include using namespace KFileMetaData; QString EmbeddedImageDataTest::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + fileName; } void EmbeddedImageDataTest::test() { QFETCH(QString, fileName); QMimeDatabase mimeDb; QString testAudioFile; EmbeddedImageData imageData; QMap images; QByteArray originalFrontCoverImage; QFile testFile(testFilePath("cover.jpg")); testFile.open(QIODevice::ReadOnly); originalFrontCoverImage = testFile.readAll(); testAudioFile = testFilePath(fileName); const QString mimeType = mimeDb.mimeTypeForFile(testAudioFile).name(); if (!imageData.mimeTypes().contains(mimeType)) { qWarning() << "mimeType" << mimeType << "not in imageData.mimeTypes()" << imageData.mimeTypes(); } QVERIFY(imageData.mimeTypes().contains(mimeType)); images = imageData.imageData(testAudioFile); QCOMPARE(images.value(EmbeddedImageData::FrontCover), originalFrontCoverImage); } void EmbeddedImageDataTest::test_data() { QTest::addColumn("fileName"); QTest::addRow("aiff") << QStringLiteral("test.aif") ; QTest::addRow("ape") << QStringLiteral("test.ape") ; QTest::addRow("opus") << QStringLiteral("test.opus") ; QTest::addRow("ogg") << QStringLiteral("test.ogg") ; QTest::addRow("flac") << QStringLiteral("test.flac") ; QTest::addRow("mp3") << QStringLiteral("test.mp3") ; QTest::addRow("m4a") << QStringLiteral("test.m4a") ; QTest::addRow("mpc") << QStringLiteral("test.mpc") ; QTest::addRow("speex") << QStringLiteral("test.spx") ; QTest::addRow("wav") << QStringLiteral("test.wav") ; QTest::addRow("wavpack") << QStringLiteral("test.wv") ; QTest::addRow("wma") << QStringLiteral("test.wma") ; } void EmbeddedImageDataTest::testWrite() { QFETCH(QString, fileName); EmbeddedImageData imageData; QString testFileName = testFilePath(QStringLiteral("writer") + fileName); QFile::copy(testFilePath(fileName), testFileName); QFile testFile(testFilePath("test.jpg")); testFile.open(QIODevice::ReadOnly); QMap writeImages; QMap readImages; writeImages.insert(EmbeddedImageData::ImageType::FrontCover, testFile.readAll()); imageData.writeImageData(testFileName, writeImages); readImages = imageData.imageData(testFileName); QCOMPARE(readImages.value(EmbeddedImageData::FrontCover), writeImages.value(EmbeddedImageData::FrontCover)); QFile::remove(testFileName); } void EmbeddedImageDataTest::testWrite_data() { QTest::addColumn("fileName"); QTest::addRow("aiff") << QStringLiteral("test.aif") ; QTest::addRow("ape") << QStringLiteral("test.ape") ; QTest::addRow("opus") << QStringLiteral("test.opus") ; QTest::addRow("ogg") << QStringLiteral("test.ogg") ; QTest::addRow("flac") << QStringLiteral("test.flac") ; QTest::addRow("mp3") << QStringLiteral("test.mp3") ; QTest::addRow("m4a") << QStringLiteral("test.m4a") ; QTest::addRow("mpc") << QStringLiteral("test.mpc") ; QTest::addRow("speex") << QStringLiteral("test.spx") ; QTest::addRow("wav") << QStringLiteral("test.wav") ; QTest::addRow("wavpack") << QStringLiteral("test.wv") ; QTest::addRow("wma") << QStringLiteral("test.wma") ; } QTEST_GUILESS_MAIN(EmbeddedImageDataTest) diff --git a/autotests/embeddedimagedatatest.h b/autotests/embeddedimagedatatest.h index 3d4326b..ffd8331 100644 --- a/autotests/embeddedimagedatatest.h +++ b/autotests/embeddedimagedatatest.h @@ -1,41 +1,28 @@ /* - * EmbeddedImageData tests. - * - * 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 - * - */ + EmbeddedImageData tests. + + SPDX-FileCopyrightText: 2018 Alexander Stippich + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef EMBEDDEDIMAGEDATATEST_H #define EMBEDDEDIMAGEDATATEST_H #include #include "properties.h" class EmbeddedImageDataTest : public QObject { Q_OBJECT private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void test(); void test_data(); void testWrite(); void testWrite_data(); }; #endif // EMBEDDEDIMAGEDATATEST_H diff --git a/autotests/epubextractortest.cpp b/autotests/epubextractortest.cpp index e9f4754..487e173 100644 --- a/autotests/epubextractortest.cpp +++ b/autotests/epubextractortest.cpp @@ -1,99 +1,85 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "epubextractortest.h" #include "simpleextractionresult.h" #include "indexerextractortestsconfig.h" #include "extractors/epubextractor.h" #include "mimeutils.h" #include #include using namespace KFileMetaData; QString EPubExtractorTest::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + fileName; } void EPubExtractorTest::testNoExtraction() { EPubExtractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test.epub")); QMimeDatabase mimeDb; QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType, ExtractionResult::ExtractNothing); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().constFirst(), Type::Document); QCOMPARE(result.properties().size(), 0); } void EPubExtractorTest::test() { EPubExtractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test.epub")); QMimeDatabase mimeDb; QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().constFirst(), Type::Document); // We're doing a contains instead of an exact check cause the epub file contains // a ton of css and other garbage. QVERIFY(result.text().contains(QStringLiteral("This is a sample PDF file for KFileMetaData."))); QCOMPARE(result.properties().value(Property::Author), QVariant(QStringLiteral("Happy Man"))); QCOMPARE(result.properties().value(Property::Publisher), QVariant(QStringLiteral("Happy Publisher"))); QCOMPARE(result.properties().value(Property::Title), QVariant(QStringLiteral("The Big Brown Bear"))); QCOMPARE(result.properties().value(Property::Subject), QVariant(QStringLiteral("Baloo KFileMetaData"))); QCOMPARE(result.properties().value(Property::Description), QVariant(QStringLiteral("Honey"))); QDateTime dt(QDate(2014, 1, 1), QTime(1, 1, 1)); dt.setTimeSpec(Qt::UTC); QCOMPARE(result.properties().value(Property::CreationDate), QVariant(dt)); QCOMPARE(result.properties().value(Property::ReleaseYear), QVariant(2014)); QCOMPARE(result.properties().size(), 7); } void EPubExtractorTest::testMetaDataOnly() { EPubExtractor plugin{this}; SimpleExtractionResult result(testFilePath("test.epub"), "application/epub+zip", ExtractionResult::ExtractMetaData); plugin.extract(&result); QVERIFY(!result.types().isEmpty()); QVERIFY(!result.properties().isEmpty()); QVERIFY(result.text().isEmpty()); } QTEST_GUILESS_MAIN(EPubExtractorTest) diff --git a/autotests/epubextractortest.h b/autotests/epubextractortest.h index d5238ad..ab14535 100644 --- a/autotests/epubextractortest.h +++ b/autotests/epubextractortest.h @@ -1,38 +1,24 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef EPUBEXTRACTORTEST_H #define EPUBEXTRACTORTEST_H #include class EPubExtractorTest : public QObject { Q_OBJECT private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void testNoExtraction(); void test(); void testMetaDataOnly(); }; #endif // EPUBEXTRACTORTEST_H diff --git a/autotests/exiv2extractortest.cpp b/autotests/exiv2extractortest.cpp index 3966dd0..10a298e 100644 --- a/autotests/exiv2extractortest.cpp +++ b/autotests/exiv2extractortest.cpp @@ -1,103 +1,89 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "exiv2extractortest.h" #include "simpleextractionresult.h" #include "indexerextractortestsconfig.h" #include "extractors/exiv2extractor.h" #include "mimeutils.h" #include #include using namespace KFileMetaData; using namespace KFileMetaData::Property; QString Exiv2ExtractorTest::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + fileName; } void Exiv2ExtractorTest::testNoExtraction() { Exiv2Extractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test.jpg")); QMimeDatabase mimeDb; QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType, ExtractionResult::ExtractNothing); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().constFirst(), Type::Image); QCOMPARE(result.properties().size(), 0); } void Exiv2ExtractorTest::test() { Exiv2Extractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test.jpg")); QMimeDatabase mimeDb; QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().constFirst(), Type::Image); QCOMPARE(result.properties().value(Artist).toString(), QStringLiteral("Artist")); QCOMPARE(result.properties().value(Description).toString(), QStringLiteral("Description")); QCOMPARE(result.properties().value(Copyright).toString(), QStringLiteral("Copyright")); QCOMPARE(result.properties().value(Generator).toString(), QStringLiteral("digiKam-5.9.0")); } void Exiv2ExtractorTest::testGPS() { Exiv2Extractor plugin{this}; SimpleExtractionResult result(testFilePath("test.jpg"), "image/jpeg"); plugin.extract(&result); QCOMPARE(result.properties().value(PhotoGpsLatitude).toDouble(), 41.411); QCOMPARE(result.properties().value(PhotoGpsLongitude).toDouble(), 2.173); QCOMPARE(result.properties().value(PhotoGpsAltitude).toDouble(), 12.2); SimpleExtractionResult resultEmpty(testFilePath("test_no_gps.jpg"), "image/jpeg"); plugin.extract(&resultEmpty); QVERIFY(!resultEmpty.properties().contains(PhotoGpsLatitude)); QVERIFY(!resultEmpty.properties().contains(PhotoGpsLongitude)); QVERIFY(!resultEmpty.properties().contains(PhotoGpsAltitude)); SimpleExtractionResult resultZero(testFilePath("test_zero_gps.jpg"), "image/jpeg"); plugin.extract(&resultZero); QVERIFY(resultZero.properties().contains(PhotoGpsLatitude)); QVERIFY(resultZero.properties().contains(PhotoGpsLongitude)); QVERIFY(resultZero.properties().contains(PhotoGpsAltitude)); QCOMPARE(resultZero.properties().value(PhotoGpsLatitude).toDouble(), 0.0); QCOMPARE(resultZero.properties().value(PhotoGpsLongitude).toDouble(), 0.0); QCOMPARE(resultZero.properties().value(PhotoGpsAltitude).toDouble(), 0.0); } QTEST_GUILESS_MAIN(Exiv2ExtractorTest) diff --git a/autotests/exiv2extractortest.h b/autotests/exiv2extractortest.h index 23effba..ab2d6bc 100644 --- a/autotests/exiv2extractortest.h +++ b/autotests/exiv2extractortest.h @@ -1,38 +1,24 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef EXIV2EXTRACTORTEST_H #define EXIV2EXTRACTORTEST_H #include class Exiv2ExtractorTest : public QObject { Q_OBJECT private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void testNoExtraction(); void test(); void testGPS(); }; #endif // EXIV2EXTRACTORTEST_H diff --git a/autotests/externalextractortest.cpp b/autotests/externalextractortest.cpp index 35f12d8..599f4fd 100644 --- a/autotests/externalextractortest.cpp +++ b/autotests/externalextractortest.cpp @@ -1,51 +1,37 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "externalextractortest.h" #include "simpleextractionresult.h" #include "indexerextractortestsconfig.h" #include "externalextractor.h" #include "config-kfilemetadata.h" #include #include using namespace KFileMetaData; QString ExternalExtractorTest::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_CONFIGURED_FILES_PATH) + QLatin1Char('/') + fileName; } void ExternalExtractorTest::test() { QTemporaryFile file; file.open(); file.write("Hello"); file.close(); ExternalExtractor plugin{testFilePath("testexternalextractor")}; SimpleExtractionResult result(file.fileName(), "application/text"); plugin.extract(&result); QCOMPARE(result.text(), QStringLiteral("Hello ")); } QTEST_GUILESS_MAIN(ExternalExtractorTest) diff --git a/autotests/externalextractortest.h b/autotests/externalextractortest.h index f9598a7..4055b42 100644 --- a/autotests/externalextractortest.h +++ b/autotests/externalextractortest.h @@ -1,38 +1,24 @@ /* - * - * Copyright (C) 2014 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + SPDX-FileCopyrightText: 2016 Varun Joshi + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef EXTERNALEXTRACTORTEST_H #define EXTERNALEXTRACTORTEST_H #include class ExternalExtractorTest : public QObject { Q_OBJECT private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void test(); }; #endif // EXTERNALEXTRACTORTEST_H diff --git a/autotests/externalwritertest.cpp b/autotests/externalwritertest.cpp index 675abe2..9950917 100644 --- a/autotests/externalwritertest.cpp +++ b/autotests/externalwritertest.cpp @@ -1,48 +1,34 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "externalwritertest.h" #include "writedata.h" #include "indexerextractortestsconfig.h" #include "externalwriter.h" #include "config-kfilemetadata.h" #include #include using namespace KFileMetaData; QString ExternalWriterTest::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_CONFIGURED_FILES_PATH) + QLatin1Char('/') + fileName; } void ExternalWriterTest::test() { QTemporaryFile file; ExternalWriter plugin{testFilePath("testexternalwriter")}; file.open(); WriteData data(file.fileName(), "application/text"); plugin.write(data); QCOMPARE(QString(file.readAll()), QStringLiteral("{}")); } QTEST_GUILESS_MAIN(ExternalWriterTest) diff --git a/autotests/externalwritertest.h b/autotests/externalwritertest.h index fac6a12..bc8ce5c 100644 --- a/autotests/externalwritertest.h +++ b/autotests/externalwritertest.h @@ -1,37 +1,23 @@ /* - * - * Copyright (C) 2014 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + SPDX-FileCopyrightText: 2016 Varun Joshi + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef EXTERNALWRITERTEST_H #define EXTERNALWRITERTEST_H #include class ExternalWriterTest : public QObject { Q_OBJECT private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void test(); }; #endif // EXTERNALWRITERTEST_H diff --git a/autotests/extractorcollectiontest.cpp b/autotests/extractorcollectiontest.cpp index b3afbaa..3b4f6f2 100644 --- a/autotests/extractorcollectiontest.cpp +++ b/autotests/extractorcollectiontest.cpp @@ -1,155 +1,142 @@ /* - * This file is part of the KDE KFileMetaData project - * Copyright (C) 2014 Vishesh Handa - * 2017 Igor Poboiko - * - * 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 - * - */ + This file is part of the KDE KFileMetaData project + SPDX-FileCopyrightText: 2014 Vishesh Handa + SPDX-FileCopyrightText: 2017 Igor Poboiko + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include #include #include #include "extractorcollection.h" namespace KFileMetaData { class ExtractorCollectionTest : public QObject { Q_OBJECT private Q_SLOTS: void testFetchExtractors() { QCoreApplication::setLibraryPaths({QCoreApplication::applicationDirPath()}); ExtractorCollection collection; QVERIFY(collection.fetchExtractors("unknown/mimetype").isEmpty()); QVERIFY(!collection.fetchExtractors("text/plain").isEmpty()); } void testMultipleExtractorCollections() { QCoreApplication::setLibraryPaths({QCoreApplication::applicationDirPath()}); ExtractorCollection collection; QVERIFY(collection.fetchExtractors("unknown/mimetype").isEmpty()); QVERIFY(!collection.fetchExtractors("text/plain").isEmpty()); ExtractorCollection collection2; QVERIFY(collection.fetchExtractors("unknown/mimetype").isEmpty()); QVERIFY(!collection.fetchExtractors("text/plain").isEmpty()); QVERIFY(collection2.fetchExtractors("unknown/mimetype").isEmpty()); QVERIFY(!collection2.fetchExtractors("text/plain").isEmpty()); } void testMimeInheritance() { QCoreApplication::setLibraryPaths({QCoreApplication::applicationDirPath()}); ExtractorCollection collection; auto textExtractors = collection.fetchExtractors("text/plain"); QVERIFY(!textExtractors.isEmpty()); auto xmlExtractors = collection.fetchExtractors("application/xml"); QVERIFY(!xmlExtractors.isEmpty()); // Verify the generic "text/plain" extractor is not used for "application/xml" for (auto extractor : textExtractors) { QVERIFY(!xmlExtractors.contains(extractor)); } } void testBestMatching() { QCoreApplication::setLibraryPaths({QCoreApplication::applicationDirPath()}); ExtractorCollection collection; auto textExtractors = collection.fetchExtractors("text/plain"); // "application/mathml+xml" is "sub-class-of" "application/xml" (i.e. inherits it), // according to the shared-mime-info database auto xmlSubtypeExtractors = collection.fetchExtractors("application/mathml+xml"); QVERIFY(!xmlSubtypeExtractors.isEmpty()); // Verify the generic "text/plain" extractor is also not used for // types inherited from "application/xml" for (auto extractor : textExtractors) { QVERIFY(!xmlSubtypeExtractors.contains(extractor)); } } void testExtractorMetadata() { QCoreApplication::setLibraryPaths({QCoreApplication::applicationDirPath()}); ExtractorCollection collection; auto allExtractors = collection.allExtractors(); for (auto extractor : allExtractors) { auto exProperties = extractor->extractorProperties(); if (exProperties.isEmpty()) { qWarning() << "Extractor has no property data, please add it! - (Extractor mimetypes:" << extractor->mimetypes().join(", ") + ')'; continue; } // Verify properties for every supported mimetype auto propMimetypesJson = exProperties["MimeTypes"]; #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) QSet propMimetypes = propMimetypesJson.toMap().keys().toSet(); QSet supportedMimetypes = extractor->mimetypes().toSet(); #else const QStringList propMimeList = propMimetypesJson.toMap().keys(); QSet propMimetypes(propMimeList.begin(), propMimeList.end()); const QStringList extractedMimes = extractor->mimetypes(); QSet supportedMimetypes(extractedMimes.begin(), extractedMimes.end()); #endif QVERIFY2(!exProperties["Name"].toString().isEmpty(), "Missing \"Name\" property"); QVERIFY2(!exProperties["Id"].toString().isEmpty(), "Missing \"Id\" property"); if (propMimetypes == supportedMimetypes) { continue; } auto diff = propMimetypes - supportedMimetypes; if (!diff.isEmpty()) { for (auto mimetype : diff.values()) { auto mimetypeProp = propMimetypesJson.toMap()[mimetype]; auto runtimedep = mimetypeProp.toMap()["HasRuntimeDependency"]; if (runtimedep.isValid() && runtimedep.toInt()) { diff.remove(mimetype); } } if (!diff.isEmpty()) { qWarning() << exProperties["Name"].toString() << exProperties["Id"].toString() << "has extraneous properties for these mimetypes:" << diff.values().join(", "); } } diff = supportedMimetypes - propMimetypes; if (!diff.isEmpty()) { qWarning() << exProperties["Name"].toString() << exProperties["Id"].toString() << "has no properties for these mimetypes:" + diff.values().join(", "); } } } }; } QTEST_GUILESS_MAIN(KFileMetaData::ExtractorCollectionTest) #include "extractorcollectiontest.moc" diff --git a/autotests/extractorcoveragetest.cpp b/autotests/extractorcoveragetest.cpp index 8d78e65..7705416 100644 --- a/autotests/extractorcoveragetest.cpp +++ b/autotests/extractorcoveragetest.cpp @@ -1,156 +1,143 @@ /* - * This file is part of the KDE KFileMetaData project - * Copyright (C) 2014 Vishesh Handa - * 2017 Igor Poboiko - * - * 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 - * - */ + This file is part of the KDE KFileMetaData project + SPDX-FileCopyrightText: 2014 Vishesh Handa + SPDX-FileCopyrightText: 2017 Igor Poboiko + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include #include #include #include #include "mimeutils.h" #include "indexerextractortestsconfig.h" namespace KFileMetaData { class ExtractorCoverageTest : public QObject { Q_OBJECT private: static QString filePath() { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH); } QStringList m_testFiles; QMap m_knownFiles; private Q_SLOTS: void initTestCase() { // Expected mimetypes m_knownFiles = { { "test.aif", "audio/x-aifc"}, { "test.ape", "audio/x-ape"}, { "test.AppImage", "application/vnd.appimage"}, { "test_apple_systemprofiler.spx", "application/xml"}, { "test.dot", "text/vnd.graphviz"}, { "test.eps", "image/x-eps"}, { "test.epub", "application/epub+zip"}, { "test.flac", "audio/flac"}, { "test.jpg", "image/jpeg"}, { "test_libreoffice.docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, { "test.m4a", "audio/mp4"}, { "test_missing_content.odt", "application/vnd.oasis.opendocument.text"}, { "test_missing_meta.odt", "application/vnd.oasis.opendocument.text"}, { "test.mkv", "video/x-matroska"}, { "test.mp3", "audio/mpeg"}, { "test.mpc", "audio/x-musepack"}, { "test_no_gps.jpg", "image/jpeg"}, { "test.odp", "application/vnd.oasis.opendocument.presentation"}, { "test.odt", "application/vnd.oasis.opendocument.text"}, { "test.ogg", "audio/x-vorbis+ogg"}, { "test.mml", "application/mathml+xml"}, { "test_multivalue.ogg", "audio/x-vorbis+ogg"}, { "test.ogv", "video/x-theora+ogg"}, { "test.opus", "audio/x-opus+ogg"}, { "test.pdf", "application/pdf"}, { "test.pl", "application/x-perl"}, { "test.ps", "application/postscript"}, { "test_public_key.gpg", "application/pgp-encrypted"}, { "test.spx", "audio/x-speex+ogg"}, { "test.ts", "video/mp2t"}, { "test.wav", "audio/x-wav"}, { "test.webm", "video/webm"}, { "test_with_container.svg", "image/svg+xml"}, { "test_with_metadata.svg", "image/svg+xml"}, { "test.wma", "audio/x-ms-wma"}, { "test.wv", "audio/x-wavpack"}, { "test_zero_gps.jpg", "image/jpeg"}, { "test.mobi", "application/x-mobipocket-ebook"}, }; // Collect all test files from the samplefiles directory QDirIterator it(filePath(), {QStringLiteral("test*")}, QDir::Files); while (it.hasNext()) { it.next(); m_testFiles.append(it.fileName()); } } void testMimetype_data() { /* * Check if we get the correct mimetype for * each available test sample */ QTest::addColumn("fileName"); QTest::addColumn("mimeType"); auto it = m_knownFiles.cbegin(); while (it != m_knownFiles.cend()) { QTest::addRow("%s", it.key().toUtf8().constData()) << it.key() << it.value(); ++it; } } void testMimetype() { QFETCH(QString, fileName); QFETCH(QString, mimeType); QString url = filePath() + QChar('/') + fileName; QMimeDatabase db; auto fileMime = MimeUtils::strictMimeType(url, db); QVERIFY(fileMime.isValid()); QCOMPARE(fileMime.name(), mimeType); } void testFileCoverage_data() { /* * Check if we get the correct mimetype for * each available test sample */ QTest::addColumn("fileName"); auto it = m_testFiles.cbegin(); while (it != m_testFiles.cend()) { QTest::addRow("%s", it->toUtf8().constData()) << (*it); ++it; } } void testFileCoverage() { QFETCH(QString, fileName); QVERIFY2(m_knownFiles.contains(fileName), "test file omitted from test suite"); } }; } QTEST_GUILESS_MAIN(KFileMetaData::ExtractorCoverageTest) #include "extractorcoveragetest.moc" diff --git a/autotests/ffmpegextractortest.cpp b/autotests/ffmpegextractortest.cpp index 94198d5..776a221 100644 --- a/autotests/ffmpegextractortest.cpp +++ b/autotests/ffmpegextractortest.cpp @@ -1,131 +1,118 @@ /* - * Copyright (C) 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 - * - */ + SPDX-FileCopyrightText: 2019 Alexander Stippich + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "ffmpegextractortest.h" #include "simpleextractionresult.h" #include "indexerextractortestsconfig.h" #include "extractors/ffmpegextractor.h" #include "mimeutils.h" #include using namespace KFileMetaData; namespace { QString testFilePath(const QString& baseName, const QString& extension) { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + baseName + QLatin1Char('.') + extension; } } // namespace void ffmpegExtractorTest::testNoExtraction() { QString fileName = testFilePath(QStringLiteral("test"), QStringLiteral("webm")); QMimeDatabase mimeDb; QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); FFmpegExtractor plugin{this}; QVERIFY(plugin.mimetypes().contains(plugin.getSupportedMimeType(mimeType))); SimpleExtractionResult result(fileName, mimeType, ExtractionResult::ExtractNothing); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().constFirst(), Type::Video); QCOMPARE(result.properties().size(), 0); } void ffmpegExtractorTest::testVideoProperties_data() { QTest::addColumn("fileType"); QTest::addRow("WebM") << QStringLiteral("webm"); QTest::addRow("Matroska Video") << QStringLiteral("mkv"); QTest::addRow("Vorbis Video") << QStringLiteral("ogv"); QTest::addRow("MPEG Transport") << QStringLiteral("ts"); } // only for testing of intrinsic video properties void ffmpegExtractorTest::testVideoProperties() { QFETCH(QString, fileType); QString fileName = testFilePath(QStringLiteral("test"), fileType); QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); FFmpegExtractor plugin{this}; QVERIFY(plugin.mimetypes().contains(plugin.getSupportedMimeType(mimeType))); SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().constFirst(), Type::Video); QCOMPARE(result.properties().value(Property::Width).toInt(), 1280); QCOMPARE(result.properties().value(Property::Height).toInt(), 720); QCOMPARE(result.properties().value(Property::FrameRate).toDouble(), 24.0/1.001); QCOMPARE(result.properties().value(Property::AspectRatio).toDouble(), 16.0/9); } void ffmpegExtractorTest::testMetaData_data() { QTest::addColumn("fileType"); QTest::addRow("WebM") << QStringLiteral("webm"); QTest::addRow("Matroska Video") << QStringLiteral("mkv"); QTest::addRow("Vorbis Video") << QStringLiteral("ogv"); } void ffmpegExtractorTest::testMetaData() { QFETCH(QString, fileType); QString fileName = testFilePath(QStringLiteral("test"), fileType); QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); FFmpegExtractor plugin{this}; SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QEXPECT_FAIL("Vorbis Video", "Not yet supported", Abort); QCOMPARE(result.properties().value(Property::Title).toString(), QStringLiteral("Title")); QCOMPARE(result.properties().value(Property::Copyright).toString(), QStringLiteral("Copyright")); QCOMPARE(result.properties().value(Property::Author).toString(), QStringLiteral("Author")); QCOMPARE(result.properties().value(Property::ReleaseYear).toInt(), 2019); } QTEST_GUILESS_MAIN(ffmpegExtractorTest) diff --git a/autotests/ffmpegextractortest.h b/autotests/ffmpegextractortest.h index c67ecd4..a2ef855 100644 --- a/autotests/ffmpegextractortest.h +++ b/autotests/ffmpegextractortest.h @@ -1,44 +1,31 @@ /* - * Copyright (C) 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 - * - */ + SPDX-FileCopyrightText: 2019 Alexander Stippich + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef FFMPEGEXTRACTORTEST_H #define FFMPEGEXTRACTORTEST_H #include #include namespace KFileMetaData { class ffmpegExtractorTest : public QObject { Q_OBJECT private Q_SLOTS: void testNoExtraction(); void testVideoProperties(); void testVideoProperties_data(); void testMetaData(); void testMetaData_data(); private: QMimeDatabase mimeDb; }; } // namespace KFileMetaData #endif // FFMPEGEXTRACTORTEST_H diff --git a/autotests/indexerextractortests.cpp b/autotests/indexerextractortests.cpp index 727adb8..7b4db40 100644 --- a/autotests/indexerextractortests.cpp +++ b/autotests/indexerextractortests.cpp @@ -1,123 +1,109 @@ /* - This file is part of the Nepomuk KDE project. - Copyright (C) 2013 David Edmundson - 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 . + This file is part of the Nepomuk KDE project. + SPDX-FileCopyrightText: 2013 David Edmundson + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "indexerextractortests.h" #include #include #include "simpleextractionresult.h" #include "indexerextractortestsconfig.h" #include "extractors/plaintextextractor.h" using namespace KFileMetaData; IndexerExtractorTests::IndexerExtractorTests(QObject* parent) : QObject(parent) { } QString IndexerExtractorTests::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + fileName; } void IndexerExtractorTests::benchMarkPlainTextExtractor() { PlainTextExtractor plugin(this); // generate a test file with varying number of words per line QTemporaryFile file(QStringLiteral("XXXXXX.txt")); QVERIFY(file.open()); QByteArray chunk("foo bar "); for (int line = 0; line < 10000; ++line) { for (int i = 0; i < line % 100; ++i) { file.write(chunk); } file.write("\n"); } SimpleExtractionResult result(file.fileName(), QStringLiteral("text/plain")); QBENCHMARK { plugin.extract(&result); } } void IndexerExtractorTests::testNoExtraction() { PlainTextExtractor plugin{this}; SimpleExtractionResult result(testFilePath(QStringLiteral("plain_text_file.txt")), QStringLiteral("text/plain"), ExtractionResult::ExtractNothing); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().at(0), Type::Text); QCOMPARE(result.properties().size(), 0); } void IndexerExtractorTests::testPlainTextExtractor() { PlainTextExtractor plugin{this}; SimpleExtractionResult result(testFilePath(QStringLiteral("plain_text_file.txt")), QStringLiteral("text/plain")); plugin.extract(&result); QString content; QTextStream(&content) << "This is a text file\n" << "it is four lines long\n" << "it has 77 characters\n" << "and 17 words.\n"; QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().at(0), Type::Text); QCOMPARE(result.properties().size(), 1); QCOMPARE(result.properties().value(Property::LineCount), QVariant(4)); content.replace(QLatin1Char('\n'), QLatin1Char(' ')); QCOMPARE(result.text(), content); } void IndexerExtractorTests::testPlainTextExtractorNoPlainText() { PlainTextExtractor plugin{this}; SimpleExtractionResult result(testFilePath(QStringLiteral("plain_text_file.txt")), QStringLiteral("text/plain"), ExtractionResult::ExtractMetaData); plugin.extract(&result); QString content; QTextStream(&content) << "This is a text file\n" << "it is four lines long\n" << "it has 77 characters\n" << "and 17 words.\n"; QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().at(0), Type::Text); QCOMPARE(result.properties().size(), 0); } QTEST_GUILESS_MAIN(IndexerExtractorTests) diff --git a/autotests/indexerextractortests.h b/autotests/indexerextractortests.h index 383c0b4..5d72260 100644 --- a/autotests/indexerextractortests.h +++ b/autotests/indexerextractortests.h @@ -1,44 +1,30 @@ /* - This file is part of the Nepomuk KDE project. - Copyright (C) 2013 David Edmundson + This file is part of the Nepomuk KDE project. + SPDX-FileCopyrightText: 2013 David Edmundson - 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 . + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef INDEXEREXTRACTORTESTS_H #define INDEXEREXTRACTORTESTS_H #include #include class IndexerExtractorTests : public QObject { Q_OBJECT public: explicit IndexerExtractorTests(QObject* parent = nullptr); private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void testNoExtraction(); void benchMarkPlainTextExtractor(); void testPlainTextExtractor(); void testPlainTextExtractorNoPlainText(); }; #endif // INDEXERTESTS_H diff --git a/autotests/indexerextractortestsconfig.h.in b/autotests/indexerextractortestsconfig.h.in index 37e0efd..4780f20 100644 --- a/autotests/indexerextractortestsconfig.h.in +++ b/autotests/indexerextractortestsconfig.h.in @@ -1,28 +1,14 @@ /* - This file is part of the Nepomuk KDE project. - Copyright (C) 2013 David Edmundson + This file is part of the Nepomuk KDE project. + SPDX-FileCopyrightText: 2013 David Edmundson - 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 . + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef INDEXEREXTRACTORTESTSCONFIG_H #define INDEXEREXTRACTORTESTSCONFIG_H #define INDEXER_TESTS_SAMPLE_FILES_PATH "@CMAKE_CURRENT_SOURCE_DIR@/samplefiles" #define INDEXER_TESTS_SAMPLE_CONFIGURED_FILES_PATH "@CMAKE_CURRENT_BINARY_DIR@/../autotests/samplefiles" #endif diff --git a/autotests/mobiextractortest.cpp b/autotests/mobiextractortest.cpp index 18bea1c..4fdd889 100644 --- a/autotests/mobiextractortest.cpp +++ b/autotests/mobiextractortest.cpp @@ -1,62 +1,48 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "mobiextractortest.h" #include "simpleextractionresult.h" #include "indexerextractortestsconfig.h" #include "extractors/mobiextractor.h" #include "mimeutils.h" #include #include #include using namespace KFileMetaData; QString MobiExtractorTest::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + fileName; } void MobiExtractorTest::test() { MobiExtractor plugin{this}; QString fileName = testFilePath("test.mobi"); QMimeDatabase mimeDb; QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().first(), Type::Document); QCOMPARE(result.properties().value(Property::Author), QVariant(QStringLiteral("Happy Man"))); QCOMPARE(result.properties().value(Property::Title), QVariant(QStringLiteral("The Big Brown Bear"))); QCOMPARE(result.properties().value(Property::Subject), QVariant(QStringLiteral("Baloo KFileMetaData"))); QCOMPARE(result.properties().value(Property::Description), QVariant(QStringLiteral("Honey"))); QCOMPARE(result.properties().value(Property::Copyright), QVariant(QStringLiteral("License"))); QCOMPARE(result.properties().size(), 5); } QTEST_GUILESS_MAIN(MobiExtractorTest) diff --git a/autotests/mobiextractortest.h b/autotests/mobiextractortest.h index 9b97fb3..bdeb0df 100644 --- a/autotests/mobiextractortest.h +++ b/autotests/mobiextractortest.h @@ -1,36 +1,22 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef MOBIEXTRACTORTEST_H #define MOBIEXTRACTORTEST_H #include class MobiExtractorTest : public QObject { Q_OBJECT private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void test(); }; #endif // MOBIEXTRACTORTEST_H diff --git a/autotests/odfextractortest.cpp b/autotests/odfextractortest.cpp index b3fc234..a98943d 100644 --- a/autotests/odfextractortest.cpp +++ b/autotests/odfextractortest.cpp @@ -1,133 +1,119 @@ /* - * - * Copyright (C) 2014 Vishesh Handa - * Copyright (C) 2016 Christoph Cullmann - * - * 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + SPDX-FileCopyrightText: 2016 Christoph Cullmann + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "odfextractortest.h" #include #include "simpleextractionresult.h" #include "indexerextractortestsconfig.h" #include "extractors/odfextractor.h" #include "mimeutils.h" using namespace KFileMetaData; QString OdfExtractorTest::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + fileName; } void OdfExtractorTest::testNoExtraction() { OdfExtractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test.odt")); QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType, ExtractionResult::ExtractNothing); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().at(0), Type::Document); QCOMPARE(result.properties().size(),0); } void OdfExtractorTest::testText() { OdfExtractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test.odt")); QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().at(0), Type::Document); QCOMPARE(result.properties().value(Property::Title), QVariant(QStringLiteral("KFileMetaData Title"))); QCOMPARE(result.properties().value(Property::Subject), QVariant(QStringLiteral("KFileMetaData Subject"))); QCOMPARE(result.properties().value(Property::Keywords), QVariant(QStringLiteral("KFileMetaData keyword"))); QCOMPARE(result.properties().value(Property::Description), QVariant(QStringLiteral("KFileMetaData description"))); QVERIFY(result.properties().value(Property::Generator).toString().contains(QStringLiteral("LibreOffice"))); QDateTime dt(QDate(2014, 07, 01), QTime(17, 37, 40, 690)); QCOMPARE(result.properties().value(Property::CreationDate), QVariant(dt)); QCOMPARE(result.properties().value(Property::WordCount), QVariant(4)); QCOMPARE(result.properties().value(Property::PageCount), QVariant(1)); QCOMPARE(result.text(), QStringLiteral("Test file for KFileMetaData. ")); QCOMPARE(result.properties().size(), 8); } void OdfExtractorTest::testTextMetaDataOnly() { OdfExtractor plugin{this}; SimpleExtractionResult result(testFilePath(QStringLiteral("test.odt")), QStringLiteral("application/vnd.oasis.opendocument.text"), ExtractionResult::ExtractMetaData); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.properties().size(), 8); QVERIFY(result.text().isEmpty()); } void OdfExtractorTest::testPresentation() { OdfExtractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test.odp")); QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QCOMPARE(result.types().size(), 2); QCOMPARE(result.types().at(0), Type::Document); QCOMPARE(result.types().at(1), Type::Presentation); QVERIFY(result.properties().value(Property::Generator).toString().contains(QStringLiteral("LibreOffice"))); QDateTime dt(QDate(2014, 07, 02), QTime(10, 59, 23, 434)); QCOMPARE(result.properties().value(Property::CreationDate), QVariant(dt)); QCOMPARE(result.text(), QStringLiteral("KFileMetaData Pres ")); } void OdfExtractorTest::testTextMissingMetaNoCrash() { OdfExtractor plugin{this}; SimpleExtractionResult result(testFilePath(QStringLiteral("test_missing_meta.odt")), QStringLiteral("application/vnd.oasis.opendocument.text")); plugin.extract(&result); } void OdfExtractorTest::testTextMissingContentNoCrash() { OdfExtractor plugin{this}; SimpleExtractionResult result(testFilePath(QStringLiteral("test_missing_content.odt")), QStringLiteral("application/vnd.oasis.opendocument.text")); plugin.extract(&result); } QTEST_GUILESS_MAIN(OdfExtractorTest) diff --git a/autotests/odfextractortest.h b/autotests/odfextractortest.h index 0467f9b..1d6961d 100644 --- a/autotests/odfextractortest.h +++ b/autotests/odfextractortest.h @@ -1,48 +1,34 @@ /* - * - * Copyright (C) 2014 Vishesh Handa - * Copyright (C) 2016 Christoph Cullmann - * - * 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + SPDX-FileCopyrightText: 2016 Christoph Cullmann + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef ODFEXTRACTORTEST_H #define ODFEXTRACTORTEST_H #include #include class OdfExtractorTest : public QObject { Q_OBJECT private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void testNoExtraction(); void testText(); void testTextMetaDataOnly(); void testPresentation(); void testTextMissingMetaNoCrash(); void testTextMissingContentNoCrash(); private: QMimeDatabase mimeDb; }; #endif // ODFEXTRACTORTEST_H diff --git a/autotests/office2007extractortest.cpp b/autotests/office2007extractortest.cpp index ce82f7c..abb9f49 100644 --- a/autotests/office2007extractortest.cpp +++ b/autotests/office2007extractortest.cpp @@ -1,99 +1,85 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "office2007extractortest.h" #include "simpleextractionresult.h" #include "indexerextractortestsconfig.h" #include "extractors/office2007extractor.h" #include "mimeutils.h" #include #include using namespace KFileMetaData; QString Office2007ExtractorTest::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + fileName; } void Office2007ExtractorTest::testNoExtraction() { Office2007Extractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test_libreoffice.docx")); QMimeDatabase mimeDb; QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType, ExtractionResult::ExtractNothing); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().at(0), Type::Document); QCOMPARE(result.properties().size(), 0); } void Office2007ExtractorTest::test() { Office2007Extractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test_libreoffice.docx")); QMimeDatabase mimeDb; QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().at(0), Type::Document); QCOMPARE(result.properties().value(Property::Title), QVariant(QStringLiteral("KFileMetaData Title"))); QCOMPARE(result.properties().value(Property::Subject), QVariant(QStringLiteral("KFileMetaData Subject"))); QCOMPARE(result.properties().value(Property::Keywords), QVariant(QStringLiteral("KFileMetaData keyword"))); QCOMPARE(result.properties().value(Property::Description), QVariant(QStringLiteral("KFileMetaData comment"))); QCOMPARE(result.properties().value(Property::Language), QVariant(QStringLiteral("en-US"))); QVERIFY(result.properties().value(Property::Generator).toString().contains(QStringLiteral("LibreOffice"))); QDateTime dt(QDate(2014, 07, 01), QTime(17, 37, 40)); dt.setTimeSpec(Qt::UTC); QCOMPARE(result.properties().value(Property::CreationDate), QVariant(dt)); QCOMPARE(result.properties().size(), 7); QCOMPARE(result.text(), QStringLiteral("Test file for KFileMetaData. ")); } void Office2007ExtractorTest::testMetaDataOnly() { Office2007Extractor plugin{this}; SimpleExtractionResult result(testFilePath(QStringLiteral("test_libreoffice.docx")), QStringLiteral("application/vnd.openxmlformats-officedocument.wordprocessingml.document"), ExtractionResult::ExtractMetaData); plugin.extract(&result); QVERIFY(!result.types().isEmpty()); QVERIFY(!result.properties().isEmpty()); QVERIFY(result.text().isEmpty()); } QTEST_GUILESS_MAIN(Office2007ExtractorTest) diff --git a/autotests/office2007extractortest.h b/autotests/office2007extractortest.h index 1e4b6ce..11b9525 100644 --- a/autotests/office2007extractortest.h +++ b/autotests/office2007extractortest.h @@ -1,38 +1,24 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef OFFICE2007EXTRACTORTEST_H #define OFFICE2007EXTRACTORTEST_H #include class Office2007ExtractorTest : public QObject { Q_OBJECT private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void testNoExtraction(); void test(); void testMetaDataOnly(); }; #endif // OFFICE2007EXTRACTORTEST_H diff --git a/autotests/popplerextractortest.cpp b/autotests/popplerextractortest.cpp index 21da574..8fdf97b 100644 --- a/autotests/popplerextractortest.cpp +++ b/autotests/popplerextractortest.cpp @@ -1,95 +1,81 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "popplerextractortest.h" #include "simpleextractionresult.h" #include "indexerextractortestsconfig.h" #include "extractors/popplerextractor.h" #include "mimeutils.h" #include #include using namespace KFileMetaData; QString PopplerExtractorTest::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + fileName; } void PopplerExtractorTest::testNoExtraction() { PopplerExtractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test.pdf")); QMimeDatabase mimeDb; QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType, ExtractionResult::ExtractNothing); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().constFirst(), Type::Document); QCOMPARE(result.properties().size(), 0); } void PopplerExtractorTest::test() { PopplerExtractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test.pdf")); QMimeDatabase mimeDb; QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().constFirst(), Type::Document); QCOMPARE(result.text(), QStringLiteral("This is a sample PDF file for KFileMetaData. ")); QCOMPARE(result.properties().value(Property::Author), QVariant(QStringLiteral("Happy Man"))); QCOMPARE(result.properties().value(Property::Title), QVariant(QStringLiteral("The Big Brown Bear"))); QCOMPARE(result.properties().value(Property::Subject), QVariant(QStringLiteral("PDF Metadata"))); QCOMPARE(result.properties().value(Property::Generator), QVariant(QStringLiteral("LibreOffice 4.2"))); QDateTime dt(QDate(2014, 07, 01), QTime(13, 38, 50)); dt.setTimeSpec(Qt::UTC); QCOMPARE(result.properties().value(Property::CreationDate), QVariant(dt)); QCOMPARE(result.properties().size(), 5); } void PopplerExtractorTest::testMetaDataOnly() { PopplerExtractor plugin{this}; SimpleExtractionResult result(testFilePath("test.pdf"), "application/pdf", ExtractionResult::ExtractMetaData); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QVERIFY(result.text().isEmpty()); QCOMPARE(result.properties().size(), 5); } QTEST_GUILESS_MAIN(PopplerExtractorTest) diff --git a/autotests/popplerextractortest.h b/autotests/popplerextractortest.h index bf8547b..e5df7ec 100644 --- a/autotests/popplerextractortest.h +++ b/autotests/popplerextractortest.h @@ -1,38 +1,24 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef POPPLEREXTRACTORTEST_H #define POPPLEREXTRACTORTEST_H #include class PopplerExtractorTest : public QObject { Q_OBJECT private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void testNoExtraction(); void test(); void testMetaDataOnly(); }; #endif // POPPLEREXTRACTORTEST_H diff --git a/autotests/postscriptdscextractortest.cpp b/autotests/postscriptdscextractortest.cpp index 7c09d81..203d35e 100644 --- a/autotests/postscriptdscextractortest.cpp +++ b/autotests/postscriptdscextractortest.cpp @@ -1,98 +1,85 @@ /* - * Copyright (C) 2018 Stefan Brüns - * - * 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 - * - */ + SPDX-FileCopyrightText: 2018 Stefan Brüns + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "postscriptdscextractortest.h" #include "simpleextractionresult.h" #include "indexerextractortestsconfig.h" #include "extractors/postscriptdscextractor.h" #include "mimeutils.h" #include using namespace KFileMetaData; QString PostscriptDscExtractorTest::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + fileName; } void PostscriptDscExtractorTest::testNoExtraction() { DscExtractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test.ps")); QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType, ExtractionResult::ExtractNothing); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().constFirst(), Type::Document); QCOMPARE(result.properties().size(), 0); } void PostscriptDscExtractorTest::testPS() { DscExtractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test.ps")); QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().constFirst(), Type::Document); QCOMPARE(result.properties().value(Property::Title).toString(), QStringLiteral("The Big Brown Bear")); QCOMPARE(result.properties().value(Property::PageCount).toInt(), 2); QDateTime dt(QDate(2018, 10, 28), QTime(21, 13, 39)); dt.setOffsetFromUtc(+3600); QCOMPARE(result.properties().value(Property::CreationDate), QVariant(dt)); QCOMPARE(result.properties().size(), 3); } void PostscriptDscExtractorTest::testEPS() { DscExtractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test.eps")); QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().constFirst(), Type::Image); QCOMPARE(result.properties().value(Property::Title).toString(), QStringLiteral("The Big Brown Bear")); QCOMPARE(result.properties().value(Property::PageCount).toInt(), 1); QDateTime dt(QDate(2018, 10, 28), QTime(21, 13, 39)); dt.setOffsetFromUtc(-5400); QCOMPARE(result.properties().value(Property::CreationDate), QVariant(dt)); QCOMPARE(result.properties().size(), 3); } QTEST_GUILESS_MAIN(PostscriptDscExtractorTest) diff --git a/autotests/postscriptdscextractortest.h b/autotests/postscriptdscextractortest.h index db601d6..312eb97 100644 --- a/autotests/postscriptdscextractortest.h +++ b/autotests/postscriptdscextractortest.h @@ -1,40 +1,27 @@ /* - * Copyright (C) 2018 Stefan Brüns - * - * 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 - * - */ + SPDX-FileCopyrightText: 2018 Stefan Brüns + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef POSTSCRIPTDSCEXTRACTORTEST_H #define POSTSCRIPTDSCEXTRACTORTEST_H #include #include class PostscriptDscExtractorTest : public QObject { Q_OBJECT private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void testNoExtraction(); void testPS(); void testEPS(); private: QMimeDatabase mimeDb; }; #endif // POSTSCRIPTDSCEXTRACTORTEST_H diff --git a/autotests/propertyinfotest.cpp b/autotests/propertyinfotest.cpp index d4d96b6..9a7b76a 100644 --- a/autotests/propertyinfotest.cpp +++ b/autotests/propertyinfotest.cpp @@ -1,162 +1,149 @@ /* - * This file is part of the KDE KFileMetaData project - * 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) 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 - * - */ + This file is part of the KDE KFileMetaData project + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "propertyinfotest.h" #include "propertyinfo.h" #include using namespace KFileMetaData; //QTEST_GUILESS_MAIN(PropertyInfoTest) int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); PropertyInfoTest tc; auto arguments = app.arguments(); if (arguments.contains(QStringLiteral("--localized"))) { arguments.removeAll(QStringLiteral("--localized")); tc.setLocalized(true); } return QTest::qExec(&tc, arguments); } void PropertyInfoTest::setLocalized(bool localized) { m_useLocalization = localized; } void PropertyInfoTest::init() { if (!m_useLocalization) { QLocale().setDefault(QLocale(QLocale::English, QLocale::UnitedStates)); } } void PropertyInfoTest::testNameIdMapping() { // The +1 is to avoid the Empty Property int i = static_cast(Property::FirstProperty) + 1; int e = static_cast(Property::LastProperty); for (; i <= e; i++) { Property::Property p = static_cast(i); PropertyInfo pi(p); // qDebug() << pi.name(); QCOMPARE(pi.property(), p); QVERIFY(!pi.name().isEmpty()); QVERIFY(!pi.displayName().isEmpty()); PropertyInfo pi2 = PropertyInfo::fromName(pi.name()); QCOMPARE(pi2.property(), p); } } void PropertyInfoTest::testFormatAsDisplayString() { QFETCH(KFileMetaData::PropertyInfo, propertyInfo); QFETCH(QVariant, value); QFETCH(QString, expected); QFETCH(bool, maybeLocalized); if (m_useLocalization && maybeLocalized) { qDebug() << "Expected:" << expected << ", formatted/localized:" << propertyInfo.formatAsDisplayString(value); if (expected != propertyInfo.formatAsDisplayString(value)) { QEXPECT_FAIL("", "Expected value not localized", Continue); } } QCOMPARE(propertyInfo.formatAsDisplayString(value), expected); } void PropertyInfoTest::testFormatAsDisplayString_data() { QTest::addColumn("propertyInfo"); QTest::addColumn("value"); // expected values for an en_US locale QTest::addColumn("expected"); QTest::addColumn("maybeLocalized"); auto emptyProperty = PropertyInfo::fromName(QStringLiteral("no valid property name")); QTest::addRow("") << emptyProperty << QVariant(QStringLiteral("empty")) << QStringLiteral("empty") << true; QStringList artistList = {QStringLiteral("Artist1"), QStringLiteral("Artist2"), QStringLiteral("Artist3")}; QStringList authorList = {QStringLiteral("Author1")}; QVariantList arrangerList = {QStringLiteral("Arranger1"), QStringLiteral("Arranger2")}; QVariantList bitRateList = {128000, 130000}; QVariantList titleList = {QStringLiteral("Title1"), QStringLiteral("Title2")}; struct { KFileMetaData::Property::Property property; bool maybeLocalized; QVariant value; QString expected; } rows[] = { { Property::DiscNumber, true, 2018, QStringLiteral("2018")}, { Property::Title, false, QStringLiteral("Title"), QStringLiteral("Title")}, { Property::Title, false, titleList, QStringLiteral("Title1 and Title2")}, { Property::Artist, true, artistList, QStringLiteral("Artist1, Artist2, and Artist3")}, { Property::Author, true, authorList, QStringLiteral("Author1")}, { Property::Arranger, true, arrangerList, QStringLiteral("Arranger1 and Arranger2")}, { Property::Duration, true, 1800, QStringLiteral("0:30:00")}, { Property::SampleRate, true, 44100, QStringLiteral("44.1 kHz")}, { Property::BitRate, true, 128000, QStringLiteral("128 kbit/s")}, { Property::BitRate, true, 1350000, QStringLiteral("1.35 Mbit/s")}, { Property::BitRate, true, 14700000, QStringLiteral("14.7 Mbit/s")}, { Property::BitRate, true, bitRateList, QStringLiteral("128 kbit/s and 130 kbit/s")}, { Property::ImageOrientation, true, 5, QStringLiteral("Transposed")}, { Property::PhotoFlash, true, 0x00, QStringLiteral("No flash")}, { Property::PhotoFlash, true, 0x50, QStringLiteral("No, red-eye reduction")}, { Property::PhotoGpsAltitude, true, 1.1, QStringLiteral("1.1 m")}, // make VisualStudio compiler happy: QChar(0x00B0) = "°" { Property::PhotoGpsLatitude, true, 25, QStringLiteral("25") + QChar(0x00B0)}, { Property::PhotoGpsLongitude, true, 13.5, QStringLiteral("13.5") + QChar(0x00B0)}, { Property::PhotoExposureTime, true, 0.0015625, QStringLiteral("1/640 s")}, { Property::PhotoExposureTime, true, 0.5, QStringLiteral("0.5 s")}, { Property::PhotoExposureTime, true, 0.15, QStringLiteral("0.15 s")}, { Property::PhotoExposureBiasValue, true, 0.33333, QStringLiteral("1/3 EV")}, { Property::PhotoExposureBiasValue, true, 0.66667, QStringLiteral("2/3 EV")}, { Property::PhotoExposureBiasValue, true, 1, QStringLiteral("1 EV")}, { Property::PhotoExposureBiasValue, true, 1.66667, QStringLiteral("1 2/3 EV")}, { Property::PhotoExposureBiasValue, true, 0.1888, QStringLiteral("0.189 EV")}, { Property::PhotoExposureBiasValue, true, -0.33333, QStringLiteral("-1/3 EV")}, { Property::PhotoExposureBiasValue, true, 0, QStringLiteral("0 EV")}, { Property::PhotoExposureBiasValue, true, -1.5, QStringLiteral("-1 1/2 EV")}, { Property::PhotoFNumber, true, 4.0, QStringLiteral("f/4")}, { Property::PhotoFNumber, true, 2.8, QStringLiteral("f/2.8")}, { Property::ReplayGainAlbumGain, true, -9.90, QStringLiteral("-9.9")}, { Property::ReplayGainAlbumPeak, true, 1.512, QStringLiteral("1.51")}, { Property::ReplayGainAlbumGain, true, 10.44, QStringLiteral("10.4")}, { Property::ReplayGainAlbumPeak, true, 1.306, QStringLiteral("1.31")}, { Property::FrameRate, true, 23, QStringLiteral("23 fps")}, { Property::FrameRate, true, 23.976, QStringLiteral("23.98 fps")}, { Property::AspectRatio, true, 1.77778, QStringLiteral("1.78:1")}, { Property::PhotoFocalLength, true, 2.0, QStringLiteral("2 mm")}, { Property::PhotoFocalLength, true, 2.4, QStringLiteral("2.4 mm")}, }; for (auto row : rows) { PropertyInfo info(row.property); QTest::addRow("%s", info.displayName().toUtf8().constData()) << info << row.value << row.expected << row.maybeLocalized; } } diff --git a/autotests/propertyinfotest.h b/autotests/propertyinfotest.h index d2f86d7..4b87cbd 100644 --- a/autotests/propertyinfotest.h +++ b/autotests/propertyinfotest.h @@ -1,45 +1,32 @@ /* - * This file is part of the KDE KFileMetaData project - * 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) 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 - * - */ + This file is part of the KDE KFileMetaData project + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef PROPERTYINFOTEST_H #define PROPERTYINFOTEST_H #include namespace KFileMetaData { class PropertyInfoTest : public QObject { Q_OBJECT public: void setLocalized(bool); private Q_SLOTS: void init(); void testNameIdMapping(); void testFormatAsDisplayString(); void testFormatAsDisplayString_data(); private: bool m_useLocalization = false; }; } #endif // PROPERTYINFOTEST_H diff --git a/autotests/samplefiles/testexternalextractor/main.py b/autotests/samplefiles/testexternalextractor/main.py index d075c96..cd5b107 100755 --- a/autotests/samplefiles/testexternalextractor/main.py +++ b/autotests/samplefiles/testexternalextractor/main.py @@ -1,41 +1,27 @@ #!@PYTHON_EXECUTABLE@ # -# Copyright (C) 2016 Varun Joshi +# SPDX-FileCopyrightText: 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 . +# SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL import sys import json extractor_data = json.loads(sys.stdin.read()) def extract(): path = extractor_data.get('path') mimetype = extractor_data.get('mimetype') doc = open(path) return_value = {} return_value['properties'] = {} return_value['properties']['text'] = doc.read() return_value['status'] = 'OK' return_value['error'] = '' print(json.dumps(return_value)) if __name__ == "__main__": extract() diff --git a/autotests/samplefiles/testexternalwriter/main.py b/autotests/samplefiles/testexternalwriter/main.py index a965d9f..c43369c 100755 --- a/autotests/samplefiles/testexternalwriter/main.py +++ b/autotests/samplefiles/testexternalwriter/main.py @@ -1,41 +1,27 @@ #!@PYTHON_EXECUTABLE@ # -# Copyright (C) 2016 Varun Joshi +# SPDX-FileCopyrightText: 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 . +# SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL import sys import json writer_data = json.loads(sys.stdin.read()) def write(): path = writer_data.get('path') mimetype = writer_data.get('mimetype', '') properties = writer_data.get('properties', '') output = open(path, 'w') output.write(json.dumps(properties)) return_status = {} return_status['status'] = 'OK' return_status['error'] = '' print(json.dumps(return_status)) if __name__ == "__main__": write() diff --git a/autotests/taglibextractortest.cpp b/autotests/taglibextractortest.cpp index aaaf188..3c4790b 100644 --- a/autotests/taglibextractortest.cpp +++ b/autotests/taglibextractortest.cpp @@ -1,684 +1,671 @@ /* - * TagLibExtractor tests. - * - * Copyright (C) 2015 Juan Palacios - * - * 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 - * - */ + TagLibExtractor tests. + + SPDX-FileCopyrightText: 2015 Juan Palacios + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "taglibextractortest.h" #include "simpleextractionresult.h" #include "propertyinfo.h" //TODO: use QTESTFINDDATA and remove this #include "indexerextractortestsconfig.h" #include "extractors/taglibextractor.h" #include "mimeutils.h" #include #include using namespace KFileMetaData; QString TagLibExtractorTest::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + fileName; } const QStringList TagLibExtractorTest::propertyEnumNames(const QList& keys) const { QStringList result; for (auto key : keys) { result.append(PropertyInfo(key).name()); } return result; } void TagLibExtractorTest::testNoExtraction() { TagLibExtractor plugin{this}; SimpleExtractionResult result(testFilePath("test.opus"), QStringLiteral("audio/opus"), ExtractionResult::ExtractNothing); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().constFirst(), Type::Audio); QCOMPARE(result.properties().size(), 0); } void TagLibExtractorTest::testPropertyTypes() { TagLibExtractor plugin{this}; SimpleExtractionResult resultOpus(testFilePath("test.opus"), "audio/opus"); plugin.extract(&resultOpus); auto testForType = [](SimpleExtractionResult &result, Property::Property prop) { QCOMPARE(result.properties().value(prop).type(), PropertyInfo(prop).valueType()); }; QCOMPARE(resultOpus.types().size(), 1); QCOMPARE(resultOpus.types().constFirst(), Type::Audio); testForType(resultOpus, Property::Title); testForType(resultOpus, Property::Artist); testForType(resultOpus, Property::Album); testForType(resultOpus, Property::AlbumArtist); testForType(resultOpus, Property::Genre); testForType(resultOpus, Property::Comment); testForType(resultOpus, Property::Composer); testForType(resultOpus, Property::Lyricist); testForType(resultOpus, Property::Conductor); testForType(resultOpus, Property::Arranger); testForType(resultOpus, Property::Ensemble); testForType(resultOpus, Property::Location); testForType(resultOpus, Property::Performer); testForType(resultOpus, Property::Language); testForType(resultOpus, Property::Publisher); testForType(resultOpus, Property::Label); testForType(resultOpus, Property::Author); testForType(resultOpus, Property::Copyright); testForType(resultOpus, Property::Compilation); testForType(resultOpus, Property::License); testForType(resultOpus, Property::Opus); testForType(resultOpus, Property::TrackNumber); testForType(resultOpus, Property::ReleaseYear); testForType(resultOpus, Property::Channels); testForType(resultOpus, Property::DiscNumber); testForType(resultOpus, Property::Rating); testForType(resultOpus, Property::ReplayGainAlbumGain); testForType(resultOpus, Property::ReplayGainAlbumPeak); testForType(resultOpus, Property::ReplayGainTrackGain); testForType(resultOpus, Property::ReplayGainTrackPeak); } void TagLibExtractorTest::testCommonData() { QFETCH(QString, fileType); QString fileName = testFilePath(QStringLiteral("test.") + fileType); QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); TagLibExtractor plugin{this}; QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().constFirst(), Type::Audio); QCOMPARE(result.properties().value(Property::Title), QVariant(QStringLiteral("Title"))); QCOMPARE(result.properties().value(Property::Artist), QVariant(QStringLiteral("Artist"))); QCOMPARE(result.properties().value(Property::Album), QVariant(QStringLiteral("Album"))); QCOMPARE(result.properties().value(Property::Genre), QVariant(QStringLiteral("Genre"))); QCOMPARE(result.properties().value(Property::Comment), QVariant(QStringLiteral("Comment"))); QCOMPARE(result.properties().value(Property::TrackNumber).toInt(), 1); QCOMPARE(result.properties().value(Property::ReleaseYear).toInt(), 2015); } void TagLibExtractorTest::testCommonData_data() { QTest::addColumn("fileType"); QTest::addRow("aiff") << QStringLiteral("aif") ; QTest::addRow("ape") << QStringLiteral("ape") ; QTest::addRow("flac") << QStringLiteral("flac") ; QTest::addRow("m4a") << QStringLiteral("m4a") ; QTest::addRow("mp3") << QStringLiteral("mp3") ; QTest::addRow("mpc") << QStringLiteral("mpc") ; QTest::addRow("ogg") << QStringLiteral("ogg") ; QTest::addRow("opus") << QStringLiteral("opus") ; QTest::addRow("speex") << QStringLiteral("spx") ; QTest::addRow("wav") << QStringLiteral("wav") ; QTest::addRow("wavpack") << QStringLiteral("wv") ; QTest::addRow("wma") << QStringLiteral("wma") ; } void TagLibExtractorTest::testVorbisComment() { QFETCH(QString, fileType); QString fileName = testFilePath(QStringLiteral("test.") + fileType); QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); TagLibExtractor plugin{this}; SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QCOMPARE(result.properties().value(Property::AlbumArtist), QVariant(QStringLiteral("Album Artist"))); QCOMPARE(result.properties().value(Property::Composer), QVariant(QStringLiteral("Composer"))); QCOMPARE(result.properties().value(Property::Lyricist), QVariant(QStringLiteral("Lyricist"))); QCOMPARE(result.properties().value(Property::Conductor), QVariant(QStringLiteral("Conductor"))); QCOMPARE(result.properties().value(Property::Arranger), QVariant(QStringLiteral("Arranger"))); QCOMPARE(result.properties().value(Property::Ensemble), QVariant(QStringLiteral("Ensemble"))); QCOMPARE(result.properties().value(Property::Location), QVariant(QStringLiteral("Location"))); QCOMPARE(result.properties().value(Property::Performer), QVariant(QStringLiteral("Performer"))); QCOMPARE(result.properties().value(Property::Language), QVariant(QStringLiteral("Language"))); QCOMPARE(result.properties().value(Property::Publisher), QVariant(QStringLiteral("Publisher"))); QCOMPARE(result.properties().value(Property::Label), QVariant(QStringLiteral("Label"))); QCOMPARE(result.properties().value(Property::Author), QVariant(QStringLiteral("Author"))); QCOMPARE(result.properties().value(Property::Copyright), QVariant(QStringLiteral("Copyright"))); QCOMPARE(result.properties().value(Property::Compilation), QVariant(QStringLiteral("Compilation"))); QCOMPARE(result.properties().value(Property::License), QVariant(QStringLiteral("License"))); QCOMPARE(result.properties().value(Property::Lyrics), QVariant(QStringLiteral("Lyrics"))); QCOMPARE(result.properties().value(Property::Opus).toInt(), 1); QCOMPARE(result.properties().value(Property::Channels).toInt(), 1); QCOMPARE(result.properties().value(Property::DiscNumber).toInt(), 1); QCOMPARE(result.properties().value(Property::Rating).toInt(), 5); QCOMPARE(result.properties().value(Property::ReplayGainAlbumGain), QVariant(-9.90)); QCOMPARE(result.properties().value(Property::ReplayGainAlbumPeak), QVariant(1.512)); QCOMPARE(result.properties().value(Property::ReplayGainTrackGain), QVariant(-10.44)); QCOMPARE(result.properties().value(Property::ReplayGainTrackPeak), QVariant(1.301)); } void TagLibExtractorTest::testVorbisComment_data() { QTest::addColumn("fileType"); QTest::addRow("flac") << QStringLiteral("flac") ; QTest::addRow("ogg") << QStringLiteral("ogg") ; QTest::addRow("opus") << QStringLiteral("opus") ; QTest::addRow("speex") << QStringLiteral("spx") ; } void TagLibExtractorTest::testVorbisCommentMultivalue() { QFETCH(QString, fileName); QFETCH(QString, mimeType); TagLibExtractor plugin{this}; SimpleExtractionResult result(testFilePath(fileName), mimeType); plugin.extract(&result); QCOMPARE(result.properties().values(Property::Artist), QVariantList({QStringLiteral("Artist1"), QStringLiteral("Artist2")})); QCOMPARE(result.properties().values(Property::Genre), QVariantList({QStringLiteral("Genre1"), QStringLiteral("Genre2")})); } void TagLibExtractorTest::testVorbisCommentMultivalue_data() { QTest::addColumn("fileName"); QTest::addColumn("mimeType"); QTest::addRow("ogg multivalue") << QStringLiteral("test_multivalue.ogg") << QStringLiteral("audio/ogg") ; } void TagLibExtractorTest::testId3() { QFETCH(QString, fileType); QString fileName = testFilePath(QStringLiteral("test.") + fileType); QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); TagLibExtractor plugin{this}; SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QCOMPARE(result.properties().value(Property::AlbumArtist), QVariant(QStringLiteral("Album Artist"))); QCOMPARE(result.properties().value(Property::Composer), QVariant(QStringLiteral("Composer"))); QCOMPARE(result.properties().value(Property::Lyricist), QVariant(QStringLiteral("Lyricist"))); QCOMPARE(result.properties().value(Property::Conductor), QVariant(QStringLiteral("Conductor"))); QCOMPARE(result.properties().value(Property::Publisher), QVariant(QStringLiteral("Publisher"))); QCOMPARE(result.properties().value(Property::Language), QVariant(QStringLiteral("Language"))); QCOMPARE(result.properties().value(Property::Compilation), QVariant(QStringLiteral("Compilation"))); QCOMPARE(result.properties().value(Property::Lyrics), QVariant(QStringLiteral("Lyrics"))); QCOMPARE(result.properties().value(Property::Channels).toInt(), 1); QCOMPARE(result.properties().value(Property::DiscNumber).toInt(), 1); QCOMPARE(result.properties().value(Property::Rating).toInt(), 10); QCOMPARE(result.properties().value(Property::ReplayGainAlbumGain), QVariant(-3.33)); QCOMPARE(result.properties().value(Property::ReplayGainAlbumPeak), QVariant(1.333)); QCOMPARE(result.properties().value(Property::ReplayGainTrackGain), QVariant(3.33)); QCOMPARE(result.properties().value(Property::ReplayGainTrackPeak), QVariant(1.369)); } void TagLibExtractorTest::testId3_data() { QTest::addColumn("fileType"); QTest::addRow("aiff") << QStringLiteral("aif") ; QTest::addRow("mp3") << QStringLiteral("mp3") ; QTest::addRow("wav") << QStringLiteral("wav") ; } void TagLibExtractorTest::testApe() { QFETCH(QString, fileType); QString fileName = testFilePath(QStringLiteral("test.") + fileType); QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); TagLibExtractor plugin{this}; SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QCOMPARE(result.properties().value(Property::AlbumArtist), QVariant(QStringLiteral("Album Artist"))); QCOMPARE(result.properties().value(Property::Composer), QVariant(QStringLiteral("Composer"))); QCOMPARE(result.properties().value(Property::Conductor), QVariant(QStringLiteral("Conductor"))); QCOMPARE(result.properties().value(Property::Arranger), QVariant(QStringLiteral("Arranger"))); QCOMPARE(result.properties().value(Property::Ensemble), QVariant(QStringLiteral("Ensemble"))); QCOMPARE(result.properties().value(Property::Location), QVariant(QStringLiteral("Location"))); QCOMPARE(result.properties().value(Property::Performer), QVariant(QStringLiteral("Performer"))); QCOMPARE(result.properties().value(Property::Language), QVariant(QStringLiteral("Language"))); QCOMPARE(result.properties().value(Property::Publisher), QVariant(QStringLiteral("Publisher"))); QCOMPARE(result.properties().value(Property::Label), QVariant(QStringLiteral("Label"))); QCOMPARE(result.properties().value(Property::Author), QVariant(QStringLiteral("Author"))); QCOMPARE(result.properties().value(Property::Copyright), QVariant(QStringLiteral("Copyright"))); QCOMPARE(result.properties().value(Property::Compilation), QVariant(QStringLiteral("Compilation"))); QCOMPARE(result.properties().value(Property::License), QVariant(QStringLiteral("License"))); QCOMPARE(result.properties().value(Property::Lyrics), QVariant(QStringLiteral("Lyrics"))); QCOMPARE(result.properties().value(Property::Channels).toInt(), 1); QCOMPARE(result.properties().value(Property::DiscNumber).toInt(), 1); QCOMPARE(result.properties().value(Property::Rating).toInt(), 4); QCOMPARE(result.properties().value(Property::ReplayGainAlbumGain), QVariant(-9.44)); QCOMPARE(result.properties().value(Property::ReplayGainAlbumPeak), QVariant(1.099)); QCOMPARE(result.properties().value(Property::ReplayGainTrackGain), QVariant(-5.23)); QCOMPARE(result.properties().value(Property::ReplayGainTrackPeak), QVariant(1.234)); } void TagLibExtractorTest::testApe_data() { QTest::addColumn("fileType"); QTest::addRow("ape") << QStringLiteral("ape") ; QTest::addRow("musepack") << QStringLiteral("mpc") ; QTest::addRow("wavpack") << QStringLiteral("wv") ; } void TagLibExtractorTest::testMp4() { QFETCH(QString, fileType); QString fileName = testFilePath(QStringLiteral("test.") + fileType); QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); TagLibExtractor plugin{this}; SimpleExtractionResult resultMp4(fileName, mimeType); plugin.extract(&resultMp4); QCOMPARE(resultMp4.properties().value(Property::AlbumArtist), QVariant(QStringLiteral("Album Artist"))); QCOMPARE(resultMp4.properties().value(Property::Composer), QVariant(QStringLiteral("Composer"))); QCOMPARE(resultMp4.properties().value(Property::Copyright), QVariant(QStringLiteral("Copyright"))); QCOMPARE(resultMp4.properties().value(Property::Lyrics), QVariant(QStringLiteral("Lyrics"))); QCOMPARE(resultMp4.properties().value(Property::Channels).toInt(), 2); QCOMPARE(resultMp4.properties().value(Property::DiscNumber).toInt(), 1); QCOMPARE(resultMp4.properties().value(Property::Rating).toInt(), 8); } void TagLibExtractorTest::testMp4_data() { QTest::addColumn("fileType"); QTest::addRow("mp4") << QStringLiteral("m4a") ; } void TagLibExtractorTest::testAax() { QFETCH(QString, fileType); QString fileName = testFilePath(QStringLiteral("nocoverage_test.") + fileType); QString mimeType = QStringLiteral("audio/vnd.audible.aax"); TagLibExtractor plugin{this}; SimpleExtractionResult resultAax(fileName, mimeType); plugin.extract(&resultAax); QCOMPARE(resultAax.properties().value(Property::AlbumArtist), QVariant(QStringLiteral("Album Artist"))); QCOMPARE(resultAax.properties().value(Property::Artist), QVariant(QStringLiteral("Artist"))); QCOMPARE(resultAax.properties().value(Property::Genre), QVariant(QStringLiteral("Hörbuch"))); QCOMPARE(resultAax.properties().value(Property::Copyright), QVariant(QStringLiteral("CopyrightHolder"))); QCOMPARE(resultAax.properties().value(Property::Title), QVariant(QStringLiteral("TrackTitle"))); QCOMPARE(resultAax.properties().value(Property::Channels).toInt(), 2); } void TagLibExtractorTest::testAax_data() { QTest::addColumn("fileType"); QTest::addRow("aax") << QStringLiteral("aax") ; } void TagLibExtractorTest::testAsf() { QFETCH(QString, fileType); QString fileName = testFilePath(QStringLiteral("test.") + fileType); QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); TagLibExtractor plugin{this}; SimpleExtractionResult result(fileName, mimeType); plugin.extract(&result); QCOMPARE(result.properties().value(Property::AlbumArtist), QVariant(QStringLiteral("Album Artist"))); QCOMPARE(result.properties().value(Property::Rating).toInt(), 6); QCOMPARE(result.properties().value(Property::DiscNumber).toInt(), 1); QCOMPARE(result.properties().value(Property::Conductor), QVariant(QStringLiteral("Conductor"))); QCOMPARE(result.properties().value(Property::Composer), QVariant(QStringLiteral("Composer"))); QCOMPARE(result.properties().value(Property::Author), QVariant(QStringLiteral("Author"))); QCOMPARE(result.properties().value(Property::Lyricist), QVariant(QStringLiteral("Lyricist"))); QCOMPARE(result.properties().value(Property::Copyright), QVariant(QStringLiteral("Copyright"))); QCOMPARE(result.properties().value(Property::Publisher), QVariant(QStringLiteral("Publisher"))); } void TagLibExtractorTest::testAsf_data() { QTest::addColumn("fileType"); QTest::addRow("asf") << QStringLiteral("wma") ; } void TagLibExtractorTest::testId3Rating_data() { QTest::addColumn("path"); QTest::addColumn("expectedRating"); QTest::addRow("WMP") << QFINDTESTDATA("samplefiles/mp3_rating/testWMP.mp3") << 0 ; QTest::addRow("WMP1") << QFINDTESTDATA("samplefiles/mp3_rating/testWMP1.mp3") << 2 ; QTest::addRow("WMP2") << QFINDTESTDATA("samplefiles/mp3_rating/testWMP2.mp3") << 4 ; QTest::addRow("WMP3") << QFINDTESTDATA("samplefiles/mp3_rating/testWMP3.mp3") << 6 ; QTest::addRow("WMP4") << QFINDTESTDATA("samplefiles/mp3_rating/testWMP4.mp3") << 8 ; QTest::addRow("WMP5") << QFINDTESTDATA("samplefiles/mp3_rating/testWMP5.mp3") << 10 ; QTest::addRow("MM") << QFINDTESTDATA("samplefiles/mp3_rating/testMM.mp3") << 0 ; QTest::addRow("MM1") << QFINDTESTDATA("samplefiles/mp3_rating/testMM1.mp3") << 1 ; QTest::addRow("MM2") << QFINDTESTDATA("samplefiles/mp3_rating/testMM2.mp3") << 2 ; QTest::addRow("MM3") << QFINDTESTDATA("samplefiles/mp3_rating/testMM3.mp3") << 3 ; QTest::addRow("MM4") << QFINDTESTDATA("samplefiles/mp3_rating/testMM4.mp3") << 4 ; QTest::addRow("MM5") << QFINDTESTDATA("samplefiles/mp3_rating/testMM5.mp3") << 5 ; QTest::addRow("MM6") << QFINDTESTDATA("samplefiles/mp3_rating/testMM6.mp3") << 6 ; QTest::addRow("MM7") << QFINDTESTDATA("samplefiles/mp3_rating/testMM7.mp3") << 7 ; QTest::addRow("MM8") << QFINDTESTDATA("samplefiles/mp3_rating/testMM8.mp3") << 8 ; QTest::addRow("MM9") << QFINDTESTDATA("samplefiles/mp3_rating/testMM9.mp3") << 9 ; QTest::addRow("MM10") << QFINDTESTDATA("samplefiles/mp3_rating/testMM10.mp3") << 10 ; } void TagLibExtractorTest::testId3Rating() { QFETCH(QString, path); QFETCH(int, expectedRating); TagLibExtractor plugin{this}; SimpleExtractionResult result(path, "audio/mpeg"); plugin.extract(&result); QCOMPARE(result.properties().value(Property::Rating).toInt(), expectedRating); } void TagLibExtractorTest::testWmaRating() { QFETCH(QString, path); QFETCH(int, expectedRating); TagLibExtractor plugin{this}; SimpleExtractionResult result(path, "audio/x-ms-wma"); plugin.extract(&result); QCOMPARE(result.properties().value(Property::Rating).toInt(), expectedRating); } void TagLibExtractorTest::testWmaRating_data() { QTest::addColumn("path"); QTest::addColumn("expectedRating"); QTest::addRow("WMP0") << QFINDTESTDATA("samplefiles/wma_rating/test0.wma") << 0 ; QTest::addRow("WMP1") << QFINDTESTDATA("samplefiles/wma_rating/test1.wma") << 2 ; QTest::addRow("WMP2") << QFINDTESTDATA("samplefiles/wma_rating/test2.wma") << 4 ; QTest::addRow("WMP3") << QFINDTESTDATA("samplefiles/wma_rating/test3.wma") << 6 ; QTest::addRow("WMP4") << QFINDTESTDATA("samplefiles/wma_rating/test4.wma") << 8 ; QTest::addRow("WMP5") << QFINDTESTDATA("samplefiles/wma_rating/test5.wma") << 10 ; } void TagLibExtractorTest::testNoMetadata_data() { const auto expectedKeys = QList{ Property::BitRate, Property::Channels, Property::Duration, Property::SampleRate, }; QTest::addColumn("path"); QTest::addColumn("mimeType"); QTest::addColumn>("expectedKeys"); QTest::addColumn("failMessage"); QTest::addRow("mp3") << QFINDTESTDATA("samplefiles/no-meta/test.mp3") << QStringLiteral("audio/mpeg") << expectedKeys << QString() ; QTest::addRow("m4a") << QFINDTESTDATA("samplefiles/no-meta/test.m4a") << QStringLiteral("audio/mp4") << expectedKeys << QString() ; QTest::addRow("flac") << QFINDTESTDATA("samplefiles/no-meta/test.flac") << QStringLiteral("audio/flac") << expectedKeys << QString() ; QTest::addRow("opus") << QFINDTESTDATA("samplefiles/no-meta/test.opus") << QStringLiteral("audio/opus") << expectedKeys << QString() ; QTest::addRow("ogg") << QFINDTESTDATA("samplefiles/no-meta/test.ogg") << QStringLiteral("audio/ogg") << expectedKeys << QString() ; QTest::addRow("mpc") << QFINDTESTDATA("samplefiles/no-meta/test.mpc") << QStringLiteral("audio/x-musepack") << expectedKeys << QString() ; QTest::addRow("aax") << QFINDTESTDATA("samplefiles/no-meta/test.aax") << QStringLiteral("audio/vnd.audible.aax") << expectedKeys << QString() ; } void TagLibExtractorTest::testNoMetadata() { QFETCH(QString, path); QFETCH(QString, mimeType); QFETCH(QList, expectedKeys); QFETCH(QString, failMessage); TagLibExtractor plugin{this}; SimpleExtractionResult extracted(path, mimeType); plugin.extract(&extracted); const auto resultList = extracted.properties(); const auto resultKeys = resultList.uniqueKeys(); #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) const QSet resultKeySet = resultKeys.toSet(); const QSet expectedKeySet = expectedKeys.toSet(); #else const QSet resultKeySet(resultKeys.begin(), resultKeys.end()); const QSet expectedKeySet(expectedKeys.begin(), expectedKeys.end()); #endif const auto excessKeys = resultKeySet - expectedKeySet; const auto missingKeys = expectedKeySet - resultKeySet; if (!excessKeys.isEmpty()) { const auto propNames = propertyEnumNames(excessKeys.values()).join(QLatin1String(", ")); if (failMessage.isEmpty()) { const auto message = QStringLiteral("Excess properties: %1").arg(propNames); QWARN(qPrintable(message)); } else { QEXPECT_FAIL("", qPrintable(QStringLiteral("%1: %2").arg(failMessage).arg(propNames)), Continue); } } else if (!missingKeys.isEmpty()) { const auto message = QStringLiteral("Missing properties: %1") .arg(propertyEnumNames(missingKeys.values()).join(QLatin1String(", "))); QWARN(qPrintable(message)); } QCOMPARE(resultKeys, expectedKeys); if (!failMessage.isEmpty()) { const auto message = QStringLiteral("%1: %2") .arg(failMessage) .arg(propertyEnumNames(excessKeys.values()).join(QLatin1String(", "))); QEXPECT_FAIL("", qPrintable(message), Continue); } QCOMPARE(resultKeys, expectedKeys); } void TagLibExtractorTest::testRobustness_data() { QTest::addColumn("path"); QTest::addColumn("mimeType"); QTest::addRow("ArcGIS GeoData spx") << QFINDTESTDATA("samplefiles/misdetected/test_arcgis_geodata.spx") << QStringLiteral("audio/speex"); } void TagLibExtractorTest::testRobustness() { QFETCH(QString, path); QFETCH(QString, mimeType); TagLibExtractor plugin{this}; SimpleExtractionResult extracted(path, mimeType); plugin.extract(&extracted); } QTEST_GUILESS_MAIN(TagLibExtractorTest) diff --git a/autotests/taglibextractortest.h b/autotests/taglibextractortest.h index c57caee..3250e3d 100644 --- a/autotests/taglibextractortest.h +++ b/autotests/taglibextractortest.h @@ -1,69 +1,57 @@ /* * TagLibExtractor tests. * - * Copyright (C) 2015 Juan Palacios + * SPDX-FileCopyrightText: 2015 Juan Palacios * - * 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 + * SPDX-License-Identifier: LGPL-2.1-or-later * */ #ifndef TAGLIBEXTRACTORTEST_H #define TAGLIBEXTRACTORTEST_H #include #include #include "properties.h" class TagLibExtractorTest : public QObject { Q_OBJECT private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void testNoExtraction(); void testPropertyTypes(); void testCommonData(); void testCommonData_data(); void testVorbisComment(); void testVorbisComment_data(); void testVorbisCommentMultivalue(); void testVorbisCommentMultivalue_data(); void testId3(); void testId3_data(); void testApe(); void testApe_data(); void testMp4(); void testMp4_data(); void testAax(); void testAax_data(); void testAsf(); void testAsf_data(); void testId3Rating_data(); void testId3Rating(); void testWmaRating_data(); void testWmaRating(); void testNoMetadata(); void testNoMetadata_data(); void testRobustness(); void testRobustness_data(); private: // Convenience function const QStringList propertyEnumNames(const QList& key) const; QMimeDatabase mimeDb; }; #endif // TAGLIBEXTRACTORTEST_H diff --git a/autotests/taglibwritertest.cpp b/autotests/taglibwritertest.cpp index f5b6125..db2124e 100644 --- a/autotests/taglibwritertest.cpp +++ b/autotests/taglibwritertest.cpp @@ -1,636 +1,623 @@ /* - * Copyright (C) 2016 Varun Joshi - * 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 - * - */ + SPDX-FileCopyrightText: 2016 Varun Joshi + SPDX-FileCopyrightText: 2018 Alexander Stippich + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "taglibwritertest.h" #include "indexerextractortestsconfig.h" #include "writers/taglibwriter.h" #include "writedata.h" #include #include #include #include #include "taglib.h" #include "fileref.h" #include #include #include using namespace KFileMetaData; QString TagLibWriterTest::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + fileName; } void TagLibWriterTest::extractResult(const QString &mimeType, KFileMetaData::ExtractionResult &result) { KFileMetaData::ExtractorCollection extractors; QList extractorList = extractors.fetchExtractors(mimeType); if (extractorList.isEmpty()) { QFAIL("This mime type is not supported by the extractor. Likely a newer KDE Frameworks version is required."); } if (extractorList.size() > 1) { QWARN("Multiple extractors are available."); } KFileMetaData::Extractor* ex = extractorList.first(); ex->extract(&result); } void TagLibWriterTest::testCommonData() { QFETCH(QString, fileType); QFETCH(QString, mimeType); QFETCH(QString, stringSuffix); QString temporaryFileName = testFilePath(QStringLiteral("writertest.") + fileType); QFile::copy(testFilePath("test." + fileType), temporaryFileName); TagLibWriter writerPlugin{this}; QCOMPARE(writerPlugin.writeMimetypes().contains(mimeType),true); WriteData data(temporaryFileName, mimeType); data.add(Property::Title, QString(QStringLiteral("Title1") + stringSuffix)); data.add(Property::Artist, QString(QStringLiteral("Artist1") + stringSuffix)); data.add(Property::Album, QString(QStringLiteral("Album1") + stringSuffix)); data.add(Property::AlbumArtist, QString(QStringLiteral("AlbumArtist1") + stringSuffix)); data.add(Property::Composer, QString(QStringLiteral("Composer1") + stringSuffix)); data.add(Property::TrackNumber, 10); data.add(Property::DiscNumber, 2); data.add(Property::ReleaseYear, 1999); data.add(Property::Genre, QString(QStringLiteral("Genre1") + stringSuffix)); data.add(Property::Comment, QString(QStringLiteral("Comment1") + stringSuffix)); data.add(Property::Copyright, QString(QStringLiteral("Copyright1") + stringSuffix)); writerPlugin.write(data); KFileMetaData::SimpleExtractionResult result(temporaryFileName, mimeType, KFileMetaData::ExtractionResult::ExtractMetaData); extractResult(mimeType, result); QCOMPARE(result.properties().value(Property::Title), QVariant(QStringLiteral("Title1") + stringSuffix)); QCOMPARE(result.properties().value(Property::Artist), QVariant(QStringLiteral("Artist1") + stringSuffix)); QCOMPARE(result.properties().value(Property::Album), QVariant(QStringLiteral("Album1") + stringSuffix)); QCOMPARE(result.properties().value(Property::AlbumArtist), QVariant(QStringLiteral("AlbumArtist1") + stringSuffix)); QCOMPARE(result.properties().value(Property::Composer), QVariant(QStringLiteral("Composer1") + stringSuffix)); QCOMPARE(result.properties().value(Property::TrackNumber).toInt(), 10); QCOMPARE(result.properties().value(Property::DiscNumber).toInt(), 2); QCOMPARE(result.properties().value(Property::ReleaseYear).toInt(), 1999); QCOMPARE(result.properties().value(Property::Genre), QVariant(QStringLiteral("Genre1") + stringSuffix)); QCOMPARE(result.properties().value(Property::Comment), QVariant(QStringLiteral("Comment1") + stringSuffix)); QCOMPARE(result.properties().value(Property::Copyright), QVariant(QStringLiteral("Copyright1") + stringSuffix)); QFile::remove(temporaryFileName); } void TagLibWriterTest::testCommonData_data() { // Add some unicode characters, use codepoints to avoid any issues with // source encoding: "€µ" static const QChar data[2] = { 0x20ac, 0xb5 }; QString unicodeTestStringSuffix(data, 2); QTest::addColumn("fileType"); QTest::addColumn("mimeType"); QTest::addColumn("stringSuffix"); QTest::addRow("aiff") << QStringLiteral("aif") << QStringLiteral("audio/x-aiff") << QString() ; QTest::addRow("aiff_unicode") << QStringLiteral("aif") << QStringLiteral("audio/x-aiff") << unicodeTestStringSuffix ; QTest::addRow("ape") << QStringLiteral("ape") << QStringLiteral("audio/x-ape") << QString() ; QTest::addRow("ape_unicode") << QStringLiteral("ape") << QStringLiteral("audio/x-ape") << unicodeTestStringSuffix ; QTest::addRow("flac") << QStringLiteral("flac") << QStringLiteral("audio/flac") << QString() ; QTest::addRow("flac_unicode") << QStringLiteral("flac") << QStringLiteral("audio/flac") << unicodeTestStringSuffix ; QTest::addRow("m4a") << QStringLiteral("m4a") << QStringLiteral("audio/mp4") << QString() ; QTest::addRow("m4a_unicode") << QStringLiteral("m4a") << QStringLiteral("audio/mp4") << unicodeTestStringSuffix ; QTest::addRow("mp3") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") << QString() ; QTest::addRow("mp3_unicode") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") << unicodeTestStringSuffix ; QTest::addRow("mpc") << QStringLiteral("mpc") << QStringLiteral("audio/x-musepack") << QString() ; QTest::addRow("mpc_unicode") << QStringLiteral("mpc") << QStringLiteral("audio/x-musepack") << unicodeTestStringSuffix ; QTest::addRow("ogg") << QStringLiteral("ogg") << QStringLiteral("audio/ogg") << QString() ; QTest::addRow("ogg_unicode") << QStringLiteral("ogg") << QStringLiteral("audio/ogg") << unicodeTestStringSuffix ; QTest::addRow("opus") << QStringLiteral("opus") << QStringLiteral("audio/opus") << QString() ; QTest::addRow("opus_unicode") << QStringLiteral("opus") << QStringLiteral("audio/opus") << unicodeTestStringSuffix ; QTest::addRow("speex") << QStringLiteral("spx") << QStringLiteral("audio/speex") << QString() ; QTest::addRow("speex_unicode") << QStringLiteral("spx") << QStringLiteral("audio/speex") << unicodeTestStringSuffix ; QTest::addRow("wav") << QStringLiteral("wav") << QStringLiteral("audio/wav") << QString() ; QTest::addRow("wav_unicode") << QStringLiteral("wav") << QStringLiteral("audio/wav") << unicodeTestStringSuffix ; QTest::addRow("wavpack") << QStringLiteral("wv") << QStringLiteral("audio/x-wavpack") << QString() ; QTest::addRow("wavpack_unicode") << QStringLiteral("wv") << QStringLiteral("audio/x-wavpack") << unicodeTestStringSuffix ; QTest::addRow("wma") << QStringLiteral("wma") << QStringLiteral("audio/x-ms-wma") << QString() ; QTest::addRow("wma_unicode") << QStringLiteral("wma") << QStringLiteral("audio/x-ms-wma") << unicodeTestStringSuffix ; } void TagLibWriterTest::testExtendedData() { QFETCH(QString, fileType); QFETCH(QString, mimeType); QString temporaryFileName = testFilePath(QStringLiteral("writertest.") + fileType); QFile::copy(testFilePath("test." + fileType), temporaryFileName); TagLibWriter writerPlugin{this}; WriteData data(temporaryFileName, mimeType); data.add(Property::Composer, QStringLiteral("Composer1")); data.add(Property::Lyricist, QStringLiteral("Lyricist1")); data.add(Property::Conductor, QStringLiteral("Conductor1")); data.add(Property::Lyrics, QStringLiteral("Lyrics1")); data.add(Property::Language, QStringLiteral("Language1")); writerPlugin.write(data); KFileMetaData::SimpleExtractionResult result(temporaryFileName, mimeType, KFileMetaData::ExtractionResult::ExtractMetaData); extractResult(mimeType, result); QCOMPARE(result.properties().value(Property::Composer), QVariant(QStringLiteral("Composer1"))); QCOMPARE(result.properties().value(Property::Lyricist), QVariant(QStringLiteral("Lyricist1"))); QCOMPARE(result.properties().value(Property::Conductor), QVariant(QStringLiteral("Conductor1"))); QCOMPARE(result.properties().value(Property::Lyrics), QVariant(QStringLiteral("Lyrics1"))); QCOMPARE(result.properties().value(Property::Language), QVariant(QStringLiteral("Language1"))); QFile::remove(temporaryFileName); } void TagLibWriterTest::testExtendedData_data() { QTest::addColumn("fileType"); QTest::addColumn("mimeType"); QTest::addRow("aiff") << QStringLiteral("aif") << QStringLiteral("audio/x-aiff") ; QTest::addRow("ape") << QStringLiteral("ape") << QStringLiteral("audio/x-ape") ; QTest::addRow("flac") << QStringLiteral("flac") << QStringLiteral("audio/flac") ; QTest::addRow("mp3") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") ; QTest::addRow("mpc") << QStringLiteral("mpc") << QStringLiteral("audio/x-musepack") ; QTest::addRow("ogg") << QStringLiteral("ogg") << QStringLiteral("audio/ogg") ; QTest::addRow("opus") << QStringLiteral("opus") << QStringLiteral("audio/opus") ; QTest::addRow("speex") << QStringLiteral("spx") << QStringLiteral("audio/speex") ; QTest::addRow("wav") << QStringLiteral("wav") << QStringLiteral("audio/wav") ; QTest::addRow("wavpack") << QStringLiteral("wv") << QStringLiteral("audio/x-wavpack") ; } void TagLibWriterTest::testRating() { QFETCH(QString, fileType); QFETCH(QString, mimeType); QFETCH(int, rating); QString temporaryFileName = testFilePath(QStringLiteral("writertest.") + fileType); QFile::copy(testFilePath("test.") + fileType, temporaryFileName); TagLibWriter writerPlugin{this}; QCOMPARE(writerPlugin.writeMimetypes().contains(mimeType),true); WriteData data(temporaryFileName, mimeType); data.add(Property::Rating, rating); writerPlugin.write(data); KFileMetaData::SimpleExtractionResult result(temporaryFileName, mimeType, KFileMetaData::ExtractionResult::ExtractMetaData); extractResult(mimeType, result); QCOMPARE(result.properties().value(Property::Rating).toInt(), rating); QFile::remove(temporaryFileName); } void TagLibWriterTest::testRating_data() { QTest::addColumn("fileType"); QTest::addColumn("mimeType"); QTest::addColumn("rating"); QTest::addRow("aiff") << QStringLiteral("aif") << QStringLiteral("audio/x-aiff") << 3 ; QTest::addRow("ape") << QStringLiteral("ape") << QStringLiteral("audio/x-ape") << 1 ; QTest::addRow("flac") << QStringLiteral("flac") << QStringLiteral("audio/flac") << 3 ; QTest::addRow("m4a") << QStringLiteral("m4a") << QStringLiteral("audio/mp4") << 5 ; QTest::addRow("mp3_0") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") << 0 ; QTest::addRow("mp3_1") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") << 1 ; QTest::addRow("mp3_2") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") << 2 ; QTest::addRow("mp3_3") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") << 3 ; QTest::addRow("mp3_4") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") << 4 ; QTest::addRow("mp3_5") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") << 5 ; QTest::addRow("mp3_6") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") << 6 ; QTest::addRow("mp3_7") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") << 7 ; QTest::addRow("mp3_8") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") << 8 ; QTest::addRow("mp3_9") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") << 9 ; QTest::addRow("mp3_10") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") << 10 ; QTest::addRow("mpc") << QStringLiteral("mpc") << QStringLiteral("audio/x-musepack") << 7 ; QTest::addRow("opus") << QStringLiteral("opus") << QStringLiteral("audio/opus") << 6 ; QTest::addRow("speex") << QStringLiteral("spx") << QStringLiteral("audio/speex") << 8 ; QTest::addRow("wav") << QStringLiteral("wav") << QStringLiteral("audio/wav") << 4 ; QTest::addRow("wavpack") << QStringLiteral("wv") << QStringLiteral("audio/x-wavpack") << 9 ; QTest::addRow("wma_0") << QStringLiteral("wma") << QStringLiteral("audio/x-ms-wma") << 0 ; QTest::addRow("wma_2") << QStringLiteral("wma") << QStringLiteral("audio/x-ms-wma") << 2 ; QTest::addRow("wma_4") << QStringLiteral("wma") << QStringLiteral("audio/x-ms-wma") << 4 ; QTest::addRow("wma_5") << QStringLiteral("wma") << QStringLiteral("audio/x-ms-wma") << 5 ; QTest::addRow("wma_6") << QStringLiteral("wma") << QStringLiteral("audio/x-ms-wma") << 6 ; QTest::addRow("wma_8") << QStringLiteral("wma") << QStringLiteral("audio/x-ms-wma") << 8 ; QTest::addRow("wma_10") << QStringLiteral("wma") << QStringLiteral("audio/x-ms-wma") << 10 ; } void TagLibWriterTest::testComplexContactData() { QFETCH(QString, fileExtension); QFETCH(QString, mimeType); QString temporaryFileName = testFilePath(QStringLiteral("writertest.") + fileExtension); QFile::copy(testFilePath("test." + fileExtension), temporaryFileName); TagLibWriter writerPlugin{this}; WriteData data(temporaryFileName, mimeType); const QMap properties = { { Property::Artist, QStringLiteral("Artist1 feat Artist2") }, { Property::AlbumArtist, QStringLiteral("Artist1 feat. Artist2") }, { Property::Composer, QStringLiteral("Composer1; Composer2") }, { Property::Lyricist, QStringLiteral("Lyricist1 ft Lyricist2") }, { Property::Genre, QStringLiteral("Genre1; Genre2") }, }; QMap::const_iterator it; for (it = properties.begin(); it != properties.end(); ++it) { data.add(it.key(), it.value()); } writerPlugin.write(data); KFileMetaData::SimpleExtractionResult result(temporaryFileName, mimeType, KFileMetaData::ExtractionResult::ExtractMetaData); extractResult(mimeType, result); for (it = properties.begin(); it != properties.end(); ++it) { QCOMPARE(result.properties().value(it.key()), it.value()); } QFile::remove(temporaryFileName); } void TagLibWriterTest::testComplexContactData_data() { QTest::addColumn("fileExtension"); QTest::addColumn("mimeType"); QTest::addRow("aiff") << QStringLiteral("aif") << QStringLiteral("audio/x-aiff") ; QTest::addRow("ape") << QStringLiteral("ape") << QStringLiteral("audio/x-ape") ; QTest::addRow("flac") << QStringLiteral("flac") << QStringLiteral("audio/flac") ; QTest::addRow("mp3") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") ; QTest::addRow("mpc") << QStringLiteral("mpc") << QStringLiteral("audio/x-musepack") ; QTest::addRow("ogg") << QStringLiteral("ogg") << QStringLiteral("audio/ogg") ; QTest::addRow("opus") << QStringLiteral("opus") << QStringLiteral("audio/opus") ; QTest::addRow("speex") << QStringLiteral("spx") << QStringLiteral("audio/speex") ; QTest::addRow("wav") << QStringLiteral("wav") << QStringLiteral("audio/wav") ; QTest::addRow("wavpack") << QStringLiteral("wv") << QStringLiteral("audio/x-wavpack") ; } QTEST_GUILESS_MAIN(TagLibWriterTest) diff --git a/autotests/taglibwritertest.h b/autotests/taglibwritertest.h index 1d9af03..69bedcf 100644 --- a/autotests/taglibwritertest.h +++ b/autotests/taglibwritertest.h @@ -1,48 +1,35 @@ /* - * Copyright (C) 2016 Varun Joshi - * 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 - * - */ + SPDX-FileCopyrightText: 2016 Varun Joshi + SPDX-FileCopyrightText: 2018 Alexander Stippich + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef TAGLIBWRITERTEST_H #define TAGLIBWRITERTEST_H #include namespace KFileMetaData { class ExtractionResult; } class TagLibWriterTest : public QObject { Q_OBJECT private: QString testFilePath(const QString& fileName) const; void extractResult(const QString &mimeType, KFileMetaData::ExtractionResult &result); private Q_SLOTS: void testCommonData(); void testCommonData_data(); void testExtendedData(); void testExtendedData_data(); void testRating(); void testRating_data(); void testComplexContactData(); void testComplexContactData_data(); }; #endif // TAGLIBWRITERTEST_H diff --git a/autotests/usermetadatawritertest.cpp b/autotests/usermetadatawritertest.cpp index a1bc9fe..47696d5 100644 --- a/autotests/usermetadatawritertest.cpp +++ b/autotests/usermetadatawritertest.cpp @@ -1,138 +1,125 @@ /* - * Copyright (C) 2017 James D. Smith - * - * 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 - * - */ + SPDX-FileCopyrightText: 2017 James D. Smith + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "usermetadatawritertest.h" #include "indexerextractortestsconfig.h" #include "usermetadata.h" #include #include #define TEST_FILENAME "writertest.txt" #define TEST_SYMLINK "dangling_symlink" using namespace KFileMetaData; QString UserMetaDataWriterTest::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + fileName; } void UserMetaDataWriterTest::initTestCase() { QFile testFile(testFilePath("plain_text_file.txt")); QFile writerTestFile(testFilePath(TEST_FILENAME)); QFile::copy(testFilePath("plain_text_file.txt"), testFilePath(TEST_FILENAME)); QFile::link(testFilePath("invalid_target"), testFilePath(TEST_SYMLINK)); } void UserMetaDataWriterTest::test() { KFileMetaData::UserMetaData md(testFilePath(TEST_FILENAME)); QVERIFY(md.isSupported()); // Tags md.setTags(QStringList() << QStringLiteral("this/is/a/test/tag")); QCOMPARE(md.tags().at(0), QStringLiteral("this/is/a/test/tag")); QVERIFY(md.queryAttributes(UserMetaData::Attribute::Any) & UserMetaData::Attribute::Tags); QVERIFY(md.queryAttributes(UserMetaData::Attribute::All) & UserMetaData::Attribute::Tags); QVERIFY(md.queryAttributes(UserMetaData::Attribute::Tags) & UserMetaData::Attribute::Tags); QVERIFY(!(md.queryAttributes(UserMetaData::Attribute::Rating) & UserMetaData::Attribute::Tags)); md.setTags(QStringList()); QVERIFY(!md.hasAttribute(QStringLiteral("xdg.tags"))); QVERIFY(!(md.queryAttributes(UserMetaData::Attribute::Tags) & UserMetaData::Attribute::Tags)); // Rating md.setRating(3); QCOMPARE(md.rating(), 3); QVERIFY(md.queryAttributes(UserMetaData::Attribute::All) & UserMetaData::Attribute::Rating); QVERIFY(md.queryAttributes(UserMetaData::Attribute::Rating) & UserMetaData::Attribute::Rating); md.setRating(0); QVERIFY(!md.hasAttribute(QStringLiteral("baloo.rating"))); QVERIFY(!(md.queryAttributes(UserMetaData::Attribute::All) & UserMetaData::Attribute::Rating)); QVERIFY(!(md.queryAttributes(UserMetaData::Attribute::Rating) & UserMetaData::Attribute::Rating)); // Comment md.setUserComment(QStringLiteral("this is a test comment")); QCOMPARE(md.userComment(), QStringLiteral("this is a test comment")); md.setUserComment(QString()); QVERIFY(!md.hasAttribute(QStringLiteral("xdg.comment"))); // Origin url md.setOriginUrl(QUrl("http://this.is.a.test.website.local")); QCOMPARE(md.originUrl(), QUrl("http://this.is.a.test.website.local")); md.setOriginUrl(QUrl()); QVERIFY(!md.hasAttribute(QStringLiteral("xdg.origin.url"))); // Origin e-mail subject md.setOriginEmailSubject(QStringLiteral("this is a test e-mail subject")); QCOMPARE(md.originEmailSubject(), QStringLiteral("this is a test e-mail subject")); md.setOriginEmailSubject(QString()); QVERIFY(!md.hasAttribute(QStringLiteral("xdg.origin.email.subject"))); // Origin e-mail sender md.setOriginEmailSender(QStringLiteral("Blue Bear")); QCOMPARE(md.originEmailSender(), QStringLiteral("Blue Bear")); md.setOriginEmailSender(QString()); QVERIFY(!md.hasAttribute(QStringLiteral("xdg.origin.email.sender"))); // Origin e-mail message id md.setOriginEmailMessageId(QStringLiteral("19991231235959.52234.24C26516HHBTF1C4")); QCOMPARE(md.originEmailMessageId(), QStringLiteral("19991231235959.52234.24C26516HHBTF1C4")); md.setOriginEmailMessageId(QString()); QVERIFY(!md.hasAttribute(QStringLiteral("xdg.origin.email.message-id"))); // Attribute md.setAttribute(QStringLiteral("test.attribute"), QStringLiteral("attribute")); QCOMPARE(md.attribute(QStringLiteral("test.attribute")), QStringLiteral("attribute")); md.setAttribute(QStringLiteral("test.attribute2"), QStringLiteral("attribute2")); QCOMPARE(md.attribute(QStringLiteral("test.attribute2")), QStringLiteral("attribute2")); QVERIFY(md.queryAttributes(UserMetaData::Attribute::All) & UserMetaData::Attribute::Other); QVERIFY(md.queryAttributes(UserMetaData::Attribute::Other) & UserMetaData::Attribute::Other); md.setAttribute(QStringLiteral("test.attribute"), QString()); QVERIFY(!md.hasAttribute(QStringLiteral("test.attribute"))); QVERIFY(md.queryAttributes(UserMetaData::Attribute::All) & UserMetaData::Attribute::Other); QVERIFY(md.queryAttributes(UserMetaData::Attribute::Other) & UserMetaData::Attribute::Other); md.setAttribute(QStringLiteral("test.attribute2"), QString()); QVERIFY(!md.hasAttribute(QStringLiteral("test.attribute2"))); // Check for side effects of calling sequence QVERIFY(!md.hasAttribute(QStringLiteral("test.check_contains"))); md.setAttribute(QStringLiteral("test.check_contains"), QStringLiteral("dummy")); QVERIFY(md.hasAttribute(QStringLiteral("test.check_contains"))); md.setAttribute(QStringLiteral("test.check_contains"), QString()); QVERIFY(!md.hasAttribute(QStringLiteral("test.check_contains"))); } void UserMetaDataWriterTest::testDanglingSymlink() { KFileMetaData::UserMetaData md(testFilePath(TEST_SYMLINK)); QVERIFY(md.queryAttributes(UserMetaData::Attribute::All) == UserMetaData::Attribute::None); } void UserMetaDataWriterTest::cleanupTestCase() { QFile::remove(testFilePath(TEST_FILENAME)); QFile::remove(testFilePath(TEST_SYMLINK)); } QTEST_GUILESS_MAIN(UserMetaDataWriterTest) diff --git a/autotests/usermetadatawritertest.h b/autotests/usermetadatawritertest.h index 2faa136..074111f 100644 --- a/autotests/usermetadatawritertest.h +++ b/autotests/usermetadatawritertest.h @@ -1,38 +1,25 @@ /* - * Copyright (C) 2017 James D. Smith - * - * 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 - * - */ + SPDX-FileCopyrightText: 2017 James D. Smith + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef USERMETADATAWRITERTEST_H #define USERMETADATAWRITERTEST_H #include class UserMetaDataWriterTest : public QObject { Q_OBJECT private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void initTestCase(); void test(); void testDanglingSymlink(); void cleanupTestCase(); }; #endif // USERMETADATAWRITERTEST_H diff --git a/autotests/writercollectiontest.cpp b/autotests/writercollectiontest.cpp index 9990263..d81b524 100644 --- a/autotests/writercollectiontest.cpp +++ b/autotests/writercollectiontest.cpp @@ -1,49 +1,36 @@ /* - * 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 - * - */ + This file is part of the KDE KFileMetaData project + SPDX-FileCopyrightText: 2014 Vishesh Handa + SPDX-FileCopyrightText: 2017 Igor Poboiko + SPDX-FileCopyrightText: 2019 Alexander Stippich + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #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/autotests/xmlextractortest.cpp b/autotests/xmlextractortest.cpp index 711d126..9f49491 100644 --- a/autotests/xmlextractortest.cpp +++ b/autotests/xmlextractortest.cpp @@ -1,183 +1,169 @@ /* - Copyright (C) 2018 Stefan Brüns - - 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 . + SPDX-FileCopyrightText: 2018 Stefan Brüns + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "xmlextractortest.h" #include #include #include #include "simpleextractionresult.h" #include "indexerextractortestsconfig.h" #include "extractors/xmlextractor.h" #include "mimeutils.h" using namespace KFileMetaData; XmlExtractorTests::XmlExtractorTests(QObject* parent) : QObject(parent) { } QString XmlExtractorTests::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + fileName; } void XmlExtractorTests::testNoExtraction() { XmlExtractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test_with_metadata.svg")); QMimeDatabase mimeDb; QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType, ExtractionResult::ExtractNothing); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().at(0), Type::Image); QCOMPARE(result.properties().size(), 0); } void XmlExtractorTests::benchMarkXmlExtractor() { XmlExtractor plugin(this); // generate a test file with varying number of words per line QTemporaryFile file(QStringLiteral("XXXXXX.xml")); QVERIFY(file.open()); int count = 0; file.write("\n"); QByteArray chunk("foo bar "); for (int line = 0; line < 10000; ++line) { // staircase pattern, 0, 1, 2, ... 98, 0, 0, 1 ... chunks per line for (int i = 0; i < line % 100; ++i) { count++; file.write(chunk); } file.write("\n"); } file.write("\n"); file.close(); SimpleExtractionResult result(file.fileName(), QStringLiteral("application/xml")); plugin.extract(&result); QString content = QStringLiteral("foo bar\n"); content.replace(QLatin1Char('\n'), QLatin1Char(' ')); QCOMPARE(result.text().leftRef(8), content.leftRef(8)); QCOMPARE(result.text().size(), 8 * count); QBENCHMARK { plugin.extract(&result); } } void XmlExtractorTests::testXmlExtractor() { XmlExtractor plugin{this}; QString fileName = testFilePath(QStringLiteral("test_with_metadata.svg")); QMimeDatabase mimeDb; QString mimeType = MimeUtils::strictMimeType(fileName, mimeDb).name(); QVERIFY(plugin.mimetypes().contains(mimeType)); SimpleExtractionResult result(fileName, mimeType, ExtractionResult::ExtractEverything); plugin.extract(&result); QString content = QStringLiteral("Some text\n"); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().at(0), Type::Image); QCOMPARE(result.properties().size(), 1); QCOMPARE(result.properties().value(Property::Title).toString(), QStringLiteral("Document Title")); content.replace(QLatin1Char('\n'), QLatin1Char(' ')); QCOMPARE(result.text(), content); } void XmlExtractorTests::testXmlExtractorNoContent() { XmlExtractor plugin{this}; SimpleExtractionResult result(testFilePath(QStringLiteral("test_with_metadata.svg")), QStringLiteral("image/svg"), ExtractionResult::ExtractMetaData); plugin.extract(&result); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().at(0), Type::Image); QCOMPARE(result.properties().size(), 1); QCOMPARE(result.properties().value(Property::Title).toString(), QStringLiteral("Document Title")); QVERIFY(result.text().isEmpty()); } void XmlExtractorTests::testXmlExtractorContainer() { XmlExtractor plugin{this}; SimpleExtractionResult result(testFilePath(QStringLiteral("test_with_container.svg")), QStringLiteral("image/svg"), ExtractionResult::ExtractEverything); plugin.extract(&result); QString content = QStringLiteral("Some text below \n"); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().at(0), Type::Image); QCOMPARE(result.properties().size(), 0); content.replace(QLatin1Char('\n'), QLatin1Char(' ')); QCOMPARE(result.text(), content); } void XmlExtractorTests::testXmlExtractorMathML() { XmlExtractor plugin{this}; SimpleExtractionResult result(testFilePath(QStringLiteral("test.mml")), QStringLiteral("application/mathml+xml"), ExtractionResult::ExtractEverything); plugin.extract(&result); QString content = QStringLiteral("1 + 1 = 2\n"); QCOMPARE(result.types().size(), 1); QCOMPARE(result.types().at(0), Type::Text); QCOMPARE(result.properties().size(), 0); content.replace(QLatin1Char('\n'), QLatin1Char(' ')); QCOMPARE(result.text(), content); } QTEST_GUILESS_MAIN(XmlExtractorTests) diff --git a/autotests/xmlextractortest.h b/autotests/xmlextractortest.h index 858bea9..e92c1c3 100644 --- a/autotests/xmlextractortest.h +++ b/autotests/xmlextractortest.h @@ -1,45 +1,31 @@ /* - Copyright (C) 2018 Stefan Brüns + SPDX-FileCopyrightText: 2018 Stefan Brüns - 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 . + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef XMLEXTRACTORTESTS_H #define XMLEXTRACTORTESTS_H #include #include class XmlExtractorTests : public QObject { Q_OBJECT public: explicit XmlExtractorTests(QObject* parent = nullptr); private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void testNoExtraction(); void benchMarkXmlExtractor(); void testXmlExtractor(); void testXmlExtractorNoContent(); void testXmlExtractorContainer(); void testXmlExtractorMathML(); }; #endif // XMLEXTRACTORTESTS_H diff --git a/cmake/FindCatDoc.cmake b/cmake/FindCatDoc.cmake index ac2234e..d68f55e 100644 --- a/cmake/FindCatDoc.cmake +++ b/cmake/FindCatDoc.cmake @@ -1,37 +1,13 @@ # - Find CatDoc # # This module defines # CATDOC_FOUND - whether the catdoc executable was found -# Copyright (c) 2015, Vishesh Handa -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. - +# SPDX-FileCopyrightText: 2015 Vishesh Handa +# SPDX-License-Identifier: BSD-3-Clause find_program(CATDOC_EXE NAMES catdoc) if (CATDOC_EXE) set (CATDOC_FOUND TRUE) endif() diff --git a/cmake/FindEPub.cmake b/cmake/FindEPub.cmake index bba72d8..492ea3b 100644 --- a/cmake/FindEPub.cmake +++ b/cmake/FindEPub.cmake @@ -1,56 +1,32 @@ # - Find EPub # Find the EPub library. # # This module defines # EPUB_FOUND - whether the EPub library was found # EPUB_LIBRARIES - the EPub library # EPUB_INCLUDE_DIR - the include path of the EPub library -# Copyright (c) 2008, Pino Toscano, -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. - +# SPDX-FileCopyrightText: 2008 Pino Toscano +# SPDX-License-Identifier: BSD-3-Clause if (EPUB_INCLUDE_DIR AND EPUB_LIBRARIES) # Already in cache set (EPUB_FOUND TRUE) else (EPUB_INCLUDE_DIR AND EPUB_LIBRARIES) find_library (EPUB_LIBRARIES NAMES epub libepub ) find_path (EPUB_INCLUDE_DIR NAMES epub.h ) include (FindPackageHandleStandardArgs) find_package_handle_standard_args (EPub DEFAULT_MSG EPUB_LIBRARIES EPUB_INCLUDE_DIR) endif (EPUB_INCLUDE_DIR AND EPUB_LIBRARIES) mark_as_advanced(EPUB_INCLUDE_DIR EPUB_LIBRARIES) diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index 5217f93..e9449ff 100644 --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -1,174 +1,151 @@ # vim: ts=2 sw=2 # - Try to find the required ffmpeg components(default: AVFORMAT, AVUTIL, AVCODEC) # # Once done this will define # FFMPEG_FOUND - System has the all required components. # FFMPEG_INCLUDE_DIRS - Include directory necessary for using the required components headers. # FFMPEG_LIBRARIES - Link these to use the required ffmpeg components. # FFMPEG_DEFINITIONS - Compiler switches required for using the required ffmpeg components. # # For each of the components it will additionally set. # - AVCODEC # - AVDEVICE # - AVFORMAT # - AVUTIL # - POSTPROCESS # - SWSCALE # the following variables will be defined # _FOUND - System has # _INCLUDE_DIRS - Include directory necessary for using the headers # _LIBRARIES - Link these to use # _DEFINITIONS - Compiler switches required for using # _VERSION - The components version # -# Copyright (c) 2006, Matthias Kretz, -# Copyright (c) 2008, Alexander Neundorf, -# Copyright (c) 2011, Michael Jansen, -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. +# SPDX-FileCopyrightText: 2006 Matthias Kretz +# SPDX-FileCopyrightText: 2008 Alexander Neundorf +# SPDX-FileCopyrightText: 2011 Michael Jansen +# SPDX-License-Identifier: BSD-3-Clause include(FindPackageHandleStandardArgs) # The default components were taken from a survey over other FindFFMPEG.cmake files if (NOT FFmpeg_FIND_COMPONENTS) set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL) endif () # ### Macro: set_component_found # # Marks the given component as found if both *_LIBRARIES AND *_INCLUDE_DIRS is present. # macro(set_component_found _component ) if (${_component}_LIBRARIES AND ${_component}_INCLUDE_DIRS) # message(STATUS " - ${_component} found.") set(${_component}_FOUND TRUE) set(FFmpeg_${_component}_FOUND TRUE) else () # message(STATUS " - ${_component} not found.") endif () endmacro() # ### Macro: find_component # # Checks for the given component by invoking pkgconfig and then looking up the libraries and # include directories. # macro(find_component _component _pkgconfig _library _header _version) if (NOT WIN32) # use pkg-config to get the directories and then use these values # in the FIND_PATH() and FIND_LIBRARY() calls find_package(PkgConfig) if (PKG_CONFIG_FOUND) pkg_check_modules(PC_${_component} ${_pkgconfig}>=${_version}) endif () endif (NOT WIN32) find_path(${_component}_INCLUDE_DIRS ${_header} HINTS ${PC_LIB${_component}_INCLUDEDIR} ${PC_LIB${_component}_INCLUDE_DIRS} PATH_SUFFIXES ffmpeg ) find_library(${_component}_LIBRARIES NAMES ${_library} HINTS ${PC_LIB${_component}_LIBDIR} ${PC_LIB${_component}_LIBRARY_DIRS} ) set(${_component}_DEFINITIONS ${PC_${_component}_CFLAGS_OTHER} CACHE STRING "The ${_component} CFLAGS.") set(${_component}_VERSION ${PC_${_component}_VERSION} CACHE STRING "The ${_component} version number.") set_component_found(${_component}) mark_as_advanced( ${_component}_INCLUDE_DIRS ${_component}_LIBRARIES ${_component}_DEFINITIONS ${_component}_VERSION) endmacro() # Check for cached results. If there are skip the costly part. if (NOT FFMPEG_LIBRARIES) # Check for all possible component. find_component(AVCODEC libavcodec avcodec libavcodec/avcodec.h ${FFmpeg_FIND_VERSION}) find_component(AVFORMAT libavformat avformat libavformat/avformat.h ${FFmpeg_FIND_VERSION}) find_component(AVDEVICE libavdevice avdevice libavdevice/avdevice.h ${FFmpeg_FIND_VERSION}) find_component(AVUTIL libavutil avutil libavutil/avutil.h ${FFmpeg_FIND_VERSION}) find_component(SWSCALE libswscale swscale libswscale/swscale.h ${FFmpeg_FIND_VERSION}) find_component(POSTPROCESS libpostproc postproc libpostproc/postprocess.h ${FFmpeg_FIND_VERSION}) # Check if the required components were found and add their stuff to the FFMPEG_* vars. foreach (_component ${FFmpeg_FIND_COMPONENTS}) if (${_component}_FOUND) # message(STATUS "Required component ${_component} present.") set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${${_component}_LIBRARIES}) set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} ${${_component}_DEFINITIONS}) list(APPEND FFMPEG_INCLUDE_DIRS ${${_component}_INCLUDE_DIRS}) else () # message(STATUS "Required component ${_component} missing.") endif () endforeach () # Build the include path with duplicates removed. if (FFMPEG_INCLUDE_DIRS) list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS) endif () # cache the vars. set(FFMPEG_INCLUDE_DIRS ${FFMPEG_INCLUDE_DIRS} CACHE STRING "The FFmpeg include directories." FORCE) set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} CACHE STRING "The FFmpeg libraries." FORCE) set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} CACHE STRING "The FFmpeg cflags." FORCE) mark_as_advanced(FFMPEG_INCLUDE_DIRS FFMPEG_LIBRARIES FFMPEG_DEFINITIONS) endif () # Now set the noncached _FOUND vars for the components. foreach (_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE) set_component_found(${_component}) endforeach () # Compile the list of required vars set(_FFmpeg_REQUIRED_VARS FFMPEG_LIBRARIES FFMPEG_INCLUDE_DIRS) foreach (_component ${FFmpeg_FIND_COMPONENTS}) list(APPEND _FFmpeg_REQUIRED_VARS ${_component}_LIBRARIES ${_component}_INCLUDE_DIRS) endforeach () # Give a nice error message if some of the required vars are missing. find_package_handle_standard_args(FFmpeg REQUIRED_VARS ${_FFmpeg_REQUIRED_VARS} HANDLE_COMPONENTS) diff --git a/cmake/FindLibraryWithDebug.cmake b/cmake/FindLibraryWithDebug.cmake index 7fd0dd5..448f147 100644 --- a/cmake/FindLibraryWithDebug.cmake +++ b/cmake/FindLibraryWithDebug.cmake @@ -1,135 +1,112 @@ # # FIND_LIBRARY_WITH_DEBUG # -> enhanced FIND_LIBRARY to allow the search for an # optional debug library with a WIN32_DEBUG_POSTFIX similar # to CMAKE_DEBUG_POSTFIX when creating a shared lib # it has to be the second and third argument -# Copyright (c) 2007, Christian Ehrlicher, - -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. +# SPDX-FileCopyrightText: 2007 Christian Ehrlicher +# SPDX-License-Identifier: BSD-3-Clause MACRO(FIND_LIBRARY_WITH_DEBUG var_name win32_dbg_postfix_name dgb_postfix libname) IF(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX") # no WIN32_DEBUG_POSTFIX -> simply pass all arguments to FIND_LIBRARY FIND_LIBRARY(${var_name} ${win32_dbg_postfix_name} ${dgb_postfix} ${libname} ${ARGN} ) ELSE(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX") IF(NOT WIN32) # on non-win32 we don't need to take care about WIN32_DEBUG_POSTFIX FIND_LIBRARY(${var_name} ${libname} ${ARGN}) ELSE(NOT WIN32) # 1. get all possible libnames SET(args ${ARGN}) SET(newargs "") SET(libnames_release "") SET(libnames_debug "") LIST(LENGTH args listCount) IF("${libname}" STREQUAL "NAMES") SET(append_rest 0) LIST(APPEND args " ") FOREACH(i RANGE ${listCount}) LIST(GET args ${i} val) IF(append_rest) LIST(APPEND newargs ${val}) ELSE(append_rest) IF("${val}" STREQUAL "PATHS") LIST(APPEND newargs ${val}) SET(append_rest 1) ELSE("${val}" STREQUAL "PATHS") LIST(APPEND libnames_release "${val}") LIST(APPEND libnames_debug "${val}${dgb_postfix}") ENDIF("${val}" STREQUAL "PATHS") ENDIF(append_rest) ENDFOREACH(i) ELSE("${libname}" STREQUAL "NAMES") # just one name LIST(APPEND libnames_release "${libname}") LIST(APPEND libnames_debug "${libname}${dgb_postfix}") SET(newargs ${args}) ENDIF("${libname}" STREQUAL "NAMES") # search the release lib FIND_LIBRARY(${var_name}_RELEASE NAMES ${libnames_release} ${newargs} ) # search the debug lib FIND_LIBRARY(${var_name}_DEBUG NAMES ${libnames_debug} ${newargs} ) IF(${var_name}_RELEASE AND ${var_name}_DEBUG) # both libs found SET(${var_name} optimized ${${var_name}_RELEASE} debug ${${var_name}_DEBUG}) ELSE(${var_name}_RELEASE AND ${var_name}_DEBUG) IF(${var_name}_RELEASE) # only release found SET(${var_name} ${${var_name}_RELEASE}) ELSE(${var_name}_RELEASE) # only debug (or nothing) found SET(${var_name} ${${var_name}_DEBUG}) ENDIF(${var_name}_RELEASE) - + ENDIF(${var_name}_RELEASE AND ${var_name}_DEBUG) MARK_AS_ADVANCED(${var_name}_RELEASE) MARK_AS_ADVANCED(${var_name}_DEBUG) ENDIF(NOT WIN32) ENDIF(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX") ENDMACRO(FIND_LIBRARY_WITH_DEBUG) diff --git a/cmake/FindTaglib.cmake b/cmake/FindTaglib.cmake index 0439b75..185844d 100644 --- a/cmake/FindTaglib.cmake +++ b/cmake/FindTaglib.cmake @@ -1,89 +1,66 @@ # - Try to find the Taglib library # Once done this will define # # TAGLIB_FOUND - system has the taglib library # TAGLIB_INCLUDES - the taglib includes # TAGLIB_LIBRARIES - The libraries needed to use taglib -# Copyright (c) 2006, Laurent Montel, -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. +# SPDX-FileCopyrightText: 2006 Laurent Montel +# SPDX-License-Identifier: BSD-3-Clause if(NOT TAGLIB_MIN_VERSION) set(TAGLIB_MIN_VERSION "1.4") endif(NOT TAGLIB_MIN_VERSION) if(NOT WIN32 AND NOT ANDROID) find_program(TAGLIBCONFIG_EXECUTABLE NAMES taglib-config PATHS ${BIN_INSTALL_DIR} ) endif() #reset vars set(TAGLIB_LIBRARIES) set(TAGLIB_CFLAGS) # if taglib-config has been found if(TAGLIBCONFIG_EXECUTABLE) exec_program(${TAGLIBCONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE TAGLIB_VERSION) exec_program(${TAGLIBCONFIG_EXECUTABLE} ARGS --libs RETURN_VALUE _return_VALUE OUTPUT_VARIABLE TAGLIB_LIBRARIES) exec_program(${TAGLIBCONFIG_EXECUTABLE} ARGS --cflags RETURN_VALUE _return_VALUE OUTPUT_VARIABLE TAGLIB_CFLAGS) string(REGEX REPLACE " *-I" ";" TAGLIB_INCLUDES "${TAGLIB_CFLAGS}") include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Taglib FOUND_VAR TAGLIB_FOUND REQUIRED_VARS TAGLIB_LIBRARIES TAGLIB_INCLUDES VERSION_VAR TAGLIB_VERSION) mark_as_advanced(TAGLIB_CFLAGS TAGLIB_LIBRARIES TAGLIB_INCLUDES) else(TAGLIBCONFIG_EXECUTABLE) include(FindLibraryWithDebug) include(FindPackageHandleStandardArgs) find_path(TAGLIB_INCLUDES NAMES tag.h PATH_SUFFIXES taglib PATHS ${KDE4_INCLUDE_DIR} ${INCLUDE_INSTALL_DIR} ) find_library_with_debug(TAGLIB_LIBRARIES WIN32_DEBUG_POSTFIX d NAMES tag PATHS ${KDE4_LIB_DIR} ${LIB_INSTALL_DIR} ) - + include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(Taglib DEFAULT_MSG + find_package_handle_standard_args(Taglib DEFAULT_MSG TAGLIB_INCLUDES TAGLIB_LIBRARIES) endif(TAGLIBCONFIG_EXECUTABLE) diff --git a/src/config-kfilemetadata.h.in b/src/config-kfilemetadata.h.in index 2fe3712..366e5ba 100644 --- a/src/config-kfilemetadata.h.in +++ b/src/config-kfilemetadata.h.in @@ -1,26 +1,13 @@ /* - * 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 - * - */ + SPDX-FileCopyrightText: 2016 Varun Joshi + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef CONFIGKFILEMETADATA_H #define CONFIGKFILEMETADATA_H #define LIBEXEC_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${KF5_LIBEXEC_INSTALL_DIR}" #cmakedefine01 HAVE_AVSTREAM_CODECPAR #endif // CONFIGKFILEMETADATA_H diff --git a/src/embeddedimagedata.cpp b/src/embeddedimagedata.cpp index c9ade14..5d11895 100644 --- a/src/embeddedimagedata.cpp +++ b/src/embeddedimagedata.cpp @@ -1,520 +1,507 @@ /* - * 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 - * - */ + SPDX-FileCopyrightText: 2018 Alexander Stippich + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "embeddedimagedata.h" #include "kfilemetadata_debug.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 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; void writeFrontCover(const QString &fileUrl, const QString &mimeType, const QByteArray &pictureData); void writeFrontCoverToID3(TagLib::ID3v2::Tag* Id3Tags, const QByteArray &pictureData); void writeFrontCoverToFlacPicture(TagLib::List lstPic, const QByteArray &pictureData); void writeFrontCoverToMp4(TagLib::MP4::Tag* mp4Tags, const QByteArray &pictureData); void writeFrontCoverToApe(TagLib::APE::Tag* apeTags, const QByteArray &pictureData); void writeFrontCoverToAsf(TagLib::ASF::Tag* asfTags, const QByteArray &pictureData); TagLib::String determineMimeType(const QByteArray &pictureData); 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; } void EmbeddedImageData::writeImageData(const QString &fileUrl, QMap &imageData) { const auto fileMimeType = d->mMimeDatabase.mimeTypeForFile(fileUrl); QMap::iterator frontCover = imageData.find(EmbeddedImageData::FrontCover); if (fileMimeType.name().startsWith(QLatin1String("audio/"))) { if (frontCover != imageData.end()) { d->writeFrontCover(fileUrl, fileMimeType.name(), frontCover.value()); } } } QByteArray EmbeddedImageData::Private::getFrontCover(const QString &fileUrl, const QString &mimeType) const { TagLib::FileStream stream(fileUrl.toUtf8().constData(), true); if (!stream.isOpen()) { qCWarning(KFILEMETADATA_LOG) << "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(); } void EmbeddedImageData::Private::writeFrontCover(const QString &fileUrl, const QString &mimeType, const QByteArray &pictureData) { TagLib::FileStream stream(fileUrl.toUtf8().constData(), false); if (!stream.isOpen()) { qWarning() << "Unable to open file: " << fileUrl; return; } 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(), false); if (mpegFile.ID3v2Tag()) { writeFrontCoverToID3(mpegFile.ID3v2Tag(), pictureData); } mpegFile.save(); } else if (mimeType == QLatin1String("audio/x-aiff")) { TagLib::RIFF::AIFF::File aiffFile(&stream, false); if (aiffFile.hasID3v2Tag()) { writeFrontCoverToID3(aiffFile.tag(), pictureData); } aiffFile.save(); } else if ((mimeType == QLatin1String("audio/wav")) || (mimeType == QLatin1String("audio/x-wav"))) { TagLib::RIFF::WAV::File wavFile(&stream, false); if (wavFile.hasID3v2Tag()) { writeFrontCoverToID3(wavFile.ID3v2Tag(), pictureData); } wavFile.save(); } else if (mimeType == QLatin1String("audio/mp4")) { TagLib::MP4::File mp4File(&stream, false); if (mp4File.tag()) { writeFrontCoverToMp4(mp4File.tag(), pictureData); } mp4File.save(); } else if (mimeType == QLatin1String("audio/x-musepack")) { TagLib::MPC::File mpcFile(&stream, false); if (mpcFile.APETag()) { writeFrontCoverToApe(mpcFile.APETag(), pictureData); } mpcFile.save(); } else if (mimeType == QLatin1String("audio/x-ape")) { TagLib::APE::File apeFile(&stream, false); if (apeFile.hasAPETag()) { writeFrontCoverToApe(apeFile.APETag(), pictureData); } apeFile.save(); } else if (mimeType == QLatin1String("audio/x-wavpack")) { TagLib::WavPack::File wavpackFile(&stream, false); if (wavpackFile.hasAPETag()) { writeFrontCoverToApe(wavpackFile.APETag(), pictureData); } wavpackFile.save(); } else if (mimeType == QLatin1String("audio/x-ms-wma")) { TagLib::ASF::File asfFile(&stream, false); TagLib::ASF::Tag* asfTags = dynamic_cast(asfFile.tag()); if (asfTags) { writeFrontCoverToAsf(asfTags, pictureData); } asfFile.save(); } else if (mimeType == QLatin1String("audio/flac")) { TagLib::FLAC::File flacFile(&stream, TagLib::ID3v2::FrameFactory::instance(), false); writeFrontCoverToFlacPicture(flacFile.pictureList(), pictureData); flacFile.save(); } else if ((mimeType == QLatin1String("audio/ogg")) || (mimeType == QLatin1String("audio/x-vorbis+ogg"))) { TagLib::Ogg::Vorbis::File oggFile(&stream, false); if (oggFile.tag()) { writeFrontCoverToFlacPicture(oggFile.tag()->pictureList(), pictureData); } oggFile.save(); } else if ((mimeType == QLatin1String("audio/opus")) || (mimeType == QLatin1String("audio/x-opus+ogg"))) { TagLib::Ogg::Opus::File opusFile(&stream, false); if (opusFile.tag()) { writeFrontCoverToFlacPicture(opusFile.tag()->pictureList(), pictureData); } opusFile.save(); } else if (mimeType == QLatin1String("audio/speex") || mimeType == QLatin1String("audio/x-speex")) { TagLib::Ogg::Speex::File speexFile(&stream, false); if (speexFile.tag()) { writeFrontCoverToFlacPicture(speexFile.tag()->pictureList(), pictureData); } speexFile.save(); } } 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(); } void EmbeddedImageData::Private::writeFrontCoverToID3(TagLib::ID3v2::Tag* Id3Tags, const QByteArray &pictureData) { // Try to update existing front cover frame first TagLib::ID3v2::FrameList lstID3v2; lstID3v2 = Id3Tags->frameListMap()["APIC"]; for (auto& frame : qAsConst(lstID3v2)) { auto *frontCoverFrame = static_cast(frame); if (frontCoverFrame->type() == frontCoverFrame->FrontCover) { frontCoverFrame->setPicture(TagLib::ByteVector(static_cast(pictureData.data()), pictureData.size())); frontCoverFrame->setMimeType(determineMimeType(pictureData)); return; } } auto pictureFrame = new TagLib::ID3v2::AttachedPictureFrame; pictureFrame->setPicture(TagLib::ByteVector(pictureData.data(), pictureData.size())); pictureFrame->setType(pictureFrame->FrontCover); pictureFrame->setMimeType(determineMimeType(pictureData)); Id3Tags->addFrame(pictureFrame); } 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(); } void EmbeddedImageData::Private::writeFrontCoverToFlacPicture(TagLib::List lstPic, const QByteArray &pictureData) { for (const auto &picture : qAsConst(lstPic)) { if (picture->type() == picture->FrontCover) { picture->setData(TagLib::ByteVector(pictureData.data(), pictureData.size())); picture->setMimeType(determineMimeType(pictureData)); return ; } } auto flacPicture = new TagLib::FLAC::Picture; flacPicture->setMimeType(determineMimeType(pictureData)); flacPicture->setData(TagLib::ByteVector(pictureData.data(), pictureData.size())); lstPic.append(flacPicture); } 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(); } void EmbeddedImageData::Private::writeFrontCoverToMp4(TagLib::MP4::Tag* mp4Tags, const QByteArray &pictureData) { TagLib::MP4::Item coverArtItem = mp4Tags->item("covr"); TagLib::MP4::CoverArtList coverArtList; TagLib::MP4::CoverArt coverArt(TagLib::MP4::CoverArt::Format::Unknown, TagLib::ByteVector(pictureData.data(), pictureData.size())); if (coverArtItem.isValid()) { coverArtList = coverArtItem.toCoverArtList(); coverArtList.clear(); } coverArtList.append(coverArt); mp4Tags->setItem("covr", coverArtList); } 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(); } void EmbeddedImageData::Private::writeFrontCoverToApe(TagLib::APE::Tag* apeTags, const QByteArray &pictureData) { /* The cover art tag for APEv2 tags starts with the filename as string * with zero termination followed by the actual picture data */ TagLib::ByteVector imageData; TagLib::String name; if (determineMimeType(pictureData) == TagLib::String("image/png")) { name = "frontCover.png"; } else { name = "frontCover.jpeg"; } imageData.append(name.data(TagLib::String::UTF8)); imageData.append('\0'); imageData.append(TagLib::ByteVector(pictureData.constData(), pictureData.size())); apeTags->setData("COVER ART (FRONT)", imageData); } 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(); } void EmbeddedImageData::Private::writeFrontCoverToAsf(TagLib::ASF::Tag* asfTags, const QByteArray &pictureData) { 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) { picture.setPicture(TagLib::ByteVector(pictureData.constData(), pictureData.size())); picture.setMimeType(determineMimeType(pictureData)); TagLib::ByteVector pictureData = picture.picture(); return; } } TagLib::ASF::Picture picture; picture.setPicture(TagLib::ByteVector(pictureData.constData(), pictureData.size())); picture.setType(TagLib::ASF::Picture::FrontCover); lstASF.append(picture); } TagLib::String EmbeddedImageData::Private::determineMimeType(const QByteArray &pictureData) { if (pictureData.startsWith(QByteArray::fromHex("89504E470D0A1A0A"))) { return TagLib::String("image/png"); } else if (pictureData.startsWith(QByteArray::fromHex("FFD8FFDB")) || pictureData.startsWith(QByteArray::fromHex("FFD8FFE000104A4649460001")) || pictureData.startsWith(QByteArray::fromHex("FFD8FFEE")) || pictureData.startsWith(QByteArray::fromHex("FFD8FFE1"))) { return TagLib::String("image/jpeg"); } else { return TagLib::String(); } } diff --git a/src/embeddedimagedata.h b/src/embeddedimagedata.h index f424e22..b0ad51f 100644 --- a/src/embeddedimagedata.h +++ b/src/embeddedimagedata.h @@ -1,87 +1,74 @@ /* - * EmbeddedImageData extracts binary data of cover art files. - * 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 - * - */ + EmbeddedImageData extracts binary data of cover art files. + SPDX-FileCopyrightText: 2018 Alexander Stippich + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef KFILEMETADATA_EMBEDDEDIMAGEDATA_H #define KFILEMETADATA_EMBEDDEDIMAGEDATA_H #include "kfilemetadata_export.h" #include #include #include #include namespace KFileMetaData { /** * \class EmbeddedImageData embeddedimagedata.h * * \brief The EmbeddedImageData is a class which extracts and writes the images * stored in the metadata tags of files as byte arrays. For example, the front * cover art of music albums may be extracted with this class. The byte array * will mostly contain jpeg or png files, which can be loaded into e.g. QImage. * * \author Alexander Stippich */ class KFILEMETADATA_EXPORT EmbeddedImageData { public: EmbeddedImageData(); virtual ~EmbeddedImageData(); /** * @see ImageTypes */ enum ImageType { FrontCover = 0x01, AllImages = FrontCover }; /** * Stores a combination of #ImageType values. */ Q_DECLARE_FLAGS(ImageTypes, ImageType) /** * Extracts the images stored in the metadata tags from a file. * By default, the front cover is extracted. */ QMap imageData(const QString &fileUrl, const EmbeddedImageData::ImageTypes types = FrontCover) const; /** * Provides a list of mimetypes which are supported for reading * of embedded images in e.g. audio files. * @since 5.52 */ QStringList mimeTypes() const; /** * Write the images to the metadata tags in a file. * Currently, only the front cover is supported. * Mimetype is only correctly set for jpeg and png files. * @since 5.62 */ void writeImageData(const QString &fileUrl, QMap &imageData); private: class Private; std::unique_ptr d; EmbeddedImageData& operator=(const EmbeddedImageData&); }; } #endif // KFILEMETADATA_EMBEDDEDIMAGEDATA_H diff --git a/src/externalextractor.cpp b/src/externalextractor.cpp index 9c2f353..c2965f4 100644 --- a/src/externalextractor.cpp +++ b/src/externalextractor.cpp @@ -1,174 +1,159 @@ /* - * 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 . - * - */ + This file is part of the KFileMetaData project + SPDX-FileCopyrightText: 2016 Varun Joshi + SPDX-FileCopyrightText: 2015 Boudhayan Gupta + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #include "externalextractor.h" #include "kfilemetadata_debug.h" #include "properties.h" #include "propertyinfo.h" #include "typeinfo.h" #include #include #include #include #include #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 QJsonValue &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/externalextractor.h b/src/externalextractor.h index c2f6b36..6cf5aae 100644 --- a/src/externalextractor.h +++ b/src/externalextractor.h @@ -1,50 +1,35 @@ /* - * 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 . - * - */ + This file is part of the KFileMetaData project + SPDX-FileCopyrightText: 2016 Varun Joshi + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #ifndef EXTERNALEXTRACTOR_H #define EXTERNALEXTRACTOR_H #include "extractorplugin.h" namespace KFileMetaData { class ExternalExtractor : public ExtractorPlugin { Q_OBJECT public: explicit ExternalExtractor(QObject* parent = nullptr); explicit ExternalExtractor(const QString& pluginPath); ~ExternalExtractor() override; QStringList mimetypes() const override; void extract(ExtractionResult* result) override; private: class ExternalExtractorPrivate; ExternalExtractorPrivate *d_ptr; Q_DECLARE_PRIVATE(ExternalExtractor) }; } #endif // EXTERNALEXTRACTOR_H diff --git a/src/externalwriter.cpp b/src/externalwriter.cpp index 38e33f3..5182433 100644 --- a/src/externalwriter.cpp +++ b/src/externalwriter.cpp @@ -1,147 +1,132 @@ /* - * 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 . - * - */ + This file is part of the KFileMetaData project + SPDX-FileCopyrightText: 2016 Varun Joshi + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #include "externalwriter.h" #include "properties.h" #include "propertyinfo.h" #include "kfilemetadata_debug.h" #include #include #include #include #include #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 QJsonValue &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/externalwriter.h b/src/externalwriter.h index 91a34ce..5dbe590 100644 --- a/src/externalwriter.h +++ b/src/externalwriter.h @@ -1,53 +1,38 @@ /* - * 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 . - * - */ + This file is part of the KFileMetaData project + SPDX-FileCopyrightText: 2016 Varun Joshi + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #ifndef EXTERNALWRITER_H #define EXTERNALWRITER_H #include "writerplugin.h" namespace KFileMetaData { class ExternalWriter : public WriterPlugin { Q_OBJECT public: explicit ExternalWriter(QObject* parent = nullptr); explicit ExternalWriter(const QString& pluginPath); ~ExternalWriter() override; void write(const WriteData& data) override; QStringList writeMimetypes() const override; private: bool runtimeInstalled() const; bool dependenciesSatisfied() const; class ExternalWriterPrivate; ExternalWriterPrivate *d_ptr; Q_DECLARE_PRIVATE(ExternalWriter) }; } #endif // EXTERNALWRITER_H diff --git a/src/extractionresult.cpp b/src/extractionresult.cpp index b8deeb7..14dfbcd 100644 --- a/src/extractionresult.cpp +++ b/src/extractionresult.cpp @@ -1,71 +1,56 @@ /* - * 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) 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 . - * - */ + SPDX-FileCopyrightText: 2013 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #include "extractionresult.h" #include using namespace KFileMetaData; class Q_DECL_HIDDEN ExtractionResult::Private { public: QString url; QString mimetype; ExtractionResult::Flags flags; }; ExtractionResult::ExtractionResult(const QString& url, const QString& mimetype, const Flags& flags) : d(new Private) { d->url = url; d->mimetype = mimetype; if (mimetype.isEmpty()) { d->mimetype = QMimeDatabase().mimeTypeForFile(url).name(); } d->flags = flags; } ExtractionResult::ExtractionResult(const ExtractionResult& rhs) : d(new Private(*rhs.d)) { } ExtractionResult::~ExtractionResult() { delete d; } QString ExtractionResult::inputUrl() const { return d->url; } QString ExtractionResult::inputMimetype() const { return d->mimetype; } ExtractionResult::Flags ExtractionResult::inputFlags() const { return d->flags; } diff --git a/src/extractionresult.h b/src/extractionresult.h index 379bd26..9f34391 100644 --- a/src/extractionresult.h +++ b/src/extractionresult.h @@ -1,132 +1,117 @@ /* - * 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) 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 . - * - */ + SPDX-FileCopyrightText: 2013 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #ifndef _KFILEMETADATA_EXTRACTIONRESULT_H #define _KFILEMETADATA_EXTRACTIONRESULT_H #include #include #include "kfilemetadata_export.h" #include "properties.h" #include "types.h" namespace KFileMetaData { /** * \class ExtractionResult extractionresult.h * * \brief The ExtractionResult class is where all the data extracted by * the indexer is saved. This class acts as a base class which should be * derived from and then passed to the relevant plugins. * * The derived class needs to implement 3 pure virtual functions through * which it receives the extracted data. * * \author Vishesh Handa */ class KFILEMETADATA_EXPORT ExtractionResult { public: /** * @see Flags */ enum Flag { ExtractNothing = 0, ExtractMetaData = 1, ExtractPlainText = 2, ExtractEverything = (ExtractMetaData | ExtractPlainText) }; /** * Stores a combination of #Flag values. */ Q_DECLARE_FLAGS(Flags, Flag) /** * Create an ExtractionResult which can be passed be to Extractors. The * extractors use the \p url, \p mimetype and \p flags in order to determine * which file the data should be extracted from and which data should * be extracted. */ ExtractionResult(const QString& url, const QString& mimetype = QString(), const Flags& flags = ExtractEverything); ExtractionResult(const ExtractionResult& rhs); virtual ~ExtractionResult(); /** * The input url which the plugins will use to locate the file */ QString inputUrl() const; /** * The input mimetype. This mimetype should correspond with the * mimetypes supported with the relevant plugin when it is being * passed to the Extractor, or be a subtype thereof. * * \sa ExtractorCollection::fetchExtractors * \sa ExtractorPlugin::supportedMimeType */ QString inputMimetype() const; /** * The flags which the extraction plugin should considering following * when extracting metadata from the file */ Flags inputFlags() const; /** * This function is called by plugins when they wish for some plain * text to be indexed without any property. This generally corresponds * to the text content in a file */ virtual void append(const QString& text) = 0; /** * This function is called by the plugins when they wish to * add a key value pair which should be indexed. This function may be * called multiple times for the same key. * * \p property This specifies a property name. It should be one of the * properties from the global list of properties. * * \p value The value of the property */ virtual void add(Property::Property property, const QVariant& value) = 0; /** * This function is called by the plugins. * A type is a higher level classification of the file. A file can * have multiple types, but mostly when it does, those types are related. * Eg - Document and Presentation. * * Please choose one type from the list of available types */ virtual void addType(Type::Type type) = 0; private: class Private; Private* d; }; } Q_DECLARE_OPERATORS_FOR_FLAGS(KFileMetaData::ExtractionResult::Flags) #endif // _KFILEMETADATA_EXTRACTIONRESULT_H diff --git a/src/extractor.cpp b/src/extractor.cpp index 45b0b3c..80a11ce 100644 --- a/src/extractor.cpp +++ b/src/extractor.cpp @@ -1,71 +1,57 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "extractor.h" #include "extractor_p.h" #include "extractorplugin.h" using namespace KFileMetaData; Extractor::Extractor() : d(new ExtractorPrivate) { } Extractor::~Extractor() { delete d; } Extractor::Extractor(Extractor&& other) { d = other.d; other.d = nullptr; } void Extractor::extract(ExtractionResult* result) { d->m_plugin->extract(result); } QStringList Extractor::mimetypes() const { return d->m_plugin->mimetypes(); } QVariantMap Extractor::extractorProperties() const { return d->m_metaData; } void Extractor::setExtractorPlugin(ExtractorPlugin *extractorPlugin) { d->m_plugin = extractorPlugin; } void Extractor::setAutoDeletePlugin(ExtractorPluginOwnership autoDelete) { d->m_autoDeletePlugin = autoDelete; } void Extractor::setMetaData(const QVariantMap &metaData) { d->m_metaData = metaData; } diff --git a/src/extractor.h b/src/extractor.h index 9f5d10a..9556849 100644 --- a/src/extractor.h +++ b/src/extractor.h @@ -1,71 +1,57 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef KFILEMETADATA_EXTRACTOR_H #define KFILEMETADATA_EXTRACTOR_H #include "kfilemetadata_export.h" #include #include namespace KFileMetaData { class ExtractionResult; class ExtractorCollection; class ExtractorPlugin; /** * \class Extractor extractor.h */ class KFILEMETADATA_EXPORT Extractor { class ExtractorPrivate; enum ExtractorPluginOwnership { AutoDeletePlugin, DoNotDeletePlugin, }; public: Extractor(Extractor&&); virtual ~Extractor() noexcept; void extract(ExtractionResult* result); QStringList mimetypes() const; QVariantMap extractorProperties() const; private: Extractor(); Extractor(const Extractor&); void operator =(const Extractor&); void setExtractorPlugin(ExtractorPlugin *extractorPlugin); void setAutoDeletePlugin(ExtractorPluginOwnership autoDelete); void setMetaData(const QVariantMap &metaData); ExtractorPrivate *d; friend class ExtractorCollection; }; } #endif // KFILEMETADATA_EXTRACTOR_H diff --git a/src/extractor_p.h b/src/extractor_p.h index fdfd619..1833e32 100644 --- a/src/extractor_p.h +++ b/src/extractor_p.h @@ -1,81 +1,67 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef KFILEMETADATA_EXTRACTOR_P_H #define KFILEMETADATA_EXTRACTOR_P_H #include "extractorplugin.h" #include "kfilemetadata_debug.h" #include namespace KFileMetaData { class ExtractorPlugin; class Extractor::ExtractorPrivate { public: ~ExtractorPrivate() { if (m_autoDeletePlugin == AutoDeletePlugin) { delete m_plugin; } } bool initPlugin(); ExtractorPlugin *m_plugin = nullptr; ExtractorPluginOwnership m_autoDeletePlugin = AutoDeletePlugin; QVariantMap m_metaData; QString m_pluginPath; }; inline bool Extractor::ExtractorPrivate::initPlugin() { if (m_plugin) { return true; } QPluginLoader loader(m_pluginPath); if (!loader.load()) { qCWarning(KFILEMETADATA_LOG) << "Could not create Extractor:" << m_pluginPath; qCWarning(KFILEMETADATA_LOG) << loader.errorString(); return false; } QObject* obj = loader.instance(); if (!obj) { qCWarning(KFILEMETADATA_LOG) << "Could not create instance:" << m_pluginPath; return false; } m_plugin = qobject_cast(obj); if (!m_plugin) { qCWarning(KFILEMETADATA_LOG) << "Could not convert to ExtractorPlugin:" << m_pluginPath; return false; } m_autoDeletePlugin = Extractor::DoNotDeletePlugin; return true; } } #endif diff --git a/src/extractorcollection.cpp b/src/extractorcollection.cpp index f6e2ae2..a176c83 100644 --- a/src/extractorcollection.cpp +++ b/src/extractorcollection.cpp @@ -1,220 +1,207 @@ /* - * 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 - * - */ + SPDX-FileCopyrightText: 2012 Vishesh Handa + SPDX-FileCopyrightText: 2016 Varun Joshi + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "extractorcollection.h" #include "extractor.h" #include "extractor_p.h" #include "extractorplugin.h" #include "externalextractor.h" #include "kfilemetadata_debug.h" #include "config-kfilemetadata.h" #include #include #include #include #include using namespace KFileMetaData; class Q_DECL_HIDDEN ExtractorCollection::Private { public: QMultiHash 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 (const QString &mimetype : mimetypes) { m_mimeExtractors.insert(mimetype, &extractor); } } else if (extractor.d->m_plugin) { const auto mimetypes = extractor.mimetypes(); for (const QString &mimetype : mimetypes) { m_mimeExtractors.insert(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 (const 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/extractorcollection.h b/src/extractorcollection.h index 9c7dc26..e25abd1 100644 --- a/src/extractorcollection.h +++ b/src/extractorcollection.h @@ -1,66 +1,53 @@ /* - * Copyright (C) 2012 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 - * - */ + SPDX-FileCopyrightText: 2012 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef _KFILEMETADATA_EXTRACTORCOLLECTION_H #define _KFILEMETADATA_EXTRACTORCOLLECTION_H #include "extractor.h" #include "kfilemetadata_export.h" namespace KFileMetaData { /** * \class ExtractorCollection extractorcollection.h * * \brief The ExtractorCollection is a helper class which internally * loads all the extractor plugins. It can be used to fetch a certain * subset of these plugins based on a given mimetype. * * Once the appropriate plugins have been fetched, an ExtractionResult * should be created and passed to the plugin's extract function. * * \author Vishesh Handa */ class KFILEMETADATA_EXPORT ExtractorCollection { public: explicit ExtractorCollection(); virtual ~ExtractorCollection(); /** * Fetch the extractors which can be used to extract * data for the respective file with the given mimetype. * * If no match is found then the best matching plugins * are returned, determined by mimetype inheritance. * * \sa QMimeType::allAncestors */ QList fetchExtractors(const QString& mimetype) const; private: class Private; Private* d; friend class ExtractorCollectionTest; QList allExtractors(); }; } #endif diff --git a/src/extractorplugin.cpp b/src/extractorplugin.cpp index 114cc25..cd009dd 100644 --- a/src/extractorplugin.cpp +++ b/src/extractorplugin.cpp @@ -1,165 +1,152 @@ /* - - 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 + SPDX-FileCopyrightText: 2012 Vishesh Handa + SPDX-FileCopyrightText: 2012 Jörg Ehrichs + + SPDX-License-Identifier: LGPL-2.1-or-later */ #include "extractorplugin.h" #include #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()); for (const QString& contactName : qAsConst(contactStrings)) { list << contactName.trimmed(); } return list; } QString ExtractorPlugin::getSupportedMimeType(const QString& mimetype) const { const QStringList allTypes = mimetypes(); if (allTypes.contains(mimetype)) { return mimetype; } QMimeDatabase db; auto type = db.mimeTypeForName(mimetype); const QStringList ancestors = type.allAncestors(); for (auto ancestor : ancestors) { if (allTypes.contains(ancestor)) { return ancestor; } } return QString(); } diff --git a/src/extractorplugin.h b/src/extractorplugin.h index 7321721..f0ad8a8 100644 --- a/src/extractorplugin.h +++ b/src/extractorplugin.h @@ -1,118 +1,105 @@ /* - - Copyright (C) 2012 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 + SPDX-FileCopyrightText: 2012 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef _KFILEMETADATA_EXTRACTOR_PLUGIN_H #define _KFILEMETADATA_EXTRACTOR_PLUGIN_H #include #include #include "kfilemetadata_export.h" #include "extractionresult.h" namespace KFileMetaData { /** * \class ExtractorPlugin extractorplugin.h * * \brief The ExtractorPlugin is the base class for all file metadata * extractors. It is responsible for extracting the metadata in a file. * * Plugins should derive from this class and implement the mimetypes * and extract method. * * All Plugins should be synchronous and blocking. * * \author Vishesh Handa */ class KFILEMETADATA_EXPORT ExtractorPlugin : public QObject { Q_OBJECT public: explicit ExtractorPlugin(QObject* parent); virtual ~ExtractorPlugin(); /** * Provide a list of mimetypes which are supported by this plugin. * Only files with those mimetypes will be provided to the plugin via * the extract function. * * This can also contains partial mimetypes like "text/", in that case * this plugin will be chosen only if a better plugin does not exist. * * \return A StringList containing the mimetypes. * \sa extract */ virtual QStringList mimetypes() const = 0; /** * The main function of the plugin that is responsible for extracting * the data and filling up the ExtractionResult * * The \p result provides the input url and mimetype which * can be used to identify the file. * * This function is synchronous and should be reentrant as it * can be called by multiple threads. */ virtual void extract(ExtractionResult* result) = 0; // // Helper functions // /** * Tries to extract a valid date time from the string provided. */ static QDateTime dateTimeFromString(const QString& dateString); /** * Tries to split the string into names. It cleans up any superfluous words * and removes extra junk such as curly braces */ static QStringList contactsFromString(const QString& string); protected: /** * Return the inherited mimetype which the extractor directly supports. * * The returned type is one of the types from \c mimetypes(), * and is one of the ancestors of the input \p mimetype * (including \p mimetype itself). * * In case the mimetype is not a subtype of the supported types, * an empty QString() is returned. * * \sa ExtractorCollection::fetchExtractors * \sa QMimeType::allAncestors * @since 5.57 */ QString getSupportedMimeType(const QString& mimetype) const; private: class Private; Private* d; }; } Q_DECLARE_INTERFACE(KFileMetaData::ExtractorPlugin, "org.kde.kf5.kfilemetadata.ExtractorPlugin") #endif // _KFILEMETADATA_EXTRACTOR_PLUGIN_H diff --git a/src/extractors/appimageextractor.cpp b/src/extractors/appimageextractor.cpp index 5b2fcae..116968c 100644 --- a/src/extractors/appimageextractor.cpp +++ b/src/extractors/appimageextractor.cpp @@ -1,301 +1,289 @@ /* - Copyright (C) 2019 Friedrich W. H. Kossebau + SPDX-FileCopyrightText: 2019 Friedrich W. H. Kossebau - 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 + SPDX-License-Identifier: LGPL-2.1-or-later */ #include "appimageextractor.h" // KF #include // Qt #include #include #include #include // libappimage #include using namespace KFileMetaData; namespace { namespace AttributeNames { QString xml_lang() { return QStringLiteral("xml:lang"); } } } // helper class to extract the interesting data from the appdata file // prefers localized strings over unlocalized, using system locale class AppDataParser { public: AppDataParser(const char* appImageFilePath, const QString& appdataFilePath); public: QString summary() const { return !m_localized.summary.isEmpty() ? m_localized.summary : m_unlocalized.summary; } QString description() const { return !m_localized.description.isEmpty() ? m_localized.description : m_unlocalized.description; } QString developerName() const { return !m_localized.developerName.isEmpty() ? m_localized.developerName : m_unlocalized.developerName; } QString projectLicense() const { return m_projectLicense; } private: void extractDescription(const QDomElement& e, const QString& localeName); private: struct Data { QString summary; QString description; QString developerName; }; Data m_localized; Data m_unlocalized; QString m_projectLicense; }; AppDataParser::AppDataParser(const char* appImageFilePath, const QString& appdataFilePath) { if (appdataFilePath.isEmpty()) { return; } unsigned long size = 0L; char* buf = nullptr; bool ok = appimage_read_file_into_buffer_following_symlinks(appImageFilePath, qUtf8Printable(appdataFilePath), &buf, &size); QScopedPointer cleanup(buf); if (!ok) { return; } QDomDocument domDocument; if (!domDocument.setContent(QByteArray::fromRawData(buf, size))) { return; } QDomElement docElem = domDocument.documentElement(); if (docElem.tagName() != QLatin1String("component")) { return; } const auto localeName = QLocale::system().bcp47Name(); QDomElement ec = docElem.firstChildElement(); while (!ec.isNull()) { const auto tagName = ec.tagName(); const auto hasLangAttribute = ec.hasAttribute(AttributeNames::xml_lang()); const auto matchingLocale = hasLangAttribute && (ec.attribute(AttributeNames::xml_lang()) == localeName); if (matchingLocale || !hasLangAttribute) { if (tagName == QLatin1String("summary")) { Data& data = hasLangAttribute ? m_localized : m_unlocalized; data.summary = ec.text(); } else if (tagName == QLatin1String("description")) { extractDescription(ec, localeName); } else if (tagName == QLatin1String("developer_name")) { Data& data = hasLangAttribute ? m_localized : m_unlocalized; data.developerName = ec.text(); } else if (tagName == QLatin1String("project_license")) { m_projectLicense = ec.text(); } } ec = ec.nextSiblingElement(); } } using DesriptionDomFilter = std::function; void stripDescriptionTextElements(QDomElement& element, const DesriptionDomFilter& stripFilter) { auto childElement = element.firstChildElement(); while (!childElement.isNull()) { auto nextChildElement = childElement.nextSiblingElement(); const auto tagName = childElement.tagName(); const bool isElementToFilter = (tagName == QLatin1String("p")) || (tagName == QLatin1String("li")); if (isElementToFilter && stripFilter(childElement)) { element.removeChild(childElement); } else { stripDescriptionTextElements(childElement, stripFilter); } childElement = nextChildElement; } } void AppDataParser::extractDescription(const QDomElement& e, const QString& localeName) { // create fake html from it and let QTextDocument transform it to plain text for us QDomDocument descriptionDocument; auto htmlElement = descriptionDocument.createElement(QStringLiteral("html")); descriptionDocument.appendChild(htmlElement); // first localized... auto clonedE = descriptionDocument.importNode(e, true).toElement(); clonedE.setTagName(QStringLiteral("body")); stripDescriptionTextElements(clonedE, [localeName](const QDomElement& e) { return !e.hasAttribute(AttributeNames::xml_lang()) || e.attribute(AttributeNames::xml_lang()) != localeName; }); htmlElement.appendChild(clonedE); QTextDocument textDocument; textDocument.setHtml(descriptionDocument.toString(-1)); m_localized.description = textDocument.toPlainText().trimmed(); if (!m_localized.description.isEmpty()) { // localized will be preferred, no need to calculate unlocalized one return; } // then unlocalized if still needed htmlElement.removeChild(clonedE); // reuse descriptionDocument clonedE = descriptionDocument.importNode(e, true).toElement(); clonedE.setTagName(QStringLiteral("body")); stripDescriptionTextElements(clonedE, [](const QDomElement& e) { return e.hasAttribute(AttributeNames::xml_lang()); }); htmlElement.appendChild(clonedE); textDocument.setHtml(descriptionDocument.toString(-1)); m_unlocalized.description = textDocument.toPlainText().trimmed(); } // helper class to extract the interesting data from the desktop file class DesktopFileParser { public: DesktopFileParser(const char* appImageFilePath, const QString& desktopFilePath); public: QString name; QString comment; }; DesktopFileParser::DesktopFileParser(const char* appImageFilePath, const QString& desktopFilePath) { if (desktopFilePath.isEmpty()) { return; } unsigned long size = 0L; char* buf = nullptr; bool ok = appimage_read_file_into_buffer_following_symlinks(appImageFilePath, qUtf8Printable(desktopFilePath), &buf, &size); QScopedPointer cleanup(buf); if (!ok) { return; } // create real file, KDesktopFile needs that QTemporaryFile tmpDesktopFile; tmpDesktopFile.open(); tmpDesktopFile.write(buf, size); tmpDesktopFile.close(); KDesktopFile desktopFile(tmpDesktopFile.fileName()); name = desktopFile.readName(); comment = desktopFile.readComment(); } AppImageExtractor::AppImageExtractor(QObject* parent) : ExtractorPlugin(parent) { } QStringList AppImageExtractor::mimetypes() const { return QStringList{ QStringLiteral("application/x-iso9660-appimage"), QStringLiteral("application/vnd.appimage"), }; } void KFileMetaData::AppImageExtractor::extract(ExtractionResult* result) { const auto appImageFilePath = result->inputUrl().toUtf8(); const auto appImageType = appimage_get_type(appImageFilePath.constData(), false); // not a valid appimage file? if (appImageType <= 0) { return; } // find desktop file and appdata file // need to scan ourselves, given there are no fixed names in the spec yet defined // and we just can try as the other appimage tools to simply use the first file of the type found char** filePaths = appimage_list_files(appImageFilePath.constData()); if (!filePaths) { return; } QString desktopFilePath; QString appdataFilePath; for (int i = 0; filePaths[i] != nullptr; ++i) { const auto filePath = QString::fromUtf8(filePaths[i]); if (filePath.startsWith(QLatin1String("usr/share/metainfo/")) && filePath.endsWith(QLatin1String(".appdata.xml"))) { appdataFilePath = filePath; if (!desktopFilePath.isEmpty()) { break; } } if (filePath.endsWith(QLatin1String(".desktop")) && !filePath.contains(QLatin1Char('/'))) { desktopFilePath = filePath; if (!appdataFilePath.isEmpty()) { break; } } } appimage_string_list_free(filePaths); // extract data from both files... const AppDataParser appData(appImageFilePath.constData(), appdataFilePath); const DesktopFileParser desktopFileData(appImageFilePath.constData(), desktopFilePath); // ... and insert into the result result->add(Property::Title, desktopFileData.name); if (!desktopFileData.comment.isEmpty()) { result->add(Property::Comment, desktopFileData.comment); } else if (!appData.summary().isEmpty()) { result->add(Property::Comment, appData.summary()); } if (!appData.description().isEmpty()) { result->add(Property::Description, appData.description()); } if (!appData.projectLicense().isEmpty()) { result->add(Property::License, appData.projectLicense()); } if (!appData.developerName().isEmpty()) { result->add(Property::Author, appData.developerName()); } } diff --git a/src/extractors/appimageextractor.h b/src/extractors/appimageextractor.h index f5ebbc0..67263dd 100644 --- a/src/extractors/appimageextractor.h +++ b/src/extractors/appimageextractor.h @@ -1,44 +1,32 @@ /* - Copyright (C) 2019 Friedrich W. H. Kossebau + SPDX-FileCopyrightText: 2019 Friedrich W. H. Kossebau - 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 + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef APPIMAGEEXTRACTOR_H #define APPIMAGEEXTRACTOR_H #include "extractorplugin.h" namespace KFileMetaData { class AppImageExtractor : public ExtractorPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.ExtractorPlugin" FILE "appimageextractor.json") Q_INTERFACES(KFileMetaData::ExtractorPlugin) public: explicit AppImageExtractor(QObject* parent = nullptr); public: void extract(ExtractionResult* result) override; QStringList mimetypes() const override; }; } #endif diff --git a/src/extractors/dublincoreextractor.cpp b/src/extractors/dublincoreextractor.cpp index f6b5720..1a284cb 100644 --- a/src/extractors/dublincoreextractor.cpp +++ b/src/extractors/dublincoreextractor.cpp @@ -1,63 +1,51 @@ /* Helper class to extract XML encoded Dublin Core metadata - Copyright (C) 2018 Stefan Brüns + SPDX-FileCopyrightText: 2018 Stefan Brüns - 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 + SPDX-License-Identifier: LGPL-2.1-or-later */ #include "dublincoreextractor.h" #include "extractionresult.h" namespace { inline QString dcNS() { return QStringLiteral("http://purl.org/dc/elements/1.1/"); } inline QString dctermsNS() { return QStringLiteral("http://purl.org/dc/terms/"); } } namespace KFileMetaData { void DublinCoreExtractor::extract(ExtractionResult* result, const QDomNode& fragment) { QDomElement e = fragment.firstChildElement(); while (!e.isNull()) { const QString namespaceURI = e.namespaceURI(); const QString localName = e.localName(); // Dublin Core // According to http://dublincore.org/documents/dces/, the // properties should be treated the same regardless if // used in the legacy DCES or DCMI-TERMS variant if (namespaceURI == dcNS() || namespaceURI == dctermsNS()) { if (localName == QLatin1String("description")) { result->add(Property::Description, e.text()); } else if (localName == QLatin1String("subject")) { result->add(Property::Subject, e.text()); } else if (localName == QLatin1String("title")) { result->add(Property::Title, e.text()); } else if (localName == QLatin1String("creator")) { result->add(Property::Author, e.text()); } else if (localName == QLatin1String("language")) { result->add(Property::Language, e.text()); } } e = e.nextSiblingElement(); } } } // namespace KFileMetaData diff --git a/src/extractors/dublincoreextractor.h b/src/extractors/dublincoreextractor.h index 1b6257d..424afad 100644 --- a/src/extractors/dublincoreextractor.h +++ b/src/extractors/dublincoreextractor.h @@ -1,51 +1,39 @@ /* Helper class to extract XML encoded Dublin Core metadata - Copyright (C) 2018 Stefan Brüns + SPDX-FileCopyrightText: 2018 Stefan Brüns - 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 + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef DUBLINCORE_EXTRACTOR_H #define DUBLINCORE_EXTRACTOR_H #include namespace KFileMetaData { class ExtractionResult; class DublinCoreExtractor { public: /** * Extract DC metadata from an XML fragment * * Prerequsites: * - DC element nodes are immediate children to \p fragment * - The \c QDomDocument has been parsed with enabled namespaceProcessing * * \sa QDomDocument::setContent */ static void extract(ExtractionResult* result, const QDomNode& fragment); }; } // namespace KFileMetaData #endif // DUBLINCORE_EXTRACTOR_H diff --git a/src/extractors/epubextractor.cpp b/src/extractors/epubextractor.cpp index 01abedb..85b0f8c 100644 --- a/src/extractors/epubextractor.cpp +++ b/src/extractors/epubextractor.cpp @@ -1,195 +1,183 @@ /* - Copyright (C) 2013 Vishesh Handa - Copyright (C) 2016 Christoph Cullmann - - 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 + SPDX-FileCopyrightText: 2013 Vishesh Handa + SPDX-FileCopyrightText: 2016 Christoph Cullmann + + SPDX-License-Identifier: LGPL-2.1-or-later */ #include "epubextractor.h" #include #include #include #include using namespace KFileMetaData; EPubExtractor::EPubExtractor(QObject* parent) : ExtractorPlugin(parent) { } namespace { static const QStringList supportedMimeTypes = { QStringLiteral("application/epub+zip"), }; QString fetchMetadata(struct epub* e, const epub_metadata& type) { int size = 0; unsigned char** data = epub_get_metadata(e, type, &size); if (data) { QStringList strList; for (int i = 0; i < size; i++) { // skip nullptr entries, can happen for broken xml files if (!data[i]) continue; strList << QString::fromUtf8((char*)data[i]); free(data[i]); } free(data); return strList.join(QLatin1String(", ")); } return QString(); } } QStringList EPubExtractor::mimetypes() const { return supportedMimeTypes; } void EPubExtractor::extract(ExtractionResult* result) { // open epub, return on exit, file will be closed again at end of function auto ePubDoc = epub_open(result->inputUrl().toUtf8().constData(), 1); if (!ePubDoc) { qWarning() << "Invalid document"; return; } result->addType(Type::Document); if (result->inputFlags() & ExtractionResult::ExtractMetaData) { QString value = fetchMetadata(ePubDoc, EPUB_TITLE); if (!value.isEmpty()) { result->add(Property::Title, value); } value = fetchMetadata(ePubDoc, EPUB_SUBJECT); if (!value.isEmpty()) { result->add(Property::Subject, value); } value = fetchMetadata(ePubDoc, EPUB_CREATOR); if (!value.isEmpty()) { if (value.startsWith(QLatin1String("aut:"), Qt::CaseInsensitive)) { value = value.mid(4).simplified(); } else if (value.startsWith(QLatin1String("author:"), Qt::CaseInsensitive)) { value = value.mid(7).simplified(); } // A lot of authors have their name written in () again. We discard that part int index = value.indexOf(QLatin1Char('(')); if (index) value = value.mid(0, index); result->add(Property::Author, value); } // The Contributor just seems to be mostly Calibre aka the Generator /* value = fetchMetadata(ePubDoc, EPUB_CONTRIB); if( !value.isEmpty() ) { SimpleResource con; con.addType( NCO::Contact() ); con.addProperty( NCO::fullname(), value ); fileRes.addProperty( NCO::contributor(), con ); graph << con; }*/ value = fetchMetadata(ePubDoc, EPUB_PUBLISHER); if (!value.isEmpty()) { result->add(Property::Publisher, value); } value = fetchMetadata(ePubDoc, EPUB_DESCRIPTION); if (!value.isEmpty()) { result->add(Property::Description, value); } value = fetchMetadata(ePubDoc, EPUB_DATE); if (!value.isEmpty()) { if (value.startsWith(QLatin1String("Unspecified:"), Qt::CaseInsensitive)) { value = value.mid(QByteArray("Unspecified:").size()).simplified(); } int ind = value.indexOf(QLatin1String("publication:"), Qt::CaseInsensitive); if (ind != -1) { value = value.mid(ind + QByteArray("publication:").size()).simplified(); } QDateTime dt = ExtractorPlugin::dateTimeFromString(value); if (!dt.isNull()) { result->add(Property::CreationDate, dt); result->add(Property::ReleaseYear, dt.date().year()); } } } // // Plain Text // if (result->inputFlags() & ExtractionResult::ExtractPlainText) { if (auto iter = epub_get_iterator(ePubDoc, EITERATOR_SPINE, 0)) { do { char* curr = epub_it_get_curr(iter); if (!curr) continue; QString html = QString::fromUtf8(curr); html.remove(QRegularExpression(QStringLiteral("<[^>]*>"))); result->append(html); } while (epub_it_get_next(iter)); epub_free_iterator(iter); } auto tit = epub_get_titerator(ePubDoc, TITERATOR_NAVMAP, 0); if (!tit) { tit = epub_get_titerator(ePubDoc, TITERATOR_GUIDE, 0); } if (tit) { if (epub_tit_curr_valid(tit)) { do { // get link, iterator handles freeing of it char* clink = epub_tit_get_curr_link(tit); // epub_get_data returns -1 on failure char* data = nullptr; const int size = epub_get_data(ePubDoc, clink, &data); if (size >= 0 && data) { QString html = QString::fromUtf8(data, size); // strip html tags html.remove(QRegularExpression(QStringLiteral("<[^>]*>"))); result->append(html); free(data); } } while (epub_tit_next(tit)); } epub_free_titerator(tit); } } // close epub file again epub_close(ePubDoc); } diff --git a/src/extractors/epubextractor.h b/src/extractors/epubextractor.h index 7dd8566..6f1a9f3 100644 --- a/src/extractors/epubextractor.h +++ b/src/extractors/epubextractor.h @@ -1,43 +1,31 @@ /* - Copyright (C) 2013 Vishesh Handa + SPDX-FileCopyrightText: 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 + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef EPUBEXTRACTOR_H #define EPUBEXTRACTOR_H #include "extractorplugin.h" namespace KFileMetaData { class EPubExtractor : public ExtractorPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.ExtractorPlugin" FILE "epubextractor.json") Q_INTERFACES(KFileMetaData::ExtractorPlugin) public: explicit EPubExtractor(QObject* parent = nullptr); void extract(ExtractionResult* result) override; QStringList mimetypes() const override; }; } #endif // EPUBEXTRACTOR_H diff --git a/src/extractors/exiv2extractor.cpp b/src/extractors/exiv2extractor.cpp index 482838d..2eecf14 100644 --- a/src/extractors/exiv2extractor.cpp +++ b/src/extractors/exiv2extractor.cpp @@ -1,331 +1,318 @@ /* - - Copyright (C) 2012 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 + SPDX-FileCopyrightText: 2012 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later */ #include "exiv2extractor.h" #include using namespace KFileMetaData; Exiv2Extractor::Exiv2Extractor(QObject* parent) : ExtractorPlugin(parent) { } namespace { static const QStringList supportedMimeTypes = { QStringLiteral("image/bmp"), QStringLiteral("image/gif"), QStringLiteral("image/jp2"), QStringLiteral("image/jpeg"), QStringLiteral("image/pgf"), QStringLiteral("image/png"), QStringLiteral("image/tiff"), #ifdef HAVE_WEBP_SUPPORT QStringLiteral("image/webp"), #endif QStringLiteral("image/x-exv"), QStringLiteral("image/x-canon-cr2"), QStringLiteral("image/x-canon-crw"), QStringLiteral("image/x-fuji-raf"), QStringLiteral("image/x-minolta-mrw"), QStringLiteral("image/x-nikon-nef"), QStringLiteral("image/x-olympus-orf"), QStringLiteral("image/x-panasonic-rw2"), QStringLiteral("image/x-pentax-pef"), QStringLiteral("image/x-photoshop"), QStringLiteral("image/x-samsung-srw"), QStringLiteral("image/x-tga"), }; QString toString(const Exiv2::Value& value) { const std::string str = value.toString(); return QString::fromUtf8(str.c_str(), str.length()); } QVariant toVariantDateTime(const Exiv2::Value& value) { if (value.typeId() == Exiv2::asciiString) { QDateTime val = ExtractorPlugin::dateTimeFromString(QString::fromLatin1(value.toString().c_str())); if (val.isValid()) { // Datetime is stored in exif as local time. val.setOffsetFromUtc(0); return QVariant(val); } } return QVariant(); } QVariant toVariantLong(const Exiv2::Value& value) { if (value.typeId() == Exiv2::unsignedLong || value.typeId() == Exiv2::signedLong) { qlonglong val = value.toLong(); return QVariant(val); } QString str(toString(value)); bool ok = false; int val = str.toInt(&ok); if (ok) return QVariant(val); return QVariant(); } QVariant toVariantDouble(const Exiv2::Value& value) { if (value.typeId() == Exiv2::tiffFloat || value.typeId() == Exiv2::tiffDouble || value.typeId() == Exiv2::unsignedRational || value.typeId() == Exiv2::signedRational) { return QVariant(static_cast(value.toFloat())); } QString str(toString(value)); bool ok = false; double val = str.toDouble(&ok); if (ok) return QVariant(val); return QVariant(); } QVariant toVariantString(const Exiv2::Value& value) { QString str = toString(value); if (!str.isEmpty()) return QVariant(str); return QVariant(); } QVariant toVariant(const Exiv2::Value& value, QVariant::Type type) { if (value.count() == 0) { return QVariant(); } switch (type) { case QVariant::Int: return toVariantLong(value); case QVariant::DateTime: return toVariantDateTime(value); case QVariant::Double: return toVariantDouble(value); case QVariant::String: default: return toVariantString(value); } } } QStringList Exiv2Extractor::mimetypes() const { return supportedMimeTypes; } void Exiv2Extractor::extract(ExtractionResult* result) { QByteArray arr = result->inputUrl().toUtf8(); std::string fileString(arr.data(), arr.length()); #if EXIV2_TEST_VERSION(0, 28, 0) Exiv2::Image::UniquePtr image; #else Exiv2::Image::AutoPtr image; #endif try { image = Exiv2::ImageFactory::open(fileString); } catch (const std::exception&) { return; } if (!image.get()) { return; } try { image->readMetadata(); } catch (const std::exception&) { return; } result->addType(Type::Image); if (!(result->inputFlags() & ExtractionResult::ExtractMetaData)) { return; } if (image->pixelHeight()) { result->add(Property::Height, image->pixelHeight()); } if (image->pixelWidth()) { result->add(Property::Width, image->pixelWidth()); } std::string comment = image->comment(); if (!comment.empty()) { result->add(Property::Comment, QString::fromUtf8(comment.c_str(), comment.length())); } const Exiv2::ExifData& data = image->exifData(); add(result, data, Property::Manufacturer, "Exif.Image.Make", QVariant::String); add(result, data, Property::Model, "Exif.Image.Model", QVariant::String); add(result, data, Property::Description, "Exif.Image.ImageDescription", QVariant::String); add(result, data, Property::Artist, "Exif.Image.Artist", QVariant::String); add(result, data, Property::Copyright, "Exif.Image.Copyright", QVariant::String); add(result, data, Property::Generator, "Exif.Image.Software", QVariant::String); add(result, data, Property::ImageDateTime, "Exif.Image.DateTime", QVariant::DateTime); add(result, data, Property::ImageOrientation, "Exif.Image.Orientation", QVariant::Int); add(result, data, Property::PhotoFlash, "Exif.Photo.Flash", QVariant::Int); add(result, data, Property::PhotoPixelXDimension, "Exif.Photo.PixelXDimension", QVariant::Int); add(result, data, Property::PhotoPixelYDimension, "Exif.Photo.PixelYDimension", QVariant::Int); add(result, data, Property::PhotoDateTimeOriginal, "Exif.Photo.DateTimeOriginal", QVariant::DateTime); add(result, data, Property::PhotoFocalLength, "Exif.Photo.FocalLength", QVariant::Double); add(result, data, Property::PhotoFocalLengthIn35mmFilm, "Exif.Photo.FocalLengthIn35mmFilm", QVariant::Double); add(result, data, Property::PhotoExposureTime, "Exif.Photo.ExposureTime", QVariant::Double); add(result, data, Property::PhotoExposureBiasValue, "Exif.Photo.ExposureBiasValue", QVariant::Double); add(result, data, Property::PhotoFNumber, "Exif.Photo.FNumber", QVariant::Double); add(result, data, Property::PhotoApertureValue, "Exif.Photo.ApertureValue", QVariant::Double); add(result, data, Property::PhotoWhiteBalance, "Exif.Photo.WhiteBalance", QVariant::Int); add(result, data, Property::PhotoMeteringMode, "Exif.Photo.MeteringMode", QVariant::Int); add(result, data, Property::PhotoISOSpeedRatings, "Exif.Photo.ISOSpeedRatings", QVariant::Int); add(result, data, Property::PhotoSaturation, "Exif.Photo.Saturation", QVariant::Int); add(result, data, Property::PhotoSharpness, "Exif.Photo.Sharpness", QVariant::Int); double latitude = fetchGpsDouble(data, "Exif.GPSInfo.GPSLatitude"); double longitude = fetchGpsDouble(data, "Exif.GPSInfo.GPSLongitude"); double altitude = fetchGpsAltitude(data); QByteArray latRef = fetchByteArray(data, "Exif.GPSInfo.GPSLatitudeRef"); if (!latRef.isEmpty() && latRef[0] == 'S') latitude *= -1; QByteArray longRef = fetchByteArray(data, "Exif.GPSInfo.GPSLongitudeRef"); if (!longRef.isEmpty() && longRef[0] == 'W') longitude *= -1; if (!std::isnan(latitude)) { result->add(Property::PhotoGpsLatitude, latitude); } if (!std::isnan(longitude)) { result->add(Property::PhotoGpsLongitude, longitude); } if (!std::isnan(altitude)) { result->add(Property::PhotoGpsAltitude, altitude); } } void Exiv2Extractor::add(ExtractionResult* result, const Exiv2::ExifData& data, Property::Property prop, const char* name, QVariant::Type type) { Exiv2::ExifData::const_iterator it = data.findKey(Exiv2::ExifKey(name)); if (it != data.end()) { QVariant value = toVariant(it->value(), type); if (!value.isNull()) result->add(prop, value); } } double Exiv2Extractor::fetchGpsDouble(const Exiv2::ExifData& data, const char* name) { Exiv2::ExifData::const_iterator it = data.findKey(Exiv2::ExifKey(name)); if (it != data.end() && it->count() == 3) { double n = 0.0; double d = 0.0; n = (*it).toRational(0).first; d = (*it).toRational(0).second; if (d == 0.0) { return std::numeric_limits::quiet_NaN(); } double deg = n / d; n = (*it).toRational(1).first; d = (*it).toRational(1).second; if (d == 0.0) { return deg; } double min = n / d; if (min != -1.0) { deg += min / 60.0; } n = (*it).toRational(2).first; d = (*it).toRational(2).second; if (d == 0.0) { return deg; } double sec = n / d; if (sec != -1.0) { deg += sec / 3600.0; } return deg; } return std::numeric_limits::quiet_NaN(); } double Exiv2Extractor::fetchGpsAltitude(const Exiv2::ExifData& data) { double alt = std::numeric_limits::quiet_NaN(); Exiv2::ExifData::const_iterator it = data.findKey(Exiv2::ExifKey("Exif.GPSInfo.GPSAltitude")); if (it != data.end() && it->count() > 0 && (it->value().typeId() == Exiv2::unsignedRational || it->value().typeId() == Exiv2::signedRational)) { auto ratio = it->value().toRational(); if (ratio.second == 0) { return alt; } it = data.findKey(Exiv2::ExifKey("Exif.GPSInfo.GPSAltitudeRef")); if (it != data.end() && it->count() > 0 && (it->value().typeId() == Exiv2::unsignedByte || it->value().typeId() == Exiv2::signedByte)) { auto altRef = it->value().toLong(); if (altRef) { alt = -1.0 * ratio.first / ratio.second; } else { alt = 1.0 * ratio.first / ratio.second; } } } return alt; } QByteArray Exiv2Extractor::fetchByteArray(const Exiv2::ExifData& data, const char* name) { Exiv2::ExifData::const_iterator it = data.findKey(Exiv2::ExifKey(name)); if (it != data.end() && it->count() > 0) { std::string str = it->value().toString(); return QByteArray(str.c_str(), str.size()); } return QByteArray(); } diff --git a/src/extractors/exiv2extractor.h b/src/extractors/exiv2extractor.h index c8b7ae5..6fcdfa2 100644 --- a/src/extractors/exiv2extractor.h +++ b/src/extractors/exiv2extractor.h @@ -1,54 +1,41 @@ /* - - Copyright (C) 2012 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 + SPDX-FileCopyrightText: 2012 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef EXIV2EXTRACTOR_H #define EXIV2EXTRACTOR_H #include "extractorplugin.h" #include namespace KFileMetaData { class Exiv2Extractor : public ExtractorPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.ExtractorPlugin" FILE "exiv2extractor.json") Q_INTERFACES(KFileMetaData::ExtractorPlugin) public: explicit Exiv2Extractor(QObject* parent = nullptr); void extract(ExtractionResult* result) override; QStringList mimetypes() const override; private: void add(ExtractionResult* result, const Exiv2::ExifData& data, Property::Property prop, const char* name, QVariant::Type type); double fetchGpsDouble(const Exiv2::ExifData& data, const char* name); double fetchGpsAltitude(const Exiv2::ExifData& data); QByteArray fetchByteArray(const Exiv2::ExifData& data, const char* name); }; } #endif // EXIV2EXTRACTOR_H diff --git a/src/extractors/ffmpegextractor.cpp b/src/extractors/ffmpegextractor.cpp index 57a39a8..3edc21a 100644 --- a/src/extractors/ffmpegextractor.cpp +++ b/src/extractors/ffmpegextractor.cpp @@ -1,184 +1,172 @@ /* - Copyright (C) 2012-2014 Vishesh Handa + SPDX-FileCopyrightText: 2012-2014 Vishesh Handa Code adapted from Strigi FFmpeg Analyzer - - Copyright (C) 2010 Evgeny Egorochkin - Copyright (C) 2011 Tirtha Chatterjee - - 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 + SPDX-FileCopyrightText: 2010 Evgeny Egorochkin + SPDX-FileCopyrightText: 2011 Tirtha Chatterjee + + SPDX-License-Identifier: LGPL-2.1-or-later */ #include "ffmpegextractor.h" #include "config-kfilemetadata.h" #ifdef __cplusplus #define __STDC_CONSTANT_MACROS #ifdef _STDINT_H #undef _STDINT_H #endif # include #endif extern "C" { #include #include #include } #include using namespace KFileMetaData; FFmpegExtractor::FFmpegExtractor(QObject* parent) : ExtractorPlugin(parent) { } const QStringList supportedMimeTypes = { QStringLiteral("video/mp4"), QStringLiteral("video/mpeg"), QStringLiteral("video/quicktime"), QStringLiteral("video/webm"), QStringLiteral("video/ogg"), QStringLiteral("video/mp2t"), QStringLiteral("video/x-flv"), QStringLiteral("video/x-matroska"), QStringLiteral("video/x-ms-wmv"), QStringLiteral("video/x-ms-asf"), QStringLiteral("video/x-msvideo"), }; QStringList FFmpegExtractor::mimetypes() const { return supportedMimeTypes; } void FFmpegExtractor::extract(ExtractionResult* result) { AVFormatContext* fmt_ctx = nullptr; av_register_all(); QByteArray arr = result->inputUrl().toUtf8(); fmt_ctx = avformat_alloc_context(); if (int ret = avformat_open_input(&fmt_ctx, arr.data(), nullptr, nullptr)) { qWarning() << "avformat_open_input error: " << ret; return; } int ret = avformat_find_stream_info(fmt_ctx, nullptr); if (ret < 0) { qWarning() << "avform_find_stream_info error: " << ret; return; } result->addType(Type::Video); if (result->inputFlags() & ExtractionResult::ExtractMetaData) { int totalSecs = fmt_ctx->duration / AV_TIME_BASE; int bitrate = fmt_ctx->bit_rate; result->add(Property::Duration, totalSecs); result->add(Property::BitRate, bitrate); for (uint i = 0; i < fmt_ctx->nb_streams; i++) { AVStream* stream = fmt_ctx->streams[i]; #if defined HAVE_AVSTREAM_CODECPAR && HAVE_AVSTREAM_CODECPAR const AVCodecParameters* codec = stream->codecpar; #else const AVCodecContext* codec = stream->codec; #endif if (codec->codec_type == AVMEDIA_TYPE_VIDEO) { result->add(Property::Width, codec->width); result->add(Property::Height, codec->height); AVRational avSampleAspectRatio = av_guess_sample_aspect_ratio(fmt_ctx, stream, nullptr); AVRational avDisplayAspectRatio; av_reduce(&avDisplayAspectRatio.num, &avDisplayAspectRatio.den, codec->width * avSampleAspectRatio.num, codec->height * avSampleAspectRatio.den, 1024*1024); double displayAspectRatio = avDisplayAspectRatio.num; if (avDisplayAspectRatio.den) displayAspectRatio /= avDisplayAspectRatio.den; if (displayAspectRatio) result->add(Property::AspectRatio, displayAspectRatio); AVRational avFrameRate = av_guess_frame_rate(fmt_ctx, stream, nullptr); double frameRate = avFrameRate.num; if (avFrameRate.den) frameRate /= avFrameRate.den; if (frameRate) result->add(Property::FrameRate, frameRate); } } AVDictionary* dict = fmt_ctx->metadata; AVDictionaryEntry* entry; entry = av_dict_get(dict, "title", nullptr, 0); if (entry) { result->add(Property::Title, QString::fromUtf8(entry->value)); } entry = av_dict_get(dict, "author", nullptr, 0); if (entry) { result->add(Property::Author, QString::fromUtf8(entry->value)); } entry = av_dict_get(dict, "copyright", nullptr, 0); if (entry) { result->add(Property::Copyright, QString::fromUtf8(entry->value)); } entry = av_dict_get(dict, "comment", nullptr, 0); if (entry) { result->add(Property::Comment, QString::fromUtf8(entry->value)); } entry = av_dict_get(dict, "album", nullptr, 0); if (entry) { result->add(Property::Album, QString::fromUtf8(entry->value)); } entry = av_dict_get(dict, "genre", nullptr, 0); if (entry) { result->add(Property::Genre, QString::fromUtf8(entry->value)); } entry = av_dict_get(dict, "track", nullptr, 0); if (entry) { QString value = QString::fromUtf8(entry->value); bool ok = false; int track = value.toInt(&ok); if (ok && track) result->add(Property::TrackNumber, track); } entry = av_dict_get(dict, "year", nullptr, 0); if (entry) { int year = QString::fromUtf8(entry->value).toInt(); result->add(Property::ReleaseYear, year); } } avformat_close_input(&fmt_ctx); } diff --git a/src/extractors/ffmpegextractor.h b/src/extractors/ffmpegextractor.h index fc2b449..5c26f99 100644 --- a/src/extractors/ffmpegextractor.h +++ b/src/extractors/ffmpegextractor.h @@ -1,45 +1,33 @@ /* - Copyright (C) 2012 Vishesh Handa + SPDX-FileCopyrightText: 2012 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 + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef FFMPEGEXTRACTOR_H #define FFMPEGEXTRACTOR_H #include "extractorplugin.h" namespace KFileMetaData { class FFmpegExtractor : public ExtractorPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.ExtractorPlugin" FILE "ffmpegextractor.json") Q_INTERFACES(KFileMetaData::ExtractorPlugin) public: explicit FFmpegExtractor(QObject* parent = nullptr); void extract(ExtractionResult* result) override; QStringList mimetypes() const override; friend class ffmpegExtractorTest; }; } #endif // FFMPEGEXTRACTOR_H diff --git a/src/extractors/mobiextractor.cpp b/src/extractors/mobiextractor.cpp index 7608aa3..9fd6148 100644 --- a/src/extractors/mobiextractor.cpp +++ b/src/extractors/mobiextractor.cpp @@ -1,110 +1,98 @@ /* - Copyright (C) 2013 Vishesh Handa + SPDX-FileCopyrightText: 2013 Vishesh Handa Code adapted from kdegraphics-mobipocket/strigi/ - Copyright (C) 2008 by Jakub Stachowski + SPDX-FileCopyrightText: 2008 Jakub Stachowski - 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 + SPDX-License-Identifier: LGPL-2.1-or-later */ #include "mobiextractor.h" #include #include using namespace KFileMetaData; class QFileStream : public Mobipocket::Stream { public: QFileStream(const QString& name) : d(name) { d.open(QIODevice::ReadOnly); } int read(char* buf, int size) override { return d.read(buf, size); } bool seek(int pos) override { return d.seek(pos); } private: QFile d; }; MobiExtractor::MobiExtractor(QObject* parent) : ExtractorPlugin(parent) { } static const QStringList supportedMimeTypes = { QStringLiteral("application/x-mobipocket-ebook"), }; QStringList MobiExtractor::mimetypes() const { return supportedMimeTypes; } void MobiExtractor::extract(ExtractionResult* result) { QFileStream stream(result->inputUrl()); Mobipocket::Document doc(&stream); if (!doc.isValid()) return; result->addType(Type::Document); QMapIterator it(doc.metadata()); while (it.hasNext()) { it.next(); switch (it.key()) { case Mobipocket::Document::Title: result->add(Property::Title, it.value()); break; case Mobipocket::Document::Author: { result->add(Property::Author, it.value()); break; } case Mobipocket::Document::Description: { QTextDocument document; document.setHtml(it.value()); QString plain = document.toPlainText(); if (!plain.isEmpty()) result->add(Property::Description, it.value()); break; } case Mobipocket::Document::Subject: result->add(Property::Subject, it.value()); break; case Mobipocket::Document::Copyright: result->add(Property::Copyright, it.value()); break; } } if (!doc.hasDRM()) { QString html = doc.text(); QTextDocument document; document.setHtml(html); result->append(document.toPlainText()); } } diff --git a/src/extractors/mobiextractor.h b/src/extractors/mobiextractor.h index 9930d40..7336bbc 100644 --- a/src/extractors/mobiextractor.h +++ b/src/extractors/mobiextractor.h @@ -1,44 +1,31 @@ /* - - 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 + SPDX-FileCopyrightText: 2013 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef MOBIEXTRACTOR_H #define MOBIEXTRACTOR_H #include "extractorplugin.h" namespace KFileMetaData { class MobiExtractor : public ExtractorPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.ExtractorPlugin" FILE "mobiextractor.json") Q_INTERFACES(KFileMetaData::ExtractorPlugin) public: explicit MobiExtractor(QObject* parent = nullptr); void extract(ExtractionResult* result) override; QStringList mimetypes() const override; }; } #endif // MOBIEXTRACTOR_H diff --git a/src/extractors/odfextractor.cpp b/src/extractors/odfextractor.cpp index ce127a9..bb94dc1 100644 --- a/src/extractors/odfextractor.cpp +++ b/src/extractors/odfextractor.cpp @@ -1,179 +1,166 @@ /* - - Copyright (C) 2013 Vishesh Handa - Copyright (C) 2012 Jörg Ehrichs - Copyright (C) 2016 Christoph Cullmann - - 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 + SPDX-FileCopyrightText: 2013 Vishesh Handa + SPDX-FileCopyrightText: 2012 Jörg Ehrichs + SPDX-FileCopyrightText: 2016 Christoph Cullmann + + SPDX-License-Identifier: LGPL-2.1-or-later */ #include "odfextractor.h" #include #include #include #include namespace { inline QString dcNS() { return QStringLiteral("http://purl.org/dc/elements/1.1/"); } inline QString metaNS() { return QStringLiteral("urn:oasis:names:tc:opendocument:xmlns:meta:1.0"); } inline QString officeNS() { return QStringLiteral("urn:oasis:names:tc:opendocument:xmlns:office:1.0"); } QDomElement firstChildElementNS(const QDomNode &node, const QString &nsURI, const QString &localName) { for (auto e = node.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { if (e.localName() == localName && e.namespaceURI() == nsURI) { return e; } } return QDomElement(); } const QStringList supportedMimeTypes = { QStringLiteral("application/vnd.oasis.opendocument.text"), QStringLiteral("application/vnd.oasis.opendocument.presentation"), QStringLiteral("application/vnd.oasis.opendocument.spreadsheet"), }; } using namespace KFileMetaData; OdfExtractor::OdfExtractor(QObject* parent) : ExtractorPlugin(parent) { } QStringList OdfExtractor::mimetypes() const { return supportedMimeTypes; } void OdfExtractor::extract(ExtractionResult* result) { KZip zip(result->inputUrl()); if (!zip.open(QIODevice::ReadOnly)) { qWarning() << "Document is not a valid ZIP archive"; return; } const KArchiveDirectory* directory = zip.directory(); if (!directory) { qWarning() << "Invalid document structure (main directory is missing)"; return; } // we need a meta xml file in the archive! const auto metaXml = directory->entry(QStringLiteral("meta.xml")); if (!metaXml || !metaXml->isFile()) { qWarning() << "Invalid document structure (meta.xml is missing)"; return; } if (result->inputFlags() & ExtractionResult::ExtractMetaData) { QDomDocument metaData(QStringLiteral("metaData")); metaData.setContent(static_cast(metaXml)->data(), true); // parse metadata ... QDomElement meta = firstChildElementNS(firstChildElementNS(metaData, officeNS(), QStringLiteral("document-meta")), officeNS(), QStringLiteral("meta")); QDomNode n = meta.firstChild(); while (!n.isNull()) { QDomElement e = n.toElement(); if (!e.isNull()) { const QString namespaceURI = e.namespaceURI(); const QString localName = e.localName(); // Dublin Core if (namespaceURI == dcNS()) { if (localName == QLatin1String("description")) { result->add(Property::Description, e.text()); } else if (localName == QLatin1String("subject")) { result->add(Property::Subject, e.text()); } else if (localName == QLatin1String("title")) { result->add(Property::Title, e.text()); } else if (localName == QLatin1String("creator")) { result->add(Property::Author, e.text()); } else if (localName == QLatin1String("language")) { result->add(Property::Language, e.text()); } } // Meta Properties else if (namespaceURI == metaNS()) { if (localName == QLatin1String("document-statistic")) { bool ok = false; int pageCount = e.attributeNS(metaNS(), QStringLiteral("page-count")).toInt(&ok); if (ok) { result->add(Property::PageCount, pageCount); } int wordCount = e.attributeNS(metaNS(), QStringLiteral("word-count")).toInt(&ok); if (ok) { result->add(Property::WordCount, wordCount); } } else if (localName == QLatin1String("keyword")) { QString keywords = e.text(); result->add(Property::Keywords, keywords); } else if (localName == QLatin1String("generator")) { result->add(Property::Generator, e.text()); } else if (localName == QLatin1String("creation-date")) { QDateTime dt = ExtractorPlugin::dateTimeFromString(e.text()); if (!dt.isNull()) result->add(Property::CreationDate, dt); } } } n = n.nextSibling(); } } result->addType(Type::Document); if (result->inputMimetype() == QLatin1String("application/vnd.oasis.opendocument.presentation")) { result->addType(Type::Presentation); } else if (result->inputMimetype() == QLatin1String("application/vnd.oasis.opendocument.spreadsheet")) { result->addType(Type::Spreadsheet); } if (!(result->inputFlags() & ExtractionResult::ExtractPlainText)) { return; } // for content indexing, we need content xml file const auto contentXml = directory->entry(QStringLiteral("content.xml")); if (!contentXml || !contentXml->isFile()) { qWarning() << "Invalid document structure (content.xml is missing)"; return; } QXmlStreamReader xml(static_cast(contentXml)->createDevice()); while (!xml.atEnd()) { xml.readNext(); if (xml.isCharacters()) { QString str = xml.text().toString(); result->append(str); } if (xml.hasError() || xml.isEndDocument()) break; } } diff --git a/src/extractors/odfextractor.h b/src/extractors/odfextractor.h index 500a88f..c09e7c7 100644 --- a/src/extractors/odfextractor.h +++ b/src/extractors/odfextractor.h @@ -1,46 +1,33 @@ /* - - 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 + SPDX-FileCopyrightText: 2013 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef ODF_EXTRACTOR_H #define ODF_EXTRACTOR_H #include "extractorplugin.h" namespace KFileMetaData { class OdfExtractor : public ExtractorPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.ExtractorPlugin" FILE "odfextractor.json") Q_INTERFACES(KFileMetaData::ExtractorPlugin) public: explicit OdfExtractor(QObject* parent = nullptr); QStringList mimetypes() const override; void extract(ExtractionResult* result) override; private: }; } #endif // ODF_EXTRACTOR_H diff --git a/src/extractors/office2007extractor.cpp b/src/extractors/office2007extractor.cpp index 63a6934..ad61b30 100644 --- a/src/extractors/office2007extractor.cpp +++ b/src/extractors/office2007extractor.cpp @@ -1,296 +1,283 @@ /* - - 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 + SPDX-FileCopyrightText: 2013 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later */ #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(); const bool extractMetaData = result->inputFlags() & ExtractionResult::ExtractMetaData; if (extractMetaData && 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 (extractMetaData && 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(); 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/extractors/office2007extractor.h b/src/extractors/office2007extractor.h index f09820c..57c6a2f 100644 --- a/src/extractors/office2007extractor.h +++ b/src/extractors/office2007extractor.h @@ -1,53 +1,40 @@ /* - - 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 + SPDX-FileCopyrightText: 2013 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef OFFICE_2007_EXTRACTOR_H #define OFFICE_2007_EXTRACTOR_H #include "extractorplugin.h" #include class KArchiveDirectory; namespace KFileMetaData { class Office2007Extractor : public ExtractorPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.ExtractorPlugin" FILE "office2007extractor.json") Q_INTERFACES(KFileMetaData::ExtractorPlugin) public: explicit Office2007Extractor(QObject* parent = nullptr); QStringList mimetypes() const override; void extract(ExtractionResult* result) override; private: void extractTextWithTag(QIODevice* device, const QString& tag, ExtractionResult* result); void extractAllText(QIODevice* device, ExtractionResult* result); void extractTextFromFiles(const KArchiveDirectory* archiveDir, ExtractionResult* result); }; } #endif // OFFICE_2007_EXTRACTOR_H diff --git a/src/extractors/officeextractor.cpp b/src/extractors/officeextractor.cpp index ac64c4e..ce6218f 100644 --- a/src/extractors/officeextractor.cpp +++ b/src/extractors/officeextractor.cpp @@ -1,115 +1,103 @@ /* This file is part of a KMetaData File Extractor - Copyright (C) 2013 Denis Steckelmacher + SPDX-FileCopyrightText: 2013 Denis Steckelmacher - 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 + SPDX-License-Identifier: LGPL-2.1-or-later */ #include "officeextractor.h" #include #include #include using namespace KFileMetaData; OfficeExtractor::OfficeExtractor(QObject* parent) : ExtractorPlugin(parent) { // Find the executables of catdoc, catppt and xls2csv. If an executable cannot // be found, indexing its corresponding MIME type will be disabled findExe(QStringLiteral("application/msword"), QStringLiteral("catdoc"), m_catdoc); findExe(QStringLiteral("application/vnd.ms-excel"), QStringLiteral("xls2csv"), m_xls2csv); findExe(QStringLiteral("application/vnd.ms-powerpoint"), QStringLiteral("catppt"), m_catppt); } void OfficeExtractor::findExe(const QString& mimeType, const QString& name, QString& fullPath) { fullPath = QStandardPaths::findExecutable(name); if (!fullPath.isEmpty()) { m_available_mime_types << mimeType; } } QStringList OfficeExtractor::mimetypes() const { return m_available_mime_types; } void OfficeExtractor::extract(ExtractionResult* result) { QStringList args; QString contents; args << QStringLiteral("-s") << QStringLiteral("cp1252"); // FIXME: Store somewhere a map between the user's language and the encoding of the Windows files it may use ? args << QStringLiteral("-d") << QStringLiteral("utf8"); const QString fileUrl = result->inputUrl(); const QString mimeType = result->inputMimetype(); if (mimeType == QLatin1String("application/msword")) { result->addType(Type::Document); args << QStringLiteral("-w"); contents = textFromFile(fileUrl, m_catdoc, args); // Now that we have the plain text content, count words, lines and characters // (original code from plaintextextractor.cpp, authored by Vishesh Handa) int lines = contents.count(QLatin1Char('\n')); int words = contents.count(QRegularExpression(QStringLiteral("\\b\\w+\\b"))); result->add(Property::WordCount, words); result->add(Property::LineCount, lines); } else if (mimeType == QLatin1String("application/vnd.ms-excel")) { result->addType(Type::Document); result->addType(Type::Spreadsheet); args << QStringLiteral("-c") << QStringLiteral(" "); args << QStringLiteral("-b") << QStringLiteral(" "); args << QStringLiteral("-q") << QStringLiteral("0"); contents = textFromFile(fileUrl, m_xls2csv, args); } else if (mimeType == QLatin1String("application/vnd.ms-powerpoint")) { result->addType(Type::Document); result->addType(Type::Presentation); contents = textFromFile(fileUrl, m_catppt, args); } if (contents.isEmpty()) return; result->append(contents); return; } QString OfficeExtractor::textFromFile(const QString& fileUrl, const QString& command, QStringList& arguments) { arguments << fileUrl; // Start a process and read its standard output QProcess process; process.setReadChannel(QProcess::StandardOutput); process.start(command, arguments, QIODevice::ReadOnly); process.waitForFinished(); if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) return QString(); else return QString::fromUtf8(process.readAll()); } diff --git a/src/extractors/officeextractor.h b/src/extractors/officeextractor.h index 9a3e769..ecb9084 100644 --- a/src/extractors/officeextractor.h +++ b/src/extractors/officeextractor.h @@ -1,55 +1,43 @@ /* This file is part of a KMetaData File Extractor - Copyright (C) 2013 Denis Steckelmacher + SPDX-FileCopyrightText: 2013 Denis Steckelmacher - 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 + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef OFFICE_EXTRACTOR_H #define OFFICE_EXTRACTOR_H #include "extractorplugin.h" namespace KFileMetaData { class OfficeExtractor : public ExtractorPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.ExtractorPlugin" FILE "officeextractor.json") Q_INTERFACES(KFileMetaData::ExtractorPlugin) public: explicit OfficeExtractor(QObject* parent = nullptr); QStringList mimetypes() const override; void extract(ExtractionResult* result) override; private: void findExe(const QString& mimeType, const QString& name, QString& fullPath); QString textFromFile(const QString& fileUrl, const QString& command, QStringList& arguments); private: QStringList m_available_mime_types; QString m_catdoc; QString m_catppt; QString m_xls2csv; }; } #endif diff --git a/src/extractors/plaintextextractor.cpp b/src/extractors/plaintextextractor.cpp index 1bbbd8a..c52194e 100644 --- a/src/extractors/plaintextextractor.cpp +++ b/src/extractors/plaintextextractor.cpp @@ -1,140 +1,127 @@ /* - - Copyright (C) 2012 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 + SPDX-FileCopyrightText: 2012 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later */ #include "plaintextextractor.h" #include #include #include #include #if defined(Q_OS_LINUX) || defined(__GLIBC__) #include #include #include #include #endif using namespace KFileMetaData; PlainTextExtractor::PlainTextExtractor(QObject* parent) : ExtractorPlugin(parent) { } const QStringList supportedMimeTypes = { QStringLiteral("text/plain"), }; QStringList PlainTextExtractor::mimetypes() const { return supportedMimeTypes; } void PlainTextExtractor::extract(ExtractionResult* result) { #if defined(Q_OS_LINUX) || defined(__GLIBC__) QByteArray filePath = QFile::encodeName(result->inputUrl()); #ifdef O_NOATIME int fd = open(filePath.constData(), O_RDONLY | O_NOATIME); if (fd < 0) #else int fd; #endif { fd = open(filePath.constData(), O_RDONLY); } if (fd < 0) { return; } result->addType(Type::Text); if (!(result->inputFlags() & ExtractionResult::ExtractPlainText)) { close(fd); return; } QTextCodec* codec = QTextCodec::codecForLocale(); char* line = nullptr; size_t len = 0; int lines = 0; int r = 0; FILE* fp = fdopen(fd, "r"); while ( (r = getline(&line, &len, fp)) != -1) { QTextCodec::ConverterState state; QString text = codec->toUnicode(line, r - 1, &state); if (state.invalidChars > 0) { qDebug() << "Invalid encoding. Ignoring" << result->inputUrl(); free(line); close(fd); return; } result->append(text); lines += 1; } if (result->inputFlags() & ExtractionResult::ExtractMetaData) { result->add(Property::LineCount, lines); } free(line); close(fd); #else std::string line; int lines = 0; std::ifstream fstream(QFile::encodeName(result->inputUrl()).constData()); if (!fstream.is_open()) { return; } result->addType(Type::Text); if (!(result->inputFlags() & ExtractionResult::ExtractPlainText)) { return; } QTextCodec* codec = QTextCodec::codecForLocale(); while (std::getline(fstream, line)) { QByteArray arr = QByteArray::fromRawData(line.c_str(), line.size()); QTextCodec::ConverterState state; QString text = codec->toUnicode(arr.constData(), arr.size(), &state); if (state.invalidChars > 0) { qDebug() << "Invalid encoding. Ignoring" << result->inputUrl(); return; } result->append(text); lines += 1; } result->add(Property::LineCount, lines); #endif } diff --git a/src/extractors/plaintextextractor.h b/src/extractors/plaintextextractor.h index 6a4d69d..826262b 100644 --- a/src/extractors/plaintextextractor.h +++ b/src/extractors/plaintextextractor.h @@ -1,45 +1,32 @@ /* - - Copyright (C) 2012 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 + SPDX-FileCopyrightText: 2012 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef PLAINTEXTEXTRACTOR_H #define PLAINTEXTEXTRACTOR_H #include "extractorplugin.h" namespace KFileMetaData { class PlainTextExtractor : public ExtractorPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.ExtractorPlugin" FILE "plaintextextractor.json") Q_INTERFACES(KFileMetaData::ExtractorPlugin) public: explicit PlainTextExtractor(QObject* parent = nullptr); QStringList mimetypes() const override; void extract(ExtractionResult* result) override; }; } #endif // PLAINTEXTEXTRACTOR_H diff --git a/src/extractors/poextractor.cpp b/src/extractors/poextractor.cpp index 07b2bba..7e94c7c 100644 --- a/src/extractors/poextractor.cpp +++ b/src/extractors/poextractor.cpp @@ -1,183 +1,171 @@ /* Gettext translation file analyzer - Copyright (C) 2007 Montel Laurent - Copyright (C) 2009 Jos van den Oever - Copyright (C) 2014 Nick Shaforostoff - - 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 + SPDX-FileCopyrightText: 2007 Montel Laurent + SPDX-FileCopyrightText: 2009 Jos van den Oever + SPDX-FileCopyrightText: 2014 Nick Shaforostoff + + SPDX-License-Identifier: LGPL-2.1-or-later */ #include "poextractor.h" #include #include using namespace KFileMetaData; POExtractor::POExtractor(QObject* parent) : ExtractorPlugin(parent) { } const QStringList supportedMimeTypes = { QStringLiteral("text/x-gettext-translation"), }; QStringList POExtractor::mimetypes() const { return supportedMimeTypes; } void POExtractor::endMessage() { messages++; fuzzy+=isFuzzy; untranslated+=(!isTranslated); isFuzzy = false; isTranslated = false; state = WHITESPACE; } void POExtractor::handleComment(const char* data, quint32 length) { state = COMMENT; if (length >= 8 && strncmp(data, "#, fuzzy", 8) == 0) { // could be better isFuzzy = true; } } void POExtractor::handleLine(const char* data, quint32 length) { if (state == ERROR) return; if (state == WHITESPACE) { if (length == 0) return; if (data[0] != '#') { state = COMMENT; //this allows PO files w/o comments } else { handleComment(data, length); return; } } if (state == COMMENT) { if (length == 0) { state = WHITESPACE; } else if (data[0] == '#') { handleComment(data, length); } else if (length > 7 && strncmp("msgctxt", data, 7) == 0) { state = MSGCTXT; } else if (length > 7 && strncmp("msgid \"", data, 7) == 0) { state = MSGID; } else { state = ERROR; } return; } else if (length > 1 && data[0] == '"' && data[length-1] == '"' && (state == MSGCTXT || state == MSGID || state == MSGSTR || state == MSGID_PLURAL)) { // continued text field isTranslated = state == MSGSTR && length > 2; } else if (state == MSGCTXT && length > 7 && strncmp("msgid \"", data, 7) == 0) { state = MSGID; } else if (state == MSGID && length > 14 && strncmp("msgid_plural \"", data, 14) == 0) { state = MSGID_PLURAL; } else if ((state == MSGID || state == MSGID_PLURAL || state == MSGSTR) && length > 8 && strncmp("msgstr", data, 6) == 0) { state = MSGSTR; isTranslated = strncmp(data+length-3, " \"\"", 3) != 0; } else if (state == MSGSTR) { if (length == 0) { endMessage(); } else if (data[0]=='#' || data[0]=='m') { //allow PO without empty line between entries endMessage(); state = COMMENT; handleLine(data, length); } else { state = ERROR; } } else { state = ERROR; } #if 0 if (messages > 1 || state != MSGSTR) return; // handle special values in the first message // assumption is that value takes up only one line if (strncmp("\"POT-Creation-Date: ", data, 20) == 0) { result->add(Property::TranslationTemplateDate, QByteArray(data + 20, length - 21)); } else if (strncmp("\"PO-Revision-Date: ", data, 19) == 0) { result->add(Property::TranslationLastUpDate, QByteArray(data + 19, length - 20)); } else if (strncmp("\"Last-Translator: ", data, 18) == 0) { result->add(Property::TranslationLastAuthor, QByteArray(data + 18, length - 19)); } #endif } void POExtractor::extract(ExtractionResult* result) { std::ifstream fstream(QFile::encodeName(result->inputUrl()).constData()); if (!fstream.is_open()) { return; } result->addType(Type::Text); if (!(result->inputFlags() & ExtractionResult::ExtractPlainText)) { return; } state = WHITESPACE; messages = 0; untranslated = 0; fuzzy = 0; isFuzzy = false; isTranslated = false; std::string line; int lines = 0; while (std::getline(fstream, line)) { //TODO add a parsed text of translation units //QByteArray arr = QByteArray::fromRawData(line.c_str(), line.size()); //result->append(QString::fromUtf8(arr)); handleLine(line.c_str(), line.size()); lines++; if (messages <= 1 && state == MSGSTR) { // handle special values in the first message // assumption is that value takes up only one line if (strncmp("\"POT-Creation-Date: ", line.c_str(), 20) == 0) { result->add(Property::TranslationTemplateDate, QByteArray(line.c_str() + 20, line.size() - 21)); } else if (strncmp("\"PO-Revision-Date: ", line.c_str(), 19) == 0) { result->add(Property::TranslationLastUpDate, QByteArray(line.c_str() + 19, line.size() - 20)); } else if (strncmp("\"Last-Translator: ", line.c_str(), 18) == 0) { result->add(Property::TranslationLastAuthor, QString::fromUtf8(QByteArray::fromRawData(line.c_str() + 18, line.size() - 19))); } } } handleLine("", 0); //for files with non-empty last line messages--;//cause header does not count result->add(Property::TranslationUnitsTotal, messages); result->add(Property::TranslationUnitsWithTranslation, messages-untranslated); result->add(Property::TranslationUnitsWithDraftTranslation, fuzzy); result->add(Property::LineCount, lines); //TODO WordCount } diff --git a/src/extractors/poextractor.h b/src/extractors/poextractor.h index 91bf2c8..4a83e5a 100644 --- a/src/extractors/poextractor.h +++ b/src/extractors/poextractor.h @@ -1,62 +1,50 @@ /* Gettext translation file analyzer - Copyright (C) 2007 Montel Laurent - Copyright (C) 2009 Jos van den Oever - Copyright (C) 2014 Nick Shaforostoff - - 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 + SPDX-FileCopyrightText: 2007 Montel Laurent + SPDX-FileCopyrightText: 2009 Jos van den Oever + SPDX-FileCopyrightText: 2014 Nick Shaforostoff + + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef POEXTRACTOR_H #define POEXTRACTOR_H #include "extractorplugin.h" namespace KFileMetaData { class POExtractor : public ExtractorPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.ExtractorPlugin" FILE "poextractor.json") Q_INTERFACES(KFileMetaData::ExtractorPlugin) public: explicit POExtractor(QObject* parent = nullptr); QStringList mimetypes() const override; void extract(ExtractionResult* result) override; private: void endMessage(); void handleComment(const char* data, quint32 length); void handleLine(const char* data, quint32 length); enum PoState {COMMENT, MSGCTXT, MSGID, MSGID_PLURAL, MSGSTR, MSGSTR_PLURAL, WHITESPACE, ERROR}; PoState state; int messages; int untranslated; int fuzzy; bool isFuzzy=false, isTranslated=false; }; } #endif // PLAINTEXTEXTRACTOR_H diff --git a/src/extractors/popplerextractor.cpp b/src/extractors/popplerextractor.cpp index 1bede9d..7e9b3d0 100644 --- a/src/extractors/popplerextractor.cpp +++ b/src/extractors/popplerextractor.cpp @@ -1,96 +1,83 @@ /* - - 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 + SPDX-FileCopyrightText: 2012 Vishesh Handa + SPDX-FileCopyrightText: 2012 Jörg Ehrichs + + SPDX-License-Identifier: LGPL-2.1-or-later */ #include "popplerextractor.h" #include #include using namespace KFileMetaData; PopplerExtractor::PopplerExtractor(QObject* parent) : ExtractorPlugin(parent) { } const QStringList supportedMimeTypes = { QStringLiteral("application/pdf"), }; QStringList PopplerExtractor::mimetypes() const { return supportedMimeTypes; } void PopplerExtractor::extract(ExtractionResult* result) { const QString fileUrl = result->inputUrl(); QScopedPointer pdfDoc(Poppler::Document::load(fileUrl, QByteArray(), QByteArray())); if (!pdfDoc || pdfDoc->isLocked()) { return; } result->addType(Type::Document); if (result->inputFlags() & ExtractionResult::ExtractMetaData) { QString title = pdfDoc->info(QStringLiteral("Title")).trimmed(); if (!title.isEmpty()) { result->add(Property::Title, title); } QString subject = pdfDoc->info(QStringLiteral("Subject")); if (!subject.isEmpty()) { result->add(Property::Subject, subject); } QString author = pdfDoc->info(QStringLiteral("Author")); if (!author.isEmpty()) { result->add(Property::Author, author); } QString generator = pdfDoc->info(QStringLiteral("Producer")); if (!generator.isEmpty()) { result->add(Property::Generator, generator); } QString creationDate = pdfDoc->info(QStringLiteral("CreationDate")); if (!creationDate.isEmpty()) { QByteArray utf8 = creationDate.toUtf8(); result->add(Property::CreationDate, Poppler::convertDate(utf8.data())); } } if (!(result->inputFlags() & ExtractionResult::ExtractPlainText)) { return; } for (int i = 0; i < pdfDoc->numPages(); i++) { QScopedPointer page(pdfDoc->page(i)); if (!page) { // broken pdf files do not return a valid page qWarning() << "Could not read page content from" << fileUrl; break; } result->append(page->text(QRectF())); } } diff --git a/src/extractors/popplerextractor.h b/src/extractors/popplerextractor.h index b8acd30..286e8c2 100644 --- a/src/extractors/popplerextractor.h +++ b/src/extractors/popplerextractor.h @@ -1,48 +1,35 @@ /* - - Copyright (C) 2012 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 + SPDX-FileCopyrightText: 2012 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef POPPLEREXTRACTOR_H #define POPPLEREXTRACTOR_H #include "extractorplugin.h" #include namespace KFileMetaData { class PopplerExtractor : public ExtractorPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.ExtractorPlugin" FILE "popplerextractor.json") Q_INTERFACES(KFileMetaData::ExtractorPlugin) public: explicit PopplerExtractor(QObject* parent = nullptr); QStringList mimetypes() const override; void extract(ExtractionResult* result) override; private: QString parseFirstPage(Poppler::Document* pdfDoc, const QString& fileUrl); }; } #endif // POPPLEREXTRACTOR_H diff --git a/src/extractors/postscriptdscextractor.cpp b/src/extractors/postscriptdscextractor.cpp index 1e0e5d7..fc7a3ff 100644 --- a/src/extractors/postscriptdscextractor.cpp +++ b/src/extractors/postscriptdscextractor.cpp @@ -1,118 +1,106 @@ /* - Copyright (C) 2018 Stefan Brüns + SPDX-FileCopyrightText: 2018 Stefan Brüns - 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 + SPDX-License-Identifier: LGPL-2.1-or-later */ #include "postscriptdscextractor.h" #include "kfilemetadata_debug.h" #include namespace KFileMetaData { DscExtractor::DscExtractor(QObject* parent) : ExtractorPlugin(parent) { } QStringList DscExtractor::mimetypes() const { QStringList list; list << QStringLiteral("application/postscript") << QStringLiteral("image/x-eps"); return list; } void DscExtractor::extract(ExtractionResult* result) { QFile file(result->inputUrl()); if (!file.open(QIODevice::ReadOnly)) { qCWarning(KFILEMETADATA_LOG) << "Document is not a valid file"; return; } // A little bit heuristic - assume EPS files are images, PS complete documents if (result->inputMimetype() == QLatin1String("application/postscript")) { result->addType(Type::Document); } else { result->addType(Type::Image); } if (!(result->inputFlags() & ExtractionResult::ExtractMetaData)) { return; } // Try to find some DSC (PostScript Language Document Structuring Conventions) conforming data QTextStream stream(&file); QString line; while (stream.readLineInto(&line)) { if (!line.startsWith(QLatin1String("%%"))) { continue; } if (line.startsWith(QLatin1String("%%Pages:"))) { bool ok = false; int pages = line.midRef(8).toInt(&ok, 10); if (ok) { result->add(Property::PageCount, pages); } } else if (line.startsWith(QLatin1String("%%Title:"))) { QStringRef title = line.midRef(8); title = title.trimmed(); if (title.startsWith(QLatin1Char('(')) && title.endsWith(QLatin1Char(')'))) { title = title.mid(1, title.size() - 2); } if (!title.isEmpty()) { result->add(Property::Title, title.toString()); } } else if (line.startsWith(QLatin1String("%%CreationDate:"))) { // "Neither the date nor time need be in any standard format." QStringRef date = line.midRef(15); date = date.trimmed(); if (date.startsWith(QLatin1Char('(')) && date.endsWith(QLatin1Char(')'))) { date = date.mid(1, date.size() - 2); date = date.trimmed(); } if (date.startsWith(QLatin1String("D:")) && date.size() >= 23) { // Standard PDF date format, ASN.1 like - (D:YYYYMMDDHHmmSSOHH'mm') auto dt = QDateTime::fromString(date.mid(2, 14).toString(), QLatin1String("yyyyMMddhhmmss")); auto offset = QTime::fromString(date.mid(17, 5).toString(), QLatin1String("hh'\\''mm")); if (date.mid(16,1) == QLatin1String("+")) { dt.setOffsetFromUtc(QTime(0, 0).secsTo(offset)); } else { dt.setOffsetFromUtc(-1 * QTime(0, 0).secsTo(offset)); } result->add(Property::CreationDate, dt); } else { auto dt = QDateTime::fromString(date.toString()); if (dt.isValid()) { result->add(Property::CreationDate, dt); } } } else if (line.startsWith(QLatin1String("%%EndComments"))) { break; } } } } // namespace KFileMetaData diff --git a/src/extractors/postscriptdscextractor.h b/src/extractors/postscriptdscextractor.h index 0f6d559..937d810 100644 --- a/src/extractors/postscriptdscextractor.h +++ b/src/extractors/postscriptdscextractor.h @@ -1,46 +1,34 @@ /* - Copyright (C) 2018 Stefan Brüns + SPDX-FileCopyrightText: 2018 Stefan Brüns - 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 + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef DSC_EXTRACTOR_H #define DSC_EXTRACTOR_H #include "extractorplugin.h" namespace KFileMetaData { class DscExtractor : public ExtractorPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.ExtractorPlugin" FILE "postscriptdscextractor.json") Q_INTERFACES(KFileMetaData::ExtractorPlugin) public: explicit DscExtractor(QObject* parent = nullptr); QStringList mimetypes() const override; void extract(ExtractionResult* result) override; private: }; } #endif // DSC_EXTRACTOR_H diff --git a/src/extractors/taglibextractor.cpp b/src/extractors/taglibextractor.cpp index c74cb4a..f42cbeb 100644 --- a/src/extractors/taglibextractor.cpp +++ b/src/extractors/taglibextractor.cpp @@ -1,520 +1,507 @@ /* - - Copyright (C) 2012 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 + SPDX-FileCopyrightText: 2012 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later */ #include "taglibextractor.h" #include "kfilemetadata_debug.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 using namespace KFileMetaData; namespace { const QStringList supportedMimeTypes = { 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/vnd.audible.aax"), QStringLiteral("audio/x-aiff"), QStringLiteral("audio/x-aifc"), 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+ogg"), QStringLiteral("audio/x-vorbis+ogg"), QStringLiteral("audio/x-wav"), QStringLiteral("audio/x-wavpack"), }; void extractAudioProperties(TagLib::File* file, ExtractionResult* result) { TagLib::AudioProperties* audioProp = file->audioProperties(); if (audioProp && (result->inputFlags() & ExtractionResult::ExtractMetaData)) { if (audioProp->length()) { // What about the xml duration? result->add(Property::Duration, audioProp->length()); } if (audioProp->bitrate()) { result->add(Property::BitRate, audioProp->bitrate() * 1000); } if (audioProp->channels()) { result->add(Property::Channels, audioProp->channels()); } if (audioProp->sampleRate()) { result->add(Property::SampleRate, audioProp->sampleRate()); } } } void readGenericProperties(const TagLib::PropertyMap &savedProperties, ExtractionResult* result) { if (!(result->inputFlags() & ExtractionResult::ExtractMetaData) || savedProperties.isEmpty()) { return; } if (savedProperties.contains("TITLE")) { result->add(Property::Title, TStringToQString(savedProperties["TITLE"].toString()).trimmed()); } if (savedProperties.contains("ALBUM")) { result->add(Property::Album, TStringToQString(savedProperties["ALBUM"].toString()).trimmed()); } if (savedProperties.contains("COMMENT")) { result->add(Property::Comment, TStringToQString(savedProperties["COMMENT"].toString()).trimmed()); } if (savedProperties.contains("TRACKNUMBER")) { result->add(Property::TrackNumber, savedProperties["TRACKNUMBER"].toString().toInt()); } if (savedProperties.contains("DATE")) { result->add(Property::ReleaseYear, savedProperties["DATE"].toString().toInt()); } if (savedProperties.contains("OPUS")) { result->add(Property::Opus, savedProperties["OPUS"].toString().toInt()); } if (savedProperties.contains("DISCNUMBER")) { result->add(Property::DiscNumber, savedProperties["DISCNUMBER"].toString().toInt()); } if (savedProperties.contains("RATING")) { /* * There is no standard regarding ratings. Mimic MediaMonkey's behavior * with a range of 0 to 100 (stored in steps of 10) and make it compatible * with baloo rating with a range from 0 to 10 */ result->add(Property::Rating, savedProperties["RATING"].toString().toInt() / 10); } if (savedProperties.contains("LOCATION")) { result->add(Property::Location, TStringToQString(savedProperties["LOCATION"].toString()).trimmed()); } if (savedProperties.contains("LANGUAGE")) { result->add(Property::Language, TStringToQString(savedProperties["LANGUAGE"].toString()).trimmed()); } if (savedProperties.contains("LICENSE")) { result->add(Property::License, TStringToQString(savedProperties["LICENSE"].toString()).trimmed()); } if (savedProperties.contains("PUBLISHER")) { result->add(Property::Publisher, TStringToQString(savedProperties["PUBLISHER"].toString()).trimmed()); } if (savedProperties.contains("COPYRIGHT")) { result->add(Property::Copyright, TStringToQString(savedProperties["COPYRIGHT"].toString()).trimmed()); } if (savedProperties.contains("LABEL")) { result->add(Property::Label, TStringToQString(savedProperties["LABEL"].toString()).trimmed()); } if (savedProperties.contains("ENSEMBLE")) { result->add(Property::Ensemble, TStringToQString(savedProperties["ENSEMBLE"].toString()).trimmed()); } if (savedProperties.contains("COMPILATION")) { result->add(Property::Compilation, TStringToQString(savedProperties["COMPILATION"].toString()).trimmed()); } if (savedProperties.contains("LYRICS")) { result->add(Property::Lyrics, TStringToQString(savedProperties["LYRICS"].toString()).trimmed()); } if (savedProperties.contains("ARTIST")) { const auto artists = savedProperties["ARTIST"]; for (const auto& artist : artists) { result->add(Property::Artist, TStringToQString(artist).trimmed()); } } if (savedProperties.contains("GENRE")) { const auto genres = savedProperties["GENRE"]; for (const auto& genre : genres) { result->add(Property::Genre, TStringToQString(genre).trimmed()); } } if (savedProperties.contains("ALBUMARTIST")) { const auto albumArtists = savedProperties["ALBUMARTIST"]; for (const auto& albumArtist : albumArtists) { result->add(Property::AlbumArtist, TStringToQString(albumArtist).trimmed()); } } if (savedProperties.contains("COMPOSER")) { const auto composers = savedProperties["COMPOSER"]; for (const auto& composer : composers) { result->add(Property::Composer, TStringToQString(composer).trimmed()); } } if (savedProperties.contains("LYRICIST")) { const auto lyricists = savedProperties["LYRICIST"]; for (const auto& lyricist : lyricists) { result->add(Property::Lyricist, TStringToQString(lyricist).trimmed()); } } if (savedProperties.contains("CONDUCTOR")) { const auto conductors = savedProperties["CONDUCTOR"]; for (const auto& conductor : conductors) { result->add(Property::Conductor, TStringToQString(conductor).trimmed()); } } if (savedProperties.contains("ARRANGER")) { const auto arrangers = savedProperties["ARRANGER"]; for (const auto& arranger : arrangers) { result->add(Property::Arranger, TStringToQString(arranger).trimmed()); } } if (savedProperties.contains("PERFORMER")) { const auto performers = savedProperties["PERFORMER"]; for (const auto& performer : performers) { result->add(Property::Performer, TStringToQString(performer).trimmed()); } } if (savedProperties.contains("AUTHOR")) { const auto authors = savedProperties["AUTHOR"]; for (const auto& author: authors) { result->add(Property::Author, TStringToQString(author).trimmed()); } } if (savedProperties.contains("REPLAYGAIN_TRACK_GAIN")) { auto trackGainString = TStringToQString(savedProperties["REPLAYGAIN_TRACK_GAIN"].toString(";")).trimmed(); // remove " dB" suffix if (trackGainString.endsWith(QStringLiteral(" dB"), Qt::CaseInsensitive)) { trackGainString.chop(3); } bool success = false; double replayGainTrackGain = trackGainString.toDouble(&success); if (success) { result->add(Property::ReplayGainTrackGain, replayGainTrackGain); } } if (savedProperties.contains("REPLAYGAIN_ALBUM_GAIN")) { auto albumGainString = TStringToQString(savedProperties["REPLAYGAIN_ALBUM_GAIN"].toString(";")).trimmed(); // remove " dB" suffix if (albumGainString.endsWith(QStringLiteral(" dB"), Qt::CaseInsensitive)) { albumGainString.chop(3); } bool success = false; double replayGainAlbumGain = albumGainString.toDouble(&success); if (success) { result->add(Property::ReplayGainAlbumGain, replayGainAlbumGain); } } if (savedProperties.contains("REPLAYGAIN_TRACK_PEAK")) { auto trackPeakString = TStringToQString(savedProperties["REPLAYGAIN_TRACK_PEAK"].toString(";")).trimmed(); bool success = false; double replayGainTrackPeak = trackPeakString.toDouble(&success); if (success) { result->add(Property::ReplayGainTrackPeak, replayGainTrackPeak); } } if (savedProperties.contains("REPLAYGAIN_ALBUM_PEAK")) { auto albumPeakString = TStringToQString(savedProperties["REPLAYGAIN_ALBUM_PEAK"].toString(";")).trimmed(); bool success = false; double replayGainAlbumPeak = albumPeakString.toDouble(&success); if (success) { result->add(Property::ReplayGainAlbumPeak, replayGainAlbumPeak); } } } void extractId3Tags(TagLib::ID3v2::Tag* Id3Tags, ExtractionResult* result) { if (!(result->inputFlags() & ExtractionResult::ExtractMetaData) || Id3Tags->isEmpty()) { return; } TagLib::ID3v2::FrameList lstID3v2; /* * Publisher. * Special handling because TagLib::PropertyMap maps "TPUB" to "LABEL" * Insert manually for Publisher. */ lstID3v2 = Id3Tags->frameListMap()["TPUB"]; if (!lstID3v2.isEmpty()) { result->add(Property::Publisher, TStringToQString(lstID3v2.front()->toString())); } // Compilation. lstID3v2 = Id3Tags->frameListMap()["TCMP"]; if (!lstID3v2.isEmpty()) { result->add(Property::Compilation, TStringToQString(lstID3v2.front()->toString())); } /* * Rating. * There is no standard regarding ratings. Most of the implementations match * a 5 stars rating to a range of 0-255 for MP3. * Map it to baloo rating with a range of 0 - 10. */ lstID3v2 = Id3Tags->frameListMap()["POPM"]; if (!lstID3v2.isEmpty()) { TagLib::ID3v2::PopularimeterFrame *ratingFrame = static_cast(lstID3v2.front()); int rating = ratingFrame->rating(); if (rating == 0) { rating = 0; } else if (rating == 1) { TagLib::String ratingProvider = ratingFrame->email(); if (ratingProvider == "no@email" || ratingProvider == "org.kde.kfilemetadata") { rating = 1; } else { rating = 2; } } else if (rating >= 1 && rating <= 255) { rating = static_cast(0.032 * rating + 2); } result->add(Property::Rating, rating); } } void extractMp4Tags(TagLib::MP4::Tag* mp4Tags, ExtractionResult* result) { if (!(result->inputFlags() & ExtractionResult::ExtractMetaData) || mp4Tags->isEmpty()) { return; } TagLib::MP4::ItemListMap allTags = mp4Tags->itemListMap(); /* * There is no standard regarding ratings. Mimic MediaMonkey's behavior * with a range of 0 to 100 (stored in steps of 10) and make it compatible * with baloo rating with a range from 0 to 10. */ TagLib::MP4::ItemListMap::Iterator itRating = allTags.find("rate"); if (itRating != allTags.end()) { result->add(Property::Rating, itRating->second.toStringList().toString().toInt() / 10); } } void extractAsfTags(TagLib::ASF::Tag* asfTags, ExtractionResult* result) { if (!(result->inputFlags() & ExtractionResult::ExtractMetaData) || asfTags->isEmpty()) { return; } TagLib::ASF::AttributeList lstASF = asfTags->attribute("WM/SharedUserRating"); if (!lstASF.isEmpty()) { int rating = lstASF.front().toString().toInt(); /* * Map the rating values of WMP to Baloo rating. * 0->0, 1->2, 25->4, 50->6, 75->8, 99->10 */ if (rating == 0) { rating = 0; } else if (rating == 1) { rating = 2; } else { rating = static_cast(0.09 * rating + 2); } result->add(Property::Rating, rating); } lstASF = asfTags->attribute("Author"); if (!lstASF.isEmpty()) { const auto attribute = lstASF.front(); result->add(Property::Author, TStringToQString(attribute.toString()).trimmed()); } // Lyricist is called "WRITER" for wma/asf files lstASF = asfTags->attribute("WM/Writer"); if (!lstASF.isEmpty()) { const auto attribute = lstASF.front(); result->add(Property::Lyricist, TStringToQString(attribute.toString()).trimmed()); } /* * TagLib exports "WM/PUBLISHER" as "LABEL" in the PropertyMap, * add it manually to Publisher. */ lstASF = asfTags->attribute("WM/Publisher"); if (!lstASF.isEmpty()) { const auto attribute = lstASF.front(); result->add(Property::Publisher, TStringToQString(attribute.toString()).trimmed()); } } } // anonymous namespace TagLibExtractor::TagLibExtractor(QObject* parent) : ExtractorPlugin(parent) { } QStringList TagLibExtractor::mimetypes() const { return supportedMimeTypes; } void TagLibExtractor::extract(ExtractionResult* result) { const QString fileUrl = result->inputUrl(); const QString mimeType = getSupportedMimeType(result->inputMimetype()); // Open the file readonly. Important if we're sandboxed. #if defined Q_OS_WINDOWS TagLib::FileStream stream(fileUrl.toLocal8Bit().constData(), true); #else TagLib::FileStream stream(fileUrl.toUtf8().constData(), true); #endif if (!stream.isOpen()) { qCWarning(KFILEMETADATA_LOG) << "Unable to open file readonly: " << fileUrl; return; } if (mimeType == QLatin1String("audio/mpeg") || mimeType == QLatin1String("audio/mpeg3") || mimeType == QLatin1String("audio/x-mpeg")) { TagLib::MPEG::File file(&stream, TagLib::ID3v2::FrameFactory::instance(), true); if (file.isValid()) { extractAudioProperties(&file, result); readGenericProperties(file.properties(), result); if (file.hasID3v2Tag()) { extractId3Tags(file.ID3v2Tag(), result); } } } else if (mimeType == QLatin1String("audio/x-aiff") || mimeType == QLatin1String("audio/x-aifc")) { TagLib::RIFF::AIFF::File file(&stream, true); if (file.isValid()) { extractAudioProperties(&file, result); readGenericProperties(file.properties(), result); if (file.hasID3v2Tag()) { extractId3Tags(file.tag(), result); } } } else if (mimeType == QLatin1String("audio/wav") || mimeType == QLatin1String("audio/x-wav")) { TagLib::RIFF::WAV::File file(&stream, true); if (file.isValid()) { extractAudioProperties(&file, result); readGenericProperties(file.properties(), result); if (file.hasID3v2Tag()) { extractId3Tags(file.tag(), result); } } } else if (mimeType == QLatin1String("audio/x-musepack")) { TagLib::MPC::File file(&stream, true); if (file.isValid()) { extractAudioProperties(&file, result); readGenericProperties(file.properties(), result); } } else if (mimeType == QLatin1String("audio/x-ape")) { TagLib::APE::File file(&stream, true); if (file.isValid()) { extractAudioProperties(&file, result); readGenericProperties(file.properties(), result); } } else if (mimeType == QLatin1String("audio/x-wavpack")) { TagLib::WavPack::File file(&stream, true); if (file.isValid()) { extractAudioProperties(&file, result); readGenericProperties(file.properties(), result); } } else if ((mimeType == QLatin1String("audio/mp4")) || (mimeType == QLatin1String("audio/vnd.audible.aax"))) { TagLib::MP4::File file(&stream, true); if (file.isValid()) { extractAudioProperties(&file, result); readGenericProperties(file.properties(), result); extractMp4Tags(file.tag(), result); } } else if (mimeType == QLatin1String("audio/flac")) { TagLib::FLAC::File file(&stream, TagLib::ID3v2::FrameFactory::instance(), true); if (file.isValid()) { extractAudioProperties(&file, result); readGenericProperties(file.properties(), result); } } else if (mimeType == QLatin1String("audio/ogg") || mimeType == QLatin1String("audio/x-vorbis+ogg")) { TagLib::Ogg::Vorbis::File file(&stream, true); if (file.isValid()) { extractAudioProperties(&file, result); readGenericProperties(file.properties(), result); } } else if (mimeType == QLatin1String("audio/opus") || mimeType == QLatin1String("audio/x-opus+ogg")) { TagLib::Ogg::Opus::File file(&stream, true); if (file.isValid()) { extractAudioProperties(&file, result); readGenericProperties(file.properties(), result); } } else if (mimeType == QLatin1String("audio/speex") || mimeType == QLatin1String("audio/x-speex+ogg")) { TagLib::Ogg::Speex::File file(&stream, true); // Workaround for buggy taglib: // isValid() returns true for invalid files, but XiphComment* tag() returns a nullptr if (file.isValid() && file.tag()) { extractAudioProperties(&file, result); readGenericProperties(file.properties(), result); } } else if (mimeType == QLatin1String("audio/x-ms-wma")) { TagLib::ASF::File file(&stream, true); if (file.isValid()) { extractAudioProperties(&file, result); readGenericProperties(file.properties(), result); extractAsfTags(file.tag(), result); } } result->addType(Type::Audio); } // TAG information (incomplete). // https://xiph.org/vorbis/doc/v-comment.html // https://help.mp3tag.de/main_tags.html // http://id3.org/ // https://www.legroom.net/2009/05/09/ogg-vorbis-and-flac-comment-field-recommendations // https://kodi.wiki/view/Music_tagging#Tags_Kodi_reads // https://wiki.hydrogenaud.io/index.php?title=Tag_Mapping // https://picard.musicbrainz.org/docs/mappings/ // -- FLAC/OGG -- // Artist: ARTIST, PERFORMER // Album artist: ALBUMARTIST // Composer: COMPOSER // Lyricist: LYRICIST // Conductor: CONDUCTOR // Disc number: DISCNUMBER // Total discs: TOTALDISCS, DISCTOTAL // Track number: TRACKNUMBER // Total tracks: TOTALTRACKS, TRACKTOTAL // Genre: GENRE // -- ID3v2 -- // Artist: TPE1 // Album artist: TPE2 // Composer: TCOM // Lyricist: TEXT // Conductor: TPE3 // Disc number[/total dics]: TPOS // Track number[/total tracks]: TRCK // Genre: TCON diff --git a/src/extractors/taglibextractor.h b/src/extractors/taglibextractor.h index a3c807e..2682ad4 100644 --- a/src/extractors/taglibextractor.h +++ b/src/extractors/taglibextractor.h @@ -1,46 +1,33 @@ /* - - Copyright (C) 2012 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 + SPDX-FileCopyrightText: 2012 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef TAGLIBEXTRACTOR_H #define TAGLIBEXTRACTOR_H #include "extractorplugin.h" namespace KFileMetaData { class TagLibExtractor : public ExtractorPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.ExtractorPlugin" FILE "taglibextractor.json") Q_INTERFACES(KFileMetaData::ExtractorPlugin) public: explicit TagLibExtractor(QObject* parent = nullptr); void extract(ExtractionResult* result) override; QStringList mimetypes() const override; }; } #endif // TAGLIBEXTRACTOR_H diff --git a/src/extractors/xmlextractor.cpp b/src/extractors/xmlextractor.cpp index 939c1bb..c057420 100644 --- a/src/extractors/xmlextractor.cpp +++ b/src/extractors/xmlextractor.cpp @@ -1,148 +1,136 @@ /* - Copyright (C) 2018 Stefan Brüns + SPDX-FileCopyrightText: 2018 Stefan Brüns - 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 + SPDX-License-Identifier: LGPL-2.1-or-later */ #include "xmlextractor.h" #include "kfilemetadata_debug.h" #include "dublincoreextractor.h" #include #include #include namespace { inline QString dcNS() { return QStringLiteral("http://purl.org/dc/elements/1.1/"); } inline QString svgNS() { return QStringLiteral("http://www.w3.org/2000/svg"); } inline QString rdfNS() { return QStringLiteral("http://www.w3.org/1999/02/22-rdf-syntax-ns#"); } inline QString ccNS() { return QStringLiteral("http://creativecommons.org/ns#"); } void extractSvgText(KFileMetaData::ExtractionResult* result, const QDomElement &node) { if (node.namespaceURI() != svgNS()) { return; } if ((node.localName() == QLatin1String("g")) || (node.localName() == QLatin1String("a"))) { QDomElement e = node.firstChildElement(); for (; !e.isNull(); e = e.nextSiblingElement()) { extractSvgText(result, e); } } else if (node.localName() == QLatin1String("text")) { qCDebug(KFILEMETADATA_LOG) << node.text(); result->append(node.text()); } } static const QStringList supportedMimeTypes = { QStringLiteral("application/xml"), QStringLiteral("image/svg+xml"), QStringLiteral("image/svg"), }; } namespace KFileMetaData { XmlExtractor::XmlExtractor(QObject* parent) : ExtractorPlugin(parent) { } QStringList XmlExtractor::mimetypes() const { return supportedMimeTypes; } void XmlExtractor::extract(ExtractionResult* result) { auto flags = result->inputFlags(); QFile file(result->inputUrl()); if (!file.open(QIODevice::ReadOnly)) { qCWarning(KFILEMETADATA_LOG) << "Document is not a valid file"; return; } if ((result->inputMimetype() == QLatin1String("image/svg")) || (result->inputMimetype() == QLatin1String("image/svg+xml"))) { result->addType(Type::Image); QDomDocument doc; const bool processNamespaces = true; doc.setContent(&file, processNamespaces); QDomElement svg = doc.firstChildElement(); if (!svg.isNull() && svg.localName() == QLatin1String("svg") && svg.namespaceURI() == svgNS()) { QDomElement e = svg.firstChildElement(); for (; !e.isNull(); e = e.nextSiblingElement()) { if (e.namespaceURI() != svgNS()) { continue; } if (e.localName() == QLatin1String("metadata")) { if (!(flags & ExtractionResult::ExtractMetaData)) { continue; } auto rdf = e.firstChildElement(QLatin1String("RDF")); if (rdf.isNull() || rdf.namespaceURI() != rdfNS()) { continue; } auto cc = rdf.firstChildElement(QLatin1String("Work")); if (cc.isNull() || cc.namespaceURI() != ccNS()) { continue; } DublinCoreExtractor::extract(result, cc); } else if (e.localName() == QLatin1String("defs")) { // skip continue; } else if (flags & ExtractionResult::ExtractPlainText) { // extract extractSvgText(result, e); } } } } else { result->addType(Type::Text); if (flags & ExtractionResult::ExtractPlainText) { QXmlStreamReader stream(&file); while (!stream.atEnd()) { QXmlStreamReader::TokenType token = stream.readNext(); if (token == QXmlStreamReader::Characters) { QString text = stream.text().trimmed().toString(); if (!text.isEmpty()) { result->append(text); } } } } } } } // namespace KFileMetaData diff --git a/src/extractors/xmlextractor.h b/src/extractors/xmlextractor.h index 67a6d35..9f0a494 100644 --- a/src/extractors/xmlextractor.h +++ b/src/extractors/xmlextractor.h @@ -1,46 +1,34 @@ /* - Copyright (C) 2018 Stefan Brüns + SPDX-FileCopyrightText: 2018 Stefan Brüns - 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 + SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef XML_EXTRACTOR_H #define XML_EXTRACTOR_H #include "extractorplugin.h" namespace KFileMetaData { class XmlExtractor : public ExtractorPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.ExtractorPlugin" FILE "xmlextractor.json") Q_INTERFACES(KFileMetaData::ExtractorPlugin) public: explicit XmlExtractor(QObject* parent = nullptr); QStringList mimetypes() const override; void extract(ExtractionResult* result) override; private: }; } #endif // XML_EXTRACTOR_H diff --git a/src/formatstrings.cpp b/src/formatstrings.cpp index dd66c77..cd1ed2f 100644 --- a/src/formatstrings.cpp +++ b/src/formatstrings.cpp @@ -1,220 +1,207 @@ /* - * 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 - * - */ + SPDX-FileCopyrightText: 2018 Alexander Stippich + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "formatstrings_p.h" #include #include #include #include using namespace KFileMetaData; /* * Calculates and returns the number of digits after the * comma to always show three significant digits for use * with KFormat::formatValue. */ int threeSignificantDigits(int value) { if (value == 0) { return 0; } int before_decimal_point = static_cast(log10(value > 0 ? value : -value)) % 3; return 2 - before_decimal_point; } QString FormatStrings::toStringFunction(const QVariant& value) { return value.toString(); } QString FormatStrings::formatDouble(const QVariant& value) { return QLocale().toString(value.toDouble(),'g',3); } QString FormatStrings::formatDate(const QVariant& value) { KFormat form; QDateTime dt; if (value.type() == QVariant::DateTime) { dt = value.toDateTime(); } else { dt = QDateTime::fromString(value.toString(), Qt::ISODate); } if (dt.isValid()) { return form.formatRelativeDateTime(dt, QLocale::LongFormat); } return QString(); } QString FormatStrings::formatDuration(const QVariant& value) { KFormat form; return form.formatDuration(value.toInt() * 1000); } QString FormatStrings::formatBitRate(const QVariant& value) { KFormat form; return i18nc("@label bitrate (per second)", "%1/s", form.formatValue(value.toInt(), KFormat::Unit::Bit, threeSignificantDigits(value.toInt()), KFormat::UnitPrefix::AutoAdjust, KFormat::MetricBinaryDialect)); } QString FormatStrings::formatSampleRate(const QVariant& value) { KFormat form; return form.formatValue(value.toInt(), KFormat::Unit::Hertz, threeSignificantDigits(value.toInt()), KFormat::UnitPrefix::AutoAdjust, KFormat::MetricBinaryDialect); } QString FormatStrings::formatOrientationValue(const QVariant& value) { QString string; switch (value.toInt()) { case 1: string = i18nc("Description of image orientation", "Unchanged"); break; case 2: string = i18nc("Description of image orientation", "Horizontally flipped"); break; case 3: string = i18nc("Description of image orientation", "180° rotated"); break; case 4: string = i18nc("Description of image orientation", "Vertically flipped"); break; case 5: string = i18nc("Description of image orientation", "Transposed"); break; case 6: string = i18nc("Description of image orientation, counter clock-wise rotated", "90° rotated CCW "); break; case 7: string = i18nc("Description of image orientation", "Transversed"); break; case 8: string = i18nc("Description of image orientation, counter clock-wise rotated", "270° rotated CCW"); break; default: break; } return string; } QString FormatStrings::formatPhotoFlashValue(const QVariant& value) { // copied from exiv2 tags_int.cpp const QMap flashTranslation = { { 0x00, i18nc("Description of photo flash", "No flash") }, { 0x01, i18nc("Description of photo flash", "Fired") }, { 0x05, i18nc("Description of photo flash", "Fired, return light not detected") }, { 0x07, i18nc("Description of photo flash", "Fired, return light detected") }, { 0x08, i18nc("Description of photo flash", "Yes, did not fire") }, { 0x09, i18nc("Description of photo flash", "Yes, compulsory") }, { 0x0d, i18nc("Description of photo flash", "Yes, compulsory, return light not detected") }, { 0x0f, i18nc("Description of photo flash", "Yes, compulsory, return light detected") }, { 0x10, i18nc("Description of photo flash", "No, compulsory") }, { 0x14, i18nc("Description of photo flash", "No, did not fire, return light not detected") }, { 0x18, i18nc("Description of photo flash", "No, auto") }, { 0x19, i18nc("Description of photo flash", "Yes, auto") }, { 0x1d, i18nc("Description of photo flash", "Yes, auto, return light not detected") }, { 0x1f, i18nc("Description of photo flash", "Yes, auto, return light detected") }, { 0x20, i18nc("Description of photo flash", "No flash function") }, { 0x30, i18nc("Description of photo flash", "No, no flash function") }, { 0x41, i18nc("Description of photo flash", "Yes, red-eye reduction") }, { 0x45, i18nc("Description of photo flash", "Yes, red-eye reduction, return light not detected") }, { 0x47, i18nc("Description of photo flash", "Yes, red-eye reduction, return light detected") }, { 0x49, i18nc("Description of photo flash", "Yes, compulsory, red-eye reduction") }, { 0x4d, i18nc("Description of photo flash", "Yes, compulsory, red-eye reduction, return light not detected") }, { 0x4f, i18nc("Description of photo flash", "Yes, compulsory, red-eye reduction, return light detected") }, { 0x50, i18nc("Description of photo flash", "No, red-eye reduction") }, { 0x58, i18nc("Description of photo flash", "No, auto, red-eye reduction") }, { 0x59, i18nc("Description of photo flash", "Yes, auto, red-eye reduction") }, { 0x5d, i18nc("Description of photo flash", "Yes, auto, red-eye reduction, return light not detected") }, { 0x5f, i18nc("Description of photo flash", "Yes, auto, red-eye reduction, return light detected") } }; if (flashTranslation.contains(value.toInt())) { return flashTranslation.value(value.toInt()); } else { return i18n("Unknown"); } } QString FormatStrings::formatAsDegree(const QVariant& value) { return i18nc("Symbol of degree, no space", "%1°", QLocale().toString(value.toDouble())); } QString FormatStrings::formatAsMeter(const QVariant& value) { KFormat form; return form.formatValue(value.toDouble(), KFormat::Unit::Meter, 1, KFormat::UnitPrefix::AutoAdjust, KFormat::MetricBinaryDialect); } QString FormatStrings::formatAsMilliMeter(const QVariant& value) { return i18nc("Focal length given in mm", "%1 mm", QLocale().toString(value.toDouble(), 'g', 3)); } QString FormatStrings::formatAsFrameRate(const QVariant& value) { return i18nc("Symbol of frames per second, with space", "%1 fps", QLocale().toString(round(value.toDouble() * 100) / 100)); } QString FormatStrings::formatPhotoTime(const QVariant& value) { auto val = value.toDouble(); if (val < 0.3 && !qFuzzyIsNull(val)) { auto reciprocal = 1.0/val; auto roundedReciprocal = round(reciprocal); if (abs(reciprocal - roundedReciprocal) < 1e-3) { return i18nc("Time period given in seconds as rational number, denominator is given", "1/%1 s", roundedReciprocal); } } return i18nc("Time period given in seconds", "%1 s", QLocale().toString(value.toDouble(), 'g', 3)); } QString FormatStrings::formatPhotoExposureBias(const QVariant& value) { QLocale locale; auto val = value.toDouble(); /* * Exposure values are mostly in steps of one half or third. * Try to construct a rational number from it. * Output as double when it is not possible. */ auto sixthParts = val * 6; int roundedSixthParts = static_cast(round(sixthParts)); int fractional = roundedSixthParts % 6; if (fractional == 0 || abs(sixthParts - roundedSixthParts) > 1e-3) { return i18nc("Exposure bias/compensation in exposure value (EV)", "%1 EV", locale.toString(val, 'g', 3)); } int integral = roundedSixthParts / 6; int nominator = fractional; int denominator = 6; if (nominator % 2 == 0) { nominator = nominator / 2; denominator = denominator / 2; } else if (nominator % 3 == 0) { nominator = nominator / 3; denominator = denominator / 3; } if (integral != 0) { return i18nc("Exposure compensation given as integral with fraction, in exposure value (EV)", "%1 %2/%3 EV", locale.toString(integral), locale.toString(abs(nominator)), locale.toString(denominator)); } return i18nc("Exposure compensation given as rational, in exposure value (EV)", "%1/%2 EV", locale.toString(nominator), locale.toString(denominator)); } QString FormatStrings::formatAspectRatio(const QVariant& value) { return i18nc("Aspect ratio, normalized to one", "%1:1", QLocale().toString(round(value.toDouble() * 100) / 100)); } QString FormatStrings::formatAsFNumber(const QVariant& value) { return i18nc("F number for photographs", "f/%1", QLocale().toString(value.toDouble(), 'g', 2)); } diff --git a/src/formatstrings_p.h b/src/formatstrings_p.h index a3148f9..cb9c2fa 100644 --- a/src/formatstrings_p.h +++ b/src/formatstrings_p.h @@ -1,67 +1,54 @@ /* - * 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 - * - */ + SPDX-FileCopyrightText: 2018 Alexander Stippich + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef KFILEMETADATA_FORMATSTRINGS_P_H #define KFILEMETADATA_FORMATSTRINGS_P_H #include #include namespace KFileMetaData { class Q_DECL_HIDDEN FormatStrings { public: static QString toStringFunction(const QVariant& value); static QString formatDouble(const QVariant& value); static QString formatDate(const QVariant& value); static QString formatDuration(const QVariant& value); static QString formatBitRate(const QVariant& value); static QString formatSampleRate(const QVariant& value); static QString formatOrientationValue(const QVariant& value); static QString formatPhotoFlashValue(const QVariant& value); static QString formatAsDegree(const QVariant& value); static QString formatAsMeter(const QVariant& value); static QString formatAsMilliMeter(const QVariant& value); static QString formatAsFrameRate(const QVariant& value); static QString formatPhotoTime(const QVariant& value); static QString formatPhotoExposureBias(const QVariant& value); static QString formatAspectRatio(const QVariant& value); static QString formatAsFNumber(const QVariant& value); }; } #endif diff --git a/src/mimeutils.cpp b/src/mimeutils.cpp index d09d5da..675b023 100644 --- a/src/mimeutils.cpp +++ b/src/mimeutils.cpp @@ -1,50 +1,37 @@ /* - * This file is part of KFileMetaData - * Copyright (C) 2019 Stefan Brüns - * - * 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 - * - */ + This file is part of KFileMetaData + SPDX-FileCopyrightText: 2019 Stefan Brüns + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "mimeutils.h" namespace KFileMetaData { namespace MimeUtils { QMimeType strictMimeType(const QString& filePath, const QMimeDatabase& db) { auto extensionMimes = db.mimeTypesForFileName(filePath); auto contentMime = db.mimeTypeForFile(filePath, QMimeDatabase::MatchContent); if (extensionMimes.contains(contentMime)) { // content based mime type is one of the types for the file extension, e.g.: // *.ogg -> [ audio/ogg, audio/x-vorbis+ogg, ...] // content -> audio/x-vorbis+ogg return contentMime; } for (const auto &mime : extensionMimes) { // check if the content is generic and the extension is more specific, e.g.: // *.mkv -> [ video/matroska ] // content -> application/matroska if (mime.inherits(contentMime.name())) { return mime; } } // content mime type does not match the extension, trust the content return contentMime; } }} // namespace KFileMetaData::MimeUtils diff --git a/src/mimeutils.h b/src/mimeutils.h index f33e100..ba4aadb 100644 --- a/src/mimeutils.h +++ b/src/mimeutils.h @@ -1,55 +1,42 @@ /* - * This file is part of KFileMetaData - * Copyright (C) 2019 Stefan Brüns - * - * 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 - * - */ + This file is part of KFileMetaData + SPDX-FileCopyrightText: 2019 Stefan Brüns + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef KFILEMETADATA_MIMEUTILS #define KFILEMETADATA_MIMEUTILS #include #include "kfilemetadata_export.h" namespace KFileMetaData { namespace MimeUtils { /** * Returns the mimetype for a file * * The function uses both content and filename to determine the * \c QMimeType. In case the extension mimetype is more specific * than the content mimetype, and the first inherits the latter, * the extension mimetype is preferred. * If the extension does not match the content, the content has * higher priority. * The file must exist and be readable. * * @since 5.57 * * \sa QMimeDatabase::mimeTypesForFileName * \sa QMimeType::inherits */ KFILEMETADATA_EXPORT QMimeType strictMimeType(const QString& filePath, const QMimeDatabase& db); } // namespace MimeUtils } // namespace KFileMetaData #endif // KFILEMETADATA_MIMEUTILS diff --git a/src/properties.h b/src/properties.h index 92d9eed..4d1a183 100644 --- a/src/properties.h +++ b/src/properties.h @@ -1,425 +1,412 @@ /* - * This file is part of KFileMetaData - * 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) 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 - * - */ + This file is part of KFileMetaData + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef KFILEMETADATA_PROPERTIES #define KFILEMETADATA_PROPERTIES #include "kfilemetadata_export.h" #include #include /** @file properties.h */ namespace KFileMetaData { namespace Property { /** * @brief The Property enum contains all files property types that KFileMetaData manipulates * * @todo KF6 remove PropertyCount and LastProperty such that one can easily add new properties */ enum Property { FirstProperty = 0, Empty = 0, /** * The Bit Rate of the Audio in the File. Represented as an integer * in kbit/sec */ BitRate, /** * The number of channels of the Audio in the File. Represented as an * integer. */ Channels, /** * The duration of the media in the file. Represented as an integer * in seconds. */ Duration, /** * The Genre of an Audio file. This s represented as a string * of genres and not integers. The IDv1 standard provides a list of * commonly excepted genres. */ Genre, /** * The same rate or frequency of the Audio in the file. This is represented * as an integer in Hz. So a file with "44.1KHz" will have a frequency * of 44100 */ SampleRate, /** * Represents the track number in a set. Typically maps to the "TRCK" tag * in IDv3 */ TrackNumber, /** * Indicates the year a track was released. Represented as an integer. * Typically mapped to the "TYE (Year)" tag in IDv1 */ ReleaseYear, /** * Represents a comment stored in the file. This can map * to e.g. the "COMM" field from IDv3 */ Comment, /** * Represents the artist of a media file. This generally corresponds * to the IDv1 ARTIST tag. Many extractors often split this string * into a number of artists. */ Artist, /** * Represents the album of a media file. This generally corresponds * to the IDv1 ALBUM tag. */ Album, /** * Represents the album artist of a media file. This generally corresponds * to the IDv3 TPE2 ("Band/Orchestra/Accompaniment") tag. */ AlbumArtist, /** * Represents the Composer of a media file. This generally corresponds * to the IDv2 COMPOSER tag. */ Composer, /** * Represents the Lyricist of a media file. This generally corresponds * to the IDv2 "Lyricist/text writer" tag. */ Lyricist, /** * The Author field indicated the primary creator of a document. * This often corresponds directly to dc:creator */ Author, /** * Refers to the Title of the content of the file. This can represented * by the IDv1 tag TT2 (Title/songname/content description) or the TITLE * in a PDF file or the 'dc:title' tag in DublinCore. */ Title, /** * Refers to the subject of the file. This directly corresponds to the * 'dc:subject' tag from DublinCore. */ Subject, /** * Refers to the Application used to create this file. In the ODF standard * this maps to the 'meta:generator' tag. In PDFs its mapped to the * "Producer" tag. */ Generator, /** * The number of pages in a document */ PageCount, /** * The number of words in a document. This is often only provided for * documents where the word count is available in the metadata. */ WordCount, /** * The number of lines in a document. This is often only provided for * documents where the line count is available in the metadata. */ LineCount, /** * The language the document is written in. This directly maps to the * 'dc:language' tag from DublinCore. We do NOT employ any language * detection schemes on the text. * @since 5.50 */ Language, #if KFILEMETADATA_ENABLE_DEPRECATED_SINCE(5, 50) /** * Same as @c Language. * @deprecated Since 5.50, use @c Language instead */ Langauge = Language, #endif /** * The copyright of the file. Represented as a string. */ Copyright, /** * The publisher of the content. Represented as a string. */ Publisher, /** * The date the content of the file was created. This is extracted * from the File MetaData and not from the file system. * In ODF, it corresponds to "meta:creation-date", in PDF to the * "CreationDate" tag, and otherwise the "dcterms:created" tag. */ CreationDate, /** * The keywords used to represent the document. This is mostly a string list * of all the keywords. */ Keywords, /** * Represents the width of the Media in pixels. This is generally * only applicable for Images and Videos. */ Width, /** * Represents the height of the Media in pixels. This is generally * only applicable for Images and Videos. */ Height, /** * The Aspect Ratio of the visual image or video. * It is the width of a pixel divided by the height of the pixel. */ AspectRatio, /** * Number of frames per second */ FrameRate, /** * The manufacturer of the equipment used for generating the file * and metadata. Typically maps to the 'Exif.Image.Make' tag. * @since 5.60 */ Manufacturer, #if KFILEMETADATA_ENABLE_DEPRECATED_SINCE(5, 60) /** * Same as @c Manufacturer. * @deprecated Since 5.60, use @c Manufacturer instead */ ImageMake = Manufacturer, #endif /** * The model name of the equipment used for generating the file * and metadata. Typically maps to the 'Exif.Image.Model' tag. * @since 5.60 */ Model, #if KFILEMETADATA_ENABLE_DEPRECATED_SINCE(5, 60) /** * Same as @c Model. * @deprecated Since 5.60, use @c Model instead */ ImageModel = Model, #endif ImageDateTime, ImageOrientation, PhotoFlash, PhotoPixelXDimension, PhotoPixelYDimension, PhotoDateTimeOriginal, PhotoFocalLength, PhotoFocalLengthIn35mmFilm, PhotoExposureTime, PhotoFNumber, PhotoApertureValue, PhotoExposureBiasValue, PhotoWhiteBalance, PhotoMeteringMode, PhotoISOSpeedRatings, PhotoSaturation, PhotoSharpness, PhotoGpsLatitude, PhotoGpsLongitude, PhotoGpsAltitude, TranslationUnitsTotal, TranslationUnitsWithTranslation, TranslationUnitsWithDraftTranslation, TranslationLastAuthor, TranslationLastUpDate, TranslationTemplateDate, /** * The URL this file has originally been downloaded from. */ OriginUrl, /** * The subject of the email this file was originally attached to. */ OriginEmailSubject, /** * The sender of the email this file was originally attached to. */ OriginEmailSender, /** * The message ID of the email this file was originally attached to. */ OriginEmailMessageId, /** * Represents the disc number in a multi-disc set. Typically maps to the "TPOS" tag for mp3 */ DiscNumber, /** * Represents the location where an audio file was recorded. */ Location, /** * Represents the (lead) performer of an audio file. */ Performer, /** * Represents the ensemble of an audio file. */ Ensemble, /** * Represents the arranger of an audio file. */ Arranger, /** * Represents the conductor of an audio file. */ Conductor, /** * Represents the opus of an audio file mostly used for classical music. */ Opus, /** * Represents the label of the content. */ Label, /** * Contains the name of the compilation of an audio file. */ Compilation, /** * Contains the license information of the file */ License, /** * For ratings stored in Metadata tags */ Rating, /** * Contains the lyrics of a song embedded in the file */ Lyrics, /** * Contains ReplayGain information for audio files */ ReplayGainAlbumPeak, /** * Contains ReplayGain information for audio files * The album gain is given in "dB" */ ReplayGainAlbumGain, /** * Contains ReplayGain information for audio files */ ReplayGainTrackPeak, /** * Contains ReplayGain information for audio files * The track gain is given in "dB" */ ReplayGainTrackGain, /** * Represents the description stored in the file. This maps * to the 'dc:description' tag from DublinCore */ Description, PropertyCount, LastProperty = PropertyCount-1, }; } // namespace Property typedef QMap PropertyMap; inline QVariantMap toVariantMap(const PropertyMap& propMap) { QVariantMap varMap; PropertyMap::const_iterator it = propMap.constBegin(); for (; it != propMap.constEnd(); ++it) { int p = static_cast(it.key()); varMap.insertMulti(QString::number(p), it.value()); } return varMap; } inline PropertyMap toPropertyMap(const QVariantMap& varMap) { PropertyMap propMap; QVariantMap::const_iterator it = varMap.constBegin(); for (; it != varMap.constEnd(); ++it) { int p = it.key().toInt(); propMap.insertMulti(static_cast(p), it.value()); } return propMap; } } // namespace KFileMetaData Q_DECLARE_METATYPE(KFileMetaData::Property::Property) #endif diff --git a/src/propertyinfo.cpp b/src/propertyinfo.cpp index 8fbdac6..295d761 100644 --- a/src/propertyinfo.cpp +++ b/src/propertyinfo.cpp @@ -1,743 +1,728 @@ /* - * This file is part of the KFileMetaData project - * 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 . - * - */ + This file is part of the KFileMetaData project + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #include "propertyinfo.h" #include #include "formatstrings_p.h" #include using namespace KFileMetaData; class Q_DECL_HIDDEN PropertyInfo::Private { public: Property::Property prop; QString name; QString displayName; QVariant::Type valueType; bool shouldBeIndexed; QString (*formatAsString)(const QVariant& value) = nullptr; }; PropertyInfo::PropertyInfo() : d(new Private) { d->prop = Property::Empty; d->name = QStringLiteral("empty"); d->valueType = QVariant::Invalid; d->shouldBeIndexed = false; d->formatAsString = &FormatStrings::toStringFunction; } PropertyInfo::PropertyInfo(Property::Property property) : d(new Private) { d->prop = property; d->shouldBeIndexed = true; d->formatAsString = &FormatStrings::toStringFunction; switch (property) { case Property::Album: d->name = QStringLiteral("album"); d->displayName = i18nc("@label music album", "Album"); d->valueType = QVariant::String; break; case Property::AlbumArtist: d->name = QStringLiteral("albumArtist"); d->displayName = i18nc("@label", "Album Artist"); d->valueType = QVariant::String; break; case Property::Artist: d->name = QStringLiteral("artist"); d->displayName = i18nc("@label", "Artist"); d->valueType = QVariant::String; break; case Property::AspectRatio: d->name = QStringLiteral("aspectRatio"); d->displayName = i18nc("@label", "Aspect Ratio"); d->valueType = QVariant::Double; d->formatAsString = &FormatStrings::formatAspectRatio; break; case Property::Author: d->name = QStringLiteral("author"); d->displayName = i18nc("@label", "Author"); d->valueType = QVariant::String; break; case Property::BitRate: d->name = QStringLiteral("bitRate"); d->displayName = i18nc("@label", "Bitrate"); d->valueType = QVariant::Int; d->formatAsString = &FormatStrings::formatBitRate; break; case Property::Channels: d->name = QStringLiteral("channels"); d->displayName = i18nc("@label", "Channels"); d->valueType = QVariant::Int; break; case Property::Comment: d->name = QStringLiteral("comment"); d->displayName = i18nc("@label", "Comment"); d->valueType = QVariant::String; d->shouldBeIndexed = false; break; case Property::Description: d->name = QStringLiteral("description"); d->displayName = i18nc("@label", "Description"); d->valueType = QVariant::String; d->shouldBeIndexed = false; break; case Property::Composer: d->name = QStringLiteral("composer"); d->displayName = i18nc("@label", "Composer"); d->valueType = QVariant::String; break; case Property::Copyright: d->name = QStringLiteral("copyright"); d->displayName = i18nc("@label", "Copyright"); d->valueType = QVariant::String; d->shouldBeIndexed = false; break; case Property::CreationDate: d->name = QStringLiteral("creationDate"); d->displayName = i18nc("@label", "Creation Date"); d->valueType = QVariant::DateTime; d->formatAsString = &FormatStrings::formatDate; break; case Property::Duration: d->name = QStringLiteral("duration"); d->displayName = i18nc("@label", "Duration"); d->valueType = QVariant::Int; d->formatAsString = &FormatStrings::formatDuration; break; case Property::Empty: d->name = QStringLiteral("empty"); d->valueType = QVariant::Invalid; break; case Property::FrameRate: d->name = QStringLiteral("frameRate"); d->displayName = i18nc("@label", "Frame Rate"); d->valueType = QVariant::Double; d->formatAsString = &FormatStrings::formatAsFrameRate; break; case Property::Generator: d->name = QStringLiteral("generator"); d->displayName = i18nc("@label", "Document Generated By"); d->valueType = QVariant::String; d->shouldBeIndexed = false; break; case Property::Genre: d->name = QStringLiteral("genre"); d->displayName = i18nc("@label music genre", "Genre"); d->valueType = QVariant::String; break; case Property::Height: d->name = QStringLiteral("height"); d->displayName = i18nc("@label", "Height"); d->valueType = QVariant::Int; break; case Property::ImageDateTime: d->name = QStringLiteral("imageDateTime"); d->displayName = i18nc("@label EXIF", "Image Date Time"); d->valueType = QVariant::DateTime; d->formatAsString = &FormatStrings::formatDate; break; case Property::Manufacturer: d->name = QStringLiteral("manufacturer"); d->displayName = i18nc("@label EXIF", "Manufacturer"); d->valueType = QVariant::String; d->shouldBeIndexed = false; break; case Property::Model: d->name = QStringLiteral("model"); d->displayName = i18nc("@label EXIF", "Model"); d->valueType = QVariant::String; d->shouldBeIndexed = false; break; case Property::ImageOrientation: d->name = QStringLiteral("imageOrientation"); d->displayName = i18nc("@label EXIF", "Image Orientation"); d->valueType = QVariant::Int; d->formatAsString = &FormatStrings::formatOrientationValue; break; case Property::Keywords: d->name = QStringLiteral("keywords"); d->displayName = i18nc("@label", "Keywords"); d->valueType = QVariant::String; d->shouldBeIndexed = false; break; case Property::Language: d->name = QStringLiteral("language"); d->displayName = i18nc("@label", "Language"); d->valueType = QVariant::String; d->shouldBeIndexed = false; break; case Property::LineCount: d->name = QStringLiteral("lineCount"); d->displayName = i18nc("@label number of lines", "Line Count"); d->valueType = QVariant::Int; break; case Property::Lyricist: d->name = QStringLiteral("lyricist"); d->displayName = i18nc("@label", "Lyricist"); d->valueType = QVariant::String; break; case Property::PageCount: d->name = QStringLiteral("pageCount"); d->displayName = i18nc("@label", "Page Count"); d->valueType = QVariant::Int; break; case Property::PhotoApertureValue: d->name = QStringLiteral("photoApertureValue"); d->displayName = i18nc("@label EXIF", "Aperture Value"); d->valueType = QVariant::Double; d->formatAsString = &FormatStrings::formatAsFNumber; break; case Property::PhotoDateTimeOriginal: d->name = QStringLiteral("photoDateTimeOriginal"); d->displayName = i18nc("@label EXIF", "Original Date Time"); d->valueType = QVariant::DateTime; d->formatAsString = &FormatStrings::formatDate; break; case Property::PhotoExposureBiasValue: d->name = QStringLiteral("photoExposureBiasValue"); d->displayName = i18nc("@label EXIF", "Exposure Bias"); d->valueType = QVariant::Double; d->formatAsString = &FormatStrings::formatPhotoExposureBias; break; case Property::PhotoExposureTime: d->name = QStringLiteral("photoExposureTime"); d->displayName = i18nc("@label EXIF", "Exposure Time"); d->valueType = QVariant::Double; d->formatAsString = &FormatStrings::formatPhotoTime; break; case Property::PhotoFlash: d->name = QStringLiteral("photoFlash"); d->displayName = i18nc("@label EXIF", "Flash"); d->valueType = QVariant::Int; d->formatAsString = &FormatStrings::formatPhotoFlashValue; break; case Property::PhotoFNumber: d->name = QStringLiteral("photoFNumber"); d->displayName = i18nc("@label EXIF", "F Number"); d->valueType = QVariant::Double; d->formatAsString = &FormatStrings::formatAsFNumber; break; case Property::PhotoFocalLength: d->name = QStringLiteral("photoFocalLength"); d->displayName = i18nc("@label EXIF", "Focal Length"); d->valueType = QVariant::Double; d->formatAsString = &FormatStrings::formatAsMilliMeter; break; case Property::PhotoFocalLengthIn35mmFilm: d->name = QStringLiteral("photoFocalLengthIn35mmFilm"); d->displayName = i18nc("@label EXIF", "Focal Length 35mm"); d->valueType = QVariant::Double; d->formatAsString = &FormatStrings::formatAsMilliMeter; break; case Property::PhotoGpsLatitude: d->name = QStringLiteral("photoGpsLatitude"); d->displayName = i18nc("@label EXIF", "GPS Latitude"); d->valueType = QVariant::Double; d->formatAsString = &FormatStrings::formatAsDegree; break; case Property::PhotoGpsLongitude: d->name = QStringLiteral("photoGpsLongitude"); d->displayName = i18nc("@label EXIF", "GPS Longitude"); d->valueType = QVariant::Double; d->formatAsString = &FormatStrings::formatAsDegree; break; case Property::PhotoGpsAltitude: d->name = QStringLiteral("photoGpsAltitude"); d->displayName = i18nc("@label EXIF", "GPS Altitude"); d->valueType = QVariant::Double; d->formatAsString = &FormatStrings::formatAsMeter; break; case Property::PhotoISOSpeedRatings: d->name = QStringLiteral("photoISOSpeedRatings"); d->displayName = i18nc("@label EXIF", "ISO Speed Rating"); d->valueType = QVariant::Int; break; case Property::PhotoMeteringMode: d->name = QStringLiteral("photoMeteringMode"); d->displayName = i18nc("@label EXIF", "Metering Mode"); d->valueType = QVariant::Int; break; case Property::PhotoPixelXDimension: d->name = QStringLiteral("photoPixelXDimension"); d->displayName = i18nc("@label EXIF", "X Dimension"); d->valueType = QVariant::Int; break; case Property::PhotoPixelYDimension: d->name = QStringLiteral("photoPixelYDimension"); d->displayName = i18nc("@label EXIF", "Y Dimension"); d->valueType = QVariant::Int; break; case Property::PhotoSaturation: d->name = QStringLiteral("photoSaturation"); d->displayName = i18nc("@label EXIF", "Saturation"); d->valueType = QVariant::Int; break; case Property::PhotoSharpness: d->name = QStringLiteral("photoSharpness"); d->displayName = i18nc("@label EXIF", "Sharpness"); d->valueType = QVariant::Int; break; case Property::PhotoWhiteBalance: d->name = QStringLiteral("photoWhiteBalance"); d->displayName = i18nc("@label EXIF", "White Balance"); d->valueType = QVariant::Int; break; case Property::Publisher: d->name = QStringLiteral("publisher"); d->displayName = i18nc("@label", "Publisher"); d->valueType = QVariant::String; break; case Property::Label: d->name = QStringLiteral("label"); d->displayName = i18nc("@label", "Label"); d->valueType = QVariant::String; break; case Property::ReleaseYear: d->name = QStringLiteral("releaseYear"); d->displayName = i18nc("@label", "Release Year"); d->valueType = QVariant::Int; break; case Property::SampleRate: d->name = QStringLiteral("sampleRate"); d->displayName = i18nc("@label", "Sample Rate"); d->valueType = QVariant::Int; d->formatAsString = &FormatStrings::formatSampleRate; break; case Property::Subject: d->name = QStringLiteral("subject"); d->displayName = i18nc("@label", "Subject"); d->valueType = QVariant::String; d->shouldBeIndexed = false; break; case Property::Title: d->name = QStringLiteral("title"); d->displayName = i18nc("@label", "Title"); d->valueType = QVariant::String; break; case Property::TrackNumber: d->name = QStringLiteral("trackNumber"); d->displayName = i18nc("@label music track number", "Track Number"); d->valueType = QVariant::Int; break; case Property::DiscNumber: d->name = QStringLiteral("discNumber"); d->displayName = i18nc("@label music disc number", "Disc Number"); d->valueType = QVariant::Int; break; case Property::Location: d->name = QStringLiteral("location"); d->displayName = i18nc("@label", "Location"); d->valueType = QVariant::String; break; case Property::Performer: d->name = QStringLiteral("performer"); d->displayName = i18nc("@label", "Performer"); d->valueType = QVariant::String; break; case Property::Ensemble: d->name = QStringLiteral("ensemble"); d->displayName = i18nc("@label", "Ensemble"); d->valueType = QVariant::String; break; case Property::Arranger: d->name = QStringLiteral("arranger"); d->displayName = i18nc("@label", "Arranger"); d->valueType = QVariant::String; break; case Property::Conductor: d->name = QStringLiteral("conductor"); d->displayName = i18nc("@label", "Conductor"); d->valueType = QVariant::String; break; case Property::Compilation: d->name = QStringLiteral("compilation"); d->displayName = i18nc("@label", "Compilation"); d->valueType = QVariant::String; break; case Property::License: d->name = QStringLiteral("license"); d->displayName = i18nc("@label", "License"); d->valueType = QVariant::String; break; case Property::Lyrics: d->name = QStringLiteral("lyrics"); d->displayName = i18nc("@label", "Lyrics"); d->valueType = QVariant::String; break; case Property::Opus: d->name = QStringLiteral("opus"); d->displayName = i18nc("@label", "Opus"); d->valueType = QVariant::Int; break; case Property::Rating: d->name = QStringLiteral("embeddedRating"); d->displayName = i18nc("@label", "Rating"); d->valueType = QVariant::Int; break; case Property::ReplayGainAlbumPeak: d->name = QStringLiteral("replayGainAlbumPeak"); d->displayName = i18nc("@label", "Replay Gain Album Peak"); d->valueType = QVariant::Double; d->formatAsString = &FormatStrings::formatDouble; break; case Property::ReplayGainAlbumGain: d->name = QStringLiteral("replayGainAlbumGain"); d->displayName = i18nc("@label", "Replay Gain Album Gain"); d->valueType = QVariant::Double; d->formatAsString = &FormatStrings::formatDouble; break; case Property::ReplayGainTrackPeak: d->name = QStringLiteral("replayGainTrackPeak"); d->displayName = i18nc("@label", "Replay Gain Track Peak"); d->valueType = QVariant::Double; d->formatAsString = &FormatStrings::formatDouble; break; case Property::ReplayGainTrackGain: d->name = QStringLiteral("replayGainTrackGain"); d->displayName = i18nc("@label", "Replay Gain Track Gain"); d->valueType = QVariant::Double; d->formatAsString = &FormatStrings::formatDouble; break; case Property::Width: d->name = QStringLiteral("width"); d->displayName = i18nc("@label", "Width"); d->valueType = QVariant::Int; break; case Property::WordCount: d->name = QStringLiteral("wordCount"); d->displayName = i18nc("@label number of words", "Word Count"); d->valueType = QVariant::Int; break; case Property::TranslationUnitsTotal: d->name = QStringLiteral("translationUnitsTotal"); d->displayName = i18nc("@label number of translatable strings", "Translatable Units"); d->valueType = QVariant::Int; d->shouldBeIndexed = false; break; case Property::TranslationUnitsWithTranslation: d->name = QStringLiteral("translationUnitsWithTranslation"); d->displayName = i18nc("@label number of translated strings", "Translations"); d->valueType = QVariant::Int; d->shouldBeIndexed = false; break; case Property::TranslationUnitsWithDraftTranslation: d->name = QStringLiteral("translationUnitsWithDraftTranslation"); d->displayName = i18nc("@label number of fuzzy translated strings", "Draft Translations"); d->valueType = QVariant::Int; d->shouldBeIndexed = false; break; case Property::TranslationLastAuthor: d->name = QStringLiteral("translationLastAuthor"); d->displayName = i18nc("@label translation author", "Author"); d->valueType = QVariant::String; d->shouldBeIndexed = false; break; case Property::TranslationLastUpDate: d->name = QStringLiteral("translationLastUpDate"); d->displayName = i18nc("@label translations last update", "Last Update"); d->valueType = QVariant::String; d->shouldBeIndexed = false; d->formatAsString = &FormatStrings::formatDate; break; case Property::TranslationTemplateDate: d->name = QStringLiteral("translationTemplateDate"); d->displayName = i18nc("@label date of template creation8", "Template Creation"); d->valueType = QVariant::String; d->shouldBeIndexed = false; d->formatAsString = &FormatStrings::formatDate; break; case Property::OriginUrl: d->name = QStringLiteral("originUrl"); d->displayName = i18nc("@label the URL a file was originally downloaded from", "Downloaded From"); d->valueType = QVariant::Url; d->shouldBeIndexed = false; break; case Property::OriginEmailSubject: d->name = QStringLiteral("originEmailSubject"); d->displayName = i18nc("@label the subject of an email this file was attached to", "E-Mail Attachment Subject"); d->valueType = QVariant::String; d->shouldBeIndexed = false; break; case Property::OriginEmailSender: d->name = QStringLiteral("originEmailSender"); d->displayName = i18nc("@label the sender of an email this file was attached to", "E-Mail Attachment Sender"); d->valueType = QVariant::String; d->shouldBeIndexed = false; break; case Property::OriginEmailMessageId: d->name = QStringLiteral("originEmailMessageId"); d->displayName = i18nc("@label the message ID of an email this file was attached to", "E-Mail Attachment Message ID"); d->valueType = QVariant::String; d->shouldBeIndexed = false; break; case Property::PropertyCount: // To silence the compiler. break; // NOTE: new properties must also be added to ::fromName() } if (d->valueType == QVariant::Int || d->valueType == QVariant::DateTime || d->valueType == QVariant::Double) { d->shouldBeIndexed = false; } } PropertyInfo::PropertyInfo(const PropertyInfo& pi) : d(new Private(*pi.d)) { } PropertyInfo::~PropertyInfo() { delete d; } PropertyInfo& PropertyInfo::operator=(const PropertyInfo& rhs) { *d = *rhs.d; return *this; } bool PropertyInfo::operator==(const PropertyInfo& rhs) const { return d->name == rhs.d->name && d->displayName == rhs.d->displayName && d->prop == rhs.d->prop && d->shouldBeIndexed == rhs.d->shouldBeIndexed; } QString PropertyInfo::displayName() const { return d->displayName; } QString PropertyInfo::name() const { return d->name; } Property::Property PropertyInfo::property() const { return d->prop; } QVariant::Type PropertyInfo::valueType() const { return d->valueType; } bool PropertyInfo::shouldBeIndexed() const { return d->shouldBeIndexed; } QString PropertyInfo::formatAsDisplayString(const QVariant &value) const { if (value.type() == QVariant::List || value.type() == QVariant::StringList) { if (d->valueType == QVariant::String) { return QLocale().createSeparatedList(value.toStringList()); } else { QStringList displayList; const auto valueList = value.toList(); for (const auto& entry : valueList) { displayList << d->formatAsString(entry); } return QLocale().createSeparatedList(displayList); } } else { return d->formatAsString(value); } } PropertyInfo PropertyInfo::fromName(const QString& name) { static QHash propertyHash = { { QStringLiteral("bitrate"), Property::BitRate }, { QStringLiteral("channels"), Property::Channels }, { QStringLiteral("duration"), Property::Duration }, { QStringLiteral("genre"), Property::Genre }, { QStringLiteral("samplerate"), Property::SampleRate }, { QStringLiteral("tracknumber"), Property::TrackNumber }, { QStringLiteral("discnumber"), Property::DiscNumber }, { QStringLiteral("releaseyear"), Property::ReleaseYear }, { QStringLiteral("comment"), Property::Comment }, { QStringLiteral("description"), Property::Description }, { QStringLiteral("artist"), Property::Artist }, { QStringLiteral("album"), Property::Album }, { QStringLiteral("albumartist"), Property::AlbumArtist }, { QStringLiteral("composer"), Property::Composer }, { QStringLiteral("lyricist"), Property::Lyricist }, { QStringLiteral("location"), Property::Location }, { QStringLiteral("performer"), Property::Performer }, { QStringLiteral("ensemble"), Property::Ensemble }, { QStringLiteral("arranger"), Property::Arranger }, { QStringLiteral("conductor"), Property::Conductor }, { QStringLiteral("opus"), Property::Opus }, { QStringLiteral("embeddedrating"), Property::Rating }, { QStringLiteral("author"), Property::Author }, { QStringLiteral("title"), Property::Title }, { QStringLiteral("subject"), Property::Subject }, { QStringLiteral("generator"), Property::Generator }, { QStringLiteral("pagecount"), Property::PageCount }, { QStringLiteral("wordcount"), Property::WordCount }, { QStringLiteral("linecount"), Property::LineCount }, { QStringLiteral("language"), Property::Language }, { QStringLiteral("copyright"), Property::Copyright }, { QStringLiteral("publisher"), Property::Publisher }, { QStringLiteral("label"), Property::Label }, { QStringLiteral("compilation"), Property::Compilation }, { QStringLiteral("license"), Property::License }, { QStringLiteral("lyrics"), Property::Lyrics }, { QStringLiteral("replaygainalbumpeak"), Property::ReplayGainAlbumPeak }, { QStringLiteral("replaygainalbumgain"), Property::ReplayGainAlbumGain }, { QStringLiteral("replaygaintrackpeak"), Property::ReplayGainTrackPeak }, { QStringLiteral("replaygaintrackgain"), Property::ReplayGainTrackGain }, { QStringLiteral("creationdate"), Property::CreationDate }, { QStringLiteral("keywords"), Property::Keywords }, { QStringLiteral("width"), Property::Width }, { QStringLiteral("height"), Property::Height }, { QStringLiteral("aspectratio"), Property::AspectRatio }, { QStringLiteral("framerate"), Property::FrameRate }, { QStringLiteral("manufacturer"), Property::Manufacturer }, { QStringLiteral("model"), Property::Model }, { QStringLiteral("imagedatetime"), Property::ImageDateTime }, { QStringLiteral("imageorientation"), Property::ImageOrientation }, { QStringLiteral("photoflash"), Property::PhotoFlash }, { QStringLiteral("photopixelxdimension"), Property::PhotoPixelXDimension }, { QStringLiteral("photopixelydimension"), Property::PhotoPixelYDimension }, { QStringLiteral("photodatetimeoriginal"), Property::PhotoDateTimeOriginal }, { QStringLiteral("photofocallength"), Property::PhotoFocalLength }, { QStringLiteral("photofocallengthin35mmfilm"), Property::PhotoFocalLengthIn35mmFilm }, { QStringLiteral("photoexposuretime"), Property::PhotoExposureTime }, { QStringLiteral("photofnumber"), Property::PhotoFNumber }, { QStringLiteral("photoaperturevalue"), Property::PhotoApertureValue }, { QStringLiteral("photoexposurebiasvalue"), Property::PhotoExposureBiasValue }, { QStringLiteral("photowhitebalance"), Property::PhotoWhiteBalance }, { QStringLiteral("photometeringmode"), Property::PhotoMeteringMode }, { QStringLiteral("photoisospeedratings"), Property::PhotoISOSpeedRatings }, { QStringLiteral("photosaturation"), Property::PhotoSaturation }, { QStringLiteral("photosharpness"), Property::PhotoSharpness }, { QStringLiteral("photogpslatitude"), Property::PhotoGpsLatitude }, { QStringLiteral("photogpslongitude"), Property::PhotoGpsLongitude }, { QStringLiteral("photogpsaltitude"), Property::PhotoGpsAltitude }, { QStringLiteral("translationunitstotal"), Property::TranslationUnitsTotal }, { QStringLiteral("translationunitswithtranslation"), Property::TranslationUnitsWithTranslation }, { QStringLiteral("translationunitswithdrafttranslation"), Property::TranslationUnitsWithDraftTranslation }, { QStringLiteral("translationlastauthor"), Property::TranslationLastAuthor }, { QStringLiteral("translationlastupdate"), Property::TranslationLastUpDate }, { QStringLiteral("translationtemplatedate"), Property::TranslationTemplateDate }, { QStringLiteral("originurl"), Property::OriginUrl }, { QStringLiteral("originemailsubject"), Property::OriginEmailSubject }, { QStringLiteral("originemailsender"), Property::OriginEmailSender }, { QStringLiteral("originemailmessageid"), Property::OriginEmailMessageId } }; return PropertyInfo(propertyHash.value(name.toLower())); } diff --git a/src/propertyinfo.h b/src/propertyinfo.h index 1b5fa2f..98a42f4 100644 --- a/src/propertyinfo.h +++ b/src/propertyinfo.h @@ -1,105 +1,90 @@ /* - * This file is part of the KFileMetaData project - * 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 . - * - */ + This file is part of the KFileMetaData project + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #ifndef _KFILEMETADATA_PROPERTYINFO_H #define _KFILEMETADATA_PROPERTYINFO_H #include #include #include "properties.h" #include "kfilemetadata_export.h" namespace KFileMetaData { /** * \class PropertyInfo propertyinfo.h * * The PropertyInfo class can be used to obtain extra information * about any property. It is commonly used be indexers in order * to obtain a translatable name of the property along with * additional information such as if the property should be indexed. */ class KFILEMETADATA_EXPORT PropertyInfo { public: PropertyInfo(); PropertyInfo(Property::Property property); PropertyInfo(const PropertyInfo& pi); ~PropertyInfo(); PropertyInfo& operator=(const PropertyInfo& rhs); bool operator==(const PropertyInfo& rhs) const; /** * The enumeration which represents this property */ Property::Property property() const; /** * The internal unique name used to refer to the property */ QString name() const; /** * A user visible name of the property */ QString displayName() const; /** * The type the value of this property should be. * Eg - Property::Height should be an integer */ QVariant::Type valueType() const; /** * Indicates if this property requires indexing or should just be stored. * Eg - Property::Height does not need to be part of the global index. * When a user searches for 600, they should not get images with * that height * * This is just a recommendation. */ bool shouldBeIndexed() const; /** * Construct a PropertyInfo from the internal property name. * The internal property name is case insensitive */ static PropertyInfo fromName(const QString& name); /** * Returns the value of the property as a QString with added formatting, * added units if needed, and translated enums. * @since 5.56 */ QString formatAsDisplayString(const QVariant& value) const; private: class Private; Private* d; }; } // namespace Q_DECLARE_METATYPE(KFileMetaData::PropertyInfo) #endif // _KFILEMETADATA_PROPERTYINFO_H diff --git a/src/simpleextractionresult.cpp b/src/simpleextractionresult.cpp index 7d923f4..a155a84 100644 --- a/src/simpleextractionresult.cpp +++ b/src/simpleextractionresult.cpp @@ -1,90 +1,77 @@ /* - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "simpleextractionresult.h" using namespace KFileMetaData; class Q_DECL_HIDDEN SimpleExtractionResult::Private { public: PropertyMap m_properties; QString m_text; QVector m_types; }; SimpleExtractionResult::SimpleExtractionResult(const QString& url, const QString& mimetype, const Flags& flags) : ExtractionResult(url, mimetype, flags) , d(new Private) { } SimpleExtractionResult::SimpleExtractionResult(const SimpleExtractionResult& rhs) : ExtractionResult(*this) , d(new Private(*rhs.d)) { } SimpleExtractionResult::~SimpleExtractionResult() { delete d; } SimpleExtractionResult& SimpleExtractionResult::operator=(const SimpleExtractionResult& rhs) { *d = *rhs.d; return *this; } bool SimpleExtractionResult::operator==(const SimpleExtractionResult& rhs) const { return d->m_properties == rhs.d->m_properties && d->m_text == rhs.d->m_text && d->m_types == rhs.d->m_types; } void SimpleExtractionResult::add(Property::Property property, const QVariant& value) { d->m_properties.insertMulti(property, value); } void SimpleExtractionResult::addType(Type::Type type) { d->m_types << type; } void SimpleExtractionResult::append(const QString& text) { d->m_text.append(text); d->m_text.append(QLatin1Char(' ')); } PropertyMap SimpleExtractionResult::properties() const { return d->m_properties; } QString SimpleExtractionResult::text() const { return d->m_text; } QVector SimpleExtractionResult::types() const { return d->m_types; } diff --git a/src/simpleextractionresult.h b/src/simpleextractionresult.h index 7070aea..d0821c3 100644 --- a/src/simpleextractionresult.h +++ b/src/simpleextractionresult.h @@ -1,64 +1,51 @@ /* - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef KFILEMETADATA_SimpleExtractionResult_H #define KFILEMETADATA_SimpleExtractionResult_H #include "extractionresult.h" #include #include namespace KFileMetaData { /** * \class SimpleExtractionResult simpleextractionresult.h * * A simple ExtractionResult implementation which stores * all the data in memory. * * This should ideally not be used in production applications as * it holds all of the plain text in memory, and that can get quite large * when extracting certain documents. */ class KFILEMETADATA_EXPORT SimpleExtractionResult : public ExtractionResult { public: SimpleExtractionResult(const QString& url, const QString& mimetype = QString(), const Flags& flags = ExtractEverything); SimpleExtractionResult(const SimpleExtractionResult& rhs); ~SimpleExtractionResult() override; SimpleExtractionResult& operator=(const SimpleExtractionResult& rhs); bool operator==(const SimpleExtractionResult& rhs) const; void add(Property::Property property, const QVariant& value) override; void addType(Type::Type type) override; void append(const QString& text) override; PropertyMap properties() const; QString text() const; QVector types() const; private: class Private; Private* d; }; } #endif // KFILEMETADATA_SimpleExtractionResult_H diff --git a/src/typeinfo.cpp b/src/typeinfo.cpp index c5249e1..332feee 100644 --- a/src/typeinfo.cpp +++ b/src/typeinfo.cpp @@ -1,139 +1,125 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "typeinfo.h" #include using namespace KFileMetaData; class Q_DECL_HIDDEN TypeInfo::Private { public: Type::Type type; QString name; QString displayName; }; TypeInfo::TypeInfo(Type::Type type) : d(new Private) { d->type = type; switch (type) { case Type::Empty: d->name = QStringLiteral("empty"); d->displayName = QString(); break; case Type::Archive: d->name = QStringLiteral("Archive"); d->displayName = i18nc("@label", "Archive"); break; case Type::Audio: d->name = QStringLiteral("Audio"); d->displayName = i18nc("@label", "Audio"); break; case Type::Document: d->name = QStringLiteral("Document"); d->displayName = i18nc("@label", "Document"); break; case Type::Image: d->name = QStringLiteral("Image"); d->displayName = i18nc("@label", "Image"); break; case Type::Presentation: d->name = QStringLiteral("Presentation"); d->displayName = i18nc("@label", "Presentation"); break; case Type::Spreadsheet: d->name = QStringLiteral("Spreadsheet"); d->displayName = i18nc("@label", "Spreadsheet"); break; case Type::Text: d->name = QStringLiteral("Text"); d->displayName = i18nc("@label", "Text"); break; case Type::Video: d->name = QStringLiteral("Video"); d->displayName = i18nc("@label", "Video"); break; case Type::Folder: d->name = QStringLiteral("Folder"); d->displayName = i18nc("@label", "Folder"); break; } } TypeInfo::TypeInfo(const TypeInfo& ti) : d(new Private(*ti.d)) { } TypeInfo::~TypeInfo() { delete d; } TypeInfo& TypeInfo::operator=(const TypeInfo& rhs) { *d = *rhs.d; return *this; } bool TypeInfo::operator==(const TypeInfo& rhs) { return d->type == rhs.d->type && d->name == rhs.d->name && d->displayName == rhs.d->displayName; } QString TypeInfo::displayName() const { return d->displayName; } QString TypeInfo::name() const { return d->name; } Type::Type TypeInfo::type() const { return d->type; } TypeInfo TypeInfo::fromName(const QString& name) { for (int t = static_cast(Type::FirstType); t <= static_cast(Type::LastType); t++) { TypeInfo ti(static_cast(t)); if (ti.name().compare(name, Qt::CaseInsensitive) == 0) { return ti; } } return TypeInfo(Type::Empty); } diff --git a/src/typeinfo.h b/src/typeinfo.h index f79ae0e..ae0937f 100644 --- a/src/typeinfo.h +++ b/src/typeinfo.h @@ -1,70 +1,56 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef KFILEMETADATA_TYPEINFO_H #define KFILEMETADATA_TYPEINFO_H #include "types.h" #include "kfilemetadata_export.h" #include namespace KFileMetaData { /** * \class TypeInfo typeinfo.h */ class KFILEMETADATA_EXPORT TypeInfo { public: TypeInfo(Type::Type type); TypeInfo(const TypeInfo& ti); ~TypeInfo(); TypeInfo& operator=(const TypeInfo& rhs); bool operator==(const TypeInfo& rhs); /** * The type identifier */ Type::Type type() const; /** * An internal unique name for the type */ QString name() const; /** * A user visible translated name for this type */ QString displayName() const; /** * Construct a TypeInfo from the internal type name. * The internal type name is case insensitive */ static TypeInfo fromName(const QString& name); private: class Private; Private* d; }; } #endif // KFILEMETADATA_TYPEINFO_H diff --git a/src/types.h b/src/types.h index c1a3a11..3dfb718 100644 --- a/src/types.h +++ b/src/types.h @@ -1,94 +1,81 @@ /* - * This file is part of KFileMetaData - * 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) 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 - * - */ + This file is part of KFileMetaData + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef KFILEMETADATA_TYPES #define KFILEMETADATA_TYPES namespace KFileMetaData { namespace Type { /** * A Type represents a way to represent a way to group files based on * a higher level view, which the user generally expects. * * Every extractor provides a list of types applicable for each file. */ enum Type { FirstType = 0, Empty = 0, /** * Any file which contains a compressed collection of other files * eg - tar, zip, rar, gz */ Archive, /** * Used to mark any file which just contains audio. Do not use this * type if the file also contains Video */ Audio, /** * Any file which contains Video. It may also contain Audio */ Video, /** * Any Image file. This includes both raster and vector formats. */ Image, /** * Any file which counts as a document. Documents are generally * files which contain rich text, formatting and maybe images */ Document, /** * A SpreadSheet file. This is a specialization of the Document type * Any file which has this type should also have the Document type */ Spreadsheet, /** * A Presentation file. This is a specialization of the Document type. * Any file which has this type should also have the Document type */ Presentation, /** * Any file which just contains plain text data counts * as a Text file */ Text, /** * A directory or folder */ Folder, LastType = Folder }; } } #endif diff --git a/src/usermetadata.cpp b/src/usermetadata.cpp index 3f3ba0b..952ef01 100644 --- a/src/usermetadata.cpp +++ b/src/usermetadata.cpp @@ -1,221 +1,208 @@ /* - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "usermetadata.h" #include "xattr_p.h" using namespace KFileMetaData; class Q_DECL_HIDDEN UserMetaData::Private { public: QString filePath; }; UserMetaData::UserMetaData(const QString& filePath) : d(new Private) { d->filePath = filePath; } UserMetaData::UserMetaData(const UserMetaData& rhs) : d(new Private(*rhs.d)) { } UserMetaData::~UserMetaData() { delete d; } const UserMetaData& UserMetaData::operator=(const UserMetaData& rhs) { d->filePath = rhs.d->filePath; return *this; } QString UserMetaData::filePath() const { return d->filePath; } UserMetaData::Error UserMetaData::setTags(const QStringList& tags) { if (!tags.isEmpty()) { k_setxattr(d->filePath, QStringLiteral("user.xdg.tags"), tags.join(QLatin1Char(','))); } else { k_removexattr(d->filePath, QStringLiteral("user.xdg.tags")); } return NoError; } QStringList UserMetaData::tags() const { QString value; k_getxattr(d->filePath, QStringLiteral("user.xdg.tags"), &value); return value.split(QLatin1Char(','), QString::SkipEmptyParts); } int UserMetaData::rating() const { QString value; k_getxattr(d->filePath, QStringLiteral("user.baloo.rating"), &value); return value.toInt(); } UserMetaData::Error UserMetaData::setRating(int rating) { if (rating) { k_setxattr(d->filePath, QStringLiteral("user.baloo.rating"), QString::number(rating)); } else { k_removexattr(d->filePath, QStringLiteral("user.baloo.rating")); } return NoError; } QString UserMetaData::userComment() const { QString value; k_getxattr(d->filePath, QStringLiteral("user.xdg.comment"), &value); return value; } UserMetaData::Error UserMetaData::setUserComment(const QString& userComment) { if (!userComment.isEmpty()) { k_setxattr(d->filePath, QStringLiteral("user.xdg.comment"), userComment); } else { k_removexattr(d->filePath, QStringLiteral("user.xdg.comment")); } return NoError; } QUrl UserMetaData::originUrl() const { QString value; k_getxattr(d->filePath, QStringLiteral("user.xdg.origin.url"), &value); return QUrl(value); } UserMetaData::Error UserMetaData::setOriginUrl(const QUrl &originUrl) { if (!originUrl.isEmpty()) { k_setxattr(d->filePath, QStringLiteral("user.xdg.origin.url"), originUrl.toString()); } else { k_removexattr(d->filePath, QStringLiteral("user.xdg.origin.url")); } return NoError; } QString UserMetaData::originEmailSubject() const { QString value; k_getxattr(d->filePath, QStringLiteral("user.xdg.origin.email.subject"), &value); return value; } UserMetaData::Error UserMetaData::setOriginEmailSubject(const QString &originEmailSubject) { if (!originEmailSubject.isEmpty()) { k_setxattr(d->filePath, QStringLiteral("user.xdg.origin.email.subject"), originEmailSubject); } else { k_removexattr(d->filePath, QStringLiteral("user.xdg.origin.email.subject")); } return NoError; } QString UserMetaData::originEmailSender() const { QString value; k_getxattr(d->filePath, QStringLiteral("user.xdg.origin.email.sender"), &value); return value; } UserMetaData::Error UserMetaData::setOriginEmailSender(const QString &originEmailSender) { if (!originEmailSender.isEmpty()) { k_setxattr(d->filePath, QStringLiteral("user.xdg.origin.email.sender"), originEmailSender); } else { k_removexattr(d->filePath, QStringLiteral("user.xdg.origin.email.sender")); } return NoError; } QString UserMetaData::originEmailMessageId() const { QString value; k_getxattr(d->filePath, QStringLiteral("user.xdg.origin.email.message-id"), &value); return value; } UserMetaData::Error UserMetaData::setOriginEmailMessageId(const QString &originEmailMessageId) { if (!originEmailMessageId.isEmpty()) { k_setxattr(d->filePath, QStringLiteral("user.xdg.origin.email.message-id"), originEmailMessageId); } else { k_removexattr(d->filePath, QStringLiteral("user.xdg.origin.email.message-id")); } return NoError; } UserMetaData::Error UserMetaData::setAttribute(const QString& key, const QString& value) { if (!value.isEmpty()) { k_setxattr(d->filePath, QStringLiteral("user.") + key, value); } else { k_removexattr(d->filePath, QStringLiteral("user.") + key); } return NoError; } bool UserMetaData::hasAttribute(const QString& key) { return k_hasAttribute(d->filePath, QStringLiteral("user.") + key); } QString UserMetaData::attribute(const QString& key) { QString value; k_getxattr(d->filePath, QStringLiteral("user.") + key, &value); return value; } bool UserMetaData::isSupported() const { return k_isSupported(d->filePath); } UserMetaData::Attributes UserMetaData::queryAttributes(UserMetaData::Attributes attributes) const { return k_queryAttributes(d->filePath, attributes); } diff --git a/src/usermetadata.h b/src/usermetadata.h index 78c2c17..ef0c3a0 100644 --- a/src/usermetadata.h +++ b/src/usermetadata.h @@ -1,117 +1,103 @@ /* - * - * 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) 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 - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef KFILEMETADATA_USERMETADATA_H #define KFILEMETADATA_USERMETADATA_H #include "kfilemetadata_export.h" #include #include namespace KFileMetaData { /** * \class UserMetaData usermetadata.h */ class KFILEMETADATA_EXPORT UserMetaData { public: UserMetaData(const QString &filePath); UserMetaData(const UserMetaData &rhs); virtual ~UserMetaData(); enum Error { NoError = 0 }; /** * @see Attributes */ enum Attribute : uint32_t { None = 0x0, Any = None, Tags = 0x1, Rating = 0x2, Comment = 0x4, OriginUrl = 0x8, OriginEmailSubject = 0x10, OriginEmailSender = 0x20, OriginEmailMessageId = 0x40, Other = 0xffffff80, All = 0xffffffff, }; /** * Stores a combination of #Attribute values. */ Q_DECLARE_FLAGS(Attributes, Attribute) const UserMetaData& operator =(const UserMetaData& rhs); QString filePath() const; bool isSupported() const; Error setTags(const QStringList& tags); QStringList tags() const; int rating() const; Error setRating(int rating); QString userComment() const; Error setUserComment(const QString& userComment); QUrl originUrl() const; Error setOriginUrl(const QUrl &originUrl); QString originEmailSubject() const; Error setOriginEmailSubject(const QString &originEmailSubject); QString originEmailSender() const; Error setOriginEmailSender(const QString &originEmailSender); QString originEmailMessageId() const; Error setOriginEmailMessageId(const QString &originEmailMessageId); QString attribute(const QString& name); Error setAttribute(const QString& name, const QString& value); bool hasAttribute(const QString& name); /** * Query list of available attributes * * Checks for the availability of the given \p attributes. May return * a superset of the input value when the file has attributes set * beyond the requested ones. * * If the input attribute mask is Attribute::Any, either Attribute::None * (the file has no user attributes) or Attribute::All (the file has at * least one attribute set) is returned. * * \since 5.60 */ Attributes queryAttributes(Attributes attributes = Attribute::Any) const; private: class Private; Private *d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(UserMetaData::Attributes) } #endif // KFILEMETADATA_USERMETADATA_H diff --git a/src/writedata.cpp b/src/writedata.cpp index c1c88e2..8f2bf94 100644 --- a/src/writedata.cpp +++ b/src/writedata.cpp @@ -1,95 +1,80 @@ /* - * 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 . - * - */ + This file is part of the KFileMetaData project + SPDX-FileCopyrightText: 2016 Varun Joshi + SPDX-FileCopyrightText: 2016 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #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/writedata.h b/src/writedata.h index f1763eb..0e3e451 100644 --- a/src/writedata.h +++ b/src/writedata.h @@ -1,65 +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 . - * - */ + This file is part of the KFileMetaData project + SPDX-FileCopyrightText: 2016 Varun Joshi + SPDX-FileCopyrightText: 2016 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #ifndef _KFILEMETADATA_WRITEDATA_H #define _KFILEMETADATA_WRITEDATA_H #include "kfilemetadata_export.h" #include #include #include #include "properties.h" #include "types.h" namespace KFileMetaData { /** * \class WriteData writedata.h */ class KFILEMETADATA_EXPORT WriteData { public: WriteData(const QString& url, const QString& mimetype); WriteData(const WriteData& rhs); virtual ~WriteData(); WriteData& operator=(const WriteData& rhs); bool operator==(const WriteData& rhs) const; QString inputUrl() const; QString inputMimetype() const; void add(Property::Property property, const QVariant& value); QMap getAllProperties() const; private: class WriteDataPrivate; WriteDataPrivate* d_ptr; Q_DECLARE_PRIVATE(WriteData) }; } #endif // _KFILEMETADATA_WRITEDATA_H diff --git a/src/writer.cpp b/src/writer.cpp index 56269bd..9af52ec 100644 --- a/src/writer.cpp +++ b/src/writer.cpp @@ -1,60 +1,45 @@ /* - * 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 . - * - */ + This file is part of the KFileMetaData project + SPDX-FileCopyrightText: 2016 Varun Joshi + SPDX-FileCopyrightText: 2016 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #include "writer.h" #include "writer_p.h" #include "writerplugin.h" using namespace KFileMetaData; Writer::Writer() : d(new WriterPrivate) { } Writer::~Writer() { delete d; } Writer::Writer(Writer&& other) { d = other.d; other.d = nullptr; } void Writer::write(const WriteData& data) { d->m_plugin->write(data); } QStringList Writer::mimetypes() const { 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 4e00392..6fc3fca 100644 --- a/src/writer.h +++ b/src/writer.h @@ -1,68 +1,53 @@ /* - * 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 . - * - */ + This file is part of the KFileMetaData project + SPDX-FileCopyrightText: 2016 Varun Joshi + SPDX-FileCopyrightText: 2016 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #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&); 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 02e0348..ba25f55 100644 --- a/src/writer_p.h +++ b/src/writer_p.h @@ -1,50 +1,35 @@ /* - * 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 . - * - */ + This file is part of the KFileMetaData project + SPDX-FileCopyrightText: 2016 Varun Joshi + SPDX-FileCopyrightText: 2016 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #ifndef KFILEMETADATA_WRITER_P_H #define KFILEMETADATA_WRITER_P_H #include "writerplugin.h" namespace KFileMetaData { class WriterPlugin; 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 4c7b896..d2d7a39 100644 --- a/src/writercollection.cpp +++ b/src/writercollection.cpp @@ -1,174 +1,159 @@ /* - * 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 . - * - */ + This file is part of the KFileMetaData project + SPDX-FileCopyrightText: 2016 Varun Joshi + SPDX-FileCopyrightText: 2016 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #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: QMultiHash m_writers; std::vector m_allWriters; void findWriters(); }; WriterCollection::WriterCollection() : d(new WriterCollectionPrivate) { d->findWriters(); } WriterCollection::~WriterCollection() { delete d; } 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(); 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; writer.d->m_plugin = plugin; writer.setAutoDeletePlugin(Writer::DoNotDeletePlugin); 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; writer.d->m_plugin = plugin; writer.setAutoDeletePlugin(Writer::AutoDeletePlugin); m_allWriters.push_back(std::move(writer)); } for (Writer& writer : m_allWriters) { const QStringList lst = writer.mimetypes(); for (const QString& type : lst) { m_writers.insert(type, &writer); } } } QList WriterCollection::fetchWriters(const QString& mimetype) const { QList plugins = d->m_writers.values(mimetype); 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 7246d64..6ae83a3 100644 --- a/src/writercollection.h +++ b/src/writercollection.h @@ -1,52 +1,37 @@ /* - * 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 . - * - */ + This file is part of the KFileMetaData project + SPDX-FileCopyrightText: 2016 Varun Joshi + SPDX-FileCopyrightText: 2016 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #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; }; } #endif // _KFILEMETADTA_WRITERCOLLECTION_H diff --git a/src/writerplugin.cpp b/src/writerplugin.cpp index cb28621..0d469d7 100644 --- a/src/writerplugin.cpp +++ b/src/writerplugin.cpp @@ -1,35 +1,20 @@ /* - * 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 . - * - */ + This file is part of the KFileMetaData project + SPDX-FileCopyrightText: 2016 Varun Joshi + SPDX-FileCopyrightText: 2016 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #include "writerplugin.h" using namespace KFileMetaData; WriterPlugin::WriterPlugin(QObject* parent): QObject(parent) { } WriterPlugin::~WriterPlugin() { } diff --git a/src/writerplugin.h b/src/writerplugin.h index 1524098..28a06f1 100644 --- a/src/writerplugin.h +++ b/src/writerplugin.h @@ -1,52 +1,37 @@ /* - * 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 . - * - */ + This file is part of the KFileMetaData project + SPDX-FileCopyrightText: 2016 Varun Joshi + SPDX-FileCopyrightText: 2016 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #ifndef _KFILEMETADTA_WRITERPLUGIN_H #define _KFILEMETADTA_WRITERPLUGIN_H #include "kfilemetadata_export.h" #include #include "writedata.h" namespace KFileMetaData { /** * \class WriterPlugin writerplugin.h */ class KFILEMETADATA_EXPORT WriterPlugin : public QObject { Q_OBJECT public: explicit WriterPlugin(QObject* parent); virtual ~WriterPlugin(); virtual QStringList writeMimetypes() const = 0; virtual void write(const WriteData& data) = 0; }; } Q_DECLARE_INTERFACE(KFileMetaData::WriterPlugin, "org.kde.kf5.kfilemetadata.WriterPlugin") #endif // _KFILEMETADTA_WRITERPLUGIN_H diff --git a/src/writers/taglibwriter.cpp b/src/writers/taglibwriter.cpp index aaecaf3..b765bbc 100644 --- a/src/writers/taglibwriter.cpp +++ b/src/writers/taglibwriter.cpp @@ -1,358 +1,345 @@ /* - * Copyright (C) 2016 Varun Joshi - * 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 - * - */ + SPDX-FileCopyrightText: 2016 Varun Joshi + SPDX-FileCopyrightText: 2018 Alexander Stippich + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #include "taglibwriter.h" #include "kfilemetadata_debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { const QStringList supportedMimeTypes = { 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-aifc"), 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+ogg"), QStringLiteral("audio/x-vorbis+ogg"), QStringLiteral("audio/x-wav"), QStringLiteral("audio/x-wavpack"), }; int id3v2RatingTranslation[11] = { 0, 1, 13, 54, 64, 118, 128, 186, 196, 242, 255 }; using namespace KFileMetaData; void writeID3v2Tags(TagLib::ID3v2::Tag *id3Tags, const PropertyMap &newProperties) { if (newProperties.contains(Property::Rating)) { int rating = newProperties.value(Property::Rating).toInt(); if (rating >= 0 && rating <= 10) { id3Tags->removeFrames("POPM"); auto ratingFrame = new TagLib::ID3v2::PopularimeterFrame; ratingFrame->setEmail("org.kde.kfilemetadata"); ratingFrame->setRating(id3v2RatingTranslation[rating]); id3Tags->addFrame(ratingFrame); } } } void writeApeTags(TagLib::PropertyMap &oldProperties, const PropertyMap &newProperties) { if (newProperties.contains(Property::Rating)) { oldProperties.replace("RATING", TagLib::String::number(newProperties.value(Property::Rating).toInt() * 10)); } } void writeVorbisTags(TagLib::PropertyMap &oldProperties, const PropertyMap &newProperties) { if (newProperties.contains(Property::Rating)) { oldProperties.replace("RATING", TagLib::String::number(newProperties.value(Property::Rating).toInt() * 10)); } } void writeAsfTags(TagLib::ASF::Tag *asfTags, const PropertyMap &properties) { if (properties.contains(Property::Rating)) { //map the rating values of WMP to Baloo rating //0->0, 1->2, 4->25, 6->50, 8->75, 10->99 int rating = properties.value(Property::Rating).toInt(); if (rating == 0) { rating = 0; } else if (rating <= 2) { rating = 1; } else if (rating == 10){ rating = 99; } else { rating = static_cast(12.5 * rating - 25); } asfTags->setAttribute("WM/SharedUserRating", TagLib::String::number(rating)); } } void writeMp4Tags(TagLib::MP4::Tag *mp4Tags, const PropertyMap &newProperties) { if (newProperties.contains(Property::Rating)) { mp4Tags->setItem("rate", TagLib::StringList(TagLib::String::number(newProperties.value(Property::Rating).toInt() * 10))); } } } // anonymous namespace void writeGenericProperties(TagLib::PropertyMap &oldProperties, const PropertyMap &newProperties) { if (newProperties.contains(Property::Title)) { oldProperties.replace("TITLE", QStringToTString(newProperties.value(Property::Title).toString())); } if (newProperties.contains(Property::Artist)) { oldProperties.replace("ARTIST", QStringToTString(newProperties.value(Property::Artist).toString())); } if (newProperties.contains(Property::AlbumArtist)) { oldProperties.replace("ALBUMARTIST", QStringToTString(newProperties.value(Property::AlbumArtist).toString())); } if (newProperties.contains(Property::Album)) { oldProperties.replace("ALBUM", QStringToTString(newProperties.value(Property::Album).toString())); } if (newProperties.contains(Property::TrackNumber)) { int trackNumber = newProperties.value(Property::TrackNumber).toInt(); //taglib requires uint if (trackNumber >= 0) { oldProperties.replace("TRACKNUMBER", QStringToTString(newProperties.value(Property::TrackNumber).toString())); } } if (newProperties.contains(Property::DiscNumber)) { int discNumber = newProperties.value(Property::DiscNumber).toInt(); //taglib requires uint if (discNumber >= 0) { oldProperties.replace("DISCNUMBER", QStringToTString(newProperties.value(Property::DiscNumber).toString())); } } if (newProperties.contains(Property::ReleaseYear)) { int year = newProperties.value(Property::ReleaseYear).toInt(); //taglib requires uint if (year >= 0) { oldProperties.replace("DATE", QStringToTString(newProperties.value(Property::ReleaseYear).toString())); } } if (newProperties.contains(Property::Genre)) { oldProperties.replace("GENRE", QStringToTString(newProperties.value(Property::Genre).toString())); } if (newProperties.contains(Property::Comment)) { oldProperties.replace("COMMENT", QStringToTString(newProperties.value(Property::Comment).toString())); } if (newProperties.contains(Property::Composer)) { oldProperties.replace("COMPOSER", QStringToTString(newProperties.value(Property::Composer).toString())); } if (newProperties.contains(Property::Lyricist)) { oldProperties.replace("LYRICIST", QStringToTString(newProperties.value(Property::Lyricist).toString())); } if (newProperties.contains(Property::Conductor)) { oldProperties.replace("CONDUCTOR", QStringToTString(newProperties.value(Property::Conductor).toString())); } if (newProperties.contains(Property::Copyright)) { oldProperties.replace("COPYRIGHT", QStringToTString(newProperties.value(Property::Copyright).toString())); } if (newProperties.contains(Property::Lyrics)) { oldProperties.replace("LYRICS", QStringToTString(newProperties.value(Property::Lyrics).toString())); } if (newProperties.contains(Property::Language)) { oldProperties.replace("LANGUAGE", QStringToTString(newProperties.value(Property::Language).toString())); } } TagLibWriter::TagLibWriter(QObject* parent) : WriterPlugin(parent) { } QStringList TagLibWriter::writeMimetypes() const { return supportedMimeTypes; } void TagLibWriter::write(const WriteData& data) { const QString fileUrl = data.inputUrl(); const PropertyMap properties = data.getAllProperties(); const QString mimeType = data.inputMimetype(); #if defined Q_OS_WINDOWS TagLib::FileStream stream(fileUrl.toLocal8Bit().constData(), true); #else TagLib::FileStream stream(fileUrl.toUtf8().constData(), false); #endif if (!stream.isOpen()) { qCWarning(KFILEMETADATA_LOG) << "Unable to open file in write mode: " << fileUrl; return; } if (mimeType == QLatin1String("audio/mpeg") || mimeType == QLatin1String("audio/mpeg3") || mimeType == QLatin1String("audio/x-mpeg")) { TagLib::MPEG::File file(&stream, TagLib::ID3v2::FrameFactory::instance(), false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); if (file.hasID3v2Tag()) { writeID3v2Tags(file.ID3v2Tag(), properties); } file.save(); } } else if (mimeType == QLatin1String("audio/x-aiff") || mimeType == QLatin1String("audio/x-aifc")) { TagLib::RIFF::AIFF::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); auto id3Tags = dynamic_cast(file.tag()); if (id3Tags) { writeID3v2Tags(id3Tags, properties); } file.save(); } } else if (mimeType == QLatin1String("audio/wav") || mimeType == QLatin1String("audio/x-wav")) { TagLib::RIFF::WAV::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); auto id3Tags = dynamic_cast(file.tag()); if (id3Tags) { writeID3v2Tags(id3Tags, properties); } file.save(); } } else if (mimeType == QLatin1String("audio/x-musepack")) { TagLib::MPC::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); writeApeTags(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/x-ape")) { TagLib::APE::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); writeApeTags(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/x-wavpack")) { TagLib::WavPack::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); writeApeTags(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/mp4")) { TagLib::MP4::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); auto mp4Tags = dynamic_cast(file.tag()); if (mp4Tags) { writeMp4Tags(mp4Tags, properties); } file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/flac")) { TagLib::FLAC::File file(&stream, TagLib::ID3v2::FrameFactory::instance(), false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); writeVorbisTags(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/ogg") || mimeType == QLatin1String("audio/x-vorbis+ogg")) { TagLib::Ogg::Vorbis::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); writeVorbisTags(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/opus") || mimeType == QLatin1String("audio/x-opus+ogg")) { TagLib::Ogg::Opus::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); writeVorbisTags(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/speex") || mimeType == QLatin1String("audio/x-speex+ogg")) { TagLib::Ogg::Speex::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); writeVorbisTags(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/x-ms-wma")) { TagLib::ASF::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); auto asfTags = dynamic_cast(file.tag()); if (asfTags){ writeAsfTags(asfTags, properties); } file.save(); } } } diff --git a/src/writers/taglibwriter.h b/src/writers/taglibwriter.h index 65e8639..59c3455 100644 --- a/src/writers/taglibwriter.h +++ b/src/writers/taglibwriter.h @@ -1,45 +1,32 @@ /* - * Copyright (C) 2016 Varun Joshi - * 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 - * - */ + SPDX-FileCopyrightText: 2016 Varun Joshi + SPDX-FileCopyrightText: 2018 Alexander Stippich + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef TAGLIBWRITER_H #define TAGLIBWRITER_H #include "writerplugin.h" namespace KFileMetaData { class TagLibWriter : public WriterPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kde.kf5.kfilemetadata.WriterPlugin") Q_INTERFACES(KFileMetaData::WriterPlugin) public: explicit TagLibWriter(QObject* parent = nullptr); void write(const WriteData& data) override; QStringList writeMimetypes() const override; }; } #endif // TAGLIBWRITER_H diff --git a/src/xattr_p.h b/src/xattr_p.h index 419e812..01c5575 100644 --- a/src/xattr_p.h +++ b/src/xattr_p.h @@ -1,457 +1,444 @@ /* - * This file is part of the KDE Baloo Project - * Copyright (C) 2014 Raphael Kubo da Costa - * - * 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 - * - */ + This file is part of the KDE Baloo Project + SPDX-FileCopyrightText: 2014 Raphael Kubo da Costa + + SPDX-License-Identifier: LGPL-2.1-or-later +*/ #ifndef KFILEMETADATA_XATTR_P_H #define KFILEMETADATA_XATTR_P_H #include #include #include #include #include #if defined(Q_OS_LINUX) || defined(__GLIBC__) #include #include #if defined(Q_OS_ANDROID) || defined(Q_OS_LINUX) // attr/xattr.h is not available in the Android NDK so we are defining ENOATTR ourself #ifndef ENOATTR # define ENOATTR ENODATA /* No such attribute */ #endif #endif #include #elif defined(Q_OS_MAC) #include #include #include #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) #include #include #include #elif defined(Q_OS_WIN) #include #define ssize_t SSIZE_T #endif #if defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) inline ssize_t k_getxattr(const QString& path, const QString& name, QString* value) { const QByteArray p = QFile::encodeName(path); const char* encodedPath = p.constData(); const QByteArray n = name.toUtf8(); const char* attributeName = n.constData(); // First get the size of the data we are going to get to reserve the right amount of space. #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_getxattr)) const ssize_t size = getxattr(encodedPath, attributeName, nullptr, 0); #elif defined(Q_OS_MAC) const ssize_t size = getxattr(encodedPath, attributeName, NULL, 0, 0, 0); #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) const ssize_t size = extattr_get_file(encodedPath, EXTATTR_NAMESPACE_USER, attributeName, NULL, 0); #endif if (!value) { return size; } if (size <= 0) { value->clear(); return size; } QByteArray data(size, Qt::Uninitialized); while (true) { #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_getxattr)) const ssize_t r = getxattr(encodedPath, attributeName, data.data(), data.size()); #elif defined(Q_OS_MAC) const ssize_t r = getxattr(encodedPath, attributeName, data.data(), data.size(), 0, 0); #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) const ssize_t r = extattr_get_file(encodedPath, EXTATTR_NAMESPACE_USER, attributeName, data.data(), data.size()); #endif if (r < 0 && errno != ERANGE) { value->clear(); return r; } if (r >= 0) { data.resize(r); *value = QString::fromUtf8(data); return size; } else { // ERANGE data.resize(data.size() * 2); } } } inline int k_setxattr(const QString& path, const QString& name, const QString& value) { const QByteArray p = QFile::encodeName(path); const char* encodedPath = p.constData(); const QByteArray n = name.toUtf8(); const char* attributeName = n.constData(); const QByteArray v = value.toUtf8(); const void* attributeValue = v.constData(); const size_t valueSize = v.size(); #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_setxattr)) return setxattr(encodedPath, attributeName, attributeValue, valueSize, 0); #elif defined(Q_OS_MAC) return setxattr(encodedPath, attributeName, attributeValue, valueSize, 0, 0); #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) const ssize_t count = extattr_set_file(encodedPath, EXTATTR_NAMESPACE_USER, attributeName, attributeValue, valueSize); return count == -1 ? -1 : 0; #endif } inline int k_removexattr(const QString& path, const QString& name) { const QByteArray p = QFile::encodeName(path); const char* encodedPath = p.constData(); const QByteArray n = name.toUtf8(); const char* attributeName = n.constData(); #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_removexattr)) return removexattr(encodedPath, attributeName); #elif defined(Q_OS_MAC) return removexattr(encodedPath, attributeName, XATTR_NOFOLLOW ); #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) return extattr_delete_file (encodedPath, EXTATTR_NAMESPACE_USER, attributeName); #endif } inline bool k_hasAttribute(const QString& path, const QString& name) { auto ret = k_getxattr(path, name, nullptr); return (ret >= 0); } inline bool k_isSupported(const QString& path) { auto ret = k_getxattr(path, QStringLiteral("user.test"), nullptr); return (ret >= 0) || (errno != ENOTSUP); } static KFileMetaData::UserMetaData::Attribute _mapAttribute(const QByteArray& key) { using KFileMetaData::UserMetaData; if (key == "user.xdg.tags") { return UserMetaData::Attribute::Tags; } if (key == "user.baloo.rating") { return UserMetaData::Attribute::Rating; } if (key == "user.xdg.comment") { return UserMetaData::Attribute::Comment; } if (key == "user.xdg.origin.url") { return UserMetaData::Attribute::OriginUrl; } if (key == "user.xdg.origin.email.subject") { return UserMetaData::Attribute::OriginEmailSubject; } if (key == "user.xdg.origin.email.sender") { return UserMetaData::Attribute::OriginEmailSender; } if (key == "user.xdg.origin.email.message-id") { return UserMetaData::Attribute::OriginEmailMessageId; } return UserMetaData::Attribute::Other; } #if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) static QList _split_length_value(QByteArray data) { int pos = 0; QList entries; while (pos < data.size()) { unsigned char len = data[pos]; if (pos + 1 + len <= data.size()) { auto value = data.mid(pos + 1, len); entries.append(value); } pos += 1 + len; } return entries; } #endif KFileMetaData::UserMetaData::Attributes k_queryAttributes(const QString& path, KFileMetaData::UserMetaData::Attributes attributes) { using KFileMetaData::UserMetaData; const QByteArray p = QFile::encodeName(path); const char* encodedPath = p.constData(); #if defined(Q_OS_LINUX) const ssize_t size = listxattr(encodedPath, nullptr, 0); #elif defined(Q_OS_MAC) const ssize_t size = listxattr(encodedPath, nullptr, 0, 0); #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) const ssize_t size = extattr_list_file(encodedPath, EXTATTR_NAMESPACE_USER, nullptr, 0); #endif if (size == 0) { return UserMetaData::Attribute::None; } if (size < 0) { if (errno == E2BIG) { return UserMetaData::Attribute::All; } return UserMetaData::Attribute::None; } if (attributes == UserMetaData::Attribute::Any) { return UserMetaData::Attribute::All; } QByteArray data(size, Qt::Uninitialized); while (true) { #if defined(Q_OS_LINUX) const ssize_t r = listxattr(encodedPath, data.data(), data.size()); #elif defined(Q_OS_MAC) const ssize_t r = listxattr(encodedPath, data.data(), data.size(), 0); #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) const ssize_t r = extattr_list_file(encodedPath, EXTATTR_NAMESPACE_USER, data.data(), data.size()); #endif if (r == 0) { return UserMetaData::Attribute::None; } if (r < 0 && errno != ERANGE) { return UserMetaData::Attribute::None; } if (r > 0) { data.resize(r); break; } else { data.resize(data.size() * 2); } } UserMetaData::Attributes fileAttributes = UserMetaData::Attribute::None; QByteArray prefix = QByteArray::fromRawData("user.", 5); #if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) const auto entries = _split_length_value(data); #else const auto entries = data.split('\0'); #endif for (const auto entry : entries) { if (!entry.startsWith(prefix)) { continue; } fileAttributes |= _mapAttribute(entry); fileAttributes &= attributes; if (fileAttributes == attributes) { break; } } return fileAttributes; } #elif defined(Q_OS_WIN) inline ssize_t k_getxattr(const QString& path, const QString& name, QString* value) { const QString fullADSName = path + QLatin1Char(':') + name; HANDLE hFile = ::CreateFileW(reinterpret_cast(fullADSName.utf16()), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if(!hFile) return 0; LARGE_INTEGER lsize; BOOL ret = GetFileSizeEx(hFile, &lsize); if (ret || lsize.QuadPart > 0x7fffffff || lsize.QuadPart == 0) { CloseHandle(hFile); value->clear(); return lsize.QuadPart == 0 ? 0 : -1; } DWORD r = 0; QByteArray data(lsize.QuadPart, Qt::Uninitialized); // should we care about attributes longer than 2GiB? - unix xattr are restricted to much lower values ret = ::ReadFile(hFile, data.data(), data.size(), &r, NULL); CloseHandle(hFile); if (ret || r == 0) { value->clear(); return r == 0 ? 0 : -1; } data.resize(r); *value = QString::fromUtf8(data); return r; } inline int k_setxattr(const QString& path, const QString& name, const QString& value) { const QByteArray v = value.toUtf8(); const QString fullADSName = path + QLatin1Char(':') + name; HANDLE hFile = ::CreateFileW(reinterpret_cast(fullADSName.utf16()), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if(!hFile) return -1; DWORD count = 0; if(!::WriteFile(hFile, v.constData(), v.size(), &count, NULL)) { DWORD dw = GetLastError(); TCHAR msg[1024]; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &msg, 0, NULL ); qWarning() << "failed to write to ADS:" << msg; CloseHandle(hFile); return -1; } CloseHandle(hFile); return count; } inline bool k_hasAttribute(const QString& path, const QString& name) { // enumerate all streams: const QString streamName = QStringLiteral(":") + name + QStringLiteral(":$DATA"); HANDLE hFile = ::CreateFileW(reinterpret_cast(path.utf16()), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if(!hFile) { return false; } FILE_STREAM_INFO* fi = new FILE_STREAM_INFO[256]; if(GetFileInformationByHandleEx(hFile, FileStreamInfo, fi, 256 * sizeof(FILE_STREAM_INFO))) { if(QString::fromUtf16((ushort*)fi->StreamName, fi->StreamNameLength / sizeof(ushort)) == streamName) { delete[] fi; CloseHandle(hFile); return true; } FILE_STREAM_INFO* p = fi; do { p = (FILE_STREAM_INFO*) ((char*)p + p->NextEntryOffset); if(QString::fromUtf16((ushort*)p->StreamName, p->StreamNameLength / sizeof(ushort)) == streamName) { delete[] fi; CloseHandle(hFile); return true; } } while(p->NextEntryOffset != NULL); } delete[] fi; CloseHandle(hFile); return false; } inline int k_removexattr(const QString& path, const QString& name) { const QString fullADSName = path + QLatin1Char(':') + name; int ret = (DeleteFileW(reinterpret_cast(fullADSName.utf16()))) ? 0 : -1; return ret; } inline bool k_isSupported(const QString& path) { QFileInfo f(path); const QString drive = QString(f.absolutePath().left(2)) + QStringLiteral("\\"); WCHAR szFSName[MAX_PATH]; DWORD dwVolFlags; ::GetVolumeInformationW(reinterpret_cast(drive.utf16()), NULL, 0, NULL, NULL, &dwVolFlags, szFSName, MAX_PATH); return ((dwVolFlags & FILE_NAMED_STREAMS) && _wcsicmp(szFSName, L"NTFS") == 0); } KFileMetaData::UserMetaData::Attributes k_queryAttributes(const QString& path, KFileMetaData::UserMetaData::Attributes attributes) { using KFileMetaData::UserMetaData; if (!k_isSupported(path)) { return UserMetaData::Attribute::None; } // TODO - this is mostly a stub, streams should be enumerated, see k_hasAttribute above if (attributes == UserMetaData::Attribute::Any) { return UserMetaData::Attribute::All; } return attributes; } #else inline ssize_t k_getxattr(const QString&, const QString&, QString*) { return 0; } inline int k_setxattr(const QString&, const QString&, const QString&) { return -1; } inline int k_removexattr(const QString&, const QString&) { return -1; } inline bool k_hasAttribute(const QString&, const QString&) { return false; } inline bool k_isSupported(const QString&) { return false; } KFileMetaData::UserMetaData::Attributes k_queryAttributes(const QString&, KFileMetaData::UserMetaData::Attributes attributes) { return KFileMetaData::UserMetaData::Attribute::None; } #endif #endif // KFILEMETADATA_XATTR_P_H diff --git a/tests/dump.cpp b/tests/dump.cpp index ab58f5d..1c8b461 100644 --- a/tests/dump.cpp +++ b/tests/dump.cpp @@ -1,76 +1,61 @@ /* - * 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 . - * - */ + SPDX-FileCopyrightText: 2014 Vishesh Handa + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ #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"; 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; }