changeset 6596:de1b2b661ec3

upgrade to minizip 1.3.2
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 20 Feb 2026 16:03:16 +0100
parents c23bb535bade
children 81746b9484c4
files NEWS OrthancFramework/Resources/ThirdParty/minizip/NOTES OrthancFramework/Resources/ThirdParty/minizip/SyncMinizip.py OrthancFramework/Resources/ThirdParty/minizip/crypt.h OrthancFramework/Resources/ThirdParty/minizip/ints.h OrthancFramework/Resources/ThirdParty/minizip/ioapi.c OrthancFramework/Resources/ThirdParty/minizip/ioapi.h OrthancFramework/Resources/ThirdParty/minizip/skipset.h OrthancFramework/Resources/ThirdParty/minizip/unzip.c OrthancFramework/Resources/ThirdParty/minizip/unzip.h OrthancFramework/Resources/ThirdParty/minizip/zip.c OrthancFramework/Resources/ThirdParty/minizip/zip.h
diffstat 12 files changed, 865 insertions(+), 146 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Fri Feb 20 15:41:05 2026 +0100
+++ b/NEWS	Fri Feb 20 16:03:16 2026 +0100
@@ -48,6 +48,7 @@
 * Upgraded dependencies for static builds:
   - boost 1.89.0
   - dcmtk 3.7.0
+  - minizip 1.3.2
 
 NB: To maintain compatibility with Windows XP, which is not supported
 by DCMTK 3.7.0, Windows 32-bit builds must use
--- a/OrthancFramework/Resources/ThirdParty/minizip/NOTES	Fri Feb 20 15:41:05 2026 +0100
+++ b/OrthancFramework/Resources/ThirdParty/minizip/NOTES	Fri Feb 20 16:03:16 2026 +0100
@@ -1,2 +1,2 @@
-These files come from the "contrib/minizip" directory in zlib 1.3+.
-It was last synced on this commit: https://github.com/madler/zlib/commit/73331a6a0481067628f065ffe87bb1d8f787d10c.
+These files come from the "contrib/minizip" directory in zlib.
+The Python script "./SyncMinizip.py" can be used to update the version of minizip.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Resources/ThirdParty/minizip/SyncMinizip.py	Fri Feb 20 16:03:16 2026 +0100
@@ -0,0 +1,24 @@
+#!/usr/bin/env python3
+
+import os
+import requests
+
+ZLIB_VERSION = '1.3.2'
+URL = 'https://raw.githubusercontent.com/madler/zlib/refs/tags/v%s/contrib/minizip' % ZLIB_VERSION
+TARGET = os.path.join(os.path.dirname(__file__))
+
+for f in [
+        'crypt.h',
+        'ints.h',
+        'ioapi.c',
+        'ioapi.h',
+        'skipset.h',
+        'unzip.c',
+        'unzip.h',
+        'zip.c',
+        'zip.h',
+]:
+    r = requests.get('%s/%s' % (URL, f))
+    r.raise_for_status()
+    with open(os.path.join(TARGET, f), 'wb') as f:
+        f.write(r.content)
--- a/OrthancFramework/Resources/ThirdParty/minizip/crypt.h	Fri Feb 20 15:41:05 2026 +0100
+++ b/OrthancFramework/Resources/ThirdParty/minizip/crypt.h	Fri Feb 20 16:03:16 2026 +0100
@@ -1,9 +1,6 @@
 /* crypt.h -- base code for crypt/uncrypt ZIPfile
 
-
-   Version 1.01e, February 12th, 2005
-
-   Copyright (C) 1998-2005 Gilles Vollant
+   Copyright (C) 1998-2026 Gilles Vollant
 
    This code is a modified version of crypting code in Infozip distribution
 
@@ -23,7 +20,7 @@
    This code support the "Traditional PKWARE Encryption".
 
    The new AES encryption added on Zip format by Winzip (see the page
-   http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
+   https://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
    Encryption is not supported.
 */
 
