Logo Search packages:      
Sourcecode: karchiver version File versions  Download package

carchive.cpp

/***************************************************************************
                          carchive.cpp  -  description
                             -------------------
    begin                : Sat Dec 2 2000
    copyright            : (C) 2000 by Eric Coquelle
    email                : coquelle@caramail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "carchive.h"

#include <stdio.h>
#include <sys/stat.h>
#include <kiconloader.h>
#include <kfileitem.h>
#include <kdebug.h>
#include <qprogressdialog.h>

#include <qfileinfo.h>
#include <math.h>

QListView* CArchive::list=NULL;
QComboBox* CArchive::combodirectories=NULL;
int CArchive::iconsize=16;
int CArchive::kindofdate=STANDARD_DATE;
QProgressBar* CArchive::progressbar=NULL;
bool CArchive::overwrite=true;
bool CArchive::recursivemode=true;
bool CArchive::displayicons=true;
int CArchive::compressrate=9;
bool CArchive::viewbydirectories=false;
QCString CArchive::archivePassword="";
bool CArchive::readArchiveWithStream=false;

CArchive::CArchive(){
  readArchiveWithStream=true;
  stopreadprocess=false;
  archiveName="";
  archivecomments.clear();
  issourcesoftware=0;
  lookforsoucearchive=true;
  connect(&processread,SIGNAL(receivedStderr(KProcess*, char*, int)),this,SLOT(haveStdErr(KProcess*,char*,int)));
}

CArchive::~CArchive(){
}


/** Find which icon to insert in the listview, by
examinating the extension of files the archive contains */
00059 void CArchive::setIcon(QString name, QString /*permissions*/, CListViewItem* elementListe){
  if(!displayicons)
    return;

    KMimeType::Ptr mimeType = KMimeType::findByPath( name, 0, true );
    //if(mimeType != KMimeType::findByPath( "/", 0, true ) )
      elementListe->setPixmap( 0, mimeType->pixmap( KIcon::Small ) );
    /*else
    {
      KFileItem item(KFileItem::Unknown, KFileItem::Unknown, KURL("file:/"+name));
      elementListe->setPixmap(0,item.pixmap(iconsize,KIcon::DefaultState));
    }*/
}

void CArchive::setIcon(QString name, mode_t permissions, CListViewItem* elementListe){
  if(!displayicons)
    return;

    KMimeType::Ptr mimeType = KMimeType::findByPath( name, permissions, true );
    if(mimeType != KMimeType::findByPath( "/", 0, true ) )
      elementListe->setPixmap( 0, mimeType->pixmap( KIcon::Small ) );
    else
    {
      KFileItem item(KFileItem::Unknown, KFileItem::Unknown, KURL("file:/"+name));
      elementListe->setPixmap(0,item.pixmap(iconsize,KIcon::DefaultState));
    }
}

/** prepare the local variable, clear the listview
before reading any archive */
00089 void CArchive::initializeReadingArchive(){
  stopreadprocess=false;
  counter=0;
  errors.clear();
  processread.clearArguments();
}

/** set the main widget so as to this class can
draw the archive content */
00098 void CArchive::setWidgetListView( QListView *l ){
      list=l;
}

/** set the main widget so as to this class can
display the subfolders */
00104 void CArchive::setWidgetComboDirectories( QComboBox *c ){
      combodirectories=c;
}

/** If @param read is true, read current archive
with a stream, ie by a quick way, but this
freezes karchiveur's interface */
00111 void CArchive::setReadArchiveWithStream( bool read ){
      readArchiveWithStream=read;
}

void CArchive::displayArchiveContent() {
}

void CArchive::extractArchive(QString & , int , QString & ) {
}

void CArchive::removeFilesFromArchive(QStringList ) {
}

void CArchive::addFilesToArchive( QStringList , bool, int , QString ) {
}

void CArchive::createArchive(QString , QStringList, QString ) {
}

/** set the name of the working archive to
@param archName */
00132 void CArchive::setArchiveName( QString archName ){
  archiveName=archName;
}
QString CArchive::getArchiveName() {
  return archiveName;
}

