[graphics/krita] /: Upgrade macOS integration plugins

Boudewijn Rempt null at kde.org
Mon Nov 16 09:24:39 GMT 2020


Git commit b5375c4d31f368f090db4119aa7fa9cffede95d3 by Boudewijn Rempt, on behalf of L. E. Segovia.
Committed on 16/11/2020 at 09:24.
Pushed by rempt into branch 'master'.

Upgrade macOS integration plugins

This commit brings a massive refactor to the existing plugins for macOS:

- Adds QuickLook Thumbnailing (10.15+) support.
- Adds Spotlight metadata support.
- It drops NSTasks for reading the KRA file in favor of a bundled
minizip library. NSTask is usable from QuickLook generators, but not
from Spotlight (mdimporter/mdworker).
- It adds license headers throughout the updated code, recognising the
original authors of the Quicklook plugin.

The README and packaging scripts have been updated to reflect these changes.
The LICENSE (GPLv2) has been removed to make it consistent with the rest
of Krita; feel free to contact me if this is wrong.

CCMAIL: kimageshop at kde.org

A  +88   -0    krita/integration/.gitignore
A  +17   -0    krita/integration/3rdparty/LICENSE
A  +84   -0    krita/integration/3rdparty/README.md
A  +353  -0    krita/integration/3rdparty/ioapi.c  *
A  +153  -0    krita/integration/3rdparty/ioapi.h  *
A  +1985 -0    krita/integration/3rdparty/unzip.c  *
A  +308  -0    krita/integration/3rdparty/unzip.h  *
M  +9    -3    krita/integration/CMakeLists.txt
D  +0    -340  krita/integration/LICENSE
M  +40   -5    krita/integration/README.md
A  +780  -0    krita/integration/integration.xcodeproj/project.pbxproj
R  +10   -20   krita/integration/integration.xcodeproj/xcshareddata/xcschemes/kritaquicklook.xcscheme [from: krita/integration/kritaquicklook.xcodeproj/xcuserdata/alvina.xcuserdatad/xcschemes/kritaquicklook.xcscheme - 069% similarity]
D  +0    -301  krita/integration/kritaquicklook.xcodeproj/project.pbxproj
D  +0    -7    krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/contents.xcworkspacedata
D  +0    -41   krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/xcshareddata/Krita.xccheckout
D  +0    -41   krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/xcshareddata/kritaquicklook.xccheckout
D  +-    --    krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/xcuserdata/alvina.xcuserdatad/UserInterfaceState.xcuserstate
D  +0    -23   krita/integration/kritaquicklook.xcodeproj/xcuserdata/alvina.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
D  +0    -27   krita/integration/kritaquicklook.xcodeproj/xcuserdata/alvina.xcuserdatad/xcschemes/xcschememanagement.plist
D  +0    -6    krita/integration/kritaquicklook/CMakeLists.txt
D  +0    -70   krita/integration/kritaquicklook/GeneratePreviewForURL.m
D  +0    -92   krita/integration/kritaquicklook/GenerateThumbnailForURL.m
D  +0    -159  krita/integration/kritaquicklook/Info.plist
D  +0    -340  krita/integration/kritaquicklook/LICENSE
D  +0    -9    krita/integration/kritaquicklook/README.md
A  +85   -0    krita/integration/quicklook/GeneratePreviewForURL.m
A  +112  -0    krita/integration/quicklook/GenerateThumbnailForURL.m
A  +159  -0    krita/integration/quicklook/Info.plist
R  +25   -0    krita/integration/quicklook/main.c [from: krita/integration/kritaquicklook/main.c - 090% similarity]
A  +87   -0    krita/integration/quicklookng/Info.plist
A  +74   -0    krita/integration/quicklookng/ThumbnailProvider.swift
A  +26   -0    krita/integration/quicklookng/quicklookng-Bridging-Header.h     [License: GPL (v2+)]
A  +10   -0    krita/integration/quicklookng/quicklookng.entitlements
A  +276  -0    krita/integration/spotlight/GetMetadataForFile.m
A  +103  -0    krita/integration/spotlight/Info.plist
A  +238  -0    krita/integration/spotlight/main.c     [License: GPL (v2+)]
A  +31   -0    krita/integration/unzipTask/UnzipTask.h     [License: GPL (v2+)]
A  +90   -0    krita/integration/unzipTask/UnzipTask.m
M  +1    -1    packaging/macos/osxbuild.sh
M  +7    -1    packaging/macos/osxdeploy.sh

The files marked with a * at the end have a non valid license. Please read: https://community.kde.org/Policies/Licensing_Policy and use the headers which are listed at that page.


https://invent.kde.org/graphics/krita/commit/b5375c4d31f368f090db4119aa7fa9cffede95d3