@@ -50,7 +47,7 @@
     (*(pkeys+1)) += (*(pkeys+0)) & 0xff;
     (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
     {
-      register int keyshift = (int)((*(pkeys+1)) >> 24);
+      int keyshift = (int)((*(pkeys+1)) >> 24);
       (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
     }
     return c;
@@ -106,7 +103,7 @@
      */
     if (++calls == 1)
     {
-        srand((unsigned)(time(NULL) ^ ZCR_SEED2));
+        srand((unsigned)time(NULL) ^ ZCR_SEED2);
     }
     init_keys(passwd, pkeys, pcrc_32_tab);
     for (n = 0; n < RAND_HEAD_LEN-2; n++)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Resources/ThirdParty/minizip/ints.h	Fri Feb 20 16:03:16 2026 +0100
@@ -0,0 +1,57 @@
+/* ints.h -- create integer types for 8, 16, 32, and 64 bits
+ * Copyright (C) 2024 Mark Adler
+ * For conditions of distribution and use, see the copyright notice in zlib.h
+ *
+ * There exist compilers with limits.h, but not stdint.h or inttypes.h.
+ */
+
+#ifndef INTS_H
+#define INTS_H
+#include <limits.h>
+#if defined(UCHAR_MAX) && UCHAR_MAX == 0xff
+    typedef signed char i8_t;
+    typedef unsigned char ui8_t;
+#else
+#   error "no 8-bit integer"
+#endif
+#if defined(USHRT_MAX) && USHRT_MAX == 0xffff
+    typedef short i16_t;
+    typedef unsigned short ui16_t;
+#elif defined(UINT_MAX) && UINT_MAX == 0xffff
+    typedef int i16_t;
+    typedef unsigned ui16_t;
+#else
+#   error "no 16-bit integer"
+#endif
+#if defined(UINT_MAX) && UINT_MAX == 0xffffffff
+    typedef int i32_t;
+    typedef unsigned ui32_t;
+#   define PI32 "d"
+#   define PUI32 "u"
+#elif defined(ULONG_MAX) && ULONG_MAX == 0xffffffff
+    typedef long i32_t;
+    typedef unsigned long ui32_t;
+#   define PI32 "ld"
+#   define PUI32 "lu"
+#else
+#   error "no 32-bit integer"
+#endif
+#if defined(ULONG_MAX) && ULONG_MAX == 0xffffffffffffffff
+    typedef long i64_t;
+    typedef unsigned long ui64_t;
+#   define PI64 "ld"
+#   define PUI64 "lu"
+#elif defined(ULLONG_MAX) && ULLONG_MAX == 0xffffffffffffffff
+    typedef long long i64_t;
+    typedef unsigned long long ui64_t;
+#   define PI64 "lld"
+#   define PUI64 "llu"
+#elif defined(ULONG_LONG_MAX) && ULONG_LONG_MAX == 0xffffffffffffffff
+    typedef long long i64_t;
+    typedef unsigned long long ui64_t;
+#   define PI64 "lld"
+#   define PUI64 "llu"
+#else
+#   error "no 64-bit integer"
+#endif
+#endif
--- a/OrthancFramework/Resources/ThirdParty/minizip/ioapi.c	Fri Feb 20 15:41:05 2026 +0100
+++ b/OrthancFramework/Resources/ThirdParty/minizip/ioapi.c	Fri Feb 20 16:03:16 2026 +0100
@@ -1,10 +1,10 @@
 /* ioapi.h -- IO base function header for compress/uncompress .zip
-   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+   part of the MiniZip project - ( https://www.winimage.com/zLibDll/minizip.html )
 
-         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+         Copyright (C) 1998-2026 Gilles Vollant (minizip) ( https://www.winimage.com/zLibDll/minizip.html )
 
          Modifications for Zip64 support
-         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+         Copyright (C) 2009-2010 Mathias Svensson ( https://result42.com )
 
          For more info read MiniZip_info.txt
 
@@ -14,8 +14,8 @@
         #define _CRT_SECURE_NO_WARNINGS
 #endif
 
-#if defined(__APPLE__) || defined(IOAPI_NO_64) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64)
-// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
+#if defined(__APPLE__) || defined(IOAPI_NO_64) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64) || (defined(__ANDROID_API__) && __ANDROID_API__ < 24)
+/* In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions */
 #define FOPEN_FUNC(filename, mode) fopen(filename, mode)
 #define FTELLO_FUNC(stream) ftello(stream)
 #define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin)
--- a/OrthancFramework/Resources/ThirdParty/minizip/ioapi.h	Fri Feb 20 15:41:05 2026 +0100
+++ b/OrthancFramework/Resources/ThirdParty/minizip/ioapi.h	Fri Feb 20 16:03:16 2026 +0100
@@ -1,10 +1,10 @@
 /* ioapi.h -- IO base function header for compress/uncompress .zip
-   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+   part of the MiniZip project - ( https://www.winimage.com/zLibDll/minizip.html )
 
-         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+         Copyright (C) 1998-2026 Gilles Vollant (minizip) ( https://www.winimage.com/zLibDll/minizip.html )
 
          Modifications for Zip64 support
-         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+         Copyright (C) 2009-2010 Mathias Svensson ( https://result42.com )
 
          For more info read MiniZip_info.txt
 
@@ -18,13 +18,13 @@
 
 */
 
-#ifndef _ZLIBIOAPI64_H
-#define _ZLIBIOAPI64_H
+#ifndef ZLIBIOAPI64_H
+#define ZLIBIOAPI64_H
 
-#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
+#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) && (!(defined(__ANDROID_API__) || __ANDROID_API__ >= 24))
 
-  // Linux needs this to support file operation on files larger then 4+GB
-  // But might need better if/def to select just the platforms that needs them.
+  /* Linux needs this to support file operation on files larger then 4+GB */
+  /* But might need better if/def to select just the platforms that needs them.*/
 
         #ifndef __USE_FILE_OFFSET64
                 #define __USE_FILE_OFFSET64
@@ -67,39 +67,12 @@
 #endif
 #endif
 
-/*
-#ifndef ZPOS64_T
-  #ifdef _WIN32
-                #define ZPOS64_T fpos_t
-  #else
-    #include <stdint.h>
-    #define ZPOS64_T uint64_t
-  #endif
-#endif
-*/
-
 #ifdef HAVE_MINIZIP64_CONF_H
 #include "mz64conf.h"
 #endif
 
-/* a type chosen by DEFINE */
-#ifdef HAVE_64BIT_INT_CUSTOM
-typedef  64BIT_INT_CUSTOM_TYPE ZPOS64_T;
-#else
-#ifdef HAS_STDINT_H
-#include "stdint.h"
-typedef uint64_t ZPOS64_T;
-#else
-
-
-
-#if defined(_MSC_VER) || defined(__BORLANDC__)
-typedef unsigned __int64 ZPOS64_T;
-#else
-typedef unsigned long long int ZPOS64_T;
-#endif
-#endif
-#endif
+#include "ints.h"
+typedef ui64_t ZPOS64_T;
 
 /* Maximum unsigned 32-bit value used as placeholder for zip64 */
 #ifndef MAXU32
@@ -188,8 +161,8 @@
 
 #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 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))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Resources/ThirdParty/minizip/skipset.h	Fri Feb 20 16:03:16 2026 +0100
@@ -0,0 +1,366 @@
+/* skipset.h -- set operations using a skiplist
+// Copyright (C) 2024-2026 Mark Adler
+// See MiniZip_info.txt for the license.
+
+// This implements a skiplist set, i.e. just keys, no data, with ~O(log n) time
+// insert and search operations. The application defines the type of a key, and
+// provides a function to compare two keys.
+
+// This header is not definitions of functions found in another source file --
+// it creates the set functions, with the application's key type, right where
+// the #include is. Before this header is #included, these must be defined:
+//
+// 1. A macro or typedef for set_key_t, the type of a key.
+// 2. A macro or function set_cmp(a, b) to compare two keys. The return values
+//    are < 0 for a < b, 0 for a == b, and > 0 for a > b.
+// 3. A macro or function set_drop(s, k) to release the key k's resources, if
+//    any, when doing a set_end() or set_clear(). s is a pointer to the set
+//    that key is in, for use with set_free() if desired.
+//
+// Example usage:
+//
+//      typedef int set_key_t;
+//      #define set_cmp(a, b) ((a) < (b) ? -1 : (a) == (b) ? 0 : 1)
+//      #define set_drop(s, k)
+//      #include "skipset.h"
+//
+//      int test(void) {        // return 0: good, 1: bad, -1: out of memory
+//          set_t set;
+//          if (setjmp(set.env))
+//              return -1;
+//          set_start(&set);
+//          set_insert(&set, 2);
+//          set_insert(&set, 1);
+//          set_insert(&set, 7);
+//          int bad = !set_found(&set, 2);
+//          bad = bad || set_found(&set, 5);
+//          set_end(&set);
+//          return bad;
+//      }
+//
+// Interface summary (see more details below):
+// - set_t is the type of the set being operated on (a set_t pointer is passed)
+// - set_start() initializes a new, empty set (initialize set.env first)
+// - set_insert() inserts a new key into the set, or not if it's already there
+// - set_found() determines whether or not a key is in the set
+// - set_end() ends the use of the set, freeing all memory
+// - set_clear() empties the set, equivalent to set_end() and then set_start()
+// - set_ok() checks if set appears to be usable, i.e. started and not ended
+//
+// Auxiliary functions available to the application:
+// - set_alloc() allocates memory with optional tracking (#define SET_TRACK)
+// - set_free() deallocates memory allocated by set_alloc()
+// - set_rand() returns 32 random bits (seeded by set_start()) */
+
+#ifndef SKIPSET_H
+#define SKIPSET_H
+
+#include <stdlib.h>     /* realloc(), free(), NULL, size_t */
+#include <stddef.h>     /* ptrdiff_t */
+#include <setjmp.h>     /* jmp_buf, longjmp() */
+#include <errno.h>      /* ENOMEM */
+#include <time.h>       /* time(), clock() */
+#include <assert.h>     /* assert.h */
+#include "ints.h"       /* i16_t, ui32_t, ui64_t */
+
+/* Structures and functions below noted as "--private--" should not be used by
+// the application. set_t is partially private and partially public -- see the
+// comments there.
+
+// There is no POSIX random() in MSVC, and rand() is awful. For portability, we
+// cannot rely on a library function for random numbers. Instead we use the
+// fast and effective algorithm below, invented by Melissa O'Neill.
+
+// *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / www.pcg-random.org
+// Licensed under Apache License 2.0 (NO WARRANTY, etc. see website)
+// --private-- Random number generator state. */
+typedef struct {
+    ui64_t state;       /* 64-bit generator state */
+    ui64_t inc;         /* 63-bit sequence id */
+} set_rand_t;
+/* --private-- Initialize the state *gen using seed and seq. seed seeds the
+// advancing 64-bit state. seq is a sequence selection constant. */
+void set_seed(set_rand_t *gen, ui64_t seed, ui64_t seq) {
+    gen->inc = (seq << 1) | 1;
+    gen->state = (seed + gen->inc) * 6364136223846793005ULL + gen->inc;
+}
+/* Start a unique random number sequence using bits from noise sources. */
+void set_uniq(set_rand_t *gen, const void *ptr) {
+    set_seed(gen, ((ui64_t)(ptrdiff_t)ptr << 32) ^
+                  ((ui64_t)time(NULL) << 12) ^ clock(), 0);
+}
+/* Return 32 random bits, advancing the state *gen. */
+ui32_t set_rand(set_rand_t *gen) {
+    ui64_t state = gen->state;
+    gen->state = state * 6364136223846793005ULL + gen->inc;
+    ui32_t mix = (ui32_t)(((state >> 18) ^ state) >> 27);
+    int rot = state >> 59;
+    return (mix >> rot) | (mix << ((-rot) & 31));
+}
+/* End of PCG32 code. */
+
+/* --private-- Linked-list node. */
+typedef struct set_node_s set_node_t;
+struct set_node_s {
+    set_key_t key;          /* the key (not used for head or path) */
+    i16_t size;             /* number of allocated pointers in right[] */
+    i16_t fill;             /* number of pointers in right[] filled in */
+    set_node_t **right;     /* pointer for each level, each to the right */
+};
+
+/* A set. The application sets env, may use gen with set_rand(), and may read
+// allocs and memory. The remaining variables are --private-- . */
+typedef struct set_s {
+    set_node_t *head;       /* skiplist head -- no key, just links */
+    set_node_t *path;       /* right[] is path to key from set_found() */
+    set_node_t *node;       /* node under construction, in case of longjmp() */
+    i16_t depth;            /* maximum depth of the skiplist */
+    ui64_t ran;             /* a precious trove of random bits */
+    set_rand_t gen;         /* random number generator state */
+    jmp_buf env;            /* setjmp() environment for allocation errors */
+#ifdef SET_TRACK
+    size_t allocs;          /* number of allocations */
+    size_t memory;          /* total amount of allocated memory (>= requests) */
+#endif
+} set_t;
+
+/* Memory allocation and deallocation. set_alloc(set, ptr, size) returns a
+// pointer to an allocation of size bytes if ptr is NULL, or the previous
+// allocation ptr resized to size bytes. set_alloc() will never return NULL.
+// set_free(set, ptr) frees an allocation created by set_alloc(). These may be
+// used by the application. e.g. if allocation tracking is desired. */
+#ifdef SET_TRACK
+/* Track the number of allocations and the total backing memory size. */
+#  if defined(_WIN32)
+#    include <malloc.h>
+#    define SET_ALLOC_SIZE(ptr) _msize(ptr)
+#  elif defined(__MACH__)
+#    include <malloc/malloc.h>
+#    define SET_ALLOC_SIZE(ptr) malloc_size(ptr)
+#  elif defined(__linux__)
+#    include <malloc.h>
+#    define SET_ALLOC_SIZE(ptr) malloc_usable_size(ptr)
+#  elif defined(__FreeBSD__)
+#    include <malloc_np.h>
+#    define SET_ALLOC_SIZE(ptr) malloc_usable_size(ptr)
+#  elif defined(__NetBSD__)
+#    include <jemalloc/jemalloc.h>
+#    define SET_ALLOC_SIZE(ptr) malloc_usable_size(ptr)
+#  else     // e.g. OpenBSD
+#    define SET_ALLOC_SIZE(ptr) 0
+#  endif
+// With tracking.
+void *set_alloc(set_t *set, void *ptr, size_t size) {
+    size_t had = ptr == NULL ? 0 : SET_ALLOC_SIZE(ptr);
+    void *mem = realloc(ptr, size);
+    if (mem == NULL)
+        longjmp(set->env, ENOMEM);
+    set->allocs += ptr == NULL;
+    set->memory += SET_ALLOC_SIZE(mem) - had;
+    return mem;
+}
+void set_free(set_t *set, void *ptr) {
+    if (ptr != NULL) {
+        set->allocs--;
+        set->memory -= SET_ALLOC_SIZE(ptr);
+        free(ptr);
+    }
+}
+#else
+/* Without tracking. */
+void *set_alloc(set_t *set, void *ptr, size_t size) {
+    void *mem = realloc(ptr, size);
+    if (mem == NULL)
+        longjmp(set->env, ENOMEM);
+    return mem;
+}
+void set_free(set_t *set, void *ptr) {
+    (void)set;
+    free(ptr);
+}
+#endif
+
+/* --private-- Grow node's array right[] as needed to be able to hold at least
+// want links. If fill is true, assure that the first want links are filled in,
+// setting them to set->head if not previously filled in. Otherwise it is
+// assumed that the first want links are about to be filled in. */
+void set_grow(set_t *set, set_node_t *node, int want, int fill) {
+    if (node->size < want) {
+        int more = node->size ? node->size : 1;
+        while (more < want)
+            more <<= 1;
+        node->right = set_alloc(set, node->right,
+                                (size_t)more * sizeof(set_node_t *));
+        node->size = (i16_t)more;
+    }
+    int i;
+    if (fill)
+        for (i = node->fill; i < want; i++)
+            node->right[i] = set->head;
+    node->fill = (i16_t)want;
+}
+
+/* --private-- Return a new node. key is left uninitialized. */
+set_node_t *set_node(set_t *set) {
+    set_node_t *node = set_alloc(set, NULL, sizeof(set_node_t));
+    node->size = 0;
+    node->fill = 0;
+    node->right = NULL;
+    return node;
+}
+
+/* --private-- Free the list linked from head, along with the keys. */
+void set_sweep(set_t *set) {
+    set_node_t *step = set->head->right[0];
+    while (step != set->head) {
+        set_node_t *next = step->right[0];      /* save link to next node */
+        set_drop(set, step->key);
+        set_free(set, step->right);
+        set_free(set, step);
+        step = next;
+    }
+}
+
+/* Initialize a new set. set->env must be initialized using setjmp() before
+// set_start() is called. A longjmp(set->env, ENOMEM) will be used to handle a
+// memory allocation failure during any of the operations. (See setjmp.h and
+// errno.h.) The set can still be used if this happens, assuming that it didn't
+// happen during set_start(). Whether set_start() completed or not, set_end()
+// can be used to free the set's memory after a longjmp(). */
+void set_start(set_t *set) {
+#ifdef SET_TRACK
+    set->allocs = 0;
+    set->memory = 0;
+#endif
+    set->head = set->path = set->node = NULL;   /* in case set_node() fails */
+    set->path = set_node(set);
+    set->head = set_node(set);
+    set_grow(set, set->head, 1, 1); /* one link back to head for an empty set */
+    *(unsigned char *)&set->head->key = 137;    /* set id */
+    set->depth = 0;
+    set_uniq(&set->gen, set);
+    set->ran = 1;
+}
+
+/* Return true if *set appears to be in a usable state. If *set has been zeroed
+// out, then set_ok(set) will be false and set_end(set) will be safe. */
+int set_ok(set_t *set) {
+    return set->head != NULL &&
+           set->head->right != NULL &&
+           *(unsigned char *)&set->head->key == 137;
+}
+
+/* Empty the set. This frees the memory used for the previous set contents.
+// After set_clear(), *set is ready for use, as if after a set_start(). */
+void set_clear(set_t *set) {
+    assert(set_ok(set) && "improper use");
+
+    /* Free all the keys and their nodes. */
+    set_sweep(set);
+
+    /* Leave the head and path allocations as is. Clear their contents, with
+    // head pointing to itself and setting depth to zero, for an empty set. */
+    set->head->right[0] = set->head;
+    set->head->fill = 1;
+    set->path->fill = 0;
+    set->depth = 0;
+}
+
+/* Done using the set -- free all allocations. The only operation on *set
+// permitted after this is set_start(). Though another set_end() would do no
+// harm. This can be done at any time after a set_start(), or after a longjmp()
+// on any allocation failure, including during a set_start(). */
+void set_end(set_t *set) {
+    if (set->head != NULL) {
+        /* Empty the set and free the head node. */
+        if (set->head->right != NULL) {
+            set_sweep(set);
+            set_free(set, set->head->right);
+        }
+        set_free(set, set->head);
+        set->head = NULL;
+    }
+    if (set->path != NULL) {
+        /* Free the path work area. */
+        set_free(set, set->path->right);
+        set_free(set, set->path);
+        set->path = NULL;
+    }
+    if (set->node != NULL) {
+        /* Free the node that was under construction when longjmp() hit. */
+        set_drop(set, set->node->key);
+        set_free(set, set->node->right);
+        set_free(set, set->node);
+        set->node = NULL;
+    }
+}
+
+/* Look for key. Return 1 if found or 0 if not. This also puts the path to get
+// there in set->path, for use by set_insert(). */
+int set_found(set_t *set, set_key_t key) {
+    assert(set_ok(set) && "improper use");
+
+    /* Start at depth and work down and right as determined by key comparisons. */
+    set_node_t *head = set->head, *here = head;
+    int i = set->depth;
+    set_grow(set, set->path, i + 1, 0);
+    do {
+        while (here->right[i] != head &&
+               set_cmp(here->right[i]->key, key) < 0)
+            here = here->right[i];
+        set->path->right[i] = here;
+    } while (i--);
+
+    /* See if the key matches. */
+    here = here->right[0];
+    return here != head && set_cmp(here->key, key) == 0;
+}
+
+/* Insert the key key. Return 0 on success, or 1 if key is already in the set. */
+int set_insert(set_t *set, set_key_t key) {
+    assert(set_ok(set) && "improper use");
+
+    if (set_found(set, key))
+        /* That key is already in the set. */
+        return 1;
+
+    /* Randomly generate a new level-- level 0 with probability 1/2, 1 with
+    // probability 1/4, 2 with probability 1/8, etc. */
+    int level = 0;
+    for (;;) {
+        if (set->ran == 1)
+            /* Ran out. Get another 32 random bits. */
+            set->ran = set_rand(&set->gen) | (1ULL << 32);
+        int bit = set->ran & 1;
+        set->ran >>= 1;
+        if (bit)
+            break;
+        assert(level < 32767 &&
+               "Overhead, without any fuss, the stars were going out.");
+        level++;
+    }
+    if (level > set->depth) {
+        /* The maximum depth is now deeper. Update the structures. */
+        set_grow(set, set->path, level + 1, 1);
+        set_grow(set, set->head, level + 1, 1);
+        set->depth = (i16_t)level;
+    }
+
+    /* Make a new node for the provided key, and insert it in the lists up to
+    // and including level. */
+    set->node = set_node(set);
+    set->node->key = key;
+    set_grow(set, set->node, level + 1, 0);
+    int i;
+    for (i = 0; i <= level; i++) {
+        set->node->right[i] = set->path->right[i]->right[i];
+        set->path->right[i]->right[i] = set->node;
+    }
+    set->node = NULL;
+    return 0;
+}
+
+#else
+#error ** another skiplist set already created here
+/* Would need to implement a prefix in order to support multiple sets. */
+#endif
--- a/OrthancFramework/Resources/ThirdParty/minizip/unzip.c	Fri Feb 20 15:41:05 2026 +0100
+++ b/OrthancFramework/Resources/ThirdParty/minizip/unzip.c	Fri Feb 20 16:03:16 2026 +0100
@@ -1,14 +1,13 @@
 /* unzip.c -- IO for uncompress .zip files using zlib
-   Version 1.1, February 14h, 2010
-   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+   part of the MiniZip project - ( https://www.winimage.com/zLibDll/minizip.html )
 
-         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+         Copyright (C) 1998-2026 Gilles Vollant (minizip) ( https://www.winimage.com/zLibDll/minizip.html )
 
          Modifications of Unzip for Zip64
          Copyright (C) 2007-2008 Even Rouault
 
          Modifications for Zip64 support on both zip and unzip
-         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+         Copyright (C) 2009-2010 Mathias Svensson ( https://result42.com )
 
          For more info read MiniZip_info.txt
 
@@ -68,10 +67,9 @@
 #include <stdlib.h>
 #include <string.h>
 
-#ifndef NOUNCRYPT
-        #define NOUNCRYPT
+#ifdef ZLIB_DLL
+#  undef ZLIB_DLL
 #endif
-
 #include "zlib.h"
 #include "unzip.h"
 
@@ -92,7 +90,7 @@
 
 
 #ifndef CASESENSITIVITYDEFAULT_NO
-#  if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES)
+#  if (!defined(__unix__) && !defined(__unix) || defined(__CYGWIN__))  && !defined(CASESENSITIVITYDEFAULT_YES)
 #    define CASESENSITIVITYDEFAULT_NO
 #  endif
 #endif
@@ -115,9 +113,9 @@
 
 
 const char unz_copyright[] =
-   " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
+   " unzip 1.01 Copyright 1998-2004 Gilles Vollant - https://www.winimage.com/zLibDll/minizip.html";
 
-/* unz_file_info_interntal contain internal info about a file in zipfile*/
+/* unz_file_info64_internal contain internal info about a file in zipfile*/
 typedef struct unz_file_info64_internal_s
 {
     ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */
@@ -450,7 +448,7 @@
     if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
         return CENTRALDIRINVALID;
 
-    /* number of the disk with the start of the zip64 end of  central directory */
+    /* number of the disk with the start of the zip64 end of central directory */
     if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
         return CENTRALDIRINVALID;
     if (uL != 0)
@@ -497,9 +495,9 @@
     ZPOS64_T central_pos;
     uLong   uL;
 
-    uLong number_disk;          /* number of the current dist, used for
+    uLong number_disk;          /* number of the current disk, used for
                                    spanning ZIP, unsupported, always 0*/
-    uLong number_disk_with_CD;  /* number the the disk with central dir, used
+    uLong number_disk_with_CD;  /* number the disk with central dir, used
                                    for spanning ZIP, unsupported, always 0*/
     ZPOS64_T number_entry_CD;      /* total number of entries in
                                    the central dir
@@ -687,6 +685,7 @@
     {
         zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
         zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+        zlib_filefunc64_32_def_fill.zopen32_file = NULL;
         zlib_filefunc64_32_def_fill.ztell32_file = NULL;
         zlib_filefunc64_32_def_fill.zseek32_file = NULL;
         return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 1);
@@ -846,7 +845,7 @@
     if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK)
         err=UNZ_ERRNO;
 
-                // relative offset of local header
+                /* relative offset of local header */
     if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
         err=UNZ_ERRNO;
     file_info_internal.offset_curfile = uL;
@@ -869,7 +868,7 @@
         lSeek -= uSizeRead;
     }
 
-    // Read extrafield
+    /* Read extrafield */
     if ((err==UNZ_OK) && (extraField!=NULL))
     {
         ZPOS64_T uSizeRead ;
@@ -900,7 +899,7 @@
     {
                                 uLong acc = 0;
 
-        // since lSeek now points to after the extra field we need to move back
+        /* since lSeek now points to after the extra field we need to move back */
         lSeek -= file_info.size_file_extra;
 
         if (lSeek!=0)
@@ -1529,10 +1528,10 @@
     file_in_zip64_read_info_s* pfile_in_zip_read_info;
     s=(unz64_s*)file;
     if (file==NULL)
-        return 0; //UNZ_PARAMERROR;
+        return 0; /* UNZ_PARAMERROR; */
     pfile_in_zip_read_info=s->pfile_in_zip_read;
     if (pfile_in_zip_read_info==NULL)
-        return 0; //UNZ_PARAMERROR;
+        return 0; /* UNZ_PARAMERROR; */
     return pfile_in_zip_read_info->pos_in_zipfile +
                          pfile_in_zip_read_info->byte_before_the_zipfile;
 }
@@ -1613,7 +1612,7 @@
                 uInt i;
                 for(i=0;i<uReadThis;i++)
                   pfile_in_zip_read_info->read_buffer[i] =
-                      zdecode(s->keys,s->pcrc_32_tab,
+                      (char)zdecode(s->keys,s->pcrc_32_tab,
                               pfile_in_zip_read_info->read_buffer[i]);
             }
 #            endif
@@ -1701,7 +1700,7 @@
             if (err!=BZ_OK)
               break;
 #endif
-        } // end Z_BZIP2ED
+        } /* end Z_BZIP2ED */
         else
         {
             ZPOS64_T uTotalOutBefore,uTotalOutAfter;
@@ -1944,7 +1943,7 @@
     unz64_s* s;
 
     if (file==NULL)
-          return 0; //UNZ_PARAMERROR;
+          return 0; /* UNZ_PARAMERROR; */
     s=(unz64_s*)file;
     if (!s->current_file_ok)
       return 0;
@@ -1958,7 +1957,7 @@
     ZPOS64_T offset64;
 
     if (file==NULL)
-          return 0; //UNZ_PARAMERROR;
+          return 0; /* UNZ_PARAMERROR; */
     offset64 = unzGetOffset64(file);
     return (uLong)offset64;
 }
--- a/OrthancFramework/Resources/ThirdParty/minizip/unzip.h	Fri Feb 20 15:41:05 2026 +0100
+++ b/OrthancFramework/Resources/ThirdParty/minizip/unzip.h	Fri Feb 20 16:03:16 2026 +0100
@@ -1,14 +1,13 @@
 /* unzip.h -- IO for uncompress .zip files using zlib
-   Version 1.1, February 14h, 2010
-   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+   part of the MiniZip project - ( https://www.winimage.com/zLibDll/minizip.html )
 
-         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+         Copyright (C) 1998-2026 Gilles Vollant (minizip) ( https://www.winimage.com/zLibDll/minizip.html )
 
          Modifications of Unzip for Zip64
          Copyright (C) 2007-2008 Even Rouault
 
          Modifications for Zip64 support on both zip and unzip
-         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+         Copyright (C) 2009-2010 Mathias Svensson ( https://result42.com )
 
          For more info read MiniZip_info.txt
 
@@ -70,6 +69,8 @@
 typedef voidp unzFile;
 #endif
 
+extern const char unz_copyright[];
+
 
 #define UNZ_OK                          (0)
 #define UNZ_END_OF_LIST_OF_FILE         (-100)
@@ -306,13 +307,17 @@
   Get Info about the current file
   if pfile_info!=NULL, the *pfile_info structure will contain some info about
         the current file
-  if szFileName!=NULL, the filemane string will be copied in szFileName
+  if szFileName!=NULL, the filename string will be copied in szFileName
             (fileNameBufferSize is the size of the buffer)
   if extraField!=NULL, the extra field information will be copied in extraField
             (extraFieldBufferSize is the size of the buffer).
             This is the Central-header version of the extra field
   if szComment!=NULL, the comment string of the file will be copied in szComment
             (commentBufferSize is the size of the buffer)
+  The file name and comment will be zero-terminated if there is room in the
+  provided buffer. Otherwise the buffer will contain as much as will fit. If at
+  least 65537 bytes of room is provided, then the result will always be
+  complete and zero-terminated.
 */
 
 
--- a/OrthancFramework/Resources/ThirdParty/minizip/zip.c	Fri Feb 20 15:41:05 2026 +0100
+++ b/OrthancFramework/Resources/ThirdParty/minizip/zip.c	Fri Feb 20 16:03:16 2026 +0100
@@ -1,11 +1,10 @@
 /* zip.c -- IO on .zip files using zlib
-   Version 1.1, February 14h, 2010
-   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+   part of the MiniZip project - ( https://www.winimage.com/zLibDll/minizip.html )
 
-         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+         Copyright (C) 1998-2026 Gilles Vollant (minizip) ( https://www.winimage.com/zLibDll/minizip.html )
 
          Modifications for Zip64 support
-         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+         Copyright (C) 2009-2010 Mathias Svensson ( https://result42.com )
 
          For more info read MiniZip_info.txt
 
@@ -25,8 +24,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <stdint.h>
 #include <time.h>
+#ifndef ZLIB_CONST
+#  define ZLIB_CONST
+#endif
+#ifdef ZLIB_DLL
+#  undef ZLIB_DLL
+#endif
 #include "zlib.h"
 #include "zip.h"
 
@@ -50,7 +54,7 @@
 #endif
 
 #ifndef Z_BUFSIZE
-#define Z_BUFSIZE (64*1024) //(16384)
+#define Z_BUFSIZE (64*1024) /* (16384) */
 #endif
 
 #ifndef Z_MAXFILENAMEINZIP
@@ -69,7 +73,7 @@
 /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
 
 
-// NOT sure that this work on ALL platform
+/* NOT sure that this work on ALL platform */
 #define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32))
 
 #ifndef SEEK_CUR
@@ -91,7 +95,7 @@
 #  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
 #endif
 #endif
-const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
+const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - https://www.winimage.com/zLibDll/minizip.html";
 
 
 #define SIZEDATA_INDATABLOCK (4096-(4*4))
@@ -123,6 +127,19 @@
 } linkedlist_data;
 
 
