Git commit 593dba2b7098049092072a4260005996b34a8a56 by Boudewijn Rempt. Committed on 23/01/2019 at 08:29. Pushed by rempt into branch 'master'. Use QuaZip instead of KArchive for ZIP64 support This makes it possible to save and load .kra files that are larger than 4GiB -- depending on available memory, of course. There is an option in the settings dialog to enable this; it's off by default because older versions of Krita cannot read Zip64 files. Note that everything that uses zip files now uses quazip, the karchive dependency is gone. CCMAIL:kimageshop@kde.org M +1 -0 3rdparty/CMakeLists.txt M +0 -18 3rdparty/ext_frameworks/CMakeLists.txt D +0 -39 3rdparty/ext_frameworks/karchive.diff A +12 -0 3rdparty/ext_quazip/CMakeLists.txt A +10 -0 3rdparty/ext_quazip/find_quazip.diff M +14 -1 CMakeLists.txt A +43 -0 cmake/modules/FindQuaZip.cmake M +12 -2 libs/store/CMakeLists.txt A +260 -0 libs/store/KoQuaZipStore.cpp [License: LGPL (v2+)] A +62 -0 libs/store/KoQuaZipStore.h [License: LGPL (v2+)] M +3 -12 libs/store/KoStore.cpp M +0 -25 libs/store/KoStore.h M +1 -5 libs/store/KoStore_p.h D +0 -257 libs/store/KoZipStore.cpp M +1 -6 libs/store/KoZipStore.h M +1 -0 libs/ui/KisImportExportManager.cpp M +1 -1 libs/ui/KisWelcomePageWidget.cpp M +8 -0 libs/ui/dialogs/kis_dlg_preferences.cc M +1 -0 libs/ui/dialogs/kis_dlg_preferences.h M +21 -11 libs/ui/forms/wdggeneralsettings.ui M +10 -0 libs/ui/kis_config.cc M +2 -0 libs/ui/kis_config.h M +2 -2 plugins/impex/kra/kra_export.cpp https://commits.kde.org/krita/593dba2b7098049092072a4260005996b34a8a56 diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index c992e5fade0..81127ae7e42 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -208,3 +208,4 @@ if (NOT APPLE) endif () = add_subdirectory(ext_giflib) +add_subdirectory(ext_quazip) diff --git a/3rdparty/ext_frameworks/CMakeLists.txt b/3rdparty/ext_framewor= ks/CMakeLists.txt index 5e5354204e2..1e9346574ab 100644 --- a/3rdparty/ext_frameworks/CMakeLists.txt +++ b/3rdparty/ext_frameworks/CMakeLists.txt @@ -2,7 +2,6 @@ SET(EXTPREFIX_frameworks "${EXTPREFIX}" ) # # All needed frameworks: # -# Archive = # Config = # WidgetsAddons = # Completion @@ -31,23 +30,6 @@ ExternalProject_Add( ) = = -ExternalProject_Add( - ext_karchive - DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} - URL http://download.kde.org/stable/frameworks/5.44/karchive-5.44.0.zip - URL_MD5 c60a8e22b88cc7328610041638459689 - PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/karc= hive.diff - INSTALL_DIR ${EXTPREFIX_frameworks} - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=3D${EXTPREFIX_frameworks} - -DCMAKE_BUILD_TYPE=3D${GLOBAL_BUILD_TYPE} = - ${GLOBAL_PROFILE} - -DCMAKE_SYSTEM_PREFIX_PATH=3D${EXTPREFIX} = - -DBUILD_TESTING=3Dfalse - UPDATE_COMMAND "" - DEPENDS ext_extra_cmake_modules -) - - ExternalProject_Add( ext_kconfig DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} diff --git a/3rdparty/ext_frameworks/karchive.diff b/3rdparty/ext_framework= s/karchive.diff deleted file mode 100644 index 909d6beb591..00000000000 --- a/3rdparty/ext_frameworks/karchive.diff +++ /dev/null @@ -1,39 +0,0 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 2441977..2a20a13 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -29,20 +29,20 @@ set_package_properties(ZLIB PROPERTIES - PURPOSE "Required by the core KDE libraries and some critical kioslav= es" - ) - = --find_package(BZip2) --set_package_properties(BZip2 PROPERTIES -- URL "http://www.bzip.org" -- DESCRIPTION "Support for BZip2 compressed files and data streams" -- TYPE RECOMMENDED -- PURPOSE "Support for BZip2 compressed files and data streams" --) -- --find_package(LibLZMA) --set_package_properties(LibLZMA PROPERTIES -- URL "http://tukaani.org/xz/" -- DESCRIPTION "Support for xz compressed files and data streams" -- PURPOSE "Support for xz compressed files and data streams" --) -+#find_package(BZip2) -+#set_package_properties(BZip2 PROPERTIES -+# URL "http://www.bzip.org" -+# DESCRIPTION "Support for BZip2 compressed files and data streams" -+# TYPE RECOMMENDED -+# PURPOSE "Support for BZip2 compressed files and data streams" -+#) -+ -+#find_package(LibLZMA) -+#set_package_properties(LibLZMA PROPERTIES -+# URL "http://tukaani.org/xz/" -+# DESCRIPTION "Support for xz compressed files and data streams" -+# PURPOSE "Support for xz compressed files and data streams" -+#) - include_directories( - ${ZLIB_INCLUDE_DIR} - ) diff --git a/3rdparty/ext_quazip/CMakeLists.txt b/3rdparty/ext_quazip/CMake= Lists.txt new file mode 100644 index 00000000000..5819b107c4c --- /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=3D${PREFIX_ext_quazip} -DCMAKE_BUILD= _TYPE=3D${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/fin= d_quazip.diff new file mode 100644 index 00000000000..a5fb1a5291d --- /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_SU= FFIX} CACHE + = + add_subdirectory(quazip) + = +-install(FILES FindQuaZip.cmake RENAME FindQuaZip${QUAZIP_LIB_VERSION_SUFF= IX}.cmake DESTINATION ${CMAKE_ROOT}/Modules) ++#install(FILES FindQuaZip.cmake RENAME FindQuaZip${QUAZIP_LIB_VERSION_SUF= FIX}.cmake DESTINATION ${CMAKE_ROOT}/Modules) diff --git a/CMakeLists.txt b/CMakeLists.txt index f17a07e0eda..f32061cd9fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,7 +275,6 @@ include(KDECompilerSettings) # do not reorder to be alphabetical: this is the order in which the framew= orks # depend on each other. find_package(KF5 ${MIN_FRAMEWORKS_VERSION} REQUIRED COMPONENTS - Archive Config WidgetsAddons Completion @@ -700,6 +699,20 @@ set_package_properties(Poppler PROPERTIES 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 index 00000000000..23f4918db4f --- /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 (combin= ed 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/i= nclude) + 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 QU= AZIP_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 index 719fe00a796..b7c42996bdb 100644 --- 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 @@ set(kritastore_LIB_SRCS 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::Gu= i 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_SOV= ERSION} diff --git a/libs/store/KoQuaZipStore.cpp b/libs/store/KoQuaZipStore.cpp new file mode 100644 index 00000000000..a48e9d81874 --- /dev/null +++ b/libs/store/KoQuaZipStore.cpp @@ -0,0 +1,260 @@ +/* + * 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 Licen= se + * 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 +#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 =3D _filename; + dd->archive =3D new QuaZip(_filename); + init(appIdentification); + +} + +KoQuaZipStore::KoQuaZipStore(QIODevice *dev, KoStore::Mode _mode, const QB= yteArray &appIdentification, bool writeMimetype) + : KoStore(_mode, writeMimetype) + , dd(new Private()) +{ + Q_D(KoStore); + dd->archive =3D 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 =3D Z_BEST_COMPRESSION; + } + else { + dd->compressionLevel =3D Z_NO_COMPRESSION; + } +} + +qint64 KoQuaZipStore::write(const char *_data, qint64 _len) +{ + Q_D(KoStore); + if (_len =3D=3D 0) return 0; + + if (!d->isOpen) { + errorStore << "KoStore: You must open before writing" << endl; + return 0; + } + + if (d->mode !=3D Write) { + errorStore << "KoStore: Can not write to store that is opened for = reading" << endl; + return 0; + } + + d->size +=3D _len; + if (dd->currentFile->write(_data, _len)) { // writeData returns a b= ool! + return _len; + } + return 0; +} + +QStringList KoQuaZipStore::directoryList() const +{ + return dd->archive->getFileNameList(); +} + +void KoQuaZipStore::init(const QByteArray &appIdentification) +{ + Q_D(KoStore); + + bool enableZip64 =3D false; + if (appIdentification =3D=3D "application/x-krita") { + enableZip64 =3D KSharedConfig::openConfig()->group("").readEntry("UseZip64", false); + } + dd->archive->setZip64Enabled(enableZip64); + dd->archive->setFileNameCodec("UTF-8"); + dd->usingSaveFile =3D dd->archive->getIoDevice() && dd->archive->getIo= Device()->inherits("QSaveFile"); + dd->archive->setAutoClose(!dd->usingSaveFile); + + d->good =3D dd->archive->open(d->mode =3D=3D Write ? QuaZip::mdCreate = : QuaZip::mdUnzip); + + if (!d->good) { + return; + } + + if (d->mode =3D=3D Write) { + if (d->writeMimetype) { + QuaZipFile f(dd->archive); + QuaZipNewInfo newInfo("mimetype"); + newInfo.setPermissions(QFileDevice::ReadOwner | QFileDevice::R= eadGroup | QFileDevice::ReadOther); + if (!f.open(QIODevice::WriteOnly, newInfo, 0, 0, Z_DEFLATED, Z= _NO_COMPRESSION)) { + d->good =3D false; + return; + } + f.write(appIdentification); + f.close(); + } + } + else { + d->good =3D dd->archive->getEntriesCount(); + } +} + +bool KoQuaZipStore::doFinalize() +{ + Q_D(KoStore); + + d->stream =3D 0; + if (!dd->usingSaveFile) { + dd->archive->close(); + } + return dd->archive->getZipError() =3D=3D ZIP_OK; + +} + +bool KoQuaZipStore::openWrite(const QString &name) +{ + Q_D(KoStore); + QString fixedPath =3D name; + fixedPath.replace("//", "/"); + + delete d->stream; + d->stream =3D 0; // Not used when writing + + delete dd->currentFile; + dd->currentFile =3D new QuaZipFile(dd->archive); + QuaZipNewInfo newInfo(fixedPath); + newInfo.setPermissions(QFileDevice::ReadOwner | QFileDevice::ReadGroup= | QFileDevice::ReadOther); + bool r =3D dd->currentFile->open(QIODevice::WriteOnly, newInfo, 0, 0, = Z_DEFLATED, dd->compressionLevel); + if (!r) { + qWarning() << "Could not open" << name << dd->currentFile->getZipE= rror(); + } + return r; +} + +bool KoQuaZipStore::openRead(const QString &name) +{ + Q_D(KoStore); + QString fixedPath =3D name; + fixedPath.replace("//", "/"); + + delete d->stream; + d->stream =3D 0; + delete dd->currentFile; + dd->currentFile =3D 0; + + if (!currentPath().isEmpty() && !fixedPath.startsWith(currentPath())) { + fixedPath =3D currentPath() + '/' + fixedPath; + } + + if (!dd->archive->setCurrentFile(fixedPath)) { + warnStore << "\t\tCould not set current file" << dd->archive->getZ= ipError(); + return false; + } + + dd->currentFile =3D new QuaZipFile(dd->archive); + if (!dd->currentFile->open(QIODevice::ReadOnly)) { + warnStore << "\t\t\tBut could not open!!!" << dd->archive->getZipE= rror(); + return false; + } + d->stream =3D dd->currentFile; + d->size =3D dd->currentFile->size(); + return true; +} + +bool KoQuaZipStore::closeWrite() +{ + Q_D(KoStore); + dd->currentFile->close(); + d->stream =3D 0; + return dd->currentFile->getZipError() =3D=3D ZIP_OK; +} + +bool KoQuaZipStore::closeRead() +{ + Q_D(KoStore); + d->stream =3D 0; + return true; +} + +bool KoQuaZipStore::enterRelativeDirectory(const QString &) +{ + return true; +} + +bool KoQuaZipStore::enterAbsoluteDirectory(const QString &path) +{ + QString fixedPath =3D 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 =3D absPath; + fixedPath.replace("//", "/"); + return dd->archive->getFileNameList().contains(fixedPath); +} diff --git a/libs/store/KoQuaZipStore.h b/libs/store/KoQuaZipStore.h new file mode 100644 index 00000000000..e9fc320aab4 --- /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 Licen= se + * 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 =3D true); + + KoQuaZipStore(QIODevice *dev, Mode mode, const QByteArray & appIdentif= ication, + bool writeMimetype =3D 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/KoStore.cpp b/libs/store/KoStore.cpp index ac6cc53021e..f0d3a4c9f16 100644 --- 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 @@ KoStore* KoStore::createStore(const QString& fileName, Mo= de mode, const QByteArr } switch (backend) { case Zip: - return new KoZipStore(fileName, mode, appIdentification, writeMime= type); + return new KoQuaZipStore(fileName, mode, appIdentification, writeM= imetype); case Directory: return new KoDirectoryStore(fileName /* should be a dir name.... *= /, mode, writeMimetype); default: @@ -90,19 +90,13 @@ KoStore* KoStore::createStore(QIODevice *device, Mode m= ode, const QByteArray & a errorStore << "Can't create a Directory store for a memory buffer!= " << endl; return 0; case Zip: - return new KoZipStore(device, mode, appIdentification, writeMimety= pe); + return new KoQuaZipStore(device, mode, appIdentification, writeMim= etype); default: warnStore << "Unsupported backend requested for KoStore : " << bac= kend; 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, backen= d, writeMimetype); -} - namespace { const char ROOTPART[] =3D "root"; @@ -168,15 +162,12 @@ bool KoStore::isOpen() const bool KoStore::close() { Q_D(KoStore); - debugStore << "Closing"; - if (!d->isOpen) { warnStore << "You must open before closing"; return false; } = bool ret =3D d->mode =3D=3D Write ? closeWrite() : closeRead(); - delete d->stream; d->stream =3D 0; d->isOpen =3D false; diff --git a/libs/store/KoStore.h b/libs/store/KoStore.h index ae5370e46ed..56d10657043 100644 --- a/libs/store/KoStore.h +++ b/libs/store/KoStore.h @@ -74,31 +74,6 @@ public: const QByteArray &appIdentification =3D QB= yteArray(), Backend backend =3D Auto, bool writeMimety= pe =3D 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!=3DDirectory. - * - * 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 =3D QB= yteArray(), Backend backend =3D Auto, bool writeMimetype =3D true); = /** * Destroys the store (i.e. closes the file on the hard disk) diff --git a/libs/store/KoStore_p.h b/libs/store/KoStore_p.h index 4a6c6e0ff44..565f6f4288f 100644 --- a/libs/store/KoStore_p.h +++ b/libs/store/KoStore_p.h @@ -70,11 +70,7 @@ public: 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.cpp b/libs/store/KoZipStore.cpp deleted file mode 100644 index badd197841d..00000000000 --- 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 Licen= se - 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 QByteAr= ray & appIdentification, - bool writeMimetype) - : KoStore(mode, writeMimetype) -{ - Q_D(KoStore); - - d->localFileName =3D _filename; - - m_pZip =3D new SaveZip(_filename); - - init(appIdentification); // open the zip file and init some vars -} - -KoZipStore::KoZipStore(QIODevice *dev, Mode mode, const QByteArray & appId= entification, - bool writeMimetype) - : KoStore(mode, writeMimetype) -{ - m_pZip =3D new SaveZip(dev); - init(appIdentification); -} - -KoZipStore::KoZipStore(QWidget* window, const QUrl &_url, const QString & = _filename, Mode mode, - const QByteArray & appIdentification, bool writeMim= etype) - : KoStore(mode, writeMimetype) -{ - debugStore << "KoZipStore Constructor url" << _url.url(QUrl::PreferLoc= alFile) - << " filename =3D " << _filename - << " mode =3D " << int(mode) - << " mimetype =3D " << appIdentification; - Q_D(KoStore); - - d->url =3D _url; - d->window =3D window; - - if (mode =3D=3D KoStore::Read) { - d->localFileName =3D _filename; - } else { - QTemporaryFile f("kozip"); - f.open(); - d->localFileName =3D f.fileName(); - f.close(); - } - - m_pZip =3D 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 c= lose(), which aborts on a qsavefile - } - else { - if (!d->finalized) { - finalize(); // ### no error checking when the app forgot to ca= ll finalize itself - } - } - delete m_pZip; - - // When writing, we write to a temp file that then gets copied over th= e original filename - if (d->mode =3D=3D Write && (!d->localFileName.isEmpty() && !d->url.is= Empty())) { - QFile f(d->localFileName); - if (f.copy(d->url.toLocalFile())) { - f.remove(); - } - } -} - -void KoZipStore::init(const QByteArray& appIdentification) -{ - Q_D(KoStore); - - m_currentDir =3D 0; - d->good =3D m_pZip->open(d->mode =3D=3D Write ? QIODevice::WriteOnly := QIODevice::ReadOnly); - - if (!d->good) - return; - - if (d->mode =3D=3D Write) { - - m_pZip->setCompression(KZip::NoCompression); - m_pZip->setExtraField(KZip::NoExtraField); - - // Write identification - if (d->writeMimetype) { - (void)m_pZip->writeFile(QLatin1String("mimetype"), appIdentifi= cation); - } - - 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 =3D m_pZip->directory() !=3D 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("QSaveFi= le")) { - return m_pZip->close(); - } - else { - return true; - } -} - -bool KoZipStore::openWrite(const QString& name) -{ - Q_D(KoStore); - d->stream =3D 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 =3D m_pZip->directory()->entry(name); - if (entry =3D=3D 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 =3D static_cast(entry); - delete d->stream; - d->stream =3D f->createDevice(); - d->size =3D f->size(); - return true; -} - -qint64 KoZipStore::write(const char* _data, qint64 _len) -{ - Q_D(KoStore); - if (_len =3D=3D 0) return 0; - if (!d->isOpen) { - errorStore << "KoStore: You must open before writing" << endl; - return 0; - } - if (d->mode !=3D Write) { - errorStore << "KoStore: Can not write to store that is opened for = reading" << endl; - return 0; - } - - d->size +=3D _len; - if (m_pZip->writeData(_data, _len)) // writeData returns a bool! - return _len; - return 0; -} - -QStringList KoZipStore::directoryList() const -{ - QStringList retval; - const KArchiveDirectory *directory =3D m_pZip->directory(); - Q_FOREACH (const QString &name, directory->entries()) { - const KArchiveEntry* fileArchiveEntry =3D m_pZip->directory()->ent= ry(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 =3D=3D Read) { - if (!m_currentDir) { - m_currentDir =3D m_pZip->directory(); // initialize - Q_ASSERT(d->currentPath.isEmpty()); - } - const KArchiveEntry *entry =3D m_currentDir->entry(dirName); - if (entry && entry->isDirectory()) { - m_currentDir =3D dynamic_cast(entry); - return m_currentDir !=3D 0; - } - return false; - } else // Write, no checking here - return true; -} - -bool KoZipStore::enterAbsoluteDirectory(const QString& path) -{ - if (path.isEmpty()) { - m_currentDir =3D 0; - return true; - } - m_currentDir =3D dynamic_cast(m_pZip->direct= ory()->entry(path)); - Q_ASSERT(m_currentDir); - return m_currentDir !=3D 0; -} - -bool KoZipStore::fileExists(const QString& absPath) const -{ - const KArchiveEntry *entry =3D m_pZip->directory()->entry(absPath); - return entry && entry->isFile(); -} diff --git a/libs/store/KoZipStore.h b/libs/store/KoZipStore.h index b1a4c0409fc..7e40bfa783c 100644 --- a/libs/store/KoZipStore.h +++ b/libs/store/KoZipStore.h @@ -33,12 +33,7 @@ public: bool writeMimetype =3D true); KoZipStore(QIODevice *dev, Mode mode, const QByteArray & appIdentifica= tion, bool writeMimetype =3D true); - /** - * QUrl-constructor - * @todo saving not completely implemented (fixed temporary file) - */ - KoZipStore(QWidget* window, const QUrl &_url, const QString & _filenam= e, Mode _mode, - const QByteArray & appIdentification, bool writeMimetype = =3D true); + ~KoZipStore() override; = void setCompressionEnabled(bool e) override; diff --git a/libs/ui/KisImportExportManager.cpp b/libs/ui/KisImportExportMa= nager.cpp index affa7e68937..7e8f616ad4b 100644 --- a/libs/ui/KisImportExportManager.cpp +++ b/libs/ui/KisImportExportManager.cpp @@ -648,6 +648,7 @@ KisImportExportFilter::ConversionStatus KisImportExport= Manager::doExportImpl(con } else { #ifdef USE_QSAVEFILE if (!file.commit()) { + qWarning() << "Could not commit QSaveFile"; QString error =3D file.errorString(); if (error.isEmpty()) { error =3D i18n("Could not write to %1.", location); diff --git a/libs/ui/KisWelcomePageWidget.cpp b/libs/ui/KisWelcomePageWidge= t.cpp index 255a8e5e770..bc906e1dc2a 100644 --- a/libs/ui/KisWelcomePageWidget.cpp +++ b/libs/ui/KisWelcomePageWidget.cpp @@ -209,7 +209,7 @@ void KisWelcomePageWidget::populateRecentDocuments() else { if (QFileInfo(recentFileUrlPath).exists()) { if (recentFileUrlPath.endsWith("ora") || recentFileUrlPath= .endsWith("kra")) { - QScopedPointer store(KoStore::createStore(QUr= l::fromLocalFile(recentFileUrlPath), KoStore::Read)); + QScopedPointer store(KoStore::createStore(rec= entFileUrlPath, 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.cc b/libs/ui/dialogs/kis_d= lg_preferences.cc index d6f197a16a3..d3d3c7ff4d3 100644 --- a/libs/ui/dialogs/kis_dlg_preferences.cc +++ b/libs/ui/dialogs/kis_dlg_preferences.cc @@ -185,6 +185,7 @@ GeneralTab::GeneralTab(QWidget *_parent, const char *_n= ame) m_autosaveCheckBox->setChecked(autosaveInterval > 0); = m_chkCompressKra->setChecked(cfg.compressKra()); + chkZip64->setChecked(cfg.useZip64()); = m_backupFileCheckBox->setChecked(cfg.backupFile()); = @@ -238,6 +239,7 @@ void GeneralTab::setDefault() 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 @@ bool GeneralTab::compressKra() return m_chkCompressKra->isChecked(); } = +bool GeneralTab::useZip64() +{ + return chkZip64->isChecked(); +} + bool GeneralTab::toolOptionsInDocker() { return m_radioToolOptionsInDocker->isChecked(); @@ -1337,6 +1344,7 @@ bool KisDlgPreferences::editPreferences() cfg.setBackupFile(dialog->m_general->m_backupFileCheckBox->isCheck= ed()); cfg.setShowCanvasMessages(dialog->m_general->showCanvasMessages()); cfg.setCompressKra(dialog->m_general->compressKra()); + cfg.setUseZip64(dialog->m_general->useZip64()); = const QString configPath =3D QStandardPaths::writableLocation(QSta= ndardPaths::GenericConfigLocation); QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), = QSettings::IniFormat); diff --git a/libs/ui/dialogs/kis_dlg_preferences.h b/libs/ui/dialogs/kis_dl= g_preferences.h index 626c42a0974..c28ac9bdfdc 100644 --- a/libs/ui/dialogs/kis_dlg_preferences.h +++ b/libs/ui/dialogs/kis_dlg_preferences.h @@ -85,6 +85,7 @@ public: int favoritePresets(); bool showCanvasMessages(); bool compressKra(); + bool useZip64(); bool toolOptionsInDocker(); bool kineticScrollingEnabled(); int kineticScrollingGesture(); diff --git a/libs/ui/forms/wdggeneralsettings.ui b/libs/ui/forms/wdggeneral= settings.ui index 5a49e1e2fee..66712afca50 100644 --- 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 colo= rspace - + @@ -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 t= his option for <span style=3D" font-weight:600;">very</s= pan> large files: larger than 4 GiB on disk.</p></body></= html> + + + Use Zip64 (for very large files: cannot be opened in ver= sions of Krita older than 4.2.0) + + + diff --git a/libs/ui/kis_config.cc b/libs/ui/kis_config.cc index 9551c4678e7..3bf4253a7ae 100644 --- a/libs/ui/kis_config.cc +++ b/libs/ui/kis_config.cc @@ -2004,6 +2004,16 @@ void KisConfig::setActivateTransformToolAfterPaste(b= ool value) 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/libs/ui/kis_config.h b/libs/ui/kis_config.h index dbc8d05056c..8f8cdab216b 100644 --- a/libs/ui/kis_config.h +++ b/libs/ui/kis_config.h @@ -579,6 +579,8 @@ public: bool activateTransformToolAfterPaste(bool defaultValue =3D false) cons= t; void setActivateTransformToolAfterPaste(bool value); = + bool useZip64(bool defaultValue =3D false) const; + void setUseZip64(bool value); = template void writeEntry(const QString& name, const T& value) { diff --git a/plugins/impex/kra/kra_export.cpp b/plugins/impex/kra/kra_expor= t.cpp index f135675413c..69a1a6984bd 100644 --- a/plugins/impex/kra/kra_export.cpp +++ b/plugins/impex/kra/kra_export.cpp @@ -62,10 +62,10 @@ KisImportExportFilter::ConversionStatus KraExport::conv= ert(KisDocument *document KisImageBuilder_Result res =3D kraConverter.buildFile(io, filename()); = if (res =3D=3D KisImageBuilder_RESULT_OK) { - dbgFile << "success !"; + dbgFile << "KraExport::convert success !"; return KisImportExportFilter::OK; } - dbgFile << " Result =3D" << res; + dbgFile << "KraExport::convert result =3D" << res; return KisImportExportFilter::InternalError; } =20