File indexing completed on 2024-05-12 04:51:11

0001 /*
0002     SPDX-FileCopyrightText: 2003-2004 Christian Kvasny <chris@k3b.org>
0003     THX to Manfred Odenstein <odix@chello.at>
0004     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "k3bvcdxmlview.h"
0010 #include "k3bvcdtrack.h"
0011 #include "k3bcore.h"
0012 #include "k3bversion.h"
0013 
0014 #include <QDebug>
0015 #include <QDir>
0016 #include <QStandardPaths>
0017 #include <QTextStream>
0018 #include <QDomDocument>
0019 #include <QDomElement>
0020 
0021 
0022 class K3b::VcdXmlView::Private
0023 {
0024 public:
0025     void addComment( QDomDocument& doc, QDomElement& parent, const QString& text );
0026     QDomElement addSubElement( QDomDocument&, QDomElement&, const QString& name, const QString& value = QString() );
0027     QDomElement addSubElement( QDomDocument&, QDomElement&, const QString& name, const int& value );
0028 
0029     QDomElement addFolderElement( QDomDocument&, QDomElement&, const QString& name );
0030     void addFileElement( QDomDocument&, QDomElement&, const QString& src, const QString& name, bool mixed = false );
0031     void doPbc( QDomDocument&, QDomElement&, VcdTrack* );
0032     void setNumkeyBSN( QDomDocument& , QDomElement&, VcdTrack* );
0033     void setNumkeySEL( QDomDocument& , QDomElement&, VcdTrack* );
0034     
0035     VcdDoc* doc;
0036     QString xmlstring;
0037     int startkey;
0038 };
0039 
0040 void K3b::VcdXmlView::Private::addComment( QDomDocument& doc, QDomElement& parent, const QString& text )
0041 {
0042     QDomComment comment = doc.createComment( text );
0043     parent.appendChild( comment );
0044 }
0045 
0046 QDomElement K3b::VcdXmlView::Private::addSubElement( QDomDocument& doc, QDomElement& parent, const QString& name, const QString& value )
0047 {
0048     QDomElement element = doc.createElement( name );
0049     parent.appendChild( element );
0050     if ( !value.isNull() ) {
0051         QDomText t = doc.createTextNode( value );
0052         element.appendChild( t );
0053     }
0054     return element;
0055 }
0056 
0057 QDomElement K3b::VcdXmlView::Private::addSubElement( QDomDocument& doc, QDomElement& parent, const QString& name, const int& value )
0058 {
0059     QDomElement element = doc.createElement( name );
0060     parent.appendChild( element );
0061     if ( value >= -1 ) {
0062         QDomText t = doc.createTextNode( QString( "%1" ).arg( value ) );
0063         element.appendChild( t );
0064     }
0065     return element;
0066 }
0067 
0068 QDomElement K3b::VcdXmlView::Private::addFolderElement( QDomDocument& doc, QDomElement& parent, const QString& name )
0069 {
0070     QDomElement elemFolder = addSubElement( doc, parent, "folder" );
0071     addSubElement( doc, elemFolder, "name", name );
0072 
0073     return elemFolder;
0074 }
0075 
0076 void K3b::VcdXmlView::Private::addFileElement( QDomDocument& doc, QDomElement& parent, const QString& src, const QString& name, bool mixed )
0077 {
0078     QDomElement elemFile = addSubElement( doc, parent, "file" );
0079     elemFile.setAttribute( "src", QString( "%1" ).arg( src ) );
0080     if ( mixed )
0081         elemFile.setAttribute( "format", "mixed" );
0082 
0083     addSubElement( doc, elemFile, "name", name );
0084 }
0085 
0086 void K3b::VcdXmlView::Private::doPbc( QDomDocument& doc, QDomElement& parent, K3b::VcdTrack* track )
0087 {
0088     QString ref = ( track->isSegment() ) ? "segment" : "sequence";
0089 
0090     QDomElement elemSelection = addSubElement( doc, parent, "selection" );
0091     elemSelection.setAttribute( "id", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( track->index() ).rightJustified( 3, '0' ) ) );
0092 
0093     setNumkeyBSN( doc, elemSelection, track );
0094 
0095     Q_FOREACH( VcdTrack::PbcTracks pbc, VcdTrack::trackPlaybackValues() ) {
0096         QDomElement elemPbcSelectionPNRDT;
0097 
0098         if ( track->getPbcTrack( pbc ) ) {
0099             int index = track->getPbcTrack( pbc ) ->index();
0100             QString ref = ( track->getPbcTrack( pbc ) ->isSegment() ) ? "segment" : "sequence";
0101 
0102             switch ( pbc ) {
0103             case K3b::VcdTrack::PREVIOUS:
0104                 elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "prev" );
0105                 elemPbcSelectionPNRDT.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( index ).rightJustified( 3, '0' ) ) );
0106                 break;
0107             case K3b::VcdTrack::NEXT:
0108                 elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "next" );
0109                 elemPbcSelectionPNRDT.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( index ).rightJustified( 3, '0' ) ) );
0110                 break;
0111             case K3b::VcdTrack::RETURN:
0112                 elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "return" );
0113                 elemPbcSelectionPNRDT.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( index ).rightJustified( 3, '0' ) ) );
0114                 break;
0115             case K3b::VcdTrack::DEFAULT:
0116                 elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "default" );
0117                 elemPbcSelectionPNRDT.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( index ).rightJustified( 3, '0' ) ) );
0118                 break;
0119             case K3b::VcdTrack::AFTERTIMEOUT:
0120                 if ( track->getWaitTime() >= 0 ) {
0121                     elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "timeout" );
0122                     elemPbcSelectionPNRDT.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( index ).rightJustified( 3, '0' ) ) );
0123                 }
0124                 break;
0125             }
0126         } else {
0127             // jump to <endlist> otherwise do noop while disabled
0128             if ( track->getNonPbcTrack( pbc ) == K3b::VcdTrack::VIDEOEND ) {
0129                 switch ( pbc ) {
0130                 case K3b::VcdTrack::PREVIOUS:
0131                     elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "prev" );
0132                     elemPbcSelectionPNRDT.setAttribute( "ref", "end" );
0133                     break;
0134                 case K3b::VcdTrack::NEXT:
0135                     elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "next" );
0136                     elemPbcSelectionPNRDT.setAttribute( "ref", "end" );
0137                     break;
0138                 case K3b::VcdTrack::RETURN:
0139                     elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "return" );
0140                     elemPbcSelectionPNRDT.setAttribute( "ref", "end" );
0141                     break;
0142                 case K3b::VcdTrack::DEFAULT:
0143                     elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "default" );
0144                     elemPbcSelectionPNRDT.setAttribute( "ref", "end" );
0145                     break;
0146                 case K3b::VcdTrack::AFTERTIMEOUT:
0147                     if ( track->getWaitTime() >= 0 ) {
0148                         elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "timeout" );
0149                         elemPbcSelectionPNRDT.setAttribute( "ref", "end" );
0150                     }
0151                     break;
0152                 }
0153             }
0154         }
0155     }
0156 
0157     addSubElement( doc, elemSelection, "wait", track->getWaitTime() );
0158     QDomElement loop = addSubElement( doc, elemSelection, "loop", track->getPlayTime() );
0159     if ( track->Reactivity() )
0160         loop.setAttribute( "jump-timing", "delayed" );
0161     else
0162         loop.setAttribute( "jump-timing", "immediate" );
0163 
0164     addSubElement( doc, elemSelection, "play-item" ).setAttribute( "ref", QString( "%1-%2" ).arg( ref ).arg( QString::number( track->index() ).rightJustified( 3, '0' ) ) );
0165 
0166     setNumkeySEL( doc, elemSelection, track );
0167 }
0168 
0169 void K3b::VcdXmlView::Private::setNumkeyBSN( QDomDocument& doc, QDomElement& parent, K3b::VcdTrack* track )
0170 {
0171     if ( track->PbcNumKeys() ) {
0172         if ( track->PbcNumKeysUserdefined() ) {
0173             QMap<int, K3b::VcdTrack*> numKeyMap = track->DefinedNumKey();
0174             QMap<int, K3b::VcdTrack*>::const_iterator trackIt;
0175 
0176             startkey = 0;
0177             trackIt = numKeyMap.constBegin();
0178             if ( trackIt != numKeyMap.constEnd() )
0179                 startkey = trackIt.key();
0180 
0181             if ( startkey > 0 )
0182                 addSubElement( doc, parent, "bsn", startkey );
0183             else // user has no numKeys defined for this track
0184                 track->setPbcNumKeys( false );
0185 
0186         } else {
0187             // default start with key #1
0188             addSubElement( doc, parent, "bsn", 1 );
0189         }
0190     }
0191 }
0192 
0193 void K3b::VcdXmlView::Private::setNumkeySEL( QDomDocument& doc, QDomElement& parent, K3b::VcdTrack* track )
0194 {
0195     if ( track->PbcNumKeys() ) {
0196         QDomElement elemPbcSelectionNumKeySEL;
0197         QString ref = ( track->isSegment() ) ? "segment" : "sequence";
0198         int none = startkey;
0199         if ( track->PbcNumKeysUserdefined() ) {
0200             QMap<int, K3b::VcdTrack*> numKeyMap = track->DefinedNumKey();
0201             QMap<int, K3b::VcdTrack*>::const_iterator trackIt;
0202 
0203             for ( trackIt = numKeyMap.constBegin(); trackIt != numKeyMap.constEnd(); ++trackIt ) {
0204 
0205                 qDebug() << QString( "trackIt key: %1 none: %2" ).arg( trackIt.key() ).arg( none );
0206                 while ( none < trackIt.key() ) {
0207                     elemPbcSelectionNumKeySEL = addSubElement( doc, parent, "select" );
0208                     elemPbcSelectionNumKeySEL.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( track->index() ).rightJustified( 3, '0' ) ) );
0209                     addComment( doc, parent, QString( "key %1 -> %2 (normal none)" ).arg( none ).arg( track->absolutePath() ) );
0210                     none++;
0211                 }
0212 
0213                 if ( trackIt.value() ) {
0214                     QString ref = ( trackIt.value() ->isSegment() ) ? "segment" : "sequence";
0215                     elemPbcSelectionNumKeySEL = addSubElement( doc, parent, "select" );
0216                     elemPbcSelectionNumKeySEL.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( trackIt.value() ->index() ).rightJustified( 3, '0' ) ) );
0217                     addComment( doc, parent, QString( "key %1 -> %2" ).arg( trackIt.key() ).arg( trackIt.value() ->absolutePath() ) );
0218                 } else {
0219                     elemPbcSelectionNumKeySEL = addSubElement( doc, parent, "select" );
0220                     elemPbcSelectionNumKeySEL.setAttribute( "ref", "end" );
0221                     addComment( doc, parent, QString( "key %1 -> end" ).arg( trackIt.key() ) );
0222                 }
0223                 none++;
0224             }
0225         } else {
0226             // default reference to itSelf
0227             elemPbcSelectionNumKeySEL = addSubElement( doc, parent, "select" );
0228             elemPbcSelectionNumKeySEL.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( track->index() ).rightJustified( 3, '0' ) ) );
0229         }
0230     }
0231 }
0232 
0233 K3b::VcdXmlView::VcdXmlView( K3b::VcdDoc* pDoc )
0234     : d( new Private )
0235 {
0236     d->doc = pDoc;
0237 }
0238 
0239 K3b::VcdXmlView::~VcdXmlView()
0240 {
0241     delete d;
0242 }
0243 
0244 void K3b::VcdXmlView::write( QFile& file )
0245 {
0246 
0247     QDomDocument xmlDoc( "videocd PUBLIC \"-//GNU//DTD VideoCD//EN\" \"http://www.gnu.org/software/vcdimager/videocd.dtd\"" );
0248     // xmlDoc.appendChild( xmlDoc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"iso-8859-1\"" ) );
0249     xmlDoc.appendChild( xmlDoc.createProcessingInstruction( "xml", "version=\"1.0\"" ) );
0250 
0251     // create root element
0252     QDomElement root = xmlDoc.createElement( "videocd" );
0253     root.setAttribute( "xmlns", "http://www.gnu.org/software/vcdimager/1.0/" );
0254     root.setAttribute( "class", d->doc->vcdOptions() ->vcdClass() );
0255     root.setAttribute( "version", d->doc->vcdOptions() ->vcdVersion() );
0256     xmlDoc.appendChild( root );
0257 
0258     // create option elements
0259 
0260     // Broken SVCD mode - NonCompliantMode
0261     if ( d->doc->vcdOptions() ->NonCompliantMode() ) {
0262         QDomElement elemOption;
0263         elemOption = d->addSubElement( xmlDoc, root, "option" );
0264         elemOption.setAttribute( "name", "svcd vcd30 mpegav" );
0265         elemOption.setAttribute( "value", "true" );
0266 
0267         elemOption = d->addSubElement( xmlDoc, root, "option" );
0268         elemOption.setAttribute( "name", "svcd vcd30 entrysvd" );
0269         elemOption.setAttribute( "value", "true" );
0270     }
0271 
0272     // VCD3.0 track interpretation
0273     if ( d->doc->vcdOptions() ->VCD30interpretation() ) {
0274         QDomElement elemOption;
0275         elemOption = d->addSubElement( xmlDoc, root, "option" );
0276         elemOption.setAttribute( "name", "svcd vcd30 tracksvd" );
0277         elemOption.setAttribute( "value", "true" );
0278     }
0279 
0280     // Relaxed aps
0281     if ( d->doc->vcdOptions() ->RelaxedAps() ) {
0282         QDomElement elemOption;
0283         elemOption = d->addSubElement( xmlDoc, root, "option" );
0284         elemOption.setAttribute( "name", "relaxed aps" );
0285         elemOption.setAttribute( "value", "true" );
0286     }
0287 
0288     // Update scan offsets
0289     if ( d->doc->vcdOptions() ->UpdateScanOffsets() ) {
0290         QDomElement elemOption;
0291         elemOption = d->addSubElement( xmlDoc, root, "option" );
0292         elemOption.setAttribute( "name", "update scan offsets" );
0293         elemOption.setAttribute( "value", "true" );
0294 
0295     }
0296 
0297     // Gaps & Margins
0298     if ( d->doc->vcdOptions() ->UseGaps() ) {
0299         QDomElement elemOption;
0300         elemOption = d->addSubElement( xmlDoc, root, "option" );
0301         elemOption.setAttribute( "name", "leadout pregap" );
0302         elemOption.setAttribute( "value", d->doc->vcdOptions() ->PreGapLeadout() );
0303 
0304         elemOption = d->addSubElement( xmlDoc, root, "option" );
0305         elemOption.setAttribute( "name", "track pregap" );
0306         elemOption.setAttribute( "value", d->doc->vcdOptions() ->PreGapTrack() );
0307 
0308         if ( d->doc->vcdOptions() ->vcdClass() == "vcd" ) {
0309             elemOption = d->addSubElement( xmlDoc, root, "option" );
0310             elemOption.setAttribute( "name", "track front margin" );
0311             elemOption.setAttribute( "value", d->doc->vcdOptions() ->FrontMarginTrack() );
0312 
0313             elemOption = d->addSubElement( xmlDoc, root, "option" );
0314             elemOption.setAttribute( "name", "track rear margin" );
0315             elemOption.setAttribute( "value", d->doc->vcdOptions() ->RearMarginTrack() );
0316         } else {
0317             elemOption = d->addSubElement( xmlDoc, root, "option" );
0318             elemOption.setAttribute( "name", "track front margin" );
0319             elemOption.setAttribute( "value", d->doc->vcdOptions() ->FrontMarginTrackSVCD() );
0320 
0321             elemOption = d->addSubElement( xmlDoc, root, "option" );
0322             elemOption.setAttribute( "name", "track rear margin" );
0323             elemOption.setAttribute( "value", d->doc->vcdOptions() ->RearMarginTrackSVCD() );
0324         }
0325 
0326     }
0327 
0328     // create info element
0329     QDomElement elemInfo = d->addSubElement( xmlDoc, root, "info" );
0330     d->addSubElement( xmlDoc, elemInfo, "album-id", d->doc->vcdOptions() ->albumId().toUpper() );
0331     d->addSubElement( xmlDoc, elemInfo, "volume-count", d->doc->vcdOptions() ->volumeCount() );
0332     d->addSubElement( xmlDoc, elemInfo, "volume-number", d->doc->vcdOptions() ->volumeNumber() );
0333     d->addSubElement( xmlDoc, elemInfo, "restriction", d->doc->vcdOptions() ->Restriction() );
0334 
0335     // create pvd element
0336     QDomElement elemPvd = d->addSubElement( xmlDoc, root, "pvd" );
0337     d->addSubElement( xmlDoc, elemPvd, "volume-id", d->doc->vcdOptions() ->volumeId().toUpper() );
0338     d->addSubElement( xmlDoc, elemPvd, "system-id", d->doc->vcdOptions() ->systemId() );
0339     d->addSubElement( xmlDoc, elemPvd, "application-id", d->doc->vcdOptions() ->applicationId() );
0340     d->addSubElement( xmlDoc, elemPvd, "preparer-id", QString( "K3b - Version %1" ).arg( k3bcore->version() ).toUpper() );
0341     d->addSubElement( xmlDoc, elemPvd, "publisher-id", d->doc->vcdOptions() ->publisher().toUpper() );
0342 
0343 
0344     // create filesystem element
0345     QDomElement elemFileSystem = d->addSubElement( xmlDoc, root, "filesystem" );
0346 
0347     // SEGMENT folder, some standalone DVD-Player need this
0348     if ( !d->doc->vcdOptions() ->haveSegments() && d->doc->vcdOptions() ->SegmentFolder() )
0349         d->addFolderElement( xmlDoc, elemFileSystem, "SEGMENT" );
0350 
0351     // create cdi element
0352     if ( d->doc->vcdOptions() ->CdiSupport() ) {
0353         QDomElement elemFolder = d->addFolderElement( xmlDoc, elemFileSystem, "CDI" );
0354 
0355         d->addFileElement( xmlDoc, elemFolder, QStandardPaths::locate( QStandardPaths::GenericDataLocation, "k3b/cdi/cdi_imag.rtf" ), "CDI_IMAG.RTF", true );
0356         d->addFileElement( xmlDoc, elemFolder, QStandardPaths::locate( QStandardPaths::GenericDataLocation, "k3b/cdi/cdi_text.fnt" ), "CDI_TEXT.FNT" );
0357         d->addFileElement( xmlDoc, elemFolder, QStandardPaths::locate( QStandardPaths::GenericDataLocation, "k3b/cdi/cdi_vcd.app" ), "CDI_VCD.APP" );
0358 
0359         QString dirPath = QStandardPaths::writableLocation( QStandardPaths::AppDataLocation ) + "/cdi";
0360         QDir().mkpath(dirPath);
0361         QString usercdicfg = dirPath + "cdi_vcd.cfg";
0362         if ( QFile::exists( usercdicfg ) )
0363             d->addFileElement( xmlDoc, elemFolder, usercdicfg, "CDI_VCD.CFG" );
0364         else
0365             d->addFileElement( xmlDoc, elemFolder, QStandardPaths::locate( QStandardPaths::GenericDataLocation, "k3b/cdi/cdi_vcd.cfg" ), "CDI_VCD.CFG" );
0366     }
0367 
0368     // sequence-items element & segment-items element
0369     QDomElement elemsequenceItems;
0370     QDomElement elemsegmentItems;
0371 
0372     // sequence-item element & segment-item element
0373     QDomElement elemsequenceItem;
0374     QDomElement elemsegmentItem;
0375 
0376     // if we have segments, elemsegmentItems must be before any sequence in xml file order
0377     if ( d->doc->vcdOptions()->haveSegments()  )
0378         elemsegmentItems = d->addSubElement( xmlDoc, root, "segment-items" );
0379 
0380     // sequence must always available ...
0381     elemsequenceItems = d->addSubElement( xmlDoc, root, "sequence-items" );
0382     // if we have no sequence (photo (s)vcd) we must add a dummy sequence they inform the user to turn on pbc on there videoplayer
0383     if ( !d->doc->vcdOptions()->haveSequence() )  {
0384         QString filename;
0385         if  ( d->doc->vcdOptions()->mpegVersion() == 1 )
0386             filename = QStandardPaths::locate( QStandardPaths::GenericDataLocation, "k3b/extra/k3bphotovcd.mpg" );
0387         else
0388             filename = QStandardPaths::locate( QStandardPaths::GenericDataLocation, "k3b/extra/k3bphotosvcd.mpg" );
0389 
0390         elemsequenceItem = d->addSubElement( xmlDoc, elemsequenceItems, "sequence-item" );
0391         elemsequenceItem.setAttribute( "src", filename );
0392         elemsequenceItem.setAttribute( "id", "sequence-000"  );
0393         // default entry
0394         QDomElement elemdefaultEntry;
0395         elemdefaultEntry = d->addSubElement( xmlDoc, elemsequenceItem, "default-entry" );
0396         elemdefaultEntry.setAttribute( "id", "entry-000"  );
0397     }
0398 
0399 
0400     // pbc
0401     QDomElement elemPbc;
0402 
0403     // Add Tracks to XML
0404     Q_FOREACH( K3b::VcdTrack* track,  *d->doc->tracks() ) {
0405         if ( !track ->isSegment() ) {
0406             QString seqId = QString::number( track ->index() ).rightJustified( 3, '0' );
0407 
0408             elemsequenceItem = d->addSubElement( xmlDoc, elemsequenceItems, "sequence-item" );
0409             elemsequenceItem.setAttribute( "src", track ->absolutePath() );
0410             elemsequenceItem.setAttribute( "id", QString( "sequence-%1" ).arg( seqId ) );
0411 
0412             // default entry
0413             QDomElement elemdefaultEntry;
0414             elemdefaultEntry = d->addSubElement( xmlDoc, elemsequenceItem, "default-entry" );
0415             elemdefaultEntry.setAttribute( "id", QString( "entry-%1" ).arg( seqId ) );
0416 
0417         } else {
0418             // sequence-items element needs at least one segment to fit the XML
0419             elemsegmentItem = d->addSubElement( xmlDoc, elemsegmentItems, "segment-item" );
0420             elemsegmentItem.setAttribute( "src", track ->absolutePath() );
0421             elemsegmentItem.setAttribute( "id", QString( "segment-%1" ).arg( QString::number( track ->index() ).rightJustified( 3, '0' ) ) );
0422 
0423         }
0424     }
0425     Q_FOREACH( K3b::VcdTrack* track,  *d->doc->tracks() ) {
0426         if ( d->doc->vcdOptions() ->PbcEnabled() ) {
0427             if ( elemPbc.isNull() )
0428                 elemPbc = d->addSubElement( xmlDoc, root, "pbc" );
0429 
0430             d->doPbc( xmlDoc, elemPbc, track );
0431         }
0432     }
0433 
0434     if ( ! elemPbc.isNull() ) {
0435         QDomElement elemEndlist = d->addSubElement( xmlDoc, elemPbc, "endlist" );
0436         elemEndlist.setAttribute( "id", "end" );
0437         elemEndlist.setAttribute( "rejected", "true" );
0438     }
0439 
0440     d->xmlstring = xmlDoc.toString();
0441     
0442     QTextStream ts( &file );
0443     ts << d->xmlstring;
0444 }
0445 
0446 const QString& K3b::VcdXmlView::xmlString() const
0447 {
0448     return d->xmlstring;
0449 }