+/* zipAlreadyThere() set functions for a set of zero-terminated strings, and
+// a block_t type for reading the central directory datablocks. */
+typedef char *set_key_t;
+#define set_cmp(a, b) strcmp(a, b)
+#define set_drop(s, k) set_free(s, k)
+#include "skipset.h"
+typedef struct {
+    unsigned char *next;        /* next byte in datablock data */
+    size_t left;                /* number of bytes left in data (at least) */
+    linkedlist_datablock_internal *node;    /* current datablock */
+} block_t;
+
+
 typedef struct
 {
     z_stream stream;            /* zLib stream structure for inflate */
@@ -174,6 +191,10 @@
     char *globalcomment;
 #endif
 
+    /* Support for zipAlreadyThere(). */
+    set_t set;              /* set for detecting name collisions */
+    block_t block;          /* block for reading the central directory */
+
 } zip64_internal;
 
 
@@ -264,6 +285,229 @@
     return ZIP_OK;
 }
 
+/* zipAlreadyThere() operations. "set" in the zip internal structure keeps the
+// set of names that are in the under-construction central directory so far. A
+// skipset provides ~O(log n) time insertion and searching. Central directory
+// records, stored in a linked list of allocated memory datablocks, is read
+// through "block" in the zip internal structure.
+
+// The block_*() functions support extracting the central directory file names
+// from the datablocks. They are designed to support a growing directory by
+// automatically continuing once more data has been appended to the linked
+// datablocks.
+
+// Initialize *block to the head of list. This should only be called once the
+// list has at least some data in it, i.e. list->first_block is not NULL. */
+local void block_init(block_t *block, linkedlist_data *list) {
+    block->node = list->first_block;
+    block->next = block->node->data;
+    block->left = block->node->filled_in_this_block;
+}
+
+/* Mark *block as bad, with all subsequent reads returning end, even if more
+// data is added to the datablocks. This is invoked if the central directory is
+// invalid, so there is no longer any point in attempting to interpret it. */
+local void block_stop(block_t *block) {
+    block->left = 0;
+    block->next = NULL;
+}
+
+/* Return true if *block has reached the end of the data in the datablocks. */
+local int block_end(block_t *block) {
+    linkedlist_datablock_internal *node = block->node;
+    if (node == NULL)
+        /* This block was previously terminated with extreme prejudice. */
+        return 1;
+    if (block->next < node->data + node->filled_in_this_block)
+        /* There are more bytes to read in the current datablock. */
+        return 0;
+    while (node->next_datablock != NULL) {
+        if (node->filled_in_this_block != 0)
+            /* There are some bytes in a later datablock. */
+            return 0;
+        node = node->next_datablock;
+    }
+    /* Reached the end of the list of datablocks. There's nothing. */
+    return 1;
+}
+
+/* Return one byte from *block, or -1 if the end is reached. */
+local int block_get(block_t *block) {
+    while (block->left == 0) {
+        if (block->node == NULL)
+            /* We've been marked bad. Return end. */
+            return -1;
+        /* Update left in case more was filled in since we were last here. */
+        block->left = block->node->filled_in_this_block -
+                      (size_t)(block->next - block->node->data);
+        if (block->left != 0)
+            /* There was indeed more data appended in the current datablock. */
+            break;
+        if (block->node->next_datablock == NULL)
+            /* No more data here, and there is no next datablock. At the end. */
+            return -1;
+        /* Try the next datablock for more data. */
+        block->node = block->node->next_datablock;
+        block->next = block->node->data;
+        block->left = block->node->filled_in_this_block;
+    }
+    /* We have a byte to return. */
+    block->left--;
+    return *block->next++;
+}
+
+/* Return a 16-bit unsigned little-endian value from block, or a negative value
+// if the end is reached. */
+local long block_get2(block_t *block) {
+    int low = block_get(block);
+    int high = block_get(block);
+    return low < 0 || high < 0 ? -1 : low | ((long)high << 8);
+}
+
+/* Read up to len bytes from block into buf. Return the number of bytes read. */
+local size_t block_read(block_t *block, unsigned char *buf, size_t len) {
+    size_t need = len;
+    while (need) {
+        if (block->left == 0) {
+            /* Get a byte to update and step through the linked list as needed. */
+            int got = block_get(block);
+            if (got == -1)
+                /* Reached the end. */
+                break;
+            *buf++ = (unsigned char)got;
+            need--;
+            continue;
+        }
+        size_t take = need > block->left ? block->left : need;
+        memcpy(buf, block->next, take);
+        block->next += take;
+        block->left -= take;
+        buf += take;
+        need -= take;
+    }
+    return len - need;      /* return the number of bytes copied */
+}
+
+/* Skip n bytes in block. Return 0 on success or -1 if there are less than n
+// bytes to the end. */
+local int block_skip(block_t *block, size_t n) {
+    while (n > block->left) {
+        n -= block->left;
+        block->next += block->left;
+        block->left = 0;
+        if (block_get(block) == -1)
+            return -1;
+        n--;
+    }
+    block->next += n;
+    block->left -= n;
+    return 0;
+}
+
+/* Process the next central directory record at *block. Return the allocated,
+// zero-terminated file name, or NULL for end of input or invalid data. If
+// invalid, *block is marked bad. This uses *set for the allocation of memory. */
+local char *block_central_name(block_t *block, set_t *set) {
+    char *name = NULL;
+    for (;;) {
+        if (block_end(block))
+            /* At the end of the central directory (so far). */
+            return NULL;
+
+        /* Check for a central directory record signature. */
+        if (block_get2(block) != (CENTRALHEADERMAGIC & 0xffff) ||
+            block_get2(block) != (CENTRALHEADERMAGIC >> 16))
+            /* Incorrect signature. */
+            break;
+
+        /* Go through the remaining fixed-length portion of the record,
+        // extracting the lengths of the three variable-length fields. */
+        block_skip(block, 24);
+        unsigned flen = (unsigned)block_get2(block);    /* file name length */
+        unsigned xlen = (unsigned)block_get2(block);    /* extra length */
+        unsigned clen = (unsigned)block_get2(block);    /* comment length */
+        if (block_skip(block, 12) == -1)
+            /* Premature end of the record. */
+            break;
+
+        /* Extract the name and skip over the extra and comment fields. */
+        name = set_alloc(set, NULL, flen + 1);
+        if (block_read(block, (unsigned char *)name, flen) < flen ||
+            block_skip(block, xlen + clen) == -1)
+            /* Premature end of the record. */
+            break;
+
+        /* Check for embedded nuls in the name. */
+        if (memchr(name, 0, flen) != NULL) {
+            /* This name can never match the zero-terminated name provided to
+            // zipAlreadyThere(), so we discard it and go back to get another
+            // name. (Who the heck is putting nuls inside their zip file entry
+            // names anyway?) */
+            set_free(set, name);
+            continue;
+        }
+
+        /* All good. Return the zero-terminated file name. */
+        name[flen] = 0;
+        return name;
+    }
+
+    /* Invalid signature or premature end of the central directory record.
+    // Abandon trying to process the central directory. */
+    set_free(set, name);
+    block_stop(block);
+    return NULL;
+}
+
+/* Return 0 if name is not in the central directory so far, 1 if it is, -1 if
+// the central directory is invalid, -2 if out of memory, or ZIP_PARAMERROR if
+// file is NULL. */
+extern int ZEXPORT zipAlreadyThere(zipFile file, char const *name) {
+    zip64_internal *zip = file;
+    if (zip == NULL)
+        return ZIP_PARAMERROR;
+    if (zip->central_dir.first_block == NULL)
+        /* No central directory yet, so no, name isn't there. */
+        return 0;
+    if (setjmp(zip->set.env)) {
+        /* Memory allocation failure. */
+        set_end(&zip->set);
+        return -2;
+    }
+    if (!set_ok(&zip->set)) {
+        /* This is the first time here with some central directory content. We
+        // construct this set of names only on demand. Prepare set and block. */
+        set_start(&zip->set);
+        block_init(&zip->block, &zip->central_dir);
+    }
+
+    /* Update the set of names from the current central directory contents.
+    // This reads any new central directory records since the last time we were
+    // here. */
+    for (;;) {
+        char *there = block_central_name(&zip->block, &zip->set);
+        if (there == NULL) {
+            if (zip->block.next == NULL)
+                /* The central directory is invalid. */
+                return -1;
+            break;
+        }
+
+        /* Add there to the set. */
+        if (set_insert(&zip->set, there))
+            /* There's already a duplicate in the central directory! We'll just
+            // let this be and carry on. */
+            set_free(&zip->set, there);
+    }
+
+    /* Return true if name is in the central directory. */
+    size_t len = strlen(name);
+    char *copy = set_alloc(&zip->set, NULL, len + 1);
+    memcpy(copy, name, len + 1);
+    int found = set_found(&zip->set, copy);
+    set_free(&zip->set, copy);
+    return found;
+}
 
 
 /****************************************************************************/
