Pencil2D Animation
Download Community News Docs Contribute
  • Overview
  • Articles
  • Code
  •  
  • Class List
  • Class Index
  • Class Hierarchy
  • Class Members
  • File List
Loading...
Searching...
No Matches
  • core_lib
  • src
qminiz.cpp
1/*
2
3Pencil2D - Traditional Animation Software
4Copyright (C) 2012-2020 Matthew Chiawen Chang
5
6This program is free software; you can redistribute it and/or
7modify it under the terms of the GNU General Public License
8as published by the Free Software Foundation; version 2 of the License.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15*/
16#include "qminiz.h"
17
18#include <sstream>
19#include <QFileInfo>
20#include <QDir>
21#include <QDebug>
22#include <QDirIterator>
23#include "util.h"
24
25
26Status MiniZ::sanityCheck(const QString& sZipFilePath)
27{
28 mz_zip_archive* mz = new mz_zip_archive;
29 OnScopeExit(delete mz);
30 mz_zip_zero_struct(mz);
31 QByteArray utf8Bytes = sZipFilePath.toUtf8();
32 mz_bool readOk = mz_zip_reader_init_file(mz, utf8Bytes.constData(), 0);
33
34 mz_zip_error read_err = mz_zip_get_last_error(mz);
35
36 mz_bool closeOk = mz_zip_reader_end(mz);
37
38 mz_zip_error close_err = mz_zip_get_last_error(mz);
39
40 if (!readOk || !closeOk) {
41 DebugDetails dd;
42
43 dd << "\n[Miniz sanity check]\n";
44 if (read_err != MZ_ZIP_NO_ERROR) {
45 dd << QString("Found an error while reading the file. Error code: %2, reason: %3").arg(static_cast<int>(read_err)).arg(mz_zip_get_error_string(read_err));
46 }
47 if (close_err != MZ_ZIP_NO_ERROR) {
48 dd << QString("Found an error while closing the file. Error code: %2, reason: %3").arg(static_cast<int>(close_err)).arg(mz_zip_get_error_string(close_err));
49 }
50 return Status(Status::ERROR_MINIZ_FAIL, dd);
51 }
52
53
54 return Status::OK;
55}
56
57size_t MiniZ::istreamReadCallback(void *pOpaque, mz_uint64 file_ofs, void * pBuf, size_t n)
58{
59 std::istream *stream = static_cast<std::istream*>(pOpaque);
60 mz_int64 cur_ofs = stream->tellg();
61 if ((mz_int64)file_ofs < 0 || (cur_ofs != (mz_int64)file_ofs && stream->seekg((mz_int64)file_ofs, std::ios_base::beg)))
62 return 0;
63 stream->read(static_cast<char*>(pBuf), n);
64 return stream->gcount();
65}
66
67// ReSharper disable once CppInconsistentNaming
68Status MiniZ::compressFolder(QString zipFilePath, QString srcFolderPath, const QStringList& fileList, QString mimetype)
69{
70 DebugDetails dd;
71 dd << "\n[Miniz COMPRESSION diagnostics]\n";
72 dd << QString("Creating Zip %1 from folder %2").arg(zipFilePath, srcFolderPath);
73
74 if (!srcFolderPath.endsWith("/"))
75 {
76 dd << "Adding / to path";
77 srcFolderPath.append("/");
78 }
79
80 mz_zip_archive* mz = new mz_zip_archive;
81 ScopeGuard mzScopeGuard([&] {
82 delete mz;
83 });
84
85 mz_zip_zero_struct(mz);
86
87 mz_bool ok = mz_zip_writer_init_file(mz, zipFilePath.toUtf8().data(), 0);
88
89 if (!ok)
90 {
91 mz_zip_error err = mz_zip_get_last_error(mz);
92 dd << QString("Error: Failed to init writer. Error code: %1, reason: %2").arg(static_cast<int>(err)).arg(mz_zip_get_error_string(err));
93 return Status(Status::FAIL, dd);
94 }
95 ScopeGuard mzScopeGuard2([&] {
96 mz_zip_writer_end(mz);
97 });
98
99 // Add special uncompressed mimetype file to help with the identification of projects
100 {
101 QByteArray mimeData = mimetype.toUtf8();
102 std::stringstream mimeStream(mimeData.toStdString());
103 ok = mz_zip_writer_add_read_buf_callback(mz, "mimetype", MiniZ::istreamReadCallback, &mimeStream, mimeData.length(),
104 0, "", 0, MZ_NO_COMPRESSION, 0, 0,
105 0, 0);
106 if (!ok)
107 {
108 mz_zip_error err = mz_zip_get_last_error(mz);
109 dd << QString("ERROR: Unable to add mimetype. Error code: %1, reason: %2").arg(static_cast<int>(err)).arg(mz_zip_get_error_string(err));
110 return Status(Status::FAIL, dd);
111 }
112 }
113
114 //qDebug() << "SrcFolder=" << srcFolderPath;
115 for (const QString& filePath : fileList)
116 {
117 QString sRelativePath = filePath;
118 sRelativePath.remove(srcFolderPath);
119 if (sRelativePath == "mimetype") continue;
120
121 dd << QString("Add file to zip: ").append(sRelativePath);
122
123 ok = mz_zip_writer_add_file(mz,
124 sRelativePath.toUtf8().data(),
125 filePath.toUtf8().data(),
126 "", 0, MZ_BEST_SPEED);
127 if (!ok)
128 {
129 mz_zip_error err = mz_zip_get_last_error(mz);
130 dd << QString("Error: Unable to add file: %3. Error code: %1, reason: %2 - Aborting!").arg(static_cast<int>(err)).arg(mz_zip_get_error_string(err), sRelativePath);
131 return Status(Status::FAIL, dd);
132 }
133 }
134 ok &= mz_zip_writer_finalize_archive(mz);
135 if (!ok)
136 {
137 mz_zip_error err = mz_zip_get_last_error(mz);
138 dd << QString("Error: Failed to finalize archive. Error code %1, reason: %2").arg(static_cast<int>(err)).arg(mz_zip_get_error_string(err));
139 return Status(Status::FAIL, dd);
140 }
141
142 return Status::OK;
143}
144
145Status MiniZ::uncompressFolder(QString zipFilePath, QString destPath)
146{
147 DebugDetails dd;
148 dd << "\n[Miniz EXTRACTION diagnostics]\n";
149 dd << QString("Unzip file %1 to folder %2").arg(zipFilePath, destPath);
150
151 if (!QFile::exists(zipFilePath))
152 {
153 dd << QString("Error: Zip file does not exist.");
154 return Status::FILE_NOT_FOUND;
155 }
156
157 QString sBaseDir = QFileInfo(destPath).absolutePath();
158 QDir baseDir(sBaseDir);
159 if (!baseDir.exists())
160 {
161 bool ok = baseDir.mkpath(".");
162 Q_ASSERT(ok);
163 }
164
165 baseDir.makeAbsolute();
166
167 mz_zip_archive* mz = new mz_zip_archive;
168 ScopeGuard mzScopeGuard([&] {
169 delete mz;
170 });
171
172 mz_zip_zero_struct(mz);
173
174 mz_bool ok = mz_zip_reader_init_file(mz, zipFilePath.toUtf8().data(), 0);
175 if (!ok) {
176 mz_zip_error err = mz_zip_get_last_error(mz);
177 dd << QString("Error: Failed to init reader. Error code: %1, reason: %2").arg(static_cast<int>(err)).arg(mz_zip_get_error_string(err));
178 return Status(Status::FAIL, dd);
179 }
180 ScopeGuard mzScopeGuard2([&] {
181 mz_zip_reader_end(mz);
182 });
183
184 int num = mz_zip_reader_get_num_files(mz);
185
186 mz_zip_archive_file_stat* stat = new mz_zip_archive_file_stat;
187 OnScopeExit(delete stat);
188
189 for (int i = 0; i < num; ++i)
190 {
191 ok &= mz_zip_reader_file_stat(mz, i, stat);
192
193 if (stat->m_is_directory)
194 {
195 QString sFolderPath = QString::fromUtf8(stat->m_filename);
196 dd << QString("Make Dir: ").append(sFolderPath);
197
198 bool mkDirOK = baseDir.mkpath(sFolderPath);
199 Q_ASSERT(mkDirOK);
200 if (!mkDirOK)
201 dd << "Make Dir failed.";
202 }
203 }
204
205 for (int i = 0; i < num; ++i)
206 {
207 ok &= mz_zip_reader_file_stat(mz, i, stat);
208
209 if (!stat->m_is_directory)
210 {
211 if (QString(stat->m_filename) == "mimetype") continue;
212 QString sFullPath = baseDir.filePath(QString::fromUtf8(stat->m_filename));
213 dd << QString("Unzip file: ").append(sFullPath);
214 bool b = QFileInfo(sFullPath).absoluteDir().mkpath(".");
215 Q_ASSERT(b);
216
217 bool extractOK = mz_zip_reader_extract_to_file(mz, i, sFullPath.toUtf8(), 0);
218 if (!extractOK)
219 {
220 ok = false;
221 mz_zip_error err = mz_zip_get_last_error(mz);
222 dd << QString("WARNING: Unable to extract file. Error code: %1, reason: %2").arg(static_cast<int>(err)).arg(mz_zip_get_error_string(err));
223 }
224 }
225 }
226
227 if (!ok)
228 {
229 return Status(Status::FAIL, dd);
230 }
231 return Status::OK;
232}
DebugDetails
Definition: pencilerror.h:25
ScopeGuard
Definition: util.h:41
Status
Definition: pencilerror.h:40
QByteArray
QByteArray::constData
const char * constData() const const
QByteArray::data
char * data()
QByteArray::length
int length() const const
QByteArray::toStdString
std::string toStdString() const const
QDir
QDir::mkpath
bool mkpath(const QString &dirPath) const const
QFile::exists
bool exists() const const
QFileInfo
QFileInfo::absoluteDir
QDir absoluteDir() const const
QFileInfo::absolutePath
QString absolutePath() const const
QString
QString::append
QString & append(QChar ch)
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString::endsWith
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
QString::fromUtf8
QString fromUtf8(const char *str, int size)
QString::remove
QString & remove(int position, int n)
QString::toUtf8
QByteArray toUtf8() const const
QStringList
mz_zip_archive_file_stat
Definition: miniz.h:924
mz_zip_archive
Definition: miniz.h:1053
Generated on Thu May 8 2025 04:47:53 for Pencil2D by doxygen 1.9.6 based on revision 4513250b1d5b1a3676ec0e67b06b7a885ceaae39