File indexing completed on 2024-06-16 07:42:04

0001 /*
0002     SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 #include <config-k3b.h>
0006 
0007 #include "k3bclonetocreader.h"
0008 #include "k3bdeviceglobals.h"
0009 #include "k3bglobals.h"
0010 
0011 #include <QDebug>
0012 #include <QFile>
0013 #include <QFileInfo>
0014 
0015 
0016 class K3b::CloneTocReader::Private
0017 {
0018 public:
0019     Private()
0020         : size(0) {
0021     }
0022 
0023     K3b::Msf size;
0024     QString tocFile;
0025 };
0026 
0027 
0028 
0029 K3b::CloneTocReader::CloneTocReader( const QString& filename )
0030     : K3b::ImageFileReader()
0031 {
0032     d = new Private;
0033     openFile( filename );
0034 }
0035 
0036 
0037 K3b::CloneTocReader::~CloneTocReader()
0038 {
0039     delete d;
0040 }
0041 
0042 
0043 K3b::Msf K3b::CloneTocReader::imageSize() const
0044 {
0045     return d->size;
0046 }
0047 
0048 
0049 void K3b::CloneTocReader::readFile()
0050 {
0051     // first of all we check if we find the image file which contains the data for this toc
0052     // cdrecord always uses this strange file naming:
0053     //   somedata
0054     //   somedata.toc
0055 
0056     // filename should always be the toc file
0057     if( filename().right( 4 ) == ".toc" )
0058         d->tocFile = filename();
0059     else
0060         d->tocFile = filename() + ".toc";
0061 
0062     // now get rid of the ".toc" extension
0063     QString imageFileName = d->tocFile.left( d->tocFile.length()-4 );
0064     if( !QFile::exists( imageFileName ) ) {
0065         qDebug() << "(K3b::CloneTocReader) could not find image file " << imageFileName;
0066         return;
0067     }
0068 
0069     setImageFilename( imageFileName );
0070 
0071     d->size = 0;
0072 
0073     QFile f( d->tocFile );
0074     if( f.open( QIODevice::ReadOnly ) ) {
0075         //
0076         // Inspired by clone.c from the cdrecord sources
0077         //
0078         char buffer[2048];
0079         int read = f.read( buffer, 2048 );
0080         f.close();
0081 
0082         if( read == 2048 ) {
0083             qDebug() << "(K3b::CloneTocReader) TOC too large.";
0084             return;
0085         }
0086 
0087         // the toc starts with a tocheader
0088         struct tocheader {
0089             unsigned char len[2];
0090             unsigned char first; // first session
0091             unsigned char last; // last session
0092         };
0093 
0094         struct tocheader* th = (struct tocheader*)buffer;
0095         int dataLen = K3b::Device::from2Byte( th->len ) + 2;  // the len field does not include it's own length
0096 
0097         if( th->first != 1 ) {
0098             qDebug() << "(K3b::CloneTocReader) first session != 1";
0099             return;
0100         }
0101 
0102         // the following bytes are multiple instances of
0103         struct ftrackdesc {
0104             unsigned char sess_number;
0105 #ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN
0106             unsigned char adr      : 4;
0107             unsigned char control  : 4;
0108 #else
0109             unsigned char control  : 4;
0110             unsigned char adr      : 4;
0111 #endif
0112             unsigned char track;
0113             unsigned char point;
0114             unsigned char amin;
0115             unsigned char asec;
0116             unsigned char aframe;
0117             unsigned char res7;
0118             unsigned char pmin;
0119             unsigned char psec;
0120             unsigned char pframe;
0121         };
0122 
0123         for( int i = 4; i < dataLen; i += 11) {
0124             struct ftrackdesc* ft = (struct ftrackdesc*)&buffer[i];
0125 
0126             if( ft->sess_number != 1 ) {
0127                 qDebug() << "(K3b::CloneTocReader} session number != 1";
0128                 return;
0129             }
0130 
0131             // now we check some of the values
0132             if( ft->point >= 0x1 && ft->point <= 0x63 ) {
0133                 if( ft->adr == 1 ) {
0134                     // check track starttime
0135                     if( ft->psec > 60 || ft->pframe > 75 ) {
0136                         qDebug() << "(K3b::CloneTocReader) invalid track start: "
0137                                  << (int)ft->pmin << "."
0138                                  << (int)ft->psec << "."
0139                                  << (int)ft->pframe << Qt::endl;
0140                         return;
0141                     }
0142                 }
0143             }
0144             else {
0145                 switch( ft->point ) {
0146                 case 0xa0:
0147                     if( ft->adr != 1 ) {
0148                         qDebug() << "(K3b::CloneTocReader) adr != 1";
0149                         return;
0150                     }
0151 
0152                     // disk type in psec
0153                     if( ft->psec != 0x00 && ft->psec != 0x10 && ft->psec != 0x20 ) {
0154                         qDebug() << "(K3b::CloneTocReader) invalid disktype: " << ft->psec;
0155                         return;
0156                     }
0157 
0158                     if( ft->pmin != 1 ) {
0159                         qDebug() << "(K3b::CloneTocReader) first track number != 1 ";
0160                         return;
0161                     }
0162 
0163                     if( ft->pframe != 0x0 ) {
0164                         qDebug() << "(K3b::CloneTocReader) found data when there should be 0x0";
0165                         return;
0166                     }
0167                     break;
0168 
0169                 case  0xa1:
0170                     if( ft->adr != 1 ) {
0171                         qDebug() << "(K3b::CloneTocReader) adr != 1";
0172                         return;
0173                     }
0174 
0175                     if( !(ft->pmin >= 1) ) {
0176                         qDebug() << "(K3b::CloneTocReader) last track number needs to be >= 1.";
0177                         return;
0178                     }
0179                     if( ft->psec != 0x0 || ft->pframe != 0x0 ) {
0180                         qDebug() << "(K3b::CloneTocReader) found data when there should be 0x0";
0181                         return;
0182                     }
0183                     break;
0184 
0185                 case 0xa2:
0186                     if( ft->adr != 1 ) {
0187                         qDebug() << "(K3b::CloneTocReader) adr != 1";
0188                         return;
0189                     }
0190 
0191                     // start of the leadout = size of the image
0192                     // subtract 2 seconds since in cdrecord other than in K3b lba 0 = msf 2:00
0193                     // (the cdrecord way is actually more accurate but we use k3b::Msf for many
0194                     // things and it is simpler this way.)
0195                     d->size = K3b::Msf( ft->pmin, ft->psec, ft->pframe ) - K3b::Msf( 0, 2, 0 );
0196 
0197                     // leadout... no check so far...
0198                     break;
0199 
0200                 default:
0201                     if( ft->adr != 5 ) {
0202                         qDebug() << "(K3b::CloneTocReader) adr != 5";
0203                         return;
0204                     }
0205                     break;
0206                 }
0207             }
0208         }
0209 
0210         if( d->size.rawBytes() != KIO::filesize_t(QFileInfo(imageFileName).size()) ) {
0211             qDebug() << "(K3b::CloneTocReader) image file size invalid.";
0212             return;
0213         }
0214 
0215         // ok, could be a cdrecord toc file
0216         setValid(true);
0217     }
0218     else {
0219         qDebug() << "(K3b::CloneTocReader) could not open file " << d->tocFile;
0220     }
0221 }