@@ -551,7 +795,7 @@
 
     for (i=(int)uReadSize-3; (i--)>0;)
     {
-      // Signature "0x07064b50" Zip64 end of central directory locater
+      /* Signature "0x07064b50" Zip64 end of central directory locator */
       if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))
       {
         uPosFound = uReadPos+(unsigned)i;
@@ -575,7 +819,7 @@
   if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
     return 0;
 
-  /* number of the disk with the start of the zip64 end of  central directory */
+  /* number of the disk with the start of the zip64 end of central directory */
   if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
     return 0;
   if (uL != 0)
@@ -599,7 +843,7 @@
   if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
     return 0;
 
-  if (uL != 0x06064b50) // signature of 'Zip64 end of central directory'
+  if (uL != 0x06064b50) /* signature of 'Zip64 end of central directory' */
     return 0;
 
   return relativeOffset;
@@ -628,7 +872,7 @@
 
   int hasZIP64Record = 0;
 
-  // check first if we find a ZIP64 record
+  /* check first if we find a ZIP64 record */
   central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream);
   if(central_pos > 0)
   {
@@ -694,13 +938,13 @@
     if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK)
       err=ZIP_ERRNO;
 
-    // TODO..
-    // read the comment from the standard central header.
+    /* TODO..
+    // read the comment from the standard central header. */
     size_comment = 0;
   }
   else
   {
-    // Read End of central Directory info
+    /* Read End of central Directory info */
     if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
       err=ZIP_ERRNO;
 
@@ -843,6 +1087,7 @@
     ziinit.number_entry = 0;
     ziinit.add_position_when_writing_offset = 0;
     init_linkedlist(&(ziinit.central_dir));
+    memset(&ziinit.set, 0, sizeof(set_t));  /* make sure set appears dormant */
 
 
 
@@ -858,7 +1103,7 @@
     ziinit.globalcomment = NULL;
     if (append == APPEND_STATUS_ADDINZIP)
     {
-      // Read and Cache Central Directory Records
+      /* Read and Cache Central Directory Records */
       err = LoadCentralDirectoryRecord(&ziinit);
     }
 
@@ -899,6 +1144,7 @@
     {
         zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
         zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+        zlib_filefunc64_32_def_fill.zopen32_file = NULL;
         zlib_filefunc64_32_def_fill.ztell32_file = NULL;
         zlib_filefunc64_32_def_fill.zseek32_file = NULL;
         return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill);
@@ -942,7 +1188,7 @@
   if (err==ZIP_OK)
     err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4);
 
