You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
6.0 KiB
256 lines
6.0 KiB
/*************************************************************************** |
|
* 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/QRegExp> |
|
|
|
#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" |
|
|
|
#include <memory> |
|
|
|
struct UnrarHelper |
|
{ |
|
UnrarHelper(); |
|
~UnrarHelper(); |
|
|
|
UnrarFlavour *kind; |
|
QString unrarPath; |
|
}; |
|
|
|
K_GLOBAL_STATIC( UnrarHelper, helper ) |
|
|
|
static UnrarFlavour* detectUnrar( const QString &unrarPath ) |
|
{ |
|
UnrarFlavour* kind = 0; |
|
QProcess proc; |
|
proc.start( unrarPath, QStringList() << "--version" ); |
|
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 ); |
|
|
|
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 ) { |
|
if ( QFile::exists( mTempDir->name() + f ) ) { |
|
newList.append( f ); |
|
} |
|
} |
|
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; |
|
|
|
std::auto_ptr< QFile> file( new QFile( mTempDir->name() + fileName ) ); |
|
if ( !file->open( QIODevice::ReadOnly ) ) |
|
return 0; |
|
|
|
return file.release(); |
|
} |
|
|
|
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 "unrar.moc"
|
|
|