summaryrefslogtreecommitdiff
path: root/utils/rbutilqt/base/ziputil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/rbutilqt/base/ziputil.cpp')
-rw-r--r--utils/rbutilqt/base/ziputil.cpp302
1 files changed, 302 insertions, 0 deletions
diff --git a/utils/rbutilqt/base/ziputil.cpp b/utils/rbutilqt/base/ziputil.cpp
new file mode 100644
index 0000000000..45119f7d99
--- /dev/null
+++ b/utils/rbutilqt/base/ziputil.cpp
@@ -0,0 +1,302 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2011 Dominik Riebeling
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#include <QtCore>
20#include <QDebug>
21#include "ziputil.h"
22#include "progressloggerinterface.h"
23#include "Logger.h"
24
25#include "quazip/quazip.h"
26#include "quazip/quazipfile.h"
27#include "quazip/quazipfileinfo.h"
28
29
30ZipUtil::ZipUtil(QObject* parent) : ArchiveUtil(parent)
31{
32 m_zip = nullptr;
33}
34
35
36ZipUtil::~ZipUtil()
37{
38 if(m_zip) {
39 delete m_zip;
40 }
41}
42
43//! @brief open zip file.
44//! @param zipfile path to zip file
45//! @param mode open mode (see QuaZip::Mode)
46//! @return true on success, false otherwise
47bool ZipUtil::open(QString& zipfile, QuaZip::Mode mode)
48{
49 m_zip = new QuaZip(zipfile);
50 return m_zip->open(mode);
51}
52
53
54//! @brief close zip file.
55//! @return true on success, false otherwise
56bool ZipUtil::close(void)
57{
58 if(!m_zip) {
59 return false;
60 }
61
62 int error = UNZ_OK;
63 if(m_zip->isOpen()) {
64 m_zip->close();
65 error = m_zip->getZipError();
66 }
67 delete m_zip;
68 m_zip = nullptr;
69 return (error == UNZ_OK) ? true : false;
70}
71
72
73//! @brief extract currently opened archive
74//! @brief dest path to extract archive to, can be filename when extracting a
75//! single file.
76//! @brief file file to extract from archive, full archive if empty.
77//! @return true on success, false otherwise
78bool ZipUtil::extractArchive(const QString& dest, QString file)
79{
80 LOG_INFO() << "extractArchive" << dest << file;
81 bool result = true;
82 if(!m_zip) {
83 return false;
84 }
85 QuaZipFile *currentFile = new QuaZipFile(m_zip);
86 int entries = m_zip->getEntriesCount();
87 int current = 0;
88 // construct the filename when extracting a single file from an archive.
89 // if the given destination is a full path use it as output name,
90 // otherwise use it as path to place the file as named in the archive.
91 QString singleoutfile;
92 if(!file.isEmpty() && QFileInfo(dest).isDir()) {
93 singleoutfile = dest + "/" + file;
94 }
95 else if(!file.isEmpty()){
96 singleoutfile = dest;
97 }
98 for(bool more = m_zip->goToFirstFile(); more; more = m_zip->goToNextFile())
99 {
100 ++current;
101 // if the entry is a path ignore it. Path existence is ensured separately.
102 if(m_zip->getCurrentFileName().split("/").last() == "")
103 continue;
104 // some tools set the MS-DOS file attributes. Check those for D flag,
105 // since in some cases a folder entry does not end with a /
106 QuaZipFileInfo fi;
107 currentFile->getFileInfo(&fi);
108 if(fi.externalAttr & 0x10) // FAT entry bit 4 indicating directory
109 continue;
110
111 QString outfilename;
112 if(!singleoutfile.isEmpty()
113 && QFileInfo(m_zip->getCurrentFileName()).fileName() == file) {
114 outfilename = singleoutfile;
115 }
116 else if(singleoutfile.isEmpty()) {
117 outfilename = dest + "/" + m_zip->getCurrentFileName();
118 }
119 if(outfilename.isEmpty())
120 continue;
121 QFile outputFile(outfilename);
122 // make sure the output path exists
123 if(!QDir().mkpath(QFileInfo(outfilename).absolutePath())) {
124 result = false;
125 emit logItem(tr("Creating output path failed"), LOGERROR);
126 LOG_INFO() << "creating output path failed for:"
127 << outfilename;
128 break;
129 }
130 if(!outputFile.open(QFile::WriteOnly)) {
131 result = false;
132 emit logItem(tr("Creating output file failed"), LOGERROR);
133 LOG_INFO() << "creating output file failed:"
134 << outfilename;
135 break;
136 }
137 currentFile->open(QIODevice::ReadOnly);
138 outputFile.write(currentFile->readAll());
139 if(currentFile->getZipError() != UNZ_OK) {
140 result = false;
141 emit logItem(tr("Error during Zip operation"), LOGERROR);
142 LOG_INFO() << "QuaZip error:" << currentFile->getZipError()
143 << "on file" << currentFile->getFileName();
144 break;
145 }
146 currentFile->close();
147 outputFile.close();
148
149 emit logProgress(current, entries);
150 }
151 delete currentFile;
152 emit logProgress(1, 1);
153
154 return result;
155}
156
157
158//! @brief append a folder to current archive
159//! @param source source folder
160//! @param basedir base folder for archive. Will get stripped from zip paths.
161//! @return true on success, false otherwise
162bool ZipUtil::appendDirToArchive(QString& source, QString& basedir)
163{
164 bool result = true;
165 if(!m_zip || !m_zip->isOpen()) {
166 LOG_INFO() << "Zip file not open!";
167 return false;
168 }
169 // get a list of all files and folders. Needed for progress info and avoids
170 // recursive calls.
171 QDirIterator iterator(source, QDirIterator::Subdirectories);
172 QStringList fileList;
173 while(iterator.hasNext()) {
174 iterator.next();
175 // skip folders, we can't add them.
176 if(!QFileInfo(iterator.filePath()).isDir()) {
177 fileList.append(iterator.filePath());
178 }
179 }
180 LOG_INFO() << "Adding" << fileList.size() << "files to archive";
181
182 int max = fileList.size();
183 for(int i = 0; i < max; i++) {
184 QString current = fileList.at(i);
185 if(!appendFileToArchive(current, basedir)) {
186 LOG_ERROR() << "Error appending file" << current
187 << "to archive" << m_zip->getZipName();
188 result = false;
189 break;
190 }
191 emit logProgress(i, max);
192 }
193 return result;
194}
195
196
197//! @brief append a single file to current archive
198//!
199bool ZipUtil::appendFileToArchive(QString& file, QString& basedir)
200{
201 bool result = true;
202 if(!m_zip || !m_zip->isOpen()) {
203 LOG_ERROR() << "Zip file not open!";
204 return false;
205 }
206 // skip folders, we can't add them.
207 QFileInfo fileinfo(file);
208 if(fileinfo.isDir()) {
209 return false;
210 }
211 QString infile = fileinfo.canonicalFilePath();
212 QString newfile = infile;
213 newfile.remove(QDir(basedir).canonicalPath() + "/");
214
215 QuaZipFile fout(m_zip);
216 QFile fin(file);
217
218 if(!fin.open(QFile::ReadOnly)) {
219 LOG_ERROR() << "Could not open file for reading:" << file;
220 return false;
221 }
222 if(!fout.open(QIODevice::WriteOnly, QuaZipNewInfo(newfile, infile))) {
223 fin.close();
224 LOG_ERROR() << "Could not open file for writing:" << newfile;
225 return false;
226 }
227
228 result = (fout.write(fin.readAll()) < 0) ? false : true;
229 fin.close();
230 fout.close();
231 return result;
232}
233
234
235//! @brief calculate total size of extracted files
236qint64 ZipUtil::totalUncompressedSize(unsigned int clustersize)
237{
238 qint64 uncompressed = 0;
239
240 QList<QuaZipFileInfo> items = contentProperties();
241 if(items.size() == 0) {
242 return -1;
243 }
244 int max = items.size();
245 if(clustersize > 0) {
246 for(int i = 0; i < max; ++i) {
247 qint64 item = items.at(i).uncompressedSize;
248 uncompressed += (item + clustersize - (item % clustersize));
249 }
250 }
251 else {
252 for(int i = 0; i < max; ++i) {
253 uncompressed += items.at(i).uncompressedSize;
254 }
255 }
256 if(clustersize > 0) {
257 LOG_INFO() << "calculation rounded to cluster size for each file:"
258 << clustersize;
259 }
260 LOG_INFO() << "size of archive files uncompressed:"
261 << uncompressed;
262 return uncompressed;
263}
264
265
266QStringList ZipUtil::files(void)
267{
268 QList<QuaZipFileInfo> items = contentProperties();
269 QStringList fileList;
270 if(items.size() == 0) {
271 return fileList;
272 }
273 int max = items.size();
274 for(int i = 0; i < max; ++i) {
275 fileList.append(items.at(i).name);
276 }
277 return fileList;
278}
279
280
281QList<QuaZipFileInfo> ZipUtil::contentProperties()
282{
283 QList<QuaZipFileInfo> items;
284 if(!m_zip || !m_zip->isOpen()) {
285 LOG_ERROR() << "Zip file not open!";
286 return items;
287 }
288 QuaZipFileInfo info;
289 QuaZipFile currentFile(m_zip);
290 for(bool more = m_zip->goToFirstFile(); more; more = m_zip->goToNextFile())
291 {
292 currentFile.getFileInfo(&info);
293 if(currentFile.getZipError() != UNZ_OK) {
294 LOG_ERROR() << "QuaZip error:" << currentFile.getZipError()
295 << "on file" << currentFile.getFileName();
296 return QList<QuaZipFileInfo>();
297 }
298 items.append(info);
299 }
300 return items;
301}
302