-  // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later
+  /* CRC / Compressed size / Uncompressed size will be filled in later and rewritten later */
   if (err==ZIP_OK)
     err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */
   if (err==ZIP_OK)
@@ -986,13 +1232,13 @@
 
   if ((err==ZIP_OK) && (zi->ci.zip64))
   {
-      // write the Zip64 extended info
+      /* write the Zip64 extended info */
       short HeaderID = 1;
       short DataSize = 16;
       ZPOS64_T CompressedSize = 0;
       ZPOS64_T UncompressedSize = 0;
 
-      // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file)
+      /* Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) */
       zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream);
 
       err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)HeaderID,2);
@@ -1005,6 +1251,46 @@
   return err;
 }
 
+/* Return the length of the UTF-8 code at str[0..len-1] in [1..4], or negative
+   if there is no valid UTF-8 code there. If negative, it is minus the number
+   of bytes examined in order to determine it was bad. Or if minus the return
+   code is one less than len, then at least one more byte than provided would
+   be needed to complete the code. */
+local int utf8len(unsigned char const *str, size_t len) {
+    return
+        len == 0 ? -1 :                         /* empty input */
+        str[0] < 0x80 ? 1 :                     /* good one-byte */
+        str[0] < 0xc0 ? -1 :                    /* bad first byte */
+        len < 2 || (str[1] >> 6) != 2 ? -2 :    /* missing or bad 2nd byte */
+        str[0] < 0xc2 ? -2 :                    /* overlong code */
+        str[0] < 0xe0 ? 2 :                     /* good two-byte */
+        len < 3 || (str[2] >> 6) != 2 ? -3 :    /* missing or bad 3rd byte */
+        str[0] == 0xe0 && str[1] < 0xa0 ? -3 :  /* overlong code */
+        str[0] < 0xf0 ? 3 :                     /* good three-byte */
+        len < 4 || (str[3] >> 6) != 2 ? -4 :    /* missing or bad 4th byte */
+        str[0] == 0xf0 && str[1] < 0x90 ? -4 :  /* overlong code */
+        str[0] < 0xf4 ||
+        (str[0] == 0xf4 && str[1] < 0x90) ? 4 : /* good four-byte */
+        -4;                                     /* code > 0x10ffff */
+}
+
+/* Return true if str[0..len-1] is valid UTF-8 *and* it contains at least one
+   code of two or more bytes. This is used to determine whether or not to set
+   bit 11 in the zip header flags. */
+local int isutf8(char const *str, size_t len) {
+    int utf8 = 0;
+    while (len) {
+        int code = utf8len((unsigned char const *)str, len);
+        if (code < 0)
+            return 0;
+        if (code > 1)
+            utf8 = 1;
+        str += code;
+        len -= (unsigned)code;
+    }
+    return utf8;
+}
+
 /*
  NOTE.
  When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped
@@ -1027,7 +1313,6 @@
     int err = ZIP_OK;
 
 #    ifdef NOCRYPT
-    (crcForCrypting);
     if (password != NULL)
         return ZIP_PARAMERROR;
 #    endif
@@ -1043,14 +1328,14 @@
       return ZIP_PARAMERROR;
 #endif
 
-    // The filename and comment length must fit in 16 bits.
+    /* The filename and comment length must fit in 16 bits. */
     if ((filename!=NULL) && (strlen(filename)>0xffff))
         return ZIP_PARAMERROR;
     if ((comment!=NULL) && (strlen(comment)>0xffff))
         return ZIP_PARAMERROR;