/** set the name of the password to
@param archPassword */
00141 void CArchive::setPassword( QString archPassword){
  archivePassword=archPassword;
}

/** the the format of displayed date to d
 */
00147 void CArchive::setKindOfDate( int d ){
      kindofdate=d;
}

/** if @param overwr is true, one will overwrite
files when extracting files */
00153 void CArchive::setOverwriteFilesWhenExtracting( bool overwr ){
      overwrite=overwr;
          CCheckFiles::setOverwrite(overwrite);
}

/** A link to the progressbar */
00159 void CArchive::setWidgetProgressBar( QProgressBar *progress ){
      progressbar=progress;
}

/** Kill the read process */
00164 void CArchive::stopReading(){
      stopreadprocess=true;
      processread.kill();

}
/** Kill the extract process */
00170 void CArchive::stopExtracting(){
      processextract.kill();
}

/** Set the size of the icons in the listview to @param size */
00175 void CArchive::setIconSize( int size ){
      iconsize=size;
}

/** If true, when adding a directory, also add the subdirs */
00180 void CArchive::setRecursiveMode (bool rec){
      recursivemode=rec;
}

/** if @param icons is false, don't display the
icons, to speed up archive reading */
00186 void CArchive::setDisplayIcons( bool icons ){
      displayicons=icons;
}

/** If avaible for the compressor, set the compress
rate to @param rate. @param rate must be in [1,9] */
00192 void CArchive::setCompressRate( int rate ){
  if((rate>=0)&&(rate<=9))//Valid compress rates
    compressrate=rate;
}

void CArchive::haveStdErr(KProcess *, char *buffer, int length)
{
  QString sbuffer=buffer;
  sbuffer.truncate(length-1);
  errors.append(sbuffer);
}

/** we recive some informations through the error
      * output of the process */
00206 void CArchive::haveSdtErrExtract(KProcess *, char *buffer, int length){
  buffer[length]=0;
  kdDebug()<<QString("Got error:%1").arg(buffer)<<endl;
  errors.append(buffer);
}

00212 QStringList CArchive::getErrors()
{
  return errors;
}

00217 QString CArchive::getIndividualPermissions(bool b, QString perm)
{
  if(b)
    return perm;
  else
    return "-";
}

QString CArchive::getReadablePermissions(mode_t mode)
{
  QString permission;
  if(mode & S_IFLNK)
    permission="l";
  else if(mode & S_IFDIR)
    permission="d";
  else
    permission="-";

    permission+=getIndividualPermissions(mode & S_IRUSR, "r");
    permission+=getIndividualPermissions(mode & S_IWUSR, "w");
    permission+=getIndividualPermissions(mode & S_IXUSR, "x");
    permission+=getIndividualPermissions(mode & S_IRGRP, "r");
    permission+=getIndividualPermissions(mode & S_IWGRP, "w");
    permission+=getIndividualPermissions(mode & S_IXGRP, "x");
    permission+=getIndividualPermissions(mode & S_IROTH, "r");
    permission+=getIndividualPermissions(mode & S_IWOTH, "w");
    permission+=getIndividualPermissions(mode & S_IXOTH, "x");
    return permission;
}

