diff options
Diffstat (limited to 'utils/rbutilqt/base/ziputil.cpp')
-rw-r--r-- | utils/rbutilqt/base/ziputil.cpp | 302 |
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 | |||
30 | ZipUtil::ZipUtil(QObject* parent) : ArchiveUtil(parent) | ||
31 | { | ||
32 | m_zip = nullptr; | ||
33 | } | ||
34 | |||
35 | |||
36 | ZipUtil::~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 | ||
47 | bool 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 | ||
56 | bool 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 | ||
78 | bool 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 | ||
162 | bool 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 | //! | ||
199 | bool 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 | ||
236 | qint64 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 | |||
266 | QStringList 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 | |||
281 | QList<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 | |||