diff --git a/krita/integration/.gitignore b/krita/integration/.gitignore
new file mode 100644
index 0000000000..7952016608
--- /dev/null
+++ b/krita/integration/.gitignore
@@ -0,0 +1,88 @@
+
+# Created by https://www.toptal.com/developers/gitignore/api/objective-c,xcode
+# Edit at https://www.toptal.com/developers/gitignore?templates=objective-c,xcode
+
+### Objective-C ###
+# Xcode
+#
+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
+
+## User settings
+xcuserdata/
+
+## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
+*.xcscmblueprint
+*.xccheckout
+
+## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
+build/
+DerivedData/
+*.moved-aside
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+
+## Obj-C/Swift specific
+*.hmap
+
+## App packaging
+*.ipa
+*.dSYM.zip
+*.dSYM
+
+# CocoaPods
+# We recommend against adding the Pods directory to your .gitignore. However
+# you should judge for yourself, the pros and cons are mentioned at:
+# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
+# Pods/
+# Add this line if you want to avoid checking in source code from the Xcode workspace
+# *.xcworkspace
+
+# Carthage
+# Add this line if you want to avoid checking in source code from Carthage dependencies.
+# Carthage/Checkouts
+
+Carthage/Build/
+
+# fastlane
+# It is recommended to not store the screenshots in the git repo.
+# Instead, use fastlane to re-generate the screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://docs.fastlane.tools/best-practices/source-control/#source-control
+
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots/**/*.png
+fastlane/test_output
+
+# Code Injection
+# After new code Injection tools there's a generated folder /iOSInjectionProject
+# https://github.com/johnno1962/injectionforxcode
+
+iOSInjectionProject/
+
+### Objective-C Patch ###
+
+### Xcode ###
+# Xcode
+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
+
+
+
+
+## Gcc Patch
+/*.gcno
+
+### Xcode Patch ###
+*.xcodeproj/*
+!*.xcodeproj/project.pbxproj
+!*.xcodeproj/xcshareddata/
+!*.xcworkspace/contents.xcworkspacedata
+**/xcshareddata/WorkspaceSettings.xcsettings
+
+# End of https://www.toptal.com/developers/gitignore/api/objective-c,xcode
diff --git a/krita/integration/3rdparty/LICENSE b/krita/integration/3rdparty/LICENSE
new file mode 100644
index 0000000000..086295a2b2
--- /dev/null
+++ b/krita/integration/3rdparty/LICENSE
@@ -0,0 +1,17 @@
+Condition of use and distribution are the same as zlib:
+
+This software is provided 'as-is', without any express or implied
+warranty.  In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software
+   in a product, an acknowledgement in the product documentation would be
+   appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
\ No newline at end of file
diff --git a/krita/integration/3rdparty/README.md b/krita/integration/3rdparty/README.md
new file mode 100644
index 0000000000..4317ca5a91
--- /dev/null
+++ b/krita/integration/3rdparty/README.md
@@ -0,0 +1,84 @@
+# Minizip 1.2
+
+Zlib contribution fork that ontains the latest bug fixes that having been found all over the internet including the [old minizip forum](https://web.archive.org/web/20121015065401/http://www.winimage.info/forum/) and zlib developer's mailing list along with some additional features. Based on the original work of [Gilles Vollant](http://www.winimage.com/zLibDll/minizip.html) and contributed to by many people over the years.
+
+## Features
+
+### I/O Memory
+
+To unzip from a zip file in memory use fill_memory_filefunc and supply a proper ourmemory_t structure.
+```
+zlib_filefunc_def filefunc32 = {0};
+ourmemory_t unzmem = {0};
+
+unzmem.size = bufsize;
+unzmem.base = (char *)malloc(unzmem.size);
+memcpy(unzmem.base, buffer, unzmem.size);
+    
+fill_memory_filefunc(&filefunc32, &unzmem);
+
+unzOpen2("__notused__", &filefunc32);
+```
+
+To create a zip file in memory use fill_memory_filefunc and supply a proper ourmemory_t structure. It is important
+not to forget to free zipmem->base when finished. If grow is set, zipmem->base will expand to fit the size of the zip. 
+If grow is not set be sure to fill out zipmem.base and zipmem.size.
+
+```
+zlib_filefunc_def filefunc32 = {0};
+ourmemory_t zipmem = {0};
+
+zipmem.grow = 1;
+
+fill_memory_filefunc(&filefunc32, &zipmem);
+
+zipOpen3("__notused__", APPEND_STATUS_CREATE, 0, 0, &filefunc32);
+```
+
+### BZIP2
+
++ Requires #define HAVE_BZIP2
++ Requires BZIP2 library
+
+### Windows RT
+
++ Requires #define IOWIN32_USING_WINRT_API
+
+## Additional Features
+
+### [WinZIP AES Encryption](http://www.winzip.com/aes_info.htm)
+
++ Requires #define HAVE_AES
++ Requires AES library files
+
+When zipping with a password it will always use AES 256-bit encryption. 
+When unzipping it will use AES decryption only if necessary. Does not support central directory or local file header encryption.
+
+### PKWARE disk splitting
+
+To create an archive with multiple disks use zipOpen3_64 supplying a disk size value in bytes.
+
+```
+extern zipFile ZEXPORT zipOpen3_64(const void *pathname, int append, 
+  ZPOS64_T disk_size, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def);
+```
+The central directory is the only data stored in the .zip and doesn't follow disk size restrictions.
+
+When unzipping it will automatically determine when in needs to cross disk boundaries.
+
+### I/O Buffering
+
+Improves I/O performance by buffering read and write operations. 
+```
+zlib_filefunc64_def filefunc64 = {0};
+ourbuffer_t buffered = {0};
+    
+fill_win32_filefunc64(&buffered->filefunc64);
+fill_buffer_filefunc64(&filefunc64, buffered);
+    
+unzOpen2_64(filename, &filefunc64)
+```
+
+### Apple libcompression
+
++ Requires #define HAVE_APPLE_COMPRESSION
diff --git a/krita/integration/3rdparty/ioapi.c b/krita/integration/3rdparty/ioapi.c
new file mode 100644
index 0000000000..239bb05a4d
--- /dev/null
+++ b/krita/integration/3rdparty/ioapi.c
@@ -0,0 +1,353 @@
+/* ioapi.c -- IO base function header for compress/uncompress .zip
+   part of the MiniZip project
+
+   Copyright (C) 2012-2017 Nathan Moinvaziri
+     https://github.com/nmoinvaz/minizip
+   Modifications for Zip64 support
+     Copyright (C) 2009-2010 Mathias Svensson
+     http://result42.com
+   Copyright (C) 1998-2010 Gilles Vollant
+     http://www.winimage.com/zLibDll/minizip.html
+
+   This program is distributed under the terms of the same license as zlib.
+   See the accompanying LICENSE file for the full text of the license.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined unix || defined __APPLE__
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include "ioapi.h"
+
+#if defined(_WIN32)
+#  define snprintf _snprintf
+#endif
+
+voidpf call_zopen64(const zlib_filefunc64_32_def *pfilefunc, const void *filename, int mode)
+{
+    if (pfilefunc->zfile_func64.zopen64_file != NULL)
+        return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque, filename, mode);
+    return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque, (const char*)filename, mode);
+}
+
+voidpf call_zopendisk64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint32_t number_disk, int mode)
+{
+    if (pfilefunc->zfile_func64.zopendisk64_file != NULL)
+        return (*(pfilefunc->zfile_func64.zopendisk64_file)) (pfilefunc->zfile_func64.opaque, filestream, number_disk, mode);
+    return (*(pfilefunc->zopendisk32_file))(pfilefunc->zfile_func64.opaque, filestream, number_disk, mode);
+}
+
+long call_zseek64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint64_t offset, int origin)
+{
+    uint32_t offset_truncated = 0;
+    if (pfilefunc->zfile_func64.zseek64_file != NULL)
+        return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
+    offset_truncated = (uint32_t)offset;
+    if (offset_truncated != offset)
+        return -1;
+    return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream, offset_truncated, origin);
+}
+
+uint64_t call_ztell64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream)
+{
+    uint64_t position;
+    if (pfilefunc->zfile_func64.zseek64_file != NULL)
+        return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque, filestream);
+    position = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque, filestream);
+    if ((position) == UINT32_MAX)
+        return (uint64_t)-1;
+    return position;
+}
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def *p_filefunc64_32, const zlib_filefunc_def *p_filefunc32)
+{
+    p_filefunc64_32->zfile_func64.zopen64_file = NULL;
+    p_filefunc64_32->zfile_func64.zopendisk64_file = NULL;
+    p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
+    p_filefunc64_32->zopendisk32_file = p_filefunc32->zopendisk_file;
+    p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+    p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
+    p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
+    p_filefunc64_32->zfile_func64.ztell64_file = NULL;
+    p_filefunc64_32->zfile_func64.zseek64_file = NULL;
+    p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
+    p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+    p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
+    p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
+    p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
+}
+
+static voidpf   ZCALLBACK fopen_file_func(ZIP_UNUSED voidpf opaque, const char *filename, int mode);
+static uint32_t ZCALLBACK fread_file_func(voidpf opaque, voidpf stream, void* buf, uint32_t size);
+static uint32_t ZCALLBACK fwrite_file_func(voidpf opaque, voidpf stream, const void *buf, uint32_t size);
+static uint64_t ZCALLBACK ftell64_file_func(voidpf opaque, voidpf stream);
+static long     ZCALLBACK fseek64_file_func(voidpf opaque, voidpf stream, uint64_t offset, int origin);
+static int      ZCALLBACK fclose_file_func(voidpf opaque, voidpf stream);
+static int      ZCALLBACK ferror_file_func(voidpf opaque, voidpf stream);
+
+typedef struct 
+{
+    FILE *file;
+    int filenameLength;
+    void *filename;
+} FILE_IOPOSIX;
+
+static voidpf file_build_ioposix(FILE *file, const char *filename)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    if (file == NULL)
+        return NULL;
+    ioposix = (FILE_IOPOSIX*)malloc(sizeof(FILE_IOPOSIX));
+    ioposix->file = file;
+    ioposix->filenameLength = (int)strlen(filename) + 1;
+    ioposix->filename = (char*)malloc(ioposix->filenameLength * sizeof(char));
+    strncpy((char*)ioposix->filename, filename, ioposix->filenameLength);
+    return (voidpf)ioposix;
+}
+
+static voidpf ZCALLBACK fopen_file_func(ZIP_UNUSED voidpf opaque, const char *filename, int mode)
+{
+    FILE* file = NULL;
+    const char *mode_fopen = NULL;
+    if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
+        mode_fopen = "rb";
+    else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+        mode_fopen = "r+b";
+    else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+        mode_fopen = "wb";
+
+    if ((filename != NULL) && (mode_fopen != NULL))
+    {
+        file = fopen(filename, mode_fopen);
+        return file_build_ioposix(file, filename);
+    }
+    return file;
+}
+
+static voidpf ZCALLBACK fopen64_file_func(ZIP_UNUSED voidpf opaque, const void *filename, int mode)
+{
+    FILE* file = NULL;
+    const char *mode_fopen = NULL;
+    if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
+        mode_fopen = "rb";
+    else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+        mode_fopen = "r+b";
+    else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+        mode_fopen = "wb";
+
+    if ((filename != NULL) && (mode_fopen != NULL))
+    {
+        file = fopen64((const char*)filename, mode_fopen);
+        return file_build_ioposix(file, (const char*)filename);
+    }
+    return file;
+}
+
+static voidpf ZCALLBACK fopendisk64_file_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    char *diskFilename = NULL;
+    voidpf ret = NULL;
+    int i = 0;
+
+    if (stream == NULL)
+        return NULL;
+    ioposix = (FILE_IOPOSIX*)stream;
+    diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char));
+    strncpy(diskFilename, (const char*)ioposix->filename, ioposix->filenameLength);
+    for (i = ioposix->filenameLength - 1; i >= 0; i -= 1)
+    {
+        if (diskFilename[i] != '.')
+            continue;
+        snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02u", number_disk + 1);
+        break;
+    }
+    if (i >= 0)
+        ret = fopen64_file_func(opaque, diskFilename, mode);
+    free(diskFilename);
+    return ret;
+}
+
+static voidpf ZCALLBACK fopendisk_file_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    char *diskFilename = NULL;
+    voidpf ret = NULL;
+    int i = 0;
+
+    if (stream == NULL)
+        return NULL;
+    ioposix = (FILE_IOPOSIX*)stream;
+    diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char));
+    strncpy(diskFilename, (const char*)ioposix->filename, ioposix->filenameLength);
+    for (i = ioposix->filenameLength - 1; i >= 0; i -= 1)
+    {
+        if (diskFilename[i] != '.')
+            continue;
+        snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02u", number_disk + 1);
+        break;
+    }
+    if (i >= 0)
+        ret = fopen_file_func(opaque, diskFilename, mode);
+    free(diskFilename);
+    return ret;
+}
+
+static uint32_t ZCALLBACK fread_file_func(ZIP_UNUSED voidpf opaque, voidpf stream, void* buf, uint32_t size)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    uint32_t read = (uint32_t)-1;
+    if (stream == NULL)
+        return read;
+    ioposix = (FILE_IOPOSIX*)stream;
+    read = (uint32_t)fread(buf, 1, (size_t)size, ioposix->file);
+    return read;
+}
+
+static uint32_t ZCALLBACK fwrite_file_func(ZIP_UNUSED voidpf opaque, voidpf stream, const void *buf, uint32_t size)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    uint32_t written = (uint32_t)-1;
+    if (stream == NULL)
+        return written;
+    ioposix = (FILE_IOPOSIX*)stream;
+    written = (uint32_t)fwrite(buf, 1, (size_t)size, ioposix->file);
+    return written;
+}
+
+static long ZCALLBACK ftell_file_func(ZIP_UNUSED voidpf opaque, voidpf stream)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    long ret = -1;
+    if (stream == NULL)
+        return ret;
+    ioposix = (FILE_IOPOSIX*)stream;
+    ret = ftell(ioposix->file);
+    return ret;
+}
+
+static uint64_t ZCALLBACK ftell64_file_func(ZIP_UNUSED voidpf opaque, voidpf stream)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    uint64_t ret = (uint64_t)-1;
+    if (stream == NULL)
+        return ret;
+    ioposix = (FILE_IOPOSIX*)stream;
+    ret = ftello64(ioposix->file);
+    return ret;
+}
+
+static long ZCALLBACK fseek_file_func(ZIP_UNUSED voidpf opaque, voidpf stream, uint32_t offset, int origin)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    int fseek_origin = 0;
+    long ret = 0;
+
+    if (stream == NULL)
+        return -1;
+    ioposix = (FILE_IOPOSIX*)stream;
+
+    switch (origin)
+    {
+        case ZLIB_FILEFUNC_SEEK_CUR:
+            fseek_origin = SEEK_CUR;
+            break;
+        case ZLIB_FILEFUNC_SEEK_END:
+            fseek_origin = SEEK_END;
+            break;
+        case ZLIB_FILEFUNC_SEEK_SET:
+            fseek_origin = SEEK_SET;
+            break;
+        default:
+            return -1;
+    }
+    if (fseek(ioposix->file, offset, fseek_origin) != 0)
+        ret = -1;
+    return ret;
+}
+
+static long ZCALLBACK fseek64_file_func(ZIP_UNUSED voidpf opaque, voidpf stream, uint64_t offset, int origin)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    int fseek_origin = 0;
+    long ret = 0;
+
+    if (stream == NULL)
+        return -1;
+    ioposix = (FILE_IOPOSIX*)stream;
+
+    switch (origin)
+    {
+        case ZLIB_FILEFUNC_SEEK_CUR:
+            fseek_origin = SEEK_CUR;
+            break;
+        case ZLIB_FILEFUNC_SEEK_END:
+            fseek_origin = SEEK_END;
+            break;
+        case ZLIB_FILEFUNC_SEEK_SET:
+            fseek_origin = SEEK_SET;
+            break;
+        default:
+            return -1;
+    }
+
+    if (fseeko64(ioposix->file, offset, fseek_origin) != 0)
+        ret = -1;
+
+    return ret;
+}
+
+static int ZCALLBACK fclose_file_func(ZIP_UNUSED voidpf opaque, voidpf stream)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    int ret = -1;
+    if (stream == NULL)
+        return ret;
+    ioposix = (FILE_IOPOSIX*)stream;
+    if (ioposix->filename != NULL)
+        free(ioposix->filename);
+    ret = fclose(ioposix->file);
+    free(ioposix);
+    return ret;
+}
+
+static int ZCALLBACK ferror_file_func(ZIP_UNUSED voidpf opaque, voidpf stream)
+{
+    FILE_IOPOSIX *ioposix = NULL;
+    int ret = -1;
+    if (stream == NULL)
+        return ret;
+    ioposix = (FILE_IOPOSIX*)stream;
+    ret = ferror(ioposix->file);
+    return ret;
+}
+
+void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def)
+{
+    pzlib_filefunc_def->zopen_file = fopen_file_func;
+    pzlib_filefunc_def->zopendisk_file = fopendisk_file_func;
+    pzlib_filefunc_def->zread_file = fread_file_func;
+    pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+    pzlib_filefunc_def->ztell_file = ftell_file_func;
+    pzlib_filefunc_def->zseek_file = fseek_file_func;
+    pzlib_filefunc_def->zclose_file = fclose_file_func;
+    pzlib_filefunc_def->zerror_file = ferror_file_func;
+    pzlib_filefunc_def->opaque = NULL;
+}
+
+void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def)
+{
+    pzlib_filefunc_def->zopen64_file = fopen64_file_func;
+    pzlib_filefunc_def->zopendisk64_file = fopendisk64_file_func;
+    pzlib_filefunc_def->zread_file = fread_file_func;
+    pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+    pzlib_filefunc_def->ztell64_file = ftell64_file_func;
+    pzlib_filefunc_def->zseek64_file = fseek64_file_func;
+    pzlib_filefunc_def->zclose_file = fclose_file_func;
+    pzlib_filefunc_def->zerror_file = ferror_file_func;
+    pzlib_filefunc_def->opaque = NULL;
+}
diff --git a/krita/integration/3rdparty/ioapi.h b/krita/integration/3rdparty/ioapi.h
new file mode 100644
index 0000000000..b4a0d461da
--- /dev/null
+++ b/krita/integration/3rdparty/ioapi.h
@@ -0,0 +1,153 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+   part of the MiniZip project
+
+   Copyright (C) 2012-2017 Nathan Moinvaziri
+     https://github.com/nmoinvaz/minizip
+   Copyright (C) 2009-2010 Mathias Svensson
+     Modifications for Zip64 support
+     http://result42.com
+   Copyright (C) 1998-2010 Gilles Vollant
+     http://www.winimage.com/zLibDll/minizip.html
+
+   This program is distributed under the terms of the same license as zlib.
+   See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef _ZLIBIOAPI64_H
+#define _ZLIBIOAPI64_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "zlib.h"
+
+#ifdef __GNUC__
+#  define ZIP_UNUSED __attribute__((__unused__))
+#else
+#  define ZIP_UNUSED
+#endif
+
+#if defined(USE_FILE32API)
+#  define fopen64 fopen
+#  define ftello64 ftell
+#  define fseeko64 fseek
+#else
+#  if defined(_MSC_VER)
+#    define fopen64 fopen
+#    if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
+#      define ftello64 _ftelli64
+#      define fseeko64 _fseeki64
+#    else /* old MSC */
+#      define ftello64 ftell
+#      define fseeko64 fseek
+#    endif
+#  else
+#    define fopen64 fopen
+#    define ftello64 ftello
+#    define fseeko64 fseeko
+#  endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_FILEFUNC_SEEK_CUR (1)
+#define ZLIB_FILEFUNC_SEEK_END (2)
+#define ZLIB_FILEFUNC_SEEK_SET (0)
+
+#define ZLIB_FILEFUNC_MODE_READ             (1)
+#define ZLIB_FILEFUNC_MODE_WRITE            (2)
+#define ZLIB_FILEFUNC_MODE_READWRITEFILTER  (3)
+#define ZLIB_FILEFUNC_MODE_EXISTING         (4)
+#define ZLIB_FILEFUNC_MODE_CREATE           (8)
+
+#ifndef ZCALLBACK
+#  if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || \
+       defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
+#    define ZCALLBACK CALLBACK
+#  else
+#    define ZCALLBACK
+#  endif
+#endif
+
+typedef voidpf   (ZCALLBACK *open_file_func)     (voidpf opaque, const char *filename, int mode);
+typedef voidpf   (ZCALLBACK *opendisk_file_func) (voidpf opaque, voidpf stream, uint32_t number_disk, int mode);
+typedef uint32_t (ZCALLBACK *read_file_func)     (voidpf opaque, voidpf stream, void* buf, uint32_t size);
+typedef uint32_t (ZCALLBACK *write_file_func)    (voidpf opaque, voidpf stream, const void *buf, uint32_t size);
+typedef int      (ZCALLBACK *close_file_func)    (voidpf opaque, voidpf stream);
+typedef int      (ZCALLBACK *error_file_func)    (voidpf opaque, voidpf stream);
+
+typedef long     (ZCALLBACK *tell_file_func)     (voidpf opaque, voidpf stream);
+typedef long     (ZCALLBACK *seek_file_func)     (voidpf opaque, voidpf stream, uint32_t offset, int origin);
+
+/* here is the "old" 32 bits structure structure */
+typedef struct zlib_filefunc_def_s
+{
+    open_file_func      zopen_file;
+    opendisk_file_func  zopendisk_file;
+    read_file_func      zread_file;
+    write_file_func     zwrite_file;
+    tell_file_func      ztell_file;
+    seek_file_func      zseek_file;
+    close_file_func     zclose_file;
+    error_file_func     zerror_file;
+    voidpf              opaque;
+} zlib_filefunc_def;
+
+typedef uint64_t (ZCALLBACK *tell64_file_func)    (voidpf opaque, voidpf stream);
+typedef long     (ZCALLBACK *seek64_file_func)    (voidpf opaque, voidpf stream, uint64_t offset, int origin);
+typedef voidpf   (ZCALLBACK *open64_file_func)    (voidpf opaque, const void *filename, int mode);
+typedef voidpf   (ZCALLBACK *opendisk64_file_func)(voidpf opaque, voidpf stream, uint32_t number_disk, int mode);
+
+typedef struct zlib_filefunc64_def_s
+{
+    open64_file_func     zopen64_file;
+    opendisk64_file_func zopendisk64_file;
+    read_file_func       zread_file;
+    write_file_func      zwrite_file;
+    tell64_file_func     ztell64_file;
+    seek64_file_func     zseek64_file;
+    close_file_func      zclose_file;
+    error_file_func      zerror_file;
+    voidpf               opaque;
+} zlib_filefunc64_def;
+
+void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def);
+void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def);
+
+/* now internal definition, only for zip.c and unzip.h */
+typedef struct zlib_filefunc64_32_def_s
+{
+    zlib_filefunc64_def zfile_func64;
+    open_file_func      zopen32_file;
+    opendisk_file_func  zopendisk32_file;
+    tell_file_func      ztell32_file;
+    seek_file_func      zseek32_file;
+} zlib_filefunc64_32_def;
+
+#define ZREAD64(filefunc,filestream,buf,size)       ((*((filefunc).zfile_func64.zread_file))        ((filefunc).zfile_func64.opaque,filestream,buf,size))
+#define ZWRITE64(filefunc,filestream,buf,size)      ((*((filefunc).zfile_func64.zwrite_file))       ((filefunc).zfile_func64.opaque,filestream,buf,size))
+/*#define ZTELL64(filefunc,filestream)                ((*((filefunc).ztell64_file))                   ((filefunc).opaque,filestream))*/
+/*#define ZSEEK64(filefunc,filestream,pos,mode)       ((*((filefunc).zseek64_file))                   ((filefunc).opaque,filestream,pos,mode))*/
+#define ZCLOSE64(filefunc,filestream)               ((*((filefunc).zfile_func64.zclose_file))       ((filefunc).zfile_func64.opaque,filestream))
+#define ZERROR64(filefunc,filestream)               ((*((filefunc).zfile_func64.zerror_file))       ((filefunc).zfile_func64.opaque,filestream))
+
+voidpf   call_zopen64(const zlib_filefunc64_32_def *pfilefunc,const void*filename, int mode);
+voidpf   call_zopendisk64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint32_t number_disk, int mode);
+long     call_zseek64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint64_t offset, int origin);
+uint64_t call_ztell64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream);
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def *p_filefunc64_32, const zlib_filefunc_def *p_filefunc32);
+
+#define ZOPEN64(filefunc,filename,mode)             (call_zopen64((&(filefunc)),(filename),(mode)))
+#define ZOPENDISK64(filefunc,filestream,diskn,mode) (call_zopendisk64((&(filefunc)),(filestream),(diskn),(mode)))
+#define ZTELL64(filefunc,filestream)                (call_ztell64((&(filefunc)),(filestream)))
+#define ZSEEK64(filefunc,filestream,pos,mode)       (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/krita/integration/3rdparty/unzip.c b/krita/integration/3rdparty/unzip.c
new file mode 100644
index 0000000000..b4cbd05cee
--- /dev/null
+++ b/krita/integration/3rdparty/unzip.c
@@ -0,0 +1,1985 @@
+/* unzip.c -- IO for uncompress .zip files using zlib
+   Version 1.2.0, September 16th, 2017
+   part of the MiniZip project
+
+   Copyright (C) 2010-2017 Nathan Moinvaziri
+     Modifications for AES, PKWARE disk spanning
+     https://github.com/nmoinvaz/minizip
+   Copyright (C) 2009-2010 Mathias Svensson
+     Modifications for Zip64 support on both zip and unzip
+     http://result42.com
+   Copyright (C) 2007-2008 Even Rouault
+     Modifications of Unzip for Zip64
+   Copyright (C) 1998-2010 Gilles Vollant
+     http://www.winimage.com/zLibDll/minizip.html
+
+   This program is distributed under the terms of the same license as zlib.
+   See the accompanying LICENSE file for the full text of the license.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "zlib.h"
+#include "unzip.h"
+
+#ifdef HAVE_AES
+#  define AES_METHOD          (99)
+#  define AES_PWVERIFYSIZE    (2)
+#  define AES_MAXSALTLENGTH   (16)
+#  define AES_AUTHCODESIZE    (10)
+#  define AES_HEADERSIZE      (11)
+#  define AES_KEYSIZE(mode)   (64 + (mode * 64))
+
+#  include "aes/aes.h"
+#  include "aes/fileenc.h"
+#endif
+#ifdef HAVE_APPLE_COMPRESSION
+#  include <compression.h>
+#endif
+
+#ifndef NOUNCRYPT
+#  include "crypt.h"
+#endif
+
+#define DISKHEADERMAGIC             (0x08074b50)
+#define LOCALHEADERMAGIC            (0x04034b50)
+#define CENTRALHEADERMAGIC          (0x02014b50)
+#define ENDHEADERMAGIC              (0x06054b50)
+#define ZIP64ENDHEADERMAGIC         (0x06064b50)
+#define ZIP64ENDLOCHEADERMAGIC      (0x07064b50)
+
+#define SIZECENTRALDIRITEM          (0x2e)
+#define SIZECENTRALHEADERLOCATOR    (0x14)
+#define SIZEZIPLOCALHEADER          (0x1e)
+
+#ifndef BUFREADCOMMENT
+#  define BUFREADCOMMENT            (0x400)
+#endif
+
+#ifndef UNZ_BUFSIZE
+#  define UNZ_BUFSIZE               (UINT16_MAX)
+#endif
+#ifndef UNZ_MAXFILENAMEINZIP
+#  define UNZ_MAXFILENAMEINZIP      (256)
+#endif
+
+#ifndef ALLOC
+#  define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+#  define TRYFREE(p) {if (p) free(p);}
+#endif
+
+const char unz_copyright[] = " unzip 1.2.0 Copyright 1998-2017 - https://github.com/nmoinvaz/minizip";
+
+/* unz_file_info_internal contain internal info about a file in zipfile*/
+typedef struct unz_file_info64_internal_s
+{
+    uint64_t offset_curfile;            /* relative offset of local header 8 bytes */
+    uint64_t byte_before_the_zipfile;   /* byte before the zipfile, (>0 for sfx) */
+#ifdef HAVE_AES
+    uint8_t  aes_encryption_mode;
+    uint16_t aes_compression_method;
+    uint16_t aes_version;
+#endif
+} unz_file_info64_internal;
+
+/* file_in_zip_read_info_s contain internal information about a file in zipfile */
+typedef struct
+{
+    uint8_t *read_buffer;               /* internal buffer for compressed data */
+    z_stream stream;                    /* zLib stream structure for inflate */
+#ifdef HAVE_BZIP2
+    bz_stream bstream;                  /* bzLib stream structure for bziped */
+#endif
+#ifdef HAVE_APPLE_COMPRESSION
+    compression_stream astream;         /* libcompression stream structure */
+#endif
+#ifdef HAVE_AES
+    fcrypt_ctx aes_ctx;
+#endif
+    uint64_t pos_in_zipfile;            /* position in byte on the zipfile, for fseek */
+    uint8_t  stream_initialised;        /* flag set if stream structure is initialised */
+
+    uint64_t offset_local_extrafield;   /* offset of the local extra field */
+    uint16_t size_local_extrafield;     /* size of the local extra field */
+    uint64_t pos_local_extrafield;      /* position in the local extra field in read */
+    uint64_t total_out_64;
+
+    uint32_t crc32;                     /* crc32 of all data uncompressed */
+    uint32_t crc32_expected;            /* crc32 we must obtain after decompress all */
+    uint64_t rest_read_compressed;      /* number of byte to be decompressed */
+    uint64_t rest_read_uncompressed;    /* number of byte to be obtained after decomp */
+
+    zlib_filefunc64_32_def z_filefunc;
+
+    voidpf   filestream;                /* io structore of the zipfile */
+    uint16_t compression_method;        /* compression method (0==store) */
+    uint64_t byte_before_the_zipfile;   /* byte before the zipfile, (>0 for sfx) */
+    int      raw;
+} file_in_zip64_read_info_s;
+
+/* unz64_s contain internal information about the zipfile */
+typedef struct
+{
+    zlib_filefunc64_32_def z_filefunc;
+
+    voidpf filestream;                  /* io structure of the current zipfile */
+    voidpf filestream_with_CD;          /* io structure of the disk with the central directory */
+
+    unz_global_info64 gi;               /* public global information */
+
+    uint64_t byte_before_the_zipfile;   /* byte before the zipfile, (>0 for sfx) */
+    uint64_t num_file;                  /* number of the current file in the zipfile */
+    uint64_t pos_in_central_dir;        /* pos of the current file in the central dir */
+    uint64_t current_file_ok;           /* flag about the usability of the current file */
+    uint64_t central_pos;               /* position of the beginning of the central dir */
+    uint32_t number_disk;               /* number of the current disk, used for spanning ZIP */
+    uint64_t size_central_dir;          /* size of the central directory */
+    uint64_t offset_central_dir;        /* offset of start of central directory with
+                                           respect to the starting disk number */
+
+    unz_file_info64 cur_file_info;      /* public info about the current file in zip*/
+    unz_file_info64_internal cur_file_info_internal;
+                                        /* private info about it*/
+    file_in_zip64_read_info_s *pfile_in_zip_read;
+                                        /* structure about the current file if we are decompressing it */
+    int is_zip64;                       /* is the current file zip64 */
+#ifndef NOUNCRYPT
+    uint32_t keys[3];                   /* keys defining the pseudo-random sequence */
+    const z_crc_t *pcrc_32_tab;
+#endif
+} unz64_internal;
+
+/* Read a byte from a gz_stream; Return EOF for end of file. */
+static int unzReadUInt8(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint8_t *value)
+{
+    uint8_t c = 0;
+    if (ZREAD64(*pzlib_filefunc_def, filestream, &c, 1) == 1)
+    {
+        *value = (uint8_t)c;
+        return UNZ_OK;
+    }
+    *value = 0;
+    if (ZERROR64(*pzlib_filefunc_def, filestream))
+        return UNZ_ERRNO;
+    return UNZ_EOF;
+}
+
+static int unzReadUInt16(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint16_t *value)
+{
+    uint16_t x;
+    uint8_t c = 0;
+    int err = UNZ_OK;
+
+    err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x = (uint16_t)c;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x |= ((uint16_t)c) << 8;
+
+    if (err == UNZ_OK)
+        *value = x;
+    else
+        *value = 0;
+    return err;
+}
+
+static int unzReadUInt32(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint32_t *value)
+{
+    uint32_t x = 0;
+    uint8_t c = 0;
+    int err = UNZ_OK;
+
+    err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x = (uint32_t)c;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x |= ((uint32_t)c) << 8;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x |= ((uint32_t)c) << 16;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
+    x += ((uint32_t)c) << 24;
+
+    if (err == UNZ_OK)
+        *value = x;
+    else
+        *value = 0;
+    return err;
+}
+
+static int unzReadUInt64(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint64_t *value)
+{
+    uint64_t x = 0;
+    uint8_t i = 0;
+    int err = UNZ_OK;
+
+    err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x = (uint64_t)i;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x |= ((uint64_t)i) << 8;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x |= ((uint64_t)i) << 16;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x |= ((uint64_t)i) << 24;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x |= ((uint64_t)i) << 32;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x |= ((uint64_t)i) << 40;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x |= ((uint64_t)i) << 48;
+    if (err == UNZ_OK)
+        err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
+    x |= ((uint64_t)i) << 56;
+
+    if (err == UNZ_OK)
+        *value = x;
+    else
+        *value = 0;
+    return err;
+}
+
+/* Locate the Central directory of a zip file (at the end, just before the global comment) */
+static int unzSearchCentralDir(const zlib_filefunc64_32_def *pzlib_filefunc_def, uint64_t *pos_found, voidpf filestream)
+{
+    uint8_t buf[BUFREADCOMMENT + 4];
+    uint64_t file_size = 0;
+    uint64_t back_read = 4;
+    uint64_t max_back = UINT16_MAX; /* maximum size of global comment */
+    uint32_t read_size = 0;
+    uint64_t read_pos = 0;
+    uint32_t i = 0;
+    *pos_found = 0;
+
+    if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) != 0)
+        return UNZ_ERRNO;
+
+    file_size = ZTELL64(*pzlib_filefunc_def, filestream);
+
+    if (max_back > file_size)
+        max_back = file_size;
+
+    while (back_read < max_back)
+    {
+        if (back_read + BUFREADCOMMENT > max_back)
+            back_read = max_back;
+        else
+            back_read += BUFREADCOMMENT;
+
+        read_pos = file_size - back_read;
+        read_size = ((BUFREADCOMMENT + 4) < (file_size - read_pos)) ?
+                     (BUFREADCOMMENT + 4) : (uint32_t)(file_size - read_pos);
+
+        if (ZSEEK64(*pzlib_filefunc_def, filestream, read_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+            break;
+        if (ZREAD64(*pzlib_filefunc_def, filestream, buf, read_size) != read_size)
+            break;
+
+        for (i = read_size - 3; (i--) > 0;)
+            if (((*(buf+i)) == (ENDHEADERMAGIC & 0xff)) &&
+                ((*(buf+i+1)) == (ENDHEADERMAGIC >> 8 & 0xff)) &&
+                ((*(buf+i+2)) == (ENDHEADERMAGIC >> 16 & 0xff)) &&
+                ((*(buf+i+3)) == (ENDHEADERMAGIC >> 24 & 0xff)))
+            {
+                *pos_found = read_pos+i;
+                return UNZ_OK;
+            }
+    }
+
+    return UNZ_ERRNO;
+}
+
+/* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */
+static int unzSearchCentralDir64(const zlib_filefunc64_32_def *pzlib_filefunc_def, uint64_t *offset, voidpf filestream,
+    const uint64_t endcentraloffset)
+{
+    uint32_t value32 = 0;
+    *offset = 0;
+
+    /* Zip64 end of central directory locator */
+    if (ZSEEK64(*pzlib_filefunc_def, filestream, endcentraloffset - SIZECENTRALHEADERLOCATOR, ZLIB_FILEFUNC_SEEK_SET) != 0)
+        return UNZ_ERRNO;
+
+    /* Read locator signature */
+    if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
+        return UNZ_ERRNO;
+    if (value32 != ZIP64ENDLOCHEADERMAGIC)
+        return UNZ_ERRNO;
+    /* Number of the disk with the start of the zip64 end of  central directory */
+    if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
+        return UNZ_ERRNO;
+    /* Relative offset of the zip64 end of central directory record */
+    if (unzReadUInt64(pzlib_filefunc_def, filestream, offset) != UNZ_OK)
+        return UNZ_ERRNO;
+    /* Total number of disks */
+    if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
+        return UNZ_ERRNO;
+    /* Goto end of central directory record */
+    if (ZSEEK64(*pzlib_filefunc_def, filestream, *offset, ZLIB_FILEFUNC_SEEK_SET) != 0)
+        return UNZ_ERRNO;
+     /* The signature */
+    if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
+        return UNZ_ERRNO;
+    if (value32 != ZIP64ENDHEADERMAGIC)
+        return UNZ_ERRNO;
+
+    return UNZ_OK;
+}
+
+static unzFile unzOpenInternal(const void *path, zlib_filefunc64_32_def *pzlib_filefunc64_32_def)
+{
+    unz64_internal us;
+    unz64_internal *s = NULL;
+    uint64_t central_pos = 0;
+    uint64_t central_pos64 = 0;
+    uint64_t number_entry_CD = 0;
+    uint16_t value16 = 0;
+    uint32_t value32 = 0;
+    uint64_t value64 = 0;
+    voidpf filestream = NULL;
+    int err = UNZ_OK;
+
+    us.filestream = NULL;
+    us.filestream_with_CD = NULL;
+    us.z_filefunc.zseek32_file = NULL;
+    us.z_filefunc.ztell32_file = NULL;
+
+    if (pzlib_filefunc64_32_def == NULL)
+        fill_fopen64_filefunc(&us.z_filefunc.zfile_func64);
+    else
+        us.z_filefunc = *pzlib_filefunc64_32_def;
+
+    us.filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
+
+    if (us.filestream == NULL)
+        return NULL;
+
+    us.filestream_with_CD = us.filestream;
+    us.is_zip64 = 0;
+
+    /* Search for end of central directory header */
+    err = unzSearchCentralDir(&us.z_filefunc, &central_pos, us.filestream);
+    if (err == UNZ_OK)
+    {
+        if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+            err = UNZ_ERRNO;
+
+        /* The signature, already checked */
+        if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
+            err = UNZ_ERRNO;
+        /* Number of this disk */
+        if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
+            err = UNZ_ERRNO;
+        us.number_disk = value16;
+        /* Number of the disk with the start of the central directory */
+        if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
+            err = UNZ_ERRNO;
+        us.gi.number_disk_with_CD = value16;
+        /* Total number of entries in the central directory on this disk */
+        if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
+            err = UNZ_ERRNO;
+        us.gi.number_entry = value16;
+        /* Total number of entries in the central directory */
+        if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
+            err = UNZ_ERRNO;
+        number_entry_CD = value16;
+        if (number_entry_CD != us.gi.number_entry)
+            err = UNZ_BADZIPFILE;
+        /* Size of the central directory */
+        if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
+            err = UNZ_ERRNO;
+        us.size_central_dir = value32;
+        /* Offset of start of central directory with respect to the starting disk number */
+        if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
+            err = UNZ_ERRNO;
+        us.offset_central_dir = value32;
+        /* Zipfile comment length */
+        if (unzReadUInt16(&us.z_filefunc, us.filestream, &us.gi.size_comment) != UNZ_OK)
+            err = UNZ_ERRNO;
+
+        if (err == UNZ_OK)
+        {
+            /* Search for Zip64 end of central directory header */
+            int err64 = unzSearchCentralDir64(&us.z_filefunc, &central_pos64, us.filestream, central_pos);
+            if (err64 == UNZ_OK)
+            {
+                central_pos = central_pos64;
+                us.is_zip64 = 1;
+
+                if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+                    err = UNZ_ERRNO;
+
+                /* the signature, already checked */
+                if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* size of zip64 end of central directory record */
+                if (unzReadUInt64(&us.z_filefunc, us.filestream, &value64) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* version made by */
+                if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* version needed to extract */
+                if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* number of this disk */
+                if (unzReadUInt32(&us.z_filefunc, us.filestream, &us.number_disk) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* number of the disk with the start of the central directory */
+                if (unzReadUInt32(&us.z_filefunc, us.filestream, &us.gi.number_disk_with_CD) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* total number of entries in the central directory on this disk */
+                if (unzReadUInt64(&us.z_filefunc, us.filestream, &us.gi.number_entry) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* total number of entries in the central directory */
+                if (unzReadUInt64(&us.z_filefunc, us.filestream, &number_entry_CD) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                if (number_entry_CD != us.gi.number_entry)
+                    err = UNZ_BADZIPFILE;
+                /* size of the central directory */
+                if (unzReadUInt64(&us.z_filefunc, us.filestream, &us.size_central_dir) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* offset of start of central directory with respect to the starting disk number */
+                if (unzReadUInt64(&us.z_filefunc, us.filestream, &us.offset_central_dir) != UNZ_OK)
+                    err = UNZ_ERRNO;
+            }
+            else if ((us.gi.number_entry == UINT16_MAX) || (us.size_central_dir == UINT16_MAX) || (us.offset_central_dir == UINT32_MAX))
+                err = UNZ_BADZIPFILE;
+        }
+    }
+    else
+        err = UNZ_ERRNO;
+
+    if ((err == UNZ_OK) && (central_pos < us.offset_central_dir + us.size_central_dir))
+        err = UNZ_BADZIPFILE;
+
+    if (err != UNZ_OK)
+    {
+        ZCLOSE64(us.z_filefunc, us.filestream);
+        return NULL;
+    }
+
+    if (us.gi.number_disk_with_CD == 0)
+    {
+        /* If there is only one disk open another stream so we don't have to seek between the CD
+           and the file headers constantly */
+        filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
+        if (filestream != NULL)
+            us.filestream = filestream;
+    }
+
+    /* Hack for zip files that have no respect for zip64
+    if ((central_pos > 0xffffffff) && (us.offset_central_dir < 0xffffffff))
+        us.offset_central_dir = central_pos - us.size_central_dir;*/
+
+    us.byte_before_the_zipfile = central_pos - (us.offset_central_dir + us.size_central_dir);
+    us.central_pos = central_pos;
+    us.pfile_in_zip_read = NULL;
+
+    s = (unz64_internal*)ALLOC(sizeof(unz64_internal));
+    if (s != NULL)
+    {
+        *s = us;
+        unzGoToFirstFile((unzFile)s);
+    }
+    return (unzFile)s;
+}
+
+extern unzFile ZEXPORT unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc32_def)
+{
+    if (pzlib_filefunc32_def != NULL)
+    {
+        zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+        fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill, pzlib_filefunc32_def);
+        return unzOpenInternal(path, &zlib_filefunc64_32_def_fill);
+    }
+    return unzOpenInternal(path, NULL);
+}
+
+extern unzFile ZEXPORT unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def)
+{
+    if (pzlib_filefunc_def != NULL)
+    {
+        zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+        zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+        zlib_filefunc64_32_def_fill.ztell32_file = NULL;
+        zlib_filefunc64_32_def_fill.zseek32_file = NULL;
+        return unzOpenInternal(path, &zlib_filefunc64_32_def_fill);
+    }
+    return unzOpenInternal(path, NULL);
+}
+
+extern unzFile ZEXPORT unzOpen(const char *path)
+{
+    return unzOpenInternal(path, NULL);
+}
+
+extern unzFile ZEXPORT unzOpen64(const void *path)
+{
+    return unzOpenInternal(path, NULL);
+}
+
+extern int ZEXPORT unzClose(unzFile file)
+{
+    unz64_internal *s;
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    if (s->pfile_in_zip_read != NULL)
+        unzCloseCurrentFile(file);
+
+    if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD))
+        ZCLOSE64(s->z_filefunc, s->filestream);
+    if (s->filestream_with_CD != NULL)
+        ZCLOSE64(s->z_filefunc, s->filestream_with_CD);
+
+    s->filestream = NULL;
+    s->filestream_with_CD = NULL;
+    TRYFREE(s);
+    return UNZ_OK;
+}
+
+/* Goto to the next available disk for spanned archives */
+static int unzGoToNextDisk(unzFile file)
+{
+    unz64_internal *s;
+    uint32_t number_disk_next = 0;
+
+    s = (unz64_internal*)file;
+    if (s == NULL)
+        return UNZ_PARAMERROR;
+    number_disk_next = s->number_disk;
+
+    if ((s->pfile_in_zip_read != NULL) && (s->pfile_in_zip_read->rest_read_uncompressed > 0))
+        /* We are currently reading a file and we need the next sequential disk */
+        number_disk_next += 1;
+    else
+        /* Goto the disk for the current file */
+        number_disk_next = s->cur_file_info.disk_num_start;
+
+    if (number_disk_next != s->number_disk)
+    {
+        /* Switch disks */
+        if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD))
+            ZCLOSE64(s->z_filefunc, s->filestream);
+
+        if (number_disk_next == s->gi.number_disk_with_CD)
+        {
+            s->filestream = s->filestream_with_CD;
+        }
+        else
+        {
+            s->filestream = ZOPENDISK64(s->z_filefunc, s->filestream_with_CD, number_disk_next,
+                ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
+        }
+
+        if (s->filestream == NULL)
+            return UNZ_ERRNO;
+
+        s->number_disk = number_disk_next;
+    }
+
+    return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32)
+{
+    unz64_internal *s = NULL;
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    pglobal_info32->number_entry = (uint32_t)s->gi.number_entry;
+    pglobal_info32->size_comment = s->gi.size_comment;
+    pglobal_info32->number_disk_with_CD = s->gi.number_disk_with_CD;
+    return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info)
+{
+    unz64_internal *s = NULL;
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    *pglobal_info = s->gi;
+    return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetGlobalComment(unzFile file, char *comment, uint16_t comment_size)
+{
+    unz64_internal *s = NULL;
+    uint16_t bytes_to_read = comment_size;
+    if (file == NULL)
+        return (int)UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    if (bytes_to_read > s->gi.size_comment)
+        bytes_to_read = s->gi.size_comment;
+
+    if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, s->central_pos + 22, ZLIB_FILEFUNC_SEEK_SET) != 0)
+        return UNZ_ERRNO;
+
+    if (bytes_to_read > 0)
+    {
+        *comment = 0;
+        if (ZREAD64(s->z_filefunc, s->filestream_with_CD, comment, bytes_to_read) != bytes_to_read)
+            return UNZ_ERRNO;
+    }
+
+    if ((comment != NULL) && (comment_size > s->gi.size_comment))
+        *(comment + s->gi.size_comment) = 0;
+
+    return (int)bytes_to_read;
+}
+
+static int unzGetCurrentFileInfoField(unzFile file, uint32_t *seek, void *field, uint16_t field_size, uint16_t size_file_field, int null_terminated_field)
+{
+    unz64_internal *s = NULL;
+    uint32_t bytes_to_read = 0;
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return (int)UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    /* Read field */
+    if (field != NULL)
+    {
+        if (size_file_field < field_size)
+        {
+            if (null_terminated_field)
+                *((char *)field+size_file_field) = 0;
+
+            bytes_to_read = size_file_field;
+        }
+        else
+            bytes_to_read = field_size;
+        
+        if (*seek != 0)
+        {
+            if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, *seek, ZLIB_FILEFUNC_SEEK_CUR) == 0)
+                *seek = 0;
+            else
+                err = UNZ_ERRNO;
+        }
+        
+        if ((size_file_field > 0) && (field_size > 0))
+        {
+            if (ZREAD64(s->z_filefunc, s->filestream_with_CD, field, bytes_to_read) != bytes_to_read)
+                err = UNZ_ERRNO;
+        }
+        *seek += size_file_field - bytes_to_read;
+    }
+    else
+    {
+        *seek += size_file_field;
+    }
+
+    return err;
+}
+
+/* Get info about the current file in the zipfile, with internal only info */
+static int unzGetCurrentFileInfoInternal(unzFile file, unz_file_info64 *pfile_info,
+    unz_file_info64_internal *pfile_info_internal, char *filename, uint16_t filename_size, void *extrafield,
+    uint16_t extrafield_size, char *comment, uint16_t comment_size)
+{
+    unz64_internal *s = NULL;
+    unz_file_info64 file_info;
+    unz_file_info64_internal file_info_internal;
+    uint32_t magic = 0;
+    uint64_t current_pos = 0;
+    uint32_t seek = 0;
+    uint32_t extra_pos = 0;
+    uint16_t extra_header_id = 0;
+    uint16_t extra_data_size = 0;
+    uint16_t value16 = 0;
+    uint32_t value32 = 0;
+    uint64_t value64 = 0;
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    if (ZSEEK64(s->z_filefunc, s->filestream_with_CD,
+            s->pos_in_central_dir + s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
+        err = UNZ_ERRNO;
+
+    /* Check the magic */
+    if (err == UNZ_OK)
+    {
+        if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &magic) != UNZ_OK)
+            err = UNZ_ERRNO;
+        else if (magic != CENTRALHEADERMAGIC)
+            err = UNZ_BADZIPFILE;
+    }
+
+    /* Read central directory header */
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.version) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.version_needed) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.flag) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.compression_method) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.dos_date) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.crc) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &value32) != UNZ_OK)
+        err = UNZ_ERRNO;
+    file_info.compressed_size = value32;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &value32) != UNZ_OK)
+        err = UNZ_ERRNO;
+    file_info.uncompressed_size = value32;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.size_filename) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_extra) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_comment) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &value16) != UNZ_OK)
+        err = UNZ_ERRNO;
+    file_info.disk_num_start = value16;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.internal_fa) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.external_fa) != UNZ_OK)
+        err = UNZ_ERRNO;
+    /* Relative offset of local header */
+    if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &value32) != UNZ_OK)
+        err = UNZ_ERRNO;
+
+    file_info.size_file_extra_internal = 0;
+    file_info.disk_offset = value32;
+    file_info_internal.offset_curfile = value32;
+#ifdef HAVE_AES
+    file_info_internal.aes_compression_method = 0;
+    file_info_internal.aes_encryption_mode = 0;
+    file_info_internal.aes_version = 0;
+#endif
+
+    if (err == UNZ_OK)
+        err = unzGetCurrentFileInfoField(file, &seek, filename, filename_size, file_info.size_filename, 1);
+
+    /* Read extrafield */
+    if (err == UNZ_OK)
+        err = unzGetCurrentFileInfoField(file, &seek, extrafield, extrafield_size, file_info.size_file_extra, 0);
+
+    if ((err == UNZ_OK) && (file_info.size_file_extra != 0))
+    {
+        if (seek != 0)
+        {
+            if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, seek, ZLIB_FILEFUNC_SEEK_CUR) == 0)
+                seek = 0;
+            else
+                err = UNZ_ERRNO;
+        }
+
+        /* We are going to parse the extra field so we need to move back */
+        current_pos = ZTELL64(s->z_filefunc, s->filestream_with_CD);
+        if (current_pos < file_info.size_file_extra)
+            err = UNZ_ERRNO;
+        current_pos -= file_info.size_file_extra;
+        if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, current_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+            err = UNZ_ERRNO;
+
+        while ((err != UNZ_ERRNO) && (extra_pos < file_info.size_file_extra))
+        {
+            if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &extra_header_id) != UNZ_OK)
+                err = UNZ_ERRNO;
+            if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &extra_data_size) != UNZ_OK)
+                err = UNZ_ERRNO;
+
+            /* ZIP64 extra fields */
+            if (extra_header_id == 0x0001)
+            {
+                /* Subtract size of ZIP64 field, since ZIP64 is handled internally */
+                file_info.size_file_extra_internal += 2 + 2 + extra_data_size;
+
+                if (file_info.uncompressed_size == UINT32_MAX)
+                {
+                    if (unzReadUInt64(&s->z_filefunc, s->filestream_with_CD, &file_info.uncompressed_size) != UNZ_OK)
+                        err = UNZ_ERRNO;
+                }
+                if (file_info.compressed_size == UINT32_MAX)
+                {
+                    if (unzReadUInt64(&s->z_filefunc, s->filestream_with_CD, &file_info.compressed_size) != UNZ_OK)
+                        err = UNZ_ERRNO;
+                }
+                if (file_info_internal.offset_curfile == UINT32_MAX)
+                {
+                    /* Relative Header offset */
+                    if (unzReadUInt64(&s->z_filefunc, s->filestream_with_CD, &value64) != UNZ_OK)
+                        err = UNZ_ERRNO;
+                    file_info_internal.offset_curfile = value64;
+                    file_info.disk_offset = value64;
+                }
+                if (file_info.disk_num_start == UINT32_MAX)
+                {
+                    /* Disk Start Number */
+                    if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.disk_num_start) != UNZ_OK)
+                        err = UNZ_ERRNO;
+                }
+            }
+#ifdef HAVE_AES
+            /* AES header */
+            else if (extra_header_id == 0x9901)
+            {
+                uint8_t value8 = 0;
+
+                /* Subtract size of AES field, since AES is handled internally */
+                file_info.size_file_extra_internal += 2 + 2 + extra_data_size;
+
+                /* Verify version info */
+                if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &value16) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                /* Support AE-1 and AE-2 */
+                if (value16 != 1 && value16 != 2)
+                    err = UNZ_ERRNO;
+                file_info_internal.aes_version = value16;
+                if (unzReadUInt8(&s->z_filefunc, s->filestream_with_CD, &value8) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                if ((char)value8 != 'A')
+                    err = UNZ_ERRNO;
+                if (unzReadUInt8(&s->z_filefunc, s->filestream_with_CD, &value8) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                if ((char)value8 != 'E')
+                    err = UNZ_ERRNO;
+                /* Get AES encryption strength and actual compression method */
+                if (unzReadUInt8(&s->z_filefunc, s->filestream_with_CD, &value8) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                file_info_internal.aes_encryption_mode = value8;
+                if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &value16) != UNZ_OK)
+                    err = UNZ_ERRNO;
+                file_info_internal.aes_compression_method = value16;
+            }
+#endif
+            else
+            {
+                if (ZSEEK64(s->z_filefunc, s->filestream_with_CD,extra_data_size, ZLIB_FILEFUNC_SEEK_CUR) != 0)
+                    err = UNZ_ERRNO;
+            }
+
+            extra_pos += 2 + 2 + extra_data_size;
+        }
+    }
+
+    if (file_info.disk_num_start == s->gi.number_disk_with_CD)
+        file_info_internal.byte_before_the_zipfile = s->byte_before_the_zipfile;
+    else
+        file_info_internal.byte_before_the_zipfile = 0;
+
+    if (err == UNZ_OK)
+        err = unzGetCurrentFileInfoField(file, &seek, comment, comment_size, file_info.size_file_comment, 1);
+
+    if ((err == UNZ_OK) && (pfile_info != NULL))
+        *pfile_info = file_info;
+    if ((err == UNZ_OK) && (pfile_info_internal != NULL))
+        *pfile_info_internal = file_info_internal;
+
+    return err;
+}
+
+extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
+{
+    unz_file_info64 file_info64;
+    int err = UNZ_OK;
+
+    err = unzGetCurrentFileInfoInternal(file, &file_info64, NULL, filename, filename_size,
+                extrafield, extrafield_size, comment, comment_size);
+
+    if ((err == UNZ_OK) && (pfile_info != NULL))
+    {
+        pfile_info->version = file_info64.version;
+        pfile_info->version_needed = file_info64.version_needed;
+        pfile_info->flag = file_info64.flag;
+        pfile_info->compression_method = file_info64.compression_method;
+        pfile_info->dos_date = file_info64.dos_date;
+        pfile_info->crc = file_info64.crc;
+
+        pfile_info->size_filename = file_info64.size_filename;
+        pfile_info->size_file_extra = file_info64.size_file_extra - file_info64.size_file_extra_internal;
+        pfile_info->size_file_comment = file_info64.size_file_comment;
+
+        pfile_info->disk_num_start = (uint16_t)file_info64.disk_num_start;
+        pfile_info->internal_fa = file_info64.internal_fa;
+        pfile_info->external_fa = file_info64.external_fa;
+
+        pfile_info->compressed_size = (uint32_t)file_info64.compressed_size;
+        pfile_info->uncompressed_size = (uint32_t)file_info64.uncompressed_size;
+    }
+    return err;
+}
+
+extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
+{
+    return unzGetCurrentFileInfoInternal(file, pfile_info, NULL, filename, filename_size,
+        extrafield, extrafield_size, comment,comment_size);
+}
+
+/* Read the local header of the current zipfile. Check the coherency of the local header and info in the
+   end of central directory about this file store in *piSizeVar the size of extra info in local header
+   (filename and size of extra field data) */
+static int unzCheckCurrentFileCoherencyHeader(unz64_internal *s, uint32_t *psize_variable, uint64_t *poffset_local_extrafield,
+    uint16_t *psize_local_extrafield)
+{
+    uint32_t magic = 0;
+    uint16_t value16 = 0;
+    uint32_t value32 = 0;
+    uint32_t flags = 0;
+    uint16_t size_filename = 0;
+    uint16_t size_extra_field = 0;
+    uint16_t compression_method = 0;
+    int err = UNZ_OK;
+
+    if (psize_variable == NULL)
+        return UNZ_PARAMERROR;
+    *psize_variable = 0;
+    if (poffset_local_extrafield == NULL)
+        return UNZ_PARAMERROR;
+    *poffset_local_extrafield = 0;
+    if (psize_local_extrafield == NULL)
+        return UNZ_PARAMERROR;
+    *psize_local_extrafield = 0;
+
+    err = unzGoToNextDisk((unzFile)s);
+    if (err != UNZ_OK)
+        return err;
+
+    if (ZSEEK64(s->z_filefunc, s->filestream, s->cur_file_info_internal.offset_curfile +
+        s->cur_file_info_internal.byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
+        return UNZ_ERRNO;
+
+    if (err == UNZ_OK)
+    {
+        if (unzReadUInt32(&s->z_filefunc, s->filestream, &magic) != UNZ_OK)
+            err = UNZ_ERRNO;
+        else if (magic != LOCALHEADERMAGIC)
+            err = UNZ_BADZIPFILE;
+    }
+
+    if (unzReadUInt16(&s->z_filefunc, s->filestream, &value16) != UNZ_OK)
+        err = UNZ_ERRNO;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream, &value16) != UNZ_OK)
+        err = UNZ_ERRNO;
+    flags = value16;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream, &value16) != UNZ_OK)
+        err = UNZ_ERRNO;
+    else if ((err == UNZ_OK) && (value16 != s->cur_file_info.compression_method))
+        err = UNZ_BADZIPFILE;
+
+    compression_method = s->cur_file_info.compression_method;
+#ifdef HAVE_AES
+    if (compression_method == AES_METHOD)
+        compression_method = s->cur_file_info_internal.aes_compression_method;
+#endif
+
+    if ((err == UNZ_OK) && (compression_method != 0) && (compression_method != Z_DEFLATED))
+    {
+#ifdef HAVE_BZIP2
+        if (compression_method != Z_BZIP2ED)
+#endif
+            err = UNZ_BADZIPFILE;
+    }
+
+    if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* date/time */
+        err = UNZ_ERRNO;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* crc */
+        err = UNZ_ERRNO;
+    else if ((err == UNZ_OK) && (value32 != s->cur_file_info.crc) && ((flags & 8) == 0))
+        err = UNZ_BADZIPFILE;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* size compr */
+        err = UNZ_ERRNO;
+    else if ((value32 != UINT32_MAX) && (err == UNZ_OK) && (value32 != s->cur_file_info.compressed_size) && ((flags & 8) == 0))
+        err = UNZ_BADZIPFILE;
+    if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* size uncompr */
+        err = UNZ_ERRNO;
+    else if ((value32 != UINT32_MAX) && (err == UNZ_OK) && (value32 != s->cur_file_info.uncompressed_size) && ((flags & 8) == 0))
+        err = UNZ_BADZIPFILE;
+    if (unzReadUInt16(&s->z_filefunc, s->filestream, &size_filename) != UNZ_OK)
+        err = UNZ_ERRNO;
+
+    *psize_variable += size_filename;
+
+    if (unzReadUInt16(&s->z_filefunc, s->filestream, &size_extra_field) != UNZ_OK)
+        err = UNZ_ERRNO;
+
+    *poffset_local_extrafield = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename;
+    *psize_local_extrafield = size_extra_field;
+    *psize_variable += size_extra_field;
+
+    return err;
+}
+
+/*
+  Open for reading data the current file in the zipfile.
+  If there is no error and the file is opened, the return value is UNZ_OK.
+*/
+extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password)
+{
+    unz64_internal *s = NULL;
+    file_in_zip64_read_info_s *pfile_in_zip_read_info = NULL;
+    uint16_t compression_method = 0;
+    uint64_t offset_local_extrafield = 0;
+    uint16_t size_local_extrafield = 0;
+    uint32_t size_variable = 0;
+    int err = UNZ_OK;
+#ifndef NOUNCRYPT
+    char source[12];
+#else
+    if (password != NULL)
+        return UNZ_PARAMERROR;
+#endif
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (!s->current_file_ok)
+        return UNZ_PARAMERROR;
+
+    if (s->pfile_in_zip_read != NULL)
+        unzCloseCurrentFile(file);
+
+    if (unzCheckCurrentFileCoherencyHeader(s, &size_variable, &offset_local_extrafield, &size_local_extrafield) != UNZ_OK)
+        return UNZ_BADZIPFILE;
+    
+    compression_method = s->cur_file_info.compression_method;
+#ifdef HAVE_AES
+    if (compression_method == AES_METHOD)
+    {
+        compression_method = s->cur_file_info_internal.aes_compression_method;
+        if (password == NULL)
+        {
+            return UNZ_PARAMERROR;
+        }
+    }
+#endif
+
+    if (method != NULL)
+        *method = compression_method;
+
+    if (level != NULL)
+    {
+        *level = 6;
+        switch (s->cur_file_info.flag & 0x06)
+        {
+          case 6 : *level = 1; break;
+          case 4 : *level = 2; break;
+          case 2 : *level = 9; break;
+        }
+    }
+
+    if ((compression_method != 0) && (compression_method != Z_DEFLATED))
+    {
+#ifdef HAVE_BZIP2
+        if (compression_method != Z_BZIP2ED)
+#endif
+        {
+            return UNZ_BADZIPFILE;
+        }
+    }
+    
+    pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s));
+    if (pfile_in_zip_read_info == NULL)
+        return UNZ_INTERNALERROR;
+
+    pfile_in_zip_read_info->read_buffer = (uint8_t*)ALLOC(UNZ_BUFSIZE);
+    if (pfile_in_zip_read_info->read_buffer == NULL)
+    {
+        TRYFREE(pfile_in_zip_read_info);
+        return UNZ_INTERNALERROR;
+    }
+    
+    pfile_in_zip_read_info->stream_initialised = 0;
+
+    pfile_in_zip_read_info->filestream = s->filestream;
+    pfile_in_zip_read_info->z_filefunc = s->z_filefunc;
+
+    pfile_in_zip_read_info->raw = raw;
+    pfile_in_zip_read_info->crc32 = 0;
+    pfile_in_zip_read_info->crc32_expected = s->cur_file_info.crc;
+    pfile_in_zip_read_info->total_out_64 = 0;
+    pfile_in_zip_read_info->compression_method = compression_method;
+    
+    pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
+    pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
+    pfile_in_zip_read_info->pos_local_extrafield = 0;
+
+    pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size;
+    pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size;
+    pfile_in_zip_read_info->byte_before_the_zipfile = 0;
+
+    if (s->number_disk == s->gi.number_disk_with_CD)
+        pfile_in_zip_read_info->byte_before_the_zipfile = s->byte_before_the_zipfile;
+        
+    pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_variable;
+
+    pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+    pfile_in_zip_read_info->stream.zfree = (free_func)0;
+    pfile_in_zip_read_info->stream.opaque = (voidpf)s;
+    pfile_in_zip_read_info->stream.total_out = 0;
+    pfile_in_zip_read_info->stream.total_in = 0;
+    pfile_in_zip_read_info->stream.next_in = NULL;
+    pfile_in_zip_read_info->stream.avail_in = 0;
+
+    if (!raw)
+    {
+        if (compression_method == Z_BZIP2ED)
+        {
+#ifdef HAVE_BZIP2
+            pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0;
+            pfile_in_zip_read_info->bstream.bzfree = (free_func)0;
+            pfile_in_zip_read_info->bstream.opaque = (voidpf)0;
+            pfile_in_zip_read_info->bstream.state = (voidpf)0;
+
+            err = BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0);
+            if (err == Z_OK)
+            {
+                pfile_in_zip_read_info->stream_initialised = Z_BZIP2ED;
+            }
+            else
+            {
+                TRYFREE(pfile_in_zip_read_info);
+                return err;
+            }
+#else
+            pfile_in_zip_read_info->raw = 1;
+#endif
+        }
+        else if (compression_method == Z_DEFLATED)
+        {
+#ifdef HAVE_APPLE_COMPRESSION
+            err = compression_stream_init(&pfile_in_zip_read_info->astream, COMPRESSION_STREAM_DECODE, COMPRESSION_ZLIB);
+            if (err == COMPRESSION_STATUS_ERROR)
+                err = UNZ_INTERNALERROR;
+            else
+                err = Z_OK;
+#else
+            err = inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
+#endif
+            if (err == Z_OK)
+            {
+                pfile_in_zip_read_info->stream_initialised = Z_DEFLATED;
+            }
+            else
+            {
+                TRYFREE(pfile_in_zip_read_info);
+                return err;
+            }
+            /* windowBits is passed < 0 to tell that there is no zlib header.
+             * Note that in this case inflate *requires* an extra "dummy" byte
+             * after the compressed stream in order to complete decompression and
+             * return Z_STREAM_END.
+             * In unzip, i don't wait absolutely Z_STREAM_END because I known the
+             * size of both compressed and uncompressed data
+             */
+        }
+    }
+
+    s->pfile_in_zip_read = pfile_in_zip_read_info;
+
+#ifndef NOUNCRYPT
+    s->pcrc_32_tab = NULL;
+
+    if ((password != NULL) && ((s->cur_file_info.flag & 1) != 0))
+    {
+        if (ZSEEK64(s->z_filefunc, s->filestream,
+                  s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile,
+                  ZLIB_FILEFUNC_SEEK_SET) != 0)
+            return UNZ_INTERNALERROR;
+#ifdef HAVE_AES
+        if (s->cur_file_info.compression_method == AES_METHOD)
+        {
+            unsigned char passverify_archive[AES_PWVERIFYSIZE];
+            unsigned char passverify_password[AES_PWVERIFYSIZE];
+            unsigned char salt_value[AES_MAXSALTLENGTH];
+            uint32_t salt_length = 0;
+
+            if ((s->cur_file_info_internal.aes_encryption_mode < 1) ||
+                (s->cur_file_info_internal.aes_encryption_mode > 3))
+                return UNZ_INTERNALERROR;
+
+            salt_length = SALT_LENGTH(s->cur_file_info_internal.aes_encryption_mode);
+
+            if (ZREAD64(s->z_filefunc, s->filestream, salt_value, salt_length) != salt_length)
+                return UNZ_INTERNALERROR;
+            if (ZREAD64(s->z_filefunc, s->filestream, passverify_archive, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE)
+                return UNZ_INTERNALERROR;
+
+            fcrypt_init(s->cur_file_info_internal.aes_encryption_mode, (uint8_t *)password,
+                (uint32_t)strlen(password), salt_value, passverify_password, &s->pfile_in_zip_read->aes_ctx);
+
+            if (memcmp(passverify_archive, passverify_password, AES_PWVERIFYSIZE) != 0)
+                return UNZ_BADPASSWORD;
+
+            s->pfile_in_zip_read->rest_read_compressed -= salt_length + AES_PWVERIFYSIZE;
+            s->pfile_in_zip_read->rest_read_compressed -= AES_AUTHCODESIZE;
+
+            s->pfile_in_zip_read->pos_in_zipfile += salt_length + AES_PWVERIFYSIZE;
+        }
+        else
+#endif
+        {
+            int i;
+            uint8_t expected;
+            uint8_t actual;
+           
+            s->pcrc_32_tab = (const z_crc_t*)get_crc_table();
+            init_keys(password, s->keys, s->pcrc_32_tab);
+
+            if (ZREAD64(s->z_filefunc, s->filestream, source, 12) < 12)
+                return UNZ_INTERNALERROR;
+
+            for (i = 0; i < 12; i++)
+                zdecode(s->keys, s->pcrc_32_tab, source[i]);
+            expected = (s->cur_file_info.flag & (1 << 3)) ?
+                s->cur_file_info.dos_date >> 8 :
+                s->cur_file_info.crc >> 24;
+            actual = (uint8_t)source[11];
+            if ((actual != 0) && (expected != actual)) {
+              return UNZ_BADPASSWORD;
+            }
+
+            s->pfile_in_zip_read->rest_read_compressed -= 12;
+            s->pfile_in_zip_read->pos_in_zipfile += 12;
+        }
+    }
+#endif
+
+    return UNZ_OK;
+}
+
+extern int ZEXPORT unzOpenCurrentFile(unzFile file)
+{
+    return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
+}
+
+extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char *password)
+{
+    return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
+}
+
+extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw)
+{
+    return unzOpenCurrentFile3(file, method, level, raw, NULL);
+}
+
+/* Read bytes from the current file.
+   buf contain buffer where data must be copied
+   len the size of buf.
+
+   return the number of byte copied if some bytes are copied
+   return 0 if the end of file was reached
+   return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */
+extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, uint32_t len)
+{
+    unz64_internal *s = NULL;
+    uint32_t read = 0;
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    if (s->pfile_in_zip_read == NULL)
+        return UNZ_PARAMERROR;
+    if (s->pfile_in_zip_read->read_buffer == NULL)
+        return UNZ_END_OF_LIST_OF_FILE;
+    if (len == 0)
+        return 0;
+    // avail_out is uInt, so uint32_t len might allow requesting a larger buffer than zlib can support
+    if (len > UINT_MAX)
+        return UNZ_PARAMERROR;
+
+    s->pfile_in_zip_read->stream.next_out = (uint8_t*)buf;
+    s->pfile_in_zip_read->stream.avail_out = (uInt)len;
+
+    if ((s->pfile_in_zip_read->compression_method == 0) || (s->pfile_in_zip_read->raw))
+    {
+        if (len > s->pfile_in_zip_read->rest_read_compressed + s->pfile_in_zip_read->stream.avail_in)
+            s->pfile_in_zip_read->stream.avail_out = (uInt)s->pfile_in_zip_read->rest_read_compressed +
+            s->pfile_in_zip_read->stream.avail_in;
+    }
+
+    do
+    {
+        if (s->pfile_in_zip_read->stream.avail_in == 0)
+        {
+            uint32_t bytes_to_read = UNZ_BUFSIZE;
+            uint32_t bytes_not_read = 0;
+            uint32_t bytes_read = 0;
+            uint32_t total_bytes_read = 0;
+
+            if (s->pfile_in_zip_read->stream.next_in != NULL)
+                bytes_not_read = (uint32_t)(s->pfile_in_zip_read->read_buffer + UNZ_BUFSIZE -
+                    s->pfile_in_zip_read->stream.next_in);
+            bytes_to_read -= bytes_not_read;
+            if (bytes_not_read > 0)
+                memmove(s->pfile_in_zip_read->read_buffer, s->pfile_in_zip_read->stream.next_in, bytes_not_read);
+            if (s->pfile_in_zip_read->rest_read_compressed < bytes_to_read)
+                bytes_to_read = (uint32_t)s->pfile_in_zip_read->rest_read_compressed;
+
+            while (total_bytes_read != bytes_to_read)
+            {
+                if (ZSEEK64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream,
+                        s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile,
+                        ZLIB_FILEFUNC_SEEK_SET) != 0)
+                    return UNZ_ERRNO;
+
+                bytes_read = ZREAD64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream,
+                          s->pfile_in_zip_read->read_buffer + bytes_not_read + total_bytes_read,
+                          bytes_to_read - total_bytes_read);
+
+                total_bytes_read += bytes_read;
+                s->pfile_in_zip_read->pos_in_zipfile += bytes_read;
+
+                if (bytes_read == 0)
+                {
+                    if (ZERROR64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream))
+                        return UNZ_ERRNO;
+
+                    err = unzGoToNextDisk(file);
+                    if (err != UNZ_OK)
+                        return err;
+
+                    s->pfile_in_zip_read->pos_in_zipfile = 0;
+                    s->pfile_in_zip_read->filestream = s->filestream;
+                }
+            }
+
+#ifndef NOUNCRYPT
+            if ((s->cur_file_info.flag & 1) != 0)
+            {
+#ifdef HAVE_AES
+                if (s->cur_file_info.compression_method == AES_METHOD)
+                {
+                    fcrypt_decrypt(s->pfile_in_zip_read->read_buffer, bytes_to_read, &s->pfile_in_zip_read->aes_ctx);
+                }
+                else
+#endif
+                if (s->pcrc_32_tab != NULL)
+                {
+                    uint32_t i = 0;
+
+                    for (i = 0; i < total_bytes_read; i++)
+                      s->pfile_in_zip_read->read_buffer[i] =
+                          zdecode(s->keys, s->pcrc_32_tab, s->pfile_in_zip_read->read_buffer[i]);
+                }
+            }
+#endif
+
+            s->pfile_in_zip_read->rest_read_compressed -= total_bytes_read;
+            s->pfile_in_zip_read->stream.next_in = (uint8_t*)s->pfile_in_zip_read->read_buffer;
+            s->pfile_in_zip_read->stream.avail_in = (uInt)(bytes_not_read + total_bytes_read);
+        }
+
+        if ((s->pfile_in_zip_read->compression_method == 0) || (s->pfile_in_zip_read->raw))
+        {
+            uint32_t i = 0;
+            uint32_t copy = 0;
+
+            if ((s->pfile_in_zip_read->stream.avail_in == 0) &&
+                (s->pfile_in_zip_read->rest_read_compressed == 0))
+                return (read == 0) ? UNZ_EOF : read;
+
+            if (s->pfile_in_zip_read->stream.avail_out < s->pfile_in_zip_read->stream.avail_in)
+                copy = s->pfile_in_zip_read->stream.avail_out;
+            else
+                copy = s->pfile_in_zip_read->stream.avail_in;
+
+            for (i = 0; i < copy; i++)
+                *(s->pfile_in_zip_read->stream.next_out + i) =
+                        *(s->pfile_in_zip_read->stream.next_in + i);
+
+            s->pfile_in_zip_read->total_out_64 = s->pfile_in_zip_read->total_out_64 + copy;
+            s->pfile_in_zip_read->rest_read_uncompressed -= copy;
+            s->pfile_in_zip_read->crc32 = (uint32_t)crc32(s->pfile_in_zip_read->crc32,
+                                s->pfile_in_zip_read->stream.next_out, copy);
+
+            s->pfile_in_zip_read->stream.avail_in -= copy;
+            s->pfile_in_zip_read->stream.avail_out -= copy;
+            s->pfile_in_zip_read->stream.next_out += copy;
+            s->pfile_in_zip_read->stream.next_in += copy;
+            s->pfile_in_zip_read->stream.total_out += copy;
+
+            read += copy;
+        }
+        else if (s->pfile_in_zip_read->compression_method == Z_BZIP2ED)
+        {
+#ifdef HAVE_BZIP2
+            uint64_t total_out_before = 0;
+            uint64_t total_out_after = 0;
+            uint64_t out_bytes = 0;
+            const uint8_t *buf_before = NULL;
+
+            s->pfile_in_zip_read->bstream.next_in        = (char*)s->pfile_in_zip_read->stream.next_in;
+            s->pfile_in_zip_read->bstream.avail_in       = s->pfile_in_zip_read->stream.avail_in;
+            s->pfile_in_zip_read->bstream.total_in_lo32  = (uint32_t)s->pfile_in_zip_read->stream.total_in;
+            s->pfile_in_zip_read->bstream.total_in_hi32  = s->pfile_in_zip_read->stream.total_in >> 32;
+            
+            s->pfile_in_zip_read->bstream.next_out       = (char*)s->pfile_in_zip_read->stream.next_out;
+            s->pfile_in_zip_read->bstream.avail_out      = s->pfile_in_zip_read->stream.avail_out;
+            s->pfile_in_zip_read->bstream.total_out_lo32 = (uint32_t)s->pfile_in_zip_read->stream.total_out;
+            s->pfile_in_zip_read->bstream.total_out_hi32 = s->pfile_in_zip_read->stream.total_out >> 32;
+
+            total_out_before = s->pfile_in_zip_read->bstream.total_out_lo32 + 
+                (((uint32_t)s->pfile_in_zip_read->bstream.total_out_hi32) << 32);
+            buf_before = (const uint8_t*)s->pfile_in_zip_read->bstream.next_out;
+
+            err = BZ2_bzDecompress(&s->pfile_in_zip_read->bstream);
+
+            total_out_after = s->pfile_in_zip_read->bstream.total_out_lo32 + 
+                (((uint32_t)s->pfile_in_zip_read->bstream.total_out_hi32) << 32);
+
+            out_bytes = total_out_after - total_out_before;
+
+            s->pfile_in_zip_read->total_out_64 = s->pfile_in_zip_read->total_out_64 + out_bytes;
+            s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes;
+            s->pfile_in_zip_read->crc32 = crc32(s->pfile_in_zip_read->crc32, buf_before, (uint32_t)out_bytes);
+
+            read += (uint32_t)out_bytes;
+
+            s->pfile_in_zip_read->stream.next_in   = (uint8_t*)s->pfile_in_zip_read->bstream.next_in;
+            s->pfile_in_zip_read->stream.avail_in  = s->pfile_in_zip_read->bstream.avail_in;
+            s->pfile_in_zip_read->stream.total_in  = s->pfile_in_zip_read->bstream.total_in_lo32;
+            s->pfile_in_zip_read->stream.next_out  = (uint8_t*)s->pfile_in_zip_read->bstream.next_out;
+            s->pfile_in_zip_read->stream.avail_out = s->pfile_in_zip_read->bstream.avail_out;
+            s->pfile_in_zip_read->stream.total_out = s->pfile_in_zip_read->bstream.total_out_lo32;
+
+            if (err == BZ_STREAM_END)
+                return (read == 0) ? UNZ_EOF : read;
+            if (err != BZ_OK)
+                break;
+#endif
+        }
+#ifdef HAVE_APPLE_COMPRESSION
+        else
+        {
+            uint64_t total_out_before = 0;
+            uint64_t total_out_after = 0;
+            uint64_t out_bytes = 0;
+            const uint8_t *buf_before = NULL;
+
+            s->pfile_in_zip_read->astream.src_ptr = s->pfile_in_zip_read->stream.next_in;
+            s->pfile_in_zip_read->astream.src_size = s->pfile_in_zip_read->stream.avail_in;
+            s->pfile_in_zip_read->astream.dst_ptr = s->pfile_in_zip_read->stream.next_out;
+            s->pfile_in_zip_read->astream.dst_size = len;
+
+            total_out_before = s->pfile_in_zip_read->stream.total_out;
+            buf_before = s->pfile_in_zip_read->stream.next_out;
+
+            compression_status status;
+            compression_stream_flags flags;
+
+            if (s->pfile_in_zip_read->stream.avail_in == 0)
+            {
+                flags = COMPRESSION_STREAM_FINALIZE;
+            }
+
+            status = compression_stream_process(&s->pfile_in_zip_read->astream, flags);
+
+            total_out_after = len - s->pfile_in_zip_read->astream.dst_size;
+            out_bytes = total_out_after - total_out_before;
+
+            s->pfile_in_zip_read->total_out_64 += out_bytes;
+            s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes;
+            s->pfile_in_zip_read->crc32 =
+                crc32(s->pfile_in_zip_read->crc32, buf_before, (uint32_t)out_bytes);
+
+            read += (uint32_t)out_bytes;
+
+            s->pfile_in_zip_read->stream.next_in = s->pfile_in_zip_read->astream.src_ptr;
+            s->pfile_in_zip_read->stream.avail_in = s->pfile_in_zip_read->astream.src_size;
+            s->pfile_in_zip_read->stream.next_out = s->pfile_in_zip_read->astream.dst_ptr;
+            s->pfile_in_zip_read->stream.avail_out = s->pfile_in_zip_read->astream.dst_size;
+
+            if (status == COMPRESSION_STATUS_END)
+                return (read == 0) ? UNZ_EOF : read;
+            if (status == COMPRESSION_STATUS_ERROR)
+                return Z_DATA_ERROR;
+            return read;
+        }
+#else
+        else
+        {
+            uint64_t total_out_before = 0;
+            uint64_t total_out_after = 0;
+            uint64_t out_bytes = 0;
+            const uint8_t *buf_before = NULL;
+            int flush = Z_SYNC_FLUSH;
+
+            total_out_before = s->pfile_in_zip_read->stream.total_out;
+            buf_before = s->pfile_in_zip_read->stream.next_out;
+
+            /*
+            if ((pfile_in_zip_read_info->rest_read_uncompressed ==
+                     pfile_in_zip_read_info->stream.avail_out) &&
+                (pfile_in_zip_read_info->rest_read_compressed == 0))
+                flush = Z_FINISH;
+            */
+            err = inflate(&s->pfile_in_zip_read->stream, flush);
+
+            if ((err >= 0) && (s->pfile_in_zip_read->stream.msg != NULL))
+                err = Z_DATA_ERROR;
+
+            total_out_after = s->pfile_in_zip_read->stream.total_out;
+            out_bytes = total_out_after - total_out_before;
+
+            s->pfile_in_zip_read->total_out_64 += out_bytes;
+            s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes;
+            s->pfile_in_zip_read->crc32 =
+                (uint32_t)crc32(s->pfile_in_zip_read->crc32,buf_before, (uint32_t)out_bytes);
+
+            read += (uint32_t)out_bytes;
+
+            if (err == Z_STREAM_END)
+                return (read == 0) ? UNZ_EOF : read;
+            if (err != Z_OK)
+                break;
+        }
+#endif
+    }
+    while (s->pfile_in_zip_read->stream.avail_out > 0);
+
+    if (err == Z_OK)
+        return read;
+    return err;
+}
+
+extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, uint32_t len)
+{
+    unz64_internal *s = NULL;
+    uint64_t size_to_read = 0;
+    uint32_t read_now = 0;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (s->pfile_in_zip_read == NULL)
+        return UNZ_PARAMERROR;
+
+    size_to_read = s->pfile_in_zip_read->size_local_extrafield - s->pfile_in_zip_read->pos_local_extrafield;
+
+    if (buf == NULL)
+        return (int)size_to_read;
+
+    if (len > size_to_read)
+        read_now = (uint32_t)size_to_read;
+    else
+        read_now = len;
+
+    if (read_now == 0)
+        return 0;
+
+    if (ZSEEK64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream,
+        s->pfile_in_zip_read->offset_local_extrafield + s->pfile_in_zip_read->pos_local_extrafield,
+        ZLIB_FILEFUNC_SEEK_SET) != 0)
+        return UNZ_ERRNO;
+
+    if (ZREAD64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream, buf, read_now) != read_now)
+        return UNZ_ERRNO;
+
+    return (int)read_now;
+}
+
+extern int ZEXPORT unzCloseCurrentFile(unzFile file)
+{
+    unz64_internal *s = NULL;
+    file_in_zip64_read_info_s *pfile_in_zip_read_info = NULL;
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    pfile_in_zip_read_info = s->pfile_in_zip_read;
+    if (pfile_in_zip_read_info == NULL)
+        return UNZ_PARAMERROR;
+
+#ifdef HAVE_AES
+    if (s->cur_file_info.compression_method == AES_METHOD)
+    {
+        unsigned char authcode[AES_AUTHCODESIZE];
+        unsigned char rauthcode[AES_AUTHCODESIZE];
+
+        if (ZREAD64(s->z_filefunc, s->filestream, authcode, AES_AUTHCODESIZE) != AES_AUTHCODESIZE)
+            return UNZ_ERRNO;
+
+        if (fcrypt_end(rauthcode, &s->pfile_in_zip_read->aes_ctx) != AES_AUTHCODESIZE)
+            err = UNZ_CRCERROR;
+        if (memcmp(authcode, rauthcode, AES_AUTHCODESIZE) != 0)
+            err = UNZ_CRCERROR;
+    }
+    /* AES zip version AE-1 will expect a valid crc as well */
+    if ((s->cur_file_info.compression_method != AES_METHOD) ||
+        (s->cur_file_info_internal.aes_version == 0x0001))
+#endif
+    {
+        if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
+            (!pfile_in_zip_read_info->raw))
+        {
+            if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_expected)
+                err = UNZ_CRCERROR;
+        }
+    }
+
+    TRYFREE(pfile_in_zip_read_info->read_buffer);
+    pfile_in_zip_read_info->read_buffer = NULL;
+    if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
+    {
+#ifdef HAVE_APPLE_COMPRESSION
+        if (compression_stream_destroy)
+            compression_stream_destroy(&pfile_in_zip_read_info->astream);
+#else
+        inflateEnd(&pfile_in_zip_read_info->stream);
+#endif
+        
+    }
+#ifdef HAVE_BZIP2
+    else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED)
+        BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);
+#endif
+
+    pfile_in_zip_read_info->stream_initialised = 0;
+    TRYFREE(pfile_in_zip_read_info);
+
+    s->pfile_in_zip_read = NULL;
+
+    return err;
+}
+
+extern int ZEXPORT unzGoToFirstFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
+{
+    unz64_internal *s = NULL;
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    if (s->gi.number_entry == 0)
+        return UNZ_END_OF_LIST_OF_FILE;
+
+    s->pos_in_central_dir = s->offset_central_dir;
+    s->num_file = 0;
+
+    err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal,
+            filename, filename_size, extrafield, extrafield_size, comment,comment_size);
+
+    s->current_file_ok = (err == UNZ_OK);
+    if ((err == UNZ_OK) && (pfile_info != NULL))
+        memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64));
+
+    return err;
+}
+
+extern int ZEXPORT unzGoToFirstFile(unzFile file)
+{
+    return unzGoToFirstFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0);
+}
+
+extern int ZEXPORT unzGoToNextFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
+{
+    unz64_internal *s = NULL;
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    if (!s->current_file_ok)
+        return UNZ_END_OF_LIST_OF_FILE;
+    if (s->gi.number_entry != UINT16_MAX)    /* 2^16 files overflow hack */
+    {
+        if (s->num_file+1 == s->gi.number_entry)
+            return UNZ_END_OF_LIST_OF_FILE;
+    }
+
+    s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
+            s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment;
+    s->num_file += 1;
+
+    err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal,
+            filename, filename_size, extrafield,extrafield_size, comment, comment_size);
+
+    s->current_file_ok = (err == UNZ_OK);
+    if ((err == UNZ_OK) && (pfile_info != NULL))
+        memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64));
+
+    return err;
+}
+
+extern int ZEXPORT unzGoToNextFile(unzFile file)
+{
+    return unzGoToNextFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0);
+}
+
+extern int ZEXPORT unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func)
+{
+    unz64_internal *s = NULL;
+    unz_file_info64 cur_file_info_saved;
+    unz_file_info64_internal cur_file_info_internal_saved;
+    uint64_t num_file_saved = 0;
+    uint64_t pos_in_central_dir_saved = 0;
+    char current_filename[UNZ_MAXFILENAMEINZIP+1];
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    if (strlen(filename) >= UNZ_MAXFILENAMEINZIP)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (!s->current_file_ok)
+        return UNZ_END_OF_LIST_OF_FILE;
+
+    /* Save the current state */
+    num_file_saved = s->num_file;
+    pos_in_central_dir_saved = s->pos_in_central_dir;
+    cur_file_info_saved = s->cur_file_info;
+    cur_file_info_internal_saved = s->cur_file_info_internal;
+
+    err = unzGoToFirstFile2(file, NULL, current_filename, sizeof(current_filename)-1, NULL, 0, NULL, 0);
+
+    while (err == UNZ_OK)
+    {
+        if (filename_compare_func != NULL)
+            err = filename_compare_func(file, current_filename, filename);
+        else
+            err = strcmp(current_filename, filename);
+        if (err == 0)
+            return UNZ_OK;
+        err = unzGoToNextFile2(file, NULL, current_filename, sizeof(current_filename)-1, NULL, 0, NULL, 0);
+    }
+
+    /* We failed, so restore the state of the 'current file' to where we were. */
+    s->num_file = num_file_saved;
+    s->pos_in_central_dir = pos_in_central_dir_saved;
+    s->cur_file_info = cur_file_info_saved;
+    s->cur_file_info_internal = cur_file_info_internal_saved;
+    return err;
+}
+
+extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos *file_pos)
+{
+    unz64_file_pos file_pos64;
+    int err = unzGetFilePos64(file, &file_pos64);
+    if (err == UNZ_OK)
+    {
+        file_pos->pos_in_zip_directory = (uint32_t)file_pos64.pos_in_zip_directory;
+        file_pos->num_of_file = (uint32_t)file_pos64.num_of_file;
+    }
+    return err;
+}
+
+extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos *file_pos)
+{
+    unz64_file_pos file_pos64;
+    if (file_pos == NULL)
+        return UNZ_PARAMERROR;
+    file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;
+    file_pos64.num_of_file = file_pos->num_of_file;
+    return unzGoToFilePos64(file, &file_pos64);
+}
+
+extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos *file_pos)
+{
+    unz64_internal *s = NULL;
+
+    if (file == NULL || file_pos == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (!s->current_file_ok)
+        return UNZ_END_OF_LIST_OF_FILE;
+
+    file_pos->pos_in_zip_directory  = s->pos_in_central_dir;
+    file_pos->num_of_file = s->num_file;
+    return UNZ_OK;
+}
+
+extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos)
+{
+    unz64_internal *s = NULL;
+    int err = UNZ_OK;
+
+    if (file == NULL || file_pos == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    /* Jump to the right spot */
+    s->pos_in_central_dir = file_pos->pos_in_zip_directory;
+    s->num_file = file_pos->num_of_file;
+
+    /* Set the current file */
+    err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0);
+    /* Return results */
+    s->current_file_ok = (err == UNZ_OK);
+    return err;
+}
+
+extern int32_t ZEXPORT unzGetOffset(unzFile file)
+{
+    uint64_t offset64 = 0;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    offset64 = unzGetOffset64(file);
+    return (int32_t)offset64;
+}
+
+extern int64_t ZEXPORT unzGetOffset64(unzFile file)
+{
+    unz64_internal *s = NULL;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (!s->current_file_ok)
+        return 0;
+    if (s->gi.number_entry != 0 && s->gi.number_entry != UINT16_MAX)
+    {
+        if (s->num_file == s->gi.number_entry)
+            return 0;
+    }
+    return s->pos_in_central_dir;
+}
+
+extern int ZEXPORT unzSetOffset(unzFile file, uint32_t pos)
+{
+    return unzSetOffset64(file, pos);
+}
+
+extern int ZEXPORT unzSetOffset64(unzFile file, uint64_t pos)
+{
+    unz64_internal *s = NULL;
+    int err = UNZ_OK;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    s->pos_in_central_dir = pos;
+    s->num_file = s->gi.number_entry; /* hack */
+
+    err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0);
+
+    s->current_file_ok = (err == UNZ_OK);
+    return err;
+}
+
+extern int32_t ZEXPORT unzTell(unzFile file)
+{
+    unz64_internal *s = NULL;
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (s->pfile_in_zip_read == NULL)
+        return UNZ_PARAMERROR;
+    return (int32_t)s->pfile_in_zip_read->stream.total_out;
+}
+
+extern int64_t ZEXPORT unzTell64(unzFile file)
+{
+    unz64_internal *s = NULL;
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (s->pfile_in_zip_read == NULL)
+        return UNZ_PARAMERROR;
+    return s->pfile_in_zip_read->total_out_64;
+}
+
+extern int ZEXPORT unzSeek(unzFile file, uint32_t offset, int origin)
+{
+    return unzSeek64(file, offset, origin);
+}
+
+extern int ZEXPORT unzSeek64(unzFile file, uint64_t offset, int origin)
+{
+    unz64_internal *s = NULL;
+    uint64_t stream_pos_begin = 0;
+    uint64_t stream_pos_end = 0;
+    uint64_t position = 0;
+    int is_within_buffer = 0;
+
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+
+    if (s->pfile_in_zip_read == NULL)
+        return UNZ_ERRNO;
+    if (s->pfile_in_zip_read->compression_method != 0)
+        return UNZ_ERRNO;
+
+    if (origin == SEEK_SET)
+        position = offset;
+    else if (origin == SEEK_CUR)
+        position = s->pfile_in_zip_read->total_out_64 + offset;
+    else if (origin == SEEK_END)
+        position = s->cur_file_info.compressed_size + offset;
+    else
+        return UNZ_PARAMERROR;
+
+    if (position > s->cur_file_info.compressed_size)
+        return UNZ_PARAMERROR;
+
+    stream_pos_end = s->pfile_in_zip_read->pos_in_zipfile;
+    stream_pos_begin = stream_pos_end;
+
+    if (stream_pos_begin > UNZ_BUFSIZE)
+        stream_pos_begin -= UNZ_BUFSIZE;
+    else
+        stream_pos_begin = 0;
+
+    is_within_buffer = 
+        (s->pfile_in_zip_read->stream.avail_in != 0) &&
+        (s->pfile_in_zip_read->rest_read_compressed != 0 || s->cur_file_info.compressed_size < UNZ_BUFSIZE) &&
+        (position >= stream_pos_begin && position < stream_pos_end);
+
+    if (is_within_buffer)
+    {
+        s->pfile_in_zip_read->stream.next_in += position - s->pfile_in_zip_read->total_out_64;
+        s->pfile_in_zip_read->stream.avail_in = (uInt)(stream_pos_end - position);
+    }
+    else
+    {
+        s->pfile_in_zip_read->stream.avail_in = 0;
+        s->pfile_in_zip_read->stream.next_in = 0;
+
+        s->pfile_in_zip_read->pos_in_zipfile = s->pfile_in_zip_read->offset_local_extrafield + position;
+        s->pfile_in_zip_read->rest_read_compressed = s->cur_file_info.compressed_size - position;
+    }
+
+    s->pfile_in_zip_read->rest_read_uncompressed -= (position - s->pfile_in_zip_read->total_out_64);
+    s->pfile_in_zip_read->stream.total_out = (uint32_t)position;
+    s->pfile_in_zip_read->total_out_64 = position;
+
+    return UNZ_OK;
+}
+
+extern int ZEXPORT unzEndOfFile(unzFile file)
+{
+    unz64_internal *s = NULL;
+    if (file == NULL)
+        return UNZ_PARAMERROR;
+    s = (unz64_internal*)file;
+    if (s->pfile_in_zip_read == NULL)
+        return UNZ_PARAMERROR;
+    if (s->pfile_in_zip_read->rest_read_uncompressed == 0)
+        return 1;
+    return 0;
+}
diff --git a/krita/integration/3rdparty/unzip.h b/krita/integration/3rdparty/unzip.h
new file mode 100644
index 0000000000..8889333c84
--- /dev/null
+++ b/krita/integration/3rdparty/unzip.h
@@ -0,0 +1,308 @@
+/* unzip.h -- IO for uncompress .zip files using zlib
+   Version 1.2.0, September 16th, 2017
+   part of the MiniZip project
+
+   Copyright (C) 2012-2017 Nathan Moinvaziri
+     https://github.com/nmoinvaz/minizip
+   Copyright (C) 2009-2010 Mathias Svensson
+     Modifications for Zip64 support on both zip and unzip
+     http://result42.com
+   Copyright (C) 2007-2008 Even Rouault
+     Modifications of Unzip for Zip64
+   Copyright (C) 1998-2010 Gilles Vollant
+     http://www.winimage.com/zLibDll/minizip.html
+
+   This program is distributed under the terms of the same license as zlib.
+   See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef _UNZ_H
+#define _UNZ_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#ifndef _ZLIBIOAPI_H
+#include "ioapi.h"
+#endif
+
+#ifdef HAVE_BZIP2
+#include "bzlib.h"
+#endif
+
+#define Z_BZIP2ED 12
+
+#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+    from (void*) without cast */
+typedef struct TagunzFile__ { int unused; } unz_file__;
+typedef unz_file__ *unzFile;
+#else
+typedef voidp unzFile;
+#endif
+
+#define UNZ_OK                          (0)
+#define UNZ_END_OF_LIST_OF_FILE         (-100)
+#define UNZ_ERRNO                       (Z_ERRNO)
+#define UNZ_EOF                         (0)
+#define UNZ_PARAMERROR                  (-102)
+#define UNZ_BADZIPFILE                  (-103)
+#define UNZ_INTERNALERROR               (-104)
+#define UNZ_CRCERROR                    (-105)
+#define UNZ_BADPASSWORD                 (-106)
+
+/* unz_global_info structure contain global data about the ZIPfile
+   These data comes from the end of central dir */
+typedef struct unz_global_info64_s
+{
+    uint64_t number_entry;          /* total number of entries in the central dir on this disk */
+    uint32_t number_disk_with_CD;   /* number the the disk with central dir, used for spanning ZIP*/
+    uint16_t size_comment;          /* size of the global comment of the zipfile */
+} unz_global_info64;
+
+typedef struct unz_global_info_s
+{
+    uint32_t number_entry;          /* total number of entries in the central dir on this disk */
+    uint32_t number_disk_with_CD;   /* number the the disk with central dir, used for spanning ZIP*/
+    uint16_t size_comment;          /* size of the global comment of the zipfile */
+} unz_global_info;
+
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_info64_s
+{
+    uint16_t version;               /* version made by                 2 bytes */
+    uint16_t version_needed;        /* version needed to extract       2 bytes */
+    uint16_t flag;                  /* general purpose bit flag        2 bytes */
+    uint16_t compression_method;    /* compression method              2 bytes */
+    uint32_t dos_date;              /* last mod file date in Dos fmt   4 bytes */
+    uint32_t crc;                   /* crc-32                          4 bytes */
+    uint64_t compressed_size;       /* compressed size                 8 bytes */
+    uint64_t uncompressed_size;     /* uncompressed size               8 bytes */
+    uint16_t size_filename;         /* filename length                 2 bytes */
+    uint16_t size_file_extra;       /* extra field length              2 bytes */
+    uint16_t size_file_comment;     /* file comment length             2 bytes */
+
+    uint32_t disk_num_start;        /* disk number start               4 bytes */
+    uint16_t internal_fa;           /* internal file attributes        2 bytes */
+    uint32_t external_fa;           /* external file attributes        4 bytes */
+
+    uint64_t disk_offset;
+
+    uint16_t size_file_extra_internal;
+} unz_file_info64;
+
+typedef struct unz_file_info_s
+{
+    uint16_t version;               /* version made by                 2 bytes */
+    uint16_t version_needed;        /* version needed to extract       2 bytes */
+    uint16_t flag;                  /* general purpose bit flag        2 bytes */
+    uint16_t compression_method;    /* compression method              2 bytes */
+    uint32_t dos_date;              /* last mod file date in Dos fmt   4 bytes */
+    uint32_t crc;                   /* crc-32                          4 bytes */
+    uint32_t compressed_size;       /* compressed size                 4 bytes */
+    uint32_t uncompressed_size;     /* uncompressed size               4 bytes */
+    uint16_t size_filename;         /* filename length                 2 bytes */
+    uint16_t size_file_extra;       /* extra field length              2 bytes */
+    uint16_t size_file_comment;     /* file comment length             2 bytes */
+
+    uint16_t disk_num_start;        /* disk number start               2 bytes */
+    uint16_t internal_fa;           /* internal file attributes        2 bytes */
+    uint32_t external_fa;           /* external file attributes        4 bytes */
+
+    uint64_t disk_offset;
+} unz_file_info;
+
+/***************************************************************************/
+/* Opening and close a zip file */
+
+extern unzFile ZEXPORT unzOpen(const char *path);
+extern unzFile ZEXPORT unzOpen64(const void *path);
+/* Open a Zip file.
+
+   path should contain the full path (by example, on a Windows XP computer 
+      "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". 
+   return NULL if zipfile cannot be opened or doesn't exist
+   return unzFile handle if no error
+
+   NOTE: The "64" function take a const void *pointer, because  the path is just the value passed to the
+   open64_file_func callback. Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path 
+   is a pointer to a wide unicode string  (LPCTSTR is LPCWSTR), so const char *does not describe the reality */
+
+extern unzFile ZEXPORT unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc_def);
+/* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write operations */
+extern unzFile ZEXPORT unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def);
+/* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write 64-bit operations */
+
+extern int ZEXPORT unzClose(unzFile file);
+/* Close a ZipFile opened with unzOpen. If there is files inside the .Zip opened with unzOpenCurrentFile,
+   these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+
+   return UNZ_OK if there is no error */
+
+extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info);
+extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info);
+/* Write info about the ZipFile in the *pglobal_info structure.
+
+   return UNZ_OK if no error */
+
+extern int ZEXPORT unzGetGlobalComment(unzFile file, char *comment, uint16_t comment_size);
+/* Get the global comment string of the ZipFile, in the comment buffer.
+
+   uSizeBuf is the size of the szComment buffer.
+   return the number of byte copied or an error code <0 */
+
+/***************************************************************************/
+/* Reading the content of the current zipfile, you can open it, read data from it, and close it
+   (you can close it before reading all the file) */
+
+extern int ZEXPORT unzOpenCurrentFile(unzFile file);
+/* Open for reading data the current file in the zipfile.
+
+   return UNZ_OK if no error */
+
+extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char *password);
+/* Open for reading data the current file in the zipfile.
+   password is a crypting password
+
+   return UNZ_OK if no error */
+
+extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw);
+/* Same as unzOpenCurrentFile, but open for read raw the file (not uncompress)
+   if raw==1 *method will receive method of compression, *level will receive level of compression
+
+   NOTE: you can set level parameter as NULL (if you did not want known level,
+         but you CANNOT set method parameter as NULL */
+
+extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password);
+/* Same as unzOpenCurrentFile, but takes extra parameter password for encrypted files */
+
+extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, uint32_t len);
+/* Read bytes from the current file (opened by unzOpenCurrentFile)
+   buf contain buffer where data must be copied
+   len the size of buf.
+
+   return the number of byte copied if somes bytes are copied
+   return 0 if the end of file was reached
+   return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */
+
+extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename, 
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
+extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 *pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
+/* Get Info about the current file
+
+   pfile_info if != NULL, the *pfile_info structure will contain somes info about the current file
+   filename if != NULL, the file name string will be copied in filename 
+   filename_size is the size of the filename buffer
+   extrafield if != NULL, the extra field information from the central header will be copied in to
+   extrafield_size is the size of the extraField buffer 
+   comment if != NULL, the comment string of the file will be copied in to
+   comment_size is the size of the comment buffer */
+
+extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, uint32_t len);
+/* Read extra field from the current file (opened by unzOpenCurrentFile)
+   This is the local-header version of the extra field (sometimes, there is
+   more info in the local-header version than in the central-header)
+
+   if buf == NULL, it return the size of the local extra field
+   if buf != NULL, len is the size of the buffer, the extra header is copied in buf.
+
+   return number of bytes copied in buf, or (if <0) the error code */
+
+extern int ZEXPORT unzCloseCurrentFile(unzFile file);
+/* Close the file in zip opened with unzOpenCurrentFile
+
+   return UNZ_CRCERROR if all the file was read but the CRC is not good */
+
+/***************************************************************************/
+/* Browse the directory of the zipfile */
+
+typedef int (*unzFileNameComparer)(unzFile file, const char *filename1, const char *filename2);
+typedef int (*unzIteratorFunction)(unzFile file);
+typedef int (*unzIteratorFunction2)(unzFile file, unz_file_info64 *pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
+
+extern int ZEXPORT unzGoToFirstFile(unzFile file);
+/* Set the current file of the zipfile to the first file.
+
+   return UNZ_OK if no error */
+
+extern int ZEXPORT unzGoToFirstFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
+/* Set the current file of the zipfile to the first file and retrieves the current info on success. 
+   Not as seek intensive as unzGoToFirstFile + unzGetCurrentFileInfo.
+
+   return UNZ_OK if no error */
+
+extern int ZEXPORT unzGoToNextFile(unzFile file);
+/* Set the current file of the zipfile to the next file.
+
+   return UNZ_OK if no error
+   return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */
+
+extern int ZEXPORT unzGoToNextFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
+    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
+/* Set the current file of the zipfile to the next file and retrieves the current 
+   info on success. Does less seeking around than unzGotoNextFile + unzGetCurrentFileInfo.
+
+   return UNZ_OK if no error
+   return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */
+
+extern int ZEXPORT unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func);
+/* Try locate the file szFileName in the zipfile. For custom filename comparison pass in comparison function.
+
+   return UNZ_OK if the file is found (it becomes the current file)
+   return UNZ_END_OF_LIST_OF_FILE if the file is not found */
+
+/***************************************************************************/
+/* Raw access to zip file */
+
+typedef struct unz_file_pos_s
+{
+    uint32_t pos_in_zip_directory;  /* offset in zip file directory */
+    uint32_t num_of_file;           /* # of file */
+} unz_file_pos;
+
+extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos *file_pos);
+extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos *file_pos);
+
+typedef struct unz64_file_pos_s
+{
+    uint64_t pos_in_zip_directory;   /* offset in zip file directory */
+    uint64_t num_of_file;            /* # of file */
+} unz64_file_pos;
+
+extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos *file_pos);
+extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos);
+
+extern int32_t ZEXPORT unzGetOffset(unzFile file);
+extern int64_t ZEXPORT unzGetOffset64(unzFile file);
+/* Get the current file offset */
+
+extern int ZEXPORT unzSetOffset(unzFile file, uint32_t pos);
+extern int ZEXPORT unzSetOffset64(unzFile file, uint64_t pos);
+/* Set the current file offset */
+
+extern int32_t ZEXPORT unzTell(unzFile file);
+extern int64_t ZEXPORT unzTell64(unzFile file);
+/* return current position in uncompressed data */
+
+extern int ZEXPORT unzSeek(unzFile file, uint32_t offset, int origin);
+extern int ZEXPORT unzSeek64(unzFile file, uint64_t offset, int origin);
+/* Seek within the uncompressed data if compression method is storage */
+
+extern int ZEXPORT unzEndOfFile(unzFile file);
+/* return 1 if the end of file was reached, 0 elsewhere */
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UNZ_H */
diff --git a/krita/integration/CMakeLists.txt b/krita/integration/CMakeLists.txt
index 08e0409a38..0955e93fc4 100644
--- a/krita/integration/CMakeLists.txt
+++ b/krita/integration/CMakeLists.txt
@@ -1,3 +1,9 @@
-if (APPLE)
-    add_subdirectory(kritaquicklook)
-endif()
+project(kritaintegration)
+
+add_custom_target( kritaintegration ALL xcodebuild -project "${CMAKE_CURRENT_SOURCE_DIR}/integration.xcodeproj" -alltargets -configuration Release COMMENT build all macOS plugins )
+
+install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Build/Release/kritaquicklook.qlgenerator DESTINATION ${PLUGIN_INSTALL_DIR})
+
+install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Build/Release/kritaspotlight.mdimporter DESTINATION ${PLUGIN_INSTALL_DIR})
+
+install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Build/Release/kritaquicklookng.appex DESTINATION ${PLUGIN_INSTALL_DIR})
diff --git a/krita/integration/LICENSE b/krita/integration/LICENSE
deleted file mode 100644
index 2e6a0b73d4..0000000000
--- a/krita/integration/LICENSE
+++ /dev/null
@@ -1,340 +0,0 @@
-		    GNU GENERAL PUBLIC LICENSE
-		       Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-			    Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-		    GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-			    NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-		     END OF TERMS AND CONDITIONS
-
-	    How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) 19yy  <name of author>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program 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 General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) 19yy name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/krita/integration/README.md b/krita/integration/README.md
index e46f7fb4e3..888619bb14 100644
--- a/krita/integration/README.md
+++ b/krita/integration/README.md
@@ -1,9 +1,44 @@
-# Krita-QuickLook
-QuickLook Generator plugin for .kra and .ora files.
+# Krita's macOS integration
 
