#include "config.h"
#include "filesystembase.h"
#include "common/checksums.h"
+#include "asserts.h"
#include <QLoggingCategory>
#include <qtconcurrentrun.h>
void ComputeChecksum::start(const QString &filePath)
{
qCInfo(lcChecksums) << "Computing" << checksumType() << "checksum of" << filePath << "in a thread";
+ startImpl(std::make_unique<QFile>(filePath));
+}
+
+void ComputeChecksum::start(std::unique_ptr<QIODevice> device)
+{
+ ENFORCE(device);
+ qCInfo(lcChecksums) << "Computing" << checksumType() << "checksum of device" << device.get() << "in a thread";
+ ASSERT(!device->parent());
+ startImpl(std::move(device));
+}
+
+void ComputeChecksum::startImpl(std::unique_ptr<QIODevice> device)
+{
connect(&_watcher, &QFutureWatcherBase::finished,
this, &ComputeChecksum::slotCalculationDone,
Qt::UniqueConnection);
- // Capturing "file" extends its lifetime to the lifetime of the new thread.
+ // We'd prefer to move the unique_ptr into the lambda, but that's
+ // awkward with the C++ standard we're on
+ auto sharedDevice = QSharedPointer<QIODevice>(device.release());
+
// Bug: The thread will keep running even if ComputeChecksum is deleted.
auto type = checksumType();
- _watcher.setFuture(QtConcurrent::run([filePath, type]() {
- QFile file(filePath);
- if (!file.open(QIODevice::ReadOnly)) {
- qCWarning(lcChecksums) << "Could not open file" << filePath << "for reading to compute a checksum" << file.errorString();
+ _watcher.setFuture(QtConcurrent::run([sharedDevice, type]() {
+ if (!sharedDevice->open(QIODevice::ReadOnly)) {
+ if (auto file = qobject_cast<QFile *>(sharedDevice.data())) {
+ qCWarning(lcChecksums) << "Could not open file" << file->fileName()
+ << "for reading to compute a checksum" << file->errorString();
+ } else {
+ qCWarning(lcChecksums) << "Could not open device" << sharedDevice.data()
+ << "for reading to compute a checksum" << sharedDevice->errorString();
+ }
return QByteArray();
}
- return ComputeChecksum::computeNow(&file, type);
+ return ComputeChecksum::computeNow(sharedDevice.data(), type);
}));
}
calculator->start(filePath);
}
+void ValidateChecksumHeader::start(std::unique_ptr<QIODevice> device, const QByteArray &checksumHeader)
+{
+ if (auto calculator = prepareStart(checksumHeader))
+ calculator->start(std::move(device));
+}
+
void ValidateChecksumHeader::slotChecksumCalculated(const QByteArray &checksumType,
const QByteArray &checksum)
{
*/
void start(const QString &filePath);
+ /**
+ * Computes the checksum for the given device.
+ *
+ * done() is emitted when the calculation finishes.
+ *
+ * The device ownership transfers into the thread that
+ * will compute the checksum. It must not have a parent.
+ */
+ void start(std::unique_ptr<QIODevice> device);
+
/**
* Computes the checksum synchronously.
*/
void slotCalculationDone();
private:
+ void startImpl(std::unique_ptr<QIODevice> device);
+
QByteArray _checksumType;
// watcher for the checksum calculation thread
explicit ValidateChecksumHeader(QObject *parent = nullptr);
/**
- * Check a device's actual checksum against the provided checksumHeader
+ * Check a file's actual checksum against the provided checksumHeader
*
* 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
*/
void start(const QString &filePath, const QByteArray &checksumHeader);
+ /**
+ * Check a device's actual checksum against the provided checksumHeader
+ *
+ * Like the other start() but works on an device.
+ *
+ * The device ownership transfers into the thread that
+ * will compute the checksum. It must not have a parent.
+ */
+ void start(std::unique_ptr<QIODevice> device, const QByteArray &checksumHeader);
+
signals:
void validated(const QByteArray &checksumType, const QByteArray &checksum);
void validationFailed(const QString &errMsg);