generic: use the new karchive library

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2022-10-06 15:55:39 +03:00
parent b9c92a1ac8
commit 61bcac4d43
28 changed files with 280 additions and 2052 deletions

View file

@ -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})

View file

@ -1,7 +1,5 @@
if(LibArchive_FOUND)
add_subdirectory( libarchive )
else()
add_subdirectory( karchiveplugin )
endif()
add_subdirectory( clirarplugin )

View file

@ -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)

View file

@ -1,276 +0,0 @@
/*
* ark -- archiver for the KDE project
*
* Copyright (C) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
*
* 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 <KZip>
#include <KTar>
#include <KMimeType>
#include <KDebug>
#include <KLocale>
#include <QDir>
#include <QFileInfo>
#include <QSet>
#include <sys/stat.h>
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 <filename>%1</filename> 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<const KArchiveDirectory*>(entry), newPrefix, list);
}
else {
list.append(prefix + QLatin1Char('/') + entryName);
}
}
}
bool KArchiveInterface::copyFiles(const QList<QVariant> &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 <filename>%1</filename> for reading", filename()));
return false;
}
QList<QVariant> extrFiles = files;
if (extrFiles.isEmpty()) { // All files should be extracted
getAllEntries(dir, QString(), extrFiles);
}
bool overwriteAllSelected = false;
bool autoSkipSelected = false;
QSet<QString> dirCache;
foreach(const QVariant &file, extrFiles) {
QString realDestination = destinationDirectory;
const KArchiveEntry *archiveEntry = dir->entry(file.toString());
if (!archiveEntry) {
emit error(i18nc("@info", "File <filename>%1</filename> 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 <filename>%1</filename>", 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<const KArchiveFile*>(archiveEntry)->copyTo(realDestination);
if (response == OverwriteAll) {
overwriteAllSelected = true;
}
}
if (response == OverwriteAutoSkip) {
autoSkipSelected = true;
}
}
else {
static_cast<const KArchiveFile*>(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<const KArchiveDirectory*>(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<const KArchiveFile*>(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 <filename>%1</filename> 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 <filename>%1</filename> 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 <filename>%1</filename> to the archive.", path));
return false;
}
}
}
kDebug() << "Closing the archive";
archive()->close();
kDebug() << "Done";
return true;
}
bool KArchiveInterface::deleteFiles(const QList<QVariant> & files)
{
Q_UNUSED(files)
return false;
}
KERFUFFLE_EXPORT_PLUGIN(KArchiveInterface)

View file

@ -1,68 +0,0 @@
/*
* ark -- archiver for the KDE project
*
* Copyright (C) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
*
* 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<QVariant> &files, const QString &destinationDirectory, ExtractionOptions options);
bool addFiles(const QStringList &files, const CompressionOptions &options);
bool deleteFiles(const QList<QVariant> & 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

View file

@ -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@

View file

@ -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} )

View file

@ -29,54 +29,17 @@
#include "kerfuffle/kerfuffle_export.h"
#include "kerfuffle/queries.h"
#include <archive.h>
#include <archive_entry.h>
#include <QFileInfo>
#include <QDir>
#include <KDebug>
#include <KLocale>
#include <kde_file.h>
#include <KArchive>
#include <QDateTime>
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QList>
#include <QStringList>
#include <sys/stat.h>
#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 <filename>%1</filename>, 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 <filename>%1</filename>, 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: <message>%1</message>",
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 <filename>%1</filename>, 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 <filename>%1</filename>, 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 <filename>%1</filename>, 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: <message>%1</message>",
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: <message>%1</message>", 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: <message>%1</message>", 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 <filename>%1</filename>, 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: <message>%1</message>", 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: <message>%1</message>", 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 <filename>%1</filename>:<nl/>%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)

View file

@ -29,9 +29,6 @@
#include "kerfuffle/archiveinterface.h"
#include <QDir>
#include <QList>
#include <QScopedPointer>
#include <QStringList>
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<struct archive, ArchiveReadCustomDeleter> ArchiveRead;
typedef QScopedPointer<struct archive, ArchiveWriteCustomDeleter> 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

View file

@ -173,6 +173,7 @@ add_library(okularcore SHARED ${okularcore_SRCS})
target_link_libraries(okularcore
${KDE4_KIO_LIBS}
${KDE4_KARCHIVE_LIBS}
${MATH_LIB}
KDE4::kmediaplayer
)

View file

@ -13,6 +13,7 @@
#include "documentcommands_p.h"
#include <limits.h>
#include <sys/stat.h>
#if defined(Q_OS_FREEBSD)
#include <sys/types.h>
@ -46,9 +47,10 @@
#include <krun.h>
#include <kshell.h>
#include <kstandarddirs.h>
#include <ktempdir.h>
#include <ktemporaryfile.h>
#include <ktoolinvocation.h>
#include <kzip.h>
#include <karchive.h>
// 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;
}

View file

@ -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;

View file

@ -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.
*/

View file

@ -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)

View file

