diff --git a/CMakeLists.txt b/CMakeLists.txt index cf2dfd0..2d10c32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ set(CMAKE_AUTORCC ON) # Adding headers explicity so they are displayed in Qt Creator set(HEADERS config.h imagewriter.h networkaccessmanagerfactory.h nan.h drivelistitem.h drivelistmodel.h driveformatthread.h powersaveblocker.h - downloadthread.h downloadextractthread.h dependencies/mountutils/src/mountutils.hpp) + downloadthread.h downloadextractthread.h localfileextractthread.h dependencies/mountutils/src/mountutils.hpp) # Add dependencies if (APPLE) @@ -68,7 +68,7 @@ endif() set(SOURCES "main.cpp" "imagewriter.cpp" "networkaccessmanagerfactory.cpp" "drivelistitem.cpp" "drivelistmodel.cpp" "downloadthread.cpp" "downloadextractthread.cpp" - "driveformatthread.cpp" "powersaveblocker.cpp" "qml.qrc") + "driveformatthread.cpp" "localfileextractthread.cpp" "powersaveblocker.cpp" "qml.qrc") find_package(Qt5 COMPONENTS Core Quick LinguistTools Svg OPTIONAL_COMPONENTS Widgets) if (Qt5Widgets_FOUND) diff --git a/downloadextractthread.cpp b/downloadextractthread.cpp index 1e69036..09399f2 100644 --- a/downloadextractthread.cpp +++ b/downloadextractthread.cpp @@ -382,12 +382,12 @@ int DownloadExtractThread::_on_close(struct archive *) // static callback functions that call object oriented equivalents ssize_t DownloadExtractThread::_archive_read(struct archive *a, void *client_data, const void **buff) { - return static_cast(client_data)->_on_read(a, buff); + return qobject_cast((QObject *) client_data)->_on_read(a, buff); } int DownloadExtractThread::_archive_close(struct archive *a, void *client_data) { - return static_cast(client_data)->_on_close(a); + return qobject_cast((QObject *) client_data)->_on_close(a); } bool DownloadExtractThread::isImage() diff --git a/downloadextractthread.h b/downloadextractthread.h index 1d7e6bf..e4744a0 100644 --- a/downloadextractthread.h +++ b/downloadextractthread.h @@ -48,13 +48,13 @@ protected: QByteArray _popQueue(); void _pushQueue(const char *data, size_t len); - void _cancelExtract(); + virtual void _cancelExtract(); virtual size_t _writeData(const char *buf, size_t len); virtual void _onDownloadSuccess(); virtual void _onDownloadError(const QString &msg); - ssize_t _on_read(struct archive *a, const void **buff); - int _on_close(struct archive *a); + virtual ssize_t _on_read(struct archive *a, const void **buff); + virtual int _on_close(struct archive *a); static ssize_t _archive_read(struct archive *a, void *client_data, const void **buff); static int _archive_close(struct archive *a, void *client_data); diff --git a/imagewriter.cpp b/imagewriter.cpp index e0d6e40..f9bf421 100644 --- a/imagewriter.cpp +++ b/imagewriter.cpp @@ -8,6 +8,7 @@ #include "downloadextractthread.h" #include "dependencies/drivelist/src/drivelist.hpp" #include "driveformatthread.h" +#include "localfileextractthread.h" #include #include #include @@ -182,7 +183,11 @@ void ImageWriter::startWrite() urlstr = QUrl::fromLocalFile(_cacheFileName).toString(_src.FullyEncoded).toLatin1(); } - if (compressed) + if (QUrl(urlstr).isLocalFile()) + { + _thread = new LocalFileExtractThread(urlstr, _dst.toLatin1(), _expectedHash, this); + } + else if (compressed) { _thread = new DownloadExtractThread(urlstr, _dst.toLatin1(), _expectedHash, this); } diff --git a/localfileextractthread.cpp b/localfileextractthread.cpp new file mode 100644 index 0000000..839def6 --- /dev/null +++ b/localfileextractthread.cpp @@ -0,0 +1,74 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2020 Raspberry Pi (Trading) Limited + */ + +#include "localfileextractthread.h" +#include "config.h" + +LocalFileExtractThread::LocalFileExtractThread(const QByteArray &url, const QByteArray &dst, const QByteArray &expectedHash, QObject *parent) + : DownloadExtractThread(url, dst, expectedHash, parent) +{ + _inputBuf = (char *) qMallocAligned(IMAGEWRITER_UNCOMPRESSED_BLOCKSIZE, 4096); +} + +LocalFileExtractThread::~LocalFileExtractThread() +{ + _cancelled = true; + wait(); + qFreeAligned(_inputBuf); +} + +void LocalFileExtractThread::_cancelExtract() +{ + _cancelled = true; + if (_inputfile.isOpen()) + _inputfile.close(); +} + +void LocalFileExtractThread::run() +{ + if (isImage() && !_openAndPrepareDevice()) + return; + + _timer.start(); + _inputfile.setFileName( QUrl(_url).toLocalFile() ); + if (!_inputfile.open(_inputfile.ReadOnly)) + { + _onDownloadError(tr("Error opening image file")); + return; + } + _lastDlTotal = _inputfile.size(); + + if (isImage()) + extractImageRun(); + else + extractMultiFileRun(); + +} + +ssize_t LocalFileExtractThread::_on_read(struct archive *, const void **buff) +{ + if (_cancelled) + return -1; + + *buff = _inputBuf; + ssize_t len = _inputfile.read(_inputBuf, IMAGEWRITER_UNCOMPRESSED_BLOCKSIZE); + + if (len > 0) + { + _lastDlNow += len; + if (!_isImage) + { + _inputHash.addData(_inputBuf, len); + } + } + + return len; +} + +int LocalFileExtractThread::_on_close(struct archive *) +{ + _inputfile.close(); + return 0; +} diff --git a/localfileextractthread.h b/localfileextractthread.h new file mode 100644 index 0000000..4375e58 --- /dev/null +++ b/localfileextractthread.h @@ -0,0 +1,28 @@ +#ifndef LOCALFILEEXTRACTTHREAD_H +#define LOCALFILEEXTRACTTHREAD_H + +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2020 Raspberry Pi (Trading) Limited + */ + +#include "downloadextractthread.h" +#include + +class LocalFileExtractThread : public DownloadExtractThread +{ + Q_OBJECT +public: + explicit LocalFileExtractThread(const QByteArray &url, const QByteArray &dst = "", const QByteArray &expectedHash = "", QObject *parent = nullptr); + virtual ~LocalFileExtractThread(); + +protected: + virtual void _cancelExtract(); + virtual void run(); + virtual ssize_t _on_read(struct archive *a, const void **buff); + virtual int _on_close(struct archive *a); + QFile _inputfile; + char *_inputBuf; +}; + +#endif // LOCALFILEEXTRACTTHREAD_H