diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e183267c9..005dfeb136 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,841 +1,840 @@ project(krita) message(STATUS "Using CMake version: ${CMAKE_VERSION}") cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) set(MIN_QT_VERSION 5.6.0) set(MIN_FRAMEWORKS_VERSION 5.18.0) if (POLICY CMP0002) cmake_policy(SET CMP0002 OLD) endif() if (POLICY CMP0017) cmake_policy(SET CMP0017 NEW) endif () if (POLICY CMP0022) cmake_policy(SET CMP0022 OLD) endif () if (POLICY CMP0026) cmake_policy(SET CMP0026 OLD) endif() if (POLICY CMP0042) cmake_policy(SET CMP0042 NEW) endif() if (POLICY CMP0046) cmake_policy(SET CMP0046 OLD) endif () if (POLICY CMP0059) cmake_policy(SET CMP0059 OLD) endif() if (POLICY CMP0063) cmake_policy(SET CMP0063 OLD) endif() if (POLICY CMP0054) cmake_policy(SET CMP0054 OLD) endif() if (POLICY CMP0064) cmake_policy(SET CMP0064 OLD) endif() if (POLICY CMP0071) cmake_policy(SET CMP0071 OLD) endif() if (APPLE) set(APPLE_SUPPRESS_X11_WARNING TRUE) set(KDE_SKIP_RPATH_SETTINGS TRUE) set(CMAKE_MACOSX_RPATH 1) set(BUILD_WITH_INSTALL_RPATH 1) add_definitions(-mmacosx-version-min=10.11 -Wno-macro-redefined -Wno-deprecated-register) endif() if (CMAKE_COMPILER_IS_GNUCXX AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9 AND NOT WIN32) add_definitions(-Wno-suggest-override) endif() ###################### ####################### ## Constants defines ## ####################### ###################### # define common versions of Krita applications, used to generate kritaversion.h # update these version for every release: set(KRITA_VERSION_STRING "4.2.0-beta") # Major version: 3 for 3.x, 4 for 4.x, etc. set(KRITA_STABLE_VERSION_MAJOR 4) # Minor version: 0 for 4.0, 1 for 4.1, etc. set(KRITA_STABLE_VERSION_MINOR 2) # Bugfix release version, or 0 for before the first stable release set(KRITA_VERSION_RELEASE 0) # the 4th digit, really only used for the Windows installer: # - [Pre-]Alpha: Starts from 0, increment 1 per release # - Beta: Starts from 50, increment 1 per release # - Stable: Set to 100, bump to 101 if emergency update is needed set(KRITA_VERSION_REVISION 0) #set(KRITA_ALPHA 1) # uncomment only for Alpha set(KRITA_BETA 1) # uncomment only for Beta #set(KRITA_RC 1) # uncomment only for RC set(KRITA_YEAR 2018) # update every year if(NOT DEFINED KRITA_ALPHA AND NOT DEFINED KRITA_BETA AND NOT DEFINED KRITA_RC) set(KRITA_STABLE 1) # do not edit endif() message(STATUS "Krita version: ${KRITA_VERSION_STRING}") # Define the generic version of the Krita libraries here # This makes it easy to advance it when the next Krita release comes. # 14 was the last GENERIC_KRITA_LIB_VERSION_MAJOR of the previous Krita series # (2.x) so we're starting with 15 in 3.x series, 16 in 4.x series if(KRITA_STABLE_VERSION_MAJOR EQUAL 4) math(EXPR GENERIC_KRITA_LIB_VERSION_MAJOR "${KRITA_STABLE_VERSION_MINOR} + 16") else() # let's make sure we won't forget to update the "16" message(FATAL_ERROR "Reminder: please update offset == 16 used to compute GENERIC_KRITA_LIB_VERSION_MAJOR to something bigger") endif() set(GENERIC_KRITA_LIB_VERSION "${GENERIC_KRITA_LIB_VERSION_MAJOR}.0.0") set(GENERIC_KRITA_LIB_SOVERSION "${GENERIC_KRITA_LIB_VERSION_MAJOR}") LIST (APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules") LIST (APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/kde_macro") # fetch git revision for the current build set(KRITA_GIT_SHA1_STRING "") set(KRITA_GIT_BRANCH_STRING "") include(GetGitRevisionDescription) get_git_head_hash(GIT_SHA1) get_git_branch(GIT_BRANCH) if(GIT_SHA1) string(SUBSTRING ${GIT_SHA1} 0 7 GIT_SHA1) set(KRITA_GIT_SHA1_STRING ${GIT_SHA1}) if(GIT_BRANCH) set(KRITA_GIT_BRANCH_STRING ${GIT_BRANCH}) else() set(KRITA_GIT_BRANCH_STRING "(detached HEAD)") endif() endif() # create test make targets enable_testing() # collect list of broken tests, empty here to start fresh with each cmake run set(KRITA_BROKEN_TESTS "" CACHE INTERNAL "KRITA_BROKEN_TESTS") ############ ############# ## Options ## ############# ############ include(FeatureSummary) if (WIN32) option(USE_DRMINGW "Support the Dr. Mingw crash handler (only on windows)" ON) add_feature_info("Dr. Mingw" USE_DRMINGW "Enable the Dr. Mingw crash handler") if (MINGW) option(USE_MINGW_HARDENING_LINKER "Enable DEP (NX), ASLR and high-entropy ASLR linker flags (mingw-w64)" ON) add_feature_info("Linker Security Flags" USE_MINGW_HARDENING_LINKER "Enable DEP (NX), ASLR and high-entropy ASLR linker flags") if (USE_MINGW_HARDENING_LINKER) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--dynamicbase -Wl,--nxcompat -Wl,--disable-auto-image-base") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--dynamicbase -Wl,--nxcompat -Wl,--disable-auto-image-base") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--dynamicbase -Wl,--nxcompat -Wl,--disable-auto-image-base") if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") # Enable high-entropy ASLR for 64-bit # The image base has to be >4GB for HEASLR to be enabled. # The values used here are kind of arbitrary. set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--high-entropy-va -Wl,--image-base,0x140000000") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--high-entropy-va -Wl,--image-base,0x180000000") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--high-entropy-va -Wl,--image-base,0x180000000") endif ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") else (USE_MINGW_HARDENING_LINKER) message(WARNING "Linker Security Flags not enabled!") endif (USE_MINGW_HARDENING_LINKER) endif (MINGW) endif () option(HIDE_SAFE_ASSERTS "Don't show message box for \"safe\" asserts, just ignore them automatically and dump a message to the terminal." ON) configure_file(config-hide-safe-asserts.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-hide-safe-asserts.h) add_feature_info("Hide Safe Asserts" HIDE_SAFE_ASSERTS "Don't show message box for \"safe\" asserts, just ignore them automatically and dump a message to the terminal.") option(USE_LOCK_FREE_HASH_TABLE "Use lock free hash table instead of blocking." ON) configure_file(config-hash-table-implementaion.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-hash-table-implementaion.h) add_feature_info("Lock free hash table" USE_LOCK_FREE_HASH_TABLE "Use lock free hash table instead of blocking.") option(FOUNDATION_BUILD "A Foundation build is a binary release build that can package some extra things like color themes. Linux distributions that build and install Krita into a default system location should not define this option to true." OFF) add_feature_info("Foundation Build" FOUNDATION_BUILD "A Foundation build is a binary release build that can package some extra things like color themes. Linux distributions that build and install Krita into a default system location should not define this option to true.") option(KRITA_ENABLE_BROKEN_TESTS "Enable tests that are marked as broken" OFF) add_feature_info("Enable Broken Tests" KRITA_ENABLE_BROKEN_TESTS "Runs broken test when \"make test\" is invoked (use -DKRITA_ENABLE_BROKEN_TESTS=ON to enable).") option(LIMIT_LONG_TESTS "Run long running unittests in a limited quick mode" ON) configure_file(config-limit-long-tests.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-limit-long-tests.h) add_feature_info("Limit long tests" LIMIT_LONG_TESTS "Run long running unittests in a limited quick mode") option(ENABLE_PYTHON_2 "Enables the compiler to look for Python 2.7 instead of Python 3. Some packaged scripts are not compatible with Python 2 and this should only be used if you really have to use 2.7." OFF) option(BUILD_KRITA_QT_DESIGNER_PLUGINS "Build Qt Designer plugins for Krita widgets" OFF) add_feature_info("Build Qt Designer plugins" BUILD_KRITA_QT_DESIGNER_PLUGINS "Builds Qt Designer plugins for Krita widgets (use -DBUILD_KRITA_QT_DESIGNER_PLUGINS=ON to enable).") include(MacroJPEG) ######################################################### ## Look for Python3 It is also searched by KF5, ## ## so we should request the correct version in advance ## ######################################################### function(TestCompileLinkPythonLibs OUTPUT_VARNAME) include(CheckCXXSourceCompiles) set(CMAKE_REQUIRED_INCLUDES ${PYTHON_INCLUDE_PATH}) set(CMAKE_REQUIRED_LIBRARIES ${PYTHON_LIBRARIES}) if (MINGW) set(CMAKE_REQUIRED_DEFINITIONS -D_hypot=hypot) endif (MINGW) unset(${OUTPUT_VARNAME} CACHE) CHECK_CXX_SOURCE_COMPILES(" #include int main(int argc, char *argv[]) { Py_InitializeEx(0); }" ${OUTPUT_VARNAME}) endfunction() if(MINGW) if(ENABLE_PYTHON_2) message(FATAL_ERROR "Python 2.7 is not supported on Windows at the moment.") else(ENABLE_PYTHON_2) find_package(PythonInterp 3.6 EXACT) find_package(PythonLibs 3.6 EXACT) endif(ENABLE_PYTHON_2) if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) if(ENABLE_PYTHON_2) find_package(PythonLibrary 2.7) else(ENABLE_PYTHON_2) find_package(PythonLibrary 3.6) endif(ENABLE_PYTHON_2) TestCompileLinkPythonLibs(CAN_USE_PYTHON_LIBS) if (NOT CAN_USE_PYTHON_LIBS) message(FATAL_ERROR "Compiling with Python library failed, please check whether the architecture is correct. Python will be disabled.") endif (NOT CAN_USE_PYTHON_LIBS) endif (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) else(MINGW) if(ENABLE_PYTHON_2) find_package(PythonInterp 2.7) find_package(PythonLibrary 2.7) else(ENABLE_PYTHON_2) find_package(PythonInterp 3.0) find_package(PythonLibrary 3.0) endif(ENABLE_PYTHON_2) endif(MINGW) ######################## ######################### ## Look for KDE and Qt ## ######################### ######################## find_package(ECM 5.22 REQUIRED NOMODULE) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) include(ECMOptionalAddSubdirectory) include(ECMAddAppIcon) include(ECMSetupVersion) include(ECMMarkNonGuiExecutable) include(ECMGenerateHeaders) include(GenerateExportHeader) include(ECMMarkAsTest) include(ECMInstallIcons) include(CMakePackageConfigHelpers) include(WriteBasicConfigVersionFile) include(CheckFunctionExists) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings) # 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 Config WidgetsAddons Completion CoreAddons GuiAddons I18n ItemModels ItemViews WindowSystem - Archive ) # KConfig deprecated authorizeKAction. In order to be warning free, # compile with the updated function when the dependency is new enough. # Remove this (and the uses of the define) when the minimum KF5 # version is >= 5.24.0. if (${KF5Config_VERSION} VERSION_LESS "5.24.0" ) message("Old KConfig (< 5.24.0) found.") add_definitions(-DKCONFIG_BEFORE_5_24) endif() find_package(Qt5 ${MIN_QT_VERSION} REQUIRED COMPONENTS Core Gui Widgets Xml Network PrintSupport Svg Test Concurrent ) if (WIN32) set(CMAKE_REQUIRED_INCLUDES ${Qt5Core_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${Qt5Core_LIBRARIES}) CHECK_CXX_SOURCE_COMPILES(" #include int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_MSWindowsUseWinTabAPI); } " QT_HAS_WINTAB_SWITCH ) unset(CMAKE_REQUIRED_INCLUDES) unset(CMAKE_REQUIRED_LIBRARIES) option(USE_QT_TABLET_WINDOWS "Do not use Krita's forked Wintab and Windows Ink support on Windows, but leave everything to Qt." ON) add_feature_info("Use Qt's Windows Tablet Support" USE_QT_TABLET_WINDOWS "Do not use Krita's forked Wintab and Windows Ink support on Windows, but leave everything to Qt.") configure_file(config_use_qt_tablet_windows.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_use_qt_tablet_windows.h) endif () set(CMAKE_REQUIRED_INCLUDES ${Qt5Core_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES}) CHECK_CXX_SOURCE_COMPILES(" #include int main(int argc, char *argv[]) { QSurfaceFormat fmt; fmt.setColorSpace(QSurfaceFormat::scRGBColorSpace); fmt.setColorSpace(QSurfaceFormat::bt2020PQColorSpace); } " HAVE_HDR ) configure_file(config-hdr.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-hdr.h) CHECK_CXX_SOURCE_COMPILES(" #include int main(int argc, char *argv[]) { QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Round); QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor); QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); } " HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY ) configure_file(config-high-dpi-scale-factor-rounding-policy.h.in ${CMAKE_CURRENT_BINARY_DIR}/config-high-dpi-scale-factor-rounding-policy.h) if (WIN32) CHECK_CXX_SOURCE_COMPILES(" #include int main(int argc, char *argv[]) { QWindowsWindowFunctions::setHasBorderInFullScreenDefault(true); } " HAVE_SET_HAS_BORDER_IN_FULL_SCREEN_DEFAULT ) configure_file(config-set-has-border-in-full-screen-default.h.in ${CMAKE_CURRENT_BINARY_DIR}/config-set-has-border-in-full-screen-default.h) endif (WIN32) unset(CMAKE_REQUIRED_INCLUDES) unset(CMAKE_REQUIRED_LIBRARIES) include (MacroAddFileDependencies) include (MacroBoolTo01) include (MacroEnsureOutOfSourceBuild) macro_ensure_out_of_source_build("Compiling Krita inside the source directory is not possible. Please refer to the build instruction https://community.kde.org/Krita#Build_Instructions") # Note: OPTIONAL_COMPONENTS does not seem to be reliable # (as of ECM 5.15.0, CMake 3.2) find_package(Qt5Multimedia ${MIN_QT_VERSION}) set_package_properties(Qt5Multimedia PROPERTIES DESCRIPTION "Qt multimedia integration" URL "http://www.qt.io/" TYPE OPTIONAL PURPOSE "Optionally used to provide sound support for animations") macro_bool_to_01(Qt5Multimedia_FOUND HAVE_QT_MULTIMEDIA) configure_file(config-qtmultimedia.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-qtmultimedia.h ) if (NOT APPLE) find_package(Qt5Quick ${MIN_QT_VERSION}) set_package_properties(Qt5Quick PROPERTIES DESCRIPTION "QtQuick" URL "http://www.qt.io/" TYPE OPTIONAL PURPOSE "Optionally used for the touch gui for Krita") macro_bool_to_01(Qt5Quick_FOUND HAVE_QT_QUICK) find_package(Qt5QuickWidgets ${MIN_QT_VERSION}) set_package_properties(Qt5QuickWidgets PROPERTIES DESCRIPTION "QtQuickWidgets" URL "http://www.qt.io/" TYPE OPTIONAL PURPOSE "Optionally used for the touch gui for Krita") endif() if (NOT WIN32 AND NOT APPLE) find_package(Qt5 ${MIN_QT_VERSION} REQUIRED X11Extras) find_package(Qt5DBus ${MIN_QT_VERSION}) set(HAVE_DBUS ${Qt5DBus_FOUND}) set_package_properties(Qt5DBus PROPERTIES DESCRIPTION "Qt DBUS integration" URL "http://www.qt.io/" TYPE OPTIONAL PURPOSE "Optionally used to provide a dbus api on Linux") find_package(KF5Crash ${MIN_FRAMEWORKS_VERSION}) macro_bool_to_01(KF5Crash_FOUND HAVE_KCRASH) set_package_properties(KF5Crash PROPERTIES DESCRIPTION "KDE's Crash Handler" URL "http://api.kde.org/frameworks-api/frameworks5-apidocs/kcrash/html/index.html" TYPE OPTIONAL PURPOSE "Optionally used to provide crash reporting on Linux") find_package(X11 REQUIRED COMPONENTS Xinput) set(HAVE_X11 TRUE) add_definitions(-DHAVE_X11) find_package(XCB COMPONENTS XCB ATOM) set(HAVE_XCB ${XCB_FOUND}) else() set(HAVE_DBUS FALSE) set(HAVE_X11 FALSE) set(HAVE_XCB FALSE) endif() add_definitions( -DQT_USE_QSTRINGBUILDER -DQT_STRICT_ITERATORS -DQT_NO_SIGNALS_SLOTS_KEYWORDS -DQT_NO_URL_CAST_FROM_STRING ) if (${Qt5_VERSION} VERSION_GREATER "5.8.0" ) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50900) elseif(${Qt5_VERSION} VERSION_GREATER "5.7.0" ) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50800) elseif(${Qt5_VERSION} VERSION_GREATER "5.6.0" ) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50700) else() add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50600) endif() add_definitions(-DTRANSLATION_DOMAIN=\"krita\") # # The reason for this mode is that the Debug mode disable inlining # if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals") endif() option(KRITA_DEVS "For Krita developers. This modifies the DEBUG build type to use -O3 -g, while still enabling Q_ASSERT. This is necessary because the Qt5 cmake modules normally append QT_NO_DEBUG to any build type that is not labeled Debug") if (KRITA_DEVS) set(CMAKE_CXX_FLAGS_DEBUG "-O3 -g" CACHE STRING "" FORCE) endif() if(UNIX) set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES};m") endif() if(WIN32) if(MSVC) # C4522: 'class' : multiple assignment operators specified set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -wd4522") endif() endif() # KDECompilerSettings adds the `--export-all-symbols` linker flag. # We don't really need it. if(MINGW) string(REPLACE "-Wl,--export-all-symbols" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") string(REPLACE "-Wl,--export-all-symbols" "" CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}") endif(MINGW) if(MINGW) # Hack CMake's variables to tell AR to create thin archives to reduce unnecessary writes. # Source of definition: https://github.com/Kitware/CMake/blob/v3.14.1/Modules/Platform/Windows-GNU.cmake#L128 # Thin archives: https://sourceware.org/binutils/docs/binutils/ar.html#index-thin-archives macro(mingw_use_thin_archive lang) foreach(rule CREATE_SHARED_MODULE CREATE_SHARED_LIBRARY LINK_EXECUTABLE) string(REGEX REPLACE "( [^ T]+) " "\\1T " CMAKE_${lang}_${rule} "${CMAKE_${lang}_${rule}}") endforeach() endmacro() mingw_use_thin_archive(CXX) endif(MINGW) # enable exceptions globally kde_enable_exceptions() set(KRITA_DEFAULT_TEST_DATA_DIR ${CMAKE_SOURCE_DIR}/sdk/tests/data/) macro(macro_add_unittest_definitions) add_definitions(-DFILES_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data/") add_definitions(-DFILES_OUTPUT_DIR="${CMAKE_CURRENT_BINARY_DIR}") add_definitions(-DFILES_DEFAULT_DATA_DIR="${KRITA_DEFAULT_TEST_DATA_DIR}") add_definitions(-DSYSTEM_RESOURCES_DATA_DIR="${CMAKE_SOURCE_DIR}/krita/data/") endmacro() # overcome some platform incompatibilities if(WIN32) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/winquirks) add_definitions(-D_USE_MATH_DEFINES) add_definitions(-DNOMINMAX) set(WIN32_PLATFORM_NET_LIBS ws2_32.lib netapi32.lib) endif() # set custom krita plugin installdir set(KRITA_PLUGIN_INSTALL_DIR ${LIB_INSTALL_DIR}/kritaplugins) ########################### ############################ ## Required dependencies ## ############################ ########################### find_package(PNG REQUIRED) if (APPLE) # this is not added correctly on OSX -- see http://forum.kde.org/viewtopic.php?f=139&t=101867&p=221242#p221242 include_directories(SYSTEM ${PNG_INCLUDE_DIR}) endif() add_definitions(-DBOOST_ALL_NO_LIB) find_package(Boost 1.55 REQUIRED COMPONENTS system) include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) ## ## Test for GNU Scientific Library ## find_package(GSL) set_package_properties(GSL PROPERTIES URL "http://www.gnu.org/software/gsl" TYPE RECOMMENDED PURPOSE "Required by Krita's Transform tool.") macro_bool_to_01(GSL_FOUND HAVE_GSL) configure_file(config-gsl.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-gsl.h ) ########################### ############################ ## Optional dependencies ## ############################ ########################### find_package(ZLIB) set_package_properties(ZLIB PROPERTIES DESCRIPTION "Compression library" URL "http://www.zlib.net/" TYPE OPTIONAL PURPOSE "Optionally used by the G'Mic and the PSD plugins") macro_bool_to_01(ZLIB_FOUND HAVE_ZLIB) find_package(OpenEXR) set_package_properties(OpenEXR PROPERTIES DESCRIPTION "High dynamic-range (HDR) image file format" URL "http://www.openexr.com" TYPE OPTIONAL PURPOSE "Required by the Krita OpenEXR filter") macro_bool_to_01(OPENEXR_FOUND HAVE_OPENEXR) set(LINK_OPENEXR_LIB) if(OPENEXR_FOUND) include_directories(SYSTEM ${OPENEXR_INCLUDE_DIR}) set(LINK_OPENEXR_LIB ${OPENEXR_LIBRARIES}) add_definitions(${OPENEXR_DEFINITIONS}) endif() find_package(TIFF) set_package_properties(TIFF PROPERTIES DESCRIPTION "TIFF Library and Utilities" URL "http://www.remotesensing.org/libtiff" TYPE OPTIONAL PURPOSE "Required by the Krita TIFF filter") find_package(JPEG) set_package_properties(JPEG PROPERTIES DESCRIPTION "Free library for JPEG image compression. Note: libjpeg8 is NOT supported." URL "http://www.libjpeg-turbo.org" TYPE OPTIONAL PURPOSE "Required by the Krita JPEG filter") find_package(GIF) set_package_properties(GIF PROPERTIES DESCRIPTION "Library for loading and saving gif files." URL "http://giflib.sourceforge.net/" TYPE OPTIONAL PURPOSE "Required by the Krita GIF filter") find_package(HEIF "1.3.0") set_package_properties(HEIF PROPERTIES DESCRIPTION "Library for loading and saving heif files." URL "https://github.com/strukturag/libheif" TYPE OPTIONAL PURPOSE "Required by the Krita HEIF filter") set(LIBRAW_MIN_VERSION "0.16") find_package(LibRaw ${LIBRAW_MIN_VERSION}) set_package_properties(LibRaw PROPERTIES DESCRIPTION "Library to decode RAW images" URL "http://www.libraw.org" TYPE OPTIONAL PURPOSE "Required to build the raw import plugin") find_package(FFTW3) set_package_properties(FFTW3 PROPERTIES DESCRIPTION "A fast, free C FFT library" URL "http://www.fftw.org/" TYPE OPTIONAL PURPOSE "Required by the Krita for fast convolution operators and some G'Mic features") macro_bool_to_01(FFTW3_FOUND HAVE_FFTW3) find_package(OCIO) set_package_properties(OCIO PROPERTIES DESCRIPTION "The OpenColorIO Library" URL "http://www.opencolorio.org" TYPE OPTIONAL PURPOSE "Required by the Krita LUT docker") macro_bool_to_01(OCIO_FOUND HAVE_OCIO) set_package_properties(PythonLibrary PROPERTIES DESCRIPTION "Python Library" URL "http://www.python.org" TYPE OPTIONAL PURPOSE "Required by the Krita PyQt plugin") macro_bool_to_01(PYTHONLIBS_FOUND HAVE_PYTHONLIBS) find_package(SIP "4.19.13") set_package_properties(SIP PROPERTIES DESCRIPTION "Support for generating SIP Python bindings" URL "https://www.riverbankcomputing.com/software/sip/download" TYPE OPTIONAL PURPOSE "Required by the Krita PyQt plugin") macro_bool_to_01(SIP_FOUND HAVE_SIP) find_package(PyQt5 "5.6.0") set_package_properties(PyQt5 PROPERTIES DESCRIPTION "Python bindings for Qt5." URL "https://www.riverbankcomputing.com/software/pyqt/download5" TYPE OPTIONAL PURPOSE "Required by the Krita PyQt plugin") macro_bool_to_01(PYQT5_FOUND HAVE_PYQT5) ## ## Look for OpenGL ## # TODO: see if there is a better check for QtGui being built with opengl support (and thus the QOpenGL* classes) if(Qt5Gui_OPENGL_IMPLEMENTATION) message(STATUS "Found QtGui OpenGL support") else() message(FATAL_ERROR "Did NOT find QtGui OpenGL support. Check your Qt configuration. You cannot build Krita without Qt OpenGL support.") endif() ## ## Test for eigen3 ## find_package(Eigen3 3.0 REQUIRED) set_package_properties(Eigen3 PROPERTIES DESCRIPTION "C++ template library for linear algebra" URL "http://eigen.tuxfamily.org" TYPE REQUIRED) ## ## Test for exiv2 ## find_package(LibExiv2 0.16 REQUIRED) ## ## Test for lcms ## find_package(LCMS2 2.4 REQUIRED) set_package_properties(LCMS2 PROPERTIES DESCRIPTION "LittleCMS Color management engine" URL "http://www.littlecms.com" TYPE REQUIRED PURPOSE "Will be used for color management and is necessary for Krita") if(LCMS2_FOUND) if(NOT ${LCMS2_VERSION} VERSION_LESS 2040 ) set(HAVE_LCMS24 TRUE) endif() set(HAVE_REQUIRED_LCMS_VERSION TRUE) set(HAVE_LCMS2 TRUE) endif() ## ## Test for Vc ## set(OLD_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules ) set(HAVE_VC FALSE) if (NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") if(NOT MSVC) find_package(Vc 1.1.0) set_package_properties(Vc PROPERTIES DESCRIPTION "Portable, zero-overhead SIMD library for C++" URL "https://github.com/VcDevel/Vc" TYPE OPTIONAL PURPOSE "Required by the Krita for vectorization") macro_bool_to_01(Vc_FOUND HAVE_VC) endif() endif() configure_file(config-vc.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-vc.h ) if(HAVE_VC) message(STATUS "Vc found!") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/vc") include (VcMacros) if(Vc_COMPILER_IS_CLANG) set(ADDITIONAL_VC_FLAGS "-Wabi -ffp-contract=fast") if(NOT WIN32) set(ADDITIONAL_VC_FLAGS "${ADDITIONAL_VC_FLAGS} -fPIC") endif() elseif (NOT MSVC) set(ADDITIONAL_VC_FLAGS "-Wabi -fabi-version=0 -ffp-contract=fast") if(NOT WIN32) set(ADDITIONAL_VC_FLAGS "${ADDITIONAL_VC_FLAGS} -fPIC") endif() endif() #Handle Vc master if(Vc_COMPILER_IS_GCC OR Vc_COMPILER_IS_CLANG) AddCompilerFlag("-std=c++11" _ok) if(NOT _ok) AddCompilerFlag("-std=c++0x" _ok) endif() endif() macro(ko_compile_for_all_implementations_no_scalar _objs _src) vc_compile_for_all_implementations(${_objs} ${_src} FLAGS ${ADDITIONAL_VC_FLAGS} ONLY SSE2 SSSE3 SSE4_1 AVX AVX2+FMA+BMI2) endmacro() macro(ko_compile_for_all_implementations _objs _src) vc_compile_for_all_implementations(${_objs} ${_src} FLAGS ${ADDITIONAL_VC_FLAGS} ONLY Scalar SSE2 SSSE3 SSE4_1 AVX AVX2+FMA+BMI2) endmacro() endif() set(CMAKE_MODULE_PATH ${OLD_CMAKE_MODULE_PATH} ) add_definitions(${QT_DEFINITIONS} ${QT_QTDBUS_DEFINITIONS}) ## ## Test endianness ## include (TestBigEndian) test_big_endian(CMAKE_WORDS_BIGENDIAN) ## ## Test for qt-poppler ## find_package(Poppler COMPONENTS Qt5) set_package_properties(Poppler PROPERTIES DESCRIPTION "A PDF rendering library" URL "http://poppler.freedesktop.org" TYPE OPTIONAL PURPOSE "Required by the Krita PDF filter.") ## ## Test for quazip ## find_package(QuaZip 0.6) 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 ## include(CheckAtomic) ############################ ############################# ## Add Krita helper macros ## ############################# ############################ include(MacroKritaAddBenchmark) #################### ##################### ## Define includes ## ##################### #################### # for config.h and includes (if any?) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/interfaces ) add_subdirectory(libs) add_subdirectory(plugins) if (BUILD_TESTING) add_subdirectory(benchmarks) endif() add_subdirectory(krita) configure_file(KoConfig.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/KoConfig.h ) configure_file(config_convolution.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_convolution.h) configure_file(config-ocio.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-ocio.h ) check_function_exists(powf HAVE_POWF) configure_file(config-powf.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-powf.h) if(WIN32) include(${CMAKE_CURRENT_LIST_DIR}/packaging/windows/installer/ConfigureInstallerNsis.cmake) endif() message("\nBroken tests:") foreach(tst ${KRITA_BROKEN_TESTS}) message(" * ${tst}") endforeach() feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/po OR EXISTS ${CMAKE_CURRENT_BINARY_DIR}/po ) find_package(KF5I18n CONFIG REQUIRED) ki18n_install(po) endif() diff --git a/libs/store/CMakeLists.txt b/libs/store/CMakeLists.txt index 757c991091..b7c42996bd 100644 --- a/libs/store/CMakeLists.txt +++ b/libs/store/CMakeLists.txt @@ -1,36 +1,34 @@ include_directories(${QUAZIP_INCLUDE_DIRS}) add_subdirectory(tests) set(kritastore_LIB_SRCS KoDirectoryStore.cpp KoStoreDevice.cpp KoLZF.cpp KoStore.cpp KoXmlNS.cpp KoXmlReader.cpp KoXmlWriter.cpp KoQuaZipStore.cpp - KoLegacyZipStore.cpp StoreDebug.cpp ) add_library(kritastore SHARED ${kritastore_LIB_SRCS}) generate_export_header(kritastore BASE_NAME kritastore) target_link_libraries(kritastore PRIVATE kritaversion kritaglobal KF5::ConfigCore - KF5::Archive Qt5::Xml Qt5::Gui ${QUAZIP_LIBRARIES} ) set_target_properties(kritastore PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritastore ${INSTALL_TARGETS_DEFAULT_ARGS} ) diff --git a/libs/store/KoLegacyZipStore.cpp b/libs/store/KoLegacyZipStore.cpp deleted file mode 100644 index 72ceb155d8..0000000000 --- a/libs/store/KoLegacyZipStore.cpp +++ /dev/null @@ -1,272 +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 "KoLegacyZipStore.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); - } -}; - -KoLegacyZipStore::KoLegacyZipStore(const QString & _filename, Mode mode, const QByteArray & appIdentification, - bool writeMimetype) - : KoStore(mode, writeMimetype) -{ -// qDebug() << "KoLegacyZipStore Constructor filename =" << _filename -// << " mode = " << int(mode) -// << " mimetype = " << appIdentification; - Q_D(KoStore); - - d->localFileName = _filename; - - m_pZip = new SaveZip(_filename); - - init(appIdentification); // open the zip file and init some vars -} - -KoLegacyZipStore::KoLegacyZipStore(QIODevice *dev, Mode mode, const QByteArray & appIdentification, - bool writeMimetype) - : KoStore(mode, writeMimetype) -{ -// qDebug() << "KoLegacyZipStore Constructor device =" << dev -// << " mode = " << int(mode) -// << " mimetype = " << appIdentification; - - m_pZip = new SaveZip(dev); - init(appIdentification); -} - -KoLegacyZipStore::KoLegacyZipStore(QWidget* window, const QUrl &_url, const QString & _filename, Mode mode, - const QByteArray & appIdentification, bool writeMimetype) - : KoStore(mode, writeMimetype) -{ - debugStore << "KoLegacyZipStore 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 -} - -KoLegacyZipStore::~KoLegacyZipStore() -{ - Q_D(KoStore); -// bool sf = false; -// if (m_pZip && m_pZip->device()) { -// sf = true; -// } -// qDebug() << "KoLegacyZipStore::~KoLegacyZipStore" << d->localFileName << m_pZip << m_pZip->device() << "savefile" << sf; - 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 KoLegacyZipStore::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) { - //debugStore <<"KoLegacyZipStore::init writing mimetype" << appIdentification; - - 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 KoLegacyZipStore::setCompressionEnabled(bool e) -{ - if (e) { - m_pZip->setCompression(KZip::DeflateCompression); - } else { - m_pZip->setCompression(KZip::NoCompression); - } -} - -bool KoLegacyZipStore::doFinalize() -{ - if (m_pZip && m_pZip->device() && !m_pZip->device()->inherits("QSaveFile")) { - return m_pZip->close(); - } - else { - return true; - } -} - -bool KoLegacyZipStore::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 KoLegacyZipStore::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 KoLegacyZipStore::write(const char* _data, qint64 _len) -{ - Q_D(KoStore); - if (_len == 0) return 0; - //debugStore <<"KoLegacyZipStore::write" << _len; - - 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 KoLegacyZipStore::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 KoLegacyZipStore::closeWrite() -{ - Q_D(KoStore); - debugStore << "Wrote file" << d->fileName << " into ZIP archive. size" << d->size; - return m_pZip->finishWriting(d->size); -} - -bool KoLegacyZipStore::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 KoLegacyZipStore::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 KoLegacyZipStore::fileExists(const QString& absPath) const -{ - const KArchiveEntry *entry = m_pZip->directory()->entry(absPath); - return entry && entry->isFile(); -} diff --git a/libs/store/KoLegacyZipStore.h b/libs/store/KoLegacyZipStore.h deleted file mode 100644 index e9d414c82b..0000000000 --- a/libs/store/KoLegacyZipStore.h +++ /dev/null @@ -1,73 +0,0 @@ -/* This file is part of the KDE project - Copyright (C) 2002 David Faure - - 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 koZipStore_h -#define koZipStore_h - -#include "KoStore.h" - -class SaveZip; -class KArchiveDirectory; -class QUrl; - -class KoLegacyZipStore : public KoStore -{ -public: - KoLegacyZipStore(const QString & _filename, Mode _mode, const QByteArray & appIdentification, - bool writeMimetype = true); - KoLegacyZipStore(QIODevice *dev, Mode mode, const QByteArray & appIdentification, - bool writeMimetype = true); - /** - * QUrl-constructor - * @todo saving not completely implemented (fixed temporary file) - */ - KoLegacyZipStore(QWidget* window, const QUrl &_url, const QString & _filename, Mode _mode, - const QByteArray & appIdentification, bool writeMimetype = true); - ~KoLegacyZipStore() override; - - void setCompressionEnabled(bool e) 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 { - return true; - } - bool enterRelativeDirectory(const QString& dirName) override; - bool enterAbsoluteDirectory(const QString& path) override; - bool fileExists(const QString& absPath) const override; - -private: - - // The archive - SaveZip * m_pZip; - - // In "Read" mode this pointer is pointing to the current directory in the archive to speed up the verification process - const KArchiveDirectory* m_currentDir; - - Q_DECLARE_PRIVATE(KoStore) -}; - -#endif diff --git a/libs/store/KoStore.cpp b/libs/store/KoStore.cpp index a5ac02ea63..28c2b2897b 100644 --- a/libs/store/KoStore.cpp +++ b/libs/store/KoStore.cpp @@ -1,478 +1,452 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright (C) 2000-2002 David Faure , Werner Trobin 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 "KoStore.h" #include "KoStore_p.h" -#include "KoLegacyZipStore.h" #include "KoQuaZipStore.h" #include "KoDirectoryStore.h" #include #include #include #include #include -#include -#include -#include - - #define DefaultFormat KoStore::Zip static KoStore::Backend determineBackend(QIODevice *dev) { unsigned char buf[5]; if (dev->read((char *)buf, 4) < 4) return DefaultFormat; // will create a "bad" store (bad()==true) if (buf[0] == 'P' && buf[1] == 'K' && buf[2] == 3 && buf[3] == 4) return KoStore::Zip; return DefaultFormat; // fallback } KoStore* KoStore::createStore(const QString& fileName, Mode mode, const QByteArray & appIdentification, Backend backend, bool writeMimetype) { if (backend == Auto) { if (mode == KoStore::Write) backend = DefaultFormat; else { QFileInfo inf(fileName); if (inf.isDir()) backend = Directory; else { QFile file(fileName); if (file.open(QIODevice::ReadOnly)) backend = determineBackend(&file); else backend = DefaultFormat; // will create a "bad" store (bad()==true) } } } switch (backend) { case Zip: - if (appIdentification == "application/x-krita" && KSharedConfig::openConfig()->group("").readEntry("UseZip64", false)) { - return new KoQuaZipStore(fileName, mode, appIdentification, writeMimetype); - } - else { - KoStore *store = new KoLegacyZipStore(fileName, mode, appIdentification, writeMimetype); - if (store->bad()) { - return new KoQuaZipStore(fileName, mode, appIdentification, writeMimetype); - } - return store; - } - + return new KoQuaZipStore(fileName, mode, appIdentification, writeMimetype); case Directory: return new KoDirectoryStore(fileName /* should be a dir name.... */, mode, writeMimetype); default: warnStore << "Unsupported backend requested for KoStore : " << backend; return 0; } } KoStore* KoStore::createStore(QIODevice *device, Mode mode, const QByteArray & appIdentification, Backend backend, bool writeMimetype) { if (backend == Auto) { if (mode == KoStore::Write) backend = DefaultFormat; else { if (device->open(QIODevice::ReadOnly)) { backend = determineBackend(device); device->close(); } } } switch (backend) { case Directory: errorStore << "Can't create a Directory store for a memory buffer!" << endl; return 0; case Zip: - qDebug() << KSharedConfig::openConfig()->group("").readEntry("UseZip64", false); - if (appIdentification == "application/x-krita" && KSharedConfig::openConfig()->group("").readEntry("UseZip64", false)) { - return new KoQuaZipStore(device, mode, appIdentification, writeMimetype); - } - else { - KoStore *store = new KoLegacyZipStore(device, mode, appIdentification, writeMimetype); - if (store->bad()) { - return new KoQuaZipStore(device, mode, appIdentification, writeMimetype); - } - return store; - } + return new KoQuaZipStore(device, mode, appIdentification, writeMimetype); default: warnStore << "Unsupported backend requested for KoStore : " << backend; return 0; } } namespace { const char ROOTPART[] = "root"; const char MAINNAME[] = "maindoc.xml"; } KoStore::KoStore(Mode mode, bool writeMimetype) : d_ptr(new KoStorePrivate(this, mode, writeMimetype)) {} KoStore::~KoStore() { Q_D(KoStore); delete d->stream; delete d_ptr; } bool KoStore::open(const QString & _name) { Q_D(KoStore); // This also converts from relative to absolute, i.e. merges the currentPath() d->fileName = d->toExternalNaming(_name); debugStore << "KOStore" << _name << d->fileName; if (d->isOpen) { warnStore << "Store is already opened, missing close"; return false; } if (d->fileName.length() > 512) { errorStore << "KoStore: Filename " << d->fileName << " is too long" << endl; return false; } if (d->mode == Write) { debugStore << "opening for writing" << d->fileName; if (d->filesList.contains(d->fileName)) { warnStore << "KoStore: Duplicate filename" << d->fileName; return false; } d->filesList.append(d->fileName); d->size = 0; if (!openWrite(d->fileName)) return false; } else if (d->mode == Read) { debugStore << "Opening for reading" << d->fileName; if (!openRead(d->fileName)) return false; } else return false; d->isOpen = true; return true; } bool KoStore::isOpen() const { Q_D(const KoStore); return d->isOpen; } bool KoStore::close() { Q_D(KoStore); 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; return ret; } QIODevice* KoStore::device() const { Q_D(const KoStore); if (!d->isOpen) warnStore << "You must open before asking for a device"; if (d->mode != Read) warnStore << "Can not get device from store that is opened for writing"; return d->stream; } QByteArray KoStore::read(qint64 max) { Q_D(KoStore); QByteArray data; if (!d->isOpen) { warnStore << "You must open before reading"; return data; } if (d->mode != Read) { errorStore << "KoStore: Can not read from store that is opened for writing" << endl; return data; } return d->stream->read(max); } qint64 KoStore::write(const QByteArray& data) { return write(data.constData(), data.size()); // see below } qint64 KoStore::read(char *_buffer, qint64 _len) { Q_D(KoStore); if (!d->isOpen) { errorStore << "KoStore: You must open before reading" << endl; return -1; } if (d->mode != Read) { errorStore << "KoStore: Can not read from store that is opened for writing" << endl; return -1; } return d->stream->read(_buffer, _len); } qint64 KoStore::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; } int nwritten = d->stream->write(_data, _len); Q_ASSERT(nwritten == (int)_len); d->size += nwritten; return nwritten; } qint64 KoStore::size() const { Q_D(const KoStore); if (!d->isOpen) { warnStore << "You must open before asking for a size"; return static_cast(-1); } if (d->mode != Read) { warnStore << "Can not get size from store that is opened for writing"; return static_cast(-1); } return d->size; } bool KoStore::enterDirectory(const QString &directory) { Q_D(KoStore); //debugStore <<"enterDirectory" << directory; int pos; bool success = true; QString tmp(directory); while ((pos = tmp.indexOf('/')) != -1 && (success = d->enterDirectoryInternal(tmp.left(pos)))) tmp.remove(0, pos + 1); if (success && !tmp.isEmpty()) return d->enterDirectoryInternal(tmp); return success; } bool KoStore::leaveDirectory() { Q_D(KoStore); if (d->currentPath.isEmpty()) return false; d->currentPath.pop_back(); return enterAbsoluteDirectory(currentPath()); } QString KoStore::currentPath() const { Q_D(const KoStore); QString path; QStringList::ConstIterator it = d->currentPath.begin(); QStringList::ConstIterator end = d->currentPath.end(); for (; it != end; ++it) { path += *it; path += '/'; } return path; } void KoStore::pushDirectory() { Q_D(KoStore); d->directoryStack.push(currentPath()); } void KoStore::popDirectory() { Q_D(KoStore); d->currentPath.clear(); enterAbsoluteDirectory(QString()); enterDirectory(d->directoryStack.pop()); } bool KoStore::extractFile(const QString &srcName, QByteArray &data) { Q_D(KoStore); QBuffer buffer(&data); return d->extractFile(srcName, buffer); } bool KoStorePrivate::extractFile(const QString &srcName, QIODevice &buffer) { if (!q->open(srcName)) return false; if (!buffer.open(QIODevice::WriteOnly)) { q->close(); return false; } QByteArray data; data.resize(8 * 1024); uint total = 0; for (int block = 0; (block = q->read(data.data(), data.size())) > 0; total += block) { buffer.write(data.data(), block); } if (q->size() != static_cast(-1)) Q_ASSERT(total == q->size()); buffer.close(); q->close(); return true; } bool KoStore::seek(qint64 pos) { Q_D(KoStore); return d->stream->seek(pos); } qint64 KoStore::pos() const { Q_D(const KoStore); return d->stream->pos(); } bool KoStore::atEnd() const { Q_D(const KoStore); return d->stream->atEnd(); } // See the specification for details of what this function does. QString KoStorePrivate::toExternalNaming(const QString & _internalNaming) const { if (_internalNaming == ROOTPART) return q->currentPath() + MAINNAME; QString intern; if (_internalNaming.startsWith("tar:/")) // absolute reference intern = _internalNaming.mid(5); // remove protocol else intern = q->currentPath() + _internalNaming; return intern; } bool KoStorePrivate::enterDirectoryInternal(const QString &directory) { if (q->enterRelativeDirectory(directory)) { currentPath.append(directory); return true; } return false; } bool KoStore::hasFile(const QString& fileName) const { Q_D(const KoStore); return fileExists(d->toExternalNaming(fileName)); } bool KoStore::hasDirectory(const QString &directoryName) { return enterAbsoluteDirectory(directoryName); } bool KoStore::finalize() { Q_D(KoStore); Q_ASSERT(!d->finalized); // call this only once! d->finalized = true; return doFinalize(); } void KoStore::setCompressionEnabled(bool /*e*/) { } void KoStore::setSubstitution(const QString &name, const QString &substitution) { Q_D(KoStore); d->substituteThis = name; d->substituteWith = substitution; } bool KoStore::isEncrypted() { return false; } bool KoStore::setPassword(const QString& /*password*/) { return false; } QString KoStore::password() { return QString(); } bool KoStore::bad() const { Q_D(const KoStore); return !d->good; } KoStore::Mode KoStore::mode() const { Q_D(const KoStore); return d->mode; } QStringList KoStore::directoryList() const { return QStringList(); } diff --git a/libs/store/KoStore_p.h b/libs/store/KoStore_p.h index 11d998f84f..3c4ec984bd 100644 --- a/libs/store/KoStore_p.h +++ b/libs/store/KoStore_p.h @@ -1,108 +1,106 @@ /* This file is part of the KDE project Copyright 2004 Nicolas GOUTTE 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 __koStore_p_h_ #define __koStore_p_h_ #include "KoStore.h" #include #include #include class QWidget; class KoStorePrivate { public: explicit KoStorePrivate(KoStore *qq, KoStore::Mode _mode, bool _writeMimetype) : q(qq), window(0), mode(_mode), size(0), stream(0), isOpen(false), good(false), finalized(false), writeMimetype(_writeMimetype) { } /** * Conversion routine * @param internalNaming name used internally : "root", "tar:/0", ... * @return the name used in the file, more user-friendly ("maindoc.xml", * "part0/maindoc.xml", ...) * Examples: * * tar:/0 is saved as part0/maindoc.xml * tar:/0/1 is saved as part0/part1/maindoc.xml * tar:/0/1/pictures/picture0.png is saved as part0/part1/pictures/picture0.png * * see specification (calligra/lib/store/SPEC) for details. */ QString toExternalNaming(const QString &internalNaming) const; /** * Enter *one* single directory. Nothing like foo/bar/bleh allowed. * Performs some checking when in Read mode */ bool enterDirectoryInternal(const QString &directory); bool extractFile(const QString &sourceName, QIODevice &buffer); KoStore *q; QString localFileName; QWidget *window; KoStore::Mode mode; /// Store the filenames (with full path inside the archive) when writing, to avoid duplicates QStringList filesList; /// The "current directory" (path) QStringList currentPath; /// Current filename (between an open() and a close()) QString fileName; /// Current size of the file named m_sName qint64 size; /// The stream for the current read or write operation QIODevice *stream; bool isOpen; /// Must be set by the constructor. bool good; bool finalized; QStack directoryStack; bool writeMimetype; ///< true if the backend is allowed to create "mimetype" automatically. QString substituteThis; QString substituteWith; - - QUrl url; }; #endif