@ -10,39 +10,37 @@
#include "document.h"
#include <QtCore/QScopedPointer>
#include <QtCore/QBuffer>
#include <QtCore/QFile>
#include <QtGui/QImage>
#include <QtGui/QImageReader>
#include <klocale.h>
#include <kmimetype.h>
#include <kzip.h>
#include <ktar.h>
#include <karchive.h>
#include <sys/stat.h>
#include <memory>
#include <core/page.h>
#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<const KArchiveDirectory*>( 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<KArchiveDirectory*>( directory );
imagesInArchive( QString(), mArchiveDir, &mEntries );
imagesInArchive( mArchive, &mEntries );
return true;
}
@ -170,14 +126,13 @@ void Document::pages( QVector<Okular::Page*> * pagesVector )
QImageReader reader;
foreach(const QString &file, mEntries) {
if ( mArchive ) {
const KArchiveFile *entry = static_cast<const KArchiveFile*>( mArchiveDir->entry( file ) );
if ( entry ) {
dev.reset( entry->createDevice() );
const KArchiveEntry entry = mArchive->entry( file );
if ( !entry.isNull() ) {
dev.reset( new QBuffer() );
qobject_cast<QBuffer*>(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<const KArchiveFile*>( 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();

View file

@ -10,13 +10,11 @@
#ifndef COMICBOOK_DOCUMENT_H
#define COMICBOOK_DOCUMENT_H
#include <QtCore/QStringList>
class KArchiveDirectory;
class KArchive;
#include <QStringList>
#include <QImage>
#include <QSize>
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;
};

View file

@ -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

View file

@ -1,262 +0,0 @@
/***************************************************************************
* Copyright (C) 2007 by Tobias Koenig <tokoe@kde.org> *
* *
* 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 <QtCore/QEventLoop>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QRegExp>
#include <QtCore/QScopedPointer>
#include <kdebug.h>
#include <kglobal.h>
#include <klocale.h>
#include <kstandarddirs.h>
#include <ktempdir.h>
#if !defined(Q_OS_WIN)
#include <kptyprocess.h>
#include <kptydevice.h>
#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"

View file

@ -1,81 +0,0 @@
/***************************************************************************
* Copyright (C) 2007 by Tobias Koenig <tokoe@kde.org> *
* *
* 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 <QtCore/QObject>
#include <QtCore/QProcess>
#include <QtCore/QStringList>
#include <QEventLoop>
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

View file

@ -1,73 +0,0 @@
/***************************************************************************
* Copyright (C) 2007 by Pino Toscano <pino@kde.org> *
* *
* 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 <QtCore/QRegExp>
#include <QtCore/QStringList>
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";
}

View file

@ -1,55 +0,0 @@
/***************************************************************************
* Copyright (C) 2007 by Pino Toscano <pino@kde.org> *
* *
* 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 <QtCore/QString>
#include <QStringList>
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

View file

@ -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})

View file

@ -10,9 +10,10 @@
#include "document.h"
#include <QtCore/QFile>
#include <QtCore/QBuffer>
#include <klocale.h>
#include <kzip.h>
#include <karchive.h>
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<KArchiveEntry> 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<const KArchiveFile*>( directory->entry( documentFile ) );
// FIXME delete 'deviceì somewhen
device = entry->createDevice();
device = new QBuffer();
qobject_cast<QBuffer*>(device)->setData( zip.data( documentFile ) );
}
QString errorMsg;

View file

@ -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}

View file

@ -9,8 +9,10 @@
#include "document.h"
#include <QFile>
#include <klocale.h>
#include <kzip.h>
#include <karchive.h>
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<const KArchiveDirectory*>( 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<const KArchiveFile*>( 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<const KArchiveFile*>( 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<const KArchiveFile*>( 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<const KArchiveFile*>( 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<const KArchiveDirectory*>( directory->entry( "Pictures" ) );
const QStringList imagesEntries = imagesDirectory->entries();
for ( int i = 0; i < imagesEntries.count(); ++i ) {
file = static_cast<const KArchiveFile*>( 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;
}

View file

@ -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})

View file

@ -40,6 +40,8 @@
#include <core/area.h>
#include <core/fileprinter.h>
#include <sys/stat.h>
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<const KArchiveDirectory *>( 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<KArchiveEntry> entries = archive->list( entry->pathname );
Q_FOREACH ( const KArchiveEntry &ee, entries ) {
if ( !S_ISREG(ee.mode) )
continue;
const KZipFileEntry* relSubFile = static_cast<const KZipFileEntry *>( relSubEntry );
data.append( relSubFile->data() );
data.append( archive->data( ee.pathname ) );
}
} else {
const KZipFileEntry* relFile = static_cast<const KZipFileEntry *>( 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<const KZipFileEntry *>(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<const KZipFileEntry *>(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<const KZipFileEntry *>(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<QTransform> 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<const KZipFileEntry *>(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<const KZipFileEntry *>(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<const KZipFileEntry *>(m_xpsArchive->directory()->entry(m_corePropertiesFileName));
QXmlStreamReader xml;
xml.addData( corepropsFile->data() );
xml.addData( m_xpsArchive->data(m_corePropertiesFileName) );
while ( !xml.atEnd() )
{
xml.readNext();

View file

@ -32,7 +32,7 @@
#include <QStack>
#include <QVariant>
#include <kzip.h>
#include <karchive.h>
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<QString, int> m_fontCache;
QStringList m_fonts;