/** display archive content, using KIO methods */
00248 void CArchive::displayArchiveContent(const KArchiveDirectory* tarfileContent, QString path)
{
  QStringList entries=tarfileContent->entries();
  KArchiveFile* entry;
  CListViewItem *elementListe;
  QString str;
  int i;

  if(viewbydirectories)
  {
    i=knowndirectories.findIndex((KArchiveDirectory*)tarfileContent);
    if(i==-1)
    {
      knowndirectories.append((KArchiveDirectory*)tarfileContent);
      combodirectories->insertItem(tarfileContent->name());
      combodirectories->setCurrentItem(combodirectories->count()-1);
    }
  }
  
  for ( QStringList::Iterator it = entries.begin(); it != entries.end(); ++it ) {
    entry=(KArchiveFile*)tarfileContent->entry(*it);
    str=*it;
    emit newarchiveentryreaded();
    if(entry->isDirectory())
    {
      elementListe=new CListViewItem(list,entry->name(),"0",entry->datetime().toString("hh:mm:ss"),getLocalizedDate(entry->datetime().date()), entry->user()+"("+entry->group()+")",getReadablePermissions(entry->permissions()),path.endsWith("/")?path:path+"/");//+"/"+entry->name());
      setIcon("..", entry->permissions(),elementListe);
      
      if(viewbydirectories)
      {
        i=knowndirectories.findIndex((KArchiveDirectory*)tarfileContent);
        kdDebug()<<QString("Found subdir %1").arg(tarfileContent->name())<<endl;
        if(i==-1)
        {
          kdDebug()<<QString("Not yet known, appending")<<endl;
          knowndirectories.append((KArchiveDirectory*)tarfileContent);
          combodirectories->insertItem(tarfileContent->name());
          combodirectories->setCurrentItem(combodirectories->count()-1);
        }
        else
          combodirectories->setCurrentItem(i);
      }
      else
        displayArchiveContent((const KArchiveDirectory*)tarfileContent->entry(*it),path+entry->name());///was +"/"
    }
    else
    {
      elementListe=new CListViewItem(list,entry->name(),QString::number(entry->size()),entry->datetime().toString("hh:mm:ss"),getLocalizedDate(entry->datetime().date()), entry->user()+"("+entry->group()+")",getReadablePermissions(entry->permissions()),path+(path.endsWith("/")?"":"/"));
      setIcon(entry->name(),"",elementListe);
      
      if(entry->name()=="configure")
        issourcesoftware=issourcesoftware | HAS_CONFIGURE;
      else if(entry->name()=="Makefile.am")
        issourcesoftware=issourcesoftware | HAS_MAKEFILE_AM;
    }
  }
}

/** Returns true if selected entry is a subdirectory of currently displayed ArchiveDirectory*/
00307 bool CArchive::isDirectory(QString entryname)
{
  KArchiveDirectory* currentdir=knowndirectories.last();
  KArchiveFile* entry;
  QStringList entries=currentdir->entries();

  //Check if entryname is a subfolder of currently displayed dir
  for ( QStringList::Iterator it = entries.begin(); it != entries.end(); ++it ) {
    entry=(KArchiveFile*)currentdir->entry(*it);
    if((entry->name()==entryname)&&(entry->isDirectory()))
      return true;
  }
  return false;
}

/* display archive content, using KIO methods */
/*KIO_KARCHIVE*/
00324 void CArchive::displayArchiveContent(QString foldername, QString folderpath)
{
  kdDebug()<<QString("displayArchiveContent of subdir %1, path=%2").arg(foldername).arg(folderpath)<<endl;
  KArchiveDirectory* currentdir=knowndirectories.last();
  KArchiveDirectory* requesteddir;
  QString requesteddirpath;
  KArchiveFile* entry=0L;
  bool found=false;
  QStringList entries=currentdir->entries();
  int i=0;

  //Check if foldername is a subfolder of currently displayed dir
  for ( QStringList::Iterator it = entries.begin(); it != entries.end(); ++it ) {
    entry=(KArchiveFile*)currentdir->entry(*it);
    if((entry->name()==foldername)&&(entry->isDirectory()))
    {
      found=true;
      break;
    }
  }
  if(found)
  {
    kdDebug()<<QString("%1 is a subdir of %2").arg(foldername).arg(folderpath)<<endl;
    list->clear();
    displayArchiveContent((const KArchiveDirectory*)entry, (folderpath.endsWith("/")?folderpath:folderpath+"/")+entry->name());
  }
  else
  {
    //Otherwise, check in the parent dirs
    QString path;
    for ( QValueList<KArchiveDirectory*>::Iterator it = knowndirectories.begin();  it!= knowndirectories.end(); it++ ) {
      requesteddir=*it;
      path+=requesteddir->name();
      if(!path.endsWith("/"))
        path+="/";
      kdDebug()<<QString("Probing %1 for %2, i=%3").arg(path).arg(folderpath).arg(i)<<endl;
      if((path==folderpath)||(path==folderpath+"/"))
      {
        //Keep only the parents of current directory
        int max=combodirectories->count();
        kdDebug()<<QString("Combo has %1 entries").arg(max)<<endl;
        for(int j=i+1;j<max;j++)
        {
          kdDebug()<<QString("Removing %1 and %2").arg((*(knowndirectories.last())).name()).arg(combodirectories->text(combodirectories->count()-1))<<endl;
          knowndirectories.remove(knowndirectories.last());
          combodirectories->removeItem(combodirectories->count()-1);
        }
        list->clear();
        displayArchiveContent(requesteddir, folderpath);
        break;
      }
      requesteddirpath+=requesteddir->name();//+"/";
      i++;
    }
  }
  if(isSourceSoftware())
    emit sourceSoftwareSpotted();
}