-    // The extra field length must fit in 16 bits. If the member also requires
+    /* The extra field length must fit in 16 bits. If the member also requires
     // a Zip64 extra block, that will also need to fit within that 16-bit
-    // length, but that will be checked for later.
+    // length, but that will be checked for later. */
     if ((size_extrafield_local>0xffff) || (size_extrafield_global>0xffff))
         return ZIP_PARAMERROR;
 
@@ -1092,6 +1377,9 @@
       zi->ci.flag |= 6;
     if (password != NULL)
       zi->ci.flag |= 1;
+    if (isutf8(filename, size_filename) &&
+        (size_comment == 0 || isutf8(comment, size_comment)))
+      zi->ci.flag |= (1 << 11);
 
     zi->ci.crc32 = 0;
     zi->ci.method = method;
@@ -1102,7 +1390,7 @@
     zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream);
 
     zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment;
-    zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data
+    zi->ci.size_centralExtraFree = 32; /* Extra space we have reserved in case we need to add ZIP64 extra info data */
 
     zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree);
 
@@ -1197,7 +1485,7 @@
         else if(zi->ci.method == Z_BZIP2ED)
         {
 #ifdef HAVE_BZIP2
-            // Init BZip stuff here
+            /* Init BZip stuff here */
           zi->ci.bstream.bzalloc = 0;
           zi->ci.bstream.bzfree = 0;
           zi->ci.bstream.opaque = (voidpf)0;
@@ -1399,7 +1687,7 @@
         if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
         {
           uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32;
-//          uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32;
+/*          uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; */
           err=BZ2_bzCompress(&zi->ci.bstream,  BZ_RUN);
 
           zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ;
@@ -1412,7 +1700,7 @@
     else
 #endif
     {
-      zi->ci.stream.next_in = (Bytef*)(uintptr_t)buf;
+      zi->ci.stream.next_in = buf;
       zi->ci.stream.avail_in = len;
 
       while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
@@ -1457,7 +1745,7 @@
                   zi->ci.pos_in_buffered_data += copy_this;
               }
           }
-      }// while(...)
+      }/* while(...) */
     }
 
     return err;
