summaryrefslogtreecommitdiffstats
path: root/ark/compressedfile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ark/compressedfile.cpp')
-rw-r--r--ark/compressedfile.cpp376
1 files changed, 376 insertions, 0 deletions
diff --git a/ark/compressedfile.cpp b/ark/compressedfile.cpp
new file mode 100644
index 0000000..9ebe283
--- /dev/null
+++ b/ark/compressedfile.cpp
@@ -0,0 +1,376 @@
+/*
+ ark: A program for modifying archives via a GUI.
+
+ Copyright (C)
+
+ 2000: Corel Corporation (author: Emily Ezust, emilye@corel.com)
+ 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.com)
+ 2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de>
+
+ 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 <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+// Qt includes
+#include <qdir.h>
+
+// KDE includes
+#include <kdebug.h>
+#include <klargefile.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <ktempdir.h>
+#include <kprocess.h>
+#include <kmimetype.h>
+#include <kio/netaccess.h>
+#include <kio/global.h>
+#include <kfileitem.h>
+#include <kapplication.h>
+#include <kglobal.h>
+
+// ark includes
+#include "arkwidget.h"
+#include "filelistview.h"
+#include "compressedfile.h"
+
+// encapsulates the idea of a compressed file
+
+CompressedFile::CompressedFile( ArkWidget *_gui, const QString & _fileName, const QString & _openAsMimeType )
+ : Arch( _gui, _fileName )
+{
+ m_tempDirectory = NULL;
+ m_openAsMimeType = _openAsMimeType;
+ kdDebug(1601) << "CompressedFile constructor" << endl;
+ m_tempDirectory = new KTempDir( _gui->tmpDir()
+ + QString::fromLatin1( "compressed_file_temp" ) );
+ m_tempDirectory->setAutoDelete( true );
+ m_tmpdir = m_tempDirectory->name();
+ initData();
+ verifyCompressUtilityIsAvailable( m_archiver_program );
+ verifyUncompressUtilityIsAvailable( m_unarchiver_program );
+
+ if (!QFile::exists(_fileName))
+ {
+ KMessageBox::information(0,
+ i18n("You are creating a simple compressed archive which contains only one input file.\n"
+ "When uncompressed, the file name will be based on the name of the archive file.\n"
+ "If you add more files you will be prompted to convert it to a real archive."),
+ i18n("Simple Compressed Archive"), "CreatingCompressedArchive");
+ }
+}
+
+CompressedFile::~CompressedFile()
+{
+ if ( m_tempDirectory )
+ delete m_tempDirectory;
+}
+
+void CompressedFile::setHeaders()
+{
+ ColumnList list;
+ list.append(FILENAME_COLUMN);
+ list.append(PERMISSION_COLUMN);
+ list.append(OWNER_COLUMN);
+ list.append(GROUP_COLUMN);
+ list.append(SIZE_COLUMN);
+
+ emit headers(list);
+}
+
+void CompressedFile::initData()
+{
+ m_unarchiver_program = QString::null;
+ m_archiver_program = QString::null;
+
+ QString mimeType;
+ if ( !m_openAsMimeType.isNull() )
+ mimeType = m_openAsMimeType;
+ else
+ mimeType = KMimeType::findByPath( m_filename )->name();
+
+ if ( mimeType == "application/x-gzip" )
+ {
+ m_unarchiver_program = "gunzip";
+ m_archiver_program = "gzip";
+ m_defaultExtensions << ".gz" << "-gz" << ".z" << "-z" << "_z" << ".Z";
+ }
+ if ( mimeType == "application/x-bzip" )
+ {
+ m_unarchiver_program = "bunzip";
+ m_archiver_program = "bzip";
+ m_defaultExtensions << ".bz";
+ }
+ if ( mimeType == "application/x-bzip2" )
+ {
+ m_unarchiver_program = "bunzip2";
+ m_archiver_program = "bzip2";
+ m_defaultExtensions << ".bz2" << ".bz";
+ }
+ if ( mimeType == "application/x-lzop" )
+ { m_unarchiver_program = "lzop";
+ m_archiver_program = "lzop";
+ m_defaultExtensions << ".lzo";
+ }
+ if ( mimeType == "application/x-compress" )
+ {
+ m_unarchiver_program = KGlobal::dirs()->findExe( "uncompress" ).isNull()? "gunzip" : "uncompress";
+ m_archiver_program = "compress";
+ m_defaultExtensions = ".Z";
+ }
+
+}
+
+QString CompressedFile::extension()
+{
+ QStringList::Iterator it = m_defaultExtensions.begin();
+ for( ; it != m_defaultExtensions.end(); ++it )
+ if( m_filename.endsWith( *it ) )
+ return QString::null;
+ return m_defaultExtensions.first();
+}
+
+void CompressedFile::open()
+{
+ kdDebug(1601) << "+CompressedFile::open" << endl;
+ setHeaders();
+
+ // We copy the file into the temporary directory, uncompress it,
+ // and when the uncompression is done, list it
+ // (that code is in the slot slotOpenDone)
+
+ m_tmpfile = m_gui->realURL().fileName();
+ if ( m_tmpfile.isEmpty() )
+ m_tmpfile = m_filename;
+ m_tmpfile += extension();
+ m_tmpfile = m_tmpdir + m_tmpfile;
+
+ KURL src, target;
+ src.setPath( m_filename );
+ target.setPath( m_tmpfile );
+
+ KIO::NetAccess::copy( src, target, m_gui );
+ kdDebug(1601) << "Temp file name is " << target << endl;
+
+ if ( !KIO::NetAccess::exists( target, true, NULL ) )
+ return;
+
+ KProcess *kp = m_currentProcess = new KProcess;
+ kp->clearArguments();
+ *kp << m_unarchiver_program << "-f" ;
+ if ( m_unarchiver_program == "lzop")
+ {
+ *kp << "-d";
+ // lzop hack, see comment in tar.cpp createTmp()
+ kp->setUsePty( KProcess::Stdin, false );
+ }
+ // gunzip 1.3 seems not to like original names with directories in them
+ // testcase: https://listman.redhat.com/pipermail/valhalla-list/2006-October.txt.gz
+ /*if ( m_unarchiver_program == "gunzip" )
+ *kp << "-N";
+ */
+ *kp << m_tmpfile;
+
+ kdDebug(1601) << "Command is " << m_unarchiver_program << " " << m_tmpfile<< endl;
+
+ connect( kp, SIGNAL(receivedStdout(KProcess*, char*, int)),
+ this, SLOT(slotReceivedOutput(KProcess*, char*, int)));
+ connect( kp, SIGNAL(receivedStderr(KProcess*, char*, int)),
+ this, SLOT(slotReceivedOutput(KProcess*, char*, int)));
+ connect( kp, SIGNAL(processExited(KProcess*)), this,
+ SLOT(slotUncompressDone(KProcess*)));
+
+ if (kp->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false)
+ {
+ KMessageBox::error( 0, i18n("Could not start a subprocess.") );
+ emit sigOpen(this, false, QString::null, 0 );
+ }
+
+ kdDebug(1601) << "-CompressedFile::open" << endl;
+}
+
+void CompressedFile::slotUncompressDone(KProcess *_kp)
+{
+ bool bSuccess = false;
+ kdDebug(1601) << "normalExit = " << _kp->normalExit() << endl;
+ if( _kp->normalExit() )
+ kdDebug(1601) << "exitStatus = " << _kp->exitStatus() << endl;
+
+ if( _kp->normalExit() && (_kp->exitStatus()==0) )
+ {
+ bSuccess = true;
+ }
+
+ delete _kp;
+ _kp = m_currentProcess = 0;
+
+ if ( !bSuccess )
+ {
+ emit sigOpen( this, false, QString::null, 0 );
+ return;
+ }
+
+ QDir dir( m_tmpdir );
+ QStringList lst( dir.entryList() );
+ lst.remove( ".." );
+ lst.remove( "." );
+ KURL url;
+ url.setPath( m_tmpdir + lst.first() );
+ m_tmpfile = url.path();
+ KIO::UDSEntry udsInfo;
+ KIO::NetAccess::stat( url, udsInfo, m_gui );
+ KFileItem fileItem( udsInfo, url );
+ QStringList list;
+ list << fileItem.name();
+ list << fileItem.permissionsString();
+ list << fileItem.user();
+ list << fileItem.group();
+ list << KIO::number( fileItem.size() );
+ m_gui->fileList()->addItem(list); // send to GUI
+
+ emit sigOpen( this, bSuccess, m_filename,
+ Arch::Extract | Arch::Delete | Arch::Add | Arch::View );
+}
+
+void CompressedFile::create()
+{
+ emit sigCreate(this, true, m_filename,
+ Arch::Extract | Arch::Delete | Arch::Add
+ | Arch::View);
+}
+
+void CompressedFile::addFile( const QStringList &urls )
+{
+ // only used for adding ONE file to an EMPTY gzip file, i.e., one that
+ // has just been created
+
+ kdDebug(1601) << "+CompressedFile::addFile" << endl;
+
+ Q_ASSERT(m_gui->getNumFilesInArchive() == 0);
+ Q_ASSERT(urls.count() == 1);
+
+ KURL url = KURL::fromPathOrURL(urls.first());
+ Q_ASSERT(url.isLocalFile());
+
+ QString file;
+ file = url.path();
+
+ KProcess proc;
+ proc << "cp" << file << m_tmpdir;
+ proc.start(KProcess::Block);
+
+ m_tmpfile = file.right(file.length()
+ - file.findRev("/")-1);
+ m_tmpfile = m_tmpdir + '/' + m_tmpfile;
+
+ kdDebug(1601) << "Temp file name is " << m_tmpfile << endl;
+
+ kdDebug(1601) << "File is " << file << endl;
+
+ KProcess *kp = m_currentProcess = new KProcess;
+ kp->clearArguments();
+
+ // lzop hack, see comment in tar.cpp createTmp()
+ if ( m_archiver_program == "lzop")
+ kp->setUsePty( KProcess::Stdin, false );
+
+ QString compressor = m_archiver_program;
+
+ *kp << compressor << "-c" << file;
+
+ connect( kp, SIGNAL(receivedStdout(KProcess*, char*, int)),
+ this, SLOT(slotAddInProgress(KProcess*, char*, int)));
+ connect( kp, SIGNAL(receivedStderr(KProcess*, char*, int)),
+ this, SLOT(slotReceivedOutput(KProcess*, char*, int)));
+ connect( kp, SIGNAL(processExited(KProcess*)), this,
+ SLOT(slotAddDone(KProcess*)));
+
+ int f_desc = KDE_open(QFile::encodeName(m_filename), O_CREAT | O_TRUNC | O_WRONLY, 0666);
+ if (f_desc != -1)
+ fd = fdopen( f_desc, "w" );
+ else
+ fd = NULL;
+
+ if (kp->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false)
+ {
+ KMessageBox::error( 0, i18n("Could not start a subprocess.") );
+ }
+
+ kdDebug(1601) << "-CompressedFile::addFile" << endl;
+}
+
+void CompressedFile::slotAddInProgress(KProcess*, char* _buffer, int _bufflen)
+{
+ // we're trying to capture the output of a command like this
+ // gzip -c myfile
+ // and feed the output to the compressed file
+ int size;
+ size = fwrite(_buffer, 1, _bufflen, fd);
+ if (size != _bufflen)
+ {
+ KMessageBox::error(0, i18n("Trouble writing to the archive..."));
+ exit(99);
+ }
+}
+
+void CompressedFile::slotAddDone(KProcess *_kp)
+{
+ fclose(fd);
+ slotAddExited(_kp);
+}
+
+void CompressedFile::unarchFileInternal()
+{
+ if (m_destDir != m_tmpdir)
+ {
+ QString dest;
+ if (m_destDir.isEmpty() || m_destDir.isNull())
+ {
+ kdError(1601) << "There was no extract directory given." << endl;
+ return;
+ }
+ else
+ dest=m_destDir;
+
+ KProcess proc;
+ proc << "cp" << m_tmpfile << dest;
+ proc.start(KProcess::Block);
+ }
+ emit sigExtract(true);
+}
+
+void CompressedFile::remove(QStringList *)
+{
+ kdDebug(1601) << "+CompressedFile::remove" << endl;
+ QFile::remove(m_tmpfile);
+
+ // do not delete but truncate the compressed file in case someone
+ // does a reload and finds it no longer exists!
+ truncate(QFile::encodeName(m_filename), 0);
+
+ m_tmpfile = "";
+ emit sigDelete(true);
+ kdDebug(1601) << "-CompressedFile::remove" << endl;
+}
+
+
+
+#include "compressedfile.moc"
+