-This generator takes the preview.png image and uses it as the thumbnail image and the mergedimage.png file as the preview image. On files created with older versions of Krita that do not have the mergedimage.png file, QuickLook will simply fall back to using the thumbnail image instead.
+This Xcode project generates QuickLook (macOS < 10.15), QuickLook Thumbnailing
+(macOS 10.15+) and Spotlight plugins for .kra and .ora files.
+
+The QuickLook plugins take the `preview.png` image in the root of the ZIP
+container and use it as the thumbnail image, and the `mergedimage.png` file as
+the preview image. On files created with older versions of Krita that do not
+have `mergedimage.png`, QuickLook will simply fall back to using the thumbnail
+image instead.
+
+The Spotlight plugin extracts the following metadata from the kra file, if
+available:
+- image dimensions, DPI, bit depth, and color space
+- color space profile name (not the actual name, as it's not embedded in the container; only the file path)
+- layer names
+- authors, image title and description
 
 # Installing
-Place the generator in the `/Library/QuickLook` folder.
 
-If you package Krita 3.0, you can include the generator file in the directory `krita.app/Contents/Library/QuickLook`. Be sure to reset QuickLook with `qlmanage -r` and `qlmanage -r cache`. If the changes don't happen right away, `killall Finder` and ensure that the app you put the generator in is the default app for opening .kra files.
+Compile the project using Xcode or the provided CMake file. Find the build
+output folder (depends on how you configured the project), and place:
+- `kritaquicklook.qlgenerator` inside `~/Library/QuickLook`
+- `kritaspotlight.mdimporter` inside `~/Library/Spotlight`.
+
+You can also place them in the system folders (`/Library/QuickLook` and
+`/Library/Spotlight` respectively). Test that they have been properly installed
+with:
+- QuickLook: `qlmanage -d2 -p <path to a kra file>; qlmanage -d2 -t <path to a kra file>`
+- Spotlight: `mdimport -d2 -t <path to a kra file>`
+
+Be sure to reset QuickLook with `qlmanage -r` and `qlmanage -r cache`. If the
+changes don't happen right away, `killall Finder`.
+
+**NOTE:** `kritaquicklookng.appex` **cannot be used standalone. You must bundle it with Krita (see below).**
+
+# Bundling
+
+If you package Krita, place:
+- `kritaquicklook.qlgenerator` inside `krita.app/Contents/Library/QuickLook`
+- `kritaspotlight.mdimporter` inside `krita.app/Contents/Library/Spotlight`
+- `kritaquicklookng.appex` inside `krita.app/Contents/Library/PlugIns`
+Ensure the app is defined as the default app for opening .kra and .ora files,
+and codesign it whole if necessary.
diff --git a/krita/integration/integration.xcodeproj/project.pbxproj b/krita/integration/integration.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..2103b6e2bc
--- /dev/null
+++ b/krita/integration/integration.xcodeproj/project.pbxproj
@@ -0,0 +1,780 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 50;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		84B7B62925619404003662DB /* QuickLookThumbnailing.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84B7B62825619404003662DB /* QuickLookThumbnailing.framework */; };
+		84B7B62B25619404003662DB /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84B7B62A25619404003662DB /* Quartz.framework */; };
+		84B7B62E25619404003662DB /* ThumbnailProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B7B62D25619404003662DB /* ThumbnailProvider.swift */; };
+		84B7B63425619534003662DB /* libunziptask.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D505D725608693005AFC55 /* libunziptask.a */; };
+		84D505DB256086B4005AFC55 /* UnzipTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D6513A256043A000CC2E75 /* UnzipTask.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		84D505DC256086B4005AFC55 /* ioapi.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D5059D256056BF005AFC55 /* ioapi.h */; };
+		84D505DD256086B4005AFC55 /* unzip.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D505962560520B005AFC55 /* unzip.h */; };
+		84D505DE256086C1005AFC55 /* UnzipTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D65139256043A000CC2E75 /* UnzipTask.m */; };
+		84D505DF256086C1005AFC55 /* ioapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 84D5059C256056BF005AFC55 /* ioapi.c */; };
+		84D505E0256086C1005AFC55 /* unzip.c in Sources */ = {isa = PBXBuildFile; fileRef = 84D505972560520B005AFC55 /* unzip.c */; };
+		84D505E2256086CA005AFC55 /* libunziptask.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D505D725608693005AFC55 /* libunziptask.a */; };
+		84D505E5256086D0005AFC55 /* libunziptask.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D505D725608693005AFC55 /* libunziptask.a */; };
+		84D6510E2560370B00CC2E75 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 84D6510D2560370B00CC2E75 /* main.c */; };
+		84D6511B2560371600CC2E75 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 84D6511A2560371600CC2E75 /* main.c */; };
+		84D6511D2560371600CC2E75 /* GetMetadataForFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D6511C2560371600CC2E75 /* GetMetadataForFile.m */; };
+		84D6513025603A1E00CC2E75 /* GenerateThumbnailForURL.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D6512E25603A1E00CC2E75 /* GenerateThumbnailForURL.m */; };
+		84D6513125603A1E00CC2E75 /* GeneratePreviewForURL.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D6512F25603A1E00CC2E75 /* GeneratePreviewForURL.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+		84B7B63525619534003662DB /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 84D650F0256036F000CC2E75 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 84D505D625608693005AFC55;
+			remoteInfo = unziptask;
+		};
+		84D505E3256086CA005AFC55 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 84D650F0256036F000CC2E75 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 84D505D625608693005AFC55;
+			remoteInfo = unziptask;
+		};
+		84D505E6256086D0005AFC55 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 84D650F0256036F000CC2E75 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 84D505D625608693005AFC55;
+			remoteInfo = unziptask;
+		};
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		84D505B4256072AD005AFC55 /* Embed Libraries */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 10;
+			files = (
+			);
+			name = "Embed Libraries";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		84D505B925607381005AFC55 /* Embed Libraries */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 10;
+			files = (
+			);
+			name = "Embed Libraries";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		84A059912560A72500E4EAFD /* libbz2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libbz2.tbd; path = usr/lib/libbz2.tbd; sourceTree = SDKROOT; };
+		84A059942560A75000E4EAFD /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
+		84A059962560A7D100E4EAFD /* libbz2.1.0.5.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libbz2.1.0.5.tbd; path = usr/lib/libbz2.1.0.5.tbd; sourceTree = SDKROOT; };
+		84B7B62725619404003662DB /* kritaquicklookng.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = kritaquicklookng.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+		84B7B62825619404003662DB /* QuickLookThumbnailing.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLookThumbnailing.framework; path = System/Library/Frameworks/QuickLookThumbnailing.framework; sourceTree = SDKROOT; };
+		84B7B62A25619404003662DB /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = System/Library/Frameworks/Quartz.framework; sourceTree = SDKROOT; };
+		84B7B62D25619404003662DB /* ThumbnailProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbnailProvider.swift; sourceTree = "<group>"; };
+		84B7B62F25619404003662DB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		84B7B63025619404003662DB /* quicklookng.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = quicklookng.entitlements; sourceTree = "<group>"; };
+		84B7B63E256197D9003662DB /* quicklookng-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "quicklookng-Bridging-Header.h"; sourceTree = "<group>"; };
+		84D505962560520B005AFC55 /* unzip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unzip.h; sourceTree = "<group>"; };
+		84D505972560520B005AFC55 /* unzip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = unzip.c; sourceTree = "<group>"; };
+		84D5059C256056BF005AFC55 /* ioapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ioapi.c; sourceTree = "<group>"; };
+		84D5059D256056BF005AFC55 /* ioapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ioapi.h; sourceTree = "<group>"; };
+		84D505D725608693005AFC55 /* libunziptask.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libunziptask.a; sourceTree = BUILT_PRODUCTS_DIR; };
+		84D651072560370B00CC2E75 /* kritaquicklook.qlgenerator */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = kritaquicklook.qlgenerator; sourceTree = BUILT_PRODUCTS_DIR; };
+		84D6510D2560370B00CC2E75 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+		84D6510F2560370B00CC2E75 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		84D651172560371600CC2E75 /* kritaspotlight.mdimporter */ = {isa = PBXFileReference; explicitFileType = "wrapper.spotlight-importer"; includeInIndex = 0; path = kritaspotlight.mdimporter; sourceTree = BUILT_PRODUCTS_DIR; };
+		84D6511A2560371600CC2E75 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = main.c; path = ../main.c; sourceTree = "<group>"; };
+		84D6511C2560371600CC2E75 /* GetMetadataForFile.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GetMetadataForFile.m; sourceTree = "<group>"; };
+		84D651222560371600CC2E75 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		84D6512E25603A1E00CC2E75 /* GenerateThumbnailForURL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GenerateThumbnailForURL.m; sourceTree = "<group>"; };
+		84D6512F25603A1E00CC2E75 /* GeneratePreviewForURL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratePreviewForURL.m; sourceTree = "<group>"; };
+		84D65139256043A000CC2E75 /* UnzipTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UnzipTask.m; sourceTree = "<group>"; };
+		84D6513A256043A000CC2E75 /* UnzipTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnzipTask.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		84B7B62425619404003662DB /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				84B7B62925619404003662DB /* QuickLookThumbnailing.framework in Frameworks */,
+				84B7B63425619534003662DB /* libunziptask.a in Frameworks */,
+				84B7B62B25619404003662DB /* Quartz.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		84D505D525608693005AFC55 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		84D651032560370B00CC2E75 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				84D505E5256086D0005AFC55 /* libunziptask.a in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		84D651142560371600CC2E75 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				84D505E2256086CA005AFC55 /* libunziptask.a in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		84A059902560A72500E4EAFD /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				84A059962560A7D100E4EAFD /* libbz2.1.0.5.tbd */,
+				84A059942560A75000E4EAFD /* libz.tbd */,
+				84A059912560A72500E4EAFD /* libbz2.tbd */,
+				84B7B62825619404003662DB /* QuickLookThumbnailing.framework */,
+				84B7B62A25619404003662DB /* Quartz.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		84B7B62C25619404003662DB /* quicklookng */ = {
+			isa = PBXGroup;
+			children = (
+				84B7B62D25619404003662DB /* ThumbnailProvider.swift */,
+				84B7B62F25619404003662DB /* Info.plist */,
+				84B7B63025619404003662DB /* quicklookng.entitlements */,
+				84B7B63E256197D9003662DB /* quicklookng-Bridging-Header.h */,
+			);
+			path = quicklookng;
+			sourceTree = "<group>";
+		};
+		84D505AC2560726A005AFC55 /* unzipTask */ = {
+			isa = PBXGroup;
+			children = (
+				84D6513A256043A000CC2E75 /* UnzipTask.h */,
+				84D65139256043A000CC2E75 /* UnzipTask.m */,
+			);
+			path = unzipTask;
+			sourceTree = "<group>";
+		};
+		84D650EF256036F000CC2E75 = {
+			isa = PBXGroup;
+			children = (
+				84D505AC2560726A005AFC55 /* unzipTask */,
+				84D6512A2560379A00CC2E75 /* 3rdparty */,
+				84D651082560370B00CC2E75 /* quicklook */,
+				84D651182560371600CC2E75 /* spotlight */,
+				84B7B62C25619404003662DB /* quicklookng */,
+				84D650F9256036F000CC2E75 /* Products */,
+				84A059902560A72500E4EAFD /* Frameworks */,
+			);
+			sourceTree = "<group>";
+		};
+		84D650F9256036F000CC2E75 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				84D651072560370B00CC2E75 /* kritaquicklook.qlgenerator */,
+				84D651172560371600CC2E75 /* kritaspotlight.mdimporter */,
+				84D505D725608693005AFC55 /* libunziptask.a */,
+				84B7B62725619404003662DB /* kritaquicklookng.appex */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		84D651082560370B00CC2E75 /* quicklook */ = {
+			isa = PBXGroup;
+			children = (
+				84D6512F25603A1E00CC2E75 /* GeneratePreviewForURL.m */,
+				84D6512E25603A1E00CC2E75 /* GenerateThumbnailForURL.m */,
+				84D6510F2560370B00CC2E75 /* Info.plist */,
+				84D6513F256043CC00CC2E75 /* Supporting Files */,
+			);
+			path = quicklook;
+			sourceTree = "<group>";
+		};
+		84D651182560371600CC2E75 /* spotlight */ = {
+			isa = PBXGroup;
+			children = (
+				84D6511C2560371600CC2E75 /* GetMetadataForFile.m */,
+				84D651222560371600CC2E75 /* Info.plist */,
+				84D651192560371600CC2E75 /* Supporting Files */,
+			);
+			path = spotlight;
+			sourceTree = "<group>";
+		};
+		84D651192560371600CC2E75 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				84D6511A2560371600CC2E75 /* main.c */,
+			);
+			path = "Supporting Files";
+			sourceTree = "<group>";
+		};
+		84D6512A2560379A00CC2E75 /* 3rdparty */ = {
+			isa = PBXGroup;
+			children = (
+				84D5059C256056BF005AFC55 /* ioapi.c */,
+				84D5059D256056BF005AFC55 /* ioapi.h */,
+				84D505972560520B005AFC55 /* unzip.c */,
+				84D505962560520B005AFC55 /* unzip.h */,
+			);
+			path = 3rdparty;
+			sourceTree = "<group>";
+		};
+		84D6513F256043CC00CC2E75 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				84D6510D2560370B00CC2E75 /* main.c */,
+			);
+			name = "Supporting Files";
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+		84D505D325608693005AFC55 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				84D505DB256086B4005AFC55 /* UnzipTask.h in Headers */,
+				84D505DD256086B4005AFC55 /* unzip.h in Headers */,
+				84D505DC256086B4005AFC55 /* ioapi.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		84D651042560370B00CC2E75 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		84D6512B256037CE00CC2E75 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+		84B7B62625619404003662DB /* kritaquicklookng */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 84B7B63325619404003662DB /* Build configuration list for PBXNativeTarget "kritaquicklookng" */;
+			buildPhases = (
+				84B7B62325619404003662DB /* Sources */,
+				84B7B62425619404003662DB /* Frameworks */,
+				84B7B62525619404003662DB /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				84B7B63625619534003662DB /* PBXTargetDependency */,
+			);
+			name = kritaquicklookng;
+			productName = quicklookng;
+			productReference = 84B7B62725619404003662DB /* kritaquicklookng.appex */;
+			productType = "com.apple.product-type.app-extension";
+		};
+		84D505D625608693005AFC55 /* unziptask */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 84D505D825608693005AFC55 /* Build configuration list for PBXNativeTarget "unziptask" */;
+			buildPhases = (
+				84D505D325608693005AFC55 /* Headers */,
+				84D505D425608693005AFC55 /* Sources */,
+				84D505D525608693005AFC55 /* Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = unziptask;
+			productName = unziptask;
+			productReference = 84D505D725608693005AFC55 /* libunziptask.a */;
+			productType = "com.apple.product-type.library.static";
+		};
+		84D651062560370B00CC2E75 /* kritaquicklook */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 84D651102560370B00CC2E75 /* Build configuration list for PBXNativeTarget "kritaquicklook" */;
+			buildPhases = (
+				84D651042560370B00CC2E75 /* Headers */,
+				84D651022560370B00CC2E75 /* Sources */,
+				84D651032560370B00CC2E75 /* Frameworks */,
+				84D651052560370B00CC2E75 /* Resources */,
+				84D505B925607381005AFC55 /* Embed Libraries */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				84D505E7256086D0005AFC55 /* PBXTargetDependency */,
+			);
+			name = kritaquicklook;
+			productName = quicklook;
+			productReference = 84D651072560370B00CC2E75 /* kritaquicklook.qlgenerator */;
+			productType = "com.apple.product-type.bundle";
+		};
+		84D651162560371600CC2E75 /* kritaspotlight */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 84D651232560371600CC2E75 /* Build configuration list for PBXNativeTarget "kritaspotlight" */;
+			buildPhases = (
+				84D6512B256037CE00CC2E75 /* Headers */,
+				84D651132560371600CC2E75 /* Sources */,
+				84D651142560371600CC2E75 /* Frameworks */,
+				84D651152560371600CC2E75 /* Resources */,
+				84D505B4256072AD005AFC55 /* Embed Libraries */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				84D505E4256086CA005AFC55 /* PBXTargetDependency */,
+			);
+			name = kritaspotlight;
+			productName = spotlight;
+			productReference = 84D651172560371600CC2E75 /* kritaspotlight.mdimporter */;
+			productType = "com.apple.product-type.spotlight-importer";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		84D650F0256036F000CC2E75 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastSwiftUpdateCheck = 1130;
+				LastUpgradeCheck = 1130;
+				ORGANIZATIONNAME = "Stichting Krita Foundation";
+				TargetAttributes = {
+					84B7B62625619404003662DB = {
+						CreatedOnToolsVersion = 11.3.1;
+						LastSwiftMigration = 1130;
+					};
+					84D505D625608693005AFC55 = {
+						CreatedOnToolsVersion = 11.3.1;
+					};
+					84D651062560370B00CC2E75 = {
+						CreatedOnToolsVersion = 11.3.1;
+					};
+					84D651162560371600CC2E75 = {
+						CreatedOnToolsVersion = 11.3.1;
+					};
+				};
+			};
+			buildConfigurationList = 84D650F3256036F000CC2E75 /* Build configuration list for PBXProject "integration" */;
+			compatibilityVersion = "Xcode 9.3";
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = 84D650EF256036F000CC2E75;
+			productRefGroup = 84D650F9256036F000CC2E75 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				84D651062560370B00CC2E75 /* kritaquicklook */,
+				84D651162560371600CC2E75 /* kritaspotlight */,
+				84D505D625608693005AFC55 /* unziptask */,
+				84B7B62625619404003662DB /* kritaquicklookng */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		84B7B62525619404003662DB /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		84D651052560370B00CC2E75 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		84D651152560371600CC2E75 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		84B7B62325619404003662DB /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				84B7B62E25619404003662DB /* ThumbnailProvider.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		84D505D425608693005AFC55 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				84D505DE256086C1005AFC55 /* UnzipTask.m in Sources */,
+				84D505DF256086C1005AFC55 /* ioapi.c in Sources */,
+				84D505E0256086C1005AFC55 /* unzip.c in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		84D651022560370B00CC2E75 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				84D6513025603A1E00CC2E75 /* GenerateThumbnailForURL.m in Sources */,
+				84D6513125603A1E00CC2E75 /* GeneratePreviewForURL.m in Sources */,
+				84D6510E2560370B00CC2E75 /* main.c in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		84D651132560371600CC2E75 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				84D6511D2560371600CC2E75 /* GetMetadataForFile.m in Sources */,
+				84D6511B2560371600CC2E75 /* main.c in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+		84B7B63625619534003662DB /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 84D505D625608693005AFC55 /* unziptask */;
+			targetProxy = 84B7B63525619534003662DB /* PBXContainerItemProxy */;
+		};
+		84D505E4256086CA005AFC55 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 84D505D625608693005AFC55 /* unziptask */;
+			targetProxy = 84D505E3256086CA005AFC55 /* PBXContainerItemProxy */;
+		};
+		84D505E7256086D0005AFC55 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 84D505D625608693005AFC55 /* unziptask */;
+			targetProxy = 84D505E6256086D0005AFC55 /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+		84B7B63125619404003662DB /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_ENABLE_MODULES = YES;
+				CODE_SIGN_ENTITLEMENTS = quicklookng/quicklookng.entitlements;
+				CODE_SIGN_STYLE = Automatic;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				INFOPLIST_FILE = quicklookng/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/../Frameworks",
+					"@executable_path/../../../../Frameworks",
+				);
+				MACOSX_DEPLOYMENT_TARGET = 10.15;
+				MARKETING_VERSION = 4.4.0;
+				PRODUCT_BUNDLE_IDENTIFIER = org.krita.quicklookng;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_OBJC_BRIDGING_HEADER = "quicklookng/quicklookng-Bridging-Header.h";
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 5.0;
+			};
+			name = Debug;
+		};
+		84B7B63225619404003662DB /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_ENABLE_MODULES = YES;
+				CODE_SIGN_ENTITLEMENTS = quicklookng/quicklookng.entitlements;
+				CODE_SIGN_STYLE = Automatic;
+				INFOPLIST_FILE = quicklookng/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/../Frameworks",
+					"@executable_path/../../../../Frameworks",
+				);
+				MACOSX_DEPLOYMENT_TARGET = 10.15;
+				MARKETING_VERSION = 4.4.0;
+				PRODUCT_BUNDLE_IDENTIFIER = org.krita.quicklookng;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_COMPILATION_MODE = wholemodule;
+				SWIFT_OBJC_BRIDGING_HEADER = "quicklookng/quicklookng-Bridging-Header.h";
+				SWIFT_OPTIMIZATION_LEVEL = "-O";
+				SWIFT_VERSION = 5.0;
+			};
+			name = Release;
+		};
+		84D505D925608693005AFC55 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				EXECUTABLE_PREFIX = lib;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+			};
+			name = Debug;
+		};
+		84D505DA25608693005AFC55 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				EXECUTABLE_PREFIX = lib;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+			};
+			name = Release;
+		};
+		84D650FD256036F000CC2E75 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					HAVE_APPLE_COMPRESSION,
+					NOUNCRYPT,
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.13;
+				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+				MTL_FAST_MATH = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx;
+			};
+			name = Debug;
+		};
+		84D650FE256036F000CC2E75 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					HAVE_APPLE_COMPRESSION,
+					NOUNCRYPT,
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.13;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				MTL_FAST_MATH = YES;
+				SDKROOT = macosx;
+			};
+			name = Release;
+		};
+		84D651112560370B00CC2E75 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				INFOPLIST_FILE = quicklook/Info.plist;
+				INSTALL_PATH = /Library/QuickLook;
+				MARKETING_VERSION = 4.4.0;
+				PRODUCT_BUNDLE_IDENTIFIER = org.krita.quicklook;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				WRAPPER_EXTENSION = qlgenerator;
+			};
+			name = Debug;
+		};
+		84D651122560370B00CC2E75 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				INFOPLIST_FILE = quicklook/Info.plist;
+				INSTALL_PATH = /Library/QuickLook;
+				MARKETING_VERSION = 4.4.0;
+				PRODUCT_BUNDLE_IDENTIFIER = org.krita.quicklook;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				WRAPPER_EXTENSION = qlgenerator;
+			};
+			name = Release;
+		};
+		84D651242560371600CC2E75 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = YES;
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				INFOPLIST_FILE = spotlight/Info.plist;
+				INSTALL_PATH = /Library/Spotlight;
+				LIBRARY_STYLE = BUNDLE;
+				MARKETING_VERSION = 4.4.0;
+				PRODUCT_BUNDLE_IDENTIFIER = org.krita.spotlight;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				WRAPPER_EXTENSION = mdimporter;
+			};
+			name = Debug;
+		};
+		84D651252560371600CC2E75 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = YES;
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				INFOPLIST_FILE = spotlight/Info.plist;
+				INSTALL_PATH = /Library/Spotlight;
+				LIBRARY_STYLE = BUNDLE;
+				MARKETING_VERSION = 4.4.0;
+				PRODUCT_BUNDLE_IDENTIFIER = org.krita.spotlight;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				WRAPPER_EXTENSION = mdimporter;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		84B7B63325619404003662DB /* Build configuration list for PBXNativeTarget "kritaquicklookng" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				84B7B63125619404003662DB /* Debug */,
+				84B7B63225619404003662DB /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		84D505D825608693005AFC55 /* Build configuration list for PBXNativeTarget "unziptask" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				84D505D925608693005AFC55 /* Debug */,
+				84D505DA25608693005AFC55 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		84D650F3256036F000CC2E75 /* Build configuration list for PBXProject "integration" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				84D650FD256036F000CC2E75 /* Debug */,
+				84D650FE256036F000CC2E75 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		84D651102560370B00CC2E75 /* Build configuration list for PBXNativeTarget "kritaquicklook" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				84D651112560370B00CC2E75 /* Debug */,
+				84D651122560370B00CC2E75 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		84D651232560371600CC2E75 /* Build configuration list for PBXNativeTarget "kritaspotlight" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				84D651242560371600CC2E75 /* Debug */,
+				84D651252560371600CC2E75 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 84D650F0256036F000CC2E75 /* Project object */;
+}
diff --git a/krita/integration/kritaquicklook.xcodeproj/xcuserdata/alvina.xcuserdatad/xcschemes/kritaquicklook.xcscheme b/krita/integration/integration.xcodeproj/xcshareddata/xcschemes/kritaquicklook.xcscheme
similarity index 69%
rename from krita/integration/kritaquicklook.xcodeproj/xcuserdata/alvina.xcuserdatad/xcschemes/kritaquicklook.xcscheme
rename to krita/integration/integration.xcodeproj/xcshareddata/xcschemes/kritaquicklook.xcscheme
index 3fecd44f03..18763b8492 100644
--- a/krita/integration/kritaquicklook.xcodeproj/xcuserdata/alvina.xcuserdatad/xcschemes/kritaquicklook.xcscheme
+++ b/krita/integration/integration.xcodeproj/xcshareddata/xcschemes/kritaquicklook.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "0620"
+   LastUpgradeVersion = "1130"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"
@@ -14,56 +14,46 @@
             buildForAnalyzing = "YES">
             <BuildableReference
                BuildableIdentifier = "primary"
