File indexing completed on 2024-05-12 04:51:03
0001 /* 0002 SPDX-FileCopyrightText: 2011 Michal Malek <michalm@jabster.pl> 0003 SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 0009 #include "k3bdatadoc.h" 0010 #include "k3bfileitem.h" 0011 #include "k3bdataitem.h" 0012 #include "k3bdiritem.h" 0013 #include "k3bsessionimportitem.h" 0014 #include "k3bdatajob.h" 0015 #include "k3bbootitem.h" 0016 #include "k3bspecialdataitem.h" 0017 #include "k3bfilecompilationsizehandler.h" 0018 #include "k3bmkisofshandler.h" 0019 #include "k3bcore.h" 0020 #include "k3bglobals.h" 0021 #include "k3bmsf.h" 0022 #include "k3biso9660.h" 0023 #include "k3bisooptions.h" 0024 #include "k3bdevicehandler.h" 0025 #include "k3bdevice.h" 0026 #include "k3btoc.h" 0027 #include "k3btrack.h" 0028 #include "k3bmultichoicedialog.h" 0029 #include "k3bvalidators.h" 0030 #include "k3bglobalsettings.h" 0031 #include "k3b_i18n.h" 0032 0033 #include <KConfig> 0034 #include <KMessageBox> 0035 0036 #include <QDebug> 0037 #include <QDir> 0038 #include <QFile> 0039 #include <QFileInfo> 0040 #include <QStringList> 0041 #include <QTimer> 0042 #include <QApplication> 0043 #include <QDomElement> 0044 0045 #include <string.h> 0046 #include <stdlib.h> 0047 #include <ctype.h> 0048 0049 0050 class K3b::DataDoc::Private 0051 { 0052 public: 0053 Private() 0054 : 0055 oldSessionSize( 0 ), 0056 root( 0 ), 0057 dataMode( 0 ), 0058 verifyData( false ), 0059 importedSession( -1 ), 0060 bootCataloge( 0 ), 0061 bExistingItemsReplaceAll( false ), 0062 bExistingItemsIgnoreAll( false ), 0063 needToCutFilenames( false ) 0064 { 0065 sizeHandler = new K3b::FileCompilationSizeHandler(); 0066 } 0067 0068 ~Private() 0069 { 0070 delete root; 0071 delete sizeHandler; 0072 // delete oldSessionSizeHandler; 0073 } 0074 0075 FileCompilationSizeHandler* sizeHandler; 0076 0077 // FileCompilationSizeHandler* oldSessionSizeHandler; 0078 KIO::filesize_t oldSessionSize; 0079 0080 QStringList notFoundFiles; 0081 QStringList noPermissionFiles; 0082 0083 RootItem* root; 0084 0085 int dataMode; 0086 0087 bool verifyData; 0088 0089 IsoOptions isoOptions; 0090 0091 MultiSessionMode multisessionMode; 0092 QList<DataItem*> oldSession; 0093 int importedSession; 0094 0095 // boot cd stuff 0096 DataItem* bootCataloge; 0097 QList<BootItem*> bootImages; 0098 0099 bool bExistingItemsReplaceAll; 0100 bool bExistingItemsIgnoreAll; 0101 0102 bool needToCutFilenames; 0103 QList<DataItem*> needToCutFilenameItems; 0104 }; 0105 0106 0107 /** 0108 * There are two ways to fill a data project with files and folders: 0109 * \li Use the addUrl and addUrlsT methods 0110 * \li or create your own K3b::DirItems and K3b::FileItems. The doc will be properly updated 0111 * by the constructors of the items. 0112 */ 0113 K3b::DataDoc::DataDoc( QObject* parent ) 0114 : K3b::Doc( parent ), 0115 d( new Private ) 0116 { 0117 } 0118 0119 0120 K3b::DataDoc::~DataDoc() 0121 { 0122 delete d; 0123 } 0124 0125 0126 bool K3b::DataDoc::newDocument() 0127 { 0128 clear(); 0129 if ( !d->root ) 0130 d->root = new K3b::RootItem( *this ); 0131 0132 d->bExistingItemsReplaceAll = d->bExistingItemsIgnoreAll = false; 0133 0134 d->multisessionMode = AUTO; 0135 d->dataMode = K3b::DataModeAuto; 0136 0137 d->isoOptions = K3b::IsoOptions(); 0138 0139 return K3b::Doc::newDocument(); 0140 } 0141 0142 0143 void K3b::DataDoc::clear() 0144 { 0145 clearImportedSession(); 0146 d->importedSession = -1; 0147 d->oldSessionSize = 0; 0148 d->bootCataloge = 0; 0149 if( d->root ) { 0150 while( !d->root->children().isEmpty() ) 0151 removeItem( d->root->children().first() ); 0152 } 0153 d->sizeHandler->clear(); 0154 emit importedSessionChanged( importedSession() ); 0155 } 0156 0157 0158 QString K3b::DataDoc::name() const 0159 { 0160 return d->isoOptions.volumeID(); 0161 } 0162 0163 0164 const K3b::IsoOptions& K3b::DataDoc::isoOptions() const 0165 { 0166 return d->isoOptions; 0167 } 0168 0169 0170 void K3b::DataDoc::setIsoOptions( const K3b::IsoOptions& isoOptions ) 0171 { 0172 d->isoOptions = isoOptions; 0173 emit changed(); 0174 } 0175 0176 0177 void K3b::DataDoc::setVolumeID( const QString& v ) 0178 { 0179 d->isoOptions.setVolumeID( v ); 0180 emit changed(); 0181 emit volumeIdChanged(); 0182 } 0183 0184 0185 void K3b::DataDoc::addUrls( const QList<QUrl>& urls ) 0186 { 0187 addUrlsToDir( urls, root() ); 0188 } 0189 0190 0191 void K3b::DataDoc::addUrlsToDir( const QList<QUrl>& l, K3b::DirItem* dir ) 0192 { 0193 if( !dir ) 0194 dir = root(); 0195 0196 QList<QUrl> urls = K3b::convertToLocalUrls(l); 0197 0198 for( QList<QUrl>::ConstIterator it = urls.constBegin(); it != urls.constEnd(); ++it ) { 0199 const QUrl& url = *it; 0200 QFileInfo f( url.toLocalFile() ); 0201 QString k3bname = f.absoluteFilePath().section( '/', -1 ); 0202 0203 // filenames cannot end in backslashes (mkisofs problem. See comments in k3bisoimager.cpp (escapeGraftPoint())) 0204 while( k3bname[k3bname.length()-1] == '\\' ) 0205 k3bname.truncate( k3bname.length()-1 ); 0206 0207 // backup dummy name 0208 if( k3bname.isEmpty() ) 0209 k3bname = '1'; 0210 0211 K3b::DirItem* newDirItem = 0; 0212 0213 // rename the new item if an item with that name already exists 0214 int cnt = 0; 0215 bool ok = false; 0216 while( !ok ) { 0217 ok = true; 0218 QString name( k3bname ); 0219 if( cnt > 0 ) 0220 name += QString("_%1").arg(cnt); 0221 if( K3b::DataItem* oldItem = dir->find( name ) ) { 0222 if( f.isDir() && oldItem->isDir() ) { 0223 // ok, just reuse the dir 0224 newDirItem = static_cast<K3b::DirItem*>(oldItem); 0225 } 0226 // directories cannot replace files in an old session (I think) 0227 // and also directories can for sure never be replaced (only be reused as above) 0228 // so we always rename if the old item is a dir. 0229 else if( !oldItem->isFromOldSession() || 0230 f.isDir() || 0231 oldItem->isDir() ) { 0232 ++cnt; 0233 ok = false; 0234 } 0235 } 0236 } 0237 if( cnt > 0 ) 0238 k3bname += QString("_%1").arg(cnt); 0239 0240 // QFileInfo::exists and QFileInfo::isReadable return false for broken symlinks :( 0241 if( f.isDir() && !f.isSymLink() ) { 0242 if( !newDirItem ) { 0243 newDirItem = new K3b::DirItem( k3bname ); 0244 newDirItem->setLocalPath( url.toLocalFile() ); // HACK: see k3bdiritem.h 0245 dir->addDataItem( newDirItem ); 0246 } 0247 0248 // recursively add all the files in the directory 0249 QStringList dlist = QDir( f.absoluteFilePath() ).entryList( QDir::AllEntries|QDir::System|QDir::Hidden|QDir::NoDotAndDotDot ); 0250 QList<QUrl> newUrls; 0251 for( QStringList::ConstIterator it = dlist.constBegin(); it != dlist.constEnd(); ++it ) 0252 newUrls.append( QUrl::fromLocalFile( f.absoluteFilePath() + '/' + *it ) ); 0253 addUrlsToDir( newUrls, newDirItem ); 0254 } 0255 else if( f.isSymLink() || f.isFile() ) { 0256 dir->addDataItem( new FileItem( url.toLocalFile(), *this, k3bname ) ); 0257 } 0258 } 0259 0260 emit changed(); 0261 0262 setModified( true ); 0263 } 0264 0265 0266 bool K3b::DataDoc::nameAlreadyInDir( const QString& name, K3b::DirItem* dir ) 0267 { 0268 if( !dir ) 0269 return false; 0270 else 0271 return ( dir->find( name ) != 0 ); 0272 } 0273 0274 0275 K3b::DirItem* K3b::DataDoc::addEmptyDir( const QString& name, K3b::DirItem* parent ) 0276 { 0277 if( parent != 0 ) { 0278 K3b::DirItem* item = new K3b::DirItem( name ); 0279 parent->addDataItem( item ); 0280 0281 setModified( true ); 0282 0283 return item; 0284 } else { 0285 return 0; 0286 } 0287 } 0288 0289 0290 KIO::filesize_t K3b::DataDoc::size() const 0291 { 0292 if( d->isoOptions.doNotCacheInodes() ) 0293 return root()->blocks().mode1Bytes() + d->oldSessionSize; 0294 else 0295 return d->sizeHandler->blocks( d->isoOptions.followSymbolicLinks() || 0296 !d->isoOptions.createRockRidge() ).mode1Bytes(); 0297 } 0298 0299 0300 KIO::filesize_t K3b::DataDoc::burningSize() const 0301 { 0302 return size() - d->oldSessionSize; //d->oldSessionSizeHandler->size(); 0303 } 0304 0305 0306 K3b::Msf K3b::DataDoc::length() const 0307 { 0308 // 1 block consists of 2048 bytes real data 0309 // and 1 block equals to 1 audio frame 0310 // so this is the way to calculate: 0311 0312 return K3b::Msf( size() / 2048 ); 0313 } 0314 0315 0316 K3b::Msf K3b::DataDoc::burningLength() const 0317 { 0318 return K3b::Msf( burningSize() / 2048 ); 0319 } 0320 0321 0322 bool K3b::DataDoc::loadDocumentData( QDomElement* rootElem ) 0323 { 0324 if( !root() ) 0325 newDocument(); 0326 0327 QDomNodeList nodes = rootElem->childNodes(); 0328 0329 if( nodes.item(0).nodeName() != "general" ) { 0330 qDebug() << "(K3b::DataDoc) could not find 'general' section."; 0331 return false; 0332 } 0333 if( !readGeneralDocumentData( nodes.item(0).toElement() ) ) 0334 return false; 0335 0336 0337 // parse options 0338 // ----------------------------------------------------------------- 0339 if( nodes.item(1).nodeName() != "options" ) { 0340 qDebug() << "(K3b::DataDoc) could not find 'options' section."; 0341 return false; 0342 } 0343 if( !loadDocumentDataOptions( nodes.item(1).toElement() ) ) 0344 return false; 0345 // ----------------------------------------------------------------- 0346 0347 0348 0349 // parse header 0350 // ----------------------------------------------------------------- 0351 if( nodes.item(2).nodeName() != "header" ) { 0352 qDebug() << "(K3b::DataDoc) could not find 'header' section."; 0353 return false; 0354 } 0355 if( !loadDocumentDataHeader( nodes.item(2).toElement() ) ) 0356 return false; 0357 // ----------------------------------------------------------------- 0358 0359 0360 0361 // parse files 0362 // ----------------------------------------------------------------- 0363 if( nodes.item(3).nodeName() != "files" ) { 0364 qDebug() << "(K3b::DataDoc) could not find 'files' section."; 0365 return false; 0366 } 0367 0368 if( d->root == 0 ) 0369 d->root = new K3b::RootItem( *this ); 0370 0371 QDomNodeList filesList = nodes.item(3).childNodes(); 0372 for( int i = 0; i < filesList.count(); i++ ) { 0373 0374 QDomElement e = filesList.item(i).toElement(); 0375 if( !loadDataItem( e, root() ) ) 0376 return false; 0377 } 0378 0379 // ----------------------------------------------------------------- 0380 0381 // 0382 // Old versions of K3b do not properly save the boot catalog location 0383 // and name. So to ensure we have one around even if loading an old project 0384 // file we create a default one here. 0385 // 0386 if( !d->bootImages.isEmpty() && !d->bootCataloge ) 0387 createBootCatalogeItem( d->bootImages.first()->parent() ); 0388 0389 0390 informAboutNotFoundFiles(); 0391 0392 return true; 0393 } 0394 0395 0396 bool K3b::DataDoc::loadDocumentDataOptions( QDomElement elem ) 0397 { 0398 QDomNodeList headerList = elem.childNodes(); 0399 for( int i = 0; i < headerList.count(); i++ ) { 0400 0401 QDomElement e = headerList.item(i).toElement(); 0402 if( e.isNull() ) 0403 return false; 0404 0405 if( e.nodeName() == "rock_ridge") 0406 d->isoOptions.setCreateRockRidge( e.attributeNode( "activated" ).value() == "yes" ); 0407 0408 else if( e.nodeName() == "joliet") 0409 d->isoOptions.setCreateJoliet( e.attributeNode( "activated" ).value() == "yes" ); 0410 0411 else if( e.nodeName() == "udf") 0412 d->isoOptions.setCreateUdf( e.attributeNode( "activated" ).value() == "yes" ); 0413 0414 else if( e.nodeName() == "joliet_allow_103_characters") 0415 d->isoOptions.setJolietLong( e.attributeNode( "activated" ).value() == "yes" ); 0416 0417 else if( e.nodeName() == "iso_allow_lowercase") 0418 d->isoOptions.setISOallowLowercase( e.attributeNode( "activated" ).value() == "yes" ); 0419 0420 else if( e.nodeName() == "iso_allow_period_at_begin") 0421 d->isoOptions.setISOallowPeriodAtBegin( e.attributeNode( "activated" ).value() == "yes" ); 0422 0423 else if( e.nodeName() == "iso_allow_31_char") 0424 d->isoOptions.setISOallow31charFilenames( e.attributeNode( "activated" ).value() == "yes" ); 0425 0426 else if( e.nodeName() == "iso_omit_version_numbers") 0427 d->isoOptions.setISOomitVersionNumbers( e.attributeNode( "activated" ).value() == "yes" ); 0428 0429 else if( e.nodeName() == "iso_omit_trailing_period") 0430 d->isoOptions.setISOomitTrailingPeriod( e.attributeNode( "activated" ).value() == "yes" ); 0431 0432 else if( e.nodeName() == "iso_max_filename_length") 0433 d->isoOptions.setISOmaxFilenameLength( e.attributeNode( "activated" ).value() == "yes" ); 0434 0435 else if( e.nodeName() == "iso_relaxed_filenames") 0436 d->isoOptions.setISOrelaxedFilenames( e.attributeNode( "activated" ).value() == "yes" ); 0437 0438 else if( e.nodeName() == "iso_no_iso_translate") 0439 d->isoOptions.setISOnoIsoTranslate( e.attributeNode( "activated" ).value() == "yes" ); 0440 0441 else if( e.nodeName() == "iso_allow_multidot") 0442 d->isoOptions.setISOallowMultiDot( e.attributeNode( "activated" ).value() == "yes" ); 0443 0444 else if( e.nodeName() == "iso_untranslated_filenames") 0445 d->isoOptions.setISOuntranslatedFilenames( e.attributeNode( "activated" ).value() == "yes" ); 0446 0447 else if( e.nodeName() == "follow_symbolic_links") 0448 d->isoOptions.setFollowSymbolicLinks( e.attributeNode( "activated" ).value() == "yes" ); 0449 0450 else if( e.nodeName() == "create_trans_tbl") 0451 d->isoOptions.setCreateTRANS_TBL( e.attributeNode( "activated" ).value() == "yes" ); 0452 0453 else if( e.nodeName() == "hide_trans_tbl") 0454 d->isoOptions.setHideTRANS_TBL( e.attributeNode( "activated" ).value() == "yes" ); 0455 0456 else if( e.nodeName() == "iso_level") 0457 d->isoOptions.setISOLevel( e.text().toInt() ); 0458 0459 else if( e.nodeName() == "discard_symlinks") 0460 d->isoOptions.setDiscardSymlinks( e.attributeNode( "activated" ).value() == "yes" ); 0461 0462 else if( e.nodeName() == "discard_broken_symlinks") 0463 d->isoOptions.setDiscardBrokenSymlinks( e.attributeNode( "activated" ).value() == "yes" ); 0464 0465 else if( e.nodeName() == "preserve_file_permissions") 0466 d->isoOptions.setPreserveFilePermissions( e.attributeNode( "activated" ).value() == "yes" ); 0467 0468 else if( e.nodeName() == "do_not_cache_inodes" ) 0469 d->isoOptions.setDoNotCacheInodes( e.attributeNode( "activated" ).value() == "yes" ); 0470 0471 else if( e.nodeName() == "whitespace_treatment" ) { 0472 if( e.text() == "strip" ) 0473 d->isoOptions.setWhiteSpaceTreatment( K3b::IsoOptions::strip ); 0474 else if( e.text() == "extended" ) 0475 d->isoOptions.setWhiteSpaceTreatment( K3b::IsoOptions::extended ); 0476 else if (e.text() == "replace") 0477 d->isoOptions.setWhiteSpaceTreatment( K3b::IsoOptions::replace ); 0478 else 0479 d->isoOptions.setWhiteSpaceTreatment( K3b::IsoOptions::noChange ); 0480 } 0481 0482 else if( e.nodeName() == "whitespace_replace_string") 0483 d->isoOptions.setWhiteSpaceTreatmentReplaceString( e.text() ); 0484 0485 else if( e.nodeName() == "data_track_mode" ) { 0486 if( e.text() == "mode1" ) 0487 d->dataMode = K3b::DataMode1; 0488 else if( e.text() == "mode2" ) 0489 d->dataMode = K3b::DataMode2; 0490 else 0491 d->dataMode = K3b::DataModeAuto; 0492 } 0493 0494 else if( e.nodeName() == "multisession" ) { 0495 QString mode = e.text(); 0496 if( mode == "start" ) 0497 setMultiSessionMode( START ); 0498 else if( mode == "continue" ) 0499 setMultiSessionMode( CONTINUE ); 0500 else if( mode == "finish" ) 0501 setMultiSessionMode( FINISH ); 0502 else if( mode == "none" ) 0503 setMultiSessionMode( NONE ); 0504 else 0505 setMultiSessionMode( AUTO ); 0506 } 0507 0508 else if( e.nodeName() == "verify_data" ) 0509 setVerifyData( e.attributeNode( "activated" ).value() == "yes" ); 0510 0511 else 0512 qDebug() << "(K3b::DataDoc) unknown option entry: " << e.nodeName(); 0513 } 0514 0515 return true; 0516 } 0517 0518 0519 bool K3b::DataDoc::loadDocumentDataHeader( QDomElement headerElem ) 0520 { 0521 QDomNodeList headerList = headerElem.childNodes(); 0522 for( int i = 0; i < headerList.count(); i++ ) { 0523 0524 QDomElement e = headerList.item(i).toElement(); 0525 if( e.isNull() ) 0526 return false; 0527 0528 if( e.nodeName() == "volume_id" ) 0529 d->isoOptions.setVolumeID( e.text() ); 0530 0531 else if( e.nodeName() == "application_id" ) 0532 d->isoOptions.setApplicationID( e.text() ); 0533 0534 else if( e.nodeName() == "publisher" ) 0535 d->isoOptions.setPublisher( e.text() ); 0536 0537 else if( e.nodeName() == "preparer" ) 0538 d->isoOptions.setPreparer( e.text() ); 0539 0540 else if( e.nodeName() == "volume_set_id" ) 0541 d->isoOptions.setVolumeSetId( e.text() ); 0542 0543 else if( e.nodeName() == "volume_set_size" ) 0544 d->isoOptions.setVolumeSetSize( e.text().toInt() ); 0545 0546 else if( e.nodeName() == "volume_set_number" ) 0547 d->isoOptions.setVolumeSetNumber( e.text().toInt() ); 0548 0549 else if( e.nodeName() == "system_id" ) 0550 d->isoOptions.setSystemId( e.text() ); 0551 0552 else 0553 qDebug() << "(K3b::DataDoc) unknown header entry: " << e.nodeName(); 0554 } 0555 0556 return true; 0557 } 0558 0559 0560 bool K3b::DataDoc::loadDataItem( QDomElement& elem, K3b::DirItem* parent ) 0561 { 0562 if( !parent ) 0563 return false; 0564 0565 K3b::DataItem* newItem = 0; 0566 0567 if( elem.nodeName() == "file" ) { 0568 QDomElement urlElem = elem.firstChild().toElement(); 0569 if( urlElem.isNull() ) { 0570 qDebug() << "(K3b::DataDoc) file-element without url!"; 0571 return false; 0572 } 0573 0574 QFileInfo f( urlElem.text() ); 0575 0576 // We cannot use exists() here since this always disqualifies broken symlinks 0577 if( !f.isFile() && !f.isSymLink() ) 0578 d->notFoundFiles.append( urlElem.text() ); 0579 0580 // broken symlinks are not readable according to QFileInfo which is wrong in our case 0581 else if( f.isFile() && !f.isReadable() ) 0582 d->noPermissionFiles.append( urlElem.text() ); 0583 0584 else if( !elem.attribute( "bootimage" ).isEmpty() ) { 0585 K3b::BootItem* bootItem = new K3b::BootItem( urlElem.text(), 0586 *this, 0587 elem.attributeNode( "name" ).value() ); 0588 parent->addDataItem( bootItem ); 0589 if( elem.attribute( "bootimage" ) == "floppy" ) 0590 bootItem->setImageType( K3b::BootItem::FLOPPY ); 0591 else if( elem.attribute( "bootimage" ) == "harddisk" ) 0592 bootItem->setImageType( K3b::BootItem::HARDDISK ); 0593 else 0594 bootItem->setImageType( K3b::BootItem::NONE ); 0595 bootItem->setNoBoot( elem.attribute( "no_boot" ) == "yes" ); 0596 bootItem->setBootInfoTable( elem.attribute( "boot_info_table" ) == "yes" ); 0597 bootItem->setLoadSegment( elem.attribute( "load_segment" ).toInt() ); 0598 bootItem->setLoadSize( elem.attribute( "load_size" ).toInt() ); 0599 0600 newItem = bootItem; 0601 } 0602 0603 else { 0604 newItem = new K3b::FileItem( urlElem.text(), 0605 *this, 0606 elem.attributeNode( "name" ).value() ); 0607 parent->addDataItem( newItem ); 0608 } 0609 } 0610 else if( elem.nodeName() == "special" ) { 0611 if( elem.attributeNode( "type" ).value() == "boot cataloge" ) 0612 createBootCatalogeItem( parent )->setK3bName( elem.attributeNode( "name" ).value() ); 0613 } 0614 else if( elem.nodeName() == "directory" ) { 0615 // This is for the VideoDVD project which already contains the *_TS folders 0616 K3b::DirItem* newDirItem = 0; 0617 if( K3b::DataItem* item = parent->find( elem.attributeNode( "name" ).value() ) ) { 0618 if( item->isDir() ) { 0619 newDirItem = static_cast<K3b::DirItem*>(item); 0620 } 0621 else { 0622 qCritical() << "(K3b::DataDoc) INVALID DOCUMENT: item " << item->k3bPath() << " saved twice" << Qt::endl; 0623 return false; 0624 } 0625 } 0626 0627 if( !newDirItem ) { 0628 newDirItem = new K3b::DirItem( elem.attributeNode( "name" ).value() ); 0629 parent->addDataItem( newDirItem ); 0630 } 0631 QDomNodeList childNodes = elem.childNodes(); 0632 for( int i = 0; i < childNodes.count(); i++ ) { 0633 0634 QDomElement e = childNodes.item(i).toElement(); 0635 if( !loadDataItem( e, newDirItem ) ) 0636 return false; 0637 } 0638 0639 newItem = newDirItem; 0640 } 0641 else { 0642 qDebug() << "(K3b::DataDoc) wrong tag in files-section: " << elem.nodeName(); 0643 return false; 0644 } 0645 0646 // load the sort weight 0647 if( newItem ) 0648 newItem->setSortWeight( elem.attribute( "sort_weight", "0" ).toInt() ); 0649 0650 return true; 0651 } 0652 0653 0654 bool K3b::DataDoc::saveDocumentData( QDomElement* docElem ) 0655 { 0656 QDomDocument doc = docElem->ownerDocument(); 0657 0658 saveGeneralDocumentData( docElem ); 0659 0660 // all options 0661 // ---------------------------------------------------------------------- 0662 QDomElement optionsElem = doc.createElement( "options" ); 0663 saveDocumentDataOptions( optionsElem ); 0664 docElem->appendChild( optionsElem ); 0665 // ---------------------------------------------------------------------- 0666 0667 // the header stuff 0668 // ---------------------------------------------------------------------- 0669 QDomElement headerElem = doc.createElement( "header" ); 0670 saveDocumentDataHeader( headerElem ); 0671 docElem->appendChild( headerElem ); 0672 0673 0674 // now do the "real" work: save the entries 0675 // ---------------------------------------------------------------------- 0676 QDomElement topElem = doc.createElement( "files" ); 0677 0678 Q_FOREACH( K3b::DataItem* item, root()->children() ) { 0679 saveDataItem( item, &doc, &topElem ); 0680 } 0681 0682 docElem->appendChild( topElem ); 0683 // ---------------------------------------------------------------------- 0684 0685 return true; 0686 } 0687 0688 0689 void K3b::DataDoc::saveDocumentDataOptions( QDomElement& optionsElem ) 0690 { 0691 QDomDocument doc = optionsElem.ownerDocument(); 0692 0693 QDomElement topElem = doc.createElement( "rock_ridge" ); 0694 topElem.setAttribute( "activated", isoOptions().createRockRidge() ? "yes" : "no" ); 0695 optionsElem.appendChild( topElem ); 0696 0697 topElem = doc.createElement( "joliet" ); 0698 topElem.setAttribute( "activated", isoOptions().createJoliet() ? "yes" : "no" ); 0699 optionsElem.appendChild( topElem ); 0700 0701 topElem = doc.createElement( "udf" ); 0702 topElem.setAttribute( "activated", isoOptions().createUdf() ? "yes" : "no" ); 0703 optionsElem.appendChild( topElem ); 0704 0705 topElem = doc.createElement( "joliet_allow_103_characters" ); 0706 topElem.setAttribute( "activated", isoOptions().jolietLong() ? "yes" : "no" ); 0707 optionsElem.appendChild( topElem ); 0708 0709 topElem = doc.createElement( "iso_allow_lowercase" ); 0710 topElem.setAttribute( "activated", isoOptions().ISOallowLowercase() ? "yes" : "no" ); 0711 optionsElem.appendChild( topElem ); 0712 0713 topElem = doc.createElement( "iso_allow_period_at_begin" ); 0714 topElem.setAttribute( "activated", isoOptions().ISOallowPeriodAtBegin() ? "yes" : "no" ); 0715 optionsElem.appendChild( topElem ); 0716 0717 topElem = doc.createElement( "iso_allow_31_char" ); 0718 topElem.setAttribute( "activated", isoOptions().ISOallow31charFilenames() ? "yes" : "no" ); 0719 optionsElem.appendChild( topElem ); 0720 0721 topElem = doc.createElement( "iso_omit_version_numbers" ); 0722 topElem.setAttribute( "activated", isoOptions().ISOomitVersionNumbers() ? "yes" : "no" ); 0723 optionsElem.appendChild( topElem ); 0724 0725 topElem = doc.createElement( "iso_omit_trailing_period" ); 0726 topElem.setAttribute( "activated", isoOptions().ISOomitTrailingPeriod() ? "yes" : "no" ); 0727 optionsElem.appendChild( topElem ); 0728 0729 topElem = doc.createElement( "iso_max_filename_length" ); 0730 topElem.setAttribute( "activated", isoOptions().ISOmaxFilenameLength() ? "yes" : "no" ); 0731 optionsElem.appendChild( topElem ); 0732 0733 topElem = doc.createElement( "iso_relaxed_filenames" ); 0734 topElem.setAttribute( "activated", isoOptions().ISOrelaxedFilenames() ? "yes" : "no" ); 0735 optionsElem.appendChild( topElem ); 0736 0737 topElem = doc.createElement( "iso_no_iso_translate" ); 0738 topElem.setAttribute( "activated", isoOptions().ISOnoIsoTranslate() ? "yes" : "no" ); 0739 optionsElem.appendChild( topElem ); 0740 0741 topElem = doc.createElement( "iso_allow_multidot" ); 0742 topElem.setAttribute( "activated", isoOptions().ISOallowMultiDot() ? "yes" : "no" ); 0743 optionsElem.appendChild( topElem ); 0744 0745 topElem = doc.createElement( "iso_untranslated_filenames" ); 0746 topElem.setAttribute( "activated", isoOptions().ISOuntranslatedFilenames() ? "yes" : "no" ); 0747 optionsElem.appendChild( topElem ); 0748 0749 topElem = doc.createElement( "follow_symbolic_links" ); 0750 topElem.setAttribute( "activated", isoOptions().followSymbolicLinks() ? "yes" : "no" ); 0751 optionsElem.appendChild( topElem ); 0752 0753 topElem = doc.createElement( "create_trans_tbl" ); 0754 topElem.setAttribute( "activated", isoOptions().createTRANS_TBL() ? "yes" : "no" ); 0755 optionsElem.appendChild( topElem ); 0756 0757 topElem = doc.createElement( "hide_trans_tbl" ); 0758 topElem.setAttribute( "activated", isoOptions().hideTRANS_TBL() ? "yes" : "no" ); 0759 optionsElem.appendChild( topElem ); 0760 0761 topElem = doc.createElement( "iso_level" ); 0762 topElem.appendChild( doc.createTextNode( QString::number(isoOptions().ISOLevel()) ) ); 0763 optionsElem.appendChild( topElem ); 0764 0765 topElem = doc.createElement( "discard_symlinks" ); 0766 topElem.setAttribute( "activated", isoOptions().discardSymlinks() ? "yes" : "no" ); 0767 optionsElem.appendChild( topElem ); 0768 0769 topElem = doc.createElement( "discard_broken_symlinks" ); 0770 topElem.setAttribute( "activated", isoOptions().discardBrokenSymlinks() ? "yes" : "no" ); 0771 optionsElem.appendChild( topElem ); 0772 0773 topElem = doc.createElement( "preserve_file_permissions" ); 0774 topElem.setAttribute( "activated", isoOptions().preserveFilePermissions() ? "yes" : "no" ); 0775 optionsElem.appendChild( topElem ); 0776 0777 topElem = doc.createElement( "do_not_cache_inodes" ); 0778 topElem.setAttribute( "activated", isoOptions().doNotCacheInodes() ? "yes" : "no" ); 0779 optionsElem.appendChild( topElem ); 0780 0781 0782 topElem = doc.createElement( "whitespace_treatment" ); 0783 switch( isoOptions().whiteSpaceTreatment() ) { 0784 case K3b::IsoOptions::strip: 0785 topElem.appendChild( doc.createTextNode( "strip" ) ); 0786 break; 0787 case K3b::IsoOptions::extended: 0788 topElem.appendChild( doc.createTextNode( "extended" ) ); 0789 break; 0790 case K3b::IsoOptions::replace: 0791 topElem.appendChild( doc.createTextNode( "replace" ) ); 0792 break; 0793 default: 0794 topElem.appendChild( doc.createTextNode( "noChange" ) ); 0795 break; 0796 } 0797 optionsElem.appendChild( topElem ); 0798 0799 topElem = doc.createElement( "whitespace_replace_string" ); 0800 topElem.appendChild( doc.createTextNode( isoOptions().whiteSpaceTreatmentReplaceString() ) ); 0801 optionsElem.appendChild( topElem ); 0802 0803 topElem = doc.createElement( "data_track_mode" ); 0804 if( d->dataMode == K3b::DataMode1 ) 0805 topElem.appendChild( doc.createTextNode( "mode1" ) ); 0806 else if( d->dataMode == K3b::DataMode2 ) 0807 topElem.appendChild( doc.createTextNode( "mode2" ) ); 0808 else 0809 topElem.appendChild( doc.createTextNode( "auto" ) ); 0810 optionsElem.appendChild( topElem ); 0811 0812 0813 // save multisession 0814 topElem = doc.createElement( "multisession" ); 0815 switch( d->multisessionMode ) { 0816 case START: 0817 topElem.appendChild( doc.createTextNode( "start" ) ); 0818 break; 0819 case CONTINUE: 0820 topElem.appendChild( doc.createTextNode( "continue" ) ); 0821 break; 0822 case FINISH: 0823 topElem.appendChild( doc.createTextNode( "finish" ) ); 0824 break; 0825 case NONE: 0826 topElem.appendChild( doc.createTextNode( "none" ) ); 0827 break; 0828 default: 0829 topElem.appendChild( doc.createTextNode( "auto" ) ); 0830 break; 0831 } 0832 optionsElem.appendChild( topElem ); 0833 0834 topElem = doc.createElement( "verify_data" ); 0835 topElem.setAttribute( "activated", verifyData() ? "yes" : "no" ); 0836 optionsElem.appendChild( topElem ); 0837 // ---------------------------------------------------------------------- 0838 } 0839 0840 0841 void K3b::DataDoc::saveDocumentDataHeader( QDomElement& headerElem ) 0842 { 0843 QDomDocument doc = headerElem.ownerDocument(); 0844 0845 QDomElement topElem = doc.createElement( "volume_id" ); 0846 topElem.appendChild( doc.createTextNode( isoOptions().volumeID() ) ); 0847 headerElem.appendChild( topElem ); 0848 0849 topElem = doc.createElement( "volume_set_id" ); 0850 topElem.appendChild( doc.createTextNode( isoOptions().volumeSetId() ) ); 0851 headerElem.appendChild( topElem ); 0852 0853 topElem = doc.createElement( "volume_set_size" ); 0854 topElem.appendChild( doc.createTextNode( QString::number(isoOptions().volumeSetSize()) ) ); 0855 headerElem.appendChild( topElem ); 0856 0857 topElem = doc.createElement( "volume_set_number" ); 0858 topElem.appendChild( doc.createTextNode( QString::number(isoOptions().volumeSetNumber()) ) ); 0859 headerElem.appendChild( topElem ); 0860 0861 topElem = doc.createElement( "system_id" ); 0862 topElem.appendChild( doc.createTextNode( isoOptions().systemId() ) ); 0863 headerElem.appendChild( topElem ); 0864 0865 topElem = doc.createElement( "application_id" ); 0866 topElem.appendChild( doc.createTextNode( isoOptions().applicationID() ) ); 0867 headerElem.appendChild( topElem ); 0868 0869 topElem = doc.createElement( "publisher" ); 0870 topElem.appendChild( doc.createTextNode( isoOptions().publisher() ) ); 0871 headerElem.appendChild( topElem ); 0872 0873 topElem = doc.createElement( "preparer" ); 0874 topElem.appendChild( doc.createTextNode( isoOptions().preparer() ) ); 0875 headerElem.appendChild( topElem ); 0876 // ---------------------------------------------------------------------- 0877 } 0878 0879 0880 void K3b::DataDoc::saveDataItem( K3b::DataItem* item, QDomDocument* doc, QDomElement* parent ) 0881 { 0882 if( K3b::FileItem* fileItem = dynamic_cast<K3b::FileItem*>( item ) ) { 0883 if( d->oldSession.contains( fileItem ) ) { 0884 qDebug() << "(K3b::DataDoc) ignoring fileitem " << fileItem->k3bName() << " from old session while saving..."; 0885 } 0886 else { 0887 QDomElement topElem = doc->createElement( "file" ); 0888 topElem.setAttribute( "name", fileItem->k3bName() ); 0889 QDomElement subElem = doc->createElement( "url" ); 0890 subElem.appendChild( doc->createTextNode( fileItem->localPath() ) ); 0891 topElem.appendChild( subElem ); 0892 0893 if( item->sortWeight() != 0 ) 0894 topElem.setAttribute( "sort_weight", QString::number(item->sortWeight()) ); 0895 0896 parent->appendChild( topElem ); 0897 0898 // add boot options as attributes to preserve compatibility to older K3b versions 0899 if( K3b::BootItem* bootItem = dynamic_cast<K3b::BootItem*>( fileItem ) ) { 0900 if( bootItem->imageType() == K3b::BootItem::FLOPPY ) 0901 topElem.setAttribute( "bootimage", "floppy" ); 0902 else if( bootItem->imageType() == K3b::BootItem::HARDDISK ) 0903 topElem.setAttribute( "bootimage", "harddisk" ); 0904 else 0905 topElem.setAttribute( "bootimage", "none" ); 0906 0907 topElem.setAttribute( "no_boot", bootItem->noBoot() ? "yes" : "no" ); 0908 topElem.setAttribute( "boot_info_table", bootItem->bootInfoTable() ? "yes" : "no" ); 0909 topElem.setAttribute( "load_segment", QString::number( bootItem->loadSegment() ) ); 0910 topElem.setAttribute( "load_size", QString::number( bootItem->loadSize() ) ); 0911 } 0912 } 0913 } 0914 else if( item == d->bootCataloge ) { 0915 QDomElement topElem = doc->createElement( "special" ); 0916 topElem.setAttribute( "name", d->bootCataloge->k3bName() ); 0917 topElem.setAttribute( "type", "boot cataloge" ); 0918 0919 parent->appendChild( topElem ); 0920 } 0921 else if( K3b::DirItem* dirItem = dynamic_cast<K3b::DirItem*>( item ) ) { 0922 QDomElement topElem = doc->createElement( "directory" ); 0923 topElem.setAttribute( "name", dirItem->k3bName() ); 0924 0925 if( item->sortWeight() != 0 ) 0926 topElem.setAttribute( "sort_weight", QString::number(item->sortWeight()) ); 0927 0928 Q_FOREACH( K3b::DataItem* item, dirItem->children() ) { 0929 saveDataItem( item, doc, &topElem ); 0930 } 0931 0932 parent->appendChild( topElem ); 0933 } 0934 } 0935 0936 0937 void K3b::DataDoc::removeItem( K3b::DataItem* item ) 0938 { 0939 if( !item ) 0940 return; 0941 0942 if( item->isRemoveable() ) { 0943 delete item; 0944 } 0945 else 0946 qDebug() << "(K3b::DataDoc) tried to remove non-removable entry!"; 0947 } 0948 0949 0950 void K3b::DataDoc::removeItems( K3b::DirItem* parent, int start, int count ) 0951 { 0952 if( parent ) { 0953 parent->removeDataItems( start, count ); 0954 } 0955 } 0956 0957 0958 void K3b::DataDoc::beginInsertItems( DirItem* parent, int start, int end ) 0959 { 0960 emit itemsAboutToBeInserted( parent, start, end ); 0961 } 0962 0963 0964 void K3b::DataDoc::endInsertItems( DirItem* parent, int start, int end ) 0965 { 0966 for( int i = start; i <= end; ++i ) { 0967 DataItem* item = parent->children().at( i ); 0968 // update the project size 0969 if( !item->isFromOldSession() ) 0970 d->sizeHandler->addFile( item ); 0971 0972 // update the boot item list 0973 if( item->isBootItem() ) 0974 d->bootImages.append( static_cast<K3b::BootItem*>( item ) ); 0975 } 0976 0977 emit itemsInserted( parent, start, end ); 0978 emit changed(); 0979 } 0980 0981 0982 void K3b::DataDoc::beginRemoveItems( DirItem* parent, int start, int end ) 0983 { 0984 emit itemsAboutToBeRemoved( parent, start, end ); 0985 0986 for( int i = start; i <= end; ++i ) { 0987 DataItem* item = parent->children().at( i ); 0988 // update the project size 0989 if( !item->isFromOldSession() ) 0990 d->sizeHandler->removeFile( item ); 0991 0992 // update the boot item list 0993 if( item->isBootItem() ) { 0994 d->bootImages.removeAll( static_cast<K3b::BootItem*>( item ) ); 0995 if( d->bootImages.isEmpty() ) { 0996 delete d->bootCataloge; 0997 d->bootCataloge = 0; 0998 } 0999 } 1000 } 1001 } 1002 1003 1004 void K3b::DataDoc::endRemoveItems( DirItem* parent, int start, int end ) 1005 { 1006 emit itemsRemoved( parent, start, end ); 1007 emit changed(); 1008 } 1009 1010 1011 void K3b::DataDoc::moveItem( K3b::DataItem* item, K3b::DirItem* newParent ) 1012 { 1013 if( !item || !newParent ) { 1014 qDebug() << "(K3b::DataDoc) item or parentitem was NULL while moving."; 1015 return; 1016 } 1017 1018 if( !item->isMoveable() ) { 1019 qDebug() << "(K3b::DataDoc) item is not movable! "; 1020 return; 1021 } 1022 1023 item->reparent( newParent ); 1024 } 1025 1026 1027 void K3b::DataDoc::moveItems( const QList<K3b::DataItem*>& itemList, K3b::DirItem* newParent ) 1028 { 1029 if( !newParent ) { 1030 qDebug() << "(K3b::DataDoc) tried to move items to nowhere...!"; 1031 return; 1032 } 1033 1034 Q_FOREACH( K3b::DataItem* item, itemList ) { 1035 // check if newParent is subdir of item 1036 if( K3b::DirItem* dirItem = dynamic_cast<K3b::DirItem*>( item ) ) { 1037 if( dirItem->isSubItem( newParent ) ) { 1038 continue; 1039 } 1040 } 1041 1042 if( item->isMoveable() ) 1043 item->reparent( newParent ); 1044 } 1045 } 1046 1047 1048 K3b::BurnJob* K3b::DataDoc::newBurnJob( K3b::JobHandler* hdl, QObject* parent ) 1049 { 1050 return new K3b::DataJob( this, hdl, parent ); 1051 } 1052 1053 1054 QString K3b::DataDoc::treatWhitespace( const QString& path ) 1055 { 1056 1057 // TODO: 1058 // It could happen that two files with different names 1059 // will have the same name after the treatment 1060 // Perhaps we should add a number at the end or something 1061 // similar (s.a.) 1062 1063 1064 if( isoOptions().whiteSpaceTreatment() != K3b::IsoOptions::noChange ) { 1065 QString result = path; 1066 1067 if( isoOptions().whiteSpaceTreatment() == K3b::IsoOptions::replace ) { 1068 result.replace( ' ', isoOptions().whiteSpaceTreatmentReplaceString() ); 1069 } 1070 else if( isoOptions().whiteSpaceTreatment() == K3b::IsoOptions::strip ) { 1071 result.remove( ' ' ); 1072 } 1073 else if( isoOptions().whiteSpaceTreatment() == K3b::IsoOptions::extended ) { 1074 result.truncate(0); 1075 for( int i = 0; i < path.length(); i++ ) { 1076 if( path[i] == ' ' ) { 1077 if( path[i+1] != ' ' ) 1078 result.append( path[++i].toUpper() ); 1079 } 1080 else 1081 result.append( path[i] ); 1082 } 1083 } 1084 1085 qDebug() << "(K3b::DataDoc) converted " << path << " to " << result; 1086 return result; 1087 } 1088 else 1089 return path; 1090 } 1091 1092 1093 void K3b::DataDoc::prepareFilenames() 1094 { 1095 d->needToCutFilenames = false; 1096 d->needToCutFilenameItems.clear(); 1097 1098 // 1099 // if joliet is used cut the names and rename if necessary 1100 // 64 characters for standard joliet and 103 characters for long joliet names 1101 // 1102 // Rockridge supports the full 255 UNIX chars and in case Rockridge is disabled we leave 1103 // it to mkisofs for now since handling all the options to alter the ISO9660 standard it just 1104 // too much. 1105 // 1106 1107 K3b::DataItem* item = root(); 1108 int maxlen = ( isoOptions().jolietLong() ? 103 : 64 ); 1109 while( (item = item->nextSibling()) ) { 1110 item->setWrittenName( treatWhitespace( item->k3bName() ) ); 1111 1112 if( isoOptions().createJoliet() && item->writtenName().length() > maxlen ) { 1113 d->needToCutFilenames = true; 1114 item->setWrittenName( K3b::cutFilename( item->writtenName(), maxlen ) ); 1115 d->needToCutFilenameItems.append( item ); 1116 } 1117 1118 // TODO: check the Joliet charset 1119 } 1120 1121 // 1122 // 3. check if a directory contains items with the same name 1123 // 1124 prepareFilenamesInDir( root() ); 1125 } 1126 1127 1128 void K3b::DataDoc::prepareFilenamesInDir( K3b::DirItem* dir ) 1129 { 1130 if( !dir ) 1131 return; 1132 1133 QList<K3b::DataItem*> sortedChildren; 1134 QList<K3b::DataItem*> children( dir->children() ); 1135 QList<K3b::DataItem*>::const_iterator it = children.constEnd(); 1136 while ( it != children.constBegin() ) { 1137 --it; 1138 K3b::DataItem* item = *it; 1139 1140 if( item->isDir() ) 1141 prepareFilenamesInDir( dynamic_cast<K3b::DirItem*>( item ) ); 1142 1143 // insertion sort 1144 int i = 0; 1145 while( i < sortedChildren.count() && item->writtenName() > sortedChildren.at(i)->writtenName() ) 1146 ++i; 1147 1148 sortedChildren.insert( i, item ); 1149 } 1150 1151 if( isoOptions().createJoliet() || isoOptions().createRockRidge() ) { 1152 QList<K3b::DataItem*> sameNameList; 1153 while( !sortedChildren.isEmpty() ) { 1154 1155 sameNameList.clear(); 1156 1157 do { 1158 sameNameList.append( sortedChildren.takeFirst() ); 1159 } while( !sortedChildren.isEmpty() && 1160 sortedChildren.first()->writtenName() == sameNameList.first()->writtenName() ); 1161 1162 if( sameNameList.count() > 1 ) { 1163 // now we need to rename the items 1164 unsigned int maxlen = 255; 1165 if( isoOptions().createJoliet() ) { 1166 if( isoOptions().jolietLong() ) 1167 maxlen = 103; 1168 else 1169 maxlen = 64; 1170 } 1171 1172 int cnt = 1; 1173 Q_FOREACH( K3b::DataItem* item, sameNameList ) { 1174 item->setWrittenName( K3b::appendNumberToFilename( item->writtenName(), cnt++, maxlen ) ); 1175 } 1176 } 1177 } 1178 } 1179 } 1180 1181 1182 bool K3b::DataDoc::needToCutFilenames() const 1183 { 1184 return d->needToCutFilenames; 1185 } 1186 1187 1188 QList<K3b::DataItem*> K3b::DataDoc::needToCutFilenameItems() const 1189 { 1190 return d->needToCutFilenameItems; 1191 } 1192 1193 1194 void K3b::DataDoc::informAboutNotFoundFiles() 1195 { 1196 if( !d->notFoundFiles.isEmpty() ) { 1197 KMessageBox::informationList( qApp->activeWindow(), i18n("Could not find the following files:"), 1198 d->notFoundFiles, i18n("Not Found") ); 1199 d->notFoundFiles.clear(); 1200 } 1201 1202 if( !d->noPermissionFiles.isEmpty() ) { 1203 KMessageBox::informationList( qApp->activeWindow(), i18n("No permission to read the following files:"), 1204 d->noPermissionFiles, i18n("No Read Permission") ); 1205 1206 d->noPermissionFiles.clear(); 1207 } 1208 } 1209 1210 1211 K3b::DataDoc::MultiSessionMode K3b::DataDoc::multiSessionMode() const 1212 { 1213 return d->multisessionMode; 1214 } 1215 1216 1217 void K3b::DataDoc::setMultiSessionMode( K3b::DataDoc::MultiSessionMode mode ) 1218 { 1219 if( d->multisessionMode == NONE || d->multisessionMode == START ) 1220 clearImportedSession(); 1221 1222 d->multisessionMode = mode; 1223 } 1224 1225 1226 int K3b::DataDoc::dataMode() const 1227 { 1228 return d->dataMode; 1229 } 1230 1231 1232 void K3b::DataDoc::setDataMode( int m ) 1233 { 1234 d->dataMode = m; 1235 } 1236 1237 1238 void K3b::DataDoc::setVerifyData( bool b ) 1239 { 1240 d->verifyData = b; 1241 } 1242 1243 1244 bool K3b::DataDoc::verifyData() const 1245 { 1246 return d->verifyData; 1247 } 1248 1249 1250 bool K3b::DataDoc::importSession( K3b::Device::Device* device, int session ) 1251 { 1252 K3b::Device::DiskInfo diskInfo = device->diskInfo(); 1253 // DVD+RW media is reported as non-appendable 1254 if( !diskInfo.appendable() && 1255 !(diskInfo.mediaType() & (K3b::Device::MEDIA_DVD_PLUS_RW|K3b::Device::MEDIA_DVD_RW_OVWR)) ) 1256 return false; 1257 1258 K3b::Device::Toc toc = device->readToc(); 1259 if( toc.isEmpty() || 1260 toc.last().type() != K3b::Device::Track::TYPE_DATA ) 1261 return false; 1262 1263 long startSec = toc.last().firstSector().lba(); 1264 if ( session > 0 ) { 1265 for ( K3b::Device::Toc::const_iterator it = toc.constBegin(); it != toc.constEnd(); ++it ) { 1266 if ( ( *it ).session() == session ) { 1267 startSec = ( *it ).firstSector().lba(); 1268 break; 1269 } 1270 } 1271 } 1272 K3b::Iso9660 iso( device, startSec ); 1273 1274 if( iso.open() ) { 1275 // remove previously imported sessions 1276 clearImportedSession(); 1277 1278 // set multisession option 1279 if( d->multisessionMode != FINISH && d->multisessionMode != AUTO ) 1280 d->multisessionMode = CONTINUE; 1281 1282 // since in iso9660 it is possible that two files share it's data 1283 // simply summing the file sizes could result in wrong values 1284 // that's why we use the size from the toc. This is more accurate 1285 // anyway since there might be files overwritten or removed 1286 d->oldSessionSize = toc.last().lastSector().mode1Bytes(); 1287 d->importedSession = session; 1288 1289 qDebug() << "(K3b::DataDoc) imported session size: " << KIO::convertSize(d->oldSessionSize); 1290 1291 // the track size for DVD+RW media and DVD-RW Overwrite media has nothing to do with the filesystem 1292 // size. in that case we need to use the filesystem's size (which is ok since it's one track anyway, 1293 // no real multisession) 1294 if( diskInfo.mediaType() & (K3b::Device::MEDIA_DVD_PLUS_RW|K3b::Device::MEDIA_DVD_RW_OVWR) ) { 1295 d->oldSessionSize = iso.primaryDescriptor().volumeSpaceSize 1296 * iso.primaryDescriptor().logicalBlockSize; 1297 } 1298 1299 // import some former settings 1300 d->isoOptions.setCreateRockRidge( iso.firstRRDirEntry() != 0 ); 1301 d->isoOptions.setCreateJoliet( iso.firstJolietDirEntry() != 0 ); 1302 d->isoOptions.setVolumeID( iso.primaryDescriptor().volumeId ); 1303 // TODO: also import some other pd fields 1304 1305 const K3b::Iso9660Directory* rootDir = iso.firstRRDirEntry(); 1306 // J�rg Schilling says that it is impossible to import the joliet tree for multisession 1307 // if( !rootDir ) 1308 // rootDir = iso.firstJolietDirEntry(); 1309 if( !rootDir ) 1310 rootDir = iso.firstIsoDirEntry(); 1311 1312 if( rootDir ) { 1313 createSessionImportItems( rootDir, root() ); 1314 emit changed(); 1315 emit importedSessionChanged( importedSession() ); 1316 return true; 1317 } 1318 else { 1319 qDebug() << "(K3b::DataDoc::importSession) Could not find primary volume desc."; 1320 return false; 1321 } 1322 } 1323 else { 1324 qDebug() << "(K3b::DataDoc) unable to read toc."; 1325 return false; 1326 } 1327 } 1328 1329 1330 void K3b::DataDoc::createSessionImportItems( const K3b::Iso9660Directory* importDir, K3b::DirItem* parent ) 1331 { 1332 if( !parent ) 1333 return; 1334 1335 Q_ASSERT(importDir); 1336 QStringList entries = importDir->entries(); 1337 entries.removeAll( "." ); 1338 entries.removeAll( ".." ); 1339 for( QStringList::const_iterator it = entries.constBegin(); 1340 it != entries.constEnd(); ++it ) { 1341 if( const K3b::Iso9660Entry* entry = importDir->entry( *it ) ) { 1342 K3b::DataItem* oldItem = parent->find( entry->name() ); 1343 if( entry->isDirectory() ) { 1344 K3b::DirItem* dir = 0; 1345 if( oldItem && oldItem->isDir() ) { 1346 dir = (K3b::DirItem*)oldItem; 1347 } 1348 else { 1349 // we overwrite without warning! 1350 if( oldItem ) 1351 removeItem( oldItem ); 1352 dir = new K3b::DirItem( entry->name() ); 1353 parent->addDataItem( dir ); 1354 } 1355 1356 dir->setRemoveable(false); 1357 dir->setRenameable(false); 1358 dir->setMoveable(false); 1359 dir->setHideable(false); 1360 dir->setWriteToCd(false); 1361 dir->setExtraInfo( i18n("From previous session") ); 1362 d->oldSession.append( dir ); 1363 1364 createSessionImportItems( static_cast<const K3b::Iso9660Directory*>(entry), dir ); 1365 } 1366 else { 1367 const K3b::Iso9660File* file = static_cast<const K3b::Iso9660File*>(entry); 1368 1369 // we overwrite without warning! 1370 if( oldItem ) 1371 removeItem( oldItem ); 1372 1373 K3b::SessionImportItem* item = new K3b::SessionImportItem( file ); 1374 item->setExtraInfo( i18n("From previous session") ); 1375 parent->addDataItem( item ); 1376 d->oldSession.append( item ); 1377 } 1378 } 1379 } 1380 } 1381 1382 1383 void K3b::DataDoc::clearImportedSession() 1384 { 1385 // d->oldSessionSizeHandler->clear(); 1386 d->importedSession = -1; 1387 d->oldSessionSize = 0; 1388 1389 while( !d->oldSession.isEmpty() ) { 1390 K3b::DataItem* item = d->oldSession.takeFirst(); 1391 1392 if( item->isDir() ) { 1393 K3b::DirItem* dir = (K3b::DirItem*)item; 1394 if( dir->numDirs() + dir->numFiles() == 0 ) { 1395 // this imported dir is not needed anymore 1396 // since it is empty 1397 delete item; 1398 } 1399 else { 1400 Q_FOREACH( K3b::DataItem* item, dir->children() ) { 1401 if( !d->oldSession.contains( item ) ) { 1402 // now the dir becomes a totally normal dir 1403 dir->setRemoveable(true); 1404 dir->setRenameable(true); 1405 dir->setMoveable(true); 1406 dir->setHideable(true); 1407 dir->setWriteToCd(true); 1408 dir->setExtraInfo( "" ); 1409 break; 1410 } 1411 } 1412 } 1413 } 1414 else { 1415 delete item; 1416 } 1417 } 1418 1419 d->multisessionMode = AUTO; 1420 1421 emit changed(); 1422 emit importedSessionChanged( importedSession() ); 1423 } 1424 1425 QList<K3b::BootItem*> K3b::DataDoc::bootImages() 1426 { 1427 return d->bootImages; 1428 } 1429 1430 1431 K3b::DataItem* K3b::DataDoc::bootCataloge() 1432 { 1433 return d->bootCataloge; 1434 } 1435 1436 1437 K3b::DirItem* K3b::DataDoc::bootImageDir() 1438 { 1439 K3b::DataItem* b = d->root->find( "boot" ); 1440 if( !b ) { 1441 b = new K3b::DirItem( "boot" ); 1442 d->root->addDataItem( b ); 1443 setModified( true ); 1444 } 1445 1446 // if we cannot create the dir because there is a file named boot just use the root dir 1447 if( !b->isDir() ) 1448 return d->root; 1449 else 1450 return static_cast<K3b::DirItem*>(b); 1451 } 1452 1453 1454 K3b::BootItem* K3b::DataDoc::createBootItem( const QString& filename, K3b::DirItem* dir ) 1455 { 1456 if( !dir ) 1457 dir = bootImageDir(); 1458 1459 K3b::BootItem* boot = new K3b::BootItem( filename, *this ); 1460 dir->addDataItem( boot ); 1461 1462 if( !d->bootCataloge ) 1463 createBootCatalogeItem(dir); 1464 1465 return boot; 1466 } 1467 1468 1469 K3b::DataItem* K3b::DataDoc::createBootCatalogeItem( K3b::DirItem* dir ) 1470 { 1471 if( !d->bootCataloge ) { 1472 QString newName = "boot.catalog"; 1473 int i = 0; 1474 while( dir->alreadyInDirectory( "boot.catalog" ) ) { 1475 ++i; 1476 newName = QString( "boot%1.catalog" ).arg(i); 1477 } 1478 1479 K3b::SpecialDataItem* b = new K3b::SpecialDataItem( 0, newName ); 1480 dir->addDataItem( b ); 1481 d->bootCataloge = b; 1482 d->bootCataloge->setRemoveable(false); 1483 d->bootCataloge->setHideable(false); 1484 d->bootCataloge->setWriteToCd(false); 1485 d->bootCataloge->setExtraInfo( i18n("El Torito boot catalog file") ); 1486 b->setSpecialType( i18n("Boot catalog") ); 1487 } 1488 else 1489 d->bootCataloge->reparent( dir ); 1490 1491 return d->bootCataloge; 1492 } 1493 1494 1495 QList<K3b::DataItem*> K3b::DataDoc::findItemByLocalPath( const QString& path ) const 1496 { 1497 Q_UNUSED( path ); 1498 return QList<K3b::DataItem*>(); 1499 } 1500 1501 1502 int K3b::DataDoc::importedSession() const 1503 { 1504 return ( d->oldSession.isEmpty() ? -1 : d->importedSession ); 1505 } 1506 1507 1508 K3b::Device::MediaTypes K3b::DataDoc::supportedMediaTypes() const 1509 { 1510 return Device::MEDIA_WRITABLE; 1511 } 1512 1513 1514 K3b::RootItem* K3b::DataDoc::root() const 1515 { 1516 return d->root; 1517 } 1518 1519 #include "moc_k3bdatadoc.cpp"