Krita Source Code Documentation
Loading...
Searching...
No Matches
KoStore.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 SPDX-FileCopyrightText: 1998, 1999 Torben Weis <weis@kde.org>
3 SPDX-FileCopyrightText: 2000-2002 David Faure <faure@kde.org>, Werner Trobin <trobin@kde.org>
4 SPDX-FileCopyrightText: 2010 C. Boemann <cbo@boemann.dk>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "KoStore.h"
10#include "KoStore_p.h"
11
12#include "KoQuaZipStore.h"
13#include "KoDirectoryStore.h"
14
15#include <QBuffer>
16#include <QFileInfo>
17#include <QFile>
18
19#include <QUrl>
20#include <StoreDebug.h>
21
22#include <KConfig>
23#include <KSharedConfig>
24#include <KConfigGroup>
25
26
27#define DefaultFormat KoStore::Zip
28
29static KoStore::Backend determineBackend(QIODevice *dev)
30{
31 unsigned char buf[5];
32 if (dev->read((char *)buf, 4) < 4)
33 return DefaultFormat; // will create a "bad" store (bad()==true)
34 if (buf[0] == 'P' && buf[1] == 'K' && buf[2] == 3 && buf[3] == 4)
35 return KoStore::Zip;
36 return DefaultFormat; // fallback
37}
38
39KoStore* KoStore::createStore(const QString& fileName, Mode mode, const QByteArray & appIdentification, Backend backend, bool writeMimetype)
40{
41 if (backend == Auto) {
42 if (mode == KoStore::Write)
43 backend = DefaultFormat;
44 else {
45 QFileInfo inf(fileName);
46 if (inf.isDir())
47 backend = Directory;
48 else {
49 QFile file(fileName);
50 if (file.open(QIODevice::ReadOnly))
51 backend = determineBackend(&file);
52 else
53 backend = DefaultFormat; // will create a "bad" store (bad()==true)
54 }
55 }
56 }
57 switch (backend) {
58 case Zip:
59 return new KoQuaZipStore(fileName, mode, appIdentification, writeMimetype);
60 case Directory:
61 return new KoDirectoryStore(fileName /* should be a dir name.... */, mode, writeMimetype);
62 default:
63 warnStore << "Unsupported backend requested for KoStore : " << backend;
64 return 0;
65 }
66}
67
68KoStore* KoStore::createStore(QIODevice *device, Mode mode, const QByteArray & appIdentification, Backend backend, bool writeMimetype)
69{
70 if (backend == Auto) {
71 if (mode == KoStore::Write)
72 backend = DefaultFormat;
73 else {
74 if (device->open(QIODevice::ReadOnly)) {
75 backend = determineBackend(device);
76 device->close();
77 }
78 }
79 }
80 switch (backend) {
81 case Directory:
82 errorStore << "Can't create a Directory store for a memory buffer!" << Qt::endl;
83 return 0;
84 case Zip:
85 return new KoQuaZipStore(device, mode, appIdentification, writeMimetype);
86 default:
87 warnStore << "Unsupported backend requested for KoStore : " << backend;
88 return 0;
89 }
90}
91
92namespace
93{
94const char ROOTPART[] = "root";
95const char MAINNAME[] = "maindoc.xml";
96}
97
98KoStore::KoStore(Mode mode, bool writeMimetype)
99 : d_ptr(new KoStorePrivate(this, mode, writeMimetype))
100{}
101
103{
104 Q_D(KoStore);
105 delete d->stream;
106 delete d_ptr;
107}
108
109bool KoStore::open(const QString & _name)
110{
111 Q_D(KoStore);
112 // This also converts from relative to absolute, i.e. merges the currentPath()
113 d->fileName = d->toExternalNaming(_name);
114
115 debugStore << "KOStore" << _name << d->fileName;
116
117 if (d->isOpen) {
118 warnStore << "Store is already opened, missing close";
119 return false;
120 }
121
122 if (d->fileName.length() > 512) {
123 errorStore << "KoStore: Filename " << d->fileName << " is too long" << Qt::endl;
124 return false;
125 }
126
127 if (d->mode == Write) {
128 debugStore << "opening for writing" << d->fileName;
129 if (d->filesList.contains(d->fileName)) {
130 warnStore << "KoStore: Duplicate filename" << d->fileName;
131 return false;
132 }
133
134 d->filesList.append(d->fileName);
135
136 d->size = 0;
137 if (!openWrite(d->fileName))
138 return false;
139 } else if (d->mode == Read) {
140 debugStore << "Opening for reading" << d->fileName;
141 if (!openRead(d->fileName))
142 return false;
143 } else
144 return false;
145
146 d->isOpen = true;
147 return true;
148}
149
150bool KoStore::isOpen() const
151{
152 Q_D(const KoStore);
153 return d->isOpen;
154}
155
157{
158 Q_D(KoStore);
159 if (!d->isOpen) {
160 warnStore << "You must open before closing";
161 return false;
162 }
163
164 bool ret = d->mode == Write ? closeWrite() : closeRead();
165 delete d->stream;
166 d->stream = 0;
167 d->isOpen = false;
168 return ret;
169}
170
171QIODevice* KoStore::device() const
172{
173 Q_D(const KoStore);
174 if (!d->isOpen)
175 warnStore << "You must open before asking for a device";
176 if (d->mode != Read)
177 warnStore << "Can not get device from store that is opened for writing";
178 return d->stream;
179}
180
181QByteArray KoStore::read(qint64 max)
182{
183 Q_D(KoStore);
184 QByteArray data;
185
186 if (!d->isOpen) {
187 warnStore << "You must open before reading";
188 return data;
189 }
190 if (d->mode != Read) {
191 errorStore << "KoStore: Can not read from store that is opened for writing" << Qt::endl;
192 return data;
193 }
194
195 return d->stream->read(max);
196}
197
198qint64 KoStore::write(const QByteArray& data)
199{
200 return write(data.constData(), data.size()); // see below
201}
202
203qint64 KoStore::read(char *_buffer, qint64 _len)
204{
205 Q_D(KoStore);
206 if (!d->isOpen) {
207 errorStore << "KoStore: You must open before reading" << Qt::endl;
208 return -1;
209 }
210 if (d->mode != Read) {
211 errorStore << "KoStore: Can not read from store that is opened for writing" << Qt::endl;
212 return -1;
213 }
214
215 return d->stream->read(_buffer, _len);
216}
217
218qint64 KoStore::write(const char* _data, qint64 _len)
219{
220 Q_D(KoStore);
221 if (_len == 0) return 0;
222
223 if (!d->isOpen) {
224 errorStore << "KoStore: You must open before writing" << Qt::endl;
225 return 0;
226 }
227 if (d->mode != Write) {
228 errorStore << "KoStore: Can not write to store that is opened for reading" << Qt::endl;
229 return 0;
230 }
231
232 int nwritten = d->stream->write(_data, _len);
233 Q_ASSERT(nwritten == (int)_len);
234 d->size += nwritten;
235
236 return nwritten;
237}
238
239qint64 KoStore::size() const
240{
241 Q_D(const KoStore);
242 if (!d->isOpen) {
243 warnStore << "You must open before asking for a size";
244 return static_cast<qint64>(-1);
245 }
246 if (d->mode != Read) {
247 warnStore << "Can not get size from store that is opened for writing";
248 return static_cast<qint64>(-1);
249 }
250 return d->size;
251}
252
253bool KoStore::enterDirectory(const QString &directory)
254{
255 Q_D(KoStore);
256 //debugStore <<"enterDirectory" << directory;
257 int pos;
258 bool success = true;
259 QString tmp(directory);
260
261 while ((pos = tmp.indexOf('/')) != -1 &&
262 (success = d->enterDirectoryInternal(tmp.left(pos))))
263 tmp.remove(0, pos + 1);
264
265 if (success && !tmp.isEmpty())
266 return d->enterDirectoryInternal(tmp);
267 return success;
268}
269
271{
272 Q_D(KoStore);
273 if (d->currentPath.isEmpty())
274 return false;
275
276 d->currentPath.pop_back();
277
279}
280
281QString KoStore::currentPath() const
282{
283 Q_D(const KoStore);
284 QString path;
285 QStringList::ConstIterator it = d->currentPath.begin();
286 QStringList::ConstIterator end = d->currentPath.end();
287 for (; it != end; ++it) {
288 path += *it;
289 path += '/';
290 }
291 return path;
292}
293
295{
296 Q_D(KoStore);
297 d->directoryStack.push(currentPath());
298}
299
301{
302 Q_D(KoStore);
303 d->currentPath.clear();
304 enterAbsoluteDirectory(QString());
305 enterDirectory(d->directoryStack.pop());
306}
307
308bool KoStore::extractFile(const QString &srcName, QByteArray &data)
309{
310 Q_D(KoStore);
311 QBuffer buffer(&data);
312 return d->extractFile(srcName, buffer);
313}
314
315bool KoStorePrivate::extractFile(const QString &srcName, QIODevice &buffer)
316{
317 if (!q->open(srcName))
318 return false;
319
320 if (!buffer.open(QIODevice::WriteOnly)) {
321 q->close();
322 return false;
323 }
324
325 QByteArray data;
326 data.resize(8 * 1024);
327 uint total = 0;
328 for (int block = 0; (block = q->read(data.data(), data.size())) > 0; total += block) {
329 buffer.write(data.data(), block);
330 }
331
332 if (q->size() != static_cast<qint64>(-1))
333 Q_ASSERT(total == q->size());
334
335 buffer.close();
336 q->close();
337
338 return true;
339}
340
341bool KoStore::seek(qint64 pos)
342{
343 Q_D(KoStore);
344 return d->stream->seek(pos);
345}
346
347qint64 KoStore::pos() const
348{
349 Q_D(const KoStore);
350 return d->stream->pos();
351}
352
353bool KoStore::atEnd() const
354{
355 Q_D(const KoStore);
356 return d->stream->atEnd();
357}
358
359// See the specification for details of what this function does.
360QString KoStorePrivate::toExternalNaming(const QString & _internalNaming) const
361{
362 if (_internalNaming == ROOTPART)
363 return q->currentPath() + MAINNAME;
364
365 QString intern;
366 if (_internalNaming.startsWith("tar:/")) // absolute reference
367 intern = _internalNaming.mid(5); // remove protocol
368 else
369 intern = q->currentPath() + _internalNaming;
370
371 return intern;
372}
373
374
375bool KoStorePrivate::enterDirectoryInternal(const QString &directory)
376{
377 if (q->enterRelativeDirectory(directory)) {
378 currentPath.append(directory);
379 return true;
380 }
381 return false;
382}
383
384bool KoStore::hasFile(const QString& fileName) const
385{
386 Q_D(const KoStore);
387 return fileExists(d->toExternalNaming(fileName));
388}
389
390bool KoStore::hasDirectory(const QString &directoryName)
391{
392 return enterAbsoluteDirectory(directoryName);
393}
394
396{
397 Q_D(KoStore);
398 Q_ASSERT(!d->finalized); // call this only once!
399 d->finalized = true;
400 return doFinalize();
401}
402
404{
405}
406
407void KoStore::setSubstitution(const QString &name, const QString &substitution)
408{
409 Q_D(KoStore);
410 d->substituteThis = name;
411 d->substituteWith = substitution;
412}
413
414bool KoStore::bad() const
415{
416 Q_D(const KoStore);
417 return !d->good;
418}
419
421{
422 Q_D(const KoStore);
423 return d->mode;
424}
425
427{
428 return QStringList();
429}
QList< QString > QStringList
unsigned int uint
#define DefaultFormat
Definition KoStore.cpp:27
static KoStore::Backend determineBackend(QIODevice *dev)
Definition KoStore.cpp:29
#define debugStore
Definition StoreDebug.h:15
#define warnStore
Definition StoreDebug.h:16
#define errorStore
Definition StoreDebug.h:17
bool enterDirectoryInternal(const QString &directory)
Definition KoStore.cpp:375
QStringList currentPath
The "current directory" (path)
Definition KoStore_p.h:70
KoStore * q
Definition KoStore_p.h:59
bool extractFile(const QString &sourceName, QIODevice &buffer)
Definition KoStore.cpp:315
QString toExternalNaming(const QString &internalNaming) const
Definition KoStore.cpp:360
qint64 write(const QByteArray &data)
Definition KoStore.cpp:198
QIODevice * device() const
Definition KoStore.cpp:171
KoStorePrivate * d_ptr
Definition KoStore.h:278
bool close()
Definition KoStore.cpp:156
@ Read
Definition KoStore.h:29
@ Write
Definition KoStore.h:29
virtual bool closeRead()=0
qint64 size() const
Definition KoStore.cpp:239
virtual bool openWrite(const QString &name)=0
bool isOpen() const
Definition KoStore.cpp:150
virtual bool doFinalize()
Definition KoStore.h:230
void setSubstitution(const QString &name, const QString &substitution)
When reading, in the paths in the store where name occurs, substitution is used.
Definition KoStore.cpp:407
bool extractFile(const QString &sourceName, QByteArray &data)
Definition KoStore.cpp:308
virtual bool closeWrite()=0
virtual bool fileExists(const QString &absPath) const =0
virtual bool enterRelativeDirectory(const QString &dirName)=0
@ Auto
Definition KoStore.h:30
@ Zip
Definition KoStore.h:30
@ Directory
Definition KoStore.h:30
virtual void setCompressionEnabled(bool e)
Definition KoStore.cpp:403
Mode mode() const
Definition KoStore.cpp:420
void pushDirectory()
Definition KoStore.cpp:294
void popDirectory()
Definition KoStore.cpp:300
QString currentPath() const
Definition KoStore.cpp:281
virtual bool openRead(const QString &name)=0
virtual QStringList directoryList() const
Definition KoStore.cpp:426
bool leaveDirectory()
Definition KoStore.cpp:270
bool seek(qint64 pos)
See QIODevice.
Definition KoStore.cpp:341
bool bad() const
Definition KoStore.cpp:414
virtual bool enterDirectory(const QString &directory)
Definition KoStore.cpp:253
static KoStore * createStore(const QString &fileName, Mode mode, const QByteArray &appIdentification=QByteArray(), Backend backend=Auto, bool writeMimetype=true)
Definition KoStore.cpp:39
bool finalize()
Definition KoStore.cpp:395
bool atEnd() const
Definition KoStore.cpp:353
qint64 pos() const
Definition KoStore.cpp:347
virtual bool enterAbsoluteDirectory(const QString &path)=0
KoStore(Mode mode, bool writeMimetype=true)
Definition KoStore.cpp:98
bool hasFile(const QString &fileName) const
Definition KoStore.cpp:384
virtual ~KoStore()
Definition KoStore.cpp:102
bool open(const QString &name)
Definition KoStore.cpp:109
bool hasDirectory(const QString &directoryName)
Definition KoStore.cpp:390
QByteArray read(qint64 max)
Definition KoStore.cpp:181