-               BlueprintIdentifier = "E13E64EA1C08579B0062F932"
+               BlueprintIdentifier = "84D651062560370B00CC2E75"
                BuildableName = "kritaquicklook.qlgenerator"
                BlueprintName = "kritaquicklook"
-               ReferencedContainer = "container:kritaquicklook.xcodeproj">
+               ReferencedContainer = "container:integration.xcodeproj">
             </BuildableReference>
          </BuildActionEntry>
       </BuildActionEntries>
    </BuildAction>
    <TestAction
+      buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      buildConfiguration = "Debug">
+      shouldUseLaunchSchemeArgsEnv = "YES">
       <Testables>
       </Testables>
    </TestAction>
    <LaunchAction
+      buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       launchStyle = "0"
       useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Release"
       ignoresPersistentStateOnLaunch = "NO"
       debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
       allowLocationSimulation = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "E13E64EA1C08579B0062F932"
-            BuildableName = "kritaquicklook.qlgenerator"
-            BlueprintName = "kritaquicklook"
-            ReferencedContainer = "container:kritaquicklook.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
    </LaunchAction>
    <ProfileAction
+      buildConfiguration = "Release"
       shouldUseLaunchSchemeArgsEnv = "YES"
       savedToolIdentifier = ""
       useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Release"
       debugDocumentVersioning = "YES">
       <MacroExpansion>
          <BuildableReference
             BuildableIdentifier = "primary"