@@ -1563,7 +1851,7 @@
     compressed_size += zi->ci.crypt_header_size;
 #    endif
 
-    // update Current Item crc and sizes,
+    /* update Current Item crc and sizes, */
     if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff)
     {
       /*version Made by*/
@@ -1581,7 +1869,7 @@
     else
       zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/
 
-    /// set internal file attributes field
+    /* set internal file attributes field */
     if (zi->ci.stream.data_type == Z_ASCII)
         zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2);
 
@@ -1590,15 +1878,15 @@
     else
       zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/
 
-    // Add ZIP64 extra info field for uncompressed size
+    /* Add ZIP64 extra info field for uncompressed size */
     if(uncompressed_size >= 0xffffffff)
       datasize += 8;
 
-    // Add ZIP64 extra info field for compressed size
+    /* Add ZIP64 extra info field for compressed size */
     if(compressed_size >= 0xffffffff)
       datasize += 8;
 
-    // Add ZIP64 extra info field for relative offset to local file header of current file
+    /* Add ZIP64 extra info field for relative offset to local file header of current file */
     if(zi->ci.pos_local_header >= 0xffffffff)
       datasize += 8;
 
@@ -1608,16 +1896,16 @@
 
       if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree)
       {
-        // we can not write more data to the buffer that we have room for.
+        /* we cannot write more data to the buffer that we have room for. */
         return ZIP_BADZIPFILE;
       }
 
       p = zi->ci.central_header + zi->ci.size_centralheader;
 
