void ComputeChecksum::start(const QString &filePath)
{
qCInfo(lcChecksums) << "Computing" << checksumType() << "checksum of" << filePath << "in a thread";
- _file.reset(new QFile(filePath));
- if (!_file->open(QIODevice::ReadOnly)) {
- qCWarning(lcChecksums) << "Could not open file" << filePath << "for reading to compute a checksum" << _file->errorString();
+ // make_unique() would be more appropriate, but QtConcurrent requires
+ // copyable types.
+ auto file = std::make_shared<QFile>(filePath);
+ if (!file->open(QIODevice::ReadOnly)) {
+ qCWarning(lcChecksums) << "Could not open file" << filePath << "for reading to compute a checksum" << file->errorString();
emit done(QByteArray(), QByteArray());
return;
}
- start(_file.get());
-}
-
-void ComputeChecksum::start(QIODevice *device)
-{
- qCInfo(lcChecksums) << "Computing" << checksumType() << "checksum of iodevice in a thread";
- // Calculate the checksum in a different thread first.
connect(&_watcher, &QFutureWatcherBase::finished,
this, &ComputeChecksum::slotCalculationDone,
Qt::UniqueConnection);
- _watcher.setFuture(QtConcurrent::run(ComputeChecksum::computeNow, device, checksumType()));
+
+ // Capturing "file" extends its lifetime to the lifetime of the new thread.
+ // Bug: The thread will keep running even if ComputeChecksum is deleted.
+ auto type = checksumType();
+ _watcher.setFuture(QtConcurrent::run([file, type]() {
+ return ComputeChecksum::computeNow(file.get(), type);
+ }));
}
QByteArray ComputeChecksum::computeNowOnFile(const QString &filePath, const QByteArray &checksumType)
void ComputeChecksum::slotCalculationDone()
{
- // Close the file and delete the instance
- _file.reset(nullptr);
-
QByteArray checksum = _watcher.future().result();
if (!checksum.isNull()) {
emit done(_checksumType, checksum);
calculator->start(filePath);
}
-void ValidateChecksumHeader::start(QIODevice *device, const QByteArray &checksumHeader)
-{
- if (auto calculator = prepareStart(checksumHeader))
- calculator->start(device);
-}
-
void ValidateChecksumHeader::slotChecksumCalculated(const QByteArray &checksumType,
const QByteArray &checksum)
{
QByteArray checksumType() const;
- /**
- * Computes the checksum for given device.
- *
- * done() is emitted when the calculation finishes.
- *
- * Does not take ownership of the device.
- * Does not call open() on the device.
- */
- void start(QIODevice *device);
-
/**
* Computes the checksum for the given file path.
*
* done() is emitted when the calculation finishes.
- *
- * Convenience wrapper for start(QIODevice*) above.
*/
void start(const QString &filePath);
private:
QByteArray _checksumType;
- // The convenience wrapper may open a file and must close it too
- std::unique_ptr<QFile> _file;
-
// watcher for the checksum calculation thread
QFutureWatcher<QByteArray> _watcher;
};
* If no checksum is there, or if a correct checksum is there, the signal validated()
* will be emitted. In case of any kind of error, the signal validationFailed() will
* be emitted.
- *
- * Does not take ownership of the device.
- * Does not call open() on the device.
- */
- void start(QIODevice *device, const QByteArray &checksumHeader);
-
- /**
- * Same as above but opening a file by path.
- *
- * Convenience function for start(QIODevice*) above
*/
void start(const QString &filePath, const QByteArray &checksumHeader);
file->seek(0);
_successDown = false;
- vali->start(file, adler);
+ vali->start(_testfile, adler);
QTRY_VERIFY(_successDown);
_expectedError = QLatin1String("The downloaded file does not match the checksum, it will be resumed.");
_errorSeen = false;
file->seek(0);
- vali->start(file, "Adler32:543345");
+ vali->start(_testfile, "Adler32:543345");
QTRY_VERIFY(_errorSeen);
_expectedError = QLatin1String("The checksum header contained an unknown checksum type 'Klaas32'");
_errorSeen = false;
file->seek(0);
- vali->start(file, "Klaas32:543345");
+ vali->start(_testfile, "Klaas32:543345");
QTRY_VERIFY(_errorSeen);
delete vali;