-            BlueprintIdentifier = "E13E64EA1C08579B0062F932"
+            BlueprintIdentifier = "84D651062560370B00CC2E75"
             BuildableName = "kritaquicklook.qlgenerator"
             BlueprintName = "kritaquicklook"
-            ReferencedContainer = "container:kritaquicklook.xcodeproj">
+            ReferencedContainer = "container:integration.xcodeproj">
          </BuildableReference>
       </MacroExpansion>
    </ProfileAction>
diff --git a/krita/integration/kritaquicklook.xcodeproj/project.pbxproj b/krita/integration/kritaquicklook.xcodeproj/project.pbxproj
deleted file mode 100644
index ff141194b9..0000000000
--- a/krita/integration/kritaquicklook.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,301 +0,0 @@
-// !$*UTF8*$!
-{
-	archiveVersion = 1;
-	classes = {
-	};
-	objectVersion = 46;
-	objects = {
-
-/* Begin PBXBuildFile section */
-		E13E64F11C08579B0062F932 /* GenerateThumbnailForURL.m in Sources */ = {isa = PBXBuildFile; fileRef = E13E64F01C08579B0062F932 /* GenerateThumbnailForURL.m */; };
-		E13E64F31C08579B0062F932 /* GeneratePreviewForURL.m in Sources */ = {isa = PBXBuildFile; fileRef = E13E64F21C08579B0062F932 /* GeneratePreviewForURL.m */; };
-		E13E64F51C08579B0062F932 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = E13E64F41C08579B0062F932 /* main.c */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXFileReference section */
-		E13E64EB1C08579B0062F932 /* Krita.qlgenerator */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Krita.qlgenerator; sourceTree = BUILT_PRODUCTS_DIR; };
-		E13E64EF1C08579B0062F932 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		E13E64F01C08579B0062F932 /* GenerateThumbnailForURL.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GenerateThumbnailForURL.m; sourceTree = "<group>"; };
-		E13E64F21C08579B0062F932 /* GeneratePreviewForURL.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GeneratePreviewForURL.m; sourceTree = "<group>"; };
-		E13E64F41C08579B0062F932 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
-		E13E64E71C08579B0062F932 /* Frameworks */ = {
-			isa = PBXFrameworksBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
-		E13E64E11C08579B0062F932 = {
-			isa = PBXGroup;
-			children = (
-				E13E64ED1C08579B0062F932 /* kritaquicklook */,
-				E13E64EC1C08579B0062F932 /* Products */,
-			);
-			sourceTree = "<group>";
-		};
-		E13E64EC1C08579B0062F932 /* Products */ = {
-			isa = PBXGroup;
-			children = (
-				E13E64EB1C08579B0062F932 /* Krita.qlgenerator */,
-			);
-			name = Products;
-			sourceTree = "<group>";
-		};
-		E13E64ED1C08579B0062F932 /* kritaquicklook */ = {
-			isa = PBXGroup;
-			children = (
-				E13E64F01C08579B0062F932 /* GenerateThumbnailForURL.m */,
-				E13E64F21C08579B0062F932 /* GeneratePreviewForURL.m */,
-				E13E64F41C08579B0062F932 /* main.c */,
-				E13E64EE1C08579B0062F932 /* Supporting Files */,
-			);
-			path = kritaquicklook;
-			sourceTree = "<group>";
-		};
-		E13E64EE1C08579B0062F932 /* Supporting Files */ = {
-			isa = PBXGroup;
-			children = (
-				E13E64EF1C08579B0062F932 /* Info.plist */,
-			);
-			name = "Supporting Files";
-			sourceTree = "<group>";
-		};
-/* End PBXGroup section */
-
-/* Begin PBXHeadersBuildPhase section */
-		E13E64E81C08579B0062F932 /* Headers */ = {
-			isa = PBXHeadersBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXHeadersBuildPhase section */
-
-/* Begin PBXNativeTarget section */
-		E13E64EA1C08579B0062F932 /* kritaquicklook */ = {
-			isa = PBXNativeTarget;
-			buildConfigurationList = E13E64F81C08579B0062F932 /* Build configuration list for PBXNativeTarget "kritaquicklook" */;
-			buildPhases = (
-				E13E64E61C08579B0062F932 /* Sources */,
-				E13E64E71C08579B0062F932 /* Frameworks */,
-				E13E64E81C08579B0062F932 /* Headers */,
-				E13E64E91C08579B0062F932 /* Resources */,
-			);
-			buildRules = (
-			);
-			dependencies = (
-			);
-			name = kritaquicklook;
-			productName = Krita;
-			productReference = E13E64EB1C08579B0062F932 /* Krita.qlgenerator */;
-			productType = "com.apple.product-type.bundle";
-		};
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
-		E13E64E21C08579B0062F932 /* Project object */ = {
-			isa = PBXProject;
-			attributes = {
-				LastUpgradeCheck = 0620;
-				ORGANIZATIONNAME = "Krita Foundation";
-				TargetAttributes = {
-					E13E64EA1C08579B0062F932 = {
-						CreatedOnToolsVersion = 6.2;
-					};
-				};
-			};
-			buildConfigurationList = E13E64E51C08579B0062F932 /* Build configuration list for PBXProject "kritaquicklook" */;
-			compatibilityVersion = "Xcode 3.2";
-			developmentRegion = English;
-			hasScannedForEncodings = 0;
-			knownRegions = (
-				en,
-			);
-			mainGroup = E13E64E11C08579B0062F932;
-			productRefGroup = E13E64EC1C08579B0062F932 /* Products */;
-			projectDirPath = "";
-			projectRoot = "";
-			targets = (
-				E13E64EA1C08579B0062F932 /* kritaquicklook */,
-			);
-		};
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
-		E13E64E91C08579B0062F932 /* Resources */ = {
-			isa = PBXResourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
-		E13E64E61C08579B0062F932 /* Sources */ = {
-			isa = PBXSourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				E13E64F11C08579B0062F932 /* GenerateThumbnailForURL.m in Sources */,
-				E13E64F31C08579B0062F932 /* GeneratePreviewForURL.m in Sources */,
-				E13E64F51C08579B0062F932 /* main.c in Sources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
-		E13E64F61C08579B0062F932 /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
-				CLANG_ENABLE_OBJC_ARC = YES;
-				CLANG_WARN_BOOL_CONVERSION = YES;
-				CLANG_WARN_CONSTANT_CONVERSION = YES;
-				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-				CLANG_WARN_EMPTY_BODY = YES;
-				CLANG_WARN_ENUM_CONVERSION = YES;
-				CLANG_WARN_INT_CONVERSION = YES;
-				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_UNREACHABLE_CODE = YES;
-				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				COPY_PHASE_STRIP = NO;
-				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
-				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_OPTIMIZATION_LEVEL = 0;
-				GCC_PREPROCESSOR_DEFINITIONS = (
-					"DEBUG=1",
-					"$(inherited)",
-				);
-				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
-				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-				GCC_WARN_UNDECLARED_SELECTOR = YES;
-				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				MACOSX_DEPLOYMENT_TARGET = 10.9;
-				MTL_ENABLE_DEBUG_INFO = YES;
-				ONLY_ACTIVE_ARCH = YES;
-				SDKROOT = macosx;
-			};
-			name = Debug;
-		};
-		E13E64F71C08579B0062F932 /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
-				CLANG_ENABLE_OBJC_ARC = YES;
-				CLANG_WARN_BOOL_CONVERSION = YES;
-				CLANG_WARN_CONSTANT_CONVERSION = YES;
-				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-				CLANG_WARN_EMPTY_BODY = YES;
-				CLANG_WARN_ENUM_CONVERSION = YES;
-				CLANG_WARN_INT_CONVERSION = YES;
-				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_UNREACHABLE_CODE = YES;
-				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				COPY_PHASE_STRIP = NO;
-				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-				ENABLE_NS_ASSERTIONS = NO;
-				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
-				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-				GCC_WARN_UNDECLARED_SELECTOR = YES;
-				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				MACOSX_DEPLOYMENT_TARGET = 10.9;
-				MTL_ENABLE_DEBUG_INFO = NO;
-				SDKROOT = macosx;
-			};
-			name = Release;
-		};
-		E13E64F91C08579B0062F932 /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = YES;
-				CLANG_ENABLE_OBJC_ARC = NO;
-				COMBINE_HIDPI_IMAGES = YES;
-				FRAMEWORK_SEARCH_PATHS = (
-					"$(inherited)",
-					/Users/alvina/kf5/QuickLook/ZipFramework,
-					"/Users/alvina/kf5/QuickLook/ZipFramework-src",
-				);
-				INFOPLIST_FILE = kritaquicklook/Info.plist;
-				INSTALL_PATH = /Library/QuickLook;
-				LIBRARY_SEARCH_PATHS = (
-					"$(inherited)",
-					/Users/alvina/kf5/QuickLook/ZipArchive,
-				);
-				PRODUCT_NAME = "$(TARGET_NAME)";
-				USER_HEADER_SEARCH_PATHS = "";
-				"USER_HEADER_SEARCH_PATHS[arch=*]" = "/Users/alvina/kf5/QuickLook/ZipFramework-src/**";
-				WRAPPER_EXTENSION = qlgenerator;
-			};
-			name = Debug;
-		};
-		E13E64FA1C08579B0062F932 /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = YES;
-				CLANG_ENABLE_OBJC_ARC = NO;
-				COMBINE_HIDPI_IMAGES = YES;
-				FRAMEWORK_SEARCH_PATHS = (
-					"$(inherited)",
-					/Users/alvina/kf5/QuickLook/ZipFramework,
-					"/Users/alvina/kf5/QuickLook/ZipFramework-src",
-				);
-				INFOPLIST_FILE = kritaquicklook/Info.plist;
-				INSTALL_PATH = /Library/QuickLook;
-				LIBRARY_SEARCH_PATHS = (
-					"$(inherited)",
-					/Users/alvina/kf5/QuickLook/ZipArchive,
-				);
-				PRODUCT_NAME = "$(TARGET_NAME)";
-				USER_HEADER_SEARCH_PATHS = "";
-				"USER_HEADER_SEARCH_PATHS[arch=*]" = "/Users/alvina/kf5/QuickLook/ZipFramework-src/**";
-				WRAPPER_EXTENSION = qlgenerator;
-			};
-			name = Release;
-		};
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
-		E13E64E51C08579B0062F932 /* Build configuration list for PBXProject "kritaquicklook" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				E13E64F61C08579B0062F932 /* Debug */,
-				E13E64F71C08579B0062F932 /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-		E13E64F81C08579B0062F932 /* Build configuration list for PBXNativeTarget "kritaquicklook" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				E13E64F91C08579B0062F932 /* Debug */,
-				E13E64FA1C08579B0062F932 /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-/* End XCConfigurationList section */
-	};
-	rootObject = E13E64E21C08579B0062F932 /* Project object */;
-}
diff --git a/krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/contents.xcworkspacedata
deleted file mode 100644
index 5c7d033f10..0000000000
--- a/krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
-   version = "1.0">
-   <FileRef
-      location = "self:kritaquicklook.xcodeproj">
-   </FileRef>
-</Workspace>
diff --git a/krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/xcshareddata/Krita.xccheckout b/krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/xcshareddata/Krita.xccheckout
deleted file mode 100644
index 7671f592ed..0000000000
--- a/krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/xcshareddata/Krita.xccheckout
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>IDESourceControlProjectFavoriteDictionaryKey</key>
-	<false/>
-	<key>IDESourceControlProjectIdentifier</key>
-	<string>E3E24D36-805E-4EB4-AB6F-CCF8DE1EC9DF</string>
-	<key>IDESourceControlProjectName</key>
-	<string>Krita</string>
-	<key>IDESourceControlProjectOriginsDictionary</key>
-	<dict>
-		<key>A5B8AD5391A8194BF497FF65F2909CBC9A9EB430</key>
-		<string>https://github.com/Algorithmus/Krita-QuickLook</string>
-	</dict>
-	<key>IDESourceControlProjectPath</key>
-	<string>Krita.xcodeproj</string>
-	<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
-	<dict>
-		<key>A5B8AD5391A8194BF497FF65F2909CBC9A9EB430</key>
-		<string>../..</string>
-	</dict>
-	<key>IDESourceControlProjectURL</key>
-	<string>https://github.com/Algorithmus/Krita-QuickLook</string>
-	<key>IDESourceControlProjectVersion</key>
-	<integer>111</integer>
-	<key>IDESourceControlProjectWCCIdentifier</key>
-	<string>A5B8AD5391A8194BF497FF65F2909CBC9A9EB430</string>
-	<key>IDESourceControlProjectWCConfigurations</key>
-	<array>
-		<dict>
-			<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
-			<string>public.vcs.git</string>
-			<key>IDESourceControlWCCIdentifierKey</key>
-			<string>A5B8AD5391A8194BF497FF65F2909CBC9A9EB430</string>
-			<key>IDESourceControlWCCName</key>
-			<string>Krita</string>
-		</dict>
-	</array>
-</dict>
-</plist>
diff --git a/krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/xcshareddata/kritaquicklook.xccheckout b/krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/xcshareddata/kritaquicklook.xccheckout
deleted file mode 100644
index 6bd583d3b2..0000000000
--- a/krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/xcshareddata/kritaquicklook.xccheckout
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>IDESourceControlProjectFavoriteDictionaryKey</key>
-	<false/>
-	<key>IDESourceControlProjectIdentifier</key>
-	<string>28DD4631-F598-46F8-A5D9-6D5A4C867DCB</string>
-	<key>IDESourceControlProjectName</key>
-	<string>kritaquicklook</string>
-	<key>IDESourceControlProjectOriginsDictionary</key>
-	<dict>
-		<key>A5B8AD5391A8194BF497FF65F2909CBC9A9EB430</key>
-		<string>https://github.com/algorithmus/krita-quicklook.git</string>
-	</dict>
-	<key>IDESourceControlProjectPath</key>
-	<string>kritaquicklook.xcodeproj</string>
-	<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
-	<dict>
-		<key>A5B8AD5391A8194BF497FF65F2909CBC9A9EB430</key>
-		<string>../..</string>
-	</dict>
-	<key>IDESourceControlProjectURL</key>
-	<string>https://github.com/algorithmus/krita-quicklook.git</string>
-	<key>IDESourceControlProjectVersion</key>
-	<integer>111</integer>
-	<key>IDESourceControlProjectWCCIdentifier</key>
-	<string>A5B8AD5391A8194BF497FF65F2909CBC9A9EB430</string>
-	<key>IDESourceControlProjectWCConfigurations</key>
-	<array>
-		<dict>
-			<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
-			<string>public.vcs.git</string>
-			<key>IDESourceControlWCCIdentifierKey</key>
-			<string>A5B8AD5391A8194BF497FF65F2909CBC9A9EB430</string>
-			<key>IDESourceControlWCCName</key>
-			<string>krita-quicklook</string>
-		</dict>
-	</array>
-</dict>
-</plist>
diff --git a/krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/xcuserdata/alvina.xcuserdatad/UserInterfaceState.xcuserstate b/krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/xcuserdata/alvina.xcuserdatad/UserInterfaceState.xcuserstate
deleted file mode 100644
index 547f3f97a6..0000000000
Binary files a/krita/integration/kritaquicklook.xcodeproj/project.xcworkspace/xcuserdata/alvina.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ
diff --git a/krita/integration/kritaquicklook.xcodeproj/xcuserdata/alvina.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/krita/integration/kritaquicklook.xcodeproj/xcuserdata/alvina.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
deleted file mode 100644
index c5b338eae9..0000000000
--- a/krita/integration/kritaquicklook.xcodeproj/xcuserdata/alvina.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Bucket
-   type = "1"
-   version = "2.0">
-   <Breakpoints>
-      <BreakpointProxy
-         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
-         <BreakpointContent
-            shouldBeEnabled = "Yes"
-            ignoreCount = "0"
-            continueAfterRunningActions = "No"
-            filePath = "../ZipArchive/ZipArchive.h"
-            timestampString = "470320688.718299"
-            startingColumnNumber = "9223372036854775807"
-            endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "85"
-            endingLineNumber = "85"
-            landmarkName = "@interface ZipArchive"
-            landmarkType = "2">
-         </BreakpointContent>
-      </BreakpointProxy>
-   </Breakpoints>
-</Bucket>
diff --git a/krita/integration/kritaquicklook.xcodeproj/xcuserdata/alvina.xcuserdatad/xcschemes/xcschememanagement.plist b/krita/integration/kritaquicklook.xcodeproj/xcuserdata/alvina.xcuserdatad/xcschemes/xcschememanagement.plist
deleted file mode 100644
index 780c7c48d2..0000000000
--- a/krita/integration/kritaquicklook.xcodeproj/xcuserdata/alvina.xcuserdatad/xcschemes/xcschememanagement.plist
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>SchemeUserState</key>
-	<dict>
-		<key>Krita.xcscheme</key>
-		<dict>
-			<key>orderHint</key>
-			<integer>0</integer>
-		</dict>
-		<key>kritaquicklook.xcscheme</key>
-		<dict>
-			<key>orderHint</key>
-			<integer>0</integer>
-		</dict>
-	</dict>
-	<key>SuppressBuildableAutocreation</key>
-	<dict>
-		<key>E13E64EA1C08579B0062F932</key>
-		<dict>
-			<key>primary</key>
-			<true/>
-		</dict>
-	</dict>
-</dict>
-</plist>
diff --git a/krita/integration/kritaquicklook/CMakeLists.txt b/krita/integration/kritaquicklook/CMakeLists.txt
deleted file mode 100644
index 97c6c2b848..0000000000
--- a/krita/integration/kritaquicklook/CMakeLists.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-project(kritaquicklook)
-
-add_custom_target( kritaquicklook ALL xcodebuild -project "${CMAKE_CURRENT_SOURCE_DIR}/../kritaquicklook.xcodeproj" -target kritaquicklook -configuration Release COMMENT build kra qlgenerator )
-
-install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/Release/kritaquicklook.qlgenerator DESTINATION ${PLUGIN_INSTALL_DIR})
-
diff --git a/krita/integration/kritaquicklook/GeneratePreviewForURL.m b/krita/integration/kritaquicklook/GeneratePreviewForURL.m
deleted file mode 100644
index 8489bbf7f7..0000000000
--- a/krita/integration/kritaquicklook/GeneratePreviewForURL.m
+++ /dev/null
@@ -1,70 +0,0 @@
-#import <Cocoa/Cocoa.h>
-#include <CoreFoundation/CoreFoundation.h>
-#include <CoreServices/CoreServices.h>
-#include <QuickLook/QuickLook.h>
-
-OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options);
-void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview);
-
-/* -----------------------------------------------------------------------------
-   Generate a preview for file
-
-   This function's job is to create preview for designated file
-   ----------------------------------------------------------------------------- */
-
-OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options)
-{
-    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-    
-    NSURL *URL = (__bridge NSURL *)url;
-    
-    NSData *appPlist = nil;
-    
-    NSImage *appIcon = nil;
-    NSPipe *errorPipe = [NSPipe pipe];
-    
-    NSTask *unzipTask = [[NSTask alloc] init];
-    [unzipTask setLaunchPath:@"/usr/bin/unzip"];
-    [unzipTask setStandardOutput:[NSPipe pipe]];
-    [unzipTask setStandardError:errorPipe];
-    [unzipTask setArguments:@[@"-p", [URL path], @"mergedimage.png"]];
-    [unzipTask launch];
-    //[unzipTask waitUntilExit];
-    
-    appPlist = [[[unzipTask standardOutput] fileHandleForReading] readDataToEndOfFile];
-    
-    if (QLPreviewRequestIsCancelled(preview)) {
-        [pool release];
-        return noErr;
-    }
-    
-    if (appPlist != nil || appPlist.length) {
-    
-        appIcon = [[NSImage alloc] initWithData:appPlist];
-
-        NSImageRep *rep = [[appIcon representations] objectAtIndex:0];
-        
-        NSSize canvasSize = NSMakeSize(rep.pixelsWide, rep.pixelsHigh);
-        NSRect renderRect = NSMakeRect(0.0, 0.0, rep.pixelsWide, rep.pixelsHigh);
-        
-        CGContextRef _context = QLPreviewRequestCreateContext(preview, canvasSize, true, NULL);
-        
-        if (_context) {
-            NSGraphicsContext* _graphicsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:_context flipped:NO];
-            
-            [NSGraphicsContext setCurrentContext:_graphicsContext];
-            [appIcon drawInRect:renderRect];
-            
-            QLPreviewRequestFlushContext(preview, _context);
-            CFRelease(_context);
-        }
-    }
-    
-    [pool release];
-    return noErr;
-}
-
-void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview)
-{
-    // Implement only if supported
-}
diff --git a/krita/integration/kritaquicklook/GenerateThumbnailForURL.m b/krita/integration/kritaquicklook/GenerateThumbnailForURL.m
deleted file mode 100644
index a999353704..0000000000
--- a/krita/integration/kritaquicklook/GenerateThumbnailForURL.m
+++ /dev/null
@@ -1,92 +0,0 @@
-#import <Cocoa/Cocoa.h>
-#include <CoreFoundation/CoreFoundation.h>
-#include <CoreServices/CoreServices.h>
-#include <QuickLook/QuickLook.h>
-
-void UnzipTask(NSURL *path, NSString *target, NSData **output, NSData **error);
-OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize);
-void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbnail);
-
-/* -----------------------------------------------------------------------------
-    Generate a thumbnail for file
-
-   This function's job is to create thumbnail for designated file as fast as possible
-   ----------------------------------------------------------------------------- */
-
-// Run unzip and try to obtain the target file in the archive
-void UnzipTask(NSURL *path, NSString *target, NSData **output, NSData **error) {
-    NSPipe *errorPipe = [NSPipe pipe];
-    NSTask *unzipTask = [NSTask new];
-    [unzipTask setLaunchPath:@"/usr/bin/unzip"];
-    [unzipTask setStandardOutput:[NSPipe pipe]];
-    [unzipTask setStandardError:errorPipe];
-    [unzipTask setArguments:@[@"-p", [path path], target]];
-    [unzipTask launch];
-    //[unzipTask waitUntilExit];
-    
-    *output = [[[unzipTask standardOutput] fileHandleForReading] readDataToEndOfFile];
-    *error = [[[unzipTask standardError] fileHandleForReading] readDataToEndOfFile];
-}
-
-OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize)
-{
-    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-    
-    // Allows you to print the name of the extension on top of the thumbnail preview. Uncomment and change NULL to properties in QLThumbnailRequestSetImage down below to use it.
-    /*
-    // Get the UTI properties
-    NSDictionary* uti_declarations = ( NSDictionary*)UTTypeCopyDeclaration(contentTypeUTI);
-    
-    // Get the extensions corresponding to the image UTI, for some UTI there can be more than 1 extension (ex image.jpeg = jpeg, jpg...)
-    // If it fails for whatever reason fallback to the filename extension
-    id extensions = uti_declarations[(__bridge NSString*)kUTTypeTagSpecificationKey][(__bridge NSString*)kUTTagClassFilenameExtension];
-    NSString* extension = ([extensions isKindOfClass:[NSArray class]]) ? extensions[0] : extensions;
-    if (nil == extension)
-        extension = ([(__bridge NSURL*)url pathExtension] != nil) ? [(__bridge NSURL*)url pathExtension] : @"";
-    extension = [extension lowercaseString];
-    
-    // Create the properties dic
-    CFTypeRef keys[1] = {kQLThumbnailPropertyExtensionKey};
-    CFTypeRef values[1] = {(__bridge CFStringRef)extension};
-    CFDictionaryRef properties = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-    */
-     
-    NSURL *URL = (__bridge NSURL *)url;
-    NSData *appPlist = nil;
-    NSData *error = nil;
-    
-    NSImage *appIcon = nil;
-    
-    UnzipTask(URL, @"preview.png", &appPlist, &error);
-    
-    // Not made with Krita. Find ORA thumbnail instead.
-    if (error.length > 0) {
-        UnzipTask(URL, @"Thumbnails/thumbnail.png", &appPlist, &error);
-    }
-    
-    if (QLThumbnailRequestIsCancelled(thumbnail)) {
-        [pool release];
-        return noErr;
-    }
-    
-    if (appPlist != nil || appPlist.length) {
-    
-        appIcon = [[NSImage alloc] initWithData:appPlist];
-        
-        NSImageRep *rep = [[appIcon representations] objectAtIndex:0];
-        
-        NSRect renderRect = NSMakeRect(0.0, 0.0, rep.pixelsWide, rep.pixelsHigh);
-        
-        CGImageRef cgImage = [appIcon CGImageForProposedRect:&renderRect context:NULL hints:nil];
-        
-        QLThumbnailRequestSetImage(thumbnail, cgImage, NULL);
-        CGImageRelease(cgImage);
-    }
-    [pool release];
-    return noErr;
-}
-
-void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbnail)
-{
-    // Implement only if supported
-}
diff --git a/krita/integration/kritaquicklook/Info.plist b/krita/integration/kritaquicklook/Info.plist
deleted file mode 100644
index 4cf9a380aa..0000000000
--- a/krita/integration/kritaquicklook/Info.plist
+++ /dev/null
@@ -1,159 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>en</string>
-	<key>CFBundleDocumentTypes</key>
-	<array>
-		<dict>
-			<key>CFBundleTypeRole</key>
-			<string>QLGenerator</string>
-			<key>LSItemContentTypes</key>
-			<array>
-				<string>dyn.ah62d4rv4ge8006xb</string>
-                <string>org.krita.kra</string>
-                <string>org.krita.ora</string>
-			</array>
-		</dict>
-	</array>
-    <key>UTExportedTypeDeclarations</key>
-    <array>
-        <dict>
-            <key>UTTypeIdentifier</key>
-            <string>dyn.ah62d4rv4ge8006xb</string>
-            <key>UTTypeDescription</key>
-            <string>Krita 3.0 Image</string>
-            <key>UTTypeConformsTo</key>
-            <array>
-                <string>public.image</string>
-            </array>
-            <key>UTTypeTagSpecification</key>
-            <dict>
-                <key>public.filename-extension</key>
-                <array>
-                    <string>kra</string>
-                    <string>KRA</string>
-                </array>
-                <key>public.mime-type</key>
-                <array>
-                    <string>application/x-krita</string>
-                </array>
-            </dict>
-        </dict>
-        <dict>
-            <key>UTTypeIdentifier</key>
-            <string>dyn.ah62d4rv4ge8006xb</string>
-            <key>UTTypeDescription</key>
-            <string>Open Raster Image</string>
-            <key>UTTypeConformsTo</key>
-            <array>
-                <string>public.image</string>
-            </array>
-            <key>UTTypeTagSpecification</key>
-            <dict>
-                <key>public.filename-extension</key>
-                <array>
-                    <string>ora</string>
-                    <string>ORA</string>
-                </array>
-                <key>public.mime-type</key>
-                <array>
-                    <string>image/openraster</string>
-                </array>
-            </dict>
-        </dict>
-    </array>
-    <key>UTImportedTypeDeclarations</key>
-    <array>
-        <dict>
-            <key>UTTypeConformsTo</key>
-            <array>
-                <string>public.image</string>
-            </array>
-            <key>UTTypeDescription</key>
-            <string>Krita 3.0 Image</string>
-            <key>UTTypeIdentifier</key>
-            <string>org.krita.kra</string>
-            <key>UTTypeTagSpecification</key>
-            <dict>
-                <key>public.filename-extension</key>
-                <array>
-                    <string>kra</string>
-                    <string>KRA</string>
-                </array>
-                <key>public.mime-type</key>
-                <array>
-                    <string>application/x-krita</string>
-                </array>
-            </dict>
-        </dict>
-        <dict>
-            <key>UTTypeConformsTo</key>
-            <array>
-                <string>public.image</string>
-            </array>
-            <key>UTTypeDescription</key>
-            <string>Open Raster Image</string>
-            <key>UTTypeIdentifier</key>
-            <string>org.krita.ora</string>
-            <key>UTTypeTagSpecification</key>
-            <dict>
-                <key>public.filename-extension</key>
-                <array>
-                    <string>ora</string>
-                    <string>ORA</string>
-                </array>
-                <key>public.mime-type</key>
-                <array>
-                    <string>image/openraster</string>
-                </array>
-            </dict>
-        </dict>
-    </array>
-	<key>CFBundleExecutable</key>
-	<string>$(EXECUTABLE_NAME)</string>
-	<key>CFBundleIdentifier</key>
-	<string>org.$(PRODUCT_NAME:rfc1034identifier)</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>$(PRODUCT_NAME)</string>
-	<key>CFBundleShortVersionString</key>
-	<string>1.0</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
-	<key>CFBundleVersion</key>
-	<string>1</string>
-	<key>CFPlugInDynamicRegisterFunction</key>
-	<string></string>
-	<key>CFPlugInDynamicRegistration</key>
-	<string>NO</string>
-	<key>CFPlugInFactories</key>
-	<dict>
-		<key>292DC9CD-1640-49AE-B0C1-308ED88E6677</key>
-		<string>QuickLookGeneratorPluginFactory</string>
-	</dict>
-	<key>CFPlugInTypes</key>
-	<dict>
-		<key>5E2D9680-5022-40FA-B806-43349622E5B9</key>
-		<array>
-			<string>292DC9CD-1640-49AE-B0C1-308ED88E6677</string>
-		</array>
-	</dict>
-	<key>CFPlugInUnloadFunction</key>
-	<string></string>
-	<key>NSHumanReadableCopyright</key>
-	<string>Copyright © 2015 Krita Foundation. All rights reserved.</string>
-	<key>QLNeedsToBeRunInMainThread</key>
-	<false/>
-	<key>QLPreviewHeight</key>
-	<real>600</real>
-	<key>QLPreviewWidth</key>
-	<real>800</real>
-	<key>QLSupportsConcurrentRequests</key>
-	<false/>
-	<key>QLThumbnailMinimumSize</key>
-	<real>17</real>
-</dict>
-</plist>
diff --git a/krita/integration/kritaquicklook/LICENSE b/krita/integration/kritaquicklook/LICENSE
deleted file mode 100644
index 2e6a0b73d4..0000000000
--- a/krita/integration/kritaquicklook/LICENSE
+++ /dev/null
@@ -1,340 +0,0 @@
-		    GNU GENERAL PUBLIC LICENSE
-		       Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-			    Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-		    GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-			    NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-		     END OF TERMS AND CONDITIONS
-
-	    How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) 19yy  <name of author>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program 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 General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) 19yy name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/krita/integration/kritaquicklook/README.md b/krita/integration/kritaquicklook/README.md
deleted file mode 100644
index e46f7fb4e3..0000000000
--- a/krita/integration/kritaquicklook/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# Krita-QuickLook
-QuickLook Generator plugin for .kra and .ora files.
-
-This generator takes the preview.png image and uses it as the thumbnail image and the mergedimage.png file as the preview image. On files created with older versions of Krita that do not have the mergedimage.png file, QuickLook will simply fall back to using the thumbnail image instead.
-
-# Installing
-Place the generator in the `/Library/QuickLook` folder.
-
-If you package Krita 3.0, you can include the generator file in the directory `krita.app/Contents/Library/QuickLook`. Be sure to reset QuickLook with `qlmanage -r` and `qlmanage -r cache`. If the changes don't happen right away, `killall Finder` and ensure that the app you put the generator in is the default app for opening .kra files.
diff --git a/krita/integration/quicklook/GeneratePreviewForURL.m b/krita/integration/quicklook/GeneratePreviewForURL.m
new file mode 100644
index 0000000000..5deb73ae32
--- /dev/null
+++ b/krita/integration/quicklook/GeneratePreviewForURL.m
@@ -0,0 +1,85 @@
+/*
+ * This file is part of Krita
+ *
+ * Copyright (c) 2015 Algorithmus <angelus.tenebrae at gmail.com>
+ * Copyright (c) 2015 beelzy <alvina.lee at innoactive.de>
+ * Copyright (c) 2020 L. E. Segovia <amy at amyspark.me>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include "UnzipTask.h"
+#import <Cocoa/Cocoa.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
+#include <QuickLook/QuickLook.h>
+
+OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview,
+                               CFURLRef url, CFStringRef contentTypeUTI,
+                               CFDictionaryRef options);
+void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview);
+
+/* -----------------------------------------------------------------------------
+   Generate a preview for file
+
+   This function's job is to create preview for designated file
+   -----------------------------------------------------------------------------
+ */
+
+OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview,
+                               CFURLRef url, CFStringRef contentTypeUTI,
+                               CFDictionaryRef options) {
+  @autoreleasepool {
+    NSData *appPlist =
+        UnzipTask([(__bridge NSURL *)url path], @"mergedImage.png");
+
+    if (QLPreviewRequestIsCancelled(preview)) {
+      return noErr;
+    }
+
+    if ([appPlist length]) {
+      NSImage *appIcon = [[NSImage alloc] initWithData:appPlist];
+
+      NSImageRep *rep = [[appIcon representations] objectAtIndex:0];
+
+      NSSize canvasSize = NSMakeSize(rep.pixelsWide, rep.pixelsHigh);
+      NSRect renderRect = NSMakeRect(0.0, 0.0, rep.pixelsWide, rep.pixelsHigh);
+
+      CGContextRef _context =
+          QLPreviewRequestCreateContext(preview, canvasSize, true, NULL);
+
+      if (_context) {
+        NSGraphicsContext *_graphicsContext =
+            [NSGraphicsContext graphicsContextWithGraphicsPort:_context
+                                                       flipped:NO];
+
+        [NSGraphicsContext setCurrentContext:_graphicsContext];
+        [appIcon drawInRect:renderRect];
+
+        QLPreviewRequestFlushContext(preview, _context);
+        CFRelease(_context);
+      }
+
+      return noErr;
+    }
+
+    return NSFileNoSuchFileError;
+  }
+}
+
+void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview) {
+  // Implement only if supported
+}
diff --git a/krita/integration/quicklook/GenerateThumbnailForURL.m b/krita/integration/quicklook/GenerateThumbnailForURL.m
new file mode 100644
index 0000000000..abfa5e9abd
--- /dev/null
+++ b/krita/integration/quicklook/GenerateThumbnailForURL.m
@@ -0,0 +1,112 @@
+/*
+ * This file is part of Krita
+ *
+ * Copyright (c) 2015 Algorithmus <angelus.tenebrae at gmail.com>
+ * Copyright (c) 2015 beelzy <alvina.lee at innoactive.de>
+ * Copyright (c) 2020 L. E. Segovia <amy at amyspark.me>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include "UnzipTask.h"
+#import <Cocoa/Cocoa.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
+#include <QuickLook/QuickLook.h>
+
+OSStatus GenerateThumbnailForURL(void *thisInterface,
+                                 QLThumbnailRequestRef thumbnail, CFURLRef url,
+                                 CFStringRef contentTypeUTI,
+                                 CFDictionaryRef options, CGSize maxSize);
+void CancelThumbnailGeneration(void *thisInterface,
+                               QLThumbnailRequestRef thumbnail);
+
+/* -----------------------------------------------------------------------------
+    Generate a thumbnail for file
+
+   This function's job is to create thumbnail for designated file as fast as
+   possible
+   -----------------------------------------------------------------------------
+ */
+
+OSStatus GenerateThumbnailForURL(void *thisInterface,
+                                 QLThumbnailRequestRef thumbnail, CFURLRef url,
+                                 CFStringRef contentTypeUTI,
+                                 CFDictionaryRef options, CGSize maxSize) {
+  @autoreleasepool {
+    // Allows you to print the name of the extension on top of the thumbnail
+    // preview. Uncomment and change NULL to properties in
+    // QLThumbnailRequestSetImage down below to use it.
+    /*
+     // Get the UTI properties
+     NSDictionary* uti_declarations = (
+     NSDictionary*)UTTypeCopyDeclaration(contentTypeUTI);
+
+     // Get the extensions corresponding to the image UTI, for some UTI there
+     can be more than 1 extension (ex image.jpeg = jpeg, jpg...)
+     // If it fails for whatever reason fallback to the filename extension
+     id extensions = uti_declarations[(__bridge
+     NSString*)kUTTypeTagSpecificationKey][(__bridge
+     NSString*)kUTTagClassFilenameExtension]; NSString* extension = ([extensions
+     isKindOfClass:[NSArray class]]) ? extensions[0] : extensions; if (nil ==
+     extension) extension = ([(__bridge NSURL*)url pathExtension] != nil) ?
+     [(__bridge NSURL*)url pathExtension] : @""; extension = [extension
+     lowercaseString];
+
+     // Create the properties dic
+     CFTypeRef keys[1] = {kQLThumbnailPropertyExtensionKey};
+     CFTypeRef values[1] = {(__bridge CFStringRef)extension};
+     CFDictionaryRef properties = CFDictionaryCreate(kCFAllocatorDefault, (const
+     void**)keys, (const void**)values, 1, &kCFTypeDictionaryKeyCallBacks,
+     &kCFTypeDictionaryValueCallBacks);
+     */
+
+    NSData *appPlist = UnzipTask([(__bridge NSURL *)url path], @"preview.png");
+
+    // Not made with Krita. Find ORA thumbnail instead.
+    if (appPlist == nil || [appPlist length] == 0) {
+      appPlist =
+          UnzipTask([(__bridge NSURL *)url path], @"Thumbnails/thumbnail.png");
+    }
+
+    if (QLThumbnailRequestIsCancelled(thumbnail)) {
+      return noErr;
+    }
+
+    if ([appPlist length]) {
+      NSImage *appIcon = [[NSImage alloc] initWithData:appPlist];
+
+      NSImageRep *rep = [[appIcon representations] objectAtIndex:0];
+
+      NSRect renderRect = NSMakeRect(0.0, 0.0, rep.pixelsWide, rep.pixelsHigh);
+
+      CGImageRef cgImage =
+          [appIcon CGImageForProposedRect:&renderRect context:NULL hints:nil];
+
+      QLThumbnailRequestSetImage(thumbnail, cgImage, NULL);
+      CGImageRelease(cgImage);
+    } else {
+      return NSFileNoSuchFileError;
+    }
+
+    return noErr;
+  }
+}
+
+void CancelThumbnailGeneration(void *thisInterface,
+                               QLThumbnailRequestRef thumbnail) {
+  // Implement only if supported
+}
diff --git a/krita/integration/quicklook/Info.plist b/krita/integration/quicklook/Info.plist
new file mode 100644
index 0000000000..c433763899
--- /dev/null
+++ b/krita/integration/quicklook/Info.plist
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleDocumentTypes</key>
+	<array>
+		<dict>
+			<key>CFBundleTypeRole</key>
+			<string>QLGenerator</string>
+			<key>LSItemContentTypes</key>
+			<array>
+				<string>dyn.ah62d4rv4ge8006xb</string>
+				<string>org.krita.kra</string>
+				<string>org.krita.ora</string>
+			</array>
+		</dict>
+	</array>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundleShortVersionString</key>
+	<string>$(MARKETING_VERSION)</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>CFPlugInDynamicRegisterFunction</key>
+	<string></string>
+	<key>CFPlugInDynamicRegistration</key>
+	<string>NO</string>
+	<key>CFPlugInFactories</key>
+	<dict>
+		<key>292DC9CD-1640-49AE-B0C1-308ED88E6677</key>
+		<string>QuickLookGeneratorPluginFactory</string>
+	</dict>
+	<key>CFPlugInTypes</key>
+	<dict>
+		<key>5E2D9680-5022-40FA-B806-43349622E5B9</key>
+		<array>
+			<string>292DC9CD-1640-49AE-B0C1-308ED88E6677</string>
+		</array>
+	</dict>
+	<key>CFPlugInUnloadFunction</key>
+	<string></string>
+	<key>NSHumanReadableCopyright</key>
+	<string>Copyright © 2015-2020 Stichting Krita Foundation. All rights reserved.</string>
+	<key>QLNeedsToBeRunInMainThread</key>
+	<false/>
+	<key>QLPreviewHeight</key>
+	<real>600</real>
+	<key>QLPreviewWidth</key>
+	<real>800</real>
+	<key>QLSupportsConcurrentRequests</key>
+	<false/>
+	<key>QLThumbnailMinimumSize</key>
+	<real>17</real>
+	<key>UTExportedTypeDeclarations</key>
+	<array>
+		<dict>
+			<key>UTTypeConformsTo</key>
+			<array>
+				<string>public.image</string>
+			</array>
+			<key>UTTypeDescription</key>
+			<string>Krita 3.0 Image</string>
+			<key>UTTypeIdentifier</key>
+			<string>dyn.ah62d4rv4ge8006xb</string>
+			<key>UTTypeTagSpecification</key>
+			<dict>
+				<key>public.filename-extension</key>
+				<array>
+					<string>kra</string>
+					<string>KRA</string>
+				</array>
+				<key>public.mime-type</key>
+				<array>
+					<string>application/x-krita</string>
+				</array>
+			</dict>
+		</dict>
+		<dict>
+			<key>UTTypeConformsTo</key>
+			<array>
+				<string>public.image</string>
+			</array>
+			<key>UTTypeDescription</key>
+			<string>Open Raster Image</string>
+			<key>UTTypeIdentifier</key>
+			<string>dyn.ah62d4rv4ge8006xb</string>
+			<key>UTTypeTagSpecification</key>
+			<dict>
+				<key>public.filename-extension</key>
+				<array>
+					<string>ora</string>
+					<string>ORA</string>
+				</array>
+				<key>public.mime-type</key>
+				<array>
+					<string>image/openraster</string>
+				</array>
+			</dict>
+		</dict>
+	</array>
+	<key>UTImportedTypeDeclarations</key>
+	<array>
+		<dict>
+			<key>UTTypeConformsTo</key>
+			<array>
+				<string>public.image</string>
+			</array>
+			<key>UTTypeDescription</key>
+			<string>Krita 3.0 Image</string>
+			<key>UTTypeIdentifier</key>
+			<string>org.krita.kra</string>
+			<key>UTTypeTagSpecification</key>
+			<dict>
+				<key>public.filename-extension</key>
+				<array>
+					<string>kra</string>
+					<string>KRA</string>
+				</array>
+				<key>public.mime-type</key>
+				<array>
+					<string>application/x-krita</string>
+				</array>
+			</dict>
+		</dict>
+		<dict>
+			<key>UTTypeConformsTo</key>
+			<array>
+				<string>public.image</string>
+			</array>
+			<key>UTTypeDescription</key>
+			<string>Open Raster Image</string>
+			<key>UTTypeIdentifier</key>
+			<string>org.krita.ora</string>
+			<key>UTTypeTagSpecification</key>
+			<dict>
+				<key>public.filename-extension</key>
+				<array>
+					<string>ora</string>
+					<string>ORA</string>
+				</array>
+				<key>public.mime-type</key>
+				<array>
+					<string>image/openraster</string>
+				</array>
+			</dict>
+		</dict>
+	</array>
+</dict>
+</plist>
diff --git a/krita/integration/kritaquicklook/main.c b/krita/integration/quicklook/main.c
similarity index 90%
rename from krita/integration/kritaquicklook/main.c
rename to krita/integration/quicklook/main.c
index 039f4d7f5e..0b3341fb04 100644
--- a/krita/integration/kritaquicklook/main.c
+++ b/krita/integration/quicklook/main.c
@@ -1,3 +1,28 @@
+/*
+ * This file is part of Krita
+ *
+ * Copyright (c) 2015 Algorithmus <angelus.tenebrae at gmail.com>
+ * Copyright (c) 2015 beelzy <alvina.lee at innoactive.de>
+ * Copyright (c) 2020 L. E. Segovia <amy at amyspark.me>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+/* clang-format off */
+
 //==============================================================================
 //
 //	DO NO MODIFY THE CONTENT OF THIS FILE