/** if true, KIO supported archives will be displayed dir. by dir. */
00384 void CArchive::setDisplayArchiveByDirectories(bool b){
  viewbydirectories=b;
}

/** return a list of all files (with their archive's path) contained in the requested directory */
00389 QValueList<CArchive::archiveElement> CArchive::getAllFilesWithInfos(const KArchiveDirectory* tarfileContent, QString path)
{
  QStringList entries=tarfileContent->entries();
  KArchiveFile* entry;
  //CListViewItem *elementListe;
  QString str;
  archiveElement element;
  QValueList<archiveElement> fileswithpath;

  for ( QStringList::Iterator it = entries.begin(); it != entries.end(); ++it ) {
     entry=(KArchiveFile*)tarfileContent->entry(*it);
    str=*it;
    if(entry->isDirectory())
    {
      fileswithpath+=getAllFilesWithInfos((const KArchiveDirectory*)tarfileContent->entry(*it),path+"/"+entry->name());
    }
    else
    {
      //kdDebug()<<QString("getAllFiles: %1 => %2").arg(entry->name()).arg(path+"/"+entry->name())<<endl;
      element.name=path+"/"+entry->name();
      element.size=entry->size();
      element.date=entry->datetime();
      fileswithpath.append(element);
    }
  }
  return fileswithpath;
}

/** return a list of all files (with their archive's path) contained in the requested directory 
    returns an empty list if foldername is not a valid folder*/
00419 QValueList<CArchive::archiveElement> CArchive::getAllFilesWithInfosInCurrentSubdir(QString foldername, QString folderpath){
  KArchiveDirectory* currentdir=knowndirectories.last();
  //KArchiveDirectory* requesteddir;
  QString requesteddirpath;
  KArchiveFile* entry;
  QStringList entries=currentdir->entries();
  QValueList<CArchive::archiveElement> value;
  
  //kdDebug()<<QString("Get all files in folder %1, prefix=%2").arg(foldername).arg(folderpath)<<endl;
  //Check if foldername is a subfolder of currently displayed dir
  for ( QStringList::Iterator it = entries.begin(); it != entries.end(); ++it ) {
    entry=(KArchiveFile*)currentdir->entry(*it);
    kdDebug()<<QString("Probing %1 for %2").arg(entry->name()).arg(foldername)<<endl;
    if((entry->name()==foldername)&&(entry->isDirectory()))
      return getAllFilesWithInfos((const KArchiveDirectory*)entry, folderpath+entry->name());//was +"/"
  }
  return value;
}

