From 8cf274c35a83bf829a54cf22f0c82fdbfb333c03 Mon Sep 17 00:00:00 2001 From: Alexander Golubev Date: Sat, 7 May 2016 13:20:21 +1000 Subject: [PATCH] Removed crappy FileListView::updateItem() method and replace it with addOrUpdateItem() Enhanced in several ways parsing of rar-5+ output (fixes a crash and several potential issues) Spacing fixes Minor modification: replace assert with if() Signed-off-by: Michele Calgaro --- ark/filelistview.cpp | 88 +++++++--------------- ark/filelistview.h | 14 ++-- ark/rar.cpp | 169 ++++++++++++++++++++++--------------------- 3 files changed, 121 insertions(+), 150 deletions(-) diff --git a/ark/filelistview.cpp b/ark/filelistview.cpp index bff5329..f951a22 100644 --- a/ark/filelistview.cpp +++ b/ark/filelistview.cpp @@ -72,13 +72,13 @@ int FileLVI::compare( TQListViewItem * i, int column, bool ascending ) const if ( ( this->childCount() > 0 ) && ( item->childCount() == 0 ) ) return -1; - + if ( ( this->childCount() == 0 ) && ( item->childCount() > 0 ) ) return 1; if ( column == 0 ) return TDEListViewItem::compare( i, column, ascending ); - + columnName colName = ( static_cast< FileListView * > ( listView() ) )->nameOfColumn( column ); switch ( colName ) { @@ -170,6 +170,17 @@ void FileLVI::setText( int column, const TQString &text ) TQListViewItem::setText(column, text); } +void FileLVI::setItemData( const TQStringList &entryData ) +{ + int i = 0; + + for (TQStringList::ConstIterator it = entryData.begin(); it != entryData.end(); ++it) + { + this->setText(i, *it); + ++i; + } +} + static FileLVI* folderLVI( TDEListViewItem *parent, const TQString& name ) { FileLVI *folder = new FileLVI( parent ); @@ -383,7 +394,7 @@ FileListView::item(const TQString& filename) const return 0; } -void FileListView::addItem( const TQStringList & entries ) +FileLVI *FileListView::addItem( const TQStringList & entries ) { FileLVI *flvi, *parent = findParent( entries[0] ); if ( parent ) @@ -391,72 +402,23 @@ void FileListView::addItem( const TQStringList & entries ) else flvi = new FileLVI( this ); - - int i = 0; - - for (TQStringList::ConstIterator it = entries.begin(); it != entries.end(); ++it) - { - flvi->setText(i, *it); - ++i; - } + flvi->setItemData (entries); KMimeType::Ptr mimeType = KMimeType::findByPath( entries.first(), 0, true ); flvi->setPixmap( 0, mimeType->pixmap( TDEIcon::Small ) ); + + return flvi; } -void FileListView::updateItem( const TQStringList &entries ) +FileLVI *FileListView::addOrUpdateItem( const TQStringList &entries ) { - TQStringList ancestorList = TQStringList::split( '/', entries[0] ); - - // Checks if the listview contains the first item in the list of ancestors - TQListViewItem *item = firstChild(); - while ( item ) - { - if ( item->text( 0 ) == ancestorList[0] || item->text( 0 ) == ancestorList[0].stripWhiteSpace()) - break; - item = item->nextSibling(); - } - - // If the list view does not contain the item ... - if ( !item ) - { - kdError( 1601 ) << ancestorList[0] << " not found" << endl; - return; - } - - // We've already dealt with the first item, remove it - ancestorList.pop_front(); - - while ( ancestorList.count() > 0 ) - { - TQString name = ancestorList[0]; - - FileLVI *parent = static_cast< FileLVI*>( item ); - item = parent->firstChild(); - while ( item ) - { - if ( item->text(0) == name ) - break; - item = item->nextSibling(); - } - - if ( !item ) - { - kdError( 1601 ) << name << " not found" << endl; - return; - } - - ancestorList.pop_front(); + FileLVI *flvi = item ( entries[0] ); + if (flvi) { + flvi->setItemData (entries); + return flvi; + } else { + return addItem (entries); } - - int i = 0; - for (TQStringList::ConstIterator it = entries.begin(); it != entries.end(); ++it) - { - item->setText(i, *it); - ++i; - } - - item->setOpen( true ); } void FileListView::selectAll() @@ -481,7 +443,7 @@ void FileListView::setHeaders( const ColumnList& columns ) int colnum = addColumn( pair.first ); setColumnAlignment( colnum, pair.second ); } - + setResizeMode( TQListView::LastColumn ); header()->show(); diff --git a/ark/filelistview.h b/ark/filelistview.h index d3dd616..022ab86 100644 --- a/ark/filelistview.h +++ b/ark/filelistview.h @@ -60,6 +60,8 @@ class FileLVI : public TDEListViewItem int compare ( TQListViewItem * i, int col, bool ascending ) const; virtual TQString key( int column, bool ) const; virtual void setText( int column, const TQString &text ); + /// Set the data for model entry all at once + void setItemData( const TQStringList &entryData ); private: TDEIO::filesize_t m_fileSize; @@ -74,7 +76,7 @@ typedef TQValueList< TQPair< TQString, TQt::AlignmentFlags > > ColumnList; class FileListView: public TDEListView { Q_OBJECT - + public: FileListView( TQWidget *parent = 0, const char* name = 0 ); @@ -109,15 +111,17 @@ class FileListView: public TDEListView /** * Adds a file and stats to the file listing * @param entries A stringlist of the entries for each column of the list. + * @return The newly added FileLVI */ - void addItem( const TQStringList& entries ); + FileLVI* addItem( const TQStringList& entries ); /** - * Updates a file or folder item already included in the listview + * Adds a file and stats if it doesn't exists or updates the existing one * @param entries A stringlist of the updated entries for each column of the list. + * @return The newly added or the updated FileLVI */ - void updateItem( const TQStringList& entries ); - + FileLVI* addOrUpdateItem( const TQStringList& entries ); + /** * Returns the number of files in the archive. */ diff --git a/ark/rar.cpp b/ark/rar.cpp index 103f4ce..02600d5 100644 --- a/ark/rar.cpp +++ b/ark/rar.cpp @@ -30,6 +30,8 @@ #include // QT includes +#include +#include #include #include #include @@ -39,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -83,94 +86,96 @@ RarArch::RarArch( ArkWidget *_gui, const TQString & _fileName ) verifyUncompressUtilityIsAvailable( m_unarchiver_program ); setReadOnly( true ); } - - m_headerString = ""; } bool RarArch::processLine( const TQCString &line ) { - TQString unicode_line; - - TQTextCodec *codec = TQTextCodec::codecForLocale(); - unicode_line = codec->toUnicode( line ); - - // Look for rar/unrar version first - if (!m_version) - { - if (line.left(3) == "RAR") - { - bool ok_flag = false; - short version = line.mid(4, 1).toShort(&ok_flag); - if (ok_flag) - { - m_version = version; - if (m_version < VERSION_5) - { - m_headerString = "-------------------------------------------------------------------------------"; - m_isFirstLine = true; - } - else - { - m_headerString = "----------- --------- -------- ----- ---------- ----- -------- ----"; - } - setHeaders(); - return true; - } - } - return false; - } - - if (m_version < VERSION_5 && m_isFirstLine) + TQString uline = TQTextCodec::codecForLocale()->toUnicode(line); + + // Look for rar/unrar version first + if (!m_version) { - m_entryFilename = TQString::fromLocal8Bit( line ); - m_entryFilename.remove( 0, 1 ); - m_isFirstLine = false; - return true; + TQRegExp versionRegExp (TQString::fromLatin1 ("RAR\\s(\\d+)\\.(\\S+)\\s.*")); + + if (versionRegExp.exactMatch (uline)) + { + m_version = versionRegExp.capturedTexts()[1].toShort (); + + if (m_version < VERSION_5) { + m_headerString = "-------------------------------------------------------------------------------"; + m_isFirstLine = true; + } else { + m_headerString = "----------- --------- -------- ----- ---------- ----- -------- ----"; + } + setHeaders(); //< Note: header order for version 5 is different, but keep the old one for consistency + return true; + } + return false; } - TQStringList list; - TQStringList l2 = TQStringList::split( ' ', line ); + TQStringList entry; + TQStringList parsedData = TQStringList::split(QChar(' '), uline); - if (m_version < VERSION_5) + if (m_version < VERSION_5) { + if (m_isFirstLine) + { + m_entryFilename = uline.remove( 0, 1 ); + m_isFirstLine = false; + return true; + } + + if (parsedData.size() < 9) { + kdError ( 1601 ) << "Failed to parse rar<5 output string: \"" << uline << "\"" << endl; + } + + entry << m_entryFilename; // filename + entry << parsedData[ 0 ]; // size + entry << parsedData[ 1 ]; // packed + entry << parsedData[ 2 ]; // ratio + + TQStringList date = TQStringList::split( '-', parsedData[ 3 ] ); + entry << ArkUtils::fixYear( date[ 2 ].latin1() ) + '-' + date[ 1 ] + '-' + date [ 0 ] + ' ' + parsedData[4]; // date + entry << parsedData[ 5 ]; // attributes + entry << parsedData[ 6 ]; // crc + entry << parsedData[ 7 ]; // method + entry << parsedData[ 8 ]; // Version + + m_isFirstLine = true; + } + else { - list << m_entryFilename; // filename - list << l2[ 0 ]; // size - list << l2[ 1 ]; // packed - list << l2[ 2 ]; // ratio - - TQStringList date = TQStringList::split( '-', l2[ 3 ] ); - list << ArkUtils::fixYear( date[ 2 ].latin1() ) + '-' + date[ 1 ] + '-' + date [ 0 ] + ' ' + l2[4]; // date - list << l2[ 5 ]; // attributes - list << l2[ 6 ]; // crc - list << l2[ 7 ]; // method - list << l2[ 8 ]; // Version - - m_isFirstLine = true; - } - else - { - m_entryFilename = line.mid(line.find(l2[7])); - list << m_entryFilename; // filename - list << l2[ 1 ]; // size - list << l2[ 2 ]; // packed - list << l2[ 3 ]; // ratio - - TQStringList date = TQStringList::split('-', l2[4]); - list << l2[ 4 ] + " " + l2[ 5 ]; // date and time - list << l2[ 0 ]; // attributes - list << l2[ 6 ]; // crc - } - // send to GUI - if ( l2[6] == "00000000" ) - { - // folders have CRC equal to 00000000 - // RAR utilities show the folders at the end of the listing so the folders - // have been already added to the listview at this point without specifying - // all the columns but the name. Update the item with the missing info - m_gui->fileList()->updateItem( list ); - } - else - m_gui->fileList()->addItem( list ); + // Note: don't use parsedData for names due to they may contain trailing spaces + TQRegExp nameRegExp (TQString::fromLatin1 ("\\s*(\\S+\\s+){6}\\S+ (.*)")); + + if (parsedData.size() >= 8 && nameRegExp.exactMatch (uline)) { + m_entryFilename = nameRegExp.capturedTexts()[2]; + + entry << m_entryFilename; // filename + entry << parsedData[ 1 ]; // size + entry << parsedData[ 2 ]; // packed + entry << parsedData[ 3 ]; // ratio + + entry << parsedData[ 4 ] + " " + parsedData[ 5 ]; // date and time + entry << parsedData[ 0 ]; // attributes + entry << parsedData[ 6 ]; // crc + } else { + kdError ( 1601 ) << "Failed to parse rar-5+ output string: \"" << uline << "\"" << endl; + return false; + } + } + + // send to GUI + // Use addOrUpdateItem() rather than addItem() due to recent RAR version + // place directories in archive after their content. + FileLVI *item = m_gui->fileList()->addOrUpdateItem( entry ); + + // But archives packaged with older versions of ark may have directories + // entries first, so make sure they will get an appropriate icon + if (item && entry[5].find('d', 0, false) != -1) { + // check attr's for d (case insensitive to handle windows archives) + item->setPixmap( 0, KMimeType::mimeType( "inode/directory" )->pixmap( TDEIcon::Small ) ); + } + return true; } @@ -216,9 +221,9 @@ void RarArch::setHeaders() list.append( CRC_COLUMN ); if (m_version < VERSION_5) { - list.append( METHOD_COLUMN ); - list.append( VERSION_COLUMN ); - } + list.append( METHOD_COLUMN ); + list.append( VERSION_COLUMN ); + } emit headers( list ); }