diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -208,3 +208,4 @@ endif () add_subdirectory(ext_giflib) +add_subdirectory(ext_quazip) diff --git a/3rdparty/ext_quazip/CMakeLists.txt b/3rdparty/ext_quazip/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/3rdparty/ext_quazip/CMakeLists.txt @@ -0,0 +1,12 @@ +SET(PREFIX_ext_quazip "${EXTPREFIX}" ) +ExternalProject_Add( ext_quazip + DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} + URL https://github.com/stachenov/quazip/archive/0.7.6.zip + URL_MD5 a3335649c34053385d8390dd1a6f1ca4 + PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/find_quazip.diff + INSTALL_DIR ${PREFIX_ext_quazip} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${PREFIX_ext_quazip} -DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE} ${GLOBAL_PROFILE} + + UPDATE_COMMAND "" + DEPENDS ext_zlib ext_qt +) diff --git a/3rdparty/ext_quazip/find_quazip.diff b/3rdparty/ext_quazip/find_quazip.diff new file mode 100644 --- /dev/null +++ b/3rdparty/ext_quazip/find_quazip.diff @@ -0,0 +1,10 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 3d2fb55..5d8a5cc 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -60,4 +60,4 @@ set(QUAZIP_LIB_TARGET_NAME quazip${QUAZIP_LIB_VERSION_SUFFIX} CACHE + + add_subdirectory(quazip) + +-install(FILES FindQuaZip.cmake RENAME FindQuaZip${QUAZIP_LIB_VERSION_SUFFIX}.cmake DESTINATION ${CMAKE_ROOT}/Modules) ++#install(FILES FindQuaZip.cmake RENAME FindQuaZip${QUAZIP_LIB_VERSION_SUFFIX}.cmake DESTINATION ${CMAKE_ROOT}/Modules) diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,7 +275,6 @@ # do not reorder to be alphabetical: this is the order in which the frameworks # depend on each other. find_package(KF5 ${MIN_FRAMEWORKS_VERSION} REQUIRED COMPONENTS - Archive Config WidgetsAddons Completion @@ -700,6 +699,20 @@ TYPE OPTIONAL PURPOSE "Required by the Krita PDF filter.") + +## +## Test for quazip +## +find_package(QuaZip 0.7) +set_package_properties(QuaZip PROPERTIES + DESCRIPTION "A library for reading and writing zip files" + URL "https://stachenov.github.io/quazip/" + TYPE REQUIRED + PURPOSE "Needed for reading and writing KRA and ORA files" +) + + + ## ## Test for Atomics ## diff --git a/cmake/modules/FindQuaZip.cmake b/cmake/modules/FindQuaZip.cmake new file mode 100644 --- /dev/null +++ b/cmake/modules/FindQuaZip.cmake @@ -0,0 +1,43 @@ +# QUAZIP_FOUND - QuaZip library was found +# QUAZIP_INCLUDE_DIR - Path to QuaZip include dir +# QUAZIP_INCLUDE_DIRS - Path to QuaZip and zlib include dir (combined from QUAZIP_INCLUDE_DIR + ZLIB_INCLUDE_DIR) +# QUAZIP_LIBRARIES - List of QuaZip libraries +# QUAZIP_ZLIB_INCLUDE_DIR - The include dir of zlib headers + + +IF (QUAZIP_INCLUDE_DIRS AND QUAZIP_LIBRARIES) + # in cache already + SET(QUAZIP_FOUND TRUE) +ELSE (QUAZIP_INCLUDE_DIRS AND QUAZIP_LIBRARIES) + IF (Qt5Core_FOUND) + set(QUAZIP_LIB_VERSION_SUFFIX 5) + ENDIF() + IF (WIN32) + FIND_PATH(QUAZIP_LIBRARY_DIR + WIN32_DEBUG_POSTFIX d + NAMES libquazip${QUAZIP_LIB_VERSION_SUFFIX}.dll + HINTS "C:/Programme/" "C:/Program Files" + PATH_SUFFIXES QuaZip/lib + ) + FIND_LIBRARY(QUAZIP_LIBRARIES NAMES libquazip${QUAZIP_LIB_VERSION_SUFFIX}.dll HINTS ${QUAZIP_LIBRARY_DIR}) + FIND_PATH(QUAZIP_INCLUDE_DIR NAMES quazip.h HINTS ${QUAZIP_LIBRARY_DIR}/../ PATH_SUFFIXES include/quazip) + FIND_PATH(QUAZIP_ZLIB_INCLUDE_DIR NAMES zlib.h) + ELSE(WIN32) + FIND_PACKAGE(PkgConfig) +# pkg_check_modules(PC_QCA2 QUIET qca2) + pkg_check_modules(PC_QUAZIP quazip) + FIND_LIBRARY(QUAZIP_LIBRARIES + WIN32_DEBUG_POSTFIX d + NAMES quazip${QUAZIP_LIB_VERSION_SUFFIX} + HINTS /usr/lib /usr/lib64 + ) + FIND_PATH(QUAZIP_INCLUDE_DIR quazip.h + HINTS /usr/include /usr/local/include + PATH_SUFFIXES quazip${QUAZIP_LIB_VERSION_SUFFIX} + ) + FIND_PATH(QUAZIP_ZLIB_INCLUDE_DIR zlib.h HINTS /usr/include /usr/local/include) + ENDIF (WIN32) + INCLUDE(FindPackageHandleStandardArgs) + SET(QUAZIP_INCLUDE_DIRS ${QUAZIP_INCLUDE_DIR} ${QUAZIP_ZLIB_INCLUDE_DIR}) + find_package_handle_standard_args(QUAZIP DEFAULT_MSG QUAZIP_LIBRARIES QUAZIP_INCLUDE_DIR QUAZIP_ZLIB_INCLUDE_DIR QUAZIP_INCLUDE_DIRS) +ENDIF (QUAZIP_INCLUDE_DIRS AND QUAZIP_LIBRARIES) diff --git a/libs/store/CMakeLists.txt b/libs/store/CMakeLists.txt --- a/libs/store/CMakeLists.txt +++ b/libs/store/CMakeLists.txt @@ -1,3 +1,5 @@ +include_directories(${QUAZIP_INCLUDE_DIRS}) + add_subdirectory(tests) set(kritastore_LIB_SRCS @@ -8,14 +10,22 @@ KoXmlNS.cpp KoXmlReader.cpp KoXmlWriter.cpp - KoZipStore.cpp + KoQuaZipStore.cpp StoreDebug.cpp ) add_library(kritastore SHARED ${kritastore_LIB_SRCS}) generate_export_header(kritastore BASE_NAME kritastore) -target_link_libraries(kritastore kritaversion kritaglobal Qt5::Xml Qt5::Gui KF5::Archive) +target_link_libraries(kritastore + PRIVATE + kritaversion + kritaglobal + KF5::ConfigCore + Qt5::Xml + Qt5::Gui + ${QUAZIP_LIBRARIES} +) set_target_properties(kritastore PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} diff --git a/libs/store/KoQuaZipStore.h b/libs/store/KoQuaZipStore.h new file mode 100644 --- /dev/null +++ b/libs/store/KoQuaZipStore.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2019 Boudewijn Rempt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KoQuaZipStore_h +#define KoQuaZipStore_h + +#include "KoStore.h" +#include + +class QUrl; + +class KoQuaZipStore : public KoStore +{ +public: + KoQuaZipStore(const QString & _filename, Mode _mode, const QByteArray & appIdentification, + bool writeMimetype = true); + + KoQuaZipStore(QIODevice *dev, Mode mode, const QByteArray & appIdentification, + bool writeMimetype = true); + + ~KoQuaZipStore() override; + + void setCompressionEnabled(bool enabled) override; + qint64 write(const char* _data, qint64 _len) override; + + QStringList directoryList() const override; + +protected: + void init(const QByteArray& appIdentification); + bool doFinalize() override; + bool openWrite(const QString& name) override; + bool openRead(const QString& name) override; + bool closeWrite() override; + bool closeRead() override; + bool enterRelativeDirectory(const QString& dirName) override; + bool enterAbsoluteDirectory(const QString& path) override; + bool fileExists(const QString& absPath) const override; + +private: + struct Private; + const QScopedPointer dd; + Q_DECLARE_PRIVATE(KoStore) + +}; + +#endif diff --git a/libs/store/KoQuaZipStore.cpp b/libs/store/KoQuaZipStore.cpp new file mode 100644 --- /dev/null +++ b/libs/store/KoQuaZipStore.cpp @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2019 Boudewijn Rempt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include "KoQuaZipStore.h" +#include "KoStore_p.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +struct KoQuaZipStore::Private { + + Private() {} + ~Private() {} + + QuaZip *archive {0}; + QuaZipFile *currentFile {0}; + int compressionLevel {Z_DEFAULT_COMPRESSION}; + bool usingSaveFile {false}; +}; + + +KoQuaZipStore::KoQuaZipStore(const QString &_filename, KoStore::Mode _mode, const QByteArray &appIdentification, bool writeMimetype) + : KoStore(_mode, writeMimetype) + , dd(new Private()) +{ + Q_D(KoStore); + d->localFileName = _filename; + dd->archive = new QuaZip(_filename); + init(appIdentification); + +} + +KoQuaZipStore::KoQuaZipStore(QIODevice *dev, KoStore::Mode _mode, const QByteArray &appIdentification, bool writeMimetype) + : KoStore(_mode, writeMimetype) + , dd(new Private()) +{ + Q_D(KoStore); + dd->archive = new QuaZip(dev); + init(appIdentification); +} + +KoQuaZipStore::~KoQuaZipStore() +{ + Q_D(KoStore); + + if (dd->currentFile && dd->currentFile->isOpen()) { + dd->currentFile->close(); + } + + if (!d->finalized) { + finalize(); + } + + delete dd->archive; + delete dd->currentFile; +} + +void KoQuaZipStore::setCompressionEnabled(bool enabled) +{ + + if (enabled) { + dd->compressionLevel = Z_BEST_COMPRESSION; + } + else { + dd->compressionLevel = Z_NO_COMPRESSION; + } +} + +qint64 KoQuaZipStore::write(const char *_data, qint64 _len) +{ + Q_D(KoStore); + if (_len == 0) return 0; + + if (!d->isOpen) { + errorStore << "KoStore: You must open before writing" << endl; + return 0; + } + + if (d->mode != Write) { + errorStore << "KoStore: Can not write to store that is opened for reading" << endl; + return 0; + } + + d->size += _len; + if (dd->currentFile->write(_data, _len)) { // writeData returns a bool! + return _len; + } + return 0; +} + +QStringList KoQuaZipStore::directoryList() const +{ + return dd->archive->getFileNameList(); +} + +void KoQuaZipStore::init(const QByteArray &appIdentification) +{ + Q_D(KoStore); + + bool enableZip64 = false; + if (appIdentification == "application/x-krita") { + enableZip64 = KSharedConfig::openConfig()->group("").readEntry("UseZip64", false); + } + dd->archive->setZip64Enabled(enableZip64); + dd->archive->setFileNameCodec("utf8"); + dd->usingSaveFile = dd->archive->getIoDevice() && dd->archive->getIoDevice()->inherits("QSaveFile"); + dd->archive->setAutoClose(!dd->usingSaveFile); + + d->good = dd->archive->open(d->mode == Write ? QuaZip::mdCreate : QuaZip::mdUnzip); + + if (!d->good) { + return; + } + + if (d->mode == Write) { + if (d->writeMimetype) { + QuaZipFile f(dd->archive); + QuaZipNewInfo newInfo("mimetype"); + newInfo.setPermissions(QFileDevice::ReadOwner | QFileDevice::ReadGroup | QFileDevice::ReadOther); + if (!f.open(QIODevice::WriteOnly, newInfo, 0, 0, Z_DEFLATED, Z_NO_COMPRESSION)) { + d->good = false; + return; + } + f.write(appIdentification); + f.close(); + } + } + else { + d->good = dd->archive->getEntriesCount(); + } +} + +bool KoQuaZipStore::doFinalize() +{ + Q_D(KoStore); + + d->stream = 0; + if (!dd->usingSaveFile) { + dd->archive->close(); + } + return dd->archive->getZipError() == ZIP_OK; + +} + +bool KoQuaZipStore::openWrite(const QString &name) +{ + Q_D(KoStore); + QString fixedPath = name; + fixedPath.replace("//", "/"); + + delete d->stream; + d->stream = 0; // Not used when writing + + delete dd->currentFile; + dd->currentFile = new QuaZipFile(dd->archive); + QuaZipNewInfo newInfo(fixedPath); + newInfo.setPermissions(QFileDevice::ReadOwner | QFileDevice::ReadGroup | QFileDevice::ReadOther); + bool r = dd->currentFile->open(QIODevice::WriteOnly, newInfo, 0, 0, Z_DEFLATED, dd->compressionLevel); + if (!r) { + qWarning() << "Could not open" << name << dd->currentFile->getZipError(); + } + return r; +} + +bool KoQuaZipStore::openRead(const QString &name) +{ + Q_D(KoStore); + QString fixedPath = name; + fixedPath.replace("//", "/"); + + delete d->stream; + d->stream = 0; + delete dd->currentFile; + dd->currentFile = 0; + + if (!currentPath().isEmpty() && !fixedPath.startsWith(currentPath())) { + fixedPath = currentPath() + '/' + fixedPath; + } + + if (!dd->archive->setCurrentFile(fixedPath)) { + warnStore << "\t\tCould not set current file" << dd->archive->getZipError(); + return false; + } + + dd->currentFile = new QuaZipFile(dd->archive); + if (!dd->currentFile->open(QIODevice::ReadOnly)) { + warnStore << "\t\t\tBut could not open!!!" << dd->archive->getZipError(); + return false; + } + d->stream = dd->currentFile; + d->size = dd->currentFile->size(); + return true; +} + +bool KoQuaZipStore::closeWrite() +{ + Q_D(KoStore); + dd->currentFile->close(); + d->stream = 0; + return dd->currentFile->getZipError() == ZIP_OK; +} + +bool KoQuaZipStore::closeRead() +{ + Q_D(KoStore); + d->stream = 0; + return true; +} + +bool KoQuaZipStore::enterRelativeDirectory(const QString &) +{ + return true; +} + +bool KoQuaZipStore::enterAbsoluteDirectory(const QString &path) +{ + QString fixedPath = path; + fixedPath.replace("//", "/"); + + if (fixedPath.isEmpty()) { + return true; + } + QuaZipDir currentDir (dd->archive, fixedPath); + return currentDir.exists(); +} + +bool KoQuaZipStore::fileExists(const QString &absPath) const +{ + QString fixedPath = absPath; + fixedPath.replace("//", "/"); + return dd->archive->getFileNameList().contains(fixedPath); +} diff --git a/libs/store/KoStore.h b/libs/store/KoStore.h --- a/libs/store/KoStore.h +++ b/libs/store/KoStore.h @@ -74,31 +74,6 @@ const QByteArray &appIdentification = QByteArray(), Backend backend = Auto, bool writeMimetype = true); - /** - * Open a store (i.e. the representation on disk of a Krita document). - * - * @param url URL of the file to open - * @param mode if KoStore::Read, open an existing store to read it. - * if KoStore::Write, create or replace a store. - * @param backend the backend to use for the data storage. - * Auto means automatically-determined for reading, - * and the current format (now Zip) for writing. - * - * @param appIdentification the application's mimetype, - * to be written in the file for "mime-magic" identification. - * Only meaningful if mode is Write, and if backend!=Directory. - * - * If the file is remote, the backend Directory cannot be used! - * - * @param writeMimetype If true, some backends (notably the Zip - * store) will write a file called 'mimetype' automatically and - * fill it with data from the appIdentification. This is only - * applicable if Mode is set to Write. - * - * @bug saving not completely implemented (fixed temporary file) - */ - static KoStore *createStore(const QUrl &url, Mode mode, - const QByteArray &appIdentification = QByteArray(), Backend backend = Auto, bool writeMimetype = true); /** * Destroys the store (i.e. closes the file on the hard disk) diff --git a/libs/store/KoStore.cpp b/libs/store/KoStore.cpp --- a/libs/store/KoStore.cpp +++ b/libs/store/KoStore.cpp @@ -22,7 +22,7 @@ #include "KoStore.h" #include "KoStore_p.h" -#include "KoZipStore.h" +#include "KoQuaZipStore.h" #include "KoDirectoryStore.h" #include @@ -64,7 +64,7 @@ } switch (backend) { case Zip: - return new KoZipStore(fileName, mode, appIdentification, writeMimetype); + return new KoQuaZipStore(fileName, mode, appIdentification, writeMimetype); case Directory: return new KoDirectoryStore(fileName /* should be a dir name.... */, mode, writeMimetype); default: @@ -90,19 +90,13 @@ errorStore << "Can't create a Directory store for a memory buffer!" << endl; return 0; case Zip: - return new KoZipStore(device, mode, appIdentification, writeMimetype); + return new KoQuaZipStore(device, mode, appIdentification, writeMimetype); default: warnStore << "Unsupported backend requested for KoStore : " << backend; return 0; } } -KoStore* KoStore::createStore(const QUrl &url, Mode mode, const QByteArray & appIdentification, Backend backend, bool writeMimetype) -{ - Q_ASSERT(url.isLocalFile()); - return createStore(url.toLocalFile(), mode, appIdentification, backend, writeMimetype); -} - namespace { const char ROOTPART[] = "root"; @@ -168,15 +162,12 @@ bool KoStore::close() { Q_D(KoStore); - debugStore << "Closing"; - if (!d->isOpen) { warnStore << "You must open before closing"; return false; } bool ret = d->mode == Write ? closeWrite() : closeRead(); - delete d->stream; d->stream = 0; d->isOpen = false; diff --git a/libs/store/KoStore_p.h b/libs/store/KoStore_p.h --- a/libs/store/KoStore_p.h +++ b/libs/store/KoStore_p.h @@ -70,11 +70,7 @@ bool extractFile(const QString &sourceName, QIODevice &buffer); KoStore *q; - /** - * original URL of the remote file - * (undefined for a local file) - */ - QUrl url; + QString localFileName; QWidget *window; diff --git a/libs/store/KoZipStore.h b/libs/store/KoZipStore.h --- a/libs/store/KoZipStore.h +++ b/libs/store/KoZipStore.h @@ -33,12 +33,7 @@ bool writeMimetype = true); KoZipStore(QIODevice *dev, Mode mode, const QByteArray & appIdentification, bool writeMimetype = true); - /** - * QUrl-constructor - * @todo saving not completely implemented (fixed temporary file) - */ - KoZipStore(QWidget* window, const QUrl &_url, const QString & _filename, Mode _mode, - const QByteArray & appIdentification, bool writeMimetype = true); + ~KoZipStore() override; void setCompressionEnabled(bool e) override; diff --git a/libs/store/KoZipStore.cpp b/libs/store/KoZipStore.cpp deleted file mode 100644 --- a/libs/store/KoZipStore.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* This file is part of the KDE project - Copyright (C) 2000-2002 David Faure - Copyright (C) 2010 C. Boemann - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. -*/ - -#include "KoZipStore.h" -#include "KoStore_p.h" - -#include -#include -#include - -#include -#include - -#include - -class SaveZip : public KZip { -public: - SaveZip(const QString &filename) : KZip(filename) {} - SaveZip(QIODevice *dev) : KZip(dev) {} - ~SaveZip() override {} - void resetDevice() { - closeArchive(); - setDevice(0); - } -}; - -KoZipStore::KoZipStore(const QString & _filename, Mode mode, const QByteArray & appIdentification, - bool writeMimetype) - : KoStore(mode, writeMimetype) -{ - Q_D(KoStore); - - d->localFileName = _filename; - - m_pZip = new SaveZip(_filename); - - init(appIdentification); // open the zip file and init some vars -} - -KoZipStore::KoZipStore(QIODevice *dev, Mode mode, const QByteArray & appIdentification, - bool writeMimetype) - : KoStore(mode, writeMimetype) -{ - m_pZip = new SaveZip(dev); - init(appIdentification); -} - -KoZipStore::KoZipStore(QWidget* window, const QUrl &_url, const QString & _filename, Mode mode, - const QByteArray & appIdentification, bool writeMimetype) - : KoStore(mode, writeMimetype) -{ - debugStore << "KoZipStore Constructor url" << _url.url(QUrl::PreferLocalFile) - << " filename = " << _filename - << " mode = " << int(mode) - << " mimetype = " << appIdentification; - Q_D(KoStore); - - d->url = _url; - d->window = window; - - if (mode == KoStore::Read) { - d->localFileName = _filename; - } else { - QTemporaryFile f("kozip"); - f.open(); - d->localFileName = f.fileName(); - f.close(); - } - - m_pZip = new SaveZip(d->localFileName); - init(appIdentification); // open the zip file and init some vars -} - -KoZipStore::~KoZipStore() -{ - Q_D(KoStore); - if (m_pZip->device() && m_pZip->device()->inherits("QSaveFile")) { - m_pZip->resetDevice(); // otherwise, kzip's destructor will call close(), which aborts on a qsavefile - } - else { - if (!d->finalized) { - finalize(); // ### no error checking when the app forgot to call finalize itself - } - } - delete m_pZip; - - // When writing, we write to a temp file that then gets copied over the original filename - if (d->mode == Write && (!d->localFileName.isEmpty() && !d->url.isEmpty())) { - QFile f(d->localFileName); - if (f.copy(d->url.toLocalFile())) { - f.remove(); - } - } -} - -void KoZipStore::init(const QByteArray& appIdentification) -{ - Q_D(KoStore); - - m_currentDir = 0; - d->good = m_pZip->open(d->mode == Write ? QIODevice::WriteOnly : QIODevice::ReadOnly); - - if (!d->good) - return; - - if (d->mode == Write) { - - m_pZip->setCompression(KZip::NoCompression); - m_pZip->setExtraField(KZip::NoExtraField); - - // Write identification - if (d->writeMimetype) { - (void)m_pZip->writeFile(QLatin1String("mimetype"), appIdentification); - } - - m_pZip->setCompression(KZip::DeflateCompression); - // We don't need the extra field in Krita - so we leave it as "no extra field". - } else { - d->good = m_pZip->directory() != 0; - } -} - -void KoZipStore::setCompressionEnabled(bool e) -{ - if (e) { - m_pZip->setCompression(KZip::DeflateCompression); - } else { - m_pZip->setCompression(KZip::NoCompression); - } -} - -bool KoZipStore::doFinalize() -{ - if (m_pZip && m_pZip->device() && !m_pZip->device()->inherits("QSaveFile")) { - return m_pZip->close(); - } - else { - return true; - } -} - -bool KoZipStore::openWrite(const QString& name) -{ - Q_D(KoStore); - d->stream = 0; // Don't use! - return m_pZip->prepareWriting(name, "", "" /*m_pZip->rootDir()->user(), m_pZip->rootDir()->group()*/, 0); -} - -bool KoZipStore::openRead(const QString& name) -{ - Q_D(KoStore); - const KArchiveEntry * entry = m_pZip->directory()->entry(name); - if (entry == 0) { - return false; - } - if (entry->isDirectory()) { - warnStore << name << " is a directory !"; - return false; - } - // Must cast to KZipFileEntry, not only KArchiveFile, because device() isn't virtual! - const KZipFileEntry * f = static_cast(entry); - delete d->stream; - d->stream = f->createDevice(); - d->size = f->size(); - return true; -} - -qint64 KoZipStore::write(const char* _data, qint64 _len) -{ - Q_D(KoStore); - if (_len == 0) return 0; - if (!d->isOpen) { - errorStore << "KoStore: You must open before writing" << endl; - return 0; - } - if (d->mode != Write) { - errorStore << "KoStore: Can not write to store that is opened for reading" << endl; - return 0; - } - - d->size += _len; - if (m_pZip->writeData(_data, _len)) // writeData returns a bool! - return _len; - return 0; -} - -QStringList KoZipStore::directoryList() const -{ - QStringList retval; - const KArchiveDirectory *directory = m_pZip->directory(); - Q_FOREACH (const QString &name, directory->entries()) { - const KArchiveEntry* fileArchiveEntry = m_pZip->directory()->entry(name); - if (fileArchiveEntry->isDirectory()) { - retval << name; - } - } - return retval; -} - -bool KoZipStore::closeWrite() -{ - Q_D(KoStore); - debugStore << "Wrote file" << d->fileName << " into ZIP archive. size" << d->size; - return m_pZip->finishWriting(d->size); -} - -bool KoZipStore::enterRelativeDirectory(const QString& dirName) -{ - Q_D(KoStore); - if (d->mode == Read) { - if (!m_currentDir) { - m_currentDir = m_pZip->directory(); // initialize - Q_ASSERT(d->currentPath.isEmpty()); - } - const KArchiveEntry *entry = m_currentDir->entry(dirName); - if (entry && entry->isDirectory()) { - m_currentDir = dynamic_cast(entry); - return m_currentDir != 0; - } - return false; - } else // Write, no checking here - return true; -} - -bool KoZipStore::enterAbsoluteDirectory(const QString& path) -{ - if (path.isEmpty()) { - m_currentDir = 0; - return true; - } - m_currentDir = dynamic_cast(m_pZip->directory()->entry(path)); - Q_ASSERT(m_currentDir); - return m_currentDir != 0; -} - -bool KoZipStore::fileExists(const QString& absPath) const -{ - const KArchiveEntry *entry = m_pZip->directory()->entry(absPath); - return entry && entry->isFile(); -} diff --git a/libs/ui/KisImportExportManager.cpp b/libs/ui/KisImportExportManager.cpp --- a/libs/ui/KisImportExportManager.cpp +++ b/libs/ui/KisImportExportManager.cpp @@ -648,6 +648,7 @@ } else { #ifdef USE_QSAVEFILE if (!file.commit()) { + qWarning() << "Could not commit QSaveFile"; QString error = file.errorString(); if (error.isEmpty()) { error = i18n("Could not write to %1.", location); diff --git a/libs/ui/KisWelcomePageWidget.cpp b/libs/ui/KisWelcomePageWidget.cpp --- a/libs/ui/KisWelcomePageWidget.cpp +++ b/libs/ui/KisWelcomePageWidget.cpp @@ -209,7 +209,7 @@ else { if (QFileInfo(recentFileUrlPath).exists()) { if (recentFileUrlPath.endsWith("ora") || recentFileUrlPath.endsWith("kra")) { - QScopedPointer store(KoStore::createStore(QUrl::fromLocalFile(recentFileUrlPath), KoStore::Read)); + QScopedPointer store(KoStore::createStore(recentFileUrlPath, KoStore::Read)); if (store) { if (store->open(QString("Thumbnails/thumbnail.png")) || store->open(QString("preview.png"))) { diff --git a/libs/ui/dialogs/kis_dlg_preferences.h b/libs/ui/dialogs/kis_dlg_preferences.h --- a/libs/ui/dialogs/kis_dlg_preferences.h +++ b/libs/ui/dialogs/kis_dlg_preferences.h @@ -85,6 +85,7 @@ int favoritePresets(); bool showCanvasMessages(); bool compressKra(); + bool useZip64(); bool toolOptionsInDocker(); bool kineticScrollingEnabled(); int kineticScrollingGesture(); diff --git a/libs/ui/dialogs/kis_dlg_preferences.cc b/libs/ui/dialogs/kis_dlg_preferences.cc --- a/libs/ui/dialogs/kis_dlg_preferences.cc +++ b/libs/ui/dialogs/kis_dlg_preferences.cc @@ -185,6 +185,7 @@ m_autosaveCheckBox->setChecked(autosaveInterval > 0); m_chkCompressKra->setChecked(cfg.compressKra()); + chkZip64->setChecked(cfg.useZip64()); m_backupFileCheckBox->setChecked(cfg.backupFile()); @@ -238,6 +239,7 @@ m_backgroundimage->setText(cfg.getMDIBackgroundImage(true)); m_chkCanvasMessages->setChecked(cfg.showCanvasMessages(true)); m_chkCompressKra->setChecked(cfg.compressKra(true)); + chkZip64->setChecked(cfg.useZip64(true)); m_chkHiDPI->setChecked(false); m_chkSingleApplication->setChecked(true); @@ -321,6 +323,11 @@ return m_chkCompressKra->isChecked(); } +bool GeneralTab::useZip64() +{ + return chkZip64->isChecked(); +} + bool GeneralTab::toolOptionsInDocker() { return m_radioToolOptionsInDocker->isChecked(); @@ -1337,6 +1344,7 @@ cfg.setBackupFile(dialog->m_general->m_backupFileCheckBox->isChecked()); cfg.setShowCanvasMessages(dialog->m_general->showCanvasMessages()); cfg.setCompressKra(dialog->m_general->compressKra()); + cfg.setUseZip64(dialog->m_general->useZip64()); const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); diff --git a/libs/ui/forms/wdggeneralsettings.ui b/libs/ui/forms/wdggeneralsettings.ui --- a/libs/ui/forms/wdggeneralsettings.ui +++ b/libs/ui/forms/wdggeneralsettings.ui @@ -601,21 +601,21 @@ - + Create backup file - + On importing images as layers, convert to the image colorspace - + @@ -631,7 +631,7 @@ - + @@ -659,7 +659,7 @@ - + @@ -675,14 +675,14 @@ - + Show root layer - + Warning: if you enable this setting and the file dialogs do weird stuff, do not report a bug. @@ -692,14 +692,14 @@ - + Maximum brush size: - + @@ -735,7 +735,7 @@ - + Qt::Vertical @@ -748,7 +748,7 @@ - + @@ -770,6 +770,16 @@ + + + + <html><head/><body><p>Only use this option for <span style=" font-weight:600;">very</span> large files: larger than 4 GiB on disk.</p></body></html> + + + Use Zip64 (for very large files: cannot be opened in versions of Krita older than 4.2.0) + + + diff --git a/libs/ui/kis_config.h b/libs/ui/kis_config.h --- a/libs/ui/kis_config.h +++ b/libs/ui/kis_config.h @@ -579,6 +579,8 @@ bool activateTransformToolAfterPaste(bool defaultValue = false) const; void setActivateTransformToolAfterPaste(bool value); + bool useZip64(bool defaultValue = false) const; + void setUseZip64(bool value); template void writeEntry(const QString& name, const T& value) { diff --git a/libs/ui/kis_config.cc b/libs/ui/kis_config.cc --- a/libs/ui/kis_config.cc +++ b/libs/ui/kis_config.cc @@ -2004,6 +2004,16 @@ m_cfg.writeEntry("activateTransformToolAfterPaste", value); } +bool KisConfig::useZip64(bool defaultValue) const +{ + return defaultValue ? false : m_cfg.readEntry("UseZip64", false); +} + +void KisConfig::setUseZip64(bool value) +{ + m_cfg.writeEntry("UseZip64", value); +} + #include #include diff --git a/plugins/impex/kra/kra_export.cpp b/plugins/impex/kra/kra_export.cpp --- a/plugins/impex/kra/kra_export.cpp +++ b/plugins/impex/kra/kra_export.cpp @@ -62,10 +62,10 @@ KisImageBuilder_Result res = kraConverter.buildFile(io, filename()); if (res == KisImageBuilder_RESULT_OK) { - dbgFile << "success !"; + dbgFile << "KraExport::convert success !"; return KisImportExportFilter::OK; } - dbgFile << " Result =" << res; + dbgFile << "KraExport::convert result =" << res; return KisImportExportFilter::InternalError; }