-      // Add Extra Information Header for 'ZIP64 information'
-      zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID
+      /* Add Extra Information Header for 'ZIP64 information' */
+      zip64local_putValue_inmemory(p, 0x0001, 2); /* HeaderID */
       p += 2;
-      zip64local_putValue_inmemory(p, datasize, 2); // DataSize
+      zip64local_putValue_inmemory(p, datasize, 2); /* DataSize */
       p += 2;
 
       if(uncompressed_size >= 0xffffffff)
@@ -1638,13 +1926,13 @@
         p += 8;
       }
 
-      // Update how much extra free space we got in the memory buffer
+      /* Update how much extra free space we got in the memory buffer
       // and increase the centralheader size so the new ZIP64 fields are included
-      // ( 4 below is the size of HeaderID and DataSize field )
+      // ( 4 below is the size of HeaderID and DataSize field ) */
       zi->ci.size_centralExtraFree -= datasize + 4;
       zi->ci.size_centralheader += datasize + 4;
 
-      // Update the extra info size field
+      /* Update the extra info size field */
       zi->ci.size_centralExtra += datasize + 4;
       zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2);
     }
@@ -1656,7 +1944,7 @@
 
     if (err==ZIP_OK)
     {
-        // Update the LocalFileHeader with the new values.
+        /* Update the LocalFileHeader with the new values. */
 
         ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream);
 
@@ -1670,7 +1958,7 @@
         {
           if(zi->ci.pos_zip64extrainfo > 0)
           {
-            // Update the size in the ZIP64 extended field.
+            /* Update the size in the ZIP64 extended field. */
             if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0)
               err = ZIP_ERRNO;
 
@@ -1681,7 +1969,7 @@
               err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8);
           }
           else
-              err = ZIP_BADZIPFILE; // Caller passed zip64 = 0, so no room for zip64 info -> fatal
+              err = ZIP_BADZIPFILE; /* Caller passed zip64 = 0, so no room for zip64 info -> fatal */
         }
         else
         {
@@ -1735,7 +2023,7 @@
   err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4);
 
   if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */
-    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ?
+    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); /* why ZPOS64_T of this ? */
 
   if (err==ZIP_OK) /* version made by */
     err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);
@@ -1782,7 +2070,7 @@
   {
     {
       if(zi->number_entry >= 0xFFFF)
-        err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record
+        err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); /* use value in ZIP64 record */
       else
         err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
     }
@@ -1791,7 +2079,7 @@
   if (err==ZIP_OK) /* total number of entries in the central dir */
   {
     if(zi->number_entry >= 0xFFFF)
-      err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record
+      err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); /* use value in ZIP64 record */
     else
       err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
   }
@@ -1871,6 +2159,8 @@
     }
     free_linkedlist(&(zi->central_dir));
 
+    set_end(&zi->set);          /* set was zeroed, so this is safe */
+
     pos = centraldir_pos_inzip - zi->add_position_when_writing_offset;
     if(pos >= 0xffffffff || zi->number_entry >= 0xFFFF)
     {
@@ -1919,13 +2209,13 @@
     header = *(short*)p;
     dataSize = *(((short*)p)+1);
 
-    if( header == sHeader ) // Header found.
+    if( header == sHeader ) /* Header found. */
     {
-      p += dataSize + 4; // skip it. do not copy to temp buffer
+      p += dataSize + 4; /* skip it. do not copy to temp buffer */
     }
     else
     {
-      // Extra Info block should not be removed, So copy it to the temp buffer.
+      /* Extra Info block should not be removed, So copy it to the temp buffer. */
       memcpy(pTmp, p, dataSize + 4);
       p += dataSize + 4;
       size += dataSize + 4;
@@ -1935,14 +2225,14 @@
 
   if(size < *dataLen)
   {
-    // clean old extra info block.
+    /* clean old extra info block. */
     memset(pData,0, *dataLen);
 
-    // copy the new extra info block over the old
+    /* copy the new extra info block over the old */
     if(size > 0)
       memcpy(pData, pNewHeader, size);
 
-    // set the new extra info size
+    /* set the new extra info size */
     *dataLen = size;
 
     retVal = ZIP_OK;
--- a/OrthancFramework/Resources/ThirdParty/minizip/zip.h	Fri Feb 20 15:41:05 2026 +0100
+++ b/OrthancFramework/Resources/ThirdParty/minizip/zip.h	Fri Feb 20 16:03:16 2026 +0100
@@ -1,11 +1,10 @@
 /* zip.h -- IO on .zip files using zlib
-   Version 1.1, February 14h, 2010
-   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+   part of the MiniZip project - ( https://www.winimage.com/zLibDll/minizip.html )
 
-         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+         Copyright (C) 1998-2026 Gilles Vollant (minizip) ( https://www.winimage.com/zLibDll/minizip.html )
 
          Modifications for Zip64 support
-         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+         Copyright (C) 2009-2010 Mathias Svensson ( https://result42.com )
 
          For more info read MiniZip_info.txt
 
@@ -35,7 +34,7 @@
 
         See header of zip.h
 
-*/
+ */
 
 #ifndef _zip12_H
 #define _zip12_H
@@ -44,7 +43,7 @@
 extern "C" {
 #endif
 
-//#define HAVE_BZIP2
+/* #define HAVE_BZIP2 */
 
 #ifndef _ZLIB_H
 #include "zlib.h"
@@ -69,6 +68,8 @@
 typedef voidp zipFile;
 #endif
 
+extern const char zip_copyright[];
+
 #define ZIP_OK                          (0)
 #define ZIP_EOF                         (0)
 #define ZIP_ERRNO                       (Z_ERRNO)
@@ -127,12 +128,12 @@
      If the zipfile cannot be opened, the return value is NULL.
      Else, the return value is a zipFile Handle, usable with other function
        of this zip package.
-*/
+ */
 
 /* Note : there is no delete function into a zipfile.
    If you want delete file into a zipfile, you must open a zipfile, and create another
    Of course, you can use RAW reading and writing to copy the file you did not want delete
-*/
+ */
 
 extern zipFile ZEXPORT zipOpen2(const char *pathname,
                                 int append,
@@ -186,7 +187,7 @@
   zip64 is set to 1 if a zip64 extended information block should be added to the local file header.
                     this MUST be '1' if the uncompressed size is >= 0xffffffff.
 
-*/
+ */
 
 
 extern int ZEXPORT zipOpenNewFileInZip2(zipFile file,
@@ -311,12 +312,12 @@
                                        unsigned len);
 /*
   Write data in the zipfile
-*/
+ */
 
 extern int ZEXPORT zipCloseFileInZip(zipFile file);
 /*
   Close the current file in the zipfile
-*/
+ */
 
 extern int ZEXPORT zipCloseFileInZipRaw(zipFile file,
                                         uLong uncompressed_size,
@@ -326,17 +327,23 @@
                                           ZPOS64_T uncompressed_size,
                                           uLong crc32);
 
+extern int ZEXPORT zipAlreadyThere(zipFile file,
+                                   char const* name);
+/*
+  See if name is already in file's central directory.
+ */
+
 /*
   Close the current file in the zipfile, for file opened with
     parameter raw=1 in zipOpenNewFileInZip2
   uncompressed_size and crc32 are value for the uncompressed size
-*/
+ */
 
 extern int ZEXPORT zipClose(zipFile file,
                             const char* global_comment);
 /*
   Close the zipfile
-*/
+ */
 
 
 extern int ZEXPORT zipRemoveExtraInfoBlock(char* pData, int* dataLen, short sHeader);
@@ -355,7 +362,7 @@
 
                         Remove ZIP64 Extra information from a Local File Header extra field data
         zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001);
-*/
+ */
 
 #ifdef __cplusplus
 }