From 61bcac4d435558eb7bcd7ce06d6d2837c73d2539 Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Thu, 6 Oct 2022 15:55:39 +0300 Subject: [PATCH] generic: use the new karchive library Signed-off-by: Ivailo Monev --- ark/CMakeLists.txt | 10 +- ark/plugins/CMakeLists.txt | 2 - ark/plugins/karchiveplugin/CMakeLists.txt | 31 - ark/plugins/karchiveplugin/karchiveplugin.cpp | 276 ------ ark/plugins/karchiveplugin/karchiveplugin.h | 68 -- .../kerfuffle_karchive.desktop.cmake | 129 --- ark/plugins/libarchive/CMakeLists.txt | 4 +- ark/plugins/libarchive/libarchivehandler.cpp | 868 ++---------------- ark/plugins/libarchive/libarchivehandler.h | 35 +- okular/CMakeLists.txt | 1 + okular/core/document.cpp | 100 +- okular/core/utils.cpp | 5 + okular/core/utils_p.h | 2 + okular/generators/comicbook/CMakeLists.txt | 5 +- okular/generators/comicbook/document.cpp | 99 +- okular/generators/comicbook/document.h | 10 +- .../libokularGenerator_comicbook.desktop | 2 +- okular/generators/comicbook/unrar.cpp | 262 ------ okular/generators/comicbook/unrar.h | 81 -- okular/generators/comicbook/unrarflavours.cpp | 73 -- okular/generators/comicbook/unrarflavours.h | 55 -- okular/generators/fictionbook/CMakeLists.txt | 2 +- okular/generators/fictionbook/document.cpp | 23 +- okular/generators/ooo/CMakeLists.txt | 1 + okular/generators/ooo/document.cpp | 62 +- okular/generators/xps/CMakeLists.txt | 2 +- okular/generators/xps/generator_xps.cpp | 118 ++- okular/generators/xps/generator_xps.h | 6 +- 28 files changed, 280 insertions(+), 2052 deletions(-) delete mode 100644 ark/plugins/karchiveplugin/CMakeLists.txt delete mode 100644 ark/plugins/karchiveplugin/karchiveplugin.cpp delete mode 100644 ark/plugins/karchiveplugin/karchiveplugin.h delete mode 100644 ark/plugins/karchiveplugin/kerfuffle_karchive.desktop.cmake delete mode 100644 okular/generators/comicbook/unrar.cpp delete mode 100644 okular/generators/comicbook/unrar.h delete mode 100644 okular/generators/comicbook/unrarflavours.cpp delete mode 100644 okular/generators/comicbook/unrarflavours.h diff --git a/ark/CMakeLists.txt b/ark/CMakeLists.txt index fe5560a3..544fe7bf 100644 --- a/ark/CMakeLists.txt +++ b/ark/CMakeLists.txt @@ -12,8 +12,8 @@ endif() kde4_optional_find_package(LibArchive 3.0.3) set_package_properties(LibArchive PROPERTIES - DESCRIPTION "A library for dealing with a wide variety of archive file formats" - URL "http://code.google.com/p/libarchive/" + DESCRIPTION "Multi-format archive and compression library" + URL "https://libarchive.org/" PURPOSE "Required for among others tar, tar.gz, tar.bz2 formats in Ark" ) @@ -44,6 +44,12 @@ set_package_properties(LibLZMA PROPERTIES PURPOSE "Required for the .xz and .lzma format support in Ark" ) +find_program(RAR_AND_UNRAR_EXECUTABLE unrar rar) +add_feature_info(rar_and_unrar + RAR_AND_UNRAR_EXECUTABLE + "RAR write support in Ark" +) + add_definitions(-DQT_NO_CAST_FROM_ASCII) include_directories(${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR}) diff --git a/ark/plugins/CMakeLists.txt b/ark/plugins/CMakeLists.txt index 99035666..c85f7902 100644 --- a/ark/plugins/CMakeLists.txt +++ b/ark/plugins/CMakeLists.txt @@ -1,7 +1,5 @@ if(LibArchive_FOUND) add_subdirectory( libarchive ) -else() - add_subdirectory( karchiveplugin ) endif() add_subdirectory( clirarplugin ) diff --git a/ark/plugins/karchiveplugin/CMakeLists.txt b/ark/plugins/karchiveplugin/CMakeLists.txt deleted file mode 100644 index 4c9db595..00000000 --- a/ark/plugins/karchiveplugin/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -########### next target ############### - -set(SUPPORTED_KARCHIVE_MIMETYPES "application/x-archive;application/zip;application/x-bzip;application/x-gzip;application/x-zip-compressed;application/x-tar;application/x-compressed-tar;application/x-bzip-compressed-tar;application/x-gzip-compressed-tar;") - -set(kerfuffle_karchive_SRCS karchiveplugin.cpp) - -kde4_add_plugin(kerfuffle_karchive ${kerfuffle_karchive_SRCS}) - -target_link_libraries(kerfuffle_karchive - ${KDE4_KDECORE_LIBS} - kerfuffle -) - -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/kerfuffle_karchive.desktop.cmake - ${CMAKE_CURRENT_BINARY_DIR}/kerfuffle_karchive.desktop -) - -########### install files ############### - -install( - TARGETS kerfuffle_karchive - DESTINATION ${KDE4_PLUGIN_INSTALL_DIR} -) - -install( - FILES ${CMAKE_CURRENT_BINARY_DIR}/kerfuffle_karchive.desktop - DESTINATION ${KDE4_SERVICES_INSTALL_DIR} -) - -set(SUPPORTED_ARK_MIMETYPES "${SUPPORTED_ARK_MIMETYPES}${SUPPORTED_KARCHIVE_MIMETYPES}" PARENT_SCOPE) diff --git a/ark/plugins/karchiveplugin/karchiveplugin.cpp b/ark/plugins/karchiveplugin/karchiveplugin.cpp deleted file mode 100644 index d909650c..00000000 --- a/ark/plugins/karchiveplugin/karchiveplugin.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/* - * ark -- archiver for the KDE project - * - * Copyright (C) 2007 Henrique Pinto - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ -#include "karchiveplugin.h" -#include "kerfuffle/queries.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -KArchiveInterface::KArchiveInterface(QObject *parent, const QVariantList &args) - : ReadWriteArchiveInterface(parent, args), m_archive(0) -{ - kDebug(); -} - -KArchiveInterface::~KArchiveInterface() -{ - delete m_archive; - m_archive = 0; -} - -KArchive *KArchiveInterface::archive() -{ - if (m_archive == 0) { - KMimeType::Ptr mimeType = KMimeType::findByPath(filename()); - - if (mimeType->is(QLatin1String("application/zip"))) { - m_archive = new KZip(filename()); - } else { - m_archive = new KTar(filename()); - } - - } - return m_archive; -} - -bool KArchiveInterface::list() -{ - kDebug(); - if (!archive()->isOpen() && !archive()->open(QIODevice::ReadOnly)) { - emit error(i18nc("@info", "Could not open the archive %1 for reading", filename())); - return false; - } else { - return browseArchive(archive()); - } -} - -void KArchiveInterface::getAllEntries(const KArchiveDirectory *dir, const QString &prefix, QList< QVariant > &list) -{ - foreach(const QString &entryName, dir->entries()) { - const KArchiveEntry *entry = dir->entry(entryName); - if (entry->isDirectory()) { - QString newPrefix = (prefix.isEmpty() ? prefix : prefix + QLatin1Char('/')) + entryName; - getAllEntries(static_cast(entry), newPrefix, list); - } - else { - list.append(prefix + QLatin1Char('/') + entryName); - } - } -} - -bool KArchiveInterface::copyFiles(const QList &files, const QString &destinationDirectory, ExtractionOptions options) -{ - const bool preservePaths = options.value(QLatin1String("PreservePaths")).toBool(); - const KArchiveDirectory *dir = archive()->directory(); - - if (!archive()->isOpen() && !archive()->open(QIODevice::ReadOnly)) { - emit error(i18nc("@info", "Could not open the archive %1 for reading", filename())); - return false; - } - - QList extrFiles = files; - if (extrFiles.isEmpty()) { // All files should be extracted - getAllEntries(dir, QString(), extrFiles); - } - - bool overwriteAllSelected = false; - bool autoSkipSelected = false; - QSet dirCache; - foreach(const QVariant &file, extrFiles) { - QString realDestination = destinationDirectory; - const KArchiveEntry *archiveEntry = dir->entry(file.toString()); - if (!archiveEntry) { - emit error(i18nc("@info", "File %1 not found in the archive" , file.toString())); - return false; - } - - if (preservePaths) { - QFileInfo fi(file.toString()); - QDir dest(destinationDirectory); - QString filepath = archiveEntry->isDirectory() ? fi.filePath() : fi.path(); - if (!dirCache.contains(filepath)) { - if (!dest.mkpath(filepath)) { - emit error(i18nc("@info", "Error creating directory %1", filepath)); - return false; - } - dirCache << filepath; - } - realDestination = dest.absolutePath() + QLatin1Char('/') + filepath; - } - - // TODO: handle errors, copyTo fails silently - if (!archiveEntry->isDirectory()) { // We don't need to do anything about directories - if (QFile::exists(realDestination + QLatin1Char('/') + archiveEntry->name()) && !overwriteAllSelected) { - if (autoSkipSelected) { - continue; - } - - int response = handleFileExistsMessage(realDestination, archiveEntry->name()); - - if (response == OverwriteCancel) { - break; - } - if (response == OverwriteYes || response == OverwriteAll) { - static_cast(archiveEntry)->copyTo(realDestination); - if (response == OverwriteAll) { - overwriteAllSelected = true; - } - } - if (response == OverwriteAutoSkip) { - autoSkipSelected = true; - } - } - else { - static_cast(archiveEntry)->copyTo(realDestination); - } - } - } - - return true; -} - -int KArchiveInterface::handleFileExistsMessage(const QString &dir, const QString &fileName) -{ - Kerfuffle::OverwriteQuery query(dir + QLatin1Char('/') + fileName); - query.setNoRenameMode(true); - emit userQuery(&query); - query.waitForResponse(); - - if (query.responseOverwrite()) { - return OverwriteYes; - } else if (query.responseSkip()) { - return OverwriteSkip; - } else if (query.responseOverwriteAll()) { - return OverwriteAll; - } else if (query.responseAutoSkip()) { - return OverwriteAutoSkip; - } - - return OverwriteCancel; -} - -bool KArchiveInterface::browseArchive(KArchive *archive) -{ - return processDir(archive->directory()); -} - -bool KArchiveInterface::processDir(const KArchiveDirectory *dir, const QString & prefix) -{ - foreach(const QString& entryName, dir->entries()) { - const KArchiveEntry *entry = dir->entry(entryName); - createEntryFor(entry, prefix); - if (entry->isDirectory()) { - QString newPrefix = (prefix.isEmpty() ? prefix : prefix + QLatin1Char('/')) + entryName; - processDir(static_cast(entry), newPrefix); - } - } - return true; -} - -void KArchiveInterface::createEntryFor(const KArchiveEntry *aentry, const QString& prefix) -{ - ArchiveEntry e; - QString fileName = prefix.isEmpty() ? aentry->name() : prefix + QLatin1Char('/') + aentry->name(); - - if (aentry->isDirectory() && !fileName.endsWith(QLatin1Char('/'))) - fileName += QLatin1Char('/'); - - e[ FileName ] = fileName; - e[ InternalID ] = e[ FileName ]; - e[ Permissions ] = ReadWriteArchiveInterface::permissionsString(aentry->permissions()); - e[ Owner ] = aentry->user(); - e[ Group ] = aentry->group(); - e[ IsDirectory ] = aentry->isDirectory(); - e[ Timestamp ] = aentry->datetime(); - if (!aentry->symLinkTarget().isEmpty()) { - e[ Link ] = aentry->symLinkTarget(); - } - if (aentry->isFile()) { - e[ Size ] = static_cast(aentry)->size(); - } - else { - e[ Size ] = 0; - } - emit entry(e); -} - -bool KArchiveInterface::addFiles(const QStringList &files, const Kerfuffle::CompressionOptions &options) -{ - Q_UNUSED(options) - kDebug() << "Starting..."; -// delete m_archive; -// m_archive = 0; - if (archive()->isOpen()) { - archive()->close(); - } - if (!archive()->open(QIODevice::ReadWrite)) { - emit error(i18nc("@info", "Could not open the archive %1 for writing.", filename())); - return false; - } - - kDebug() << "Archive opened for writing..."; - kDebug() << "Will add " << files.count() << " files"; - foreach(const QString &path, files) { - kDebug() << "Adding " << path; - QFileInfo fi(path); - Q_ASSERT(fi.exists()); - - if (fi.isDir()) { - if (archive()->addLocalDirectory(path, fi.fileName())) { - const KArchiveEntry *entry = archive()->directory()->entry(fi.fileName()); - createEntryFor(entry, QString()); - processDir((KArchiveDirectory*) archive()->directory()->entry(fi.fileName()), fi.fileName()); - } else { - emit error(i18nc("@info", "Could not add the directory %1 to the archive", path)); - return false; - } - } else { - if (archive()->addLocalFile(path, fi.fileName())) { - const KArchiveEntry *entry = archive()->directory()->entry(fi.fileName()); - createEntryFor(entry, QString()); - } else { - emit error(i18nc("@info", "Could not add the file %1 to the archive.", path)); - return false; - } - } - } - kDebug() << "Closing the archive"; - archive()->close(); - kDebug() << "Done"; - return true; -} - -bool KArchiveInterface::deleteFiles(const QList & files) -{ - Q_UNUSED(files) - return false; -} - -KERFUFFLE_EXPORT_PLUGIN(KArchiveInterface) diff --git a/ark/plugins/karchiveplugin/karchiveplugin.h b/ark/plugins/karchiveplugin/karchiveplugin.h deleted file mode 100644 index 76565117..00000000 --- a/ark/plugins/karchiveplugin/karchiveplugin.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * ark -- archiver for the KDE project - * - * Copyright (C) 2007 Henrique Pinto - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ -#ifndef KARCHIVEPLUGIN_H -#define KARCHIVEPLUGIN_H -#include "kerfuffle/archiveinterface.h" - -using namespace Kerfuffle; - -class KArchive; -class KArchiveEntry; -class KArchiveDirectory; - -class KArchiveInterface: public ReadWriteArchiveInterface -{ - Q_OBJECT -public: - explicit KArchiveInterface(QObject *parent = 0, const QVariantList &args = QVariantList()); - ~KArchiveInterface(); - - bool list(); - bool copyFiles(const QList &files, const QString &destinationDirectory, ExtractionOptions options); - - bool addFiles(const QStringList &files, const CompressionOptions &options); - bool deleteFiles(const QList & files); - -private: - enum { - OverwriteYes, - OverwriteSkip, - OverwriteAll, - OverwriteAutoSkip, - OverwriteCancel - }; - - bool browseArchive(KArchive *archive); - - bool processDir(const KArchiveDirectory *dir, const QString & prefix = QString()); - - void createEntryFor(const KArchiveEntry *aentry, const QString& prefix); - - void getAllEntries(const KArchiveDirectory *dir, const QString &prefix, QList< QVariant > &list); - - int handleFileExistsMessage(const QString &dir, const QString &fileName); - - KArchive *archive(); - - KArchive *m_archive; -}; - -#endif // KARCHIVEPLUGIN_H diff --git a/ark/plugins/karchiveplugin/kerfuffle_karchive.desktop.cmake b/ark/plugins/karchiveplugin/kerfuffle_karchive.desktop.cmake deleted file mode 100644 index 6352776f..00000000 --- a/ark/plugins/karchiveplugin/kerfuffle_karchive.desktop.cmake +++ /dev/null @@ -1,129 +0,0 @@ -[Desktop Entry] -Type=Service -X-KDE-ServiceTypes=Kerfuffle/Plugin -X-KDE-Library=kerfuffle_karchive -X-KDE-PluginInfo-Author=Henrique Pinto -X-KDE-PluginInfo-Email=henrique.pinto@kdemail.net -X-KDE-PluginInfo-Name=kerfuffle_karchive -X-KDE-PluginInfo-Version=0.0.1 -X-KDE-PluginInfo-Website=http://www.kde.org -X-KDE-PluginInfo-License=GPLv2+ -X-KDE-Priority=100 -X-KDE-Kerfuffle-APIRevision=1 -Name=kerfuffle_karchive -Name[ar]=kerfuffle_karchive -Name[ast]=kerfuffle_karchive -Name[bg]=kerfuffle_karchive -Name[bs]=kerfuffle_karchive -Name[ca]=kerfuffle_karchive -Name[ca@valencia]=kerfuffle_karchive -Name[cs]=kerfuffle_karchive -Name[da]=kerfuffle_karchive -Name[de]=kerfuffle_karchive -Name[el]=kerfuffle_karchive -Name[en_GB]=kerfuffle_karchive -Name[es]=kerfuffle_karchive -Name[et]=kerfuffle_karchive -Name[eu]=kerfuffle_karchive -Name[fi]=kerfuffle_karchive -Name[fr]=kerfuffle_karchive -Name[ga]=kerfuffle_karchive -Name[gl]=kerfuffle_karchive -Name[he]=kerfuffle_karchive -Name[hne]=करफुफल_केआर्काइव -Name[hr]=kerfuffle_karchive -Name[hu]=kerfuffle_karchive -Name[ia]=kerfuffle_karchive -Name[id]=kerfuffle_karchive -Name[it]=kerfuffle_karchive -Name[ja]=kerfuffle_karchive -Name[kk]=kerfuffle_karchive -Name[km]=kerfuffle_karchive -Name[ko]=kerfuffle_karchive -Name[lt]=kerfuffle_karchive -Name[lv]=kerfuffle_karchive -Name[mr]=कर्फफल_के-संग्रह -Name[nb]=kerfuffle_karchive -Name[nds]=kerfuffle_karchive -Name[nl]=kerfuffle_karchive -Name[nn]=kerfuffle_karchive -Name[pa]=kerfuffle_karchive -Name[pl]=kerfuffle_karchive -Name[pt]=kerfuffle_karchive -Name[pt_BR]=kerfuffle_karchive -Name[ro]=kerfuffle_karchive -Name[ru]=kerfuffle_karchive -Name[sk]=kerfuffle_karchive -Name[sl]=kerfuffle_karchive -Name[sq]=kerfuffle_karchive -Name[sr]=kerfuffle_karchive -Name[sr@ijekavian]=kerfuffle_karchive -Name[sr@ijekavianlatin]=kerfuffle_karchive -Name[sr@latin]=kerfuffle_karchive -Name[sv]=Kerfuffle Karchive -Name[ta]=கெர்ஃபஃபில் கேஆர்கைவ் -Name[th]=kerfuffle_karchive -Name[tr]=kerfuffle_karchive -Name[uk]=kerfuffle_karchive -Name[wa]=kerfuffle_karchive -Name[x-test]=xxkerfuffle_karchivexx -Name[zh_CN]=kerfuffle_karchive -Name[zh_TW]=kerfuffle_karchive -Comment=KArchive plugin for Kerfuffle -Comment[ar]=KArchive ملحق لـ Kerfuffle -Comment[ast]=Aplicación KArchive pa Kerfuffle -Comment[bg]=Приставка KArchive за Kerfuffle -Comment[bs]=Priključak KArchive za Kerfafl -Comment[ca]=Connector del KArchive pel Kerfuffle -Comment[ca@valencia]=Connector del KArchive pel Kerfuffle -Comment[cs]=KArchive modul pro Kerfuffle -Comment[da]=KArchive-plugin til Kerfuffle -Comment[de]=KArchive-Modul für Kerfuffle -Comment[el]=πρόσθετο KArchive για τη Kerfuffle -Comment[en_GB]=KArchive plugin for Kerfuffle -Comment[es]=Complemento KArchive para Kerfuffle -Comment[et]=Kerfuffle'i KArchive plugin -Comment[eu]=Kerfuffle-rentzako KArchive plugina -Comment[fi]=KArchive-pakkaustuki -Comment[fr]=Module externe « KArchive » pour Kerfuffle -Comment[ga]=Breiseán KArchive le haghaidh Kerfuffle -Comment[gl]=Extensión de KArchive para Kerfuffle -Comment[he]=תוסף KArchive עבור Kerfuffle -Comment[hne]=करफुफल बर केआर्काइव प्लगइन -Comment[hr]=Priključak KArchive za Kerfuffle -Comment[hu]=KArchive Kerfuffle-modul -Comment[ia]=Plugin de Karchive per Kerfuffle -Comment[id]=Pengaya KArchive untuk Kerfuffle -Comment[it]=Estensione KArchive per Kerfuffle -Comment[ja]=Kerfuffle のための KArchive プラグイン -Comment[kk]=Kerfuffle-ге арналған KArchive плагині -Comment[km]=កម្មវិធី​របស់ KArchive សម្រាប់ Kerfuffle -Comment[ko]=Kerfuffle을 위한 KArchive 플러그인 -Comment[lt]=KArchive Kerfuffle priedas -Comment[lv]=Kerfuffle KArchive spraudnis -Comment[mr]=कर्फफल करिता के-संग्रह प्लगइन -Comment[nb]=KArchive programtillegg for Kerfuffle -Comment[nds]=KArchive-Moduul för Kerfuffle -Comment[nl]=KArchive-plug-in voor Kerfuffle -Comment[nn]=KArchive-programtillegg til Kerfuffle -Comment[pl]=Wtyczka KArchive dla Kerfuffle -Comment[pt]='Plugin' do KArchive para o Kerfuffle -Comment[pt_BR]=Plugin KArchive para a Kerfuffle -Comment[ro]=Modul KArchive pentru Kerfuffle -Comment[ru]=Модуль KArchive для Kerfuffle -Comment[sk]=KArchive modul pre Kerfuffle -Comment[sl]=Vstavek KArchive za Kerfuffle -Comment[sq]=KArchive plugin për Kerfuffle -Comment[sr]=Прикључак KArchive за Керфафл -Comment[sr@ijekavian]=Прикључак KArchive за Керфафл -Comment[sr@ijekavianlatin]=Priključak KArchive za Kerfuffle -Comment[sr@latin]=Priključak KArchive za Kerfuffle -Comment[sv]=Karchive-insticksprogram för Kerfuffle -Comment[ta]=கெர்ஃபஃபில் க்கு கேஆர்கைவ் சொருகி -Comment[th]=ส่วนเสริม Kerfuffle สำหรับใช้งานร่วมกับ KArchive -Comment[tr]=Kerfuffle için KArchive eklentisi -Comment[uk]=Додаток KArchive для Kerfuffle -Comment[x-test]=xxKArchive plugin for Kerfufflexx -Comment[zh_CN]=Kerfuffle 的 KArchive 插件 -Comment[zh_TW]=Kerfuffle 的 KArchive 外掛程式 -MimeType=@SUPPORTED_KARCHIVE_MIMETYPES@ diff --git a/ark/plugins/libarchive/CMakeLists.txt b/ark/plugins/libarchive/CMakeLists.txt index 1210804c..474a3ab9 100644 --- a/ark/plugins/libarchive/CMakeLists.txt +++ b/ark/plugins/libarchive/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories(${LibArchive_INCLUDE_DIRS}) - ########### next target ############### set(SUPPORTED_LIBARCHIVE_READONLY_MIMETYPES "application/x-archive;application/x-xar;application/x-deb;application/x-cd-image;application/x-bcpio;application/x-cpio;application/x-cpio-compressed;application/x-sv4cpio;application/x-sv4crc;application/x-rpm;application/x-source-rpm;application/vnd.ms-cab-compressed;application/x-servicepack;application/x-compress;application/x-lzip;") set(SUPPORTED_LIBARCHIVE_READWRITE_MIMETYPES "application/x-xar;application/x-tar;application/x-compressed-tar;application/x-bzip-compressed-tar;application/x-gzip-compressed-tar;application/x-tarz;application/x-xz-compressed-tar;application/x-lzma-compressed-tar;application/x-java-archive;application/zip;application/x-7z-compressed;application/x-compress;application/x-lzip;") @@ -34,7 +32,7 @@ set(kerfuffle_libarchive_SRCS libarchivehandler.cpp) kde4_add_plugin(kerfuffle_libarchive ${kerfuffle_libarchive_SRCS}) -target_link_libraries(kerfuffle_libarchive ${KDE4_KDECORE_LIBS} ${LibArchive_LIBRARIES} kerfuffle) +target_link_libraries(kerfuffle_libarchive ${KDE4_KDECORE_LIBS} ${KDE4_KARCHIVE_LIBS} kerfuffle) install(TARGETS kerfuffle_libarchive DESTINATION ${KDE4_PLUGIN_INSTALL_DIR} ) diff --git a/ark/plugins/libarchive/libarchivehandler.cpp b/ark/plugins/libarchive/libarchivehandler.cpp index d564582f..77bdd760 100644 --- a/ark/plugins/libarchive/libarchivehandler.cpp +++ b/ark/plugins/libarchive/libarchivehandler.cpp @@ -29,54 +29,17 @@ #include "kerfuffle/kerfuffle_export.h" #include "kerfuffle/queries.h" -#include -#include - +#include +#include #include #include -#include +#include -#include -#include -#include -#include -#include -#include +#include -#if ARCHIVE_VERSION_NUMBER >= 4000000 -# warning TODO: check for missing ARCHIVE_FILTER_* alternatives -#endif - -struct LibArchiveInterface::ArchiveReadCustomDeleter -{ - static inline void cleanup(struct archive *a) - { - if (a) { - archive_read_free(a); - } - } -}; - -struct LibArchiveInterface::ArchiveWriteCustomDeleter -{ - static inline void cleanup(struct archive *a) - { - if (a) { - archive_write_free(a); - } - } -}; - -LibArchiveInterface::LibArchiveInterface(QObject *parent, const QVariantList & args) +LibArchiveInterface::LibArchiveInterface(QObject *parent, const QVariantList &args) : ReadWriteArchiveInterface(parent, args) - , m_cachedArchiveEntryCount(0) - , m_emitNoEntries(false) - , m_extractedFilesSize(0) - , m_workDir(QDir::current()) - , m_archiveReadDisk(archive_read_disk_new()) - , m_abortOperation(false) { - archive_read_disk_set_standard_lookup(m_archiveReadDisk.data()); } LibArchiveInterface::~LibArchiveInterface() @@ -85,810 +48,115 @@ LibArchiveInterface::~LibArchiveInterface() bool LibArchiveInterface::list() { - kDebug(); - - ArchiveRead arch_reader(archive_read_new()); - - if (!(arch_reader.data())) { + KArchive karchive(filename()); + if (!karchive.isReadable()) { + emit error(i18nc("@info", "Could not open the archive %1, libarchive cannot handle it.", filename())); return false; } - if (archive_read_support_filter_all(arch_reader.data()) != ARCHIVE_OK) { - return false; - } - - if (archive_read_support_format_all(arch_reader.data()) != ARCHIVE_OK) { - return false; - } - - if (archive_read_open_filename(arch_reader.data(), QFile::encodeName(filename()), 10240) != ARCHIVE_OK) { - emit error(i18nc("@info", "Could not open the archive %1, libarchive cannot handle it.", - filename())); - return false; - } - - m_cachedArchiveEntryCount = 0; - m_extractedFilesSize = 0; - - struct archive_entry *aentry; - int result = ARCHIVE_EOF; - - while (!m_abortOperation && (result = archive_read_next_header(arch_reader.data(), &aentry)) == ARCHIVE_OK) { -#warning FIXME: fix double-slash root directory properly - if (qstrcmp(archive_entry_pathname(aentry), "//") == 0) { - archive_read_data_skip(arch_reader.data()); - continue; + foreach (const KArchiveEntry &karchiveentry, karchive.list()) { + ArchiveEntry archiveentry; + archiveentry[FileName] = karchiveentry.pathname; + archiveentry[InternalID] = karchiveentry.pathname; + archiveentry[Size] = qlonglong(karchiveentry.size); + archiveentry[IsDirectory] = S_ISDIR(karchiveentry.mode); + archiveentry[Permissions] = ReadWriteArchiveInterface::permissionsString(karchiveentry.mode); + archiveentry[Owner] = karchiveentry.username; + archiveentry[Group] = karchiveentry.groupname; + archiveentry[Timestamp] = QDateTime::fromTime_t(karchiveentry.mtime); + archiveentry[IsPasswordProtected] = karchiveentry.encrypted; + if (!karchiveentry.symlink.isEmpty()) { + archiveentry[Link] = karchiveentry.symlink; } - if (!m_emitNoEntries) { - emitEntryFromArchiveEntry(aentry); - } - - m_extractedFilesSize += (qlonglong)archive_entry_size(aentry); - - m_cachedArchiveEntryCount++; - archive_read_data_skip(arch_reader.data()); + emit entry(archiveentry); } - m_abortOperation = false; + emit progress(1.0); - if (result != ARCHIVE_EOF) { - emit error(i18nc("@info", "The archive reading failed with the following error: %1", - QString::fromAscii( archive_error_string(arch_reader.data())))); - return false; - } - - return archive_read_close(arch_reader.data()) == ARCHIVE_OK; -} - -bool LibArchiveInterface::doKill() -{ - m_abortOperation = true; return true; } -bool LibArchiveInterface::copyFiles(const QVariantList& files, const QString& destinationDirectory, ExtractionOptions options) +bool LibArchiveInterface::copyFiles(const QVariantList& files, const QString &destinationDirectory, ExtractionOptions options) { - kDebug() << "Changing current directory to " << destinationDirectory; - QDir::setCurrent(destinationDirectory); - const bool extractAll = files.isEmpty(); - const bool preservePaths = options.value(QLatin1String( "PreservePaths" )).toBool(); + const bool preservePaths = options.value(QLatin1String("PreservePaths")).toBool(); - QString rootNode = options.value(QLatin1String("RootNode"), QVariant()).toString(); - if ((!rootNode.isEmpty()) && (!rootNode.endsWith(QLatin1Char('/')))) { - rootNode.append(QLatin1Char('/')); - } - - ArchiveRead arch(archive_read_new()); - - if (!(arch.data())) { + KArchive karchive(filename()); + if (!karchive.isReadable()) { + emit error(i18nc("@info", "Could not open the archive %1, libarchive cannot handle it.", filename())); return false; } - if (archive_read_support_filter_all(arch.data()) != ARCHIVE_OK) { - return false; - } - - if (archive_read_support_format_all(arch.data()) != ARCHIVE_OK) { - return false; - } - - if (archive_read_open_filename(arch.data(), QFile::encodeName(filename()), 10240) != ARCHIVE_OK) { - emit error(i18nc("@info", "Could not open the archive %1, libarchive cannot handle it.", - filename())); - return false; - } - - ArchiveWrite writer(archive_write_disk_new()); - if (!(writer.data())) { - return false; - } - - archive_write_disk_set_options(writer.data(), extractionFlags()); - - int entryNr = 0; - int totalCount = 0; - + QStringList fileslist; if (extractAll) { - if (!m_cachedArchiveEntryCount) { - emit progress(0); - //TODO: once information progress has been implemented, send - //feedback here that the archive is being read - kDebug() << "For getting progress information, the archive will be listed once"; - m_emitNoEntries = true; - list(); - m_emitNoEntries = false; + foreach (const KArchiveEntry &karchiveentry, karchive.list()) { + fileslist.append(QFile::decodeName(karchiveentry.pathname)); } - totalCount = m_cachedArchiveEntryCount; } else { - totalCount = files.size(); - } - - m_currentExtractedFilesSize = 0; - - bool overwriteAll = false; // Whether to overwrite all files - bool skipAll = false; // Whether to skip all files - struct archive_entry *entry; - - QString fileBeingRenamed; - - while (archive_read_next_header(arch.data(), &entry) == ARCHIVE_OK) { - fileBeingRenamed.clear(); - - // retry with renamed entry, fire an overwrite query again - // if the new entry also exists - retry: - const bool entryIsDir = S_ISDIR(archive_entry_mode(entry)); - - //we skip directories if not preserving paths - if (!preservePaths && entryIsDir) { - archive_read_data_skip(arch.data()); - continue; - } - - //entryName is the name inside the archive, full path - QString entryName = QDir::fromNativeSeparators(QFile::decodeName(archive_entry_pathname(entry))); - - if (entryName.startsWith(QLatin1Char( '/' ))) { - // remove leading slash from absolute path entries - entryName = entryName.mid(1); - } - - if (files.contains(entryName) || entryName == fileBeingRenamed || extractAll) { - // entryFI is the fileinfo pointing to where the file will be - // written from the archive - QFileInfo entryFI(entryName); - //kDebug() << "setting path to " << archive_entry_pathname( entry ); - - const QString fileWithoutPath(entryFI.fileName()); - - //if we DON'T preserve paths, we cut the path and set the entryFI - //fileinfo to the one without the path - if (!preservePaths) { - //empty filenames (ie dirs) should have been skipped already, - //so asserting - Q_ASSERT(!fileWithoutPath.isEmpty()); - - archive_entry_copy_pathname(entry, QFile::encodeName(fileWithoutPath).constData()); - entryFI = QFileInfo(fileWithoutPath); - - //OR, if the commonBase has been set, then we remove this - //common base from the filename - } else if (!rootNode.isEmpty()) { - kDebug() << "Removing" << rootNode << "from" << entryName; - - const QString truncatedFilename(entryName.remove(0, rootNode.size())); - archive_entry_copy_pathname(entry, QFile::encodeName(truncatedFilename).constData()); - - entryFI = QFileInfo(truncatedFilename); - } - - //now check if the file about to be written already exists - if (!entryIsDir && entryFI.exists()) { - if (skipAll) { - archive_read_data_skip(arch.data()); - archive_entry_clear(entry); - continue; - } else if (!overwriteAll && !skipAll) { - Kerfuffle::OverwriteQuery query(entryName); - emit userQuery(&query); - query.waitForResponse(); - - if (query.responseCancelled()) { - archive_read_data_skip(arch.data()); - archive_entry_clear(entry); - break; - } else if (query.responseSkip()) { - archive_read_data_skip(arch.data()); - archive_entry_clear(entry); - continue; - } else if (query.responseAutoSkip()) { - archive_read_data_skip(arch.data()); - archive_entry_clear(entry); - skipAll = true; - continue; - } else if (query.responseRename()) { - const QString newName(query.newFilename()); - fileBeingRenamed = newName; - archive_entry_copy_pathname(entry, QFile::encodeName(newName).constData()); - goto retry; - } else if (query.responseOverwriteAll()) { - overwriteAll = true; - } - } - } - - //if there is an already existing directory: - if (entryIsDir && entryFI.exists()) { - if (entryFI.isWritable()) { - kDebug(1601) << "Warning, existing, but writable dir"; - } else { - kDebug(1601) << "Warning, existing, but non-writable dir. skipping"; - archive_entry_clear(entry); - archive_read_data_skip(arch.data()); - continue; - } - } - - int header_response; - kDebug() << "Writing " << fileWithoutPath << " to " << archive_entry_pathname(entry); - if ((header_response = archive_write_header(writer.data(), entry)) == ARCHIVE_OK) { - //if the whole archive is extracted and the total filesize is - //available, we use partial progress - copyData(arch.data(), writer.data(), (extractAll && m_extractedFilesSize)); - } else if (header_response == ARCHIVE_WARN) { - kDebug() << "Warning while writing " << entryName; - } else { - kDebug() << "Writing header failed with error code " << header_response - << "While attempting to write " << entryName; - } - - //if we only partially extract the archive and the number of - //archive entries is available we use a simple progress based on - //number of items extracted - if (!extractAll && m_cachedArchiveEntryCount) { - ++entryNr; - emit progress(float(entryNr) / totalCount); - } - archive_entry_clear(entry); - } else { - archive_read_data_skip(arch.data()); + foreach (const QVariant &variant, files) { + fileslist.append(variant.toString()); } } + if (karchive.extract(fileslist, destinationDirectory, preservePaths)) { + emit progress(1.0); + return true; + } - return archive_read_close(arch.data()) == ARCHIVE_OK; + emit error(karchive.errorString()); + return false; } -bool LibArchiveInterface::addFiles(const QStringList& files, const CompressionOptions& options) +bool LibArchiveInterface::addFiles(const QStringList &files, const CompressionOptions &options) { - const bool creatingNewFile = !QFileInfo(filename()).exists(); - const QString tempFilename = filename() + QLatin1String( ".arkWriting" ); - const QString globalWorkDir = options.value(QLatin1String( "GlobalWorkDir" )).toString(); - + const QString globalWorkDir = options.value(QLatin1String("GlobalWorkDir")).toString(); if (!globalWorkDir.isEmpty()) { kDebug() << "GlobalWorkDir is set, changing dir to " << globalWorkDir; - m_workDir.setPath(globalWorkDir); QDir::setCurrent(globalWorkDir); } - m_writtenFiles.clear(); - - ArchiveRead arch_reader; - if (!creatingNewFile) { - arch_reader.reset(archive_read_new()); - if (!(arch_reader.data())) { - emit error(i18n("The archive reader could not be initialized.")); - return false; - } - - if (archive_read_support_filter_all(arch_reader.data()) != ARCHIVE_OK) { - return false; - } - - if (archive_read_support_format_all(arch_reader.data()) != ARCHIVE_OK) { - return false; - } - - if (archive_read_open_filename(arch_reader.data(), QFile::encodeName(filename()), 10240) != ARCHIVE_OK) { - emit error(i18n("The source file could not be read.")); - return false; - } + QString rootNode = options.value(QLatin1String("RootNode"), QVariant()).toString(); + if (!rootNode.isEmpty() && !rootNode.endsWith(QLatin1Char('/'))) { + rootNode.append(QLatin1Char('/')); } - ArchiveWrite arch_writer(archive_write_new()); - if (!(arch_writer.data())) { - emit error(i18n("The archive writer could not be initialized.")); + KArchive karchive(filename()); + if (!karchive.isWritable()) { + emit error(i18nc("@info", "Could not open the archive %1, libarchive cannot handle it.", + filename())); return false; } - //pax_restricted is the libarchive default, let's go with that. - archive_write_set_format_pax_restricted(arch_writer.data()); - - int ret; - if (creatingNewFile) { - if (filename().right(2).toUpper() == QLatin1String( "GZ" )) { - kDebug() << "Detected gzip compression for new file"; - ret = archive_write_add_filter_gzip(arch_writer.data()); - } else if (filename().right(3).toUpper() == QLatin1String( "BZ2" )) { - kDebug() << "Detected bzip2 compression for new file"; - ret = archive_write_add_filter_bzip2(arch_writer.data()); - } else if (filename().right(2).toUpper() == QLatin1String( "XZ" )) { - kDebug() << "Detected xz compression for new file"; - ret = archive_write_add_filter_xz(arch_writer.data()); - } else if (filename().right(4).toUpper() == QLatin1String( "LZMA" )) { - kDebug() << "Detected lzma compression for new file"; - ret = archive_write_add_filter_lzma(arch_writer.data()); - } else if (filename().right(3).toUpper() == QLatin1String( "TAR" )) { - kDebug() << "Detected no compression for new file (pure tar)"; - ret = archive_write_add_filter_none(arch_writer.data()); - } else if (filename().right(3).toUpper() == QLatin1String( "ZIP" )) { - kDebug() << "Detected zip compression for new file"; - ret = archive_write_set_format_zip(arch_writer.data()); - } else if (filename().right(2).toUpper() == QLatin1String( "7Z" )) { - kDebug() << "Detected 7z compression for new file"; - ret = archive_write_set_format_7zip(arch_writer.data()); -#ifdef ARCHIVE_FILTER_LZOP - } else if (filename().right(3).toUpper() == QLatin1String( "LZO" )) { - kDebug() << "Detected LZO compression for new file"; - ret = archive_write_add_filter_lzop(arch_writer.data()); -#endif -#ifdef ARCHIVE_FILTER_LRZIP - } else if (filename().right(3).toUpper() == QLatin1String( "LRZ" )) { - kDebug() << "Detected lrzip compression for new file"; - ret = archive_write_add_filter_lrzip(arch_writer.data()); -#endif -#ifdef ARCHIVE_FILTER_LZ4 - } else if (filename().right(3).toUpper() == QLatin1String( "LZ4" )) { - kDebug() << "Detected LZ4 compression for new file"; - ret = archive_write_add_filter_lz4(arch_writer.data()); -#endif -#ifdef ARCHIVE_FILTER_ZSTD - } else if (filename().right(3).toUpper() == QLatin1String( "ZST" )) { - kDebug() << "Detected ZSTD compression for new file"; - ret = archive_write_add_filter_zstd(arch_writer.data()); -#endif -#ifdef ARCHIVE_FILTER_LZIP - } else if (filename().right(2).toUpper() == QLatin1String( "LZ" )) { - kDebug() << "Detected Lzip compression for new file"; - ret = archive_write_add_filter_lzip(arch_writer.data()); -#endif -#ifdef ARCHIVE_FILTER_COMPRESS - } else if (filename().right(1).toUpper() == QLatin1String( "Z" )) { - kDebug() << "Detected Z compression for new file"; - ret = archive_write_add_filter_compress(arch_writer.data()); -#endif - } else { - kDebug() << "Falling back to gzip"; - ret = archive_write_add_filter_gzip(arch_writer.data()); - } - - // lzop filter for example warns if external program is used - if (ret == ARCHIVE_WARN) { - emit info(QString::fromAscii(archive_error_string(arch_writer.data()))); - } else if (ret != ARCHIVE_OK) { - emit error(i18nc("@info", "Setting the compression method failed with the following error: %1", - QString::fromAscii(archive_error_string(arch_writer.data())))); - - return false; - } - } else { - switch (archive_filter_code(arch_reader.data(), 0)) { - case ARCHIVE_FILTER_GZIP: - ret = archive_write_add_filter_gzip(arch_writer.data()); - break; - case ARCHIVE_FILTER_BZIP2: - ret = archive_write_add_filter_bzip2(arch_writer.data()); - break; - case ARCHIVE_FILTER_XZ: - ret = archive_write_add_filter_xz(arch_writer.data()); - break; - case ARCHIVE_FILTER_LZMA: - ret = archive_write_add_filter_lzma(arch_writer.data()); - break; -#ifdef ARCHIVE_FILTER_LZOP - case ARCHIVE_FILTER_LZOP: - ret = archive_write_add_filter_lzop(arch_writer.data()); - break; -#endif -#ifdef ARCHIVE_FILTER_LRZIP - case ARCHIVE_FILTER_LRZIP: - ret = archive_write_add_filter_lrzip(arch_writer.data()); - break; -#endif -#ifdef ARCHIVE_FILTER_LZ4 - case ARCHIVE_FILTER_LZ4: - ret = archive_write_add_filter_lz4(arch_writer.data()); - break; -#endif -#ifdef ARCHIVE_FILTER_ZSTD - case ARCHIVE_FILTER_ZSTD: - ret = archive_write_add_filter_zstd(arch_writer.data()); - break; -#endif -#ifdef ARCHIVE_FILTER_LZIP - case ARCHIVE_FILTER_LZIP: - ret = archive_write_add_filter_lzip(arch_writer.data()); - break; -#endif -#ifdef ARCHIVE_FILTER_COMPRESS - case ARCHIVE_FILTER_COMPRESS: - ret = archive_write_add_filter_compress(arch_writer.data()); - break; -#endif - case ARCHIVE_FILTER_NONE: - if (filename().right(3).toUpper() == QLatin1String( "ZIP" )) { - ret = archive_write_set_format_zip(arch_writer.data()); - } else if (filename().right(2).toUpper() == QLatin1String( "7Z" )) { - ret = archive_write_set_format_7zip(arch_writer.data()); - } else { - ret = archive_write_add_filter_none(arch_writer.data()); - } - break; - default: - emit error(i18n("The compression type '%1' is not supported by Ark.", QString::fromAscii(archive_filter_name(arch_reader.data(), 0)))); - return false; - } - - if (ret != ARCHIVE_OK) { - emit error(i18nc("@info", "Setting the compression method failed with the following error: %1", QString::fromAscii(archive_error_string(arch_writer.data())))); - return false; - } + const QString strip = (QDir::cleanPath(globalWorkDir) + QDir::separator()); + if (karchive.add(files, QFile::encodeName(strip), QFile::encodeName(rootNode))) { + emit progress(1.0); + return true; } - ret = archive_write_open_filename(arch_writer.data(), QFile::encodeName(tempFilename)); - if (ret != ARCHIVE_OK) { - emit error(i18nc("@info", "Opening the archive for writing failed with the following error: %1", QString::fromAscii(archive_error_string(arch_writer.data())))); - return false; - } - - //**************** first write the new files - foreach(const QString& selectedFile, files) { - bool success; - - success = writeFile(selectedFile, arch_writer.data()); - - if (!success) { - QFile::remove(tempFilename); - return false; - } - - if (QFileInfo(selectedFile).isDir()) { - QDirIterator it(selectedFile, - QDir::AllEntries | QDir::Readable | - QDir::Hidden | QDir::NoDotAndDotDot, - QDirIterator::Subdirectories); - - while (it.hasNext()) { - const QString path = it.next(); - - if ((it.fileName() == QLatin1String("..")) || - (it.fileName() == QLatin1String("."))) { - continue; - } - - success = writeFile(path + - (it.fileInfo().isDir() ? QLatin1String( "/" ) : QLatin1String( "" )), - arch_writer.data()); - - if (!success) { - QFile::remove(tempFilename); - return false; - } - } - } - } - - struct archive_entry *entry; - - //and if we have old elements... - if (!creatingNewFile) { - //********** copy old elements from previous archive to new archive - while (archive_read_next_header(arch_reader.data(), &entry) == ARCHIVE_OK) { - if (m_writtenFiles.contains(QFile::decodeName(archive_entry_pathname(entry)))) { - archive_read_data_skip(arch_reader.data()); - kDebug() << "Entry already existing, will be refresh: ===> " << archive_entry_pathname(entry); - continue; - } - - int header_response; - //kDebug() << "Writing entry " << fn; - if ((header_response = archive_write_header(arch_writer.data(), entry)) == ARCHIVE_OK) { - //if the whole archive is extracted and the total filesize is - //available, we use partial progress - copyData(arch_reader.data(), arch_writer.data(), false); - } else { - kDebug() << "Writing header failed with error code " << header_response; - QFile::remove(tempFilename); - return false; - } - - archive_entry_clear(entry); - } - - //everything seems OK, so we remove the source file and replace it with - //the new one. - //TODO: do some extra checks to see if this is really OK - QFile::remove(filename()); - } - - QFile::rename(tempFilename, filename()); - - return true; + emit error(karchive.errorString()); + return false; } -bool LibArchiveInterface::deleteFiles(const QVariantList& files) +bool LibArchiveInterface::deleteFiles(const QVariantList &files) { - const QString tempFilename = filename() + QLatin1String( ".arkWriting" ); - - ArchiveRead arch_reader(archive_read_new()); - if (!(arch_reader.data())) { - emit error(i18n("The archive reader could not be initialized.")); + KArchive karchive(filename()); + if (!karchive.isWritable()) { + emit error(i18nc("@info", "Could not open the archive %1, libarchive cannot handle it.", filename())); return false; } - if (archive_read_support_filter_all(arch_reader.data()) != ARCHIVE_OK) { - return false; + QStringList fileslist; + foreach (const QVariant &variant, files) { + fileslist.append(variant.toString()); } - - if (archive_read_support_format_all(arch_reader.data()) != ARCHIVE_OK) { - return false; - } - - if (archive_read_open_filename(arch_reader.data(), QFile::encodeName(filename()), 10240) != ARCHIVE_OK) { - emit error(i18n("The source file could not be read.")); - return false; - } - - ArchiveWrite arch_writer(archive_write_new()); - if (!(arch_writer.data())) { - emit error(i18n("The archive writer could not be initialized.")); - return false; - } - - //pax_restricted is the libarchive default, let's go with that. - archive_write_set_format_pax_restricted(arch_writer.data()); - - int ret; - switch (archive_filter_code(arch_reader.data(), 0)) { - case ARCHIVE_FILTER_GZIP: - ret = archive_write_add_filter_gzip(arch_writer.data()); - break; - case ARCHIVE_FILTER_BZIP2: - ret = archive_write_add_filter_bzip2(arch_writer.data()); - break; - case ARCHIVE_FILTER_XZ: - ret = archive_write_add_filter_xz(arch_writer.data()); - break; - case ARCHIVE_FILTER_LZMA: - ret = archive_write_add_filter_lzma(arch_writer.data()); - break; -#ifdef ARCHIVE_FILTER_LZOP - case ARCHIVE_FILTER_LZOP: - ret = archive_write_add_filter_lzop(arch_writer.data()); - break; -#endif -#ifdef ARCHIVE_FILTER_LRZIP - case ARCHIVE_FILTER_LRZIP: - ret = archive_write_add_filter_lrzip(arch_writer.data()); - break; -#endif -#ifdef ARCHIVE_FILTER_LZ4 - case ARCHIVE_FILTER_LZ4: - ret = archive_write_add_filter_lz4(arch_writer.data()); - break; -#endif -#ifdef ARCHIVE_FILTER_ZSTD - case ARCHIVE_FILTER_ZSTD: - ret = archive_write_add_filter_zstd(arch_writer.data()); - break; -#endif -#ifdef ARCHIVE_FILTER_LZIP - case ARCHIVE_FILTER_LZIP: - ret = archive_write_add_filter_lzip(arch_writer.data()); - break; -#endif -#ifdef ARCHIVE_FILTER_COMPRESS - case ARCHIVE_FILTER_COMPRESS: - ret = archive_write_add_filter_compress(arch_writer.data()); - break; -#endif - case ARCHIVE_FILTER_NONE: - if (filename().right(3).toUpper() == QLatin1String( "ZIP" )) { - ret = archive_write_set_format_zip(arch_writer.data()); - } else if (filename().right(2).toUpper() == QLatin1String( "7Z" )) { - ret = archive_write_set_format_7zip(arch_writer.data()); - } else { - ret = archive_write_add_filter_none(arch_writer.data()); + if (karchive.remove(fileslist)) { + foreach (const QString &file, fileslist) { + emit entryRemoved(file); } - break; - default: - emit error(i18n("The compression type '%1' is not supported by Ark.", QString::fromAscii(archive_filter_name(arch_reader.data(), 0)))); - return false; + emit progress(1.0); + return true; } - if (ret != ARCHIVE_OK) { - emit error(i18nc("@info", "Setting the compression method failed with the following error: %1", QString::fromAscii(archive_error_string(arch_writer.data())))); - return false; - } - - ret = archive_write_open_filename(arch_writer.data(), QFile::encodeName(tempFilename)); - if (ret != ARCHIVE_OK) { - emit error(i18nc("@info", "Opening the archive for writing failed with the following error: %1", QString::fromAscii(archive_error_string(arch_writer.data())))); - return false; - } - - struct archive_entry *entry; - - //********** copy old elements from previous archive to new archive - while (archive_read_next_header(arch_reader.data(), &entry) == ARCHIVE_OK) { - if (files.contains(QFile::decodeName(archive_entry_pathname(entry)))) { - archive_read_data_skip(arch_reader.data()); - kDebug() << "Entry to be deleted, skipping" - << archive_entry_pathname(entry); - emit entryRemoved(QFile::decodeName(archive_entry_pathname(entry))); - continue; - } - - int header_response; - //kDebug() << "Writing entry " << fn; - if ((header_response = archive_write_header(arch_writer.data(), entry)) == ARCHIVE_OK) { - //if the whole archive is extracted and the total filesize is - //available, we use partial progress - copyData(arch_reader.data(), arch_writer.data(), false); - } else { - kDebug() << "Writing header failed with error code " << header_response; - return false; - } - } - - //everything seems OK, so we remove the source file and replace it with - //the new one. - //TODO: do some extra checks to see if this is really OK - QFile::remove(filename()); - QFile::rename(tempFilename, filename()); - - return true; -} - -void LibArchiveInterface::emitEntryFromArchiveEntry(struct archive_entry *aentry) -{ - ArchiveEntry e; - - e[FileName] = QDir::fromNativeSeparators(QString::fromUtf8(archive_entry_pathname_utf8(aentry))); - e[InternalID] = e[FileName]; - - const QString owner = QString::fromAscii(archive_entry_uname(aentry)); - if (!owner.isEmpty()) { - e[Owner] = owner; - } - - const QString group = QString::fromAscii(archive_entry_gname(aentry)); - if (!group.isEmpty()) { - e[Group] = group; - } - - e[Size] = (qlonglong)archive_entry_size(aentry); - const mode_t amode = archive_entry_mode(aentry); - e[IsDirectory] = S_ISDIR(amode); - e[Permissions] = ReadWriteArchiveInterface::permissionsString(amode); -#if ARCHIVE_VERSION_NUMBER >= 3002000 - e[IsPasswordProtected] = archive_entry_is_encrypted(aentry); -#endif - - if (archive_entry_symlink(aentry)) { - e[Link] = QString::fromAscii( archive_entry_symlink(aentry) ); - } - - e[Timestamp] = QDateTime::fromTime_t(archive_entry_mtime(aentry)); - - emit entry(e); -} - -int LibArchiveInterface::extractionFlags() const -{ - int result = ARCHIVE_EXTRACT_TIME; - result |= ARCHIVE_EXTRACT_SECURE_NODOTDOT; - - // TODO: Don't use arksettings here - /*if ( ArkSettings::preservePerms() ) - { - result &= ARCHIVE_EXTRACT_PERM; - } - - if ( !ArkSettings::extractOverwrite() ) - { - result &= ARCHIVE_EXTRACT_NO_OVERWRITE; - }*/ - - return result; -} - -void LibArchiveInterface::copyData(const QString& filename, struct archive *dest, bool partialprogress) -{ - char buff[10240]; - ssize_t readBytes; - QFile file(filename); - - if (!file.open(QIODevice::ReadOnly)) { - return; - } - - readBytes = file.read(buff, sizeof(buff)); - while (readBytes > 0) { - /* int writeBytes = */ - archive_write_data(dest, buff, readBytes); - if (archive_errno(dest) != ARCHIVE_OK) { - kDebug() << "Error while writing..." << archive_error_string(dest) << "(error nb =" << archive_errno(dest) << ')'; - return; - } - - if (partialprogress) { - m_currentExtractedFilesSize += readBytes; - emit progress(float(m_currentExtractedFilesSize) / m_extractedFilesSize); - } - - readBytes = file.read(buff, sizeof(buff)); - } - - file.close(); -} - -void LibArchiveInterface::copyData(struct archive *source, struct archive *dest, bool partialprogress) -{ - char buff[10240]; - ssize_t readBytes; - - readBytes = archive_read_data(source, buff, sizeof(buff)); - while (readBytes > 0) { - /* int writeBytes = */ - archive_write_data(dest, buff, readBytes); - if (archive_errno(dest) != ARCHIVE_OK) { - kDebug() << "Error while extracting..." << archive_error_string(dest) << "(error nb =" << archive_errno(dest) << ')'; - return; - } - - if (partialprogress) { - m_currentExtractedFilesSize += readBytes; - emit progress(float(m_currentExtractedFilesSize) / m_extractedFilesSize); - } - - readBytes = archive_read_data(source, buff, sizeof(buff)); - } -} - -// TODO: if we merge this with copyData(), we can pass more data -// such as an fd to archive_read_disk_entry_from_file() -bool LibArchiveInterface::writeFile(const QString& fileName, struct archive* arch_writer) -{ - int header_response; - - const bool trailingSlash = fileName.endsWith(QLatin1Char( '/' )); - - // #191821: workDir must be used instead of QDir::current() - // so that symlinks aren't resolved automatically - // TODO: this kind of call should be moved upwards in the - // class hierarchy to avoid code duplication - const QString relativeName = m_workDir.relativeFilePath(fileName) + (trailingSlash ? QLatin1String( "/" ) : QLatin1String( "" )); - - // #253059: Even if we use archive_read_disk_entry_from_file, - // libarchive may have been compiled without HAVE_LSTAT, - // or something may have caused it to follow symlinks, in - // which case stat() will be called. To avoid this, we - // call lstat() ourselves. -#warning using struct stat instead of QT_STATBUF until libarchive can handle struct stat64 - struct stat st; - ::lstat(QFile::encodeName(fileName).constData(), &st); - - struct archive_entry *entry = archive_entry_new(); - archive_entry_set_pathname(entry, QFile::encodeName(relativeName).constData()); - archive_entry_copy_sourcepath(entry, QFile::encodeName(fileName).constData()); - archive_read_disk_entry_from_file(m_archiveReadDisk.data(), entry, -1, &st); - - kDebug() << "Writing new entry " << archive_entry_pathname(entry); - if ((header_response = archive_write_header(arch_writer, entry)) == ARCHIVE_OK) { - //if the whole archive is extracted and the total filesize is - //available, we use partial progress - copyData(fileName, arch_writer, false); - } else { - kDebug() << "Writing header failed with error code " << header_response; - kDebug() << "Error while writing..." << archive_error_string(arch_writer) << "(error nb =" << archive_errno(arch_writer) << ')'; - - emit error(i18nc("@info Error in a message box", - "Ark could not compress %1:%2", - fileName, - QLatin1String(archive_error_string(arch_writer)))); - - archive_entry_free(entry); - - return false; - } - - m_writtenFiles.push_back(relativeName); - - emitEntryFromArchiveEntry(entry); - - archive_entry_free(entry); - - return true; + emit error(karchive.errorString()); + return false; } KERFUFFLE_EXPORT_PLUGIN(LibArchiveInterface) diff --git a/ark/plugins/libarchive/libarchivehandler.h b/ark/plugins/libarchive/libarchivehandler.h index 088c0fe8..5d779ec9 100644 --- a/ark/plugins/libarchive/libarchivehandler.h +++ b/ark/plugins/libarchive/libarchivehandler.h @@ -29,9 +29,6 @@ #include "kerfuffle/archiveinterface.h" -#include -#include -#include #include using namespace Kerfuffle; @@ -41,35 +38,13 @@ class LibArchiveInterface: public ReadWriteArchiveInterface Q_OBJECT public: - explicit LibArchiveInterface(QObject *parent, const QVariantList& args); + explicit LibArchiveInterface(QObject *parent, const QVariantList &args); ~LibArchiveInterface(); - bool list(); - bool doKill(); - bool copyFiles(const QVariantList& files, const QString& destinationDirectory, ExtractionOptions options); - bool addFiles(const QStringList& files, const CompressionOptions& options); - bool deleteFiles(const QVariantList& files); - -private: - void emitEntryFromArchiveEntry(struct archive_entry *entry); - int extractionFlags() const; - void copyData(const QString& filename, struct archive *dest, bool partialprogress = true); - void copyData(struct archive *source, struct archive *dest, bool partialprogress = true); - bool writeFile(const QString& fileName, struct archive* arch); - - struct ArchiveReadCustomDeleter; - struct ArchiveWriteCustomDeleter; - typedef QScopedPointer ArchiveRead; - typedef QScopedPointer ArchiveWrite; - - int m_cachedArchiveEntryCount; - qlonglong m_currentExtractedFilesSize; - bool m_emitNoEntries; - qlonglong m_extractedFilesSize; - QDir m_workDir; - QStringList m_writtenFiles; - ArchiveRead m_archiveReadDisk; - bool m_abortOperation; + bool list() final; + bool copyFiles(const QVariantList& files, const QString &destinationDirectory, ExtractionOptions options) final; + bool addFiles(const QStringList& files, const CompressionOptions &options) final; + bool deleteFiles(const QVariantList& files) final; }; #endif // LIBARCHIVEHANDLER_H diff --git a/okular/CMakeLists.txt b/okular/CMakeLists.txt index 51c76d05..4f7cc934 100644 --- a/okular/CMakeLists.txt +++ b/okular/CMakeLists.txt @@ -173,6 +173,7 @@ add_library(okularcore SHARED ${okularcore_SRCS}) target_link_libraries(okularcore ${KDE4_KIO_LIBS} + ${KDE4_KARCHIVE_LIBS} ${MATH_LIB} KDE4::kmediaplayer ) diff --git a/okular/core/document.cpp b/okular/core/document.cpp index b506a386..90702b1e 100644 --- a/okular/core/document.cpp +++ b/okular/core/document.cpp @@ -13,6 +13,7 @@ #include "documentcommands_p.h" #include +#include #if defined(Q_OS_FREEBSD) #include @@ -46,9 +47,10 @@ #include #include #include +#include #include #include -#include +#include // local includes #include "action.h" @@ -4044,20 +4046,17 @@ Document::OpenResult Document::openDocumentArchive( const QString & docFile, con if ( !mime->is( "application/vnd.kde.okular-archive" ) ) return OpenError; - KZip okularArchive( docFile ); - if ( !okularArchive.open( QIODevice::ReadOnly ) ) + KArchive okularArchive( docFile ); + if ( !okularArchive.isReadable() ) return OpenError; - const KArchiveDirectory * mainDir = okularArchive.directory(); - const KArchiveEntry * mainEntry = mainDir->entry( "content.xml" ); - if ( !mainEntry || !mainEntry->isFile() ) + const KArchiveEntry mainEntry = okularArchive.entry( "content.xml" ); + if ( !S_ISREG(mainEntry.mode) ) return OpenError; - std::unique_ptr< QIODevice > mainEntryDevice( static_cast< const KZipFileEntry * >( mainEntry )->createDevice() ); QDomDocument doc; - if ( !doc.setContent( mainEntryDevice.get() ) ) + if ( !doc.setContent( okularArchive.data("content.xml") ) ) return OpenError; - mainEntryDevice.reset(); QDomElement root = doc.documentElement(); if ( root.tagName() != "OkularArchive" ) @@ -4083,8 +4082,8 @@ Document::OpenResult Document::openDocumentArchive( const QString & docFile, con if ( documentFileName.isEmpty() ) return OpenError; - const KArchiveEntry * docEntry = mainDir->entry( documentFileName ); - if ( !docEntry || !docEntry->isFile() ) + const KArchiveEntry docEntry = okularArchive.entry( documentFileName ); + if ( !S_ISREG(docEntry.mode) ) return OpenError; std::unique_ptr< ArchiveData > archiveData( new ArchiveData() ); @@ -4096,19 +4095,17 @@ Document::OpenResult Document::openDocumentArchive( const QString & docFile, con QString tempFileName = archiveData->document.fileName(); { - std::unique_ptr< QIODevice > docEntryDevice( static_cast< const KZipFileEntry * >( docEntry )->createDevice() ); - copyQIODevice( docEntryDevice.get(), &archiveData->document ); + copyData( okularArchive.data( documentFileName ), &archiveData->document ); archiveData->document.close(); } - const KArchiveEntry * metadataEntry = mainDir->entry( metadataFileName ); - if ( metadataEntry && metadataEntry->isFile() ) + const KArchiveEntry metadataEntry = okularArchive.entry( metadataFileName ); + if ( S_ISREG(metadataEntry.mode) ) { - std::unique_ptr< QIODevice > metadataEntryDevice( static_cast< const KZipFileEntry * >( metadataEntry )->createDevice() ); archiveData->metadataFile.setSuffix( ".xml" ); if ( archiveData->metadataFile.open() ) { - copyQIODevice( metadataEntryDevice.get(), &archiveData->metadataFile ); + copyData( okularArchive.data( metadataFileName ), &archiveData->metadataFile ); archiveData->metadataFile.close(); } } @@ -4146,13 +4143,6 @@ bool Document::saveDocumentArchive( const QString &fileName ) if ( fi.isSymLink() ) docPath = fi.readLink(); - KZip okularArchive( fileName ); - if ( !okularArchive.open( QIODevice::WriteOnly ) ) - return false; - - const KUser user; - const KUserGroup userGroup( user.gid() ); - QDomDocument contentDoc( "OkularArchive" ); QDomProcessingInstruction xmlPi = contentDoc.createProcessingInstruction( QString::fromLatin1( "xml" ), QString::fromLatin1( "version=\"1.0\" encoding=\"utf-8\"" ) ); @@ -4200,14 +4190,64 @@ bool Document::saveDocumentArchive( const QString &fileName ) return false; const QByteArray contentDocXml = contentDoc.toByteArray(); - okularArchive.writeFile( "content.xml", user.loginName(), userGroup.name(), - contentDocXml.constData(), contentDocXml.length() ); - okularArchive.addLocalFile( docPath, docFileName ); - okularArchive.addLocalFile( metadataFile.fileName(), "metadata.xml" ); - - if ( !okularArchive.close() ) + KTempDir tmpDir; + if (tmpDir.status() != 0) { + kWarning(OkularDebug) << "creating temproary directory failed: " << qt_error_string(tmpDir.status()); return false; + } + + const QString contentCopy = tmpDir.name() + QLatin1String("/content.xml"); + { + QFile tmpFile(contentCopy); + if (!tmpFile.open(QFile::WriteOnly)) { + kWarning(OkularDebug) << "opening temporary content.xml failed: " << tmpFile.errorString(); + return false; + } + tmpFile.write(contentDocXml.constData(), contentDocXml.length()); + } + + const QString docCopy = tmpDir.name() + QDir::separator() + docFileName; + { + QFile tmpFile(docPath); + if (!tmpFile.copy(docCopy)) { + kWarning(OkularDebug) << "copying doc path failed: " << tmpFile.errorString(); + return false; + } + } + + const QString metadataCopy = tmpDir.name() + QLatin1String("/metdata.xml"); + { + QFile tmpFile(metadataFile.fileName()); + if (!tmpFile.copy(metadataCopy)) { + kWarning(OkularDebug) << "copying metdata failed: " << tmpFile.errorString(); + return false; + } + } + + // KArchive uses the extension to figure out the format when writing + QString tmpArchive = fileName; + if (!tmpArchive.endsWith(".zip")) { + tmpArchive.append(QLatin1String(".zip")); + } + + KArchive okularArchive( tmpArchive ); + if ( !okularArchive.isWritable() ) { + return false; + } + + if (!okularArchive.add(QStringList() << contentCopy << docCopy << metadataCopy, QFile::encodeName(tmpDir.name()))) { + kWarning(OkularDebug) << "adding to archive failed: " << okularArchive.errorString(); + return false; + } + + if (tmpArchive != fileName) { + QFile tmpFile(tmpArchive); + if (!tmpFile.rename(fileName)) { + kWarning(OkularDebug) << "renaming temporary archive failed: " << tmpFile.errorString(); + return false; + } + } return true; } diff --git a/okular/core/utils.cpp b/okular/core/utils.cpp index 30fad097..9e165932 100644 --- a/okular/core/utils.cpp +++ b/okular/core/utils.cpp @@ -216,6 +216,11 @@ void Okular::copyQIODevice( QIODevice *from, QIODevice *to ) } } +void Okular::copyData( const QByteArray &data, QIODevice *to ) +{ + to->write( data.constData(), data.size() ); +} + QTransform Okular::buildRotationMatrix(Rotation rotation) { QTransform matrix; diff --git a/okular/core/utils_p.h b/okular/core/utils_p.h index 3221f219..36bf398c 100644 --- a/okular/core/utils_p.h +++ b/okular/core/utils_p.h @@ -17,6 +17,8 @@ namespace Okular void copyQIODevice( QIODevice *from, QIODevice *to ); +void copyData( const QByteArray &data, QIODevice *to ); + /** * Return a rotation matrix corresponding to the @p rotation enumeration. */ diff --git a/okular/generators/comicbook/CMakeLists.txt b/okular/generators/comicbook/CMakeLists.txt index 41d8f020..962e2b6d 100644 --- a/okular/generators/comicbook/CMakeLists.txt +++ b/okular/generators/comicbook/CMakeLists.txt @@ -9,13 +9,12 @@ set(okularGenerator_comicbook_PART_SRCS document.cpp generator_comicbook.cpp directory.cpp - unrar.cpp qnatsort.cpp - unrarflavours.cpp + qnatsort.cpp ) kde4_add_plugin(okularGenerator_comicbook ${okularGenerator_comicbook_PART_SRCS}) -target_link_libraries(okularGenerator_comicbook okularcore ${KDE4_KIO_LIBS} ) +target_link_libraries(okularGenerator_comicbook okularcore ${KDE4_KIO_LIBS} ${KDE4_KARCHIVE_LIBS}) if (UNIX) target_link_libraries(okularGenerator_comicbook ${KDE4_KPTY_LIBS}) endif (UNIX) diff --git a/okular/generators/comicbook/document.cpp b/okular/generators/comicbook/document.cpp index ad36b9af..9c7f623a 100644 --- a/okular/generators/comicbook/document.cpp +++ b/okular/generators/comicbook/document.cpp @@ -10,39 +10,37 @@ #include "document.h" #include +#include +#include #include #include #include #include -#include -#include +#include +#include #include #include -#include "unrar.h" #include "directory.h" #include "qnatsort.h" using namespace ComicBook; -static void imagesInArchive( const QString &prefix, const KArchiveDirectory* dir, QStringList *entries ) +static void imagesInArchive( const KArchive* archive, QStringList *entries ) { - Q_FOREACH ( const QString &entry, dir->entries() ) { - const KArchiveEntry *e = dir->entry( entry ); - if ( e->isDirectory() ) { - imagesInArchive( prefix + entry + '/', static_cast( e ), entries ); - } else if ( e->isFile() ) { - entries->append( prefix + entry ); + Q_FOREACH ( const KArchiveEntry &entry, archive->list() ) { + if ( S_ISREG(entry.mode) ) { + entries->append( QFile::decodeName(entry.pathname) ); } } } Document::Document() - : mDirectory( 0 ), mUnrar( 0 ), mArchive( 0 ) + : mDirectory( 0 ), mArchive( 0 ) { } @@ -58,48 +56,18 @@ bool Document::open( const QString &fileName ) // qDebug() << Q_FUNC_INFO << mime->name(); /** - * We have a zip archive + * We have a 7-zip, zip or rar archive */ - if ( mime->is( "application/x-cbz" ) || mime->is( "application/zip" ) ) { - mArchive = new KZip( fileName ); + if ( mime->is( "application/x-cb7" ) || + mime->is( "application/x-cbz" ) || mime->is( "application/zip" ) || + mime->is( "application/x-cbt" ) || mime->is( "application/x-gzip" ) || + mime->is( "application/x-tar" ) || mime->is( "application/x-bzip" ) || + mime->is( "application/x-cbr" ) || mime->is( "application/x-rar" )) { + mArchive = new KArchive( fileName ); if ( !processArchive() ) { return false; } - /** - * We have a TAR archive - */ - } else if ( mime->is( "application/x-cbt" ) || mime->is( "application/x-gzip" ) || - mime->is( "application/x-tar" ) || mime->is( "application/x-bzip" ) ) { - mArchive = new KTar( fileName ); - - if ( !processArchive() ) { - return false; - } - } else if ( mime->is( "application/x-cbr" ) || mime->is( "application/x-rar" ) ) { - if ( !Unrar::isAvailable() ) { - mLastErrorString = i18n( "Cannot open document, unrar was not found." ); - return false; - } - - if ( !Unrar::isSuitableVersionAvailable() ) { - mLastErrorString = i18n( "The version of unrar on your system is not suitable for opening comicbooks." ); - return false; - } - - /** - * We have a rar archive - */ - mUnrar = new Unrar(); - - if ( !mUnrar->open( fileName ) ) { - delete mUnrar; - mUnrar = 0; - - return false; - } - - mEntries = mUnrar->list(); } else if ( mime->is( "inode/directory" ) ) { mDirectory = new Directory(); @@ -123,38 +91,26 @@ void Document::close() { mLastErrorString.clear(); - if ( !( mArchive || mUnrar || mDirectory ) ) + if ( !( mArchive || mDirectory ) ) return; delete mArchive; mArchive = 0; delete mDirectory; mDirectory = 0; - delete mUnrar; - mUnrar = 0; mPageMap.clear(); mEntries.clear(); } bool Document::processArchive() { - if ( !mArchive->open( QIODevice::ReadOnly ) ) { + if ( !mArchive->isReadable() ) { delete mArchive; mArchive = 0; return false; } - const KArchiveDirectory *directory = mArchive->directory(); - if ( !directory ) { - delete mArchive; - mArchive = 0; - - return false; - } - - mArchiveDir = const_cast( directory ); - - imagesInArchive( QString(), mArchiveDir, &mEntries ); + imagesInArchive( mArchive, &mEntries ); return true; } @@ -170,14 +126,13 @@ void Document::pages( QVector * pagesVector ) QImageReader reader; foreach(const QString &file, mEntries) { if ( mArchive ) { - const KArchiveFile *entry = static_cast( mArchiveDir->entry( file ) ); - if ( entry ) { - dev.reset( entry->createDevice() ); + const KArchiveEntry entry = mArchive->entry( file ); + if ( !entry.isNull() ) { + dev.reset( new QBuffer() ); + qobject_cast(dev.data())->setData( mArchive->data( file) ); } } else if ( mDirectory ) { dev.reset( mDirectory->createDevice( file ) ); - } else { - dev.reset( mUnrar->createDevice( file ) ); } if ( ! dev.isNull() ) { @@ -211,13 +166,11 @@ QStringList Document::pageTitles() const QImage Document::pageImage( int page ) const { if ( mArchive ) { - const KArchiveFile *entry = static_cast( mArchiveDir->entry( mPageMap[ page ] ) ); - if ( entry ) - return QImage::fromData( entry->data() ); + const KArchiveEntry entry = mArchive->entry( mPageMap[ page ] ); + if ( !entry.isNull() ) + return QImage::fromData( mArchive->data( mPageMap[ page ] ) ); } else if ( mDirectory ) { return QImage( mPageMap[ page ] ); - } else { - return QImage::fromData( mUnrar->contentOf( mPageMap[ page ] ) ); } return QImage(); diff --git a/okular/generators/comicbook/document.h b/okular/generators/comicbook/document.h index a9090cba..c6fd2382 100644 --- a/okular/generators/comicbook/document.h +++ b/okular/generators/comicbook/document.h @@ -10,13 +10,11 @@ #ifndef COMICBOOK_DOCUMENT_H #define COMICBOOK_DOCUMENT_H -#include - -class KArchiveDirectory; -class KArchive; +#include #include #include -class Unrar; + +class KArchive; class Directory; namespace Okular { @@ -46,9 +44,7 @@ class Document QStringList mPageMap; Directory *mDirectory; - Unrar *mUnrar; KArchive *mArchive; - KArchiveDirectory *mArchiveDir; QString mLastErrorString; QStringList mEntries; }; diff --git a/okular/generators/comicbook/libokularGenerator_comicbook.desktop b/okular/generators/comicbook/libokularGenerator_comicbook.desktop index 5a91a5fd..ee998c6d 100644 --- a/okular/generators/comicbook/libokularGenerator_comicbook.desktop +++ b/okular/generators/comicbook/libokularGenerator_comicbook.desktop @@ -120,7 +120,7 @@ Comment[x-test]=xxComic book backend for Okularxx Comment[zh_CN]=Okular 的 Comic book 格式后端 Comment[zh_TW]=Okular 的 Comic book 後端 X-KDE-ServiceTypes=okular/Generator -MimeType=application/x-cbz;application/x-cbr;application/x-cbt;inode/directory; +MimeType=application/x-cb7;application/x-cbz;application/x-cbr;application/x-cbt;inode/directory; X-KDE-Library=okularGenerator_comicbook X-KDE-Priority=1 X-KDE-okularAPIVersion=1 diff --git a/okular/generators/comicbook/unrar.cpp b/okular/generators/comicbook/unrar.cpp deleted file mode 100644 index e18ffcd4..00000000 --- a/okular/generators/comicbook/unrar.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Tobias Koenig * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - ***************************************************************************/ - -#include "unrar.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#if !defined(Q_OS_WIN) -#include -#include -#endif - -#include "unrarflavours.h" - -struct UnrarHelper -{ - UnrarHelper(); - ~UnrarHelper(); - - UnrarFlavour *kind; - QString unrarPath; -}; - -K_GLOBAL_STATIC( UnrarHelper, helper ) - -static UnrarFlavour* detectUnrar( const QString &unrarPath, const QString &versionCommand ) -{ - UnrarFlavour* kind = 0; - QProcess proc; - proc.start( unrarPath, QStringList() << versionCommand ); - bool ok = proc.waitForFinished( -1 ); - Q_UNUSED( ok ) - const QStringList lines = QString::fromLocal8Bit( proc.readAllStandardOutput() ).split( '\n', QString::SkipEmptyParts ); - if ( !lines.isEmpty() ) - { - if ( lines.first().startsWith( "UNRAR " ) ) - kind = new NonFreeUnrarFlavour(); - else if ( lines.first().startsWith( "RAR " ) ) - kind = new NonFreeUnrarFlavour(); - else if ( lines.first().startsWith( "unrar " ) ) - kind = new FreeUnrarFlavour(); - } - return kind; -} - -UnrarHelper::UnrarHelper() - : kind( 0 ) -{ - QString path = KStandardDirs::findExe( "unrar-nonfree" ); - if ( path.isEmpty() ) - path = KStandardDirs::findExe( "unrar" ); - if ( path.isEmpty() ) - path = KStandardDirs::findExe( "rar" ); - - if ( !path.isEmpty() ) - kind = detectUnrar( path, "--version" ); - - if ( !kind ) - kind = detectUnrar( path, "-v" ); - - if ( !kind ) - { - // no luck, print that - kDebug() << "No unrar detected."; - } - else - { - unrarPath = path; - kDebug() << "detected:" << path << "(" << kind->name() << ")"; - } -} - -UnrarHelper::~UnrarHelper() -{ - delete kind; -} - - -Unrar::Unrar() - : QObject( 0 ), mLoop( 0 ), mTempDir( 0 ) -{ -} - -Unrar::~Unrar() -{ - delete mTempDir; -} - -bool Unrar::open( const QString &fileName ) -{ - if ( !isSuitableVersionAvailable() ) - return false; - - delete mTempDir; - mTempDir = new KTempDir(); - - mFileName = fileName; - - /** - * Extract the archive to a temporary directory - */ - mStdOutData.clear(); - mStdErrData.clear(); - - int ret = startSyncProcess( QStringList() << "e" << mFileName << mTempDir->name() ); - bool ok = ret == 0; - - return ok; -} - -QStringList Unrar::list() -{ - mStdOutData.clear(); - mStdErrData.clear(); - - if ( !isSuitableVersionAvailable() ) - return QStringList(); - - startSyncProcess( QStringList() << "lb" << mFileName ); - - const QStringList listFiles = helper->kind->processListing( QString::fromLocal8Bit( mStdOutData ).split( '\n', QString::SkipEmptyParts ) ); - QStringList newList; - Q_FOREACH ( const QString &f, listFiles ) { - // Extract all the files to mTempDir regardless of their path inside the archive - // This will break if ever an arvhice with two files with the same name in different subfolders - QFileInfo fi( f ); - if ( QFile::exists( mTempDir->name() + fi.fileName() ) ) { - newList.append( fi.fileName() ); - } - } - return newList; -} - -QByteArray Unrar::contentOf( const QString &fileName ) const -{ - if ( !isSuitableVersionAvailable() ) - return QByteArray(); - - QFile file( mTempDir->name() + fileName ); - if ( !file.open( QIODevice::ReadOnly ) ) - return QByteArray(); - - return file.readAll(); -} - -QIODevice* Unrar::createDevice( const QString &fileName ) const -{ - if ( !isSuitableVersionAvailable() ) - return 0; - - QScopedPointer< QFile> file( new QFile( mTempDir->name() + fileName ) ); - if ( !file->open( QIODevice::ReadOnly ) ) - return 0; - - return file.take(); -} - -bool Unrar::isAvailable() -{ - return helper->kind; -} - -bool Unrar::isSuitableVersionAvailable() -{ - if ( !isAvailable() ) - return false; - - return dynamic_cast< NonFreeUnrarFlavour * >( helper->kind ); -} - -void Unrar::readFromStdout() -{ - if ( !mProcess ) - return; - - mStdOutData += mProcess->readAllStandardOutput(); -} - -void Unrar::readFromStderr() -{ - if ( !mProcess ) - return; - - mStdErrData += mProcess->readAllStandardError(); - if ( !mStdErrData.isEmpty() ) - { - mProcess->kill(); - return; - } -} - -void Unrar::finished( int exitCode, QProcess::ExitStatus exitStatus ) -{ - Q_UNUSED( exitCode ) - if ( mLoop ) - { - mLoop->exit( exitStatus == QProcess::CrashExit ? 1 : 0 ); - } -} - -int Unrar::startSyncProcess( const QStringList &args ) -{ - int ret = 0; - -#if defined(Q_OS_WIN) - mProcess = new QProcess( this ); -#else - mProcess = new KPtyProcess( this ); - mProcess->setOutputChannelMode( KProcess::SeparateChannels ); -#endif - - connect( mProcess, SIGNAL(readyReadStandardOutput()), SLOT(readFromStdout()) ); - connect( mProcess, SIGNAL(readyReadStandardError()), SLOT(readFromStderr()) ); - connect( mProcess, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(finished(int,QProcess::ExitStatus)) ); - -#if defined(Q_OS_WIN) - mProcess->start( helper->unrarPath, args, QIODevice::ReadWrite | QIODevice::Unbuffered ); - ret = mProcess->waitForFinished( -1 ) ? 0 : 1; -#else - mProcess->setProgram( helper->unrarPath, args ); - mProcess->setNextOpenMode( QIODevice::ReadWrite | QIODevice::Unbuffered ); - mProcess->start(); - QEventLoop loop; - mLoop = &loop; - ret = loop.exec( QEventLoop::WaitForMoreEvents | QEventLoop::ExcludeUserInputEvents ); - mLoop = 0; -#endif - - delete mProcess; - mProcess = 0; - - return ret; -} - -void Unrar::writeToProcess( const QByteArray &data ) -{ - if ( !mProcess || data.isNull() ) - return; - -#if defined(Q_OS_WIN) - mProcess->write( data ); -#else - mProcess->pty()->write( data ); -#endif -} - -#include "moc_unrar.cpp" diff --git a/okular/generators/comicbook/unrar.h b/okular/generators/comicbook/unrar.h deleted file mode 100644 index 711a4202..00000000 --- a/okular/generators/comicbook/unrar.h +++ /dev/null @@ -1,81 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Tobias Koenig * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - ***************************************************************************/ - -#ifndef UNRAR_H -#define UNRAR_H - -#include -#include -#include - -#include -class KTempDir; -class KPtyProcess; - -class Unrar : public QObject -{ - Q_OBJECT - - public: - /** - * Creates a new unrar object. - */ - Unrar(); - - /** - * Destroys the unrar object. - */ - ~Unrar(); - - /** - * Opens given rar archive. - */ - bool open( const QString &fileName ); - - /** - * Returns the list of files from the archive. - */ - QStringList list(); - - /** - * Returns the content of the file with the given name. - */ - QByteArray contentOf( const QString &fileName ) const; - - /** - * Returns a new device for reading the file with the given name. - */ - QIODevice* createDevice( const QString &fileName ) const; - - static bool isAvailable(); - static bool isSuitableVersionAvailable(); - - private Q_SLOTS: - void readFromStdout(); - void readFromStderr(); - void finished( int exitCode, QProcess::ExitStatus exitStatus ); - - private: - int startSyncProcess( const QStringList &args ); - void writeToProcess( const QByteArray &data ); - -#if defined(Q_OS_WIN) - QProcess *mProcess; -#else - KPtyProcess *mProcess; -#endif - QEventLoop *mLoop; - QString mFileName; - QByteArray mStdOutData; - QByteArray mStdErrData; - KTempDir *mTempDir; -}; - -#endif - diff --git a/okular/generators/comicbook/unrarflavours.cpp b/okular/generators/comicbook/unrarflavours.cpp deleted file mode 100644 index 7451321a..00000000 --- a/okular/generators/comicbook/unrarflavours.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Pino Toscano * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - ***************************************************************************/ - -#include "unrarflavours.h" - -#include -#include - -UnrarFlavour::UnrarFlavour() -{ -} - -UnrarFlavour::~UnrarFlavour() -{ -} - -void UnrarFlavour::setFileName( const QString &fileName ) -{ - mFileName = fileName; -} - -QString UnrarFlavour::fileName() const -{ - return mFileName; -} - - -NonFreeUnrarFlavour::NonFreeUnrarFlavour() - : UnrarFlavour() -{ -} - -QStringList NonFreeUnrarFlavour::processListing( const QStringList &data ) -{ - // unrar-nonfree just lists the files - return data; -} - -QString NonFreeUnrarFlavour::name() const -{ - return "unrar-nonfree"; -} - - -FreeUnrarFlavour::FreeUnrarFlavour() - : UnrarFlavour() -{ -} - -QStringList FreeUnrarFlavour::processListing( const QStringList &data ) -{ - QRegExp re( "^ ([^/]+/([^\\s]+))$" ); - - QStringList newdata; - foreach ( const QString &line, data ) - { - if ( re.exactMatch( line ) ) - newdata.append( re.cap( 1 ) ); - } - return newdata; -} - -QString FreeUnrarFlavour::name() const -{ - return "unrar-free"; -} - diff --git a/okular/generators/comicbook/unrarflavours.h b/okular/generators/comicbook/unrarflavours.h deleted file mode 100644 index d540b946..00000000 --- a/okular/generators/comicbook/unrarflavours.h +++ /dev/null @@ -1,55 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Pino Toscano * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - ***************************************************************************/ - -#ifndef UNRARFLAVOURS_H -#define UNRARFLAVOURS_H - -#include - -#include - -class UnrarFlavour -{ - public: - virtual ~UnrarFlavour(); - - virtual QStringList processListing( const QStringList &data ) = 0; - virtual QString name() const = 0; - - void setFileName( const QString &fileName ); - - protected: - UnrarFlavour(); - - QString fileName() const; - - private: - QString mFileName; -}; - -class NonFreeUnrarFlavour : public UnrarFlavour -{ - public: - NonFreeUnrarFlavour(); - - virtual QStringList processListing( const QStringList &data ); - virtual QString name() const; -}; - -class FreeUnrarFlavour : public UnrarFlavour -{ - public: - FreeUnrarFlavour(); - - virtual QStringList processListing( const QStringList &data ); - virtual QString name() const; -}; - -#endif - diff --git a/okular/generators/fictionbook/CMakeLists.txt b/okular/generators/fictionbook/CMakeLists.txt index c0161139..a43538fa 100644 --- a/okular/generators/fictionbook/CMakeLists.txt +++ b/okular/generators/fictionbook/CMakeLists.txt @@ -15,7 +15,7 @@ set(okularGenerator_fb_PART_SRCS kde4_add_plugin(okularGenerator_fb ${okularGenerator_fb_PART_SRCS}) -target_link_libraries(okularGenerator_fb okularcore ${KDE4_KIO_LIBS} ${QT_QTXML_LIBRARY}) +target_link_libraries(okularGenerator_fb okularcore ${KDE4_KIO_LIBS} ${KDE4_KARCHIVE_LIBS} ${QT_QTXML_LIBRARY}) install(TARGETS okularGenerator_fb DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}) diff --git a/okular/generators/fictionbook/document.cpp b/okular/generators/fictionbook/document.cpp index e9435660..99628631 100644 --- a/okular/generators/fictionbook/document.cpp +++ b/okular/generators/fictionbook/document.cpp @@ -10,9 +10,10 @@ #include "document.h" #include +#include #include -#include +#include using namespace FictionBook; @@ -26,7 +27,6 @@ bool Document::open() QIODevice *device; QFile file( mFileName ); - KZip zip( mFileName ); if ( mFileName.endsWith( ".fb" ) || mFileName.endsWith( ".fb2" ) ) { if ( !file.open( QIODevice::ReadOnly ) ) { setError( i18n( "Unable to open document: %1", file.errorString() ) ); @@ -35,23 +35,18 @@ bool Document::open() device = &file; } else { - if ( !zip.open( QIODevice::ReadOnly ) ) { + KArchive zip( mFileName ); + if ( !zip.isReadable() ) { setError( i18n( "Document is not a valid ZIP archive" ) ); return false; } - const KArchiveDirectory *directory = zip.directory(); - if ( !directory ) { - setError( i18n( "Invalid document structure (main directory is missing)" ) ); - return false; - } - - const QStringList entries = directory->entries(); + const QList entries = zip.list(); QString documentFile; for ( int i = 0; i < entries.count(); ++i ) { - if ( entries[ i ].endsWith( ".fb2" ) ) { - documentFile = entries[ i ]; + if ( entries[ i ].pathname.endsWith( ".fb2" ) ) { + documentFile = QFile::decodeName(entries[ i ].pathname); break; } } @@ -61,9 +56,9 @@ bool Document::open() return false; } - const KArchiveFile *entry = static_cast( directory->entry( documentFile ) ); // FIXME delete 'deviceì somewhen - device = entry->createDevice(); + device = new QBuffer(); + qobject_cast(device)->setData( zip.data( documentFile ) ); } QString errorMsg; diff --git a/okular/generators/ooo/CMakeLists.txt b/okular/generators/ooo/CMakeLists.txt index e74d24d8..4a6a7595 100644 --- a/okular/generators/ooo/CMakeLists.txt +++ b/okular/generators/ooo/CMakeLists.txt @@ -25,6 +25,7 @@ kde4_add_plugin(okularGenerator_ooo ${okularGenerator_ooo_PART_SRCS}) target_link_libraries(okularGenerator_ooo ${KDE4_KIO_LIBS} + ${KDE4_KARCHIVE_LIBS} ${MATH_LIB} ${QT_QTXML_LIBRARY} ${QT_QTNETWORK_LIBRARY} diff --git a/okular/generators/ooo/document.cpp b/okular/generators/ooo/document.cpp index 6874cdce..a7bd5c5f 100644 --- a/okular/generators/ooo/document.cpp +++ b/okular/generators/ooo/document.cpp @@ -9,8 +9,10 @@ #include "document.h" +#include + #include -#include +#include using namespace OOO; @@ -24,86 +26,64 @@ bool Document::open( const QString &password ) mContent.clear(); mStyles.clear(); - KZip zip( mFileName ); - if ( !zip.open( QIODevice::ReadOnly ) ) { + KArchive zip( mFileName ); + if ( !zip.isReadable() ) { setError( i18n( "Document is not a valid ZIP archive" ) ); return false; } - const KArchiveDirectory *directory = zip.directory(); - if ( !directory ) { - setError( i18n( "Invalid document structure (main directory is missing)" ) ); - return false; - } - - const QStringList entries = directory->entries(); - if ( !entries.contains( "META-INF" ) ) { - setError( i18n( "Invalid document structure (META-INF directory is missing)" ) ); - return false; - } - const KArchiveDirectory *metaInfDirectory = static_cast( directory->entry( "META-INF" ) ); - if ( !(metaInfDirectory->entries().contains( "manifest.xml" ) ) ) { + if ( zip.entry( "META-INF/manifest.xml" ).isNull() ) { setError( i18n( "Invalid document structure (META-INF/manifest.xml is missing)" ) ); return false; } - const KArchiveFile *file = static_cast( metaInfDirectory->entry( "manifest.xml" ) ); - mManifest = new Manifest( mFileName, file->data(), password ); + mManifest = new Manifest( mFileName, zip.data( "META-INF/manifest.xml" ), password ); // we should really get the file names from the manifest, but for now, we only care // if the manifest says the files are encrypted. - if ( !entries.contains( "content.xml" ) ) { + if ( zip.entry( "content.xml" ).isNull() ) { setError( i18n( "Invalid document structure (content.xml is missing)" ) ); return false; } - file = static_cast( directory->entry( "content.xml" ) ); if ( mManifest->testIfEncrypted( "content.xml" ) ) { mAnyEncrypted = true; - mContent = mManifest->decryptFile( "content.xml", file->data() ); + mContent = mManifest->decryptFile( "content.xml", zip.data( "content.xml" ) ); } else { - mContent = file->data(); + mContent = zip.data( "content.xml" ); } - if ( entries.contains( "styles.xml" ) ) { - file = static_cast( directory->entry( "styles.xml" ) ); + if ( !zip.entry( "styles.xml" ).isNull() ) { if ( mManifest->testIfEncrypted( "styles.xml" ) ) { mAnyEncrypted = true; - mStyles = mManifest->decryptFile( "styles.xml", file->data() ); + mStyles = mManifest->decryptFile( "styles.xml", zip.data( "styles.xml" ) ); } else { - mStyles = file->data(); + mStyles = zip.data( "styles.xml" ); } } - if ( entries.contains( "meta.xml" ) ) { - file = static_cast( directory->entry( "meta.xml" ) ); + if ( !zip.entry( "meta.xml" ).isNull() ) { if ( mManifest->testIfEncrypted( "meta.xml" ) ) { mAnyEncrypted = true; - mMeta = mManifest->decryptFile( "meta.xml", file->data() ); + mMeta = mManifest->decryptFile( "meta.xml", zip.data( "meta.xml" ) ); } else { - mMeta = file->data(); + mMeta = zip.data( "meta.xml" ); } } - if ( entries.contains( "Pictures" ) ) { - const KArchiveDirectory *imagesDirectory = static_cast( directory->entry( "Pictures" ) ); - - const QStringList imagesEntries = imagesDirectory->entries(); - for ( int i = 0; i < imagesEntries.count(); ++i ) { - file = static_cast( imagesDirectory->entry( imagesEntries[ i ] ) ); - QString fullPath = QString( "Pictures/%1" ).arg( imagesEntries[ i ] ); + foreach (const KArchiveEntry &entry, zip.list()) { + if ( entry.pathname.startsWith("Pictures/") ) { + QString fullPath = QFile::decodeName( entry.pathname ); if ( mManifest->testIfEncrypted( fullPath ) ) { mAnyEncrypted = true; - mImages.insert( fullPath, mManifest->decryptFile( fullPath, file->data() ) ); + mImages.insert( fullPath, mManifest->decryptFile( fullPath, zip.data( fullPath ) ) ); } else { - mImages.insert( fullPath, file->data() ); + mImages.insert( fullPath, zip.data( fullPath ) ); } } } - zip.close(); - return true; } diff --git a/okular/generators/xps/CMakeLists.txt b/okular/generators/xps/CMakeLists.txt index 5f65b012..54bd2ed4 100644 --- a/okular/generators/xps/CMakeLists.txt +++ b/okular/generators/xps/CMakeLists.txt @@ -12,7 +12,7 @@ set(okularGenerator_xps_SRCS kde4_add_plugin(okularGenerator_xps ${okularGenerator_xps_SRCS}) -target_link_libraries(okularGenerator_xps okularcore ${KDE4_KIO_LIBS} ${QT_QTXML_LIBRARY}) +target_link_libraries(okularGenerator_xps okularcore ${KDE4_KIO_LIBS} ${KDE4_KARCHIVE_LIBS} ${QT_QTXML_LIBRARY}) install(TARGETS okularGenerator_xps DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}) diff --git a/okular/generators/xps/generator_xps.cpp b/okular/generators/xps/generator_xps.cpp index 378c503d..1f891089 100644 --- a/okular/generators/xps/generator_xps.cpp +++ b/okular/generators/xps/generator_xps.cpp @@ -40,6 +40,8 @@ #include #include +#include + const int XpsDebug = 4712; static KAboutData createAboutData() @@ -458,9 +460,9 @@ static QString entryPath( const QString &entry ) /** \return The path of the entry */ -static QString entryPath( const KZipFileEntry* entry ) +static QString entryPath( const KArchiveEntry* entry ) { - return entryPath( entry->path() ); + return entryPath( QFile::decodeName(entry->pathname) ); } /** @@ -498,26 +500,21 @@ static QString absolutePath( const QString &path, const QString &location ) \see XPS specification 10.1.2 */ -static QByteArray readFileOrDirectoryParts( const KArchiveEntry *entry, QString *pathOfFile = 0 ) +static QByteArray readFileOrDirectoryParts(KArchive *archive, const KArchiveEntry *entry, QString *pathOfFile = 0 ) { QByteArray data; - if ( entry->isDirectory() ) { - const KArchiveDirectory* relDir = static_cast( entry ); - QStringList entries = relDir->entries(); - qSort( entries ); - Q_FOREACH ( const QString &entry, entries ) { - const KArchiveEntry* relSubEntry = relDir->entry( entry ); - if ( !relSubEntry->isFile() ) + if ( S_ISDIR(entry->mode) ) { + const QList entries = archive->list( entry->pathname ); + Q_FOREACH ( const KArchiveEntry &ee, entries ) { + if ( !S_ISREG(ee.mode) ) continue; - const KZipFileEntry* relSubFile = static_cast( relSubEntry ); - data.append( relSubFile->data() ); + data.append( archive->data( ee.pathname ) ); } } else { - const KZipFileEntry* relFile = static_cast( entry ); - data.append( relFile->data() ); + data.append( archive->data( entry->pathname) ); if ( pathOfFile ) { - *pathOfFile = entryPath( relFile ); + *pathOfFile = entryPath( entry ); } } return data; @@ -526,12 +523,12 @@ static QByteArray readFileOrDirectoryParts( const KArchiveEntry *entry, QString /** Load the resource \p fileName from the specified \p archive using the case sensitivity \p cs */ -static const KArchiveEntry* loadEntry( KZip *archive, const QString &fileName, Qt::CaseSensitivity cs ) +static const KArchiveEntry loadEntry( KArchive *archive, const QString &fileName, Qt::CaseSensitivity cs ) { // first attempt: loading the entry straight as requested - const KArchiveEntry* entry = archive->directory()->entry( fileName ); + const KArchiveEntry entry = archive->entry( fileName ); // in case sensitive mode, or if we actually found something, return what we found - if ( cs == Qt::CaseSensitive || entry ) { + if ( cs == Qt::CaseSensitive || !entry.isNull() ) { return entry; } @@ -546,24 +543,15 @@ static const KArchiveEntry* loadEntry( KZip *archive, const QString &fileName, Q path = '/'; entryName = fileName; } - const KArchiveEntry * newEntry = archive->directory()->entry( path ); - if ( newEntry->isDirectory() ) { - const KArchiveDirectory* relDir = static_cast< const KArchiveDirectory * >( newEntry ); - QStringList relEntries = relDir->entries(); - qSort( relEntries ); - Q_FOREACH ( const QString &relEntry, relEntries ) { - if ( relEntry.compare( entryName, Qt::CaseInsensitive ) == 0 ) { - return relDir->entry( relEntry ); + const KArchiveEntry newEntry = archive->entry( path ); + if ( S_ISDIR(newEntry.mode) ) { + Q_FOREACH ( const KArchiveEntry &relEntry, archive->list( newEntry.pathname ) ) { + if ( QFile::decodeName(relEntry.pathname).compare( entryName, Qt::CaseInsensitive ) == 0 ) { + return relEntry; } } } - return 0; -} - -static const KZipFileEntry* loadFile( KZip *archive, const QString &fileName, Qt::CaseSensitivity cs ) -{ - const KArchiveEntry *entry = loadEntry( archive, fileName, cs ); - return entry->isFile() ? static_cast< const KZipFileEntry * >( entry ) : 0; + return KArchiveEntry(); } static QColor interpolatedColor( const QColor &c1, const QColor &c2 ) @@ -1366,10 +1354,10 @@ XpsPage::XpsPage(XpsFile *file, const QString &fileName): m_file( file ), // kDebug(XpsDebug) << "page file name: " << fileName; - const KZipFileEntry* pageFile = static_cast(m_file->xpsArchive()->directory()->entry( fileName )); + const KArchiveEntry pageFile = m_file->xpsArchive()->entry( fileName ); QXmlStreamReader xml; - xml.addData( readFileOrDirectoryParts( pageFile ) ); + xml.addData( readFileOrDirectoryParts( m_file->xpsArchive(), &pageFile ) ); while ( !xml.atEnd() ) { xml.readNext(); @@ -1424,8 +1412,8 @@ bool XpsPage::renderToPainter( QPainter *painter ) QXmlSimpleReader parser; parser.setContentHandler( &handler ); parser.setErrorHandler( &handler ); - const KZipFileEntry* pageFile = static_cast(m_file->xpsArchive()->directory()->entry( m_fileName )); - QByteArray data = readFileOrDirectoryParts( pageFile ); + const KArchiveEntry pageFile = m_file->xpsArchive()->entry( m_fileName ); + QByteArray data = readFileOrDirectoryParts( m_file->xpsArchive(), &pageFile ); QBuffer buffer( &data ); QXmlInputSource source( &buffer ); bool ok = parser.parse( source ); @@ -1460,12 +1448,12 @@ int XpsFile::loadFontByName( const QString &fileName ) { // kDebug(XpsDebug) << "font file name: " << fileName; - const KArchiveEntry* fontFile = loadEntry( m_xpsArchive, fileName, Qt::CaseInsensitive ); - if ( !fontFile ) { + const KArchiveEntry fontFile = loadEntry( m_xpsArchive, fileName, Qt::CaseInsensitive ); + if ( fontFile.isNull() ) { return -1; } - QByteArray fontData = readFileOrDirectoryParts( fontFile ); // once per file, according to the docs + QByteArray fontData = readFileOrDirectoryParts( m_xpsArchive, &fontFile ); // once per file, according to the docs int result = -1; KTemporaryFile tempfile; @@ -1487,7 +1475,7 @@ int XpsFile::loadFontByName( const QString &fileName ) return result; // a font ID } -KZip * XpsFile::xpsArchive() { +KArchive * XpsFile::xpsArchive() { return m_xpsArchive; } @@ -1502,8 +1490,8 @@ QImage XpsPage::loadImageFromFile( const QString &fileName ) } QString absoluteFileName = absolutePath( entryPath( m_fileName ), fileName ); - const KZipFileEntry* imageFile = loadFile( m_file->xpsArchive(), absoluteFileName, Qt::CaseInsensitive ); - if ( !imageFile ) { + const KArchiveEntry imageFile = loadEntry( m_file->xpsArchive(), absoluteFileName, Qt::CaseInsensitive ); + if ( imageFile.isNull() ) { // image not found return QImage(); } @@ -1520,7 +1508,7 @@ QImage XpsPage::loadImageFromFile( const QString &fileName ) */ QImage image; - QByteArray data = imageFile->data(); + QByteArray data = m_file->xpsArchive()->data( imageFile.pathname ); QBuffer buffer(&data); buffer.open(QBuffer::ReadOnly); @@ -1544,9 +1532,9 @@ Okular::TextPage* XpsPage::textPage() Okular::TextPage* textPage = new Okular::TextPage(); - const KZipFileEntry* pageFile = static_cast(m_file->xpsArchive()->directory()->entry( m_fileName )); + const KArchiveEntry pageFile = m_file->xpsArchive()->entry( m_fileName ); QXmlStreamReader xml; - xml.addData( readFileOrDirectoryParts( pageFile ) ); + xml.addData( readFileOrDirectoryParts( m_file->xpsArchive(), &pageFile ) ); QTransform matrix = QTransform(); QStack matrices; @@ -1646,10 +1634,8 @@ void XpsDocument::parseDocumentStructure( const QString &documentStructureFileNa kDebug(XpsDebug) << "document structure file name: " << documentStructureFileName; m_haveDocumentStructure = false; - const KZipFileEntry* documentStructureFile = static_cast(m_file->xpsArchive()->directory()->entry( documentStructureFileName )); - QXmlStreamReader xml; - xml.addData( documentStructureFile->data() ); + xml.addData( m_file->xpsArchive()->data( documentStructureFileName ) ); while ( !xml.atEnd() ) { @@ -1722,12 +1708,12 @@ XpsDocument::XpsDocument(XpsFile *file, const QString &fileName): m_file(file), { kDebug(XpsDebug) << "document file name: " << fileName; - const KArchiveEntry* documentEntry = file->xpsArchive()->directory()->entry( fileName ); + const KArchiveEntry documentEntry = file->xpsArchive()->entry( fileName ); QString documentFilePath = fileName; const QString documentEntryPath = entryPath( fileName ); QXmlStreamReader docXml; - docXml.addData( readFileOrDirectoryParts( documentEntry, &documentFilePath ) ); + docXml.addData( readFileOrDirectoryParts( file->xpsArchive(), &documentEntry, &documentFilePath ) ); while( !docXml.atEnd() ) { docXml.readNext(); if ( docXml.isStartElement() ) { @@ -1761,12 +1747,12 @@ XpsDocument::XpsDocument(XpsFile *file, const QString &fileName): m_file(file), const int slashPosition = fileName.lastIndexOf( '/' ); const QString documentRelationshipFile = absolutePath( documentEntryPath, "_rels/" + fileName.mid( slashPosition + 1 ) + ".rels" ); - const KZipFileEntry* relFile = static_cast(file->xpsArchive()->directory()->entry(documentRelationshipFile)); + const KArchiveEntry relFile = file->xpsArchive()->entry(documentRelationshipFile); QString documentStructureFile; - if ( relFile ) { + if ( !relFile.isNull() ) { QXmlStreamReader xml; - xml.addData( readFileOrDirectoryParts( relFile ) ); + xml.addData( readFileOrDirectoryParts( file->xpsArchive(), &relFile ) ); while ( !xml.atEnd() ) { xml.readNext(); @@ -1839,24 +1825,25 @@ XpsFile::~XpsFile() bool XpsFile::loadDocument(const QString &filename) { - m_xpsArchive = new KZip( filename ); - if ( m_xpsArchive->open( QIODevice::ReadOnly ) == true ) { - kDebug(XpsDebug) << "Successful open of " << m_xpsArchive->fileName(); + m_xpsArchive = new KArchive( filename ); + if ( m_xpsArchive->isReadable() == true ) { + kDebug(XpsDebug) << "Successful open of " << filename; } else { - kDebug(XpsDebug) << "Could not open XPS archive: " << m_xpsArchive->fileName(); + kDebug(XpsDebug) << "Could not open XPS archive: " << filename; delete m_xpsArchive; return false; } // The only fixed entry in XPS is /_rels/.rels - const KArchiveEntry* relEntry = m_xpsArchive->directory()->entry("_rels/.rels"); - if ( !relEntry ) { + const KArchiveEntry relEntry = m_xpsArchive->entry("_rels/.rels"); + if ( relEntry.isNull() ) { // this might occur if we can't read the zip directory, or it doesn't have the relationships entry + kDebug(XpsDebug) << "No relationships found in archive: " << filename; return false; } QXmlStreamReader relXml; - relXml.addData( readFileOrDirectoryParts( relEntry ) ); + relXml.addData( readFileOrDirectoryParts( m_xpsArchive, &relEntry ) ); QString fixedRepresentationFileName; // We work through the relationships document and pull out each element. @@ -1894,14 +1881,15 @@ bool XpsFile::loadDocument(const QString &filename) if ( fixedRepresentationFileName.isEmpty() ) { // FixedRepresentation is a required part of the XPS document + kDebug(XpsDebug) << "fixedrepresentation not found in document"; return false; } - const KArchiveEntry* fixedRepEntry = m_xpsArchive->directory()->entry( fixedRepresentationFileName ); + const KArchiveEntry fixedRepEntry = m_xpsArchive->entry( fixedRepresentationFileName ); QString fixedRepresentationFilePath = fixedRepresentationFileName; QXmlStreamReader fixedRepXml; - fixedRepXml.addData( readFileOrDirectoryParts( fixedRepEntry, &fixedRepresentationFileName ) ); + fixedRepXml.addData( readFileOrDirectoryParts( m_xpsArchive, &fixedRepEntry, &fixedRepresentationFileName ) ); while ( !fixedRepXml.atEnd() ) { @@ -1940,10 +1928,8 @@ const Okular::DocumentInfo * XpsFile::generateDocumentInfo() m_docInfo->set( Okular::DocumentInfo::MimeType, "application/oxps" ); if ( ! m_corePropertiesFileName.isEmpty() ) { - const KZipFileEntry* corepropsFile = static_cast(m_xpsArchive->directory()->entry(m_corePropertiesFileName)); - QXmlStreamReader xml; - xml.addData( corepropsFile->data() ); + xml.addData( m_xpsArchive->data(m_corePropertiesFileName) ); while ( !xml.atEnd() ) { xml.readNext(); diff --git a/okular/generators/xps/generator_xps.h b/okular/generators/xps/generator_xps.h index 0e582eab..2ef354a7 100644 --- a/okular/generators/xps/generator_xps.h +++ b/okular/generators/xps/generator_xps.h @@ -32,7 +32,7 @@ #include #include -#include +#include typedef enum {abtCommand, abtNumber, abtComma, abtEOF} AbbPathTokenType; @@ -272,7 +272,7 @@ public: QFont getFontByName( const QString &fontName, float size ); - KZip* xpsArchive(); + KArchive* xpsArchive(); private: @@ -291,7 +291,7 @@ private: QString m_signatureOrigin; - KZip * m_xpsArchive; + KArchive * m_xpsArchive; QMap m_fontCache; QStringList m_fonts;