Warning, file /office/calligra/libs/store/KoStore.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the KDE project 0002 Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> 0003 Copyright (C) 2000-2002 David Faure <faure@kde.org>, Werner Trobin <trobin@kde.org> 0004 Copyright (C) 2010 C. Boemann <cbo@boemann.dk> 0005 0006 This library is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU Library General Public 0008 License as published by the Free Software Foundation; either 0009 version 2 of the License, or (at your option) any later version. 0010 0011 This library is distributed in the hope that it will be useful, 0012 but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 Library General Public License for more details. 0015 0016 You should have received a copy of the GNU Library General Public License 0017 along with this library; see the file COPYING.LIB. If not, write to 0018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0019 * Boston, MA 02110-1301, USA. 0020 */ 0021 0022 #include "KoStore.h" 0023 #include "KoStore_p.h" 0024 0025 #include "KoTarStore.h" 0026 #include "KoZipStore.h" 0027 #include "KoDirectoryStore.h" 0028 #ifdef QCA2 0029 #include "KoEncryptedStore.h" 0030 #endif 0031 0032 #include <QBuffer> 0033 #include <QFileInfo> 0034 #include <QFile> 0035 0036 #include <QUrl> 0037 #include <StoreDebug.h> 0038 0039 #include <klocalizedstring.h> 0040 #include <kmessagebox.h> 0041 #include <KoNetAccess.h> 0042 0043 #define DefaultFormat KoStore::Zip 0044 0045 static KoStore::Backend determineBackend(QIODevice *dev) 0046 { 0047 unsigned char buf[5]; 0048 if (dev->read((char *)buf, 4) < 4) 0049 return DefaultFormat; // will create a "bad" store (bad()==true) 0050 if (buf[0] == 0037 && buf[1] == 0213) // gzip -> tar.gz 0051 return KoStore::Tar; 0052 if (buf[0] == 'P' && buf[1] == 'K' && buf[2] == 3 && buf[3] == 4) 0053 return KoStore::Zip; 0054 return DefaultFormat; // fallback 0055 } 0056 0057 KoStore* KoStore::createStore(const QString& fileName, Mode mode, const QByteArray & appIdentification, Backend backend, bool writeMimetype) 0058 { 0059 bool automatic = false; 0060 if (backend == Auto) { 0061 automatic = true; 0062 if (mode == KoStore::Write) 0063 backend = DefaultFormat; 0064 else { 0065 QFileInfo inf(fileName); 0066 if (inf.isDir()) 0067 backend = Directory; 0068 else { 0069 QFile file(fileName); 0070 if (file.open(QIODevice::ReadOnly)) 0071 backend = determineBackend(&file); 0072 else 0073 backend = DefaultFormat; // will create a "bad" store (bad()==true) 0074 } 0075 } 0076 } 0077 switch (backend) { 0078 case Tar: 0079 return new KoTarStore(fileName, mode, appIdentification, writeMimetype); 0080 case Zip: 0081 #ifdef QCA2 0082 if (automatic && mode == Read) { 0083 // When automatically detecting, this might as well be an encrypted file. We'll need to check anyway, so we'll just use the encrypted store. 0084 return new KoEncryptedStore(fileName, Read, appIdentification, writeMimetype); 0085 } 0086 #endif 0087 return new KoZipStore(fileName, mode, appIdentification, writeMimetype); 0088 case Directory: 0089 return new KoDirectoryStore(fileName /* should be a dir name.... */, mode, writeMimetype); 0090 #ifdef QCA2 0091 case Encrypted: 0092 return new KoEncryptedStore(fileName, mode, appIdentification, writeMimetype); 0093 #endif 0094 default: 0095 warnStore << "Unsupported backend requested for KoStore : " << backend; 0096 return 0; 0097 } 0098 } 0099 0100 KoStore* KoStore::createStore(QIODevice *device, Mode mode, const QByteArray & appIdentification, Backend backend, bool writeMimetype) 0101 { 0102 bool automatic = false; 0103 if (backend == Auto) { 0104 automatic = true; 0105 if (mode == KoStore::Write) 0106 backend = DefaultFormat; 0107 else { 0108 if (device->open(QIODevice::ReadOnly)) { 0109 backend = determineBackend(device); 0110 device->close(); 0111 } 0112 } 0113 } 0114 switch (backend) { 0115 case Tar: 0116 return new KoTarStore(device, mode, appIdentification, writeMimetype); 0117 case Directory: 0118 errorStore << "Can't create a Directory store for a memory buffer!" << endl; 0119 // fallback 0120 case Zip: 0121 #ifdef QCA2 0122 if (automatic && mode == Read) { 0123 // When automatically detecting, this might as well be an encrypted file. We'll need to check anyway, so we'll just use the encrypted store. 0124 return new KoEncryptedStore(device, Read, appIdentification, writeMimetype); 0125 } 0126 #endif 0127 return new KoZipStore(device, mode, appIdentification, writeMimetype); 0128 #ifdef QCA2 0129 case Encrypted: 0130 return new KoEncryptedStore(device, mode, appIdentification, writeMimetype); 0131 #endif 0132 default: 0133 warnStore << "Unsupported backend requested for KoStore : " << backend; 0134 return 0; 0135 } 0136 } 0137 0138 KoStore* KoStore::createStore(QWidget* window, const QUrl &url, Mode mode, const QByteArray & appIdentification, Backend backend, bool writeMimetype) 0139 { 0140 const bool automatic = (backend == Auto); 0141 if (url.isLocalFile()) 0142 return createStore(url.toLocalFile(), mode, appIdentification, backend, writeMimetype); 0143 0144 QString tmpFile; 0145 if (mode == KoStore::Write) { 0146 if (automatic) 0147 backend = DefaultFormat; 0148 } else { 0149 const bool downloaded = 0150 KIO::NetAccess::download(url, tmpFile, window); 0151 0152 if (!downloaded) { 0153 errorStore << "Could not download file!" << endl; 0154 backend = DefaultFormat; // will create a "bad" store (bad()==true) 0155 } else if (automatic) { 0156 QFile file(tmpFile); 0157 if (file.open(QIODevice::ReadOnly)) { 0158 backend = determineBackend(&file); 0159 file.close(); 0160 } 0161 } 0162 } 0163 switch (backend) { 0164 case Tar: 0165 return new KoTarStore(window, url, tmpFile, mode, appIdentification); 0166 case Zip: 0167 #ifdef QCA2 0168 if (automatic && mode == Read) { 0169 // When automatically detecting, this might as well be an encrypted file. We'll need to check anyway, so we'll just use the encrypted store. 0170 return new KoEncryptedStore(window, url, tmpFile, Read, appIdentification, writeMimetype); 0171 } 0172 #endif 0173 return new KoZipStore(window, url, tmpFile, mode, appIdentification, writeMimetype); 0174 #ifdef QCA2 0175 case Encrypted: 0176 return new KoEncryptedStore(window, url, tmpFile, mode, appIdentification, writeMimetype); 0177 #endif 0178 default: 0179 warnStore << "Unsupported backend requested for KoStore (QUrl) : " << backend; 0180 KMessageBox::sorry(window, 0181 i18n("The directory mode is not supported for remote locations."), 0182 i18n("Calligra Storage")); 0183 return 0; 0184 } 0185 } 0186 0187 namespace 0188 { 0189 const char ROOTPART[] = "root"; 0190 const char MAINNAME[] = "maindoc.xml"; 0191 } 0192 0193 KoStore::KoStore(Mode mode, bool writeMimetype) 0194 : d_ptr(new KoStorePrivate(this, mode, writeMimetype)) 0195 {} 0196 0197 KoStore::~KoStore() 0198 { 0199 Q_D(KoStore); 0200 delete d->stream; 0201 delete d_ptr; 0202 } 0203 0204 QUrl KoStore::urlOfStore() const 0205 { 0206 Q_D(const KoStore); 0207 if (d->fileMode == KoStorePrivate::RemoteRead || d->fileMode == KoStorePrivate::RemoteWrite) { 0208 return d->url; 0209 } else { 0210 return QUrl(d->localFileName); 0211 } 0212 } 0213 0214 bool KoStore::open(const QString & _name) 0215 { 0216 Q_D(KoStore); 0217 // This also converts from relative to absolute, i.e. merges the currentPath() 0218 d->fileName = d->toExternalNaming(_name); 0219 0220 if (d->isOpen) { 0221 warnStore << "Store is already opened, missing close"; 0222 return false; 0223 } 0224 0225 if (d->fileName.length() > 512) { 0226 errorStore << "KoStore: Filename " << d->fileName << " is too long" << endl; 0227 return false; 0228 } 0229 0230 if (d->mode == Write) { 0231 debugStore << "opening for writing" << d->fileName; 0232 if (d->filesList.contains(d->fileName)) { 0233 warnStore << "KoStore: Duplicate filename" << d->fileName; 0234 return false; 0235 } 0236 0237 d->filesList.append(d->fileName); 0238 0239 d->size = 0; 0240 if (!openWrite(d->fileName)) 0241 return false; 0242 } else if (d->mode == Read) { 0243 debugStore << "Opening for reading" << d->fileName; 0244 if (!openRead(d->fileName)) 0245 return false; 0246 } else 0247 return false; 0248 0249 d->isOpen = true; 0250 return true; 0251 } 0252 0253 bool KoStore::isOpen() const 0254 { 0255 Q_D(const KoStore); 0256 return d->isOpen; 0257 } 0258 0259 bool KoStore::close() 0260 { 0261 Q_D(KoStore); 0262 debugStore << "Closing"; 0263 0264 if (!d->isOpen) { 0265 warnStore << "You must open before closing"; 0266 return false; 0267 } 0268 0269 bool ret = d->mode == Write ? closeWrite() : closeRead(); 0270 0271 delete d->stream; 0272 d->stream = 0; 0273 d->isOpen = false; 0274 return ret; 0275 } 0276 0277 QIODevice* KoStore::device() const 0278 { 0279 Q_D(const KoStore); 0280 if (!d->isOpen) 0281 warnStore << "You must open before asking for a device"; 0282 if (d->mode != Read) 0283 warnStore << "Can not get device from store that is opened for writing"; 0284 return d->stream; 0285 } 0286 0287 QByteArray KoStore::read(qint64 max) 0288 { 0289 Q_D(KoStore); 0290 QByteArray data; 0291 0292 if (!d->isOpen) { 0293 warnStore << "You must open before reading"; 0294 return data; 0295 } 0296 if (d->mode != Read) { 0297 errorStore << "KoStore: Can not read from store that is opened for writing" << endl; 0298 return data; 0299 } 0300 0301 return d->stream->read(max); 0302 } 0303 0304 qint64 KoStore::write(const QByteArray& data) 0305 { 0306 return write(data.constData(), data.size()); // see below 0307 } 0308 0309 qint64 KoStore::read(char *_buffer, qint64 _len) 0310 { 0311 Q_D(KoStore); 0312 if (!d->isOpen) { 0313 errorStore << "KoStore: You must open before reading" << endl; 0314 return -1; 0315 } 0316 if (d->mode != Read) { 0317 errorStore << "KoStore: Can not read from store that is opened for writing" << endl; 0318 return -1; 0319 } 0320 0321 return d->stream->read(_buffer, _len); 0322 } 0323 0324 qint64 KoStore::write(const char* _data, qint64 _len) 0325 { 0326 Q_D(KoStore); 0327 if (_len == 0) return 0; 0328 0329 if (!d->isOpen) { 0330 errorStore << "KoStore: You must open before writing" << endl; 0331 return 0; 0332 } 0333 if (d->mode != Write) { 0334 errorStore << "KoStore: Can not write to store that is opened for reading" << endl; 0335 return 0; 0336 } 0337 0338 int nwritten = d->stream->write(_data, _len); 0339 Q_ASSERT(nwritten == (int)_len); 0340 d->size += nwritten; 0341 0342 return nwritten; 0343 } 0344 0345 qint64 KoStore::size() const 0346 { 0347 Q_D(const KoStore); 0348 if (!d->isOpen) { 0349 warnStore << "You must open before asking for a size"; 0350 return static_cast<qint64>(-1); 0351 } 0352 if (d->mode != Read) { 0353 warnStore << "Can not get size from store that is opened for writing"; 0354 return static_cast<qint64>(-1); 0355 } 0356 return d->size; 0357 } 0358 0359 bool KoStore::enterDirectory(const QString &directory) 0360 { 0361 Q_D(KoStore); 0362 //debugStore <<"enterDirectory" << directory; 0363 int pos; 0364 bool success = true; 0365 QString tmp(directory); 0366 0367 while ((pos = tmp.indexOf('/')) != -1 && 0368 (success = d->enterDirectoryInternal(tmp.left(pos)))) 0369 tmp.remove(0, pos + 1); 0370 0371 if (success && !tmp.isEmpty()) 0372 return d->enterDirectoryInternal(tmp); 0373 return success; 0374 } 0375 0376 bool KoStore::leaveDirectory() 0377 { 0378 Q_D(KoStore); 0379 if (d->currentPath.isEmpty()) 0380 return false; 0381 0382 d->currentPath.pop_back(); 0383 0384 return enterAbsoluteDirectory(currentPath()); 0385 } 0386 0387 QString KoStore::currentPath() const 0388 { 0389 Q_D(const KoStore); 0390 QString path; 0391 QStringList::ConstIterator it = d->currentPath.begin(); 0392 QStringList::ConstIterator end = d->currentPath.end(); 0393 for (; it != end; ++it) { 0394 path += *it; 0395 path += '/'; 0396 } 0397 return path; 0398 } 0399 0400 void KoStore::pushDirectory() 0401 { 0402 Q_D(KoStore); 0403 d->directoryStack.push(currentPath()); 0404 } 0405 0406 void KoStore::popDirectory() 0407 { 0408 Q_D(KoStore); 0409 d->currentPath.clear(); 0410 enterAbsoluteDirectory(QString()); 0411 enterDirectory(d->directoryStack.pop()); 0412 } 0413 0414 bool KoStore::addLocalFile(const QString &fileName, const QString &destName) 0415 { 0416 QFileInfo fi(fileName); 0417 uint size = fi.size(); 0418 QFile file(fileName); 0419 if (!file.open(QIODevice::ReadOnly)) { 0420 return false; 0421 } 0422 0423 if (!open(destName)) { 0424 return false; 0425 } 0426 0427 QByteArray data; 0428 data.resize(8 * 1024); 0429 0430 uint total = 0; 0431 for (int block = 0; (block = file.read(data.data(), data.size())) > 0; total += block) { 0432 data.resize(block); 0433 if (write(data) != block) 0434 return false; 0435 data.resize(8*1024); 0436 } 0437 Q_ASSERT(total == size); 0438 if (total != size) { 0439 warnStore << "Did not write enough bytes. Expected: " << size << ", wrote" << total; 0440 return false; 0441 } 0442 0443 close(); 0444 file.close(); 0445 0446 return true; 0447 } 0448 0449 bool KoStore::addDataToFile(QByteArray &buffer, const QString &destName) 0450 { 0451 QBuffer file(&buffer); 0452 if (!file.open(QIODevice::ReadOnly)) { 0453 return false; 0454 } 0455 0456 if (!open(destName)) { 0457 return false; 0458 } 0459 0460 QByteArray data; 0461 data.resize(8 * 1024); 0462 0463 uint total = 0; 0464 for (int block = 0; (block = file.read(data.data(), data.size())) > 0; total += block) { 0465 data.resize(block); 0466 if (write(data) != block) 0467 return false; 0468 data.resize(8*1024); 0469 } 0470 0471 close(); 0472 file.close(); 0473 0474 return true; 0475 } 0476 0477 bool KoStore::extractFile(const QString &srcName, const QString &fileName) 0478 { 0479 Q_D(KoStore); 0480 QFile file(fileName); 0481 return d->extractFile(srcName, file); 0482 } 0483 0484 0485 bool KoStore::extractFile(const QString &srcName, QByteArray &data) 0486 { 0487 Q_D(KoStore); 0488 QBuffer buffer(&data); 0489 return d->extractFile(srcName, buffer); 0490 } 0491 0492 bool KoStorePrivate::extractFile(const QString &srcName, QIODevice &buffer) 0493 { 0494 if (!q->open(srcName)) 0495 return false; 0496 0497 if (!buffer.open(QIODevice::WriteOnly)) { 0498 q->close(); 0499 return false; 0500 } 0501 // ### This could use KArchive::copy or something, no? 0502 0503 QByteArray data; 0504 data.resize(8 * 1024); 0505 uint total = 0; 0506 for (int block = 0; (block = q->read(data.data(), data.size())) > 0; total += block) { 0507 buffer.write(data.data(), block); 0508 } 0509 0510 if (q->size() != static_cast<qint64>(-1)) 0511 Q_ASSERT(total == q->size()); 0512 0513 buffer.close(); 0514 q->close(); 0515 0516 return true; 0517 } 0518 0519 bool KoStore::seek(qint64 pos) 0520 { 0521 Q_D(KoStore); 0522 return d->stream->seek(pos); 0523 } 0524 0525 qint64 KoStore::pos() const 0526 { 0527 Q_D(const KoStore); 0528 return d->stream->pos(); 0529 } 0530 0531 bool KoStore::atEnd() const 0532 { 0533 Q_D(const KoStore); 0534 return d->stream->atEnd(); 0535 } 0536 0537 // See the specification for details of what this function does. 0538 QString KoStorePrivate::toExternalNaming(const QString & _internalNaming) const 0539 { 0540 if (_internalNaming == ROOTPART) 0541 return q->currentPath() + MAINNAME; 0542 0543 QString intern; 0544 if (_internalNaming.startsWith("tar:/")) // absolute reference 0545 intern = _internalNaming.mid(5); // remove protocol 0546 else 0547 intern = q->currentPath() + _internalNaming; 0548 0549 return intern; 0550 } 0551 0552 0553 bool KoStorePrivate::enterDirectoryInternal(const QString &directory) 0554 { 0555 if (q->enterRelativeDirectory(directory)) { 0556 currentPath.append(directory); 0557 return true; 0558 } 0559 return false; 0560 } 0561 0562 bool KoStore::hasFile(const QString& fileName) const 0563 { 0564 Q_D(const KoStore); 0565 return fileExists(d->toExternalNaming(fileName)); 0566 } 0567 0568 bool KoStore::finalize() 0569 { 0570 Q_D(KoStore); 0571 Q_ASSERT(!d->finalized); // call this only once! 0572 d->finalized = true; 0573 return doFinalize(); 0574 } 0575 0576 void KoStore::setCompressionEnabled(bool /*e*/) 0577 { 0578 } 0579 0580 bool KoStore::isEncrypted() 0581 { 0582 return false; 0583 } 0584 0585 bool KoStore::setPassword(const QString& /*password*/) 0586 { 0587 return false; 0588 } 0589 0590 QString KoStore::password() 0591 { 0592 return QString(); 0593 } 0594 0595 bool KoStore::bad() const 0596 { 0597 Q_D(const KoStore); 0598 return !d->good; 0599 } 0600 0601 KoStore::Mode KoStore::mode() const 0602 { 0603 Q_D(const KoStore); 0604 return d->mode; 0605 } 0606 0607 QStringList KoStore::directoryList() const 0608 { 0609 return QStringList(); 0610 }