From 4695b238c5da39d75ef2726ec3169c05d0fa53e6 Mon Sep 17 00:00:00 2001 From: Xie Zhuoyang <179989892+lite-tx@users.noreply.github.com> Date: Fri, 24 Jul 2026 23:26:26 +0800 Subject: [PATCH 1/2] Fix saving documents through QSaveFile --- QXlsx/header/xlsxzipwriter_p.h | 1 + QXlsx/source/xlsxdocument.cpp | 3 +- QXlsx/source/xlsxzipwriter.cpp | 56 +++++++++++++++++++++++++++++++++- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/QXlsx/header/xlsxzipwriter_p.h b/QXlsx/header/xlsxzipwriter_p.h index 42b5acab..5ad288d0 100644 --- a/QXlsx/header/xlsxzipwriter_p.h +++ b/QXlsx/header/xlsxzipwriter_p.h @@ -25,6 +25,7 @@ class ZipWriter void close(); private: + QIODevice *m_deviceProxy; QZipWriter *m_writer; }; diff --git a/QXlsx/source/xlsxdocument.cpp b/QXlsx/source/xlsxdocument.cpp index beb4e833..9e278787 100644 --- a/QXlsx/source/xlsxdocument.cpp +++ b/QXlsx/source/xlsxdocument.cpp @@ -1365,7 +1365,8 @@ bool Document::saveAs(const QString &name) const * \overload * This function writes a document to the given \a device. * - * \warning The \a device will be closed when this function returned. + * \warning The \a device will be closed when this function returns, except for + * QSaveFile. A QSaveFile remains open and must be committed by the caller. */ bool Document::saveAs(QIODevice *device) const { diff --git a/QXlsx/source/xlsxzipwriter.cpp b/QXlsx/source/xlsxzipwriter.cpp index 3c2fb19e..12cc54d2 100644 --- a/QXlsx/source/xlsxzipwriter.cpp +++ b/QXlsx/source/xlsxzipwriter.cpp @@ -5,24 +5,78 @@ #include #include +#ifndef QT_NO_TEMPORARYFILE +#include +#endif QT_BEGIN_NAMESPACE_XLSX +namespace { + +class NonClosingDevice : public QIODevice +{ +public: + explicit NonClosingDevice(QIODevice *device) + : m_device(device) + { + if (device->isOpen()) + QIODevice::open(device->openMode()); + } + + bool open(OpenMode mode) override + { + if (!m_device->isOpen() && !m_device->open(mode)) + return false; + return QIODevice::open(m_device->openMode()); + } + + void close() override { QIODevice::close(); } + bool isSequential() const override { return m_device->isSequential(); } + qint64 pos() const override { return m_device->pos(); } + qint64 size() const override { return m_device->size(); } + + bool seek(qint64 position) override + { + if (!m_device->seek(position)) + return false; + return QIODevice::seek(position); + } + +protected: + qint64 readData(char *data, qint64 maxSize) override { return m_device->read(data, maxSize); } + qint64 writeData(const char *data, qint64 maxSize) override + { + return m_device->write(data, maxSize); + } + +private: + QIODevice *m_device; +}; + +} // namespace + ZipWriter::ZipWriter(const QString &filePath) + : m_deviceProxy(nullptr) { m_writer = new QZipWriter(filePath, QIODevice::WriteOnly); m_writer->setCompressionPolicy(QZipWriter::AutoCompress); } ZipWriter::ZipWriter(QIODevice *device) + : m_deviceProxy(nullptr) { - m_writer = new QZipWriter(device); +#ifndef QT_NO_TEMPORARYFILE + if (qobject_cast(device)) + m_deviceProxy = new NonClosingDevice(device); +#endif + m_writer = new QZipWriter(m_deviceProxy ? m_deviceProxy : device); m_writer->setCompressionPolicy(QZipWriter::AutoCompress); } ZipWriter::~ZipWriter() { delete m_writer; + delete m_deviceProxy; } bool ZipWriter::error() const From d00d78fed8c852ecc82168daae0308d1a5f0960a Mon Sep 17 00:00:00 2001 From: Xie Zhuoyang <179989892+lite-tx@users.noreply.github.com> Date: Fri, 24 Jul 2026 23:34:27 +0800 Subject: [PATCH 2/2] Use scoped ownership for the device proxy --- QXlsx/header/xlsxzipwriter_p.h | 3 ++- QXlsx/source/xlsxzipwriter.cpp | 8 ++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/QXlsx/header/xlsxzipwriter_p.h b/QXlsx/header/xlsxzipwriter_p.h index 5ad288d0..39a54be0 100644 --- a/QXlsx/header/xlsxzipwriter_p.h +++ b/QXlsx/header/xlsxzipwriter_p.h @@ -6,6 +6,7 @@ #include "xlsxglobal.h" #include +#include #include class QZipWriter; @@ -25,7 +26,7 @@ class ZipWriter void close(); private: - QIODevice *m_deviceProxy; + QScopedPointer m_deviceProxy; QZipWriter *m_writer; }; diff --git a/QXlsx/source/xlsxzipwriter.cpp b/QXlsx/source/xlsxzipwriter.cpp index 12cc54d2..e0922afc 100644 --- a/QXlsx/source/xlsxzipwriter.cpp +++ b/QXlsx/source/xlsxzipwriter.cpp @@ -30,7 +30,6 @@ class NonClosingDevice : public QIODevice return QIODevice::open(m_device->openMode()); } - void close() override { QIODevice::close(); } bool isSequential() const override { return m_device->isSequential(); } qint64 pos() const override { return m_device->pos(); } qint64 size() const override { return m_device->size(); } @@ -56,27 +55,24 @@ class NonClosingDevice : public QIODevice } // namespace ZipWriter::ZipWriter(const QString &filePath) - : m_deviceProxy(nullptr) { m_writer = new QZipWriter(filePath, QIODevice::WriteOnly); m_writer->setCompressionPolicy(QZipWriter::AutoCompress); } ZipWriter::ZipWriter(QIODevice *device) - : m_deviceProxy(nullptr) { #ifndef QT_NO_TEMPORARYFILE if (qobject_cast(device)) - m_deviceProxy = new NonClosingDevice(device); + m_deviceProxy.reset(new NonClosingDevice(device)); #endif - m_writer = new QZipWriter(m_deviceProxy ? m_deviceProxy : device); + m_writer = new QZipWriter(m_deviceProxy ? m_deviceProxy.data() : device); m_writer->setCompressionPolicy(QZipWriter::AutoCompress); } ZipWriter::~ZipWriter() { delete m_writer; - delete m_deviceProxy; } bool ZipWriter::error() const