/** Return a list of all files (with their path, as stored in the archive, their size and owner) of all archives' files */
00439 QValueList<CArchive::archiveElement> CArchive::getAllFilesWithInfos(bool fetchonlyselected)
{
  QListViewItem *vi;
  int k;
  QValueList<archiveElement> elements, listsubdir;
  archiveElement element;
  if( viewbydirectories && supportDisplayByDirs() )
  {  
    if(fetchonlyselected)
    {
      vi=list->firstChild();
    
      for(k=0;k<list->childCount();k++)
      {
        if(vi->isSelected())
        {
          if(isDirectory( vi->text(0) ))
          {
              listsubdir=getAllFilesWithInfosInCurrentSubdir(vi->text(0),vi->text(6).startsWith("/") ? vi->text(6).remove(0,1):vi->text(6));
              for(QValueList<archiveElement>::Iterator it = listsubdir.begin(); it != listsubdir.end(); ++it )
              {
          kdDebug()<<QString("Appending element from subdir %1").arg((*it).name)<<endl;
              element.name=(*it).name;
                element.size=(*it).size;
                element.date=(*it).date;
                elements.append(element);
              }
          }
          else
          {
          kdDebug()<<QString("Appending single element %1").arg(vi->text(6)+vi->text(0))<<endl;
            element.name=vi->text(6)+vi->text(0);
            element.size=(QString(vi->text(1))).toInt();
            element.date=QDateTime(getDateFromLocalizedDate(vi->text(3)),QTime::fromString(vi->text(2)));
            elements.append(element);
          }
        }
        vi=vi->nextSibling();
      }
    }
    else
    {
      KArchiveDirectory* requesteddir;
      QValueList<KArchiveDirectory*>::Iterator it =knowndirectories.begin();
      requesteddir=*it;
      elements=getAllFilesWithInfos(requesteddir,"");
    }
  }
  else
  {
    QListViewItem *f = list->firstChild();
    while( f ) {
      if((strcmp(f->text(0),".")!=0)&&(strcmp(f->text(0),"..")!=0) && ((!fetchonlyselected)||(fetchonlyselected && f->isSelected())) ) //do not add directories, and if required, non-selected files
      {
        element.name=f->text(6)+(f->text(6).endsWith("/")?"":"/")+f->text(0);
        element.size=f->text(1).toInt();
        element.date=QDateTime( getDateFromLocalizedDate(f->text(2)), QTime::fromString(f->text(2)) );
        elements.append(element);
      }
      f = f->nextSibling();
    }
  }
  return elements;
}

/** Return a list of all files (with their path, as stored in the archive,) of all archives' files;
  * or only selected ones if @param  fetchonlyselected is true (default is false)*/
00506 QStringList CArchive::getAllFiles(bool fetchonlyselected)
{
  QValueList<CArchive::archiveElement> elements;
  QStringList listfiles;
  
  elements=getAllFilesWithInfos(fetchonlyselected);
  for ( QValueList<CArchive::archiveElement>::Iterator it = elements.begin(); it != elements.end(); ++it )
    listfiles.append((*it).name);
  
  //for (QString f = listfiles.first(); f; f = listfiles.next()) 
  //  kdDebug()<<QString("CArchive::getAllFiles::got %1").arg(f)<<endl;
  return listfiles;
}

/**Returns the numbers of files in current archive*/
00521 int CArchive::countFiles()
{
    return getAllFiles().count();
}

/**Get some infos on current archive (size, compress rate...)*/
00527 void CArchive::fetchArchiveInfos(int& nbfiles, int& archiveSize, int& totalSizeOfFiles, float& sigma, float& compressrate)
{
  QValueList<CArchive::archiveElement> elements;
  archiveElement element;
  float meanFileSize=0;
  totalSizeOfFiles=0;
  sigma=0.0;

  elements=getAllFilesWithInfos();
  archiveSize=QFileInfo(archiveName).size();
  nbfiles=elements.count();
  for ( QValueList<CArchive::archiveElement>::Iterator it = elements.begin(); it != elements.end(); ++it )
    totalSizeOfFiles+=(*it).size;
  meanFileSize=(float)totalSizeOfFiles/(float)nbfiles;
  for ( QValueList<CArchive::archiveElement>::Iterator it = elements.begin(); it != elements.end(); ++it )
    sigma=sigma+(float)( (float)(*it).size - meanFileSize ) * (float)( (float)(*it).size - meanFileSize );
  
  sigma=sqrt(sigma/(float)nbfiles);
  
  if(totalSizeOfFiles>0)
    compressrate=(1.0-(float)archiveSize/(float)totalSizeOfFiles)*100.0;
  else
    compressrate=0;
}

/** Set the files which can be extracted - return false if none of the files can be extracted
    otherwise, add them to processextract and return true*/
