From a42ab4b835bfac08c01cd636713b57fede162508 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Tue, 1 Mar 2022 15:50:30 -0700 Subject: [PATCH 1/2] Add mimetype to pclx files --- core_lib/src/qminiz.cpp | 19 ++++++++++++++++++- core_lib/src/qminiz.h | 2 +- core_lib/src/structure/filemanager.cpp | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/core_lib/src/qminiz.cpp b/core_lib/src/qminiz.cpp index c445b0e163..e6e16efe0d 100644 --- a/core_lib/src/qminiz.cpp +++ b/core_lib/src/qminiz.cpp @@ -39,7 +39,7 @@ bool MiniZ::isZip(const QString& sZipFilePath) } // ReSharper disable once CppInconsistentNaming -Status MiniZ::compressFolder(QString zipFilePath, QString srcFolderPath, const QStringList& fileList) +Status MiniZ::compressFolder(QString zipFilePath, QString srcFolderPath, const QStringList& fileList, QString mimetype) { DebugDetails dd; dd << QString("Creating Zip %1 from folder %2").arg(zipFilePath, srcFolderPath); @@ -65,11 +65,27 @@ Status MiniZ::compressFolder(QString zipFilePath, QString srcFolderPath, const Q dd << QString("Miniz writer init failed: error %1, %2").arg(static_cast(err)).arg(mz_zip_get_error_string(err));; } + // Add special uncompressed mimetype file to help with the identification of projects + { + auto mimeData = mimetype.toUtf8(); + FILE *buffer = fmemopen(mimeData.data(), mimeData.length(), "read"); + ok = mz_zip_writer_add_cfile(mz, "mimetype", buffer, mimeData.length(), + 0, "", 0, MZ_NO_COMPRESSION, 0, 0, + 0, 0); + fclose(buffer); + if (!ok) + { + mz_zip_error err = mz_zip_get_last_error(mz); + dd << QString("Cannot add mimetype: error %1").arg(static_cast(err)).arg(mz_zip_get_error_string(err)); + } + } + //qDebug() << "SrcFolder=" << srcFolderPath; for (const QString& filePath : fileList) { QString sRelativePath = filePath; sRelativePath.remove(srcFolderPath); + if (sRelativePath == "mimetype") continue; dd << QString("Add file to zip: ").append(sRelativePath); @@ -166,6 +182,7 @@ Status MiniZ::uncompressFolder(QString zipFilePath, QString destPath) if (!stat->m_is_directory) { + if (QString(stat->m_filename) == "mimetype") continue; QString sFullPath = baseDir.filePath(QString::fromUtf8(stat->m_filename)); dd << QString("Unzip file: ").append(sFullPath); bool b = QFileInfo(sFullPath).absoluteDir().mkpath("."); diff --git a/core_lib/src/qminiz.h b/core_lib/src/qminiz.h index 4627cfda62..67947aee1f 100644 --- a/core_lib/src/qminiz.h +++ b/core_lib/src/qminiz.h @@ -22,7 +22,7 @@ GNU General Public License for more details. namespace MiniZ { bool isZip(const QString& sZipFilePath); - Status compressFolder(QString zipFilePath, QString srcFolderPath, const QStringList& fileList); + Status compressFolder(QString zipFilePath, QString srcFolderPath, const QStringList& fileList, QString mimetype); Status uncompressFolder(QString zipFilePath, QString destPath); } #endif diff --git a/core_lib/src/structure/filemanager.cpp b/core_lib/src/structure/filemanager.cpp index 8a7f88811f..de1a7f9111 100644 --- a/core_lib/src/structure/filemanager.cpp +++ b/core_lib/src/structure/filemanager.cpp @@ -317,7 +317,7 @@ Status FileManager::save(const Object* object, const QString& sFileName) QString sBackupFile = backupPreviousFile(sFileName); - Status stMiniz = MiniZ::compressFolder(sFileName, sTempWorkingFolder, filesToZip); + Status stMiniz = MiniZ::compressFolder(sFileName, sTempWorkingFolder, filesToZip, "application/x-pencil2d-pclx"); if (!stMiniz.ok()) { dd.collect(stMiniz.details()); From e411be1cf8302f7f5746df1f1efec3354c62b35a Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Thu, 3 Mar 2022 11:58:29 -0700 Subject: [PATCH 2/2] Use custom read function to support std::istream in miniz This makes it possible to do cross-platform writing of data to the zip archive without writing the data to the hard drive first. Currently this is used to write the special mimetype file, but without having looked into it, it could be useful for faster writing of the main xml file or even frame data already in memory (cached or dirty). --- core_lib/src/qminiz.cpp | 19 ++++++++++++++----- core_lib/src/qminiz.h | 2 ++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/core_lib/src/qminiz.cpp b/core_lib/src/qminiz.cpp index e6e16efe0d..b7f7ece7e5 100644 --- a/core_lib/src/qminiz.cpp +++ b/core_lib/src/qminiz.cpp @@ -15,11 +15,11 @@ GNU General Public License for more details. */ #include "qminiz.h" +#include #include #include #include #include -#include "miniz.h" #include "util.h" @@ -38,6 +38,16 @@ bool MiniZ::isZip(const QString& sZipFilePath) return (num > 0); } +size_t MiniZ::istreamReadCallback(void *pOpaque, mz_uint64 file_ofs, void * pBuf, size_t n) +{ + std::istream *stream = static_cast(pOpaque); + mz_int64 cur_ofs = stream->tellg(); + if ((mz_int64)file_ofs < 0 || (cur_ofs != (mz_int64)file_ofs && stream->seekg((mz_int64)file_ofs, std::ios_base::beg))) + return 0; + stream->read(static_cast(pBuf), n); + return stream->gcount(); +} + // ReSharper disable once CppInconsistentNaming Status MiniZ::compressFolder(QString zipFilePath, QString srcFolderPath, const QStringList& fileList, QString mimetype) { @@ -67,12 +77,11 @@ Status MiniZ::compressFolder(QString zipFilePath, QString srcFolderPath, const Q // Add special uncompressed mimetype file to help with the identification of projects { - auto mimeData = mimetype.toUtf8(); - FILE *buffer = fmemopen(mimeData.data(), mimeData.length(), "read"); - ok = mz_zip_writer_add_cfile(mz, "mimetype", buffer, mimeData.length(), + QByteArray mimeData = mimetype.toUtf8(); + std::stringstream mimeStream(mimeData.toStdString()); + ok = mz_zip_writer_add_read_buf_callback(mz, "mimetype", MiniZ::istreamReadCallback, &mimeStream, mimeData.length(), 0, "", 0, MZ_NO_COMPRESSION, 0, 0, 0, 0); - fclose(buffer); if (!ok) { mz_zip_error err = mz_zip_get_last_error(mz); diff --git a/core_lib/src/qminiz.h b/core_lib/src/qminiz.h index 67947aee1f..9528b2f7cd 100644 --- a/core_lib/src/qminiz.h +++ b/core_lib/src/qminiz.h @@ -17,11 +17,13 @@ GNU General Public License for more details. #define QMINIZ_H #include +#include "miniz.h" #include "pencilerror.h" namespace MiniZ { bool isZip(const QString& sZipFilePath); + size_t istreamReadCallback(void *pOpaque, mz_uint64 file_ofs, void * pBuf, size_t n); Status compressFolder(QString zipFilePath, QString srcFolderPath, const QStringList& fileList, QString mimetype); Status uncompressFolder(QString zipFilePath, QString destPath); }