diff --git a/krita/integration/quicklookng/Info.plist b/krita/integration/quicklookng/Info.plist
new file mode 100644
index 0000000000..8e9afbfd3f
--- /dev/null
+++ b/krita/integration/quicklookng/Info.plist
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
+	<key>CFBundleDisplayName</key>
+	<string>quicklookng</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
+	<key>CFBundleShortVersionString</key>
+	<string>$(MARKETING_VERSION)</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>LSMinimumSystemVersion</key>
+	<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
+	<key>NSExtension</key>
+	<dict>
+		<key>NSExtensionAttributes</key>
+		<dict>
+			<key>QLSupportedContentTypes</key>
+			<array>
+				<dict>
+					<key>UTTypeConformsTo</key>
+					<array>
+						<string>public.image</string>
+					</array>
+					<key>UTTypeDescription</key>
+					<string>Open Raster Image</string>
+					<key>UTTypeIdentifier</key>
+					<string>org.krita.ora</string>
+					<key>UTTypeTagSpecification</key>
+					<dict>
+						<key>public.filename-extension</key>
+						<array>
+							<string>ora</string>
+							<string>ORA</string>
+						</array>
+						<key>public.mime-type</key>
+						<array>
+							<string>image/openraster</string>
+						</array>
+					</dict>
+				</dict>
+				<dict>
+					<key>UTTypeConformsTo</key>
+					<array>
+						<string>public.image</string>
+					</array>
+					<key>UTTypeDescription</key>
+					<string>Krita 3.0 Image</string>
+					<key>UTTypeIdentifier</key>
+					<string>org.krita.kra</string>
+					<key>UTTypeTagSpecification</key>
+					<dict>
+						<key>public.filename-extension</key>
+						<array>
+							<string>kra</string>
+							<string>KRA</string>
+						</array>
+						<key>public.mime-type</key>
+						<array>
+							<string>application/x-krita</string>
+						</array>
+					</dict>
+				</dict>
+			</array>
+			<key>QLThumbnailMinimumDimension</key>
+			<integer>17</integer>
+		</dict>
+		<key>NSExtensionPointIdentifier</key>
+		<string>com.apple.quicklook.thumbnail</string>
+		<key>NSExtensionPrincipalClass</key>
+		<string>$(PRODUCT_MODULE_NAME).ThumbnailProvider</string>
+	</dict>
+	<key>NSHumanReadableCopyright</key>
+	<string>Copyright © 2020 Stichting Krita Foundation. All rights reserved.</string>
+</dict>
+</plist>
diff --git a/krita/integration/quicklookng/ThumbnailProvider.swift b/krita/integration/quicklookng/ThumbnailProvider.swift
new file mode 100644
index 0000000000..6faf9e70c2
--- /dev/null
+++ b/krita/integration/quicklookng/ThumbnailProvider.swift
@@ -0,0 +1,74 @@
+/*
+ * This file is part of Krita
+ *
+ * Copyright (c) 2020 L. E. Segovia <amy at amyspark.me>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+import AppKit
+import QuickLookThumbnailing
+
+class ThumbnailProvider: QLThumbnailProvider {
+
+    override func provideThumbnail(for request: QLFileThumbnailRequest, _ handler: @escaping (QLThumbnailReply?, Error?) -> Void) {
+
+        // There are three ways to provide a thumbnail through a QLThumbnailReply. Only one of them should be used.
+
+        // First way: Draw the thumbnail into the current context, set up with UIKit's coordinate system.
+        /* handler(QLThumbnailReply(contextSize: request.maximumSize, currentContextDrawing: { () -> Bool in
+            // Draw the thumbnail here.
+
+            // Return true if the thumbnail was successfully drawn inside this block.
+            return true
+        }), nil) */
+
+
+
+        // Second way: Draw the thumbnail into a context passed to your block, set up with Core Graphics's coordinate system.
+        handler(QLThumbnailReply(contextSize: request.maximumSize, drawing: { (context: CGContext) -> Bool in
+            // Draw the thumbnail here.
+
+            var appPlist = UnzipTask(request.fileURL.path, "preview.png")
+
+            // Not made with Krita. Find ORA thumbnail instead.
+            if (appPlist == nil || appPlist!.isEmpty) {
+              appPlist =
+                UnzipTask(request.fileURL.path, "Thumbnails/thumbnail.png");
+            }
+
+            if (appPlist != nil && !appPlist!.isEmpty) {
+              let appIcon = NSImage.init(data: appPlist!);
+
+              let rep = appIcon!.representations.first!;
+
+              var renderRect = NSMakeRect(0.0, 0.0, CGFloat(rep.pixelsWide), CGFloat(rep.pixelsHigh));
+
+              let cgImage = appIcon?.cgImage(forProposedRect: &renderRect, context: nil, hints: nil);
+
+              context.draw(cgImage!, in: renderRect);
+            } else {
+              return false;
+            }
+
+            // Return true if the thumbnail was successfully drawn inside this block.
+            return true
+        }), nil)
+
+        // Third way: Set an image file URL.
+        /* handler(QLThumbnailReply(imageFileURL: Bundle.main.url(forResource: "fileThumbnail", withExtension: "jpg")!), nil) */
+    }
+}
diff --git a/krita/integration/quicklookng/quicklookng-Bridging-Header.h b/krita/integration/quicklookng/quicklookng-Bridging-Header.h
new file mode 100644
index 0000000000..68ae88b082
--- /dev/null
+++ b/krita/integration/quicklookng/quicklookng-Bridging-Header.h
@@ -0,0 +1,26 @@
+/*
+ * This file is part of Krita
+ *
+ * Copyright (c) 2020 L. E. Segovia <amy at amyspark.me>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+//
+//  Use this file to import your target's public headers that you would like to expose to Swift.
+//
+
+#import "UnzipTask.h"
diff --git a/krita/integration/quicklookng/quicklookng.entitlements b/krita/integration/quicklookng/quicklookng.entitlements
new file mode 100644
index 0000000000..f2ef3ae026
--- /dev/null
+++ b/krita/integration/quicklookng/quicklookng.entitlements
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+    <key>com.apple.security.app-sandbox</key>
+    <true/>
+    <key>com.apple.security.files.user-selected.read-only</key>
+    <true/>
+</dict>
+</plist>
diff --git a/krita/integration/spotlight/GetMetadataForFile.m b/krita/integration/spotlight/GetMetadataForFile.m
new file mode 100644
index 0000000000..73cf59e5e4
--- /dev/null
+++ b/krita/integration/spotlight/GetMetadataForFile.m
@@ -0,0 +1,276 @@
+/*
+ * This file is part of Krita
+ *
+ * Copyright (c) 2020 L. E. Segovia <amy at amyspark.me>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include "UnzipTask.h"
+#import <CoreData/CoreData.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+void colorSpaceAndDepthForID(NSString *_Nonnull const colorSpaceId,
+                             NSString *_Nonnull *_Nonnull colorSpace,
+                             NSInteger *_Nonnull bitDepth) {
+    /*
+
+      Color model id comparison through the ages:
+
+    2.4        2.5          2.6         ideal
+
+    ALPHA      ALPHA        ALPHA       ALPHAU8
+
+    CMYK       CMYK         CMYK        CMYKAU8
+               CMYKAF32     CMYKAF32
+    CMYKA16    CMYKAU16     CMYKAU16
+
+    GRAYA      GRAYA        GRAYA       GRAYAU8
+    GrayF32    GRAYAF32     GRAYAF32
+    GRAYA16    GRAYAU16     GRAYAU16
+
+    LABA       LABA         LABA        LABAU16
+               LABAF32      LABAF32
+               LABAU8       LABAU8
+
+    RGBA       RGBA         RGBA        RGBAU8
+    RGBA16     RGBA16       RGBA16      RGBAU16
+    RgbAF32    RGBAF32      RGBAF32
+    RgbAF16    RgbAF16      RGBAF16
+
+    XYZA16     XYZA16       XYZA16      XYZAU16
+               XYZA8        XYZA8       XYZAU8
+    XyzAF16    XyzAF16      XYZAF16
+    XyzAF32    XYZAF32      XYZAF32
+
+    YCbCrA     YCBCRA8      YCBCRA8     YCBCRAU8
+    YCbCrAU16  YCBCRAU16    YCBCRAU16
+               YCBCRF32     YCBCRF32
+     */
+
+  NSString *normalizedColorSpaceId = [colorSpaceId uppercaseString];
+
+  if ([normalizedColorSpaceId hasPrefix:@"ALPHA"]) {
+    *colorSpace = @"Alpha";
+  } else if ([normalizedColorSpaceId hasPrefix:@"CMYK"]) {
+    *colorSpace = @"CMYK";
+  } else if ([normalizedColorSpaceId hasPrefix:@"GRAYA"]) {
+    *colorSpace = @"Gray";
+  } else if ([normalizedColorSpaceId hasPrefix:@"LABA"]) {
+    *colorSpace = @"Lab";
+  } else if ([normalizedColorSpaceId hasPrefix:@"RGBA"]) {
+    *colorSpace = @"RGB";
+  } else if ([normalizedColorSpaceId hasPrefix:@"XYZA"]) {
+    *colorSpace = @"XYZ";
+  } else if ([normalizedColorSpaceId hasPrefix:@"YCBCR"]) {
+    *colorSpace = @"YCbCr";
+  }
+
+  if ([normalizedColorSpaceId hasSuffix:@"U8"] ||
+      [normalizedColorSpaceId hasSuffix:@"8"]) {
+    *bitDepth = 8;
+  } else if ([normalizedColorSpaceId hasSuffix:@"U16"] ||
+             [normalizedColorSpaceId hasSuffix:@"F16"] ||
+             [normalizedColorSpaceId hasSuffix:@"16"]) {
+    *bitDepth = 16;
+  } else if ([normalizedColorSpaceId hasSuffix:@"F32"]) {
+    *bitDepth = 32;
+  } else {
+    *bitDepth = 8;
+  }
+}
+
+//==============================================================================
+//
+//  Get metadata attributes from document files
+//
+//  The purpose of this function is to extract useful information from the
+//  file formats for your document, and set the values into the attribute
+//  dictionary for Spotlight to include.
+//
+//==============================================================================
+
+Boolean GetMetadataForFile(void *thisInterface,
+                           CFMutableDictionaryRef attributes,
+                           CFStringRef contentTypeUTI, CFStringRef pathToFile) {
+  // Pull any available metadata from the file at the specified path
+  // Return the attribute keys and attribute values in the dict
+  // Return TRUE if successful, FALSE if there was no data provided
+  // The path could point to either a Core Data store file in which
+  // case we import the store's metadata, or it could point to a Core
+  // Data external record file for a specific record instances
+
+  Boolean ok = FALSE;
+
+  @autoreleasepool {
+    NSMutableDictionary *properties =
+        (__bridge NSMutableDictionary *)attributes;
+    NSString *URL = (__bridge NSString *)pathToFile;
+
+#ifdef DEBUG
+    NSLog(@"Test... initializing data for %@", pathToFile);
+#endif
+
+    @autoreleasepool {
+      // maindoc.xml -> DOC get IMAGE attrib width, height
+#ifdef DEBUG
+      NSLog(@"Test... about to get maindoc metadata for %@", pathToFile);
+#endif
+      NSData *metaData = UnzipTask(URL, @"maindoc.xml");
+
+      if ([metaData length] == 0) {
+#ifdef DEBUG
+        NSLog(@"Test... %@ has no metadata available", pathToFile);
+#endif
+        ok = FALSE;
+      } else {
+#ifdef DEBUG
+        NSLog(@"Test... maindoc metadata for %@ returned %lu bytes", URL,
+              (unsigned long)[metaData length]);
+#endif
+        NSXMLDocument *xmlDoc = [[NSXMLDocument alloc]
+            initWithData:metaData
+                 options:(NSXMLDocumentTidyXML)error:nil];
+
+        if (xmlDoc) {
+#ifdef DEBUG
+          NSLog(@"Test... we've got a Calligra manifest @ %@", URL);
+#endif
+          NSXMLElement *rootNode = [xmlDoc rootElement];
+
+          NSXMLElement *metaNode =
+              [xmlDoc nodesForXPath:@"//IMAGE[1]" error:nil].firstObject;
+
+          NSInteger width =
+              [[[metaNode attributeForName:@"width"] stringValue] integerValue];
+          NSInteger height = [[[metaNode attributeForName:@"height"]
+              stringValue] integerValue];
+
+          NSString *xRes = [[metaNode attributeForName:@"x-res"] stringValue];
+          NSString *yRes = [[metaNode attributeForName:@"y-res"] stringValue];
+
+          NSString *colorSpaceId =
+              [[metaNode attributeForName:@"colorspacename"] stringValue];
+          NSString *colorSpace = nil;
+          NSInteger bitDepth;
+          colorSpaceAndDepthForID(colorSpaceId, &colorSpace, &bitDepth);
+
+          properties[(__bridge NSString *)kMDItemPixelWidth] = @(width);
+          properties[(__bridge NSString *)kMDItemPixelHeight] = @(height);
+          properties[(__bridge NSString *)kMDItemPixelCount] =
+              @(width * height);
+          properties[(__bridge NSString *)kMDItemBitsPerSample] = @(bitDepth);
+          properties[(__bridge NSString *)kMDItemColorSpace] = colorSpace;
+          properties[(__bridge NSString *)kMDItemHasAlphaChannel] =
+              (__bridge id _Nullable)(kCFBooleanTrue);
+          properties[(__bridge NSString *)kMDItemResolutionHeightDPI] =
+              @([xRes integerValue]);
+          properties[(__bridge NSString *)kMDItemResolutionWidthDPI] =
+              @([yRes integerValue]);
+
+          NSString *profileName =
+              [[metaNode attributeForName:@"profile"] stringValue];
+
+          properties[(__bridge NSString *)kMDItemProfileName] = profileName;
+
+          NSString *editor =
+              [[rootNode attributeForName:@"editor"] stringValue];
+          NSString *version =
+              [[rootNode attributeForName:@"kritaVersion"] stringValue];
+          NSString *creator =
+              [[NSString alloc] initWithFormat:@"%@ %@", editor, version];
+          properties[(__bridge NSString *)kMDItemCreator] = creator;
+
+          NSArray<NSXMLElement *> *layers =
+              [xmlDoc nodesForXPath:@"//layers[1]/layer" error:nil];
+          if (layers) {
+            NSMutableArray *layerNames =
+                [NSMutableArray arrayWithCapacity:[layers count]];
+            for (NSXMLElement *layer in layers) {
+              [layerNames
+                  addObject:[[layer attributeForName:@"name"] stringValue]];
+            }
+            properties[(__bridge NSString *)kMDItemLayerNames] = layerNames;
+          }
+
+          ok = TRUE;
+        }
+      }
+    }
+
+    @autoreleasepool {
+      // documentinfo.xml -> document-info get about get title
+
+#ifdef DEBUG
+      NSLog(@"Test... about to get document information for %@", URL);
+#endif
+      NSData *metaData = UnzipTask(URL, @"documentinfo.xml");
+
+      if ([metaData length] == 0) {
+#ifdef DEBUG
+        NSLog(@"Test... %@ has no document information available", URL);
+#endif
+        ok = FALSE;
+      } else {
+#ifdef DEBUG
+        NSLog(@"Test... maindoc metadata for %@ returned %lu bytes", URL,
+              (unsigned long)[metaData length]);
+#endif
+        NSXMLDocument *xmlDoc = [[NSXMLDocument alloc]
+            initWithData:metaData
+                 options:(NSXMLDocumentTidyXML)error:nil];
+
+        if (xmlDoc) {
+#ifdef DEBUG
+          NSLog(@"Test... we've got a Krita document info metadata @ %@", URL);
+#endif
+          NSXMLElement *title =
+              [xmlDoc nodesForXPath:@"//about/title[1]" error:nil].firstObject;
+          if (title) {
+            properties[(__bridge NSString *)kMDItemTitle] = [title stringValue];
+          }
+
+          NSArray<NSXMLElement *> *authors =
+              [xmlDoc nodesForXPath:@"//author/full-name" error:nil];
+          if (authors) {
+            NSMutableArray *authorsNames =
+                [NSMutableArray arrayWithCapacity:[authors count]];
+            for (NSXMLElement *author in authors) {
+              [authorsNames addObject:[author stringValue]];
+            }
+            properties[(__bridge NSString *)kMDItemAuthors] = authorsNames;
+          }
+
+          NSXMLElement *abstract =
+              [xmlDoc nodesForXPath:@"//about/description[1]" error:nil]
+                  .firstObject;
+          if (abstract) {
+            properties[(__bridge NSString *)kMDItemHeadline] =
+                [abstract stringValue];
+          }
+
+          ok = TRUE;
+        }
+      }
+    }
+#ifdef DEBUG
+    NSLog(@"[%@] %@", URL, properties);
+#endif
+  }
+
+  // Return the status
+  return ok;
+}
diff --git a/krita/integration/spotlight/Info.plist b/krita/integration/spotlight/Info.plist
new file mode 100644
index 0000000000..3d6231d3d9
--- /dev/null
+++ b/krita/integration/spotlight/Info.plist
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
+	<key>CFBundleDocumentTypes</key>
+	<array>
+		<dict>
+			<key>CFBundleTypeRole</key>
+			<string>MDImporter</string>
+			<key>LSItemContentTypes</key>
+			<array>
+				<string>org.krita.kra</string>
+				<string>org.krita.ora</string>
+			</array>
+		</dict>
+	</array>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
+	<key>CFBundleShortVersionString</key>
+	<string>$(MARKETING_VERSION)</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>CFPlugInDynamicRegisterFunction</key>
+	<string></string>
+	<key>CFPlugInDynamicRegistration</key>
+	<string>NO</string>
+	<key>CFPlugInFactories</key>
+	<dict>
+		<key>23FE92B0-6256-49C0-B1A6-942FB9B86A82</key>
+		<string>MetadataImporterPluginFactory</string>
+	</dict>
+	<key>CFPlugInTypes</key>
+	<dict>
+		<key>8B08C4BF-415B-11D8-B3F9-0003936726FC</key>
+		<array>
+			<string>23FE92B0-6256-49C0-B1A6-942FB9B86A82</string>
+		</array>
+	</dict>
+	<key>CFPlugInUnloadFunction</key>
+	<string></string>
+	<key>LSMinimumSystemVersion</key>
+	<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
+	<key>NSHumanReadableCopyright</key>
+	<string>Copyright © 2020 Stichting Krita Foundation. All rights reserved.</string>
+	<key>UTExportedTypeDeclarations</key>
+	<array>
+		<dict>
+			<key>UTTypeConformsTo</key>
+			<array>
+				<string>public.image</string>
+			</array>
+			<key>UTTypeDescription</key>
+			<string>Krita 3.0 Image</string>
+			<key>UTTypeIdentifier</key>
+			<string>org.krita.kra</string>
+			<key>UTTypeTagSpecification</key>
+			<dict>
+				<key>public.filename-extension</key>
+				<array>
+					<string>kra</string>
+					<string>KRA</string>
+				</array>
+				<key>public.mime-type</key>
+				<array>
+					<string>application/x-krita</string>
+				</array>
+			</dict>
+		</dict>
+		<dict>
+			<key>UTTypeConformsTo</key>
+			<array>
+				<string>public.image</string>
+			</array>
+			<key>UTTypeDescription</key>
+			<string>Open Raster Image</string>
+			<key>UTTypeIdentifier</key>
+			<string>org.krita.ora</string>
+			<key>UTTypeTagSpecification</key>
+			<dict>
+				<key>public.filename-extension</key>
+				<array>
+					<string>ora</string>
+					<string>ORA</string>
+				</array>
+				<key>public.mime-type</key>
+				<array>
+					<string>image/openraster</string>
+				</array>
+			</dict>
+		</dict>
+	</array>
+</dict>
+</plist>
diff --git a/krita/integration/spotlight/main.c b/krita/integration/spotlight/main.c
new file mode 100644
index 0000000000..c88126c3e8
--- /dev/null
+++ b/krita/integration/spotlight/main.c
@@ -0,0 +1,238 @@
+/*
+ * This file is part of Krita
+ *
+ * Copyright (c) 2020 L. E. Segovia <amy at amyspark.me>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+/* clang-format off */
+
+
+
+
+//==============================================================================
+//
+//  DO NO MODIFY THE CONTENT OF THIS FILE
+//
+//  This file contains the generic CFPlug-in code necessary for your importer
+//  To complete your importer implement the function in GetMetadataForFile.c
+//
+//==============================================================================
+
+
+
+
+
+#import <CoreFoundation/CoreFoundation.h>
+#import <CoreFoundation/CFPlugInCOM.h>
+#import <CoreServices/CoreServices.h>
+
+// -----------------------------------------------------------------------------
+//  constants
+// -----------------------------------------------------------------------------
+
+
+#define PLUGIN_ID "23FE92B0-6256-49C0-B1A6-942FB9B86A82"
+
+//
+// Below is the generic glue code for all plug-ins.
+//
+// You should not have to modify this code aside from changing
+// names if you decide to change the names defined in the Info.plist
+//
+
+
+// -----------------------------------------------------------------------------
+//  typedefs
+// -----------------------------------------------------------------------------
+
+// The import function to be implemented in GetMetadataForFile.c
+Boolean GetMetadataForFile(void *thisInterface, 
+               CFMutableDictionaryRef attributes, 
+               CFStringRef contentTypeUTI,
+               CFStringRef pathToFile);
+               
+// The layout for an instance of MetaDataImporterPlugIn 
+typedef struct __MetadataImporterPluginType
+{
+    MDImporterInterfaceStruct *conduitInterface;
+    CFUUIDRef                 factoryID;
+    UInt32                    refCount;
+} MetadataImporterPluginType;
+
+// -----------------------------------------------------------------------------
+//  prototypes
+// -----------------------------------------------------------------------------
+//  Forward declaration for the IUnknown implementation.
+//
+
+MetadataImporterPluginType  *AllocMetadataImporterPluginType(CFUUIDRef inFactoryID);
+void                      DeallocMetadataImporterPluginType(MetadataImporterPluginType *thisInstance);
+HRESULT                   MetadataImporterQueryInterface(void *thisInstance,REFIID iid,LPVOID *ppv);
+void                     *MetadataImporterPluginFactory(CFAllocatorRef allocator,CFUUIDRef typeID);
+ULONG                     MetadataImporterPluginAddRef(void *thisInstance);
+ULONG                     MetadataImporterPluginRelease(void *thisInstance);
+// -----------------------------------------------------------------------------
+//  testInterfaceFtbl    definition
+// -----------------------------------------------------------------------------
+//  The TestInterface function table.
+//
+
+static MDImporterInterfaceStruct testInterfaceFtbl = {
+    NULL,
+    MetadataImporterQueryInterface,
+    MetadataImporterPluginAddRef,
+    MetadataImporterPluginRelease,
+    GetMetadataForFile
+};
+
+
+// -----------------------------------------------------------------------------
+//  AllocMetadataImporterPluginType
+// -----------------------------------------------------------------------------
+//  Utility function that allocates a new instance.
+//      You can do some initial setup for the importer here if you wish
+//      like allocating globals etc...
+//
+MetadataImporterPluginType *AllocMetadataImporterPluginType(CFUUIDRef inFactoryID)
+{
+    MetadataImporterPluginType *theNewInstance;
+
+    theNewInstance = (MetadataImporterPluginType *)malloc(sizeof(MetadataImporterPluginType));
+    memset(theNewInstance,0,sizeof(MetadataImporterPluginType));
+
+        /* Point to the function table */
+    theNewInstance->conduitInterface = &testInterfaceFtbl;
+
+        /*  Retain and keep an open instance refcount for each factory. */
+    theNewInstance->factoryID = CFRetain(inFactoryID);
+    CFPlugInAddInstanceForFactory(inFactoryID);
+
+        /* This function returns the IUnknown interface so set the refCount to one. */
+    theNewInstance->refCount = 1;
+    return theNewInstance;
+}
+
+// -----------------------------------------------------------------------------
+//    DeallockritaspotlightMDImporterPluginType
+// -----------------------------------------------------------------------------
+//  Utility function that deallocates the instance when
+//  the refCount goes to zero.
+//      In the current implementation importer interfaces are never deallocated
+//      but implement this as this might change in the future
+//
+void DeallocMetadataImporterPluginType(MetadataImporterPluginType *thisInstance)
+{
+    CFUUIDRef theFactoryID;
+
+    theFactoryID = thisInstance->factoryID;
+    free(thisInstance);
+    if (theFactoryID){
+        CFPlugInRemoveInstanceForFactory(theFactoryID);
+        CFRelease(theFactoryID);
+    }
+}
+
+// -----------------------------------------------------------------------------
+//  MetadataImporterQueryInterface
+// -----------------------------------------------------------------------------
+//  Implementation of the IUnknown QueryInterface function.
+//
+HRESULT MetadataImporterQueryInterface(void *thisInstance,REFIID iid,LPVOID *ppv)
+{
+    CFUUIDRef interfaceID;
+
+    interfaceID = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault,iid);
+
+    if (CFEqual(interfaceID,kMDImporterInterfaceID)){
+            /* If the Right interface was requested, bump the ref count,
+             * set the ppv parameter equal to the instance, and
+             * return good status.
+             */
+        ((MetadataImporterPluginType*)thisInstance)->conduitInterface->AddRef(thisInstance);
+        *ppv = thisInstance;
+        CFRelease(interfaceID);
+        return S_OK;
+    }else{
+        if (CFEqual(interfaceID,IUnknownUUID)){
+                /* If the IUnknown interface was requested, same as above. */
+            ((MetadataImporterPluginType*)thisInstance )->conduitInterface->AddRef(thisInstance);
+            *ppv = thisInstance;
+            CFRelease(interfaceID);
+            return S_OK;
+        }else{
+                /* Requested interface unknown, bail with error. */
+            *ppv = NULL;
+            CFRelease(interfaceID);
+            return E_NOINTERFACE;
+        }
+    }
+}
+
+// -----------------------------------------------------------------------------
+//  MetadataImporterPluginAddRef
+// -----------------------------------------------------------------------------
+//  Implementation of reference counting for this type. Whenever an interface
+//  is requested, bump the refCount for the instance. NOTE: returning the
+//  refcount is a convention but is not required so don't rely on it.
+//
+ULONG MetadataImporterPluginAddRef(void *thisInstance)
+{
+    ((MetadataImporterPluginType *)thisInstance )->refCount += 1;
+    return ((MetadataImporterPluginType*) thisInstance)->refCount;
+}
+
+// -----------------------------------------------------------------------------
+// SampleCMPluginRelease
+// -----------------------------------------------------------------------------
+//  When an interface is released, decrement the refCount.
+//  If the refCount goes to zero, deallocate the instance.
+//
+ULONG MetadataImporterPluginRelease(void *thisInstance)
+{
+    ((MetadataImporterPluginType*)thisInstance)->refCount -= 1;
+    if (((MetadataImporterPluginType*)thisInstance)->refCount == 0){
+        DeallocMetadataImporterPluginType((MetadataImporterPluginType*)thisInstance );
+        return 0;
+    }else{
+        return ((MetadataImporterPluginType*) thisInstance )->refCount;
+    }
+}
+
+// -----------------------------------------------------------------------------
+//  kritaspotlightMDImporterPluginFactory
+// -----------------------------------------------------------------------------
+//  Implementation of the factory function for this type.
+//
+void *MetadataImporterPluginFactory(CFAllocatorRef allocator,CFUUIDRef typeID)
+{
+    MetadataImporterPluginType *result;
+    CFUUIDRef                 uuid;
+
+        /* If correct type is being requested, allocate an
+         * instance of TestType and return the IUnknown interface.
+         */
+    if (CFEqual(typeID,kMDImporterTypeID)){
+        uuid = CFUUIDCreateFromString(kCFAllocatorDefault,CFSTR(PLUGIN_ID));
+        result = AllocMetadataImporterPluginType(uuid);
+        CFRelease(uuid);
+        return result;
+    }
+        /* If the requested type is incorrect, return NULL. */
+    return NULL;
+}
+
diff --git a/krita/integration/unzipTask/UnzipTask.h b/krita/integration/unzipTask/UnzipTask.h
new file mode 100644
index 0000000000..046e683c06
--- /dev/null
+++ b/krita/integration/unzipTask/UnzipTask.h
@@ -0,0 +1,31 @@
+/*
+ * This file is part of Krita
+ *
+ * Copyright (c) 2020 L. E. Segovia <amy at amyspark.me>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#ifndef UnzipTask_h
+#define UnzipTask_h
+
+#import <Foundation/Foundation.h>
+
+// Try to unzip and read the selected file in the archive.
+FOUNDATION_EXPORT NSData *_Nullable UnzipTask(NSString *_Nonnull path,
+                                              NSString *_Nonnull target);
+
+#endif /* UnzipTask_h */
diff --git a/krita/integration/unzipTask/UnzipTask.m b/krita/integration/unzipTask/UnzipTask.m
new file mode 100644
index 0000000000..63dcd8c575
--- /dev/null
+++ b/krita/integration/unzipTask/UnzipTask.m
@@ -0,0 +1,90 @@
+/*
+ * This file is part of Krita
+ *
+ * Copyright (c) 2020 L. E. Segovia <amy at amyspark.me>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include "UnzipTask.h"
+#include "unzip.h"
+
+NSData *UnzipTask(NSString *_Nonnull path, NSString *_Nonnull target) {
+  // Spotlight plugins are sandboxed, trying to spawn unzip results in sandboxd
+  // killing us
+
+  NSData *output = nil;
+
+  const unzFile zip =
+      unzOpen64([path cStringUsingEncoding:NSUTF8StringEncoding]);
+
+  if (zip != NULL) {
+#ifdef DEBUG
+    NSLog(@"Test... opened file successfully (%@)", path);
+#endif
+    int f = unzLocateFile(
+        zip, [target cStringUsingEncoding:NSUTF8StringEncoding], 0);
+
+    if (f == UNZ_OK) {
+#ifdef DEBUG
+      NSLog(@"Test... located %@ successfully (%@)", target, path);
+#endif
+      f = unzOpenCurrentFile(zip);
+
+      if (f == UNZ_OK) {
+#ifdef DEBUG
+        NSLog(@"Test... opened %@ successfully (%@)", target, path);
+#endif
+        struct unz_file_info64_s fileInfo;
+
+        f = unzGetCurrentFileInfo64(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
+
+        if (f == UNZ_OK) {
+#ifdef DEBUG
+          NSLog(@"Test... %@ size: %llu", target, fileInfo.uncompressed_size);
+#endif
+          void *buf = malloc(fileInfo.uncompressed_size);
+
+          f = unzReadCurrentFile(zip, buf,
+                                 (unsigned)fileInfo.uncompressed_size);
+
+          if (f == fileInfo.uncompressed_size) {
+#ifdef DEBUG
+            NSLog(@"Test... read %@ successfully, copying contents to buffer "
+                  @"(%@)",
+                  target, path);
+#endif
+            output = [[NSData alloc] initWithBytes:buf
+                                            length:fileInfo.uncompressed_size];
+          }
+#ifdef DEBUG
+          else {
+            NSLog(@"Test... failed to read (errno=%d) (%@)", f, target);
+          }
+#endif
+
+          unzCloseCurrentFile(zip);
+
+          free(buf);
+        }
+      }
+
+      unzClose(zip);
+    }
+  }
+
+  return output;
+}
diff --git a/packaging/macos/osxbuild.sh b/packaging/macos/osxbuild.sh
index 39e1b84c7c..4e791691de 100755
--- a/packaging/macos/osxbuild.sh
+++ b/packaging/macos/osxbuild.sh
@@ -543,7 +543,7 @@ install_krita () {
 
     # compile integrations
     if test ${OSTYPE} == "darwin*"; then
-        cd ${KIS_BUILD_DIR}/krita/integration/kritaquicklook
+        cd ${KIS_BUILD_DIR}/krita/integration
         make install
     fi
 }
diff --git a/packaging/macos/osxdeploy.sh b/packaging/macos/osxdeploy.sh
index 312f73fa8b..a71ccd0ca9 100755
--- a/packaging/macos/osxdeploy.sh
+++ b/packaging/macos/osxdeploy.sh
@@ -506,9 +506,14 @@ krita_deploy () {
     rsync -prul ${KIS_INSTALL_DIR}/translations/ \
             ${KRITA_DMG}/krita.app/Contents/Resources/translations
 
-    echo "Copying kritaquicklook..."
+    echo "Copying QuickLook plugin..."
     mkdir -p ${KRITA_DMG}/krita.app/Contents/Library/QuickLook
     rsync -prul ${KIS_INSTALL_DIR}/plugins/kritaquicklook.qlgenerator ${KRITA_DMG}/krita.app/Contents/Library/QuickLook
+    echo "Copying Spotlight plugin..."
+    mkdir -p ${KRITA_DMG}/krita.app/Contents/Library/Spotlight
+    rsync -prul ${KIS_INSTALL_DIR}/plugins/kritaspotlight.mdimporter ${KRITA_DMG}/krita.app/Contents/Library/Spotlight
+    echo "Copying QuickLook Thumbnailing extension..."
+    rsync -prul ${KIS_INSTALL_DIR}/plugins/kritaquicklookng.appex ${KRITA_DMG}/krita.app/Contents/PlugIns
 
     cd ${KRITA_DMG}/krita.app/Contents
     ln -shF Resources share
@@ -521,6 +526,7 @@ krita_deploy () {
     cd ${KIS_INSTALL_DIR}/plugins/
     rsync -prul --delete --delete-excluded ./ \
         --exclude kritaquicklook.qlgenerator \
+        --exclude kritaspotlight.mdimporter \
         ${KRITA_DMG}/krita.app/Contents/PlugIns
 
     cd ${BUILDROOT}


More information about the kimageshop mailing list