summaryrefslogtreecommitdiffstats
path: root/ark/arch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ark/arch.cpp')
-rw-r--r--ark/arch.cpp403
1 files changed, 403 insertions, 0 deletions
diff --git a/ark/arch.cpp b/ark/arch.cpp
new file mode 100644
index 0000000..8ff6a2b
--- /dev/null
+++ b/ark/arch.cpp
@@ -0,0 +1,403 @@
+/*
+
+ ark -- archiver for the KDE project
+
+ Copyright (C)
+
+ 2002: Helio Chissini de Castro <helio@conectiva.com.br>
+ 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.com)
+ 1999-2000: Corel Corporation (author: Emily Ezust, emilye@corel.com)
+ 1999: Francois-Xavier Duranceau duranceau@kde.org
+ 1997-1999: Rob Palmbos palm9744@kettering.edu
+
+ 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.
+
+*/
+
+// C includes
+#include <stdlib.h>
+#include <time.h>
+
+// QT includes
+#include <qapplication.h>
+#include <qfile.h>
+
+// KDE includes
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <klocale.h>
+#include <kpassdlg.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+
+// ark includes
+#include "arch.h"
+#include "arkwidget.h"
+#include "arkutils.h"
+#include "filelistview.h"
+
+// the archive types
+#include "tar.h"
+#include "zip.h"
+#include "lha.h"
+#include "compressedfile.h"
+#include "zoo.h"
+#include "rar.h"
+#include "ar.h"
+#include "sevenzip.h"
+#include "ace.h"
+
+Arch::ArchColumns::ArchColumns( int col, QRegExp reg, int length, bool opt )
+ : colRef( col ), pattern( reg ), maxLength( length ), optional( opt )
+{
+}
+
+Arch::Arch( ArkWidget *gui, const QString &filename )
+ : m_filename( filename ), m_buffer( "" ), m_gui( gui ),
+ m_bReadOnly( false ), m_bNotifyWhenDeleteFails( true ),
+ m_header_removed( false ), m_finished( false ),
+ m_numCols( 0 ), m_dateCol( -1 ), m_fixYear( -1 ), m_fixMonth( -1 ),
+ m_fixDay( -1 ), m_fixTime( -1 ), m_repairYear( -1 ), m_repairMonth( -1 ),
+ m_repairTime( -1 ), m_currentProcess( 0 )
+{
+ m_archCols.setAutoDelete( true ); // To check: it still leaky here???
+}
+
+Arch::~Arch()
+{
+ if ( m_currentProcess )
+ m_currentProcess->kill();
+}
+
+//Check if a compress utility exists
+void Arch::verifyCompressUtilityIsAvailable( const QString &utility )
+{
+ // see if the utility is in the PATH of the user.
+ QString cmd = KGlobal::dirs()->findExe( utility );
+ m_bArchUtilityIsAvailable = !cmd.isEmpty();
+}
+
+//Check if a utility can uncompress files
+void Arch::verifyUncompressUtilityIsAvailable( const QString &utility )
+{
+ // see if the utility is in the PATH of the user.
+ QString cmd = KGlobal::dirs()->findExe( utility );
+ m_bUnarchUtilityIsAvailable = !cmd.isEmpty();
+}
+
+void Arch::slotOpenExited( KProcess* _kp )
+{
+ int exitStatus = 100; // arbitrary bad exit status
+
+ if ( _kp->normalExit() )
+ exitStatus = _kp->exitStatus();
+
+ if ( exitStatus == 1 )
+ {
+ exitStatus = 0; // because 1 means empty archive - not an error.
+ // Is this a safe assumption?
+ }
+
+ if ( !exitStatus )
+ emit sigOpen( this, true, m_filename,
+ Arch::Extract | Arch::Delete | Arch::Add | Arch::View );
+ else
+ emit sigOpen( this, false, QString::null, 0 );
+
+ delete _kp;
+ _kp = m_currentProcess = 0;
+}
+
+void Arch::slotDeleteExited( KProcess *_kp )
+{
+ bool success = ( _kp->normalExit() && ( _kp->exitStatus() == 0 ) );
+
+ if ( !success )
+ {
+ QApplication::restoreOverrideCursor();
+
+ QString msg = i18n( "The deletion operation failed." );
+
+ if ( !getLastShellOutput().isNull() )
+ {
+ QStringList list = QStringList::split( "\n", getLastShellOutput() );
+ KMessageBox::errorList( m_gui, msg, list );
+ clearShellOutput();
+ }
+ else
+ {
+ KMessageBox::error( m_gui, msg );
+ }
+ }
+
+ emit sigDelete( success );
+ delete _kp;
+ _kp = m_currentProcess = 0;
+}
+
+void Arch::slotExtractExited( KProcess *_kp )
+{
+ bool success = ( _kp->normalExit() && ( _kp->exitStatus() == 0 ) );
+
+ if( !success )
+ {
+ if ( passwordRequired() )
+ {
+ QString msg;
+ if ( !m_password.isEmpty() )
+ msg = i18n("The password was incorrect. ");
+ if (KPasswordDialog::getPassword( m_password, msg+i18n("You must enter a password to extract the file:") ) == KPasswordDialog::Accepted )
+ {
+ delete _kp;
+ _kp = m_currentProcess = 0;
+ clearShellOutput();
+ unarchFileInternal(); // try to extract the file again with a password
+ return;
+ }
+ m_password = "";
+ emit sigExtract( false );
+ delete _kp;
+ _kp = m_currentProcess = 0;
+ return;
+ }
+ else if ( m_password.isEmpty() || _kp->exitStatus() > 1 )
+ {
+ QApplication::restoreOverrideCursor();
+
+ QString msg = i18n( "The extraction operation failed." );
+
+ if ( !getLastShellOutput().isNull() )
+ {
+ //getLastShellOutput() is a QString. errorList is expecting QStringLists to show in multiple lines
+ QStringList list = QStringList::split( "\n", getLastShellOutput() );
+ KMessageBox::errorList( m_gui, msg, list );
+ clearShellOutput();
+ }
+ else
+ {
+ KMessageBox::error( m_gui, msg );
+ }
+ }
+ }
+ m_password = "";
+ delete _kp;
+ _kp = m_currentProcess = 0;
+ emit sigExtract( success );
+}
+
+void Arch::unarchFile( QStringList *fileList, const QString & destDir,
+ bool viewFriendly )
+{
+ m_fileList = fileList;
+ m_destDir = destDir;
+ m_viewFriendly = viewFriendly;
+ unarchFileInternal();
+}
+
+void Arch::slotAddExited( KProcess *_kp )
+{
+ bool success = ( _kp->normalExit() && ( _kp->exitStatus() == 0 ) );
+
+ if( !success )
+ {
+ QApplication::restoreOverrideCursor();
+
+ QString msg = i18n( "The addition operation failed." );
+
+ if ( !getLastShellOutput().isNull() )
+ {
+ QStringList list = QStringList::split( "\n", getLastShellOutput() );
+ KMessageBox::errorList( m_gui, msg, list );
+ clearShellOutput();
+ }
+ else
+ {
+ KMessageBox::error( m_gui, msg );
+ }
+ }
+
+ emit sigAdd( success );
+ delete _kp;
+ _kp = m_currentProcess = 0;
+}
+
+void Arch::slotReceivedOutput( KProcess*, char* data, int length )
+{
+ char c = data[ length ];
+ data[ length ] = '\0';
+
+ appendShellOutputData( data );
+ data[ length ] = c;
+}
+
+
+void Arch::slotReceivedTOC( KProcess*, char* data, int length )
+{
+ char c = data[ length ];
+ data[ length ] = '\0';
+
+ appendShellOutputData( data );
+
+ int lfChar, startChar = 0;
+
+ while ( !m_finished )
+ {
+ for ( lfChar = startChar; data[ lfChar ] != '\n' && lfChar < length;
+ lfChar++ );
+
+ if ( data[ lfChar ] != '\n')
+ break; // We are done all the complete lines
+
+ data[ lfChar ] = '\0';
+ m_buffer.append( data + startChar );
+ data[ lfChar ] = '\n';
+ startChar = lfChar + 1;
+
+ if ( m_headerString.isEmpty() )
+ {
+ processLine( m_buffer );
+ }
+ else if ( m_buffer.find( m_headerString ) == -1 )
+ {
+ if ( m_header_removed && !m_finished )
+ {
+ if ( !processLine( m_buffer ) )
+ {
+ // Have faith - maybe it wasn't a header?
+ m_header_removed = false;
+ m_error = true;
+ }
+ }
+ }
+ else if ( !m_header_removed )
+ {
+ m_header_removed = true;
+ }
+ else
+ {
+ m_finished = true;
+ }
+
+ m_buffer = "";
+ }
+
+ if ( !m_finished )
+ m_buffer.append( data + startChar); // Append what's left of the buffer
+
+ data[ length ] = c;
+}
+
+bool Arch::processLine( const QCString &line )
+{
+ QString columns[ 11 ];
+ unsigned int pos = 0;
+ int strpos, len;
+
+ // Go through our columns, try to pick out data, return silently on failure
+ for ( QPtrListIterator <ArchColumns>col( m_archCols ); col.current(); ++col )
+ {
+ ArchColumns *curCol = *col;
+
+ strpos = curCol->pattern.search( line, pos );
+ len = curCol->pattern.matchedLength();
+
+ if ( ( strpos == -1 ) || ( len > curCol->maxLength ) )
+ {
+ if ( curCol->optional )
+ continue; // More?
+ else
+ {
+ kdDebug(1601) << "processLine failed to match critical column" << endl;
+ return false;
+ }
+ }
+
+ pos = strpos + len;
+
+ columns[curCol->colRef] = QString::fromLocal8Bit( line.mid(strpos, len) );
+ }
+
+
+ if ( m_dateCol >= 0 )
+ {
+ QString year = ( m_repairYear >= 0 ) ?
+ ArkUtils::fixYear( columns[ m_repairYear ].ascii())
+ : columns[ m_fixYear ];
+ QString month = ( m_repairMonth >= 0 ) ?
+ QString( "%1" )
+ .arg( ArkUtils::getMonth( columns[ m_repairMonth ].ascii() ) )
+ : columns[ m_fixMonth ];
+ QString timestamp = QString::fromLatin1( "%1-%2-%3 %4" )
+ .arg( year )
+ .arg( month )
+ .arg( columns[ m_fixDay ] )
+ .arg( columns[ m_fixTime ] );
+
+ columns[ m_dateCol ] = timestamp;
+ }
+
+ QStringList list;
+
+ for ( int i = 0; i < m_numCols; ++i )
+ {
+ list.append( columns[ i ] );
+ }
+
+ m_gui->fileList()->addItem( list ); // send the entry to the GUI
+
+ return true;
+}
+
+
+Arch *Arch::archFactory( ArchType aType,
+ ArkWidget *parent, const QString &filename,
+ const QString &openAsMimeType )
+{
+ switch( aType )
+ {
+ case TAR_FORMAT:
+ return new TarArch( parent, filename, openAsMimeType );
+
+ case ZIP_FORMAT:
+ return new ZipArch( parent, filename );
+
+ case LHA_FORMAT:
+ return new LhaArch( parent, filename );
+
+ case COMPRESSED_FORMAT:
+ return new CompressedFile( parent, filename, openAsMimeType );
+
+ case ZOO_FORMAT:
+ return new ZooArch( parent, filename );
+
+ case RAR_FORMAT:
+ return new RarArch( parent, filename );
+
+ case AA_FORMAT:
+ return new ArArch( parent, filename );
+
+ case SEVENZIP_FORMAT:
+ return new SevenZipArch( parent, filename );
+
+ case ACE_FORMAT:
+ return new AceArch( parent, filename );
+
+ case UNKNOWN_FORMAT:
+ default:
+ return 0;
+ }
+}
+#include "arch.moc"