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