00554 QStringList CArchive::checkFilesOnly(QString& extractpath, int& extractall)
{
  CCheckFiles check;
  QString filestoextract;
  QValueList<archiveElement> listsubdir;
  QStringList listfilestoextract;
  QString str;
  
  check.setExtractPath(extractpath);
    
  bool fetchonlyselected;
  if(extractall==EXTRACT_SELECTED_FILES)
    fetchonlyselected=true;
  else
    fetchonlyselected=false;
  
  //Get all files contained in current archive
  QValueList<CArchive::archiveElement> elements;
  
  elements=getAllFilesWithInfos(fetchonlyselected);

  QProgressDialog progressdialog(i18n("Gathering data"), i18n("overwrite remaining files"), elements.count(), 0, "progress_checkfiles", true);
  int i=0;
  for ( QValueList<CArchive::archiveElement>::Iterator it = elements.begin(); it != elements.end(); ++it )
  {
    if(progressdialog.wasCanceled())
    {
      str=(*it).name;
      if(str.startsWith("/"))
        str=str.remove(0,1);
      listfilestoextract.append(str);
    }
    else if(regularexpression.isEmpty()||((!regularexpression.isEmpty())&&(str.find(regularexpression)!=0)))
    {
      check.addFile((*it).name, (*it).size, (*it).date);
      //kdDebug()<<QString("Adding %1 to check.addFile").arg((*it).name)<<endl;
    }
    progressdialog.setProgress(++i);
  }
  if(!check.canSafelyExtract())
    check.exec();
  listfilestoextract+=check.getFiles();
  progressbar->setTotalSteps(listfilestoextract.count());
  //Clear the regexp
  regularexpression=QRegExp("");
  return listfilestoextract;
}

/** Set the files which can be extracted - return false if none of the files can be extracted
    otherwise, add them to processextract and return true*/
00604 bool CArchive::checkFiles(QString extractpath, int extractall)
{
  QStringList listfilestoextract;
  listfilestoextract=checkFilesOnly(extractpath, extractall);
  progressbar->setTotalSteps(listfilestoextract.count());
  kdDebug()<<QString("CArchive::checkFiles: got %1 files").arg(listfilestoextract.count())<<endl;
  if(listfilestoextract.isEmpty())
    return false;
  //for(QStringList::Iterator it = listfilestoextract.begin(); it != listfilestoextract.end(); ++it )
  //  kdDebug()<<QString("CArchive::checkFiles adding %1 to processextract").arg(*it)<<endl;
  processextract << listfilestoextract;

  return true;
}
  
/** Returns the password */
00620 QCString CArchive::getPassword(){
 return archivePassword;
}

/** Returns the comments stored in the archive*/
00625 QStringList CArchive::getArchiveComments()
{
   return archivecomments;
}

/**Convert date to string*/
00631 QString CArchive::getLocalizedDate(QDate date)
{
  if(kindofdate==LOCALISED_DATE)
    return KGlobal::locale()->formatDate(date, true);
  else if(kindofdate==LOCALISED_FULL_DATE)
    return KGlobal::locale()->formatDate(date, false);
  return date.toString();
}

/**Convert string to date*/
00641 QDate CArchive::getDateFromLocalizedDate(QString localizeddate)
{
  QDate date;
  if(kindofdate==STANDARD_DATE)
    date = QDate::fromString(localizeddate);
  else
    date = KGlobal::locale()->readDate(localizeddate);
  if(date.isValid())
    return date;
  else
    return QDate::currentDate();
}

00654 void CArchive::setRegExp(QRegExp regexp)
{
  if(regexp.isValid())
    regularexpression=regexp;
}

/** Returns true if current archive is an autoconf-based source software*/
00661 bool CArchive::isSourceSoftware()
{
  if( (issourcesoftware & (HAS_CONFIGURE | HAS_MAKEFILE_AM )) && lookforsoucearchive )
  {
    lookforsoucearchive=false;//Don't look for Source Software anymore in current archive
    return true;
  }
  return false;
}

#include "carchive.moc"

Generated by  Doxygen 1.6.0   Back to index