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

0001 /*
0002     SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "k3bmd5job.h"
0007 #include "k3biso9660.h"
0008 #include "k3bglobals.h"
0009 #include "k3bdevice.h"
0010 #include "k3bfilesplitter.h"
0011 #include "k3b_i18n.h"
0012 
0013 #include <QCryptographicHash>
0014 #include <QDebug>
0015 #include <QIODevice>
0016 #include <QTimer>
0017 
0018 
0019 class K3b::Md5Job::Private
0020 {
0021 public:
0022     Private()
0023         : md5(QCryptographicHash::Md5),
0024           ioDevice(0),
0025           finished(true),
0026           data(0),
0027           isoFile(0),
0028           maxSize(0),
0029           lastProgress(0) {
0030     }
0031 
0032     QCryptographicHash md5;
0033     K3b::FileSplitter file;
0034     QTimer timer;
0035     QString filename;
0036     QIODevice* ioDevice;
0037     K3b::Device::Device* device;
0038 
0039     bool finished;
0040     char* data;
0041     const K3b::Iso9660File* isoFile;
0042 
0043     qint64 maxSize;
0044     qint64 readData;
0045 
0046     int lastProgress;
0047 
0048     KIO::filesize_t imageSize;
0049 
0050     static const int BUFFERSIZE = 2048*10;
0051 };
0052 
0053 
0054 K3b::Md5Job::Md5Job( K3b::JobHandler* jh, QObject* parent )
0055     : K3b::Job( jh, parent ),
0056       d( new Private() )
0057 {
0058     d->data = new char[Private::BUFFERSIZE];
0059     connect( &d->timer, SIGNAL(timeout()),
0060              this, SLOT(slotUpdate()) );
0061 }
0062 
0063 
0064 K3b::Md5Job::~Md5Job()
0065 {
0066     delete [] d->data;
0067     delete d;
0068 }
0069 
0070 
0071 void K3b::Md5Job::start()
0072 {
0073     cancel();
0074 
0075     jobStarted();
0076     d->readData = 0;
0077 
0078     if( d->isoFile ) {
0079         d->imageSize = d->isoFile->size();
0080     }
0081     else if( !d->filename.isEmpty() ) {
0082         if( !QFile::exists( d->filename ) ) {
0083             emit infoMessage( i18n("Could not find file %1",d->filename), MessageError );
0084             jobFinished(false);
0085             return;
0086         }
0087 
0088         d->file.setName( d->filename );
0089         if( !d->file.open( QIODevice::ReadOnly ) ) {
0090             emit infoMessage( i18n("Could not open file %1",d->filename), MessageError );
0091             jobFinished(false);
0092             return;
0093         }
0094 
0095         d->imageSize = K3b::filesize( QUrl::fromLocalFile(d->filename) );
0096     }
0097     else
0098         d->imageSize = 0;
0099 
0100     if( d->device ) {
0101         //
0102         // Let the drive determine the optimal reading speed
0103         //
0104         d->device->setSpeed( 0xffff, 0xffff );
0105     }
0106 
0107     d->md5.reset();
0108     d->finished = false;
0109     if( d->ioDevice )
0110         connect( d->ioDevice, SIGNAL(readyRead()), this, SLOT(slotUpdate()) );
0111     else
0112         d->timer.start(0);
0113 }
0114 
0115 
0116 void K3b::Md5Job::cancel()
0117 {
0118     if( !d->finished ) {
0119         stopAll();
0120 
0121         emit canceled();
0122         jobFinished( false );
0123     }
0124 }
0125 
0126 
0127 void K3b::Md5Job::setFile( const QString& filename )
0128 {
0129     d->filename = filename;
0130     d->isoFile = 0;
0131     d->ioDevice = 0;
0132     d->device = 0;
0133 }
0134 
0135 
0136 void K3b::Md5Job::setFile( const K3b::Iso9660File* file )
0137 {
0138     d->isoFile = file;
0139     d->ioDevice = 0;
0140     d->filename.truncate(0);
0141     d->device = 0;
0142 }
0143 
0144 
0145 void K3b::Md5Job::setIODevice( QIODevice* dev )
0146 {
0147     d->ioDevice = dev;
0148     d->filename.truncate(0);
0149     d->isoFile = 0;
0150     d->device = 0;
0151 }
0152 
0153 
0154 void K3b::Md5Job::setDevice( K3b::Device::Device* dev )
0155 {
0156     d->device = dev;
0157     d->ioDevice = 0;
0158     d->filename.truncate(0);
0159     d->isoFile = 0;
0160 }
0161 
0162 
0163 void K3b::Md5Job::setMaxReadSize( qint64 size )
0164 {
0165     d->maxSize = size;
0166 }
0167 
0168 
0169 void K3b::Md5Job::slotUpdate()
0170 {
0171     if( !d->finished ) {
0172 
0173         // determine bytes to read
0174         qint64 readSize = Private::BUFFERSIZE;
0175         if( d->maxSize > 0 )
0176             readSize = qMin( readSize, d->maxSize - d->readData );
0177 
0178         if( readSize <= 0 ) {
0179             //      qDebug() << "(K3b::Md5Job) reached max size of " << d->maxSize << ". Stopping.";
0180             emit debuggingOutput( "K3b::Md5Job", QString("Reached max read of %1. Stopping after %2 bytes.").arg(d->maxSize).arg(d->readData) );
0181             stopAll();
0182             emit percent( 100 );
0183             jobFinished(true);
0184         }
0185         else {
0186             int read = 0;
0187 
0188             //
0189             // read from the iso9660 file
0190             //
0191             if( d->isoFile ) {
0192                 read = d->isoFile->read( d->readData, d->data, readSize );
0193             }
0194 
0195             //
0196             // read from the device
0197             //
0198             else if( d->device ) {
0199                 //
0200                 // when reading from a device we always read multiples of 2048 bytes.
0201                 // Only the last sector may not be used completely.
0202                 //
0203                 qint64 sector = d->readData/2048;
0204                 qint64 sectorCnt = qMax( readSize/2048, ( qint64 )1 );
0205                 read = -1;
0206                 if( d->device->read10( reinterpret_cast<unsigned char*>(d->data),
0207                                        sectorCnt*2048,
0208                                        sector,
0209                                        sectorCnt ) )
0210                     read = qMin( readSize, sectorCnt*2048 );
0211             }
0212 
0213             //
0214             // read from the file
0215             //
0216             else if( !d->ioDevice ) {
0217                 read = d->file.read( d->data, readSize );
0218             }
0219 
0220             //
0221             // reading from the io device
0222             //
0223             else {
0224                 read = d->ioDevice->read( d->data, readSize );
0225             }
0226 
0227             if( read < 0 ) {
0228                 emit infoMessage( i18n("Error while reading from file %1", d->filename), MessageError );
0229                 stopAll();
0230                 jobFinished(false);
0231             }
0232             else if( read == 0 ) {
0233                 //  qDebug() << "(K3b::Md5Job) read all data. Total size: " << d->readData << ". Stopping.";
0234                 emit debuggingOutput( "K3b::Md5Job", QString("All data read. Stopping after %1 bytes.").arg(d->readData) );
0235                 stopAll();
0236                 emit percent( 100 );
0237                 jobFinished(true);
0238             }
0239             else {
0240                 d->readData += read;
0241                 d->md5.addData( d->data, read );
0242                 int progress = 0;
0243                 if( d->isoFile || !d->filename.isEmpty() )
0244                     progress = (int)((double)d->readData * 100.0 / (double)d->imageSize);
0245                 else if( d->maxSize > 0 )
0246                     progress = (int)((double)d->readData * 100.0 / (double)d->maxSize);
0247 
0248                 if( progress != d->lastProgress ) {
0249                     d->lastProgress = progress;
0250                     emit percent( progress );
0251                 }
0252             }
0253         }
0254     }
0255 }
0256 
0257 
0258 QByteArray K3b::Md5Job::hexDigest()
0259 {
0260     if( d->finished )
0261         return d->md5.result().toHex();
0262     else
0263         return "";
0264 }
0265 
0266 
0267 QByteArray K3b::Md5Job::base64Digest()
0268 {
0269     if( d->finished )
0270         return d->md5.result().toBase64();
0271     else
0272         return "";
0273 }
0274 
0275 
0276 void K3b::Md5Job::stop()
0277 {
0278     emit debuggingOutput( "K3b::Md5Job", QString("Stopped manually after %1 bytes.").arg(d->readData) );
0279     stopAll();
0280     jobFinished( true );
0281 }
0282 
0283 
0284 void K3b::Md5Job::stopAll()
0285 {
0286     if( d->ioDevice )
0287         disconnect( d->ioDevice, SIGNAL(readyRead()), this, SLOT(slotUpdate()) );
0288     if( d->file.isOpen() )
0289         d->file.close();
0290     d->timer.stop();
0291     d->finished = true;
0292 }
0293 
0294 #include "moc_k3bmd5job.cpp"