File indexing completed on 2024-04-28 04:49:51

0001 /*
0002     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include <config-k3b.h>
0008 #include "k3bglobals.h"
0009 
0010 #include "k3biso9660.h"
0011 #include "k3biso9660backend.h"
0012 
0013 #include "k3bdevice.h"
0014 
0015 #include "libisofs/isofs.h"
0016 
0017 #include <QDebug>
0018 #include <QDir>
0019 #include <QFile>
0020 
0021 
0022 /* callback function for libisofs */
0023 int K3b::Iso9660::read_callback( char* buf, sector_t start, int len, void* udata )
0024 {
0025     K3b::Iso9660* isoF = static_cast<K3b::Iso9660*>(udata);
0026 
0027     return isoF->read( start, buf, len );
0028 }
0029 
0030 /* callback function for libisofs */
0031 int K3b::Iso9660::isofs_callback( struct iso_directory_record *idr, void *udata )
0032 {
0033     K3b::Iso9660 *iso = static_cast<K3b::Iso9660*> (udata);
0034     QString path, isoPath,user,group,symlink;
0035     int i;
0036     int access;
0037     int time,cdate,adate;
0038     rr_entry rr;
0039     bool special=false;
0040     K3b::Iso9660Entry *entry=0;
0041     //K3b::Iso9660Entry *oldentry=0;
0042     char z_algo[2],z_params[2];
0043     int z_size=0;
0044 
0045     if (isonum_711(idr->name_len)==1) {
0046         switch (idr->name[0]) {
0047         case 0:
0048             path+=(".");
0049             special=true;
0050             break;
0051         case 1:
0052             path+=("..");
0053             special=true;
0054             break;
0055         }
0056     }
0057     //
0058     // First extract the raw iso9660 name
0059     //
0060     if( !special ) {
0061         for( i = 0; i < isonum_711( idr->name_len ); ++i ) {
0062             if( idr->name[i] )
0063                 isoPath += idr->name[i];
0064         }
0065     }
0066     else
0067         isoPath = path;
0068 
0069     //
0070     // Now see if we have RockRidge
0071     //
0072     if( !iso->plainIso9660() && ParseRR(idr,&rr) > 0 ) {
0073         iso->m_rr = true;
0074         if (!special)
0075             path = QString::fromLocal8Bit( rr.name );
0076         symlink=rr.sl;
0077         access=rr.mode;
0078         time=0;//rr.st_mtime;
0079         adate=0;//rr.st_atime;
0080         cdate=0;//rr.st_ctime;
0081         user.setNum(rr.uid);
0082         group.setNum(rr.gid);
0083         z_algo[0]=rr.z_algo[0];z_algo[1]=rr.z_algo[1];
0084         z_params[0]=rr.z_params[0];z_params[1]=rr.z_params[1];
0085         z_size=rr.z_size;
0086     }
0087     else {
0088         access=iso->dirent->permissions() & ~S_IFMT;
0089         adate=cdate=time=isodate_915(idr->date,0);
0090         user=iso->dirent->user();
0091         group=iso->dirent->group();
0092         if (idr->flags[0] & 2) access |= S_IFDIR; else access |= S_IFREG;
0093         if (!special) {
0094             if( !iso->plainIso9660() && iso->jolietLevel() ) {
0095                 for (i=0;i<(isonum_711(idr->name_len)-1);i+=2) {
0096                     QChar ch( be2me_16(*((ushort*)&(idr->name[i]))) );
0097                     if (ch==';') break;
0098                     path+=ch;
0099                 }
0100             }
0101             else {
0102                 // no RR, no Joliet, just plain iso9660
0103                 path = isoPath;
0104 
0105                 // remove the version field
0106                 int pos = path.indexOf( ';' );
0107                 if( pos > 0 )
0108                     path.truncate( pos );
0109             }
0110             if (path.endsWith('.')) path.truncate(path.length()-1);
0111         }
0112     }
0113 
0114     if( !iso->plainIso9660() )
0115         FreeRR(&rr);
0116 
0117     if (idr->flags[0] & 2) {
0118         entry = new K3b::Iso9660Directory( iso, isoPath, path, access | S_IFDIR, time, adate, cdate,
0119                                          user, group, symlink,
0120                                          special ? 0 : isonum_733(idr->extent),
0121                                          special ? 0 : isonum_733(idr->size) );
0122     }
0123     else {
0124         entry = new K3b::Iso9660File( iso, isoPath, path, access, time, adate, cdate,
0125                                     user, group, symlink, isonum_733(idr->extent), isonum_733(idr->size) );
0126         if (z_size)
0127             (static_cast<K3b::Iso9660File*>(entry))->setZF( z_algo, z_params, z_size );
0128     }
0129     iso->dirent->addEntry(entry);
0130 
0131     return 0;
0132 }
0133 
0134 
0135 
0136 K3b::Iso9660Entry::Iso9660Entry( K3b::Iso9660* archive,
0137                                   const QString& isoName,
0138                                   const QString& name,
0139                                   int access,
0140                                   int date,
0141                                   int adate,
0142                                   int cdate,
0143                                   const QString& user,
0144                                   const QString& group,
0145                                   const QString& symlink )
0146     : m_adate( adate ),
0147       m_cdate( cdate ),
0148       m_name( name ),
0149       m_isoName( isoName ),
0150       m_date( date ),
0151       m_access( access ),
0152       m_user( user ),
0153       m_group( group ),
0154       m_symlink( symlink ),
0155       m_archive( archive )
0156 {
0157 }
0158 
0159 
0160 K3b::Iso9660Entry::~Iso9660Entry()
0161 {
0162 }
0163 
0164 
0165 
0166 
0167 
0168 
0169 K3b::Iso9660File::Iso9660File( K3b::Iso9660* archive,
0170                                 const QString& isoName,
0171                                 const QString& name,
0172                                 int access,
0173                                 int date,
0174                                 int adate,
0175                                 int cdate,
0176                                 const QString& user,
0177                                 const QString& group,
0178                                 const QString& symlink,
0179                                 unsigned int pos,
0180                                 unsigned int size )
0181     : K3b::Iso9660Entry( archive, isoName, name, access, date, adate, cdate, user, group, symlink ),
0182       m_startSector(pos),
0183       m_size(size)
0184 {
0185     m_algo[0] = 0;
0186     m_algo[1] = 0;
0187     m_parms[0] = 0;
0188     m_parms[1] = 0;
0189     m_realsize = 0;
0190 }
0191 
0192 K3b::Iso9660File::~Iso9660File()
0193 {
0194 }
0195 
0196 void K3b::Iso9660File::setZF(char algo[2],char parms[2],int realsize)
0197 {
0198     m_algo[0]=algo[0];m_algo[1]=algo[1];
0199     m_parms[0]=parms[0];m_parms[1]=parms[1];
0200     m_realsize=realsize;
0201 }
0202 
0203 
0204 int K3b::Iso9660File::read( unsigned int pos, char* data, int maxlen ) const
0205 {
0206     if( pos >= size() )
0207         return 0;
0208 
0209     unsigned long startSec = m_startSector + pos/2048;
0210     int startSecOffset = pos%2048;
0211     char* buffer = data;
0212     bool buffered = false;
0213     unsigned long bufferLen = maxlen+startSecOffset;
0214 
0215     // cut to size
0216     if( pos + maxlen > size() )
0217         bufferLen = size() - pos + startSecOffset;
0218 
0219     // pad to 2048
0220     if( bufferLen%2048 )
0221         bufferLen += (2048-(bufferLen%2048));
0222 
0223     // we need to buffer if we changed the startSec or need a bigger buffer
0224     if( startSecOffset || bufferLen > (unsigned int)maxlen ) {
0225         buffered = true;
0226         buffer = new char[bufferLen];
0227     }
0228 
0229     int read = archive()->read( startSec, buffer, bufferLen/2048 )*2048;
0230 
0231     if( buffered ) {
0232         if( read > 0 ) {
0233             // cut to requested data
0234             read -= startSecOffset;
0235             if( read + pos > size() )
0236                 read = size() - pos;
0237             if( read > maxlen )
0238                 read = maxlen;
0239 
0240             ::memcpy( data, buffer+startSecOffset, read );
0241         }
0242         delete [] buffer;
0243 
0244         return read;
0245     }
0246     else {
0247         // cut read data
0248         if( read + pos > size() )
0249             read = size() - pos;
0250 
0251         return read;
0252     }
0253 }
0254 
0255 
0256 bool K3b::Iso9660File::copyTo( const QString& url ) const
0257 {
0258     QFile of( url );
0259     if( of.open( QIODevice::WriteOnly ) ) {
0260         char buffer[2048*10];
0261         unsigned int pos = 0;
0262         int r = 0;
0263         while( ( r = read( pos, buffer, 2048*10 ) ) > 0 ) {
0264             of.write( buffer, r );
0265             pos += r;
0266         }
0267 
0268         return !r;
0269     }
0270     else {
0271         qDebug() << "(K3b::Iso9660File) could not open " << url << " for writing.";
0272         return false;
0273     }
0274 }
0275 
0276 
0277 K3b::Iso9660Directory::Iso9660Directory( K3b::Iso9660* archive,
0278                                           const QString& isoName,
0279                                           const QString& name,
0280                                           int access,
0281                                           int date,
0282                                           int adate,
0283                                           int cdate,
0284                                           const QString& user,
0285                                           const QString& group,
0286                                           const QString& symlink,
0287                                           unsigned int pos,
0288                                           unsigned int size  )
0289     : K3b::Iso9660Entry( archive, isoName, name, access, date, adate, cdate, user, group, symlink ),
0290       m_bExpanded( size == 0 ), // we can only expand entries that represent an actual directory
0291       m_startSector(pos),
0292       m_size(size)
0293 {
0294 }
0295 
0296 K3b::Iso9660Directory::~Iso9660Directory()
0297 {
0298     qDeleteAll( m_entries );
0299 }
0300 
0301 
0302 void K3b::Iso9660Directory::expand()
0303 {
0304     if( !m_bExpanded ) {
0305         archive()->dirent = this;
0306         if( ProcessDir( &K3b::Iso9660::read_callback, m_startSector, m_size, &K3b::Iso9660::isofs_callback, archive() ) )
0307             qDebug() << "(K3b::Iso9660) failed to expand dir: " << name() << " with size: " << m_size;
0308 
0309         m_bExpanded = true;
0310     }
0311 }
0312 
0313 
0314 QStringList K3b::Iso9660Directory::entries() const
0315 {
0316     // create a fake const method to fool the user ;)
0317     const_cast<K3b::Iso9660Directory*>(this)->expand();
0318 
0319     QStringList l;
0320 
0321     QHashIterator<QString, K3b::Iso9660Entry*> it( m_entries );
0322     while ( it.hasNext() ) {
0323         it.next();
0324         l.append( it.key() );
0325     }
0326 
0327     return l;
0328 }
0329 
0330 
0331 QStringList K3b::Iso9660Directory::iso9660Entries() const
0332 {
0333     // create a fake const method to fool the user ;)
0334     const_cast<K3b::Iso9660Directory*>(this)->expand();
0335 
0336     QStringList l;
0337 
0338     QHashIterator<QString, K3b::Iso9660Entry*> it( m_iso9660Entries );
0339     while ( it.hasNext() ) {
0340         it.next();
0341         l.append( it.key() );
0342     }
0343 
0344     return l;
0345 }
0346 
0347 
0348 K3b::Iso9660Entry* K3b::Iso9660Directory::entry( const QString& n )
0349 {
0350     if( n.isEmpty() )
0351         return 0;
0352 
0353     expand();
0354 
0355     QString name(n);
0356 
0357     // trailing slash ? -> remove
0358     if( name.length() > 1 && name[name.length()-1] == '/' ) {
0359         name.truncate( name.length()-1 );
0360     }
0361 
0362     int pos = name.indexOf( '/' );
0363     while( pos == 0 ) {
0364         if( name.length() > 1 ) {
0365             name = name.mid( 1 ); // remove leading slash
0366             pos = name.indexOf( '/' ); // look again
0367         }
0368         else // "/"
0369             return this;
0370     }
0371 
0372     if ( pos != -1 ) {
0373         QString left = name.left( pos );
0374         QString right = name.mid( pos + 1 );
0375 
0376         K3b::Iso9660Entry* e = m_entries[ left ];
0377         if ( !e || !e->isDirectory() )
0378             return 0;
0379         return static_cast<K3b::Iso9660Directory*>(e)->entry( right );
0380     }
0381 
0382     return m_entries[ name ];
0383 }
0384 
0385 
0386 K3b::Iso9660Entry* K3b::Iso9660Directory::iso9660Entry( const QString& n )
0387 {
0388     if( n.isEmpty() )
0389         return 0;
0390 
0391     expand();
0392 
0393     QString name(n);
0394 
0395     // trailing slash ? -> remove
0396     if( name.length() > 1 && name[name.length()-1] == '/' ) {
0397         name.truncate( name.length()-1 );
0398     }
0399 
0400     int pos = name.indexOf( '/' );
0401     while( pos == 0 ) {
0402         if( name.length() > 1 ) {
0403             name = name.mid( 1 ); // remove leading slash
0404             pos = name.indexOf( '/' ); // look again
0405         }
0406         else // "/"
0407             return this;
0408     }
0409 
0410     if ( pos != -1 ) {
0411         QString left = name.left( pos );
0412         QString right = name.mid( pos + 1 );
0413 
0414         K3b::Iso9660Entry* e = m_iso9660Entries[ left ];
0415         if ( !e || !e->isDirectory() )
0416             return 0;
0417         return static_cast<K3b::Iso9660Directory*>(e)->iso9660Entry( right );
0418     }
0419 
0420     return m_iso9660Entries[ name ];
0421 }
0422 
0423 
0424 const K3b::Iso9660Entry* K3b::Iso9660Directory::entry( const QString& name ) const
0425 {
0426     return const_cast<K3b::Iso9660Directory*>(this)->entry( name );
0427 }
0428 
0429 
0430 const K3b::Iso9660Entry* K3b::Iso9660Directory::iso9660Entry( const QString& name ) const
0431 {
0432     return const_cast<K3b::Iso9660Directory*>(this)->iso9660Entry( name );
0433 }
0434 
0435 
0436 void K3b::Iso9660Directory::addEntry( K3b::Iso9660Entry* entry )
0437 {
0438     m_entries.insert( entry->name(), entry );
0439     m_iso9660Entries.insert( entry->isoName(), entry );
0440 }
0441 
0442 
0443 
0444 
0445 
0446 class K3b::Iso9660::Private
0447 {
0448 public:
0449     Private()
0450         : cdDevice(0),
0451           fd(-1),
0452           isOpen(false),
0453           startSector(0),
0454           plainIso9660(false),
0455           backend(0) {
0456     }
0457 
0458     QList<K3b::Iso9660Directory*> elToritoDirs;
0459     QList<K3b::Iso9660Directory*> jolietDirs;
0460     QList<K3b::Iso9660Directory*> isoDirs;
0461     QList<K3b::Iso9660Directory*> rrDirs; // RockRidge
0462 
0463     K3b::Iso9660SimplePrimaryDescriptor primaryDesc;
0464 
0465     K3b::Device::Device* cdDevice;
0466     int fd;
0467 
0468     bool isOpen;
0469 
0470     // only used for direkt K3b::Device::Device access
0471     unsigned int startSector;
0472 
0473     bool plainIso9660;
0474 
0475     K3b::Iso9660Backend* backend;
0476 };
0477 
0478 
0479 K3b::Iso9660::Iso9660( const QString& filename )
0480     :  m_filename( filename )
0481 {
0482     d = new Private();
0483 }
0484 
0485 
0486 K3b::Iso9660::Iso9660( int fd )
0487 {
0488     d = new Private();
0489     d->fd = fd;
0490 }
0491 
0492 
0493 K3b::Iso9660::Iso9660( K3b::Iso9660Backend* backend )
0494 {
0495     d = new Private();
0496     d->backend = backend;
0497 }
0498 
0499 
0500 K3b::Iso9660::Iso9660( K3b::Device::Device* dev, unsigned int startSector )
0501 {
0502     d = new Private();
0503     d->cdDevice = dev;
0504     d->startSector = startSector;
0505 }
0506 
0507 
0508 K3b::Iso9660::~Iso9660()
0509 {
0510     close();
0511     delete d->backend;
0512     delete d;
0513 }
0514 
0515 
0516 void K3b::Iso9660::setStartSector( unsigned int startSector )
0517 {
0518     d->startSector = startSector;
0519 }
0520 
0521 
0522 void K3b::Iso9660::setPlainIso9660( bool b )
0523 {
0524     d->plainIso9660 = b;
0525 }
0526 
0527 
0528 bool K3b::Iso9660::plainIso9660() const
0529 {
0530     return d->plainIso9660;
0531 }
0532 
0533 
0534 int K3b::Iso9660::read( unsigned int sector, char* data, int count )
0535 {
0536     if( count == 0 )
0537         return 0;
0538     else
0539         return d->backend->read( sector, data, count );
0540 }
0541 
0542 
0543 void K3b::Iso9660::addBoot(struct el_torito_boot_descriptor* bootdesc)
0544 {
0545     int i,size;
0546     boot_head boot;
0547     boot_entry *be;
0548     QString path;
0549     K3b::Iso9660File *entry;
0550 
0551     entry=new K3b::Iso9660File( this, "Catalog", "Catalog", dirent->permissions() & ~S_IFDIR,
0552                               dirent->date(), dirent->adate(), dirent->cdate(),
0553                               dirent->user(), dirent->group(), QString(),
0554                               isonum_731(bootdesc->boot_catalog), 2048 );
0555     dirent->addEntry(entry);
0556     if (!ReadBootTable(&K3b::Iso9660::read_callback,isonum_731(bootdesc->boot_catalog),&boot,this)) {
0557         i=1;
0558         be=boot.defentry;
0559         while (be) {
0560             size=BootImageSize(&K3b::Iso9660::read_callback,
0561                                isonum_711(((struct default_entry*) be->data)->media),
0562                                isonum_731(((struct default_entry*) be->data)->start),
0563                                isonum_721(((struct default_entry*) be->data)->seccount),
0564                                this);
0565             path="Default Image";
0566             if (i>1) path += " (" + QString::number(i) + ')';
0567             entry=new K3b::Iso9660File( this, path, path, dirent->permissions() & ~S_IFDIR,
0568                                       dirent->date(), dirent->adate(), dirent->cdate(),
0569                                       dirent->user(), dirent->group(), QString(),
0570                                       isonum_731(((struct default_entry*) be->data)->start), size<<9 );
0571             dirent->addEntry(entry);
0572             be=be->next;
0573             i++;
0574         }
0575 
0576         FreeBootTable(&boot);
0577     }
0578 }
0579 
0580 
0581 bool K3b::Iso9660::open()
0582 {
0583     if( d->isOpen )
0584         return true;
0585 
0586     if( !d->backend ) {
0587         // create a backend
0588 
0589         if( !m_filename.isEmpty() )
0590             d->backend = new K3b::Iso9660FileBackend( m_filename );
0591 
0592         else if( d->fd > 0 )
0593             d->backend = new K3b::Iso9660FileBackend( d->fd );
0594 
0595         else if( d->cdDevice ) {
0596             // now check if we have a scrambled video dvd
0597             if( d->cdDevice->copyrightProtectionSystemType() == K3b::Device::COPYRIGHT_PROTECTION_CSS ) {
0598 
0599                 qDebug() << "(K3b::Iso9660) found encrypted dvd. using libdvdcss.";
0600 
0601                 // open the libdvdcss stuff
0602                 d->backend = new K3b::Iso9660LibDvdCssBackend( d->cdDevice );
0603                 if( !d->backend->open() ) {
0604                     // fallback to devicebackend
0605                     delete d->backend;
0606                     d->backend = new K3b::Iso9660DeviceBackend( d->cdDevice );
0607                 }
0608             }
0609             else
0610                 d->backend = new K3b::Iso9660DeviceBackend( d->cdDevice );
0611         }
0612         else
0613             return false;
0614     }
0615 
0616     d->isOpen = d->backend->open();
0617     if( !d->isOpen )
0618         return false;
0619 
0620     iso_vol_desc *desc;
0621     QString path,tmp,uid,gid;
0622     k3b_struct_stat buf;
0623     int access,c_i,c_j;
0624     struct el_torito_boot_descriptor* bootdesc;
0625 
0626     // TODO implement win32 support
0627 
0628     /* We'll use the permission and user/group of the 'host' file except
0629      * in Rock Ridge, where the permissions are stored on the file system
0630      */
0631     if ( k3b_stat( QFile::encodeName(m_filename), &buf ) < 0 ) {
0632         /* defaults, if stat fails */
0633         memset(&buf,0,sizeof(k3b_struct_stat));
0634         buf.st_mode=0777;
0635     }
0636     uid.setNum(buf.st_uid);
0637     gid.setNum(buf.st_gid);
0638     access = buf.st_mode & ~S_IFMT;
0639 
0640 
0641     int c_b=1;
0642     c_i=1;c_j=1;
0643 
0644     desc = ReadISO9660( &K3b::Iso9660::read_callback, d->startSector, this );
0645 
0646     if (!desc) {
0647         qDebug() << "K3b::Iso9660::openArchive no volume descriptors";
0648         close();
0649         return false;
0650     }
0651 
0652     while (desc) {
0653 
0654         m_rr = false;
0655 
0656         switch (isonum_711(desc->data.type)) {
0657         case ISO_VD_BOOT:
0658 
0659             bootdesc=(struct el_torito_boot_descriptor*) &(desc->data);
0660             if( !memcmp( EL_TORITO_ID, bootdesc->system_id, ISODCL(8,39) ) ) {
0661                 path="El Torito Boot";
0662                 if( c_b > 1 )
0663                     path += " (" + QString::number(c_b) + ')';
0664 
0665                 dirent = new K3b::Iso9660Directory( this, path, path, access | S_IFDIR,
0666                                                   buf.st_mtime, buf.st_atime, buf.st_ctime, uid, gid, QString() );
0667                 d->elToritoDirs.append( dirent );
0668 
0669                 addBoot(bootdesc);
0670                 c_b++;
0671             }
0672             break;
0673 
0674         case ISO_VD_PRIMARY:
0675             createSimplePrimaryDesc( (struct iso_primary_descriptor*)&desc->data );
0676             // fall through
0677         case ISO_VD_SUPPLEMENTARY:
0678         {
0679             struct iso_primary_descriptor* primaryDesc = (struct iso_primary_descriptor*)&desc->data;
0680             struct iso_directory_record* idr = (struct iso_directory_record*)&primaryDesc->root_directory_record;
0681 
0682             m_joliet = JolietLevel(&desc->data);
0683 
0684             // skip joliet in plain iso mode
0685             if( m_joliet && plainIso9660() )
0686                 break;
0687 
0688             if (m_joliet) {
0689                 path = "Joliet level " + QString::number(m_joliet);
0690                 if( c_j > 1 )
0691                     path += " (" + QString::number(c_j) + ')';
0692             }
0693             else {
0694                 path = QString::fromLocal8Bit( primaryDesc->volume_id, 32 );
0695                 if( c_i > 1 )
0696                     path += " (" + QString::number(c_i) + ')';
0697             }
0698 
0699             dirent = new K3b::Iso9660Directory( this, path, path, access | S_IFDIR,
0700                                               buf.st_mtime, buf.st_atime, buf.st_ctime, uid, gid, QString() );
0701 
0702             // expand the root entry
0703             ProcessDir( &K3b::Iso9660::read_callback, isonum_733(idr->extent),isonum_733(idr->size),&K3b::Iso9660::isofs_callback,this);
0704 
0705             if (m_joliet)
0706                 c_j++;
0707             else
0708                 c_i++;
0709 
0710             if( m_joliet )
0711                 d->jolietDirs.append( dirent );
0712             else {
0713                 if( m_rr )
0714                     d->rrDirs.append( dirent );
0715                 d->isoDirs.append( dirent );
0716             }
0717 
0718             break;
0719         }
0720         }
0721         desc = desc->next;
0722     }
0723 
0724     FreeISO9660(desc);
0725 
0726     return true;
0727 }
0728 
0729 
0730 bool K3b::Iso9660::isOpen() const
0731 {
0732     return d->isOpen;
0733 }
0734 
0735 
0736 void K3b::Iso9660::createSimplePrimaryDesc( struct iso_primary_descriptor* desc )
0737 {
0738     d->primaryDesc.volumeId = QString::fromLocal8Bit( desc->volume_id, 32 ).trimmed();
0739     d->primaryDesc.systemId = QString::fromLocal8Bit( desc->system_id, 32 ).trimmed();
0740     d->primaryDesc.volumeSetId = QString::fromLocal8Bit( desc->volume_set_id, 128 ).trimmed();
0741     d->primaryDesc.publisherId = QString::fromLocal8Bit( desc->publisher_id, 128 ).trimmed();
0742     d->primaryDesc.preparerId = QString::fromLocal8Bit( desc->preparer_id, 128 ).trimmed();
0743     d->primaryDesc.applicationId = QString::fromLocal8Bit( desc->application_id, 128 ).trimmed();
0744     d->primaryDesc.volumeSetSize = isonum_723(desc->volume_set_size);
0745     d->primaryDesc.volumeSetNumber = isonum_723(desc->volume_set_size);
0746     d->primaryDesc.logicalBlockSize = isonum_723(desc->logical_block_size);
0747     d->primaryDesc.volumeSpaceSize = isonum_733(desc->volume_space_size);
0748 }
0749 
0750 
0751 void K3b::Iso9660::close()
0752 {
0753     if( d->isOpen ) {
0754         d->backend->close();
0755 
0756         // Since the first isoDir is the KArchive
0757         // root we must not delete it but all the
0758         // others.
0759 
0760         qDeleteAll( d->elToritoDirs );
0761         qDeleteAll( d->jolietDirs );
0762         qDeleteAll( d->isoDirs );
0763         d->elToritoDirs.clear();
0764         d->jolietDirs.clear();
0765         d->isoDirs.clear();
0766 
0767         d->isOpen = false;
0768     }
0769 }
0770 
0771 
0772 const K3b::Iso9660Directory* K3b::Iso9660::firstJolietDirEntry() const
0773 {
0774     if ( !d->jolietDirs.isEmpty() )
0775         return d->jolietDirs.first();
0776     else
0777         return 0;
0778 }
0779 
0780 
0781 const K3b::Iso9660Directory* K3b::Iso9660::firstIsoDirEntry() const
0782 {
0783     if ( !d->isoDirs.isEmpty() )
0784         return d->isoDirs.first();
0785     else
0786         return 0;
0787 }
0788 
0789 
0790 const K3b::Iso9660Directory* K3b::Iso9660::firstElToritoEntry() const
0791 {
0792     if ( !d->elToritoDirs.isEmpty() )
0793         return d->elToritoDirs.first();
0794     else
0795         return 0;
0796 }
0797 
0798 
0799 const K3b::Iso9660Directory* K3b::Iso9660::firstRRDirEntry() const
0800 {
0801     if ( !d->rrDirs.isEmpty() )
0802         return d->rrDirs.first();
0803     else
0804         return 0;
0805 }
0806 
0807 
0808 const K3b::Iso9660SimplePrimaryDescriptor& K3b::Iso9660::primaryDescriptor() const
0809 {
0810     return d->primaryDesc;
0811 }
0812 
0813 
0814 void K3b::Iso9660::debug() const
0815 {
0816     if( isOpen() ) {
0817         qDebug() << "System Id:         " << primaryDescriptor().systemId;
0818         qDebug() << "Volume Id:         " << primaryDescriptor().volumeId;
0819         qDebug() << "Volume Set Id:     " << primaryDescriptor().volumeSetId;
0820         qDebug() << "Preparer Id:       " << primaryDescriptor().preparerId;
0821         qDebug() << "Publisher Id:      " << primaryDescriptor().publisherId;
0822         qDebug() << "Application Id:    " << primaryDescriptor().applicationId;
0823         qDebug() << "Volume Set Size:   " << primaryDescriptor().volumeSetSize;
0824         qDebug() << "Volume Set Number: " << primaryDescriptor().volumeSetNumber;
0825 
0826         if( firstIsoDirEntry() ) {
0827             qDebug() << "First ISO Dir entry:";
0828             qDebug() << "----------------------------------------------";
0829             debugEntry( firstIsoDirEntry(), 0 );
0830             qDebug() << "----------------------------------------------";
0831         }
0832         if( firstRRDirEntry() ) {
0833             qDebug() << "First RR Dir entry:";
0834             qDebug() << "----------------------------------------------";
0835             debugEntry( firstRRDirEntry(), 0 );
0836             qDebug() << "----------------------------------------------";
0837         }
0838         if( firstJolietDirEntry() ) {
0839             qDebug() << "First Joliet Dir entry:";
0840             qDebug() << "----------------------------------------------";
0841             debugEntry( firstJolietDirEntry(), 0 );
0842             qDebug() << "----------------------------------------------";
0843         }
0844     }
0845 }
0846 
0847 
0848 void K3b::Iso9660::debugEntry( const K3b::Iso9660Entry* entry, int depth ) const
0849 {
0850     if( !entry ) {
0851         qDebug() << "(K3b::Iso9660::debugEntry) null entry.";
0852         return;
0853     }
0854 
0855     QString spacer;
0856     spacer.fill( ' ', depth*3 );
0857     qDebug() << spacer << "- " << entry->name() << " (" << entry->isoName() << ")";
0858     if( entry->isDirectory() ) {
0859         const K3b::Iso9660Directory* dir = dynamic_cast<const K3b::Iso9660Directory*>(entry);
0860         const QStringList entries = dir->entries();
0861         for( QStringList::const_iterator it = entries.constBegin(); it != entries.constEnd(); ++it ) {
0862             debugEntry( dir->entry( *it ), depth+1 );
0863         }
0864     }
0865 }
0866 
0867 
0868 K3b::Iso9660SimplePrimaryDescriptor::Iso9660SimplePrimaryDescriptor()
0869     : volumeSetSize(0),
0870       volumeSetNumber(0),
0871       logicalBlockSize(0),
0872       volumeSpaceSize(0)
0873 {
0874 }
0875 
0876 
0877 bool K3b::operator==( const K3b::Iso9660SimplePrimaryDescriptor& d1,
0878                       const K3b::Iso9660SimplePrimaryDescriptor& d2 )
0879 {
0880     return( d1.volumeId == d2.volumeId &&
0881             d1.systemId == d2.systemId &&
0882             d1.volumeSetId == d2.volumeSetId &&
0883             d1.publisherId == d2.publisherId &&
0884             d1.preparerId == d2.preparerId &&
0885             d1.applicationId == d2.applicationId &&
0886             d1.volumeSetSize == d2.volumeSetSize &&
0887             d1.volumeSetNumber == d2.volumeSetNumber &&
0888             d1.logicalBlockSize == d2.logicalBlockSize &&
0889             d1.volumeSpaceSize == d2.volumeSpaceSize );
0890 }
0891 
0892 
0893 bool K3b::operator!=( const K3b::Iso9660SimplePrimaryDescriptor& d1,
0894                       const K3b::Iso9660SimplePrimaryDescriptor& d2 )
0895 {
0896     return( d1.volumeId != d2.volumeId ||
0897             d1.systemId != d2.systemId ||
0898             d1.volumeSetId != d2.volumeSetId ||
0899             d1.publisherId != d2.publisherId ||
0900             d1.preparerId != d2.preparerId ||
0901             d1.applicationId != d2.applicationId ||
0902             d1.volumeSetSize != d2.volumeSetSize ||
0903             d1.volumeSetNumber != d2.volumeSetNumber ||
0904             d1.logicalBlockSize != d2.logicalBlockSize ||
0905             d1.volumeSpaceSize != d2.volumeSpaceSize );
0906 }