mirror of
https://invent.kde.org/graphics/okular
synced 2024-10-02 22:23:43 +00:00
4a4456abd7
Some instances of QRegExp are still left: generators/mobipocket and generators/epub
309 lines
8.3 KiB
C++
309 lines
8.3 KiB
C++
/***************************************************************************
|
|
* 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 <QEventLoop>
|
|
#include <QFile>
|
|
#include <QFileInfo>
|
|
#include <QGlobalStatic>
|
|
#include <QTemporaryDir>
|
|
|
|
#include <QLoggingCategory>
|
|
#if defined(WITH_KPTY)
|
|
#include <KPty/kptyprocess.h>
|
|
#include <KPty/kptydevice.h>
|
|
#endif
|
|
|
|
#include "debug_comicbook.h"
|
|
|
|
#include <memory>
|
|
#include <QStandardPaths>
|
|
|
|
struct UnrarHelper
|
|
{
|
|
UnrarHelper();
|
|
~UnrarHelper();
|
|
|
|
UnrarHelper(const UnrarHelper &) = delete;
|
|
UnrarHelper &operator=(const UnrarHelper &) = delete;
|
|
|
|
UnrarFlavour *kind;
|
|
QString unrarPath;
|
|
QString lsarPath;
|
|
};
|
|
|
|
Q_GLOBAL_STATIC( UnrarHelper, helper )
|
|
|
|
static UnrarFlavour* detectUnrar( const QString &unrarPath, const QString &versionCommand )
|
|
{
|
|
UnrarFlavour* kind = nullptr;
|
|
QProcess proc;
|
|
proc.start( unrarPath, QStringList() << versionCommand );
|
|
bool ok = proc.waitForFinished( -1 );
|
|
Q_UNUSED( ok )
|
|
const QStringList lines = QString::fromLocal8Bit( proc.readAllStandardOutput() ).split( QLatin1Char('\n'), QString::SkipEmptyParts );
|
|
if ( !lines.isEmpty() )
|
|
{
|
|
if ( lines.first().startsWith( QLatin1String("UNRAR ") ) )
|
|
kind = new NonFreeUnrarFlavour();
|
|
else if ( lines.first().startsWith( QLatin1String("RAR ") ) )
|
|
kind = new NonFreeUnrarFlavour();
|
|
else if ( lines.first().startsWith( QLatin1String("unrar ") ) )
|
|
kind = new FreeUnrarFlavour();
|
|
else if ( lines.first().startsWith( QLatin1String("v") ) )
|
|
kind = new UnarFlavour();
|
|
}
|
|
return kind;
|
|
}
|
|
|
|
UnrarHelper::UnrarHelper()
|
|
: kind( nullptr )
|
|
{
|
|
QString path = QStandardPaths::findExecutable( QStringLiteral("lsar") );
|
|
|
|
if ( !path.isEmpty() )
|
|
{
|
|
lsarPath = path;
|
|
}
|
|
|
|
path = QStandardPaths::findExecutable( QStringLiteral("unrar-nonfree") );
|
|
|
|
if ( path.isEmpty() )
|
|
path = QStandardPaths::findExecutable( QStringLiteral("unrar") );
|
|
if ( path.isEmpty() )
|
|
path = QStandardPaths::findExecutable( QStringLiteral("rar") );
|
|
if ( path.isEmpty() )
|
|
path = QStandardPaths::findExecutable( QStringLiteral("unar") );
|
|
|
|
if ( !path.isEmpty() )
|
|
kind = detectUnrar( path, QStringLiteral("--version") );
|
|
|
|
if ( !kind )
|
|
kind = detectUnrar( path, QStringLiteral("-v") );
|
|
|
|
if ( !kind )
|
|
{
|
|
// no luck, print that
|
|
qWarning() << "Neither unrar nor unarchiver were found.";
|
|
}
|
|
else
|
|
{
|
|
unrarPath = path;
|
|
qCDebug(OkularComicbookDebug) << "detected:" << path << "(" << kind->name() << ")";
|
|
}
|
|
}
|
|
|
|
UnrarHelper::~UnrarHelper()
|
|
{
|
|
delete kind;
|
|
}
|
|
|
|
|
|
Unrar::Unrar()
|
|
: QObject( nullptr ), mLoop( nullptr ), mTempDir( nullptr )
|
|
{
|
|
}
|
|
|
|
Unrar::~Unrar()
|
|
{
|
|
delete mTempDir;
|
|
}
|
|
|
|
bool Unrar::open( const QString &fileName )
|
|
{
|
|
if ( !isSuitableVersionAvailable() )
|
|
return false;
|
|
|
|
delete mTempDir;
|
|
mTempDir = new QTemporaryDir();
|
|
|
|
mFileName = fileName;
|
|
|
|
/**
|
|
* Extract the archive to a temporary directory
|
|
*/
|
|
mStdOutData.clear();
|
|
mStdErrData.clear();
|
|
|
|
const int ret = startSyncProcess( helper->kind->processOpenArchiveArgs( mFileName, mTempDir->path() ) );
|
|
bool ok = ret == 0;
|
|
|
|
return ok;
|
|
}
|
|
|
|
QStringList Unrar::list()
|
|
{
|
|
mStdOutData.clear();
|
|
mStdErrData.clear();
|
|
|
|
if ( !isSuitableVersionAvailable() )
|
|
return QStringList();
|
|
|
|
startSyncProcess( helper->kind->processListArgs( mFileName ) );
|
|
|
|
QStringList listFiles = helper->kind->processListing( QString::fromLocal8Bit( mStdOutData ).split( QLatin1Char('\n'), QString::SkipEmptyParts ) );
|
|
|
|
QString subDir;
|
|
|
|
if ( listFiles.last().endsWith( QLatin1Char('/') ) && helper->kind->name() == QLatin1String("unar") ) {
|
|
// Subfolder detected. The unarchiver is unable to extract all files into a single folder
|
|
subDir = listFiles.last();
|
|
listFiles.removeLast();
|
|
}
|
|
|
|
QStringList newList;
|
|
for ( const QString &f : qAsConst(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->path() + QLatin1Char('/') + subDir + fi.fileName() ) ) {
|
|
newList.append( subDir + fi.fileName() );
|
|
}
|
|
}
|
|
return newList;
|
|
}
|
|
|
|
QByteArray Unrar::contentOf( const QString &fileName ) const
|
|
{
|
|
if ( !isSuitableVersionAvailable() )
|
|
return QByteArray();
|
|
|
|
QFile file( mTempDir->path() + QLatin1Char('/') + fileName );
|
|
if ( !file.open( QIODevice::ReadOnly ) )
|
|
return QByteArray();
|
|
|
|
return file.readAll();
|
|
}
|
|
|
|
QIODevice* Unrar::createDevice( const QString &fileName ) const
|
|
{
|
|
if ( !isSuitableVersionAvailable() )
|
|
return nullptr;
|
|
|
|
std::unique_ptr< QFile> file( new QFile( mTempDir->path() + QLatin1Char('/') + fileName ) );
|
|
if ( !file->open( QIODevice::ReadOnly ) )
|
|
return nullptr;
|
|
|
|
return file.release();
|
|
}
|
|
|
|
bool Unrar::isAvailable()
|
|
{
|
|
return helper->kind;
|
|
}
|
|
|
|
bool Unrar::isSuitableVersionAvailable()
|
|
{
|
|
if ( !isAvailable() )
|
|
return false;
|
|
|
|
if (dynamic_cast< NonFreeUnrarFlavour * >( helper->kind ) || dynamic_cast< UnarFlavour * >( helper->kind ))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
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 ProcessArgs &args )
|
|
{
|
|
int ret = 0;
|
|
|
|
#if !defined(WITH_KPTY)
|
|
mProcess = new QProcess( this );
|
|
connect(mProcess, &QProcess::readyReadStandardOutput, this, &Unrar::readFromStdout);
|
|
connect(mProcess, &QProcess::readyReadStandardError, this, &Unrar::readFromStderr);
|
|
connect(mProcess, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, &Unrar::finished);
|
|
|
|
#else
|
|
mProcess = new KPtyProcess( this );
|
|
mProcess->setOutputChannelMode( KProcess::SeparateChannels );
|
|
connect(mProcess, &KPtyProcess::readyReadStandardOutput, this, &Unrar::readFromStdout);
|
|
connect(mProcess, &KPtyProcess::readyReadStandardError, this, &Unrar::readFromStderr);
|
|
connect(mProcess, static_cast<void (KPtyProcess::*)(int, QProcess::ExitStatus)>(&KPtyProcess::finished), this, &Unrar::finished);
|
|
|
|
#endif
|
|
|
|
#if !defined(WITH_KPTY)
|
|
if ( helper->kind->name() == QLatin1String( "unar" ) && args.useLsar )
|
|
{
|
|
mProcess->start( helper->lsarPath, args.appArgs, QIODevice::ReadWrite | QIODevice::Unbuffered );
|
|
}
|
|
else
|
|
{
|
|
mProcess->start( helper->unrarPath, args.appArgs, QIODevice::ReadWrite | QIODevice::Unbuffered );
|
|
}
|
|
|
|
ret = mProcess->waitForFinished( -1 ) ? 0 : 1;
|
|
#else
|
|
if ( helper->kind->name() == QLatin1String( "unar" ) && args.useLsar )
|
|
{
|
|
mProcess->setProgram( helper->lsarPath, args.appArgs );
|
|
}
|
|
else
|
|
{
|
|
mProcess->setProgram( helper->unrarPath, args.appArgs );
|
|
}
|
|
|
|
mProcess->setNextOpenMode( QIODevice::ReadWrite | QIODevice::Unbuffered );
|
|
mProcess->start();
|
|
QEventLoop loop;
|
|
mLoop = &loop;
|
|
ret = loop.exec( QEventLoop::WaitForMoreEvents | QEventLoop::ExcludeUserInputEvents );
|
|
mLoop = nullptr;
|
|
#endif
|
|
|
|
delete mProcess;
|
|
mProcess = nullptr;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void Unrar::writeToProcess( const QByteArray &data )
|
|
{
|
|
if ( !mProcess || data.isNull() )
|
|
return;
|
|
|
|
#if !defined(WITH_KPTY)
|
|
mProcess->write( data );
|
|
#else
|
|
mProcess->pty()->write( data );
|
|
#endif
|
|
}
|
|
|