Changeset View
Changeset View
Standalone View
Standalone View
libs/store/KoQuaZipStore.cpp
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | * Copyright (C) 2019 Boudewijn Rempt <boud@valdyas.org> | ||||
3 | * | ||||
4 | * This library is free software; you can redistribute it and/or | ||||
5 | * modify it under the terms of the GNU Library General Public | ||||
6 | * License as published by the Free Software Foundation; either | ||||
7 | * version 2 of the License, or (at your option) any later version. | ||||
8 | * | ||||
9 | * This library is distributed in the hope that it will be useful, | ||||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
12 | * Library General Public License for more details. | ||||
13 | * | ||||
14 | * You should have received a copy of the GNU Library General Public License | ||||
15 | * along with this library; see the file COPYING.LIB. If not, write to | ||||
16 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||||
17 | * Boston, MA 02110-1301, USA. | ||||
18 | */ | ||||
19 | #include "KoQuaZipStore.h" | ||||
20 | #include "KoStore_p.h" | ||||
21 | | ||||
22 | #include <StoreDebug.h> | ||||
23 | | ||||
24 | #include <zlib.h> | ||||
25 | #include <quazip.h> | ||||
26 | #include <quazipfile.h> | ||||
27 | #include <quazipdir.h> | ||||
28 | #include <quazipfileinfo.h> | ||||
29 | #include <quazipnewinfo.h> | ||||
30 | | ||||
31 | #include <QTemporaryFile> | ||||
32 | | ||||
33 | #include <KConfig> | ||||
34 | #include <KSharedConfig> | ||||
35 | #include <KConfigGroup> | ||||
36 | | ||||
37 | struct KoQuaZipStore::Private { | ||||
38 | | ||||
39 | Private() {} | ||||
40 | ~Private() {} | ||||
41 | | ||||
42 | QuaZip *archive {0}; | ||||
43 | QuaZipFile *currentFile {0}; | ||||
44 | int compressionLevel {Z_DEFAULT_COMPRESSION}; | ||||
45 | bool usingSaveFile {false}; | ||||
46 | }; | ||||
47 | | ||||
48 | | ||||
49 | KoQuaZipStore::KoQuaZipStore(const QString &_filename, KoStore::Mode _mode, const QByteArray &appIdentification, bool writeMimetype) | ||||
50 | : KoStore(_mode, writeMimetype) | ||||
51 | , dd(new Private()) | ||||
52 | { | ||||
53 | Q_D(KoStore); | ||||
54 | d->localFileName = _filename; | ||||
55 | dd->archive = new QuaZip(_filename); | ||||
56 | init(appIdentification); | ||||
57 | | ||||
58 | } | ||||
59 | | ||||
60 | KoQuaZipStore::KoQuaZipStore(QIODevice *dev, KoStore::Mode _mode, const QByteArray &appIdentification, bool writeMimetype) | ||||
61 | : KoStore(_mode, writeMimetype) | ||||
62 | , dd(new Private()) | ||||
63 | { | ||||
64 | Q_D(KoStore); | ||||
65 | dd->archive = new QuaZip(dev); | ||||
66 | init(appIdentification); | ||||
67 | } | ||||
68 | | ||||
69 | KoQuaZipStore::~KoQuaZipStore() | ||||
70 | { | ||||
71 | Q_D(KoStore); | ||||
72 | | ||||
73 | if (dd->currentFile && dd->currentFile->isOpen()) { | ||||
74 | dd->currentFile->close(); | ||||
75 | } | ||||
76 | | ||||
77 | if (!d->finalized) { | ||||
78 | finalize(); | ||||
79 | } | ||||
80 | | ||||
81 | delete dd->archive; | ||||
82 | delete dd->currentFile; | ||||
83 | } | ||||
84 | | ||||
85 | void KoQuaZipStore::setCompressionEnabled(bool enabled) | ||||
86 | { | ||||
87 | | ||||
88 | if (enabled) { | ||||
89 | dd->compressionLevel = Z_BEST_COMPRESSION; | ||||
90 | } | ||||
91 | else { | ||||
92 | dd->compressionLevel = Z_NO_COMPRESSION; | ||||
93 | } | ||||
94 | } | ||||
95 | | ||||
96 | qint64 KoQuaZipStore::write(const char *_data, qint64 _len) | ||||
97 | { | ||||
98 | Q_D(KoStore); | ||||
99 | if (_len == 0) return 0; | ||||
100 | | ||||
101 | if (!d->isOpen) { | ||||
102 | errorStore << "KoStore: You must open before writing" << endl; | ||||
103 | return 0; | ||||
104 | } | ||||
105 | | ||||
106 | if (d->mode != Write) { | ||||
107 | errorStore << "KoStore: Can not write to store that is opened for reading" << endl; | ||||
108 | return 0; | ||||
109 | } | ||||
110 | | ||||
111 | d->size += _len; | ||||
112 | if (dd->currentFile->write(_data, _len)) { // writeData returns a bool! | ||||
113 | return _len; | ||||
114 | } | ||||
115 | return 0; | ||||
116 | } | ||||
117 | | ||||
118 | QStringList KoQuaZipStore::directoryList() const | ||||
119 | { | ||||
120 | return dd->archive->getFileNameList(); | ||||
121 | } | ||||
122 | | ||||
123 | void KoQuaZipStore::init(const QByteArray &appIdentification) | ||||
124 | { | ||||
125 | Q_D(KoStore); | ||||
126 | | ||||
127 | bool enableZip64 = false; | ||||
128 | if (appIdentification == "application/x-krita") { | ||||
129 | enableZip64 = KSharedConfig::openConfig()->group("").readEntry<bool>("UseZip64", false); | ||||
130 | } | ||||
131 | dd->archive->setZip64Enabled(enableZip64); | ||||
132 | dd->archive->setFileNameCodec("utf8"); | ||||
133 | dd->usingSaveFile = dd->archive->getIoDevice() && dd->archive->getIoDevice()->inherits("QSaveFile"); | ||||
134 | dd->archive->setAutoClose(!dd->usingSaveFile); | ||||
135 | | ||||
136 | d->good = dd->archive->open(d->mode == Write ? QuaZip::mdCreate : QuaZip::mdUnzip); | ||||
137 | | ||||
138 | if (!d->good) { | ||||
139 | return; | ||||
140 | } | ||||
141 | | ||||
142 | if (d->mode == Write) { | ||||
143 | if (d->writeMimetype) { | ||||
144 | QuaZipFile f(dd->archive); | ||||
145 | QuaZipNewInfo newInfo("mimetype"); | ||||
146 | newInfo.setPermissions(QFileDevice::ReadOwner | QFileDevice::ReadGroup | QFileDevice::ReadOther); | ||||
147 | if (!f.open(QIODevice::WriteOnly, newInfo, 0, 0, Z_DEFLATED, Z_NO_COMPRESSION)) { | ||||
148 | d->good = false; | ||||
149 | return; | ||||
150 | } | ||||
151 | f.write(appIdentification); | ||||
152 | f.close(); | ||||
153 | } | ||||
154 | } | ||||
155 | else { | ||||
156 | d->good = dd->archive->getEntriesCount(); | ||||
157 | } | ||||
158 | } | ||||
159 | | ||||
160 | bool KoQuaZipStore::doFinalize() | ||||
161 | { | ||||
162 | Q_D(KoStore); | ||||
163 | | ||||
164 | d->stream = 0; | ||||
165 | if (!dd->usingSaveFile) { | ||||
166 | dd->archive->close(); | ||||
167 | } | ||||
168 | return dd->archive->getZipError() == ZIP_OK; | ||||
169 | | ||||
170 | } | ||||
171 | | ||||
172 | bool KoQuaZipStore::openWrite(const QString &name) | ||||
173 | { | ||||
174 | Q_D(KoStore); | ||||
175 | QString fixedPath = name; | ||||
176 | fixedPath.replace("//", "/"); | ||||
177 | | ||||
178 | delete d->stream; | ||||
179 | d->stream = 0; // Not used when writing | ||||
180 | | ||||
181 | delete dd->currentFile; | ||||
182 | dd->currentFile = new QuaZipFile(dd->archive); | ||||
183 | QuaZipNewInfo newInfo(fixedPath); | ||||
184 | newInfo.setPermissions(QFileDevice::ReadOwner | QFileDevice::ReadGroup | QFileDevice::ReadOther); | ||||
185 | bool r = dd->currentFile->open(QIODevice::WriteOnly, newInfo, 0, 0, Z_DEFLATED, dd->compressionLevel); | ||||
186 | if (!r) { | ||||
187 | qWarning() << "Could not open" << name << dd->currentFile->getZipError(); | ||||
188 | } | ||||
189 | return r; | ||||
190 | } | ||||
191 | | ||||
192 | bool KoQuaZipStore::openRead(const QString &name) | ||||
193 | { | ||||
194 | Q_D(KoStore); | ||||
195 | QString fixedPath = name; | ||||
196 | fixedPath.replace("//", "/"); | ||||
197 | | ||||
198 | delete d->stream; | ||||
199 | d->stream = 0; | ||||
200 | delete dd->currentFile; | ||||
201 | dd->currentFile = 0; | ||||
202 | | ||||
203 | if (!currentPath().isEmpty() && !fixedPath.startsWith(currentPath())) { | ||||
204 | fixedPath = currentPath() + '/' + fixedPath; | ||||
205 | } | ||||
206 | | ||||
207 | if (!dd->archive->setCurrentFile(fixedPath)) { | ||||
208 | warnStore << "\t\tCould not set current file" << dd->archive->getZipError(); | ||||
209 | return false; | ||||
210 | } | ||||
211 | | ||||
212 | dd->currentFile = new QuaZipFile(dd->archive); | ||||
213 | if (!dd->currentFile->open(QIODevice::ReadOnly)) { | ||||
214 | warnStore << "\t\t\tBut could not open!!!" << dd->archive->getZipError(); | ||||
215 | return false; | ||||
216 | } | ||||
217 | d->stream = dd->currentFile; | ||||
218 | d->size = dd->currentFile->size(); | ||||
219 | return true; | ||||
220 | } | ||||
221 | | ||||
222 | bool KoQuaZipStore::closeWrite() | ||||
223 | { | ||||
224 | Q_D(KoStore); | ||||
225 | dd->currentFile->close(); | ||||
226 | d->stream = 0; | ||||
227 | return dd->currentFile->getZipError() == ZIP_OK; | ||||
228 | } | ||||
229 | | ||||
230 | bool KoQuaZipStore::closeRead() | ||||
231 | { | ||||
232 | Q_D(KoStore); | ||||
233 | d->stream = 0; | ||||
234 | return true; | ||||
235 | } | ||||
236 | | ||||
237 | bool KoQuaZipStore::enterRelativeDirectory(const QString &) | ||||
238 | { | ||||
239 | return true; | ||||
240 | } | ||||
241 | | ||||
242 | bool KoQuaZipStore::enterAbsoluteDirectory(const QString &path) | ||||
243 | { | ||||
244 | QString fixedPath = path; | ||||
245 | fixedPath.replace("//", "/"); | ||||
246 | | ||||
247 | if (fixedPath.isEmpty()) { | ||||
248 | return true; | ||||
249 | } | ||||
250 | QuaZipDir currentDir (dd->archive, fixedPath); | ||||
251 | return currentDir.exists(); | ||||
252 | } | ||||
253 | | ||||
254 | bool KoQuaZipStore::fileExists(const QString &absPath) const | ||||
255 | { | ||||
256 | QString fixedPath = absPath; | ||||
257 | fixedPath.replace("//", "/"); | ||||
258 | return dd->archive->getFileNameList().contains(fixedPath); | ||||
259 | } |