1 /*
2 SPDX-FileCopyrightText: 2011 Michal Malek <michalm@jabster.pl>
3 SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
4
5 SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8
9 #include "k3bdatadoc.h"
10 #include "k3bfileitem.h"
11 #include "k3bdataitem.h"
12 #include "k3bdiritem.h"
13 #include "k3bsessionimportitem.h"
14 #include "k3bdatajob.h"
15 #include "k3bbootitem.h"
16 #include "k3bspecialdataitem.h"
17 #include "k3bfilecompilationsizehandler.h"
18 #include "k3bmkisofshandler.h"
19 #include "k3bcore.h"
20 #include "k3bglobals.h"
21 #include "k3bmsf.h"
22 #include "k3biso9660.h"
23 #include "k3bisooptions.h"
24 #include "k3bdevicehandler.h"
25 #include "k3bdevice.h"
26 #include "k3btoc.h"
27 #include "k3btrack.h"
28 #include "k3bmultichoicedialog.h"
29 #include "k3bvalidators.h"
30 #include "k3bglobalsettings.h"
31 #include "k3b_i18n.h"
32
33 #include <KConfig>
34 #include <KMessageBox>
35
36 #include <QDebug>
37 #include <QDir>
38 #include <QFile>
39 #include <QFileInfo>
40 #include <QStringList>
41 #include <QTimer>
42 #include <QApplication>
43 #include <QDomElement>
44
45 #include <string.h>
46 #include <stdlib.h>
47 #include <ctype.h>
48
49
50 class K3b::DataDoc::Private
51 {
52 public:
Private()53 Private()
54 :
55 oldSessionSize( 0 ),
56 root( 0 ),
57 dataMode( 0 ),
58 verifyData( false ),
59 importedSession( -1 ),
60 bootCataloge( 0 ),
61 bExistingItemsReplaceAll( false ),
62 bExistingItemsIgnoreAll( false ),
63 needToCutFilenames( false )
64 {
65 sizeHandler = new K3b::FileCompilationSizeHandler();
66 }
67
~Private()68 ~Private()
69 {
70 delete root;
71 delete sizeHandler;
72 // delete oldSessionSizeHandler;
73 }
74
75 FileCompilationSizeHandler* sizeHandler;
76
77 // FileCompilationSizeHandler* oldSessionSizeHandler;
78 KIO::filesize_t oldSessionSize;
79
80 QStringList notFoundFiles;
81 QStringList noPermissionFiles;
82
83 RootItem* root;
84
85 int dataMode;
86
87 bool verifyData;
88
89 IsoOptions isoOptions;
90
91 MultiSessionMode multisessionMode;
92 QList<DataItem*> oldSession;
93 int importedSession;
94
95 // boot cd stuff
96 DataItem* bootCataloge;
97 QList<BootItem*> bootImages;
98
99 bool bExistingItemsReplaceAll;
100 bool bExistingItemsIgnoreAll;
101
102 bool needToCutFilenames;
103 QList<DataItem*> needToCutFilenameItems;
104 };
105
106
107 /**
108 * There are two ways to fill a data project with files and folders:
109 * \li Use the addUrl and addUrlsT methods
110 * \li or create your own K3b::DirItems and K3b::FileItems. The doc will be properly updated
111 * by the constructors of the items.
112 */
DataDoc(QObject * parent)113 K3b::DataDoc::DataDoc( QObject* parent )
114 : K3b::Doc( parent ),
115 d( new Private )
116 {
117 }
118
119
~DataDoc()120 K3b::DataDoc::~DataDoc()
121 {
122 delete d;
123 }
124
125
newDocument()126 bool K3b::DataDoc::newDocument()
127 {
128 clear();
129 if ( !d->root )
130 d->root = new K3b::RootItem( *this );
131
132 d->bExistingItemsReplaceAll = d->bExistingItemsIgnoreAll = false;
133
134 d->multisessionMode = AUTO;
135 d->dataMode = K3b::DataModeAuto;
136
137 d->isoOptions = K3b::IsoOptions();
138
139 return K3b::Doc::newDocument();
140 }
141
142
clear()143 void K3b::DataDoc::clear()
144 {
145 clearImportedSession();
146 d->importedSession = -1;
147 d->oldSessionSize = 0;
148 d->bootCataloge = 0;
149 if( d->root ) {
150 while( !d->root->children().isEmpty() )
151 removeItem( d->root->children().first() );
152 }
153 d->sizeHandler->clear();
154 emit importedSessionChanged( importedSession() );
155 }
156
157
name() const158 QString K3b::DataDoc::name() const
159 {
160 return d->isoOptions.volumeID();
161 }
162
163
isoOptions() const164 const K3b::IsoOptions& K3b::DataDoc::isoOptions() const
165 {
166 return d->isoOptions;
167 }
168
169
setIsoOptions(const K3b::IsoOptions & isoOptions)170 void K3b::DataDoc::setIsoOptions( const K3b::IsoOptions& isoOptions )
171 {
172 d->isoOptions = isoOptions;
173 emit changed();
174 }
175
176
setVolumeID(const QString & v)177 void K3b::DataDoc::setVolumeID( const QString& v )
178 {
179 d->isoOptions.setVolumeID( v );
180 emit changed();
181 emit volumeIdChanged();
182 }
183
184
addUrls(const QList<QUrl> & urls)185 void K3b::DataDoc::addUrls( const QList<QUrl>& urls )
186 {
187 addUrlsToDir( urls, root() );
188 }
189
190
addUrlsToDir(const QList<QUrl> & l,K3b::DirItem * dir)191 void K3b::DataDoc::addUrlsToDir( const QList<QUrl>& l, K3b::DirItem* dir )
192 {
193 if( !dir )
194 dir = root();
195
196 QList<QUrl> urls = K3b::convertToLocalUrls(l);
197
198 for( QList<QUrl>::ConstIterator it = urls.constBegin(); it != urls.constEnd(); ++it ) {
199 const QUrl& url = *it;
200 QFileInfo f( url.toLocalFile() );
201 QString k3bname = f.absoluteFilePath().section( '/', -1 );
202
203 // filenames cannot end in backslashes (mkisofs problem. See comments in k3bisoimager.cpp (escapeGraftPoint()))
204 while( k3bname[k3bname.length()-1] == '\\' )
205 k3bname.truncate( k3bname.length()-1 );
206
207 // backup dummy name
208 if( k3bname.isEmpty() )
209 k3bname = '1';
210
211 K3b::DirItem* newDirItem = 0;
212
213 // rename the new item if an item with that name already exists
214 int cnt = 0;
215 bool ok = false;
216 while( !ok ) {
217 ok = true;
218 QString name( k3bname );
219 if( cnt > 0 )
220 name += QString("_%1").arg(cnt);
221 if( K3b::DataItem* oldItem = dir->find( name ) ) {
222 if( f.isDir() && oldItem->isDir() ) {
223 // ok, just reuse the dir
224 newDirItem = static_cast<K3b::DirItem*>(oldItem);
225 }
226 // directories cannot replace files in an old session (I think)
227 // and also directories can for sure never be replaced (only be reused as above)
228 // so we always rename if the old item is a dir.
229 else if( !oldItem->isFromOldSession() ||
230 f.isDir() ||
231 oldItem->isDir() ) {
232 ++cnt;
233 ok = false;
234 }
235 }
236 }
237 if( cnt > 0 )
238 k3bname += QString("_%1").arg(cnt);
239
240 // QFileInfo::exists and QFileInfo::isReadable return false for broken symlinks :(
241 if( f.isDir() && !f.isSymLink() ) {
242 if( !newDirItem ) {
243 newDirItem = new K3b::DirItem( k3bname );
244 newDirItem->setLocalPath( url.toLocalFile() ); // HACK: see k3bdiritem.h
245 dir->addDataItem( newDirItem );
246 }
247
248 // recursively add all the files in the directory
249 QStringList dlist = QDir( f.absoluteFilePath() ).entryList( QDir::AllEntries|QDir::System|QDir::Hidden|QDir::NoDotAndDotDot );
250 QList<QUrl> newUrls;
251 for( QStringList::ConstIterator it = dlist.constBegin(); it != dlist.constEnd(); ++it )
252 newUrls.append( QUrl::fromLocalFile( f.absoluteFilePath() + '/' + *it ) );
253 addUrlsToDir( newUrls, newDirItem );
254 }
255 else if( f.isSymLink() || f.isFile() ) {
256 dir->addDataItem( new FileItem( url.toLocalFile(), *this, k3bname ) );
257 }
258 }
259
260 emit changed();
261
262 setModified( true );
263 }
264
265
nameAlreadyInDir(const QString & name,K3b::DirItem * dir)266 bool K3b::DataDoc::nameAlreadyInDir( const QString& name, K3b::DirItem* dir )
267 {
268 if( !dir )
269 return false;
270 else
271 return ( dir->find( name ) != 0 );
272 }
273
274
addEmptyDir(const QString & name,K3b::DirItem * parent)275 K3b::DirItem* K3b::DataDoc::addEmptyDir( const QString& name, K3b::DirItem* parent )
276 {
277 if( parent != 0 ) {
278 K3b::DirItem* item = new K3b::DirItem( name );
279 parent->addDataItem( item );
280
281 setModified( true );
282
283 return item;
284 } else {
285 return 0;
286 }
287 }
288
289
size() const290 KIO::filesize_t K3b::DataDoc::size() const
291 {
292 if( d->isoOptions.doNotCacheInodes() )
293 return root()->blocks().mode1Bytes() + d->oldSessionSize;
294 else
295 return d->sizeHandler->blocks( d->isoOptions.followSymbolicLinks() ||
296 !d->isoOptions.createRockRidge() ).mode1Bytes();
297 }
298
299
burningSize() const300 KIO::filesize_t K3b::DataDoc::burningSize() const
301 {
302 return size() - d->oldSessionSize; //d->oldSessionSizeHandler->size();
303 }
304
305
length() const306 K3b::Msf K3b::DataDoc::length() const
307 {
308 // 1 block consists of 2048 bytes real data
309 // and 1 block equals to 1 audio frame
310 // so this is the way to calculate:
311
312 return K3b::Msf( size() / 2048 );
313 }
314
315
burningLength() const316 K3b::Msf K3b::DataDoc::burningLength() const
317 {
318 return K3b::Msf( burningSize() / 2048 );
319 }
320
321
loadDocumentData(QDomElement * rootElem)322 bool K3b::DataDoc::loadDocumentData( QDomElement* rootElem )
323 {
324 if( !root() )
325 newDocument();
326
327 QDomNodeList nodes = rootElem->childNodes();
328
329 if( nodes.item(0).nodeName() != "general" ) {
330 qDebug() << "(K3b::DataDoc) could not find 'general' section.";
331 return false;
332 }
333 if( !readGeneralDocumentData( nodes.item(0).toElement() ) )
334 return false;
335
336
337 // parse options
338 // -----------------------------------------------------------------
339 if( nodes.item(1).nodeName() != "options" ) {
340 qDebug() << "(K3b::DataDoc) could not find 'options' section.";
341 return false;
342 }
343 if( !loadDocumentDataOptions( nodes.item(1).toElement() ) )
344 return false;
345 // -----------------------------------------------------------------
346
347
348
349 // parse header
350 // -----------------------------------------------------------------
351 if( nodes.item(2).nodeName() != "header" ) {
352 qDebug() << "(K3b::DataDoc) could not find 'header' section.";
353 return false;
354 }
355 if( !loadDocumentDataHeader( nodes.item(2).toElement() ) )
356 return false;
357 // -----------------------------------------------------------------
358
359
360
361 // parse files
362 // -----------------------------------------------------------------
363 if( nodes.item(3).nodeName() != "files" ) {
364 qDebug() << "(K3b::DataDoc) could not find 'files' section.";
365 return false;
366 }
367
368 if( d->root == 0 )
369 d->root = new K3b::RootItem( *this );
370
371 QDomNodeList filesList = nodes.item(3).childNodes();
372 for( int i = 0; i < filesList.count(); i++ ) {
373
374 QDomElement e = filesList.item(i).toElement();
375 if( !loadDataItem( e, root() ) )
376 return false;
377 }
378
379 // -----------------------------------------------------------------
380
381 //
382 // Old versions of K3b do not properly save the boot catalog location
383 // and name. So to ensure we have one around even if loading an old project
384 // file we create a default one here.
385 //
386 if( !d->bootImages.isEmpty() && !d->bootCataloge )
387 createBootCatalogeItem( d->bootImages.first()->parent() );
388
389
390 informAboutNotFoundFiles();
391
392 return true;
393 }
394
395
loadDocumentDataOptions(QDomElement elem)396 bool K3b::DataDoc::loadDocumentDataOptions( QDomElement elem )
397 {
398 QDomNodeList headerList = elem.childNodes();
399 for( int i = 0; i < headerList.count(); i++ ) {
400
401 QDomElement e = headerList.item(i).toElement();
402 if( e.isNull() )
403 return false;
404
405 if( e.nodeName() == "rock_ridge")
406 d->isoOptions.setCreateRockRidge( e.attributeNode( "activated" ).value() == "yes" );
407
408 else if( e.nodeName() == "joliet")
409 d->isoOptions.setCreateJoliet( e.attributeNode( "activated" ).value() == "yes" );
410
411 else if( e.nodeName() == "udf")
412 d->isoOptions.setCreateUdf( e.attributeNode( "activated" ).value() == "yes" );
413
414 else if( e.nodeName() == "joliet_allow_103_characters")
415 d->isoOptions.setJolietLong( e.attributeNode( "activated" ).value() == "yes" );
416
417 else if( e.nodeName() == "iso_allow_lowercase")
418 d->isoOptions.setISOallowLowercase( e.attributeNode( "activated" ).value() == "yes" );
419
420 else if( e.nodeName() == "iso_allow_period_at_begin")
421 d->isoOptions.setISOallowPeriodAtBegin( e.attributeNode( "activated" ).value() == "yes" );
422
423 else if( e.nodeName() == "iso_allow_31_char")
424 d->isoOptions.setISOallow31charFilenames( e.attributeNode( "activated" ).value() == "yes" );
425
426 else if( e.nodeName() == "iso_omit_version_numbers")
427 d->isoOptions.setISOomitVersionNumbers( e.attributeNode( "activated" ).value() == "yes" );
428
429 else if( e.nodeName() == "iso_omit_trailing_period")
430 d->isoOptions.setISOomitTrailingPeriod( e.attributeNode( "activated" ).value() == "yes" );
431
432 else if( e.nodeName() == "iso_max_filename_length")
433 d->isoOptions.setISOmaxFilenameLength( e.attributeNode( "activated" ).value() == "yes" );
434
435 else if( e.nodeName() == "iso_relaxed_filenames")
436 d->isoOptions.setISOrelaxedFilenames( e.attributeNode( "activated" ).value() == "yes" );
437
438 else if( e.nodeName() == "iso_no_iso_translate")
439 d->isoOptions.setISOnoIsoTranslate( e.attributeNode( "activated" ).value() == "yes" );
440
441 else if( e.nodeName() == "iso_allow_multidot")
442 d->isoOptions.setISOallowMultiDot( e.attributeNode( "activated" ).value() == "yes" );
443
444 else if( e.nodeName() == "iso_untranslated_filenames")
445 d->isoOptions.setISOuntranslatedFilenames( e.attributeNode( "activated" ).value() == "yes" );
446
447 else if( e.nodeName() == "follow_symbolic_links")
448 d->isoOptions.setFollowSymbolicLinks( e.attributeNode( "activated" ).value() == "yes" );
449
450 else if( e.nodeName() == "create_trans_tbl")
451 d->isoOptions.setCreateTRANS_TBL( e.attributeNode( "activated" ).value() == "yes" );
452
453 else if( e.nodeName() == "hide_trans_tbl")
454 d->isoOptions.setHideTRANS_TBL( e.attributeNode( "activated" ).value() == "yes" );
455
456 else if( e.nodeName() == "iso_level")
457 d->isoOptions.setISOLevel( e.text().toInt() );
458
459 else if( e.nodeName() == "discard_symlinks")
460 d->isoOptions.setDiscardSymlinks( e.attributeNode( "activated" ).value() == "yes" );
461
462 else if( e.nodeName() == "discard_broken_symlinks")
463 d->isoOptions.setDiscardBrokenSymlinks( e.attributeNode( "activated" ).value() == "yes" );
464
465 else if( e.nodeName() == "preserve_file_permissions")
466 d->isoOptions.setPreserveFilePermissions( e.attributeNode( "activated" ).value() == "yes" );
467
468 else if( e.nodeName() == "do_not_cache_inodes" )
469 d->isoOptions.setDoNotCacheInodes( e.attributeNode( "activated" ).value() == "yes" );
470
471 else if( e.nodeName() == "whitespace_treatment" ) {
472 if( e.text() == "strip" )
473 d->isoOptions.setWhiteSpaceTreatment( K3b::IsoOptions::strip );
474 else if( e.text() == "extended" )
475 d->isoOptions.setWhiteSpaceTreatment( K3b::IsoOptions::extended );
476 else if (e.text() == "replace")
477 d->isoOptions.setWhiteSpaceTreatment( K3b::IsoOptions::replace );
478 else
479 d->isoOptions.setWhiteSpaceTreatment( K3b::IsoOptions::noChange );
480 }
481
482 else if( e.nodeName() == "whitespace_replace_string")
483 d->isoOptions.setWhiteSpaceTreatmentReplaceString( e.text() );
484
485 else if( e.nodeName() == "data_track_mode" ) {
486 if( e.text() == "mode1" )
487 d->dataMode = K3b::DataMode1;
488 else if( e.text() == "mode2" )
489 d->dataMode = K3b::DataMode2;
490 else
491 d->dataMode = K3b::DataModeAuto;
492 }
493
494 else if( e.nodeName() == "multisession" ) {
495 QString mode = e.text();
496 if( mode == "start" )
497 setMultiSessionMode( START );
498 else if( mode == "continue" )
499 setMultiSessionMode( CONTINUE );
500 else if( mode == "finish" )
501 setMultiSessionMode( FINISH );
502 else if( mode == "none" )
503 setMultiSessionMode( NONE );
504 else
505 setMultiSessionMode( AUTO );
506 }
507
508 else if( e.nodeName() == "verify_data" )
509 setVerifyData( e.attributeNode( "activated" ).value() == "yes" );
510
511 else
512 qDebug() << "(K3b::DataDoc) unknown option entry: " << e.nodeName();
513 }
514
515 return true;
516 }
517
518
loadDocumentDataHeader(QDomElement headerElem)519 bool K3b::DataDoc::loadDocumentDataHeader( QDomElement headerElem )
520 {
521 QDomNodeList headerList = headerElem.childNodes();
522 for( int i = 0; i < headerList.count(); i++ ) {
523
524 QDomElement e = headerList.item(i).toElement();
525 if( e.isNull() )
526 return false;
527
528 if( e.nodeName() == "volume_id" )
529 d->isoOptions.setVolumeID( e.text() );
530
531 else if( e.nodeName() == "application_id" )
532 d->isoOptions.setApplicationID( e.text() );
533
534 else if( e.nodeName() == "publisher" )
535 d->isoOptions.setPublisher( e.text() );
536
537 else if( e.nodeName() == "preparer" )
538 d->isoOptions.setPreparer( e.text() );
539
540 else if( e.nodeName() == "volume_set_id" )
541 d->isoOptions.setVolumeSetId( e.text() );
542
543 else if( e.nodeName() == "volume_set_size" )
544 d->isoOptions.setVolumeSetSize( e.text().toInt() );
545
546 else if( e.nodeName() == "volume_set_number" )
547 d->isoOptions.setVolumeSetNumber( e.text().toInt() );
548
549 else if( e.nodeName() == "system_id" )
550 d->isoOptions.setSystemId( e.text() );
551
552 else
553 qDebug() << "(K3b::DataDoc) unknown header entry: " << e.nodeName();
554 }
555
556 return true;
557 }
558
559
loadDataItem(QDomElement & elem,K3b::DirItem * parent)560 bool K3b::DataDoc::loadDataItem( QDomElement& elem, K3b::DirItem* parent )
561 {
562 if( !parent )
563 return false;
564
565 K3b::DataItem* newItem = 0;
566
567 if( elem.nodeName() == "file" ) {
568 QDomElement urlElem = elem.firstChild().toElement();
569 if( urlElem.isNull() ) {
570 qDebug() << "(K3b::DataDoc) file-element without url!";
571 return false;
572 }
573
574 QFileInfo f( urlElem.text() );
575
576 // We cannot use exists() here since this always disqualifies broken symlinks
577 if( !f.isFile() && !f.isSymLink() )
578 d->notFoundFiles.append( urlElem.text() );
579
580 // broken symlinks are not readable according to QFileInfo which is wrong in our case
581 else if( f.isFile() && !f.isReadable() )
582 d->noPermissionFiles.append( urlElem.text() );
583
584 else if( !elem.attribute( "bootimage" ).isEmpty() ) {
585 K3b::BootItem* bootItem = new K3b::BootItem( urlElem.text(),
586 *this,
587 elem.attributeNode( "name" ).value() );
588 parent->addDataItem( bootItem );
589 if( elem.attribute( "bootimage" ) == "floppy" )
590 bootItem->setImageType( K3b::BootItem::FLOPPY );
591 else if( elem.attribute( "bootimage" ) == "harddisk" )
592 bootItem->setImageType( K3b::BootItem::HARDDISK );
593 else
594 bootItem->setImageType( K3b::BootItem::NONE );
595 bootItem->setNoBoot( elem.attribute( "no_boot" ) == "yes" );
596 bootItem->setBootInfoTable( elem.attribute( "boot_info_table" ) == "yes" );
597 bootItem->setLoadSegment( elem.attribute( "load_segment" ).toInt() );
598 bootItem->setLoadSize( elem.attribute( "load_size" ).toInt() );
599
600 newItem = bootItem;
601 }
602
603 else {
604 newItem = new K3b::FileItem( urlElem.text(),
605 *this,
606 elem.attributeNode( "name" ).value() );
607 parent->addDataItem( newItem );
608 }
609 }
610 else if( elem.nodeName() == "special" ) {
611 if( elem.attributeNode( "type" ).value() == "boot cataloge" )
612 createBootCatalogeItem( parent )->setK3bName( elem.attributeNode( "name" ).value() );
613 }
614 else if( elem.nodeName() == "directory" ) {
615 // This is for the VideoDVD project which already contains the *_TS folders
616 K3b::DirItem* newDirItem = 0;
617 if( K3b::DataItem* item = parent->find( elem.attributeNode( "name" ).value() ) ) {
618 if( item->isDir() ) {
619 newDirItem = static_cast<K3b::DirItem*>(item);
620 }
621 else {
622 qCritical() << "(K3b::DataDoc) INVALID DOCUMENT: item " << item->k3bPath() << " saved twice" << endl;
623 return false;
624 }
625 }
626
627 if( !newDirItem ) {
628 newDirItem = new K3b::DirItem( elem.attributeNode( "name" ).value() );
629 parent->addDataItem( newDirItem );
630 }
631 QDomNodeList childNodes = elem.childNodes();
632 for( int i = 0; i < childNodes.count(); i++ ) {
633
634 QDomElement e = childNodes.item(i).toElement();
635 if( !loadDataItem( e, newDirItem ) )
636 return false;
637 }
638
639 newItem = newDirItem;
640 }
641 else {
642 qDebug() << "(K3b::DataDoc) wrong tag in files-section: " << elem.nodeName();
643 return false;
644 }
645
646 // load the sort weight
647 if( newItem )
648 newItem->setSortWeight( elem.attribute( "sort_weight", "0" ).toInt() );
649
650 return true;
651 }
652
653
saveDocumentData(QDomElement * docElem)654 bool K3b::DataDoc::saveDocumentData( QDomElement* docElem )
655 {
656 QDomDocument doc = docElem->ownerDocument();
657
658 saveGeneralDocumentData( docElem );
659
660 // all options
661 // ----------------------------------------------------------------------
662 QDomElement optionsElem = doc.createElement( "options" );
663 saveDocumentDataOptions( optionsElem );
664 docElem->appendChild( optionsElem );
665 // ----------------------------------------------------------------------
666
667 // the header stuff
668 // ----------------------------------------------------------------------
669 QDomElement headerElem = doc.createElement( "header" );
670 saveDocumentDataHeader( headerElem );
671 docElem->appendChild( headerElem );
672
673
674 // now do the "real" work: save the entries
675 // ----------------------------------------------------------------------
676 QDomElement topElem = doc.createElement( "files" );
677
678 Q_FOREACH( K3b::DataItem* item, root()->children() ) {
679 saveDataItem( item, &doc, &topElem );
680 }
681
682 docElem->appendChild( topElem );
683 // ----------------------------------------------------------------------
684
685 return true;
686 }
687
688
saveDocumentDataOptions(QDomElement & optionsElem)689 void K3b::DataDoc::saveDocumentDataOptions( QDomElement& optionsElem )
690 {
691 QDomDocument doc = optionsElem.ownerDocument();
692
693 QDomElement topElem = doc.createElement( "rock_ridge" );
694 topElem.setAttribute( "activated", isoOptions().createRockRidge() ? "yes" : "no" );
695 optionsElem.appendChild( topElem );
696
697 topElem = doc.createElement( "joliet" );
698 topElem.setAttribute( "activated", isoOptions().createJoliet() ? "yes" : "no" );
699 optionsElem.appendChild( topElem );
700
701 topElem = doc.createElement( "udf" );
702 topElem.setAttribute( "activated", isoOptions().createUdf() ? "yes" : "no" );
703 optionsElem.appendChild( topElem );
704
705 topElem = doc.createElement( "joliet_allow_103_characters" );
706 topElem.setAttribute( "activated", isoOptions().jolietLong() ? "yes" : "no" );
707 optionsElem.appendChild( topElem );
708
709 topElem = doc.createElement( "iso_allow_lowercase" );
710 topElem.setAttribute( "activated", isoOptions().ISOallowLowercase() ? "yes" : "no" );
711 optionsElem.appendChild( topElem );
712
713 topElem = doc.createElement( "iso_allow_period_at_begin" );
714 topElem.setAttribute( "activated", isoOptions().ISOallowPeriodAtBegin() ? "yes" : "no" );
715 optionsElem.appendChild( topElem );
716
717 topElem = doc.createElement( "iso_allow_31_char" );
718 topElem.setAttribute( "activated", isoOptions().ISOallow31charFilenames() ? "yes" : "no" );
719 optionsElem.appendChild( topElem );
720
721 topElem = doc.createElement( "iso_omit_version_numbers" );
722 topElem.setAttribute( "activated", isoOptions().ISOomitVersionNumbers() ? "yes" : "no" );
723 optionsElem.appendChild( topElem );
724
725 topElem = doc.createElement( "iso_omit_trailing_period" );
726 topElem.setAttribute( "activated", isoOptions().ISOomitTrailingPeriod() ? "yes" : "no" );
727 optionsElem.appendChild( topElem );
728
729 topElem = doc.createElement( "iso_max_filename_length" );
730 topElem.setAttribute( "activated", isoOptions().ISOmaxFilenameLength() ? "yes" : "no" );
731 optionsElem.appendChild( topElem );
732
733 topElem = doc.createElement( "iso_relaxed_filenames" );
734 topElem.setAttribute( "activated", isoOptions().ISOrelaxedFilenames() ? "yes" : "no" );
735 optionsElem.appendChild( topElem );
736
737 topElem = doc.createElement( "iso_no_iso_translate" );
738 topElem.setAttribute( "activated", isoOptions().ISOnoIsoTranslate() ? "yes" : "no" );
739 optionsElem.appendChild( topElem );
740
741 topElem = doc.createElement( "iso_allow_multidot" );
742 topElem.setAttribute( "activated", isoOptions().ISOallowMultiDot() ? "yes" : "no" );
743 optionsElem.appendChild( topElem );
744
745 topElem = doc.createElement( "iso_untranslated_filenames" );
746 topElem.setAttribute( "activated", isoOptions().ISOuntranslatedFilenames() ? "yes" : "no" );
747 optionsElem.appendChild( topElem );
748
749 topElem = doc.createElement( "follow_symbolic_links" );
750 topElem.setAttribute( "activated", isoOptions().followSymbolicLinks() ? "yes" : "no" );
751 optionsElem.appendChild( topElem );
752
753 topElem = doc.createElement( "create_trans_tbl" );
754 topElem.setAttribute( "activated", isoOptions().createTRANS_TBL() ? "yes" : "no" );
755 optionsElem.appendChild( topElem );
756
757 topElem = doc.createElement( "hide_trans_tbl" );
758 topElem.setAttribute( "activated", isoOptions().hideTRANS_TBL() ? "yes" : "no" );
759 optionsElem.appendChild( topElem );
760
761 topElem = doc.createElement( "iso_level" );
762 topElem.appendChild( doc.createTextNode( QString::number(isoOptions().ISOLevel()) ) );
763 optionsElem.appendChild( topElem );
764
765 topElem = doc.createElement( "discard_symlinks" );
766 topElem.setAttribute( "activated", isoOptions().discardSymlinks() ? "yes" : "no" );
767 optionsElem.appendChild( topElem );
768
769 topElem = doc.createElement( "discard_broken_symlinks" );
770 topElem.setAttribute( "activated", isoOptions().discardBrokenSymlinks() ? "yes" : "no" );
771 optionsElem.appendChild( topElem );
772
773 topElem = doc.createElement( "preserve_file_permissions" );
774 topElem.setAttribute( "activated", isoOptions().preserveFilePermissions() ? "yes" : "no" );
775 optionsElem.appendChild( topElem );
776
777 topElem = doc.createElement( "do_not_cache_inodes" );
778 topElem.setAttribute( "activated", isoOptions().doNotCacheInodes() ? "yes" : "no" );
779 optionsElem.appendChild( topElem );
780
781
782 topElem = doc.createElement( "whitespace_treatment" );
783 switch( isoOptions().whiteSpaceTreatment() ) {
784 case K3b::IsoOptions::strip:
785 topElem.appendChild( doc.createTextNode( "strip" ) );
786 break;
787 case K3b::IsoOptions::extended:
788 topElem.appendChild( doc.createTextNode( "extended" ) );
789 break;
790 case K3b::IsoOptions::replace:
791 topElem.appendChild( doc.createTextNode( "replace" ) );
792 break;
793 default:
794 topElem.appendChild( doc.createTextNode( "noChange" ) );
795 break;
796 }
797 optionsElem.appendChild( topElem );
798
799 topElem = doc.createElement( "whitespace_replace_string" );
800 topElem.appendChild( doc.createTextNode( isoOptions().whiteSpaceTreatmentReplaceString() ) );
801 optionsElem.appendChild( topElem );
802
803 topElem = doc.createElement( "data_track_mode" );
804 if( d->dataMode == K3b::DataMode1 )
805 topElem.appendChild( doc.createTextNode( "mode1" ) );
806 else if( d->dataMode == K3b::DataMode2 )
807 topElem.appendChild( doc.createTextNode( "mode2" ) );
808 else
809 topElem.appendChild( doc.createTextNode( "auto" ) );
810 optionsElem.appendChild( topElem );
811
812
813 // save multisession
814 topElem = doc.createElement( "multisession" );
815 switch( d->multisessionMode ) {
816 case START:
817 topElem.appendChild( doc.createTextNode( "start" ) );
818 break;
819 case CONTINUE:
820 topElem.appendChild( doc.createTextNode( "continue" ) );
821 break;
822 case FINISH:
823 topElem.appendChild( doc.createTextNode( "finish" ) );
824 break;
825 case NONE:
826 topElem.appendChild( doc.createTextNode( "none" ) );
827 break;
828 default:
829 topElem.appendChild( doc.createTextNode( "auto" ) );
830 break;
831 }
832 optionsElem.appendChild( topElem );
833
834 topElem = doc.createElement( "verify_data" );
835 topElem.setAttribute( "activated", verifyData() ? "yes" : "no" );
836 optionsElem.appendChild( topElem );
837 // ----------------------------------------------------------------------
838 }
839
840
saveDocumentDataHeader(QDomElement & headerElem)841 void K3b::DataDoc::saveDocumentDataHeader( QDomElement& headerElem )
842 {
843 QDomDocument doc = headerElem.ownerDocument();
844
845 QDomElement topElem = doc.createElement( "volume_id" );
846 topElem.appendChild( doc.createTextNode( isoOptions().volumeID() ) );
847 headerElem.appendChild( topElem );
848
849 topElem = doc.createElement( "volume_set_id" );
850 topElem.appendChild( doc.createTextNode( isoOptions().volumeSetId() ) );
851 headerElem.appendChild( topElem );
852
853 topElem = doc.createElement( "volume_set_size" );
854 topElem.appendChild( doc.createTextNode( QString::number(isoOptions().volumeSetSize()) ) );
855 headerElem.appendChild( topElem );
856
857 topElem = doc.createElement( "volume_set_number" );
858 topElem.appendChild( doc.createTextNode( QString::number(isoOptions().volumeSetNumber()) ) );
859 headerElem.appendChild( topElem );
860
861 topElem = doc.createElement( "system_id" );
862 topElem.appendChild( doc.createTextNode( isoOptions().systemId() ) );
863 headerElem.appendChild( topElem );
864
865 topElem = doc.createElement( "application_id" );
866 topElem.appendChild( doc.createTextNode( isoOptions().applicationID() ) );
867 headerElem.appendChild( topElem );
868
869 topElem = doc.createElement( "publisher" );
870 topElem.appendChild( doc.createTextNode( isoOptions().publisher() ) );
871 headerElem.appendChild( topElem );
872
873 topElem = doc.createElement( "preparer" );
874 topElem.appendChild( doc.createTextNode( isoOptions().preparer() ) );
875 headerElem.appendChild( topElem );
876 // ----------------------------------------------------------------------
877 }
878
879
saveDataItem(K3b::DataItem * item,QDomDocument * doc,QDomElement * parent)880 void K3b::DataDoc::saveDataItem( K3b::DataItem* item, QDomDocument* doc, QDomElement* parent )
881 {
882 if( K3b::FileItem* fileItem = dynamic_cast<K3b::FileItem*>( item ) ) {
883 if( d->oldSession.contains( fileItem ) ) {
884 qDebug() << "(K3b::DataDoc) ignoring fileitem " << fileItem->k3bName() << " from old session while saving...";
885 }
886 else {
887 QDomElement topElem = doc->createElement( "file" );
888 topElem.setAttribute( "name", fileItem->k3bName() );
889 QDomElement subElem = doc->createElement( "url" );
890 subElem.appendChild( doc->createTextNode( fileItem->localPath() ) );
891 topElem.appendChild( subElem );
892
893 if( item->sortWeight() != 0 )
894 topElem.setAttribute( "sort_weight", QString::number(item->sortWeight()) );
895
896 parent->appendChild( topElem );
897
898 // add boot options as attributes to preserve compatibility to older K3b versions
899 if( K3b::BootItem* bootItem = dynamic_cast<K3b::BootItem*>( fileItem ) ) {
900 if( bootItem->imageType() == K3b::BootItem::FLOPPY )
901 topElem.setAttribute( "bootimage", "floppy" );
902 else if( bootItem->imageType() == K3b::BootItem::HARDDISK )
903 topElem.setAttribute( "bootimage", "harddisk" );
904 else
905 topElem.setAttribute( "bootimage", "none" );
906
907 topElem.setAttribute( "no_boot", bootItem->noBoot() ? "yes" : "no" );
908 topElem.setAttribute( "boot_info_table", bootItem->bootInfoTable() ? "yes" : "no" );
909 topElem.setAttribute( "load_segment", QString::number( bootItem->loadSegment() ) );
910 topElem.setAttribute( "load_size", QString::number( bootItem->loadSize() ) );
911 }
912 }
913 }
914 else if( item == d->bootCataloge ) {
915 QDomElement topElem = doc->createElement( "special" );
916 topElem.setAttribute( "name", d->bootCataloge->k3bName() );
917 topElem.setAttribute( "type", "boot cataloge" );
918
919 parent->appendChild( topElem );
920 }
921 else if( K3b::DirItem* dirItem = dynamic_cast<K3b::DirItem*>( item ) ) {
922 QDomElement topElem = doc->createElement( "directory" );
923 topElem.setAttribute( "name", dirItem->k3bName() );
924
925 if( item->sortWeight() != 0 )
926 topElem.setAttribute( "sort_weight", QString::number(item->sortWeight()) );
927
928 Q_FOREACH( K3b::DataItem* item, dirItem->children() ) {
929 saveDataItem( item, doc, &topElem );
930 }
931
932 parent->appendChild( topElem );
933 }
934 }
935
936
removeItem(K3b::DataItem * item)937 void K3b::DataDoc::removeItem( K3b::DataItem* item )
938 {
939 if( !item )
940 return;
941
942 if( item->isRemoveable() ) {
943 delete item;
944 }
945 else
946 qDebug() << "(K3b::DataDoc) tried to remove non-removable entry!";
947 }
948
949
removeItems(K3b::DirItem * parent,int start,int count)950 void K3b::DataDoc::removeItems( K3b::DirItem* parent, int start, int count )
951 {
952 if( parent ) {
953 parent->removeDataItems( start, count );
954 }
955 }
956
957
beginInsertItems(DirItem * parent,int start,int end)958 void K3b::DataDoc::beginInsertItems( DirItem* parent, int start, int end )
959 {
960 emit itemsAboutToBeInserted( parent, start, end );
961 }
962
963
endInsertItems(DirItem * parent,int start,int end)964 void K3b::DataDoc::endInsertItems( DirItem* parent, int start, int end )
965 {
966 for( int i = start; i <= end; ++i ) {
967 DataItem* item = parent->children().at( i );
968 // update the project size
969 if( !item->isFromOldSession() )
970 d->sizeHandler->addFile( item );
971
972 // update the boot item list
973 if( item->isBootItem() )
974 d->bootImages.append( static_cast<K3b::BootItem*>( item ) );
975 }
976
977 emit itemsInserted( parent, start, end );
978 emit changed();
979 }
980
981
beginRemoveItems(DirItem * parent,int start,int end)982 void K3b::DataDoc::beginRemoveItems( DirItem* parent, int start, int end )
983 {
984 emit itemsAboutToBeRemoved( parent, start, end );
985
986 for( int i = start; i <= end; ++i ) {
987 DataItem* item = parent->children().at( i );
988 // update the project size
989 if( !item->isFromOldSession() )
990 d->sizeHandler->removeFile( item );
991
992 // update the boot item list
993 if( item->isBootItem() ) {
994 d->bootImages.removeAll( static_cast<K3b::BootItem*>( item ) );
995 if( d->bootImages.isEmpty() ) {
996 delete d->bootCataloge;
997 d->bootCataloge = 0;
998 }
999 }
1000 }
1001 }
1002
1003
endRemoveItems(DirItem * parent,int start,int end)1004 void K3b::DataDoc::endRemoveItems( DirItem* parent, int start, int end )
1005 {
1006 emit itemsRemoved( parent, start, end );
1007 emit changed();
1008 }
1009
1010
moveItem(K3b::DataItem * item,K3b::DirItem * newParent)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
moveItems(const QList<K3b::DataItem * > & itemList,K3b::DirItem * newParent)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
newBurnJob(K3b::JobHandler * hdl,QObject * parent)1048 K3b::BurnJob* K3b::DataDoc::newBurnJob( K3b::JobHandler* hdl, QObject* parent )
1049 {
1050 return new K3b::DataJob( this, hdl, parent );
1051 }
1052
1053
treatWhitespace(const QString & path)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
prepareFilenames()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
prepareFilenamesInDir(K3b::DirItem * dir)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
needToCutFilenames() const1182 bool K3b::DataDoc::needToCutFilenames() const
1183 {
1184 return d->needToCutFilenames;
1185 }
1186
1187
needToCutFilenameItems() const1188 QList<K3b::DataItem*> K3b::DataDoc::needToCutFilenameItems() const
1189 {
1190 return d->needToCutFilenameItems;
1191 }
1192
1193
informAboutNotFoundFiles()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
multiSessionMode() const1211 K3b::DataDoc::MultiSessionMode K3b::DataDoc::multiSessionMode() const
1212 {
1213 return d->multisessionMode;
1214 }
1215
1216
setMultiSessionMode(K3b::DataDoc::MultiSessionMode mode)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
dataMode() const1226 int K3b::DataDoc::dataMode() const
1227 {
1228 return d->dataMode;
1229 }
1230
1231
setDataMode(int m)1232 void K3b::DataDoc::setDataMode( int m )
1233 {
1234 d->dataMode = m;
1235 }
1236
1237
setVerifyData(bool b)1238 void K3b::DataDoc::setVerifyData( bool b )
1239 {
1240 d->verifyData = b;
1241 }
1242
1243
verifyData() const1244 bool K3b::DataDoc::verifyData() const
1245 {
1246 return d->verifyData;
1247 }
1248
1249
importSession(K3b::Device::Device * device,int session)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
createSessionImportItems(const K3b::Iso9660Directory * importDir,K3b::DirItem * parent)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
clearImportedSession()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
bootImages()1425 QList<K3b::BootItem*> K3b::DataDoc::bootImages()
1426 {
1427 return d->bootImages;
1428 }
1429
1430
bootCataloge()1431 K3b::DataItem* K3b::DataDoc::bootCataloge()
1432 {
1433 return d->bootCataloge;
1434 }
1435
1436
bootImageDir()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
createBootItem(const QString & filename,K3b::DirItem * dir)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
createBootCatalogeItem(K3b::DirItem * dir)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
findItemByLocalPath(const QString & path) const1495 QList<K3b::DataItem*> K3b::DataDoc::findItemByLocalPath( const QString& path ) const
1496 {
1497 Q_UNUSED( path );
1498 return QList<K3b::DataItem*>();
1499 }
1500
1501
importedSession() const1502 int K3b::DataDoc::importedSession() const
1503 {
1504 return ( d->oldSession.isEmpty() ? -1 : d->importedSession );
1505 }
1506
1507
supportedMediaTypes() const1508 K3b::Device::MediaTypes K3b::DataDoc::supportedMediaTypes() const
1509 {
1510 return Device::MEDIA_WRITABLE;
1511 }
1512
1513
root() const1514 K3b::RootItem* K3b::DataDoc::root() const
1515 {
1516 return d->root;
1517 }
1518
1519
1520