mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-23 18:32:53 +00:00
generic: use the new karchive library
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
b9c92a1ac8
commit
61bcac4d43
28 changed files with 280 additions and 2052 deletions
|
@ -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})
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
if(LibArchive_FOUND)
|
||||
add_subdirectory( libarchive )
|
||||
else()
|
||||
add_subdirectory( karchiveplugin )
|
||||
endif()
|
||||
|
||||
add_subdirectory( clirarplugin )
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
|
@ -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@
|
|
@ -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} )
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -173,6 +173,7 @@ add_library(okularcore SHARED ${okularcore_SRCS})
|
|||
|
||||
target_link_libraries(okularcore
|
||||
${KDE4_KIO_LIBS}
|
||||
${KDE4_KARCHIVE_LIBS}
|
||||
${MATH_LIB}
|
||||
KDE4::kmediaplayer
|
||||
)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
|
@ -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
|
||||
|
|
@ -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";
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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})
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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})
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue