1 /* This file is part of the KDE project
2 Copyright (C) 2000-2002 David Faure <faure@kde.org>
3 Copyright (C) 2010 C. Boemann <cbo@boemann.dk>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "KoZipStore.h"
22 #include "KoStore_p.h"
23
24 #include <QBuffer>
25 #include <QByteArray>
26
27 #include <kzip.h>
28 #include <StoreDebug.h>
29
30 #include <QUrl>
31 #include <KoNetAccess.h>
32
KoZipStore(const QString & _filename,Mode mode,const QByteArray & appIdentification,bool writeMimetype)33 KoZipStore::KoZipStore(const QString & _filename, Mode mode, const QByteArray & appIdentification,
34 bool writeMimetype)
35 : KoStore(mode, writeMimetype)
36 {
37 debugStore << "KoZipStore Constructor filename =" << _filename
38 << " mode = " << int(mode)
39 << " mimetype = " << appIdentification << endl;
40 Q_D(KoStore);
41
42 d->localFileName = _filename;
43
44 m_pZip = new KZip(_filename);
45
46 init(appIdentification); // open the zip file and init some vars
47 }
48
KoZipStore(QIODevice * dev,Mode mode,const QByteArray & appIdentification,bool writeMimetype)49 KoZipStore::KoZipStore(QIODevice *dev, Mode mode, const QByteArray & appIdentification,
50 bool writeMimetype)
51 : KoStore(mode, writeMimetype)
52 {
53 m_pZip = new KZip(dev);
54 init(appIdentification);
55 }
56
KoZipStore(QWidget * window,const QUrl & _url,const QString & _filename,Mode mode,const QByteArray & appIdentification,bool writeMimetype)57 KoZipStore::KoZipStore(QWidget* window, const QUrl &_url, const QString & _filename, Mode mode,
58 const QByteArray & appIdentification, bool writeMimetype)
59 : KoStore(mode, writeMimetype)
60 {
61 debugStore << "KoZipStore Constructor url" << _url.url(QUrl::PreferLocalFile)
62 << " filename = " << _filename
63 << " mode = " << int(mode)
64 << " mimetype = " << appIdentification << endl;
65 Q_D(KoStore);
66
67 d->url = _url;
68 d->window = window;
69
70 if (mode == KoStore::Read) {
71 d->fileMode = KoStorePrivate::RemoteRead;
72 d->localFileName = _filename;
73
74 } else {
75 d->fileMode = KoStorePrivate::RemoteWrite;
76 d->localFileName = QLatin1String("/tmp/kozip"); // ### FIXME with KTempFile
77 }
78
79 m_pZip = new KZip(d->localFileName);
80 init(appIdentification); // open the zip file and init some vars
81 }
82
~KoZipStore()83 KoZipStore::~KoZipStore()
84 {
85 Q_D(KoStore);
86 debugStore << "KoZipStore::~KoZipStore";
87 if (!d->finalized)
88 finalize(); // ### no error checking when the app forgot to call finalize itself
89 delete m_pZip;
90
91 // Now we have still some job to do for remote files.
92 if (d->fileMode == KoStorePrivate::RemoteRead) {
93 KIO::NetAccess::removeTempFile(d->localFileName);
94 } else if (d->fileMode == KoStorePrivate::RemoteWrite) {
95 KIO::NetAccess::upload(d->localFileName, d->url, d->window);
96 // ### FIXME: delete temp file
97 }
98 }
99
init(const QByteArray & appIdentification)100 void KoZipStore::init(const QByteArray& appIdentification)
101 {
102 Q_D(KoStore);
103
104 m_currentDir = 0;
105 d->good = m_pZip->open(d->mode == Write ? QIODevice::WriteOnly : QIODevice::ReadOnly);
106
107 if (!d->good)
108 return;
109
110 if (d->mode == Write) {
111 //debugStore <<"KoZipStore::init writing mimetype" << appIdentification;
112
113 m_pZip->setCompression(KZip::NoCompression);
114 m_pZip->setExtraField(KZip::NoExtraField);
115
116 // Write identification
117 if (d->writeMimetype) {
118 (void)m_pZip->writeFile(QLatin1String("mimetype"), appIdentification);
119 }
120
121 m_pZip->setCompression(KZip::DeflateCompression);
122 // We don't need the extra field in Calligra - so we leave it as "no extra field".
123 } else {
124 d->good = m_pZip->directory() != 0;
125 }
126 }
127
setCompressionEnabled(bool e)128 void KoZipStore::setCompressionEnabled(bool e)
129 {
130 if (e) {
131 m_pZip->setCompression(KZip::DeflateCompression);
132 } else {
133 m_pZip->setCompression(KZip::NoCompression);
134 }
135 }
136
doFinalize()137 bool KoZipStore::doFinalize()
138 {
139 return m_pZip->close();
140 }
141
openWrite(const QString & name)142 bool KoZipStore::openWrite(const QString& name)
143 {
144 Q_D(KoStore);
145 d->stream = 0; // Don't use!
146 return m_pZip->prepareWriting(name, "", "" /*m_pZip->rootDir()->user(), m_pZip->rootDir()->group()*/, 0);
147 }
148
openRead(const QString & name)149 bool KoZipStore::openRead(const QString& name)
150 {
151 Q_D(KoStore);
152 const KArchiveEntry * entry = m_pZip->directory()->entry(name);
153 if (entry == 0) {
154 return false;
155 }
156 if (entry->isDirectory()) {
157 warnStore << name << " is a directory !";
158 return false;
159 }
160 // Must cast to KZipFileEntry, not only KArchiveFile, because device() isn't virtual!
161 const KZipFileEntry * f = static_cast<const KZipFileEntry *>(entry);
162 delete d->stream;
163 d->stream = f->createDevice();
164 d->size = f->size();
165 return true;
166 }
167
write(const char * _data,qint64 _len)168 qint64 KoZipStore::write(const char* _data, qint64 _len)
169 {
170 Q_D(KoStore);
171 if (_len == 0) return 0;
172 //debugStore <<"KoZipStore::write" << _len;
173
174 if (!d->isOpen) {
175 errorStore << "KoStore: You must open before writing" << endl;
176 return 0;
177 }
178 if (d->mode != Write) {
179 errorStore << "KoStore: Can not write to store that is opened for reading" << endl;
180 return 0;
181 }
182
183 d->size += _len;
184 if (m_pZip->writeData(_data, _len)) // writeData returns a bool!
185 return _len;
186 return 0;
187 }
188
directoryList() const189 QStringList KoZipStore::directoryList() const
190 {
191 QStringList retval;
192 const KArchiveDirectory *directory = m_pZip->directory();
193 foreach(const QString &name, directory->entries()) {
194 const KArchiveEntry* fileArchiveEntry = m_pZip->directory()->entry(name);
195 if (fileArchiveEntry->isDirectory()) {
196 retval << name;
197 }
198 }
199 return retval;
200 }
201
closeWrite()202 bool KoZipStore::closeWrite()
203 {
204 Q_D(KoStore);
205 debugStore << "Wrote file" << d->fileName << " into ZIP archive. size" << d->size;
206 return m_pZip->finishWriting(d->size);
207 }
208
enterRelativeDirectory(const QString & dirName)209 bool KoZipStore::enterRelativeDirectory(const QString& dirName)
210 {
211 Q_D(KoStore);
212 if (d->mode == Read) {
213 if (!m_currentDir) {
214 m_currentDir = m_pZip->directory(); // initialize
215 Q_ASSERT(d->currentPath.isEmpty());
216 }
217 const KArchiveEntry *entry = m_currentDir->entry(dirName);
218 if (entry && entry->isDirectory()) {
219 m_currentDir = dynamic_cast<const KArchiveDirectory*>(entry);
220 return m_currentDir != 0;
221 }
222 return false;
223 } else // Write, no checking here
224 return true;
225 }
226
enterAbsoluteDirectory(const QString & path)227 bool KoZipStore::enterAbsoluteDirectory(const QString& path)
228 {
229 if (path.isEmpty()) {
230 m_currentDir = 0;
231 return true;
232 }
233 m_currentDir = dynamic_cast<const KArchiveDirectory*>(m_pZip->directory()->entry(path));
234 Q_ASSERT(m_currentDir);
235 return m_currentDir != 0;
236 }
237
fileExists(const QString & absPath) const238 bool KoZipStore::fileExists(const QString& absPath) const
239 {
240 const KArchiveEntry *entry = m_pZip->directory()->entry(absPath);
241 return entry && entry->isFile();
242 }
243