summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay Kumar Dubey <akshaymani513@gmail.com>2025-04-16 02:05:16 +0530
committerCaolán McNamara <caolan.mcnamara@collabora.com>2025-05-01 12:18:19 +0200
commitb410749d30ed167f5bf0da6491d72e55f596cd41 (patch)
tree915998c6a88a9af816f7cdfade64ee641ad71b11
parent55169df2f6e4f8deb9c042b81cc3ff4f01cbf522 (diff)
tdf#137308 - Add zstd build support and decompression classes
Integrate build system support for the Zstandard (zstd) library and implement the corresponding C++ decompression stream classes, enabling future use of zstd-compressed streams in ZIP packages. Build System (Part 2a): - Add `--with-system-zstd=[yes|no|auto]` configure option. - Implement system library checks (`zstd.h`, `libzstd`) in configure.ac. - Define rules (`external/zstd/*`) for downloading and building the internal zstd static library (decompression components only). - Set up necessary CFLAGS/LIBS via configure.ac and config_host.mk.in. - Configure linking via RepositoryExternal.mk (`gb_LinkTarget__use_zstd`). - Update auxiliary files (download.lst, distro-configs, etc.). C++ Implementation (Part 2b): - Implement `InflateZstd` (in `include/package`) and `InflaterBytesZstd` (in `package/inc`) inheriting from `Inflater`/`InflaterBytes`. - Use the zstd streaming API (`ZSTD_decompressStream`) following the existing single-call pattern established by the zlib implementation. - Manage context (`ZSTD_DCtx`) and input buffer (`ZSTD_inBuffer`) state. - Handle errors, stream completion (`ret == 0`), and input truncation. - Add new classes to `package/Library_package2.mk` build. This completes the infrastructure for zstd decompression support. The next step (Part 2c) involves adding logic to select the appropriate Inflater based on the ZIP entry's compression method ID. Change-Id: Ia673f3f19b6a751ba5225394fcf8c3f145c4ae63 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184243 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
-rw-r--r--Makefile.fetch1
-rw-r--r--RepositoryExternal.mk17
-rwxr-xr-xbin/oss-fuzz-setup.sh1
-rw-r--r--config_host.mk.in3
-rw-r--r--configure.ac51
-rw-r--r--distro-configs/CPLinux-LOKit.conf1
-rw-r--r--distro-configs/Jenkins/LibreOfficeLinuxUpdater.conf1
-rw-r--r--distro-configs/LibreOfficeLinux.conf1
-rw-r--r--distro-configs/LibreOfficeOnline.conf1
-rw-r--r--distro-configs/LibreOfficeOpenBSD.conf1
-rw-r--r--download.lst5
-rw-r--r--external/Module_external.mk1
-rw-r--r--external/zstd/Makefile14
-rw-r--r--external/zstd/Module_zstd.mk17
-rw-r--r--external/zstd/StaticLibrary_zstd.mk41
-rw-r--r--external/zstd/UnpackedTarball_zstd.mk14
-rw-r--r--include/package/InflateZstd.hxx48
-rw-r--r--package/Library_package2.mk3
-rw-r--r--package/inc/InflaterBytesZstd.hxx43
-rw-r--r--package/source/zipapi/InflateZstd.cxx94
-rw-r--r--package/source/zipapi/InflaterBytesZstd.cxx82
21 files changed, 440 insertions, 0 deletions
diff --git a/Makefile.fetch b/Makefile.fetch
index f96fc16f8926..7c8d45f07a01 100644
--- a/Makefile.fetch
+++ b/Makefile.fetch
@@ -240,6 +240,7 @@ $(WORKDIR)/download: $(BUILDDIR)/config_$(gb_Side).mk $(SRCDIR)/download.lst $(S
$(call fetch_Optional,WPS,WPS_TARBALL) \
$(call fetch_Optional,XSLTML,XSLTML_TARBALL) \
$(call fetch_Optional,ZLIB,ZLIB_TARBALL) \
+ $(call fetch_Optional,ZSTD,ZSTD_TARBALL) \
$(call fetch_Optional,ZMF,ZMF_TARBALL) \
,$(call fetch_Download_item,https://dev-www.libreoffice.org/src,$(item)))
$(foreach item, \
diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk
index ff4c86ba3b33..f16521c50d7d 100644
--- a/RepositoryExternal.mk
+++ b/RepositoryExternal.mk
@@ -409,6 +409,23 @@ endef
endif # SYSTEM_ZLIB
+ifneq ($(SYSTEM_ZSTD),)
+ define gb_LinkTarget__use_zstd
+ $(call gb_LinkTarget_add_libs,$(1),-lzstd)
+ endef
+
+ gb_ExternalProject__use_zstd :=
+else
+ define gb_LinkTarget__use_zstd
+ $(call gb_LinkTarget_set_include,$(1),$(ZSTD_CFLAGS) $$(INCLUDE))
+ $(call gb_LinkTarget_use_static_libraries,$(1),zstd)
+ endef
+
+ define gb_ExternalProject__use_zstd
+ $(call gb_ExternalProject_use_static_libraries,$(1),zstd)
+ endef
+endif
+
ifneq ($(SYSTEM_LIBJPEG),)
diff --git a/bin/oss-fuzz-setup.sh b/bin/oss-fuzz-setup.sh
index 565f972948e2..4df82dd0e050 100755
--- a/bin/oss-fuzz-setup.sh
+++ b/bin/oss-fuzz-setup.sh
@@ -53,6 +53,7 @@ curl --no-progress-meter -S \
-C - -O https://dev-www.libreoffice.org/src/$ZMF_TARBALL \
-C - -O https://dev-www.libreoffice.org/src/$PIXMAN_TARBALL \
-C - -O https://dev-www.libreoffice.org/src/$ZLIB_TARBALL \
+ -C - -O https://dev-www.libreoffice.org/src/$ZSTD_TARBALL \
-C - -O https://dev-www.libreoffice.org/src/$MDDS_TARBALL \
-C - -O https://dev-www.libreoffice.org/src/$OPENSSL_TARBALL \
-C - -O https://dev-www.libreoffice.org/src/$LANGTAGREG_TARBALL \
diff --git a/config_host.mk.in b/config_host.mk.in
index c210d78708a7..0a4d61f62875 100644
--- a/config_host.mk.in
+++ b/config_host.mk.in
@@ -736,6 +736,7 @@ SYSTEM_WPG=@SYSTEM_WPG@
SYSTEM_WPS=@SYSTEM_WPS@
SYSTEM_XMLSEC=@SYSTEM_XMLSEC@
SYSTEM_ZLIB=@SYSTEM_ZLIB@
+SYSTEM_ZSTD=@SYSTEM_ZSTD@
SYSTEM_ZMF=@SYSTEM_ZMF@
export SYSTEMD_ESCAPE=@SYSTEMD_ESCAPE@
export SYSTEMD_RUN=@SYSTEMD_RUN@
@@ -803,6 +804,8 @@ export XSLTPROC=@XSLTPROC@
export XVFB_RUN=@XVFB_RUN@
export ZLIB_CFLAGS=$(gb_SPACE)@ZLIB_CFLAGS@
export ZLIB_LIBS=$(gb_SPACE)@ZLIB_LIBS@
+ZSTD_CFLAGS=$(gb_SPACE)@ZSTD_CFLAGS@
+ZSTD_LIBS=$(gb_SPACE)@ZSTD_LIBS@
export ZMF_CFLAGS=$(gb_SPACE)@ZMF_CFLAGS@
export ZMF_LIBS=$(gb_SPACE)@ZMF_LIBS@
export GET_TASK_ALLOW_ENTITLEMENT=@GET_TASK_ALLOW_ENTITLEMENT@
diff --git a/configure.ac b/configure.ac
index 28364e612ee9..0bb64aabb9dd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2439,6 +2439,11 @@ AC_ARG_WITH(system-zlib,
[Use zlib already on system.]),,
[with_system_zlib=auto])
+AC_ARG_WITH(system-zstd,
+ AS_HELP_STRING([--with-system-zstd=@<:@yes|no|auto@:>@],
+ [Use zstd already on system [default=auto].]),,
+ [with_system_zstd=auto])
+
AC_ARG_WITH(system-jpeg,
AS_HELP_STRING([--with-system-jpeg],
[Use jpeg already on system.]),,
@@ -9858,6 +9863,52 @@ AC_SUBST(ZLIB_LIBS)
AC_SUBST(SYSTEM_ZLIB)
dnl ===================================================================
+dnl Check for system zstd
+dnl ===================================================================
+
+if test "x$with_system_zstd" = "xauto"; then
+ case "$_os" in
+ WINNT) with_system_zstd="$with_system_libs" ;; # follow system-libs on Windows
+ *) with_system_zstd="$with_system_libs" ;; # follow system-libs on Unix
+ esac
+fi
+
+AC_MSG_CHECKING([which zstd to use])
+case "$with_system_zstd" in
+ yes)
+ AC_MSG_RESULT([system])
+ SYSTEM_ZSTD=TRUE
+
+ AC_CHECK_HEADER([zstd.h], [],
+ [AC_MSG_ERROR([zstd.h not found. Install system zstd.])])
+
+ AC_CHECK_LIB([zstd], [ZSTD_createDStream],
+ [ ZSTD_LIBS="-lzstd"
+ ZSTD_CFLAGS="" ],
+ [ AC_MSG_ERROR([system zstd library not found or broken.]) ])
+ ;;
+
+ ""|no)
+ AC_MSG_RESULT([bundled])
+ SYSTEM_ZSTD=
+ ZSTD_LIBS=""
+ ZSTD_CFLAGS="-I\${WORKDIR}/UnpackedTarball/zstd/lib \
+ -I\${WORKDIR}/UnpackedTarball/zstd/lib/common \
+ -I\${WORKDIR}/UnpackedTarball/zstd/lib/decompress"
+ BUILD_TYPE="$BUILD_TYPE ZSTD"
+ ;;
+
+ *)
+ AC_MSG_ERROR([Invalid value for --with-system-zstd: $with_system_zstd])
+ ;;
+esac
+
+AC_SUBST(SYSTEM_ZSTD)
+AC_SUBST(ZSTD_LIBS)
+AC_SUBST(ZSTD_CFLAGS)
+AC_SUBST(BUILD_TYPE)
+
+dnl ===================================================================
dnl Check for system jpeg
dnl ===================================================================
AC_MSG_CHECKING([which libjpeg to use])
diff --git a/distro-configs/CPLinux-LOKit.conf b/distro-configs/CPLinux-LOKit.conf
index 321cb967b217..ef2a8638c57a 100644
--- a/distro-configs/CPLinux-LOKit.conf
+++ b/distro-configs/CPLinux-LOKit.conf
@@ -6,6 +6,7 @@
--with-system-dicts
--with-myspell-dicts
--with-system-zlib
+--with-system-zstd
--disable-poppler
--enable-cairo-rgba
--without-system-cairo
diff --git a/distro-configs/Jenkins/LibreOfficeLinuxUpdater.conf b/distro-configs/Jenkins/LibreOfficeLinuxUpdater.conf
index d9af64650eff..726044dbca49 100644
--- a/distro-configs/Jenkins/LibreOfficeLinuxUpdater.conf
+++ b/distro-configs/Jenkins/LibreOfficeLinuxUpdater.conf
@@ -3,6 +3,7 @@
--with-system-dicts
--with-myspell-dicts
--with-system-zlib
+--with-system-zstd
--without-system-poppler
--without-system-openssl
--without-system-libpng
diff --git a/distro-configs/LibreOfficeLinux.conf b/distro-configs/LibreOfficeLinux.conf
index fba02d362d31..9d5b511db944 100644
--- a/distro-configs/LibreOfficeLinux.conf
+++ b/distro-configs/LibreOfficeLinux.conf
@@ -1,6 +1,7 @@
--with-system-dicts
--with-myspell-dicts
--with-system-zlib
+--with-system-zstd
--without-system-poppler
--without-system-openssl
--without-system-libpng
diff --git a/distro-configs/LibreOfficeOnline.conf b/distro-configs/LibreOfficeOnline.conf
index b22639232b71..73b21a1dc530 100644
--- a/distro-configs/LibreOfficeOnline.conf
+++ b/distro-configs/LibreOfficeOnline.conf
@@ -37,6 +37,7 @@
--with-linker-hash-style=both
--with-system-dicts
--with-system-zlib
+--with-system-zstd
--with-theme=colibre
--without-branding
--without-help
diff --git a/distro-configs/LibreOfficeOpenBSD.conf b/distro-configs/LibreOfficeOpenBSD.conf
index 2af93a64202a..6933487102fd 100644
--- a/distro-configs/LibreOfficeOpenBSD.conf
+++ b/distro-configs/LibreOfficeOpenBSD.conf
@@ -26,6 +26,7 @@
--with-system-poppler
--with-system-redland
--with-system-zlib
+--with-system-zstd
--with-vendor=The OpenBSD project
--without-junit
--without-system-libwpd
diff --git a/download.lst b/download.lst
index b1c058e0ab98..931bd94cdfff 100644
--- a/download.lst
+++ b/download.lst
@@ -680,6 +680,11 @@ ZLIB_TARBALL := zlib-1.3.1.tar.xz
# three static lines
# so that git cherry-pick
# will not run into conflicts
+ZSTD_SHA256SUM := eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3
+ZSTD_TARBALL := zstd-1.5.7.tar.gz
+# three static lines
+# so that git cherry-pick
+# will not run into conflicts
ZMF_SHA256SUM := 27051a30cb057fdb5d5de65a1f165c7153dc76e27fe62251cbb86639eb2caf22
ZMF_TARBALL := libzmf-0.0.2.tar.xz
# three static lines
diff --git a/external/Module_external.mk b/external/Module_external.mk
index 1d4c53139cac..6390a3a7d95b 100644
--- a/external/Module_external.mk
+++ b/external/Module_external.mk
@@ -101,6 +101,7 @@ $(eval $(call gb_Module_add_moduledirs,external,\
$(call gb_Helper_optional,WPS,libwps) \
$(call gb_Helper_optional,XSLTML,xsltml) \
$(call gb_Helper_optional,ZLIB,zlib) \
+ $(call gb_Helper_optional,ZSTD,zstd) \
$(call gb_Helper_optional,ZMF,libzmf) \
))
diff --git a/external/zstd/Makefile b/external/zstd/Makefile
new file mode 100644
index 000000000000..569ad8a0ba7a
--- /dev/null
+++ b/external/zstd/Makefile
@@ -0,0 +1,14 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST))))
+
+include $(module_directory)/../../solenv/gbuild/partial_build.mk
+
+# vim: set noet sw=4 ts=4:
diff --git a/external/zstd/Module_zstd.mk b/external/zstd/Module_zstd.mk
new file mode 100644
index 000000000000..a31acb767fc7
--- /dev/null
+++ b/external/zstd/Module_zstd.mk
@@ -0,0 +1,17 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Module_Module,zstd))
+
+$(eval $(call gb_Module_add_targets,zstd,\
+ StaticLibrary_zstd \
+ UnpackedTarball_zstd \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/external/zstd/StaticLibrary_zstd.mk b/external/zstd/StaticLibrary_zstd.mk
new file mode 100644
index 000000000000..c7ca142dabd0
--- /dev/null
+++ b/external/zstd/StaticLibrary_zstd.mk
@@ -0,0 +1,41 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_StaticLibrary_StaticLibrary,zstd))
+
+$(eval $(call gb_StaticLibrary_use_unpacked,zstd,zstd))
+
+$(eval $(call gb_StaticLibrary_set_warnings_disabled,zstd))
+
+$(eval $(call gb_StaticLibrary_set_include,zstd,\
+ -I$(gb_UnpackedTarball_workdir)/zstd/lib \
+ -I$(gb_UnpackedTarball_workdir)/zstd/lib/common \
+ -I$(gb_UnpackedTarball_workdir)/zstd/lib/decompress \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_StaticLibrary_add_generated_cobjects,zstd,\
+ UnpackedTarball/zstd/lib/common/entropy_common \
+ UnpackedTarball/zstd/lib/common/error_private \
+ UnpackedTarball/zstd/lib/common/fse_decompress \
+ UnpackedTarball/zstd/lib/common/xxhash \
+ UnpackedTarball/zstd/lib/common/zstd_common \
+ UnpackedTarball/zstd/lib/decompress/huf_decompress \
+ UnpackedTarball/zstd/lib/decompress/zstd_ddict \
+ UnpackedTarball/zstd/lib/decompress/zstd_decompress \
+ UnpackedTarball/zstd/lib/decompress/zstd_decompress_block \
+))
+
+$(eval $(call gb_StaticLibrary_add_cflags,zstd,-DZSTD_DISABLE_ASM))
+
+ifeq ($(ENABLE_DEBUG),TRUE)
+$(eval $(call gb_StaticLibrary_add_cflags,zstd,-DZSTD_DEBUG=1))
+endif
+
+# vim: set noet sw=4 ts=4:
diff --git a/external/zstd/UnpackedTarball_zstd.mk b/external/zstd/UnpackedTarball_zstd.mk
new file mode 100644
index 000000000000..7770ffe1add0
--- /dev/null
+++ b/external/zstd/UnpackedTarball_zstd.mk
@@ -0,0 +1,14 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_UnpackedTarball_UnpackedTarball,zstd))
+
+$(eval $(call gb_UnpackedTarball_set_tarball,zstd,$(ZSTD_TARBALL)))
+
+# vim: set noet sw=4 ts=4:
diff --git a/include/package/InflateZstd.hxx b/include/package/InflateZstd.hxx
new file mode 100644
index 000000000000..36cb0b15405c
--- /dev/null
+++ b/include/package/InflateZstd.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <memory>
+#include <package/Inflater.hxx>
+#include <zstd.h>
+#include <zstd_errors.h>
+
+namespace ZipUtils
+{
+class DLLPUBLIC_PACKAGE InflateZstd : public Inflater
+{
+private:
+ bool bFinished;
+ bool bNeedDict;
+ sal_Int32 nLastInflateError;
+ css::uno::Sequence<sal_Int8> sInBuffer;
+ ZSTD_DCtx* pDCtx;
+ ZSTD_inBuffer inBuffer;
+ bool bStreamInitialized;
+
+ sal_Int32 doInflateBytes(css::uno::Sequence<sal_Int8>& rBuffer, sal_Int32 nNewOffset,
+ sal_Int32 nNewLength);
+
+public:
+ explicit InflateZstd(bool bNoWrap = false);
+ virtual ~InflateZstd() override;
+
+ virtual void setInput(const css::uno::Sequence<sal_Int8>& rBuffer) override;
+ virtual bool needsDictionary() const override { return bNeedDict; }
+ virtual bool finished() const override { return bFinished; }
+ virtual sal_Int32 doInflateSegment(css::uno::Sequence<sal_Int8>& rBuffer, sal_Int32 nNewOffset,
+ sal_Int32 nNewLength) override;
+ virtual void end() override final;
+ virtual sal_Int32 getLastInflateError() const override { return nLastInflateError; }
+};
+
+} // namespace ZipUtils
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/package/Library_package2.mk b/package/Library_package2.mk
index a740d33fc757..bb7f36eb802f 100644
--- a/package/Library_package2.mk
+++ b/package/Library_package2.mk
@@ -43,6 +43,7 @@ $(eval $(call gb_Library_use_libraries,package2,\
$(eval $(call gb_Library_use_externals,package2,\
argon2 \
zlib \
+ zstd \
))
$(eval $(call gb_Library_add_exception_objects,package2,\
@@ -56,7 +57,9 @@ $(eval $(call gb_Library_add_exception_objects,package2,\
package/source/zipapi/CRC32 \
package/source/zipapi/Deflater \
package/source/zipapi/InflaterBytesZlib \
+ package/source/zipapi/InflaterBytesZstd \
package/source/zipapi/InflateZlib \
+ package/source/zipapi/InflateZstd \
package/source/zipapi/sha1context \
package/source/zipapi/ThreadedDeflater \
package/source/zipapi/XBufferedThreadedStream \
diff --git a/package/inc/InflaterBytesZstd.hxx b/package/inc/InflaterBytesZstd.hxx
new file mode 100644
index 000000000000..96cf73baf5fe
--- /dev/null
+++ b/package/inc/InflaterBytesZstd.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <memory>
+#include <package/Inflater.hxx>
+#include <zstd.h>
+
+namespace ZipUtils
+{
+class DLLPUBLIC_PACKAGE InflaterBytesZstd : public InflaterBytes
+{
+private:
+ bool bFinished;
+ const sal_Int8* sInBuffer;
+ ZSTD_DCtx* pDCtx;
+ sal_Int32 nLastInflateError;
+ ZSTD_inBuffer inBuffer;
+ bool bStreamInitialized;
+
+ sal_Int32 doInflateBytes(sal_Int8* pOutBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength);
+
+public:
+ InflaterBytesZstd();
+ virtual ~InflaterBytesZstd() override;
+
+ virtual void setInput(const sal_Int8* pBuffer, sal_Int32 nLen) override;
+ virtual bool finished() const override { return bFinished; }
+ virtual sal_Int32 doInflateSegment(sal_Int8* pOutBuffer, sal_Int32 nBufLen,
+ sal_Int32 nNewOffset, sal_Int32 nNewLength) override;
+ virtual void end() override final;
+};
+
+} // namespace ZipUtils
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/package/source/zipapi/InflateZstd.cxx b/package/source/zipapi/InflateZstd.cxx
new file mode 100644
index 000000000000..16638417c569
--- /dev/null
+++ b/package/source/zipapi/InflateZstd.cxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <package/InflateZstd.hxx>
+#include <string.h>
+
+using namespace com::sun::star::uno;
+using namespace ZipUtils;
+
+InflateZstd::InflateZstd(bool)
+ : bFinished(false)
+ , bNeedDict(false)
+ , nLastInflateError(0)
+ , pDCtx(ZSTD_createDCtx())
+ , bStreamInitialized(false)
+{
+ if (!pDCtx)
+ {
+ nLastInflateError = static_cast<sal_Int32>(ZSTD_error_memory_allocation);
+ }
+ inBuffer = { nullptr, 0, 0 };
+}
+
+InflateZstd::~InflateZstd() { end(); }
+
+void InflateZstd::setInput(const Sequence<sal_Int8>& rBuffer)
+{
+ if (!pDCtx)
+ {
+ bStreamInitialized = false;
+ return;
+ }
+ sInBuffer = rBuffer;
+ inBuffer.src = sInBuffer.getConstArray();
+ inBuffer.size = sInBuffer.getLength();
+ inBuffer.pos = 0;
+ bStreamInitialized = true;
+}
+
+sal_Int32 InflateZstd::doInflateSegment(Sequence<sal_Int8>& rBuffer, sal_Int32 nNewOffset,
+ sal_Int32 nNewLength)
+{
+ if (nNewOffset < 0 || nNewLength < 0 || nNewOffset + nNewLength > rBuffer.getLength())
+ return 0;
+
+ return doInflateBytes(rBuffer, nNewOffset, nNewLength);
+}
+
+void InflateZstd::end()
+{
+ if (pDCtx)
+ {
+ ZSTD_freeDCtx(pDCtx);
+ pDCtx = nullptr;
+ }
+ bStreamInitialized = false;
+ inBuffer = { nullptr, 0, 0 };
+}
+
+sal_Int32 InflateZstd::doInflateBytes(Sequence<sal_Int8>& rBuffer, sal_Int32 nNewOffset,
+ sal_Int32 nNewLength)
+{
+ if (bFinished)
+ {
+ return 0;
+ }
+ if (!pDCtx || !bStreamInitialized)
+ {
+ nLastInflateError = 1;
+ return 0;
+ }
+ nLastInflateError = 0;
+ ZSTD_outBuffer outBuffer
+ = { rBuffer.getArray() + nNewOffset, static_cast<size_t>(nNewLength), 0 };
+ size_t ret = ZSTD_decompressStream(pDCtx, &outBuffer, &inBuffer);
+ if (ZSTD_isError(ret))
+ {
+ nLastInflateError = static_cast<sal_Int32>(ret);
+ ZSTD_DCtx_reset(pDCtx, ZSTD_reset_session_only);
+ return 0;
+ }
+ if (ret == 0)
+ bFinished = true;
+
+ return static_cast<sal_Int32>(outBuffer.pos);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/package/source/zipapi/InflaterBytesZstd.cxx b/package/source/zipapi/InflaterBytesZstd.cxx
new file mode 100644
index 000000000000..4236a58207df
--- /dev/null
+++ b/package/source/zipapi/InflaterBytesZstd.cxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <InflaterBytesZstd.hxx>
+#include <string.h>
+
+using namespace ZipUtils;
+
+InflaterBytesZstd::InflaterBytesZstd()
+ : bFinished(false)
+ , sInBuffer(nullptr)
+ , pDCtx(ZSTD_createDCtx())
+ , nLastInflateError(0)
+ , bStreamInitialized(false)
+{
+ inBuffer = { nullptr, 0, 0 };
+}
+
+InflaterBytesZstd::~InflaterBytesZstd() { end(); }
+
+void InflaterBytesZstd::setInput(const sal_Int8* rBuffer, sal_Int32 nBufLen)
+{
+ sInBuffer = rBuffer;
+ inBuffer.src = sInBuffer;
+ inBuffer.size = nBufLen;
+ inBuffer.pos = 0;
+ bStreamInitialized = true;
+}
+
+sal_Int32 InflaterBytesZstd::doInflateSegment(sal_Int8* pOutBuffer, sal_Int32 nBufLen,
+ sal_Int32 nNewOffset, sal_Int32 nNewLength)
+{
+ if (nNewOffset < 0 || nNewLength < 0 || nNewOffset + nNewLength > nBufLen)
+ return 0;
+
+ return doInflateBytes(pOutBuffer, nNewOffset, nNewLength);
+}
+
+void InflaterBytesZstd::end()
+{
+ if (pDCtx)
+ {
+ ZSTD_freeDCtx(pDCtx);
+ pDCtx = nullptr;
+ }
+ bStreamInitialized = false;
+ inBuffer = { nullptr, 0, 0 };
+}
+
+sal_Int32 InflaterBytesZstd::doInflateBytes(sal_Int8* pOutBuffer, sal_Int32 nNewOffset,
+ sal_Int32 nNewLength)
+{
+ if (!pDCtx || !bStreamInitialized)
+ return 0;
+
+ ZSTD_outBuffer outBuffer = { pOutBuffer + nNewOffset, static_cast<size_t>(nNewLength), 0 };
+ size_t ret = ZSTD_decompressStream(pDCtx, &outBuffer, &inBuffer);
+ if (ZSTD_isError(ret))
+ {
+ nLastInflateError = static_cast<sal_Int32>(ret);
+ ZSTD_DCtx_reset(pDCtx, ZSTD_reset_session_only);
+ return 0;
+ }
+ if (ret != 0)
+ {
+ ZSTD_DCtx_reset(pDCtx, ZSTD_reset_session_only);
+ return static_cast<sal_Int32>(outBuffer.pos);
+ }
+ if (ret == 0)
+ bFinished = true;
+ nLastInflateError = 0;
+
+ return static_cast<sal_Int32>(outBuffer.pos);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */