From dc16286bb48a82fdb67f965b9526a8dc79153437 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 18 Nov 2024 08:54:15 +0100 Subject: [PATCH] KArchive: Add KArchive library and its dependencies We want to include a reliable way to extract archives. KArchive is a library that provides a simple API for reading and writing archives. It will allow us to replace the current implementation of archive extraction which relies on the necessary tools (7zip, unzip, tar etc.) to be available on the users system. Since karchive is built on top of QFile if will also allow us to use it for reading and writing archives on remote devices. Change-Id: I390e0e786f2dd20ae85d16dab34f43510cdf82a6 Reviewed-by: Eike Ziller --- qt_attributions.json | 44 +- src/libs/3rdparty/CMakeLists.txt | 2 + .../karchive/3rdparty/bzip2/.gitattributes | 1 + .../karchive/3rdparty/bzip2/.gitignore | 9 + .../3rdparty/karchive/3rdparty/bzip2/CHANGES | 356 ++ .../3rdparty/karchive/3rdparty/bzip2/LICENSE | 42 + .../3rdparty/karchive/3rdparty/bzip2/README | 196 ++ .../bzip2/README.COMPILATION.PROBLEMS | 58 + .../karchive/3rdparty/bzip2/README.XML.STUFF | 45 + .../karchive/3rdparty/bzip2/README.qtcreator | 4 + .../karchive/3rdparty/bzip2/blocksort.c | 1094 ++++++ .../3rdparty/karchive/3rdparty/bzip2/bzip2.c | 2036 +++++++++++ .../karchive/3rdparty/bzip2/bzip2recover.c | 516 +++ .../3rdparty/karchive/3rdparty/bzip2/bzlib.c | 1572 +++++++++ .../3rdparty/karchive/3rdparty/bzip2/bzlib.h | 281 ++ .../karchive/3rdparty/bzip2/bzlib_private.h | 509 +++ .../karchive/3rdparty/bzip2/compress.c | 672 ++++ .../karchive/3rdparty/bzip2/crctable.c | 104 + .../karchive/3rdparty/bzip2/decompress.c | 652 ++++ .../karchive/3rdparty/bzip2/huffman.c | 205 ++ .../3rdparty/karchive/3rdparty/bzip2/mk251.c | 31 + .../karchive/3rdparty/bzip2/randtable.c | 84 + .../3rdparty/karchive/3rdparty/xz/AUTHORS | 58 + .../3rdparty/karchive/3rdparty/xz/COPYING | 83 + .../karchive/3rdparty/xz/COPYING.0BSD | 11 + .../karchive/3rdparty/xz/COPYING.GPLv2 | 339 ++ .../karchive/3rdparty/xz/COPYING.GPLv3 | 674 ++++ .../karchive/3rdparty/xz/COPYING.LGPLv2.1 | 502 +++ src/libs/3rdparty/karchive/3rdparty/xz/README | 310 ++ .../karchive/3rdparty/xz/README.qtcreator | 4 + src/libs/3rdparty/karchive/3rdparty/xz/THANKS | 202 ++ src/libs/3rdparty/karchive/3rdparty/xz/TODO | 105 + .../3rdparty/xz/src/common/mythread.h | 548 +++ .../karchive/3rdparty/xz/src/common/sysdefs.h | 199 ++ .../3rdparty/xz/src/common/tuklib_common.h | 90 + .../3rdparty/xz/src/common/tuklib_config.h | 12 + .../3rdparty/xz/src/common/tuklib_cpucores.c | 108 + .../3rdparty/xz/src/common/tuklib_cpucores.h | 22 + .../3rdparty/xz/src/common/tuklib_exit.c | 57 + .../3rdparty/xz/src/common/tuklib_exit.h | 24 + .../3rdparty/xz/src/common/tuklib_gettext.h | 43 + .../3rdparty/xz/src/common/tuklib_integer.h | 954 ++++++ .../3rdparty/xz/src/common/tuklib_mbstr.h | 65 + .../3rdparty/xz/src/common/tuklib_mbstr_fw.c | 30 + .../xz/src/common/tuklib_mbstr_width.c | 64 + .../xz/src/common/tuklib_open_stdxxx.c | 56 + .../xz/src/common/tuklib_open_stdxxx.h | 22 + .../3rdparty/xz/src/common/tuklib_physmem.c | 231 ++ .../3rdparty/xz/src/common/tuklib_physmem.h | 27 + .../3rdparty/xz/src/common/tuklib_progname.c | 49 + .../3rdparty/xz/src/common/tuklib_progname.h | 31 + .../xz/src/common/w32_application.manifest | 28 + .../w32_application.manifest.comments.txt | 178 + .../3rdparty/xz/src/liblzma/api/lzma.h | 327 ++ .../3rdparty/xz/src/liblzma/api/lzma/base.h | 747 ++++ .../3rdparty/xz/src/liblzma/api/lzma/bcj.h | 98 + .../3rdparty/xz/src/liblzma/api/lzma/block.h | 694 ++++ .../3rdparty/xz/src/liblzma/api/lzma/check.h | 163 + .../xz/src/liblzma/api/lzma/container.h | 995 ++++++ .../3rdparty/xz/src/liblzma/api/lzma/delta.h | 95 + .../3rdparty/xz/src/liblzma/api/lzma/filter.h | 769 +++++ .../xz/src/liblzma/api/lzma/hardware.h | 62 + .../3rdparty/xz/src/liblzma/api/lzma/index.h | 882 +++++ .../xz/src/liblzma/api/lzma/index_hash.h | 123 + .../3rdparty/xz/src/liblzma/api/lzma/lzma12.h | 568 ++++ .../xz/src/liblzma/api/lzma/stream_flags.h | 265 ++ .../xz/src/liblzma/api/lzma/version.h | 134 + .../3rdparty/xz/src/liblzma/api/lzma/vli.h | 166 + .../3rdparty/xz/src/liblzma/check/check.c | 173 + .../3rdparty/xz/src/liblzma/check/check.h | 174 + .../xz/src/liblzma/check/crc32_arm64.h | 122 + .../xz/src/liblzma/check/crc32_fast.c | 204 ++ .../xz/src/liblzma/check/crc32_small.c | 67 + .../xz/src/liblzma/check/crc32_table.c | 42 + .../xz/src/liblzma/check/crc32_table_be.h | 527 +++ .../xz/src/liblzma/check/crc32_table_le.h | 527 +++ .../xz/src/liblzma/check/crc32_tablegen.c | 120 + .../3rdparty/xz/src/liblzma/check/crc32_x86.S | 312 ++ .../xz/src/liblzma/check/crc64_fast.c | 156 + .../xz/src/liblzma/check/crc64_small.c | 57 + .../xz/src/liblzma/check/crc64_table.c | 37 + .../xz/src/liblzma/check/crc64_table_be.h | 523 +++ .../xz/src/liblzma/check/crc64_table_le.h | 523 +++ .../xz/src/liblzma/check/crc64_tablegen.c | 89 + .../3rdparty/xz/src/liblzma/check/crc64_x86.S | 295 ++ .../xz/src/liblzma/check/crc_common.h | 137 + .../xz/src/liblzma/check/crc_x86_clmul.h | 432 +++ .../3rdparty/xz/src/liblzma/check/sha256.c | 189 + .../xz/src/liblzma/common/alone_decoder.c | 248 ++ .../xz/src/liblzma/common/alone_decoder.h | 22 + .../xz/src/liblzma/common/alone_encoder.c | 151 + .../xz/src/liblzma/common/auto_decoder.c | 205 ++ .../src/liblzma/common/block_buffer_decoder.c | 79 + .../src/liblzma/common/block_buffer_encoder.c | 354 ++ .../src/liblzma/common/block_buffer_encoder.h | 23 + .../xz/src/liblzma/common/block_decoder.c | 288 ++ .../xz/src/liblzma/common/block_decoder.h | 21 + .../xz/src/liblzma/common/block_encoder.c | 226 ++ .../xz/src/liblzma/common/block_encoder.h | 46 + .../src/liblzma/common/block_header_decoder.c | 114 + .../src/liblzma/common/block_header_encoder.c | 131 + .../xz/src/liblzma/common/block_util.c | 89 + .../3rdparty/xz/src/liblzma/common/common.c | 480 +++ .../3rdparty/xz/src/liblzma/common/common.h | 412 +++ .../src/liblzma/common/easy_buffer_encoder.c | 26 + .../liblzma/common/easy_decoder_memusage.c | 23 + .../xz/src/liblzma/common/easy_encoder.c | 23 + .../liblzma/common/easy_encoder_memusage.c | 23 + .../xz/src/liblzma/common/easy_preset.c | 26 + .../xz/src/liblzma/common/easy_preset.h | 36 + .../xz/src/liblzma/common/file_info.c | 854 +++++ .../liblzma/common/filter_buffer_decoder.c | 87 + .../liblzma/common/filter_buffer_encoder.c | 54 + .../xz/src/liblzma/common/filter_common.c | 393 +++ .../xz/src/liblzma/common/filter_common.h | 50 + .../xz/src/liblzma/common/filter_decoder.c | 214 ++ .../xz/src/liblzma/common/filter_decoder.h | 22 + .../xz/src/liblzma/common/filter_encoder.c | 330 ++ .../xz/src/liblzma/common/filter_encoder.h | 22 + .../src/liblzma/common/filter_flags_decoder.c | 45 + .../src/liblzma/common/filter_flags_encoder.c | 55 + .../src/liblzma/common/hardware_cputhreads.c | 33 + .../xz/src/liblzma/common/hardware_physmem.c | 24 + .../3rdparty/xz/src/liblzma/common/index.c | 1268 +++++++ .../3rdparty/xz/src/liblzma/common/index.h | 80 + .../xz/src/liblzma/common/index_decoder.c | 372 ++ .../xz/src/liblzma/common/index_decoder.h | 24 + .../xz/src/liblzma/common/index_encoder.c | 262 ++ .../xz/src/liblzma/common/index_encoder.h | 22 + .../xz/src/liblzma/common/index_hash.c | 342 ++ .../xz/src/liblzma/common/lzip_decoder.c | 417 +++ .../xz/src/liblzma/common/lzip_decoder.h | 21 + .../xz/src/liblzma/common/memcmplen.h | 188 + .../xz/src/liblzma/common/microlzma_decoder.c | 220 ++ .../xz/src/liblzma/common/microlzma_encoder.c | 140 + .../3rdparty/xz/src/liblzma/common/outqueue.c | 286 ++ .../3rdparty/xz/src/liblzma/common/outqueue.h | 258 ++ .../liblzma/common/stream_buffer_decoder.c | 90 + .../liblzma/common/stream_buffer_encoder.c | 141 + .../xz/src/liblzma/common/stream_decoder.c | 473 +++ .../xz/src/liblzma/common/stream_decoder.h | 21 + .../xz/src/liblzma/common/stream_decoder_mt.c | 2017 +++++++++++ .../xz/src/liblzma/common/stream_encoder.c | 354 ++ .../xz/src/liblzma/common/stream_encoder_mt.c | 1280 +++++++ .../src/liblzma/common/stream_flags_common.c | 46 + .../src/liblzma/common/stream_flags_common.h | 35 + .../src/liblzma/common/stream_flags_decoder.c | 87 + .../src/liblzma/common/stream_flags_encoder.c | 85 + .../xz/src/liblzma/common/string_conversion.c | 1338 ++++++++ .../xz/src/liblzma/common/vli_decoder.c | 85 + .../xz/src/liblzma/common/vli_encoder.c | 68 + .../3rdparty/xz/src/liblzma/common/vli_size.c | 29 + .../xz/src/liblzma/delta/delta_common.c | 72 + .../xz/src/liblzma/delta/delta_common.h | 19 + .../xz/src/liblzma/delta/delta_decoder.c | 87 + .../xz/src/liblzma/delta/delta_decoder.h | 25 + .../xz/src/liblzma/delta/delta_encoder.c | 132 + .../xz/src/liblzma/delta/delta_encoder.h | 23 + .../xz/src/liblzma/delta/delta_private.h | 36 + .../3rdparty/xz/src/liblzma/liblzma.pc.in | 16 + .../xz/src/liblzma/liblzma_generic.map | 128 + .../3rdparty/xz/src/liblzma/liblzma_linux.map | 143 + .../3rdparty/xz/src/liblzma/lz/lz_decoder.c | 324 ++ .../3rdparty/xz/src/liblzma/lz/lz_decoder.h | 250 ++ .../3rdparty/xz/src/liblzma/lz/lz_encoder.c | 632 ++++ .../3rdparty/xz/src/liblzma/lz/lz_encoder.h | 352 ++ .../xz/src/liblzma/lz/lz_encoder_hash.h | 108 + .../xz/src/liblzma/lz/lz_encoder_hash_table.h | 70 + .../xz/src/liblzma/lz/lz_encoder_mf.c | 744 ++++ .../3rdparty/xz/src/liblzma/lzma/fastpos.h | 141 + .../xz/src/liblzma/lzma/fastpos_table.c | 521 +++ .../xz/src/liblzma/lzma/fastpos_tablegen.c | 58 + .../xz/src/liblzma/lzma/lzma2_decoder.c | 310 ++ .../xz/src/liblzma/lzma/lzma2_decoder.h | 28 + .../xz/src/liblzma/lzma/lzma2_encoder.c | 416 +++ .../xz/src/liblzma/lzma/lzma2_encoder.h | 42 + .../xz/src/liblzma/lzma/lzma_common.h | 240 ++ .../xz/src/liblzma/lzma/lzma_decoder.c | 1263 +++++++ .../xz/src/liblzma/lzma/lzma_decoder.h | 52 + .../xz/src/liblzma/lzma/lzma_encoder.c | 786 +++++ .../xz/src/liblzma/lzma/lzma_encoder.h | 58 + .../liblzma/lzma/lzma_encoder_optimum_fast.c | 169 + .../lzma/lzma_encoder_optimum_normal.c | 858 +++++ .../src/liblzma/lzma/lzma_encoder_presets.c | 63 + .../src/liblzma/lzma/lzma_encoder_private.h | 161 + .../xz/src/liblzma/rangecoder/price.h | 92 + .../xz/src/liblzma/rangecoder/price_table.c | 24 + .../src/liblzma/rangecoder/price_tablegen.c | 93 + .../xz/src/liblzma/rangecoder/range_common.h | 77 + .../xz/src/liblzma/rangecoder/range_decoder.h | 966 ++++++ .../xz/src/liblzma/rangecoder/range_encoder.h | 349 ++ .../3rdparty/xz/src/liblzma/simple/arm.c | 74 + .../3rdparty/xz/src/liblzma/simple/arm64.c | 136 + .../3rdparty/xz/src/liblzma/simple/armthumb.c | 79 + .../3rdparty/xz/src/liblzma/simple/ia64.c | 115 + .../3rdparty/xz/src/liblzma/simple/powerpc.c | 79 + .../3rdparty/xz/src/liblzma/simple/riscv.c | 755 ++++ .../xz/src/liblzma/simple/simple_coder.c | 291 ++ .../xz/src/liblzma/simple/simple_coder.h | 89 + .../xz/src/liblzma/simple/simple_decoder.c | 39 + .../xz/src/liblzma/simple/simple_decoder.h | 21 + .../xz/src/liblzma/simple/simple_encoder.c | 37 + .../xz/src/liblzma/simple/simple_encoder.h | 22 + .../xz/src/liblzma/simple/simple_private.h | 73 + .../3rdparty/xz/src/liblzma/simple/sparc.c | 86 + .../3rdparty/xz/src/liblzma/simple/x86.c | 157 + .../3rdparty/xz/src/liblzma/validate_map.sh | 163 + src/libs/3rdparty/karchive/AUTHORS | 10 + src/libs/3rdparty/karchive/CMakeLists.txt | 152 + .../karchive/LICENSES/BSD-2-Clause.txt | 22 + .../3rdparty/karchive/LICENSES/CC0-1.0.txt | 121 + .../karchive/LICENSES/LGPL-2.0-or-later.txt | 446 +++ src/libs/3rdparty/karchive/README.md | 33 + src/libs/3rdparty/karchive/src/k7zip.cpp | 3028 +++++++++++++++++ src/libs/3rdparty/karchive/src/k7zip.h | 100 + src/libs/3rdparty/karchive/src/kar.cpp | 195 ++ src/libs/3rdparty/karchive/src/kar.h | 106 + src/libs/3rdparty/karchive/src/karchive.cpp | 1062 ++++++ src/libs/3rdparty/karchive/src/karchive.h | 433 +++ .../3rdparty/karchive/src/karchive_export.h | 14 + src/libs/3rdparty/karchive/src/karchive_p.h | 59 + .../3rdparty/karchive/src/karchivedirectory.h | 131 + .../3rdparty/karchive/src/karchiveentry.h | 111 + src/libs/3rdparty/karchive/src/karchivefile.h | 110 + .../3rdparty/karchive/src/kbzip2filter.cpp | 198 ++ src/libs/3rdparty/karchive/src/kbzip2filter.h | 47 + .../karchive/src/kcompressiondevice.cpp | 519 +++ .../karchive/src/kcompressiondevice.h | 146 + .../karchive/src/kcompressiondevice_p.h | 13 + .../3rdparty/karchive/src/kfilterbase.cpp | 81 + src/libs/3rdparty/karchive/src/kfilterbase.h | 109 + .../3rdparty/karchive/src/kgzipfilter.cpp | 366 ++ src/libs/3rdparty/karchive/src/kgzipfilter.h | 59 + .../karchive/src/klimitediodevice.cpp | 73 + .../karchive/src/klimitediodevice_p.h | 58 + .../3rdparty/karchive/src/knonefilter.cpp | 127 + src/libs/3rdparty/karchive/src/knonefilter.h | 48 + src/libs/3rdparty/karchive/src/krcc.cpp | 162 + src/libs/3rdparty/karchive/src/krcc.h | 103 + src/libs/3rdparty/karchive/src/ktar.cpp | 975 ++++++ src/libs/3rdparty/karchive/src/ktar.h | 117 + src/libs/3rdparty/karchive/src/kxzfilter.cpp | 279 ++ src/libs/3rdparty/karchive/src/kxzfilter.h | 67 + src/libs/3rdparty/karchive/src/kzip.cpp | 1477 ++++++++ src/libs/3rdparty/karchive/src/kzip.h | 178 + .../3rdparty/karchive/src/kzipfileentry.h | 79 + .../3rdparty/karchive/src/kzstdfilter.cpp | 134 + src/libs/3rdparty/karchive/src/kzstdfilter.h | 46 + .../3rdparty/karchive/src/loggingcategory.cpp | 3 + .../3rdparty/karchive/src/loggingcategory.h | 5 + 250 files changed, 63456 insertions(+), 1 deletion(-) create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/.gitattributes create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/.gitignore create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/CHANGES create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/LICENSE create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/README create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/README.COMPILATION.PROBLEMS create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/README.XML.STUFF create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/README.qtcreator create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/blocksort.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2recover.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib_private.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/compress.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/crctable.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/decompress.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/huffman.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/mk251.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/bzip2/randtable.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/AUTHORS create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/COPYING create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/COPYING.0BSD create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv2 create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv3 create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/COPYING.LGPLv2.1 create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/README create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/README.qtcreator create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/THANKS create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/TODO create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/mythread.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/sysdefs.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_config.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_gettext.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_integer.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_fw.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_width.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest.comments.txt create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/base.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/bcj.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/block.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/check.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/container.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/delta.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/filter.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/hardware.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index_hash.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/lzma12.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/stream_flags.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/version.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/vli.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_arm64.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_fast.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_small.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_be.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_le.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_tablegen.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_x86.S create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_fast.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_small.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_be.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_le.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_tablegen.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_x86.S create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_x86_clmul.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/sha256.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/auto_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_util.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_buffer_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_decoder_memusage.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder_memusage.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/file_info.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_cputhreads.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_physmem.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_hash.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/memcmplen.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder_mt.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder_mt.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/string_conversion.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_size.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_private.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma.pc.in create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_generic.map create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_linux.map create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash_table.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_mf.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_table.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_tablegen.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_normal.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_presets.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_private.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_table.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_tablegen.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_common.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm64.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/armthumb.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/ia64.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/powerpc.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/riscv.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_private.h create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/sparc.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/x86.c create mode 100644 src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/validate_map.sh create mode 100644 src/libs/3rdparty/karchive/AUTHORS create mode 100644 src/libs/3rdparty/karchive/CMakeLists.txt create mode 100644 src/libs/3rdparty/karchive/LICENSES/BSD-2-Clause.txt create mode 100644 src/libs/3rdparty/karchive/LICENSES/CC0-1.0.txt create mode 100644 src/libs/3rdparty/karchive/LICENSES/LGPL-2.0-or-later.txt create mode 100644 src/libs/3rdparty/karchive/README.md create mode 100644 src/libs/3rdparty/karchive/src/k7zip.cpp create mode 100644 src/libs/3rdparty/karchive/src/k7zip.h create mode 100644 src/libs/3rdparty/karchive/src/kar.cpp create mode 100644 src/libs/3rdparty/karchive/src/kar.h create mode 100644 src/libs/3rdparty/karchive/src/karchive.cpp create mode 100644 src/libs/3rdparty/karchive/src/karchive.h create mode 100644 src/libs/3rdparty/karchive/src/karchive_export.h create mode 100644 src/libs/3rdparty/karchive/src/karchive_p.h create mode 100644 src/libs/3rdparty/karchive/src/karchivedirectory.h create mode 100644 src/libs/3rdparty/karchive/src/karchiveentry.h create mode 100644 src/libs/3rdparty/karchive/src/karchivefile.h create mode 100644 src/libs/3rdparty/karchive/src/kbzip2filter.cpp create mode 100644 src/libs/3rdparty/karchive/src/kbzip2filter.h create mode 100644 src/libs/3rdparty/karchive/src/kcompressiondevice.cpp create mode 100644 src/libs/3rdparty/karchive/src/kcompressiondevice.h create mode 100644 src/libs/3rdparty/karchive/src/kcompressiondevice_p.h create mode 100644 src/libs/3rdparty/karchive/src/kfilterbase.cpp create mode 100644 src/libs/3rdparty/karchive/src/kfilterbase.h create mode 100644 src/libs/3rdparty/karchive/src/kgzipfilter.cpp create mode 100644 src/libs/3rdparty/karchive/src/kgzipfilter.h create mode 100644 src/libs/3rdparty/karchive/src/klimitediodevice.cpp create mode 100644 src/libs/3rdparty/karchive/src/klimitediodevice_p.h create mode 100644 src/libs/3rdparty/karchive/src/knonefilter.cpp create mode 100644 src/libs/3rdparty/karchive/src/knonefilter.h create mode 100644 src/libs/3rdparty/karchive/src/krcc.cpp create mode 100644 src/libs/3rdparty/karchive/src/krcc.h create mode 100644 src/libs/3rdparty/karchive/src/ktar.cpp create mode 100644 src/libs/3rdparty/karchive/src/ktar.h create mode 100644 src/libs/3rdparty/karchive/src/kxzfilter.cpp create mode 100644 src/libs/3rdparty/karchive/src/kxzfilter.h create mode 100644 src/libs/3rdparty/karchive/src/kzip.cpp create mode 100644 src/libs/3rdparty/karchive/src/kzip.h create mode 100644 src/libs/3rdparty/karchive/src/kzipfileentry.h create mode 100644 src/libs/3rdparty/karchive/src/kzstdfilter.cpp create mode 100644 src/libs/3rdparty/karchive/src/kzstdfilter.h create mode 100644 src/libs/3rdparty/karchive/src/loggingcategory.cpp create mode 100644 src/libs/3rdparty/karchive/src/loggingcategory.h diff --git a/qt_attributions.json b/qt_attributions.json index 008ff353943..888782be407 100644 --- a/qt_attributions.json +++ b/qt_attributions.json @@ -40,6 +40,20 @@ "LicenseFile": "src/libs/3rdparty/syntax-highlighting/COPYING", "Copyright": "Author: Dominik Haumann (dhaumann@kde.org)." }, + { + "Id": "karchive", + "Name": "KArchive", + "QDocModule": "qtcreator", + "QtParts": ["tools"], + "QtUsage": "Used for reading and writing archives.", + "Path": "src/libs/3rdparty/karchive", + "Description": "KArchive provides classes for easy reading, creation and manipulation of 'archive' formats like ZIP and TAR.", + "Homepage": "https://invent.kde.org/frameworks/karchive", + "Version": "6.9.0", + "License": "GNU Lesser General Public License v2.1", + "LicenseFile": "src/libs/3rdparty/karchive/LICENSES/LGPL-2.0-or-later.txt", + "Copyright": "Copyright The KDE project contributors" + }, { "Id": "ksyntaxhighlighting-bash", "Name": "KSyntaxHighlighting: bash.xml", @@ -637,7 +651,7 @@ "Name": "ZLib", "QDocModule": "qtcreator", "QtParts": ["tools"], - "QtUsage": "Used by ZipWriter/ZipReader to support compress and uncompress operations.", + "QtUsage": "Used by KArchive/ZipWriter/ZipReader to support compress and uncompress operations.", "Path": "src/libs/3rdparty/zlib", "Description": "Zlib is a lossless data-compression library.", "Homepage": "https://www.zlib.net", @@ -646,6 +660,34 @@ "LicenseFile": "src/libs/3rdparty/zlib/LICENSE", "Copyright": "Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler" }, + { + "Id": "bzip2", + "Name": "bzip2", + "QDocModule": "qtcreator", + "QtParts": ["tools"], + "QtUsage": "Used by KArchive to support compress and uncompress operations.", + "Path": "src/libs/3rdparty/karchive/3rdparty/bzip2", + "Description": "BZip2 is a lossless data-compression library.", + "Homepage": "https://sourceware.org/bzip2/", + "Version": "1.0.8", + "License": "bzip2 and libbzip2 License v1.0.6", + "LicenseFile": "src/libs/3rdparty/karchive/3rdparty/bzip2/LICENSE", + "Copyright": "copyright (C) 1996-2019 Julian R Seward." + }, + { + "Id": "xz", + "Name": "xz", + "QDocModule": "qtcreator", + "QtParts": ["tools"], + "QtUsage": "Used by KArchive to support compress and uncompress operations.", + "Path": "src/libs/3rdparty/karchive/3rdparty/xz", + "Description": "XZ is a lossless data-compression library.", + "Homepage": "https://tukaani.org/xz/", + "Version": "5.6.3", + "License": "BSD Zero Clause License (0BSD)", + "LicenseFile": "src/libs/3rdparty/karchive/3rdparty/xz/COPYING", + "Copyright": "Copyright (C) The XZ Utils authors and contributors" + }, { "Id": "tika-mimetypes", "Name": "Apache Tika MimeType Definitions", diff --git a/src/libs/3rdparty/CMakeLists.txt b/src/libs/3rdparty/CMakeLists.txt index 4a9ec9d4904..3c28a28afd1 100644 --- a/src/libs/3rdparty/CMakeLists.txt +++ b/src/libs/3rdparty/CMakeLists.txt @@ -5,6 +5,8 @@ add_subdirectory(libptyqt) add_subdirectory(qtkeychain) add_subdirectory(lua) add_subdirectory(sol2) +# Do not enable it yet, as the necessary changes are only introduced with the next patch. +#add_subdirectory(karchive) if(WIN32) add_subdirectory(winpty) diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/.gitattributes b/src/libs/3rdparty/karchive/3rdparty/bzip2/.gitattributes new file mode 100644 index 00000000000..f3af893933f --- /dev/null +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/.gitattributes @@ -0,0 +1 @@ +*.ref binary diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/.gitignore b/src/libs/3rdparty/karchive/3rdparty/bzip2/.gitignore new file mode 100644 index 00000000000..da23814dc7b --- /dev/null +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/.gitignore @@ -0,0 +1,9 @@ +*.o +*.obj +*.rb2 +*.tst +*.a +*.lib +*.exe +bzip2 +bzip2recover diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/CHANGES b/src/libs/3rdparty/karchive/3rdparty/bzip2/CHANGES new file mode 100644 index 00000000000..30afead2586 --- /dev/null +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/CHANGES @@ -0,0 +1,356 @@ + ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.8 of 13 July 2019 + Copyright (C) 1996-2019 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ + + +0.9.0 +~~~~~ +First version. + + +0.9.0a +~~~~~~ +Removed 'ranlib' from Makefile, since most modern Unix-es +don't need it, or even know about it. + + +0.9.0b +~~~~~~ +Fixed a problem with error reporting in bzip2.c. This does not effect +the library in any way. Problem is: versions 0.9.0 and 0.9.0a (of the +program proper) compress and decompress correctly, but give misleading +error messages (internal panics) when an I/O error occurs, instead of +reporting the problem correctly. This shouldn't give any data loss +(as far as I can see), but is confusing. + +Made the inline declarations disappear for non-GCC compilers. + + +0.9.0c +~~~~~~ +Fixed some problems in the library pertaining to some boundary cases. +This makes the library behave more correctly in those situations. The +fixes apply only to features (calls and parameters) not used by +bzip2.c, so the non-fixedness of them in previous versions has no +effect on reliability of bzip2.c. + +In bzlib.c: + * made zero-length BZ_FLUSH work correctly in bzCompress(). + * fixed bzWrite/bzRead to ignore zero-length requests. + * fixed bzread to correctly handle read requests after EOF. + * wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. + +In compress.c: + * changed setting of nGroups in sendMTFValues() so as to + do a bit better on small files. This _does_ effect + bzip2.c. + + +0.9.5a +~~~~~~ +Major change: add a fallback sorting algorithm (blocksort.c) +to give reasonable behaviour even for very repetitive inputs. +Nuked --repetitive-best and --repetitive-fast since they are +no longer useful. + +Minor changes: mostly a whole bunch of small changes/ +bugfixes in the driver (bzip2.c). Changes pertaining to the +user interface are: + + allow decompression of symlink'd files to stdout + decompress/test files even without .bz2 extension + give more accurate error messages for I/O errors + when compressing/decompressing to stdout, don't catch control-C + read flags from BZIP2 and BZIP environment variables + decline to break hard links to a file unless forced with -f + allow -c flag even with no filenames + preserve file ownerships as far as possible + make -s -1 give the expected block size (100k) + add a flag -q --quiet to suppress nonessential warnings + stop decoding flags after --, so files beginning in - can be handled + resolved inconsistent naming: bzcat or bz2cat ? + bzip2 --help now returns 0 + +Programming-level changes are: + + fixed syntax error in GET_LL4 for Borland C++ 5.02 + let bzBuffToBuffDecompress return BZ_DATA_ERROR{_MAGIC} + fix overshoot of mode-string end in bzopen_or_bzdopen + wrapped bzlib.h in #ifdef __cplusplus ... extern "C" { ... } + close file handles under all error conditions + added minor mods so it compiles with DJGPP out of the box + fixed Makefile so it doesn't give problems with BSD make + fix uninitialised memory reads in dlltest.c + +0.9.5b +~~~~~~ +Open stdin/stdout in binary mode for DJGPP. + +0.9.5c +~~~~~~ +Changed BZ_N_OVERSHOOT to be ... + 2 instead of ... + 1. The + 1 +version could cause the sorted order to be wrong in some extremely +obscure cases. Also changed setting of quadrant in blocksort.c. + +0.9.5d +~~~~~~ +The only functional change is to make bzlibVersion() in the library +return the correct string. This has no effect whatsoever on the +functioning of the bzip2 program or library. Added a couple of casts +so the library compiles without warnings at level 3 in MS Visual +Studio 6.0. Included a Y2K statement in the file Y2K_INFO. All other +changes are minor documentation changes. + +1.0 +~~~ +Several minor bugfixes and enhancements: + +* Large file support. The library uses 64-bit counters to + count the volume of data passing through it. bzip2.c + is now compiled with -D_FILE_OFFSET_BITS=64 to get large + file support from the C library. -v correctly prints out + file sizes greater than 4 gigabytes. All these changes have + been made without assuming a 64-bit platform or a C compiler + which supports 64-bit ints, so, except for the C library + aspect, they are fully portable. + +* Decompression robustness. The library/program should be + robust to any corruption of compressed data, detecting and + handling _all_ corruption, instead of merely relying on + the CRCs. What this means is that the program should + never crash, given corrupted data, and the library should + always return BZ_DATA_ERROR. + +* Fixed an obscure race-condition bug only ever observed on + Solaris, in which, if you were very unlucky and issued + control-C at exactly the wrong time, both input and output + files would be deleted. + +* Don't run out of file handles on test/decompression when + large numbers of files have invalid magic numbers. + +* Avoid library namespace pollution. Prefix all exported + symbols with BZ2_. + +* Minor sorting enhancements from my DCC2000 paper. + +* Advance the version number to 1.0, so as to counteract the + (false-in-this-case) impression some people have that programs + with version numbers less than 1.0 are in some way, experimental, + pre-release versions. + +* Create an initial Makefile-libbz2_so to build a shared library. + Yes, I know I should really use libtool et al ... + +* Make the program exit with 2 instead of 0 when decompression + fails due to a bad magic number (ie, an invalid bzip2 header). + Also exit with 1 (as the manual claims :-) whenever a diagnostic + message would have been printed AND the corresponding operation + is aborted, for example + bzip2: Output file xx already exists. + When a diagnostic message is printed but the operation is not + aborted, for example + bzip2: Can't guess original name for wurble -- using wurble.out + then the exit value 0 is returned, unless some other problem is + also detected. + + I think it corresponds more closely to what the manual claims now. + + +1.0.1 +~~~~~ +* Modified dlltest.c so it uses the new BZ2_ naming scheme. +* Modified makefile-msc to fix minor build probs on Win2k. +* Updated README.COMPILATION.PROBLEMS. + +There are no functionality changes or bug fixes relative to version +1.0.0. This is just a documentation update + a fix for minor Win32 +build problems. For almost everyone, upgrading from 1.0.0 to 1.0.1 is +utterly pointless. Don't bother. + + +1.0.2 +~~~~~ +A bug fix release, addressing various minor issues which have appeared +in the 18 or so months since 1.0.1 was released. Most of the fixes +are to do with file-handling or documentation bugs. To the best of my +knowledge, there have been no data-loss-causing bugs reported in the +compression/decompression engine of 1.0.0 or 1.0.1. + +Note that this release does not improve the rather crude build system +for Unix platforms. The general plan here is to autoconfiscate/ +libtoolise 1.0.2 soon after release, and release the result as 1.1.0 +or perhaps 1.2.0. That, however, is still just a plan at this point. + +Here are the changes in 1.0.2. Bug-reporters and/or patch-senders in +parentheses. + +* Fix an infinite segfault loop in 1.0.1 when a directory is + encountered in -f (force) mode. + (Trond Eivind Glomsrod, Nicholas Nethercote, Volker Schmidt) + +* Avoid double fclose() of output file on certain I/O error paths. + (Solar Designer) + +* Don't fail with internal error 1007 when fed a long stream (> 48MB) + of byte 251. Also print useful message suggesting that 1007s may be + caused by bad memory. + (noticed by Juan Pedro Vallejo, fixed by me) + +* Fix uninitialised variable silly bug in demo prog dlltest.c. + (Jorj Bauer) + +* Remove 512-MB limitation on recovered file size for bzip2recover + on selected platforms which support 64-bit ints. At the moment + all GCC supported platforms, and Win32. + (me, Alson van der Meulen) + +* Hard-code header byte values, to give correct operation on platforms + using EBCDIC as their native character set (IBM's OS/390). + (Leland Lucius) + +* Copy file access times correctly. + (Marty Leisner) + +* Add distclean and check targets to Makefile. + (Michael Carmack) + +* Parameterise use of ar and ranlib in Makefile. Also add $(LDFLAGS). + (Rich Ireland, Bo Thorsen) + +* Pass -p (create parent dirs as needed) to mkdir during make install. + (Jeremy Fusco) + +* Dereference symlinks when copying file permissions in -f mode. + (Volker Schmidt) + +* Majorly simplify implementation of uInt64_qrm10. + (Bo Lindbergh) + +* Check the input file still exists before deleting the output one, + when aborting in cleanUpAndFail(). + (Joerg Prante, Robert Linden, Matthias Krings) + +Also a bunch of patches courtesy of Philippe Troin, the Debian maintainer +of bzip2: + +* Wrapper scripts (with manpages): bzdiff, bzgrep, bzmore. + +* Spelling changes and minor enhancements in bzip2.1. + +* Avoid race condition between creating the output file and setting its + interim permissions safely, by using fopen_output_safely(). + No changes to bzip2recover since there is no issue with file + permissions there. + +* do not print senseless report with -v when compressing an empty + file. + +* bzcat -f works on non-bzip2 files. + +* do not try to escape shell meta-characters on unix (the shell takes + care of these). + +* added --fast and --best aliases for -1 -9 for gzip compatibility. + + +1.0.3 (15 Feb 05) +~~~~~~~~~~~~~~~~~ +Fixes some minor bugs since the last version, 1.0.2. + +* Further robustification against corrupted compressed data. + There are currently no known bitstreams which can cause the + decompressor to crash, loop or access memory which does not + belong to it. If you are using bzip2 or the library to + decompress bitstreams from untrusted sources, an upgrade + to 1.0.3 is recommended. This fixes CAN-2005-1260. + +* The documentation has been converted to XML, from which html + and pdf can be derived. + +* Various minor bugs in the documentation have been fixed. + +* Fixes for various compilation warnings with newer versions of + gcc, and on 64-bit platforms. + +* The BZ_NO_STDIO cpp symbol was not properly observed in 1.0.2. + This has been fixed. + + +1.0.4 (20 Dec 06) +~~~~~~~~~~~~~~~~~ +Fixes some minor bugs since the last version, 1.0.3. + +* Fix file permissions race problem (CAN-2005-0953). + +* Avoid possible segfault in BZ2_bzclose. From Coverity's NetBSD + scan. + +* 'const'/prototype cleanups in the C code. + +* Change default install location to /usr/local, and handle multiple + 'make install's without error. + +* Sanitise file names more carefully in bzgrep. Fixes CAN-2005-0758 + to the extent that applies to bzgrep. + +* Use 'mktemp' rather than 'tempfile' in bzdiff. + +* Tighten up a couple of assertions in blocksort.c following automated + analysis. + +* Fix minor doc/comment bugs. + + +1.0.5 (10 Dec 07) +~~~~~~~~~~~~~~~~~ +Security fix only. Fixes CERT-FI 20469 as it applies to bzip2. + + +1.0.6 (6 Sept 10) +~~~~~~~~~~~~~~~~~ + +* Security fix for CVE-2010-0405. This was reported by Mikolaj + Izdebski. + +* Make the documentation build on Ubuntu 10.04 + +1.0.7 (27 Jun 19) +~~~~~~~~~~~~~~~~~ + +* Fix undefined behavior in the macros SET_BH, CLEAR_BH, & ISSET_BH + +* bzip2: Fix return value when combining --test,-t and -q. + +* bzip2recover: Fix buffer overflow for large argv[0] + +* bzip2recover: Fix use after free issue with outFile (CVE-2016-3189) + +* Make sure nSelectors is not out of range (CVE-2019-12900) + +1.0.8 (13 Jul 19) +~~~~~~~~~~~~~~~~~ + +* Accept as many selectors as the file format allows. + This relaxes the fix for CVE-2019-12900 from 1.0.7 + so that bzip2 allows decompression of bz2 files that + use (too) many selectors again. + +* Fix handling of large (> 4GB) files on Windows. + +* Cleanup of bzdiff and bzgrep scripts so they don't use + any bash extensions and handle multiple archives correctly. + +* There is now a bz2-files testsuite at + https://sourceware.org/git/bzip2-tests.git diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/LICENSE b/src/libs/3rdparty/karchive/3rdparty/bzip2/LICENSE new file mode 100644 index 00000000000..81a37eab7a5 --- /dev/null +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/LICENSE @@ -0,0 +1,42 @@ + +-------------------------------------------------------------------------- + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2019 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. 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 acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@acm.org +bzip2/libbzip2 version 1.0.8 of 13 July 2019 + +-------------------------------------------------------------------------- diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/README b/src/libs/3rdparty/karchive/3rdparty/bzip2/README new file mode 100644 index 00000000000..b9c6099fd1c --- /dev/null +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/README @@ -0,0 +1,196 @@ + +This is the README for bzip2/libzip2. +This version is fully compatible with the previous public releases. + +------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.8 of 13 July 2019 +Copyright (C) 1996-2019 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in this file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ + +Complete documentation is available in Postscript form (manual.ps), +PDF (manual.pdf) or html (manual.html). A plain-text version of the +manual page is available as bzip2.txt. + + +HOW TO BUILD -- UNIX + +Type 'make'. This builds the library libbz2.a and then the programs +bzip2 and bzip2recover. Six self-tests are run. If the self-tests +complete ok, carry on to installation: + +To install in /usr/local/bin, /usr/local/lib, /usr/local/man and +/usr/local/include, type + + make install + +To install somewhere else, eg, /xxx/yyy/{bin,lib,man,include}, type + + make install PREFIX=/xxx/yyy + +If you are (justifiably) paranoid and want to see what 'make install' +is going to do, you can first do + + make -n install or + make -n install PREFIX=/xxx/yyy respectively. + +The -n instructs make to show the commands it would execute, but not +actually execute them. + + +HOW TO BUILD -- UNIX, shared library libbz2.so. + +Do 'make -f Makefile-libbz2_so'. This Makefile seems to work for +Linux-ELF (RedHat 7.2 on an x86 box), with gcc. I make no claims +that it works for any other platform, though I suspect it probably +will work for most platforms employing both ELF and gcc. + +bzip2-shared, a client of the shared library, is also built, but not +self-tested. So I suggest you also build using the normal Makefile, +since that conducts a self-test. A second reason to prefer the +version statically linked to the library is that, on x86 platforms, +building shared objects makes a valuable register (%ebx) unavailable +to gcc, resulting in a slowdown of 10%-20%, at least for bzip2. + +Important note for people upgrading .so's from 0.9.0/0.9.5 to version +1.0.X. All the functions in the library have been renamed, from (eg) +bzCompress to BZ2_bzCompress, to avoid namespace pollution. +Unfortunately this means that the libbz2.so created by +Makefile-libbz2_so will not work with any program which used an older +version of the library. I do encourage library clients to make the +effort to upgrade to use version 1.0, since it is both faster and more +robust than previous versions. + + +HOW TO BUILD -- Windows 95, NT, DOS, Mac, etc. + +It's difficult for me to support compilation on all these platforms. +My approach is to collect binaries for these platforms, and put them +on the master web site (https://sourceware.org/bzip2/). Look there. However +(FWIW), bzip2-1.0.X is very standard ANSI C and should compile +unmodified with MS Visual C. If you have difficulties building, you +might want to read README.COMPILATION.PROBLEMS. + +At least using MS Visual C++ 6, you can build from the unmodified +sources by issuing, in a command shell: + + nmake -f makefile.msc + +(you may need to first run the MSVC-provided script VCVARS32.BAT + so as to set up paths to the MSVC tools correctly). + + +VALIDATION + +Correct operation, in the sense that a compressed file can always be +decompressed to reproduce the original, is obviously of paramount +importance. To validate bzip2, I used a modified version of Mark +Nelson's churn program. Churn is an automated test driver which +recursively traverses a directory structure, using bzip2 to compress +and then decompress each file it encounters, and checking that the +decompressed data is the same as the original. + + + +Please read and be aware of the following: + +WARNING: + + This program and library (attempts to) compress data by + performing several non-trivial transformations on it. + Unless you are 100% familiar with *all* the algorithms + contained herein, and with the consequences of modifying them, + you should NOT meddle with the compression or decompression + machinery. Incorrect changes can and very likely *will* + lead to disastrous loss of data. + + +DISCLAIMER: + + I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE + USE OF THIS PROGRAM/LIBRARY, HOWSOEVER CAUSED. + + Every compression of a file implies an assumption that the + compressed file can be decompressed to reproduce the original. + Great efforts in design, coding and testing have been made to + ensure that this program works correctly. However, the complexity + of the algorithms, and, in particular, the presence of various + special cases in the code which occur with very low but non-zero + probability make it impossible to rule out the possibility of bugs + remaining in the program. DO NOT COMPRESS ANY DATA WITH THIS + PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE POSSIBILITY, HOWEVER + SMALL, THAT THE DATA WILL NOT BE RECOVERABLE. + + That is not to say this program is inherently unreliable. + Indeed, I very much hope the opposite is true. bzip2/libbzip2 + has been carefully constructed and extensively tested. + + +PATENTS: + + To the best of my knowledge, bzip2/libbzip2 does not use any + patented algorithms. However, I do not have the resources + to carry out a patent search. Therefore I cannot give any + guarantee of the above statement. + + + +WHAT'S NEW IN 0.9.0 (as compared to 0.1pl2) ? + + * Approx 10% faster compression, 30% faster decompression + * -t (test mode) is a lot quicker + * Can decompress concatenated compressed files + * Programming interface, so programs can directly read/write .bz2 files + * Less restrictive (BSD-style) licensing + * Flag handling more compatible with GNU gzip + * Much more documentation, i.e., a proper user manual + * Hopefully, improved portability (at least of the library) + +WHAT'S NEW IN 0.9.5 ? + + * Compression speed is much less sensitive to the input + data than in previous versions. Specifically, the very + slow performance caused by repetitive data is fixed. + * Many small improvements in file and flag handling. + * A Y2K statement. + +WHAT'S NEW IN 1.0.x ? + + See the CHANGES file. + +I hope you find bzip2 useful. Feel free to contact the developers at + bzip2-devel@sourceware.org +if you have any suggestions or queries. Many people mailed me with +comments, suggestions and patches after the releases of bzip-0.15, +bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1, +1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this +feedback. I thank you for your comments. + +bzip2's "home" is https://sourceware.org/bzip2/ + +Julian Seward +jseward@acm.org +Cambridge, UK. + +18 July 1996 (version 0.15) +25 August 1996 (version 0.21) + 7 August 1997 (bzip2, version 0.1) +29 August 1997 (bzip2, version 0.1pl2) +23 August 1998 (bzip2, version 0.9.0) + 8 June 1999 (bzip2, version 0.9.5) + 4 Sept 1999 (bzip2, version 0.9.5d) + 5 May 2000 (bzip2, version 1.0pre8) +30 December 2001 (bzip2, version 1.0.2pre1) +15 February 2005 (bzip2, version 1.0.3) +20 December 2006 (bzip2, version 1.0.4) +10 December 2007 (bzip2, version 1.0.5) + 6 Sept 2010 (bzip2, version 1.0.6) +27 June 2019 (bzip2, version 1.0.7) +13 July 2019 (bzip2, version 1.0.8) diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/README.COMPILATION.PROBLEMS b/src/libs/3rdparty/karchive/3rdparty/bzip2/README.COMPILATION.PROBLEMS new file mode 100644 index 00000000000..fa317a50c81 --- /dev/null +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/README.COMPILATION.PROBLEMS @@ -0,0 +1,58 @@ +------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.8 of 13 July 2019 +Copyright (C) 1996-2019 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ + +bzip2 should compile without problems on the vast majority of +platforms. Using the supplied Makefile, I've built and tested it +myself for x86-linux and amd64-linux. With makefile.msc, Visual C++ +6.0 and nmake, you can build a native Win32 version too. Large file +support seems to work correctly on at least on amd64-linux. + +When I say "large file" I mean a file of size 2,147,483,648 (2^31) +bytes or above. Many older OSs can't handle files above this size, +but many newer ones can. Large files are pretty huge -- most files +you'll encounter are not Large Files. + +Early versions of bzip2 (0.1, 0.9.0, 0.9.5) compiled on a wide variety +of platforms without difficulty, and I hope this version will continue +in that tradition. However, in order to support large files, I've had +to include the define -D_FILE_OFFSET_BITS=64 in the Makefile. This +can cause problems. + +The technique of adding -D_FILE_OFFSET_BITS=64 to get large file +support is, as far as I know, the Recommended Way to get correct large +file support. For more details, see the Large File Support +Specification, published by the Large File Summit, at + + http://ftp.sas.com/standards/large.file + +As a general comment, if you get compilation errors which you think +are related to large file support, try removing the above define from +the Makefile, ie, delete the line + + BIGFILES=-D_FILE_OFFSET_BITS=64 + +from the Makefile, and do 'make clean ; make'. This will give you a +version of bzip2 without large file support, which, for most +applications, is probably not a problem. + +Alternatively, try some of the platform-specific hints listed below. + +You can use the spewG.c program to generate huge files to test bzip2's +large file support, if you are feeling paranoid. Be aware though that +any compilation problems which affect bzip2 will also affect spewG.c, +alas. + +AIX: I have reports that for large file support, you need to specify +-D_LARGE_FILES rather than -D_FILE_OFFSET_BITS=64. I have not tested +this myself. diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/README.XML.STUFF b/src/libs/3rdparty/karchive/3rdparty/bzip2/README.XML.STUFF new file mode 100644 index 00000000000..1503476ebe6 --- /dev/null +++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/README.XML.STUFF @@ -0,0 +1,45 @@ + ---------------------------------------------------------------- + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.8 of 13 July 2019 + Copyright (C) 1996-2019 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ---------------------------------------------------------------- + +The script xmlproc.sh takes an xml file as input, +and processes it to create .pdf, .html or .ps output. +It uses format.pl, a perl script to format
 blocks nicely,
+ and add CDATA tags so writers do not have to use eg. < 
+
+The file "entities.xml" must be edited to reflect current
+version, year, etc.
+
+
+Usage:
+
+  ./xmlproc.sh -v manual.xml
+  Validates an xml file to ensure no dtd-compliance errors
+
+  ./xmlproc.sh -html manual.xml
+  Output: manual.html
+
+  ./xmlproc.sh -pdf manual.xml
+  Output: manual.pdf
+
+  ./xmlproc.sh -ps manual.xml
+  Output: manual.ps
+
+
+Notum bene: 
+- pdfxmltex barfs if given a filename with an underscore in it
+
+- xmltex won't work yet - there's a bug in passivetex
+    which we are all waiting for Sebastian to fix.
+  So we are going the xml -> pdf -> ps route for the time being,
+    using pdfxmltex.
diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/README.qtcreator b/src/libs/3rdparty/karchive/3rdparty/bzip2/README.qtcreator
new file mode 100644
index 00000000000..b523a5153c5
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/README.qtcreator
@@ -0,0 +1,4 @@
+This directory contains a stripped down version of `git://sourceware.org/git/bzip2.git` with the following modifications:
+
+* Branch bzip2-1.0.8 was checked out (6a8690fc8d26c815e798c588f796eabe9d684cf0)
+* All unnecessary files have been removed.
diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/blocksort.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/blocksort.c
new file mode 100644
index 00000000000..92d81fe287e
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/blocksort.c
@@ -0,0 +1,1094 @@
+
+/*-------------------------------------------------------------*/
+/*--- Block sorting machinery                               ---*/
+/*---                                           blocksort.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*---------------------------------------------*/
+/*--- Fallback O(N log(N)^2) sorting        ---*/
+/*--- algorithm, for repetitive blocks      ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static 
+__inline__
+void fallbackSimpleSort ( UInt32* fmap, 
+                          UInt32* eclass, 
+                          Int32   lo, 
+                          Int32   hi )
+{
+   Int32 i, j, tmp;
+   UInt32 ec_tmp;
+
+   if (lo == hi) return;
+
+   if (hi - lo > 3) {
+      for ( i = hi-4; i >= lo; i-- ) {
+         tmp = fmap[i];
+         ec_tmp = eclass[tmp];
+         for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 )
+            fmap[j-4] = fmap[j];
+         fmap[j-4] = tmp;
+      }
+   }
+
+   for ( i = hi-1; i >= lo; i-- ) {
+      tmp = fmap[i];
+      ec_tmp = eclass[tmp];
+      for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ )
+         fmap[j-1] = fmap[j];
+      fmap[j-1] = tmp;
+   }
+}
+
+
+/*---------------------------------------------*/
+#define fswap(zz1, zz2) \
+   { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
+
+#define fvswap(zzp1, zzp2, zzn)       \
+{                                     \
+   Int32 yyp1 = (zzp1);               \
+   Int32 yyp2 = (zzp2);               \
+   Int32 yyn  = (zzn);                \
+   while (yyn > 0) {                  \
+      fswap(fmap[yyp1], fmap[yyp2]);  \
+      yyp1++; yyp2++; yyn--;          \
+   }                                  \
+}
+
+
+#define fmin(a,b) ((a) < (b)) ? (a) : (b)
+
+#define fpush(lz,hz) { stackLo[sp] = lz; \
+                       stackHi[sp] = hz; \
+                       sp++; }
+
+#define fpop(lz,hz) { sp--;              \
+                      lz = stackLo[sp];  \
+                      hz = stackHi[sp]; }
+
+#define FALLBACK_QSORT_SMALL_THRESH 10
+#define FALLBACK_QSORT_STACK_SIZE   100
+
+
+static
+void fallbackQSort3 ( UInt32* fmap, 
+                      UInt32* eclass,
+                      Int32   loSt, 
+                      Int32   hiSt )
+{
+   Int32 unLo, unHi, ltLo, gtHi, n, m;
+   Int32 sp, lo, hi;
+   UInt32 med, r, r3;
+   Int32 stackLo[FALLBACK_QSORT_STACK_SIZE];
+   Int32 stackHi[FALLBACK_QSORT_STACK_SIZE];
+
+   r = 0;
+
+   sp = 0;
+   fpush ( loSt, hiSt );
+
+   while (sp > 0) {
+
+      AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 );
+
+      fpop ( lo, hi );
+      if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) {
+         fallbackSimpleSort ( fmap, eclass, lo, hi );
+         continue;
+      }
+
+      /* Random partitioning.  Median of 3 sometimes fails to
+         avoid bad cases.  Median of 9 seems to help but 
+         looks rather expensive.  This too seems to work but
+         is cheaper.  Guidance for the magic constants 
+         7621 and 32768 is taken from Sedgewick's algorithms
+         book, chapter 35.
+      */
+      r = ((r * 7621) + 1) % 32768;
+      r3 = r % 3;
+      if (r3 == 0) med = eclass[fmap[lo]]; else
+      if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else
+                   med = eclass[fmap[hi]];
+
+      unLo = ltLo = lo;
+      unHi = gtHi = hi;
+
+      while (1) {
+         while (1) {
+            if (unLo > unHi) break;
+            n = (Int32)eclass[fmap[unLo]] - (Int32)med;
+            if (n == 0) { 
+               fswap(fmap[unLo], fmap[ltLo]); 
+               ltLo++; unLo++; 
+               continue; 
+            };
+            if (n > 0) break;
+            unLo++;
+         }
+         while (1) {
+            if (unLo > unHi) break;
+            n = (Int32)eclass[fmap[unHi]] - (Int32)med;
+            if (n == 0) { 
+               fswap(fmap[unHi], fmap[gtHi]); 
+               gtHi--; unHi--; 
+               continue; 
+            };
+            if (n < 0) break;
+            unHi--;
+         }
+         if (unLo > unHi) break;
+         fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--;
+      }
+
+      AssertD ( unHi == unLo-1, "fallbackQSort3(2)" );
+
+      if (gtHi < ltLo) continue;
+
+      n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n);
+      m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m);
+
+      n = lo + unLo - ltLo - 1;
+      m = hi - (gtHi - unHi) + 1;
+
+      if (n - lo > hi - m) {
+         fpush ( lo, n );
+         fpush ( m, hi );
+      } else {
+         fpush ( m, hi );
+         fpush ( lo, n );
+      }
+   }
+}
+
+#undef fmin
+#undef fpush
+#undef fpop
+#undef fswap
+#undef fvswap
+#undef FALLBACK_QSORT_SMALL_THRESH
+#undef FALLBACK_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+      nblock > 0
+      eclass exists for [0 .. nblock-1]
+      ((UChar*)eclass) [0 .. nblock-1] holds block
+      ptr exists for [0 .. nblock-1]
+
+   Post:
+      ((UChar*)eclass) [0 .. nblock-1] holds block
+      All other areas of eclass destroyed
+      fmap [0 .. nblock-1] holds sorted order
+      bhtab [ 0 .. 2+(nblock/32) ] destroyed
+*/
+
+#define       SET_BH(zz)  bhtab[(zz) >> 5] |= ((UInt32)1 << ((zz) & 31))
+#define     CLEAR_BH(zz)  bhtab[(zz) >> 5] &= ~((UInt32)1 << ((zz) & 31))
+#define     ISSET_BH(zz)  (bhtab[(zz) >> 5] & ((UInt32)1 << ((zz) & 31)))
+#define      WORD_BH(zz)  bhtab[(zz) >> 5]
+#define UNALIGNED_BH(zz)  ((zz) & 0x01f)
+
+static
+void fallbackSort ( UInt32* fmap, 
+                    UInt32* eclass, 
+                    UInt32* bhtab,
+                    Int32   nblock,
+                    Int32   verb )
+{
+   Int32 ftab[257];
+   Int32 ftabCopy[256];
+   Int32 H, i, j, k, l, r, cc, cc1;
+   Int32 nNotDone;
+   Int32 nBhtab;
+   UChar* eclass8 = (UChar*)eclass;
+
+   /*--
+      Initial 1-char radix sort to generate
+      initial fmap and initial BH bits.
+   --*/
+   if (verb >= 4)
+      VPrintf0 ( "        bucket sorting ...\n" );
+   for (i = 0; i < 257;    i++) ftab[i] = 0;
+   for (i = 0; i < nblock; i++) ftab[eclass8[i]]++;
+   for (i = 0; i < 256;    i++) ftabCopy[i] = ftab[i];
+   for (i = 1; i < 257;    i++) ftab[i] += ftab[i-1];
+
+   for (i = 0; i < nblock; i++) {
+      j = eclass8[i];
+      k = ftab[j] - 1;
+      ftab[j] = k;
+      fmap[k] = i;
+   }
+
+   nBhtab = 2 + (nblock / 32);
+   for (i = 0; i < nBhtab; i++) bhtab[i] = 0;
+   for (i = 0; i < 256; i++) SET_BH(ftab[i]);
+
+   /*--
+      Inductively refine the buckets.  Kind-of an
+      "exponential radix sort" (!), inspired by the
+      Manber-Myers suffix array construction algorithm.
+   --*/
+
+   /*-- set sentinel bits for block-end detection --*/
+   for (i = 0; i < 32; i++) { 
+      SET_BH(nblock + 2*i);
+      CLEAR_BH(nblock + 2*i + 1);
+   }
+
+   /*-- the log(N) loop --*/
+   H = 1;
+   while (1) {
+
+      if (verb >= 4) 
+         VPrintf1 ( "        depth %6d has ", H );
+
+      j = 0;
+      for (i = 0; i < nblock; i++) {
+         if (ISSET_BH(i)) j = i;
+         k = fmap[i] - H; if (k < 0) k += nblock;
+         eclass[k] = j;
+      }
+
+      nNotDone = 0;
+      r = -1;
+      while (1) {
+
+	 /*-- find the next non-singleton bucket --*/
+         k = r + 1;
+         while (ISSET_BH(k) && UNALIGNED_BH(k)) k++;
+         if (ISSET_BH(k)) {
+            while (WORD_BH(k) == 0xffffffff) k += 32;
+            while (ISSET_BH(k)) k++;
+         }
+         l = k - 1;
+         if (l >= nblock) break;
+         while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++;
+         if (!ISSET_BH(k)) {
+            while (WORD_BH(k) == 0x00000000) k += 32;
+            while (!ISSET_BH(k)) k++;
+         }
+         r = k - 1;
+         if (r >= nblock) break;
+
+         /*-- now [l, r] bracket current bucket --*/
+         if (r > l) {
+            nNotDone += (r - l + 1);
+            fallbackQSort3 ( fmap, eclass, l, r );
+
+            /*-- scan bucket and generate header bits-- */
+            cc = -1;
+            for (i = l; i <= r; i++) {
+               cc1 = eclass[fmap[i]];
+               if (cc != cc1) { SET_BH(i); cc = cc1; };
+            }
+         }
+      }
+
+      if (verb >= 4) 
+         VPrintf1 ( "%6d unresolved strings\n", nNotDone );
+
+      H *= 2;
+      if (H > nblock || nNotDone == 0) break;
+   }
+
+   /*-- 
+      Reconstruct the original block in
+      eclass8 [0 .. nblock-1], since the
+      previous phase destroyed it.
+   --*/
+   if (verb >= 4)
+      VPrintf0 ( "        reconstructing block ...\n" );
+   j = 0;
+   for (i = 0; i < nblock; i++) {
+      while (ftabCopy[j] == 0) j++;
+      ftabCopy[j]--;
+      eclass8[fmap[i]] = (UChar)j;
+   }
+   AssertH ( j < 256, 1005 );
+}
+
+#undef       SET_BH
+#undef     CLEAR_BH
+#undef     ISSET_BH
+#undef      WORD_BH
+#undef UNALIGNED_BH
+
+
+/*---------------------------------------------*/
+/*--- The main, O(N^2 log(N)) sorting       ---*/
+/*--- algorithm.  Faster for "normal"       ---*/
+/*--- non-repetitive blocks.                ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+__inline__
+Bool mainGtU ( UInt32  i1, 
+               UInt32  i2,
+               UChar*  block, 
+               UInt16* quadrant,
+               UInt32  nblock,
+               Int32*  budget )
+{
+   Int32  k;
+   UChar  c1, c2;
+   UInt16 s1, s2;
+
+   AssertD ( i1 != i2, "mainGtU" );
+   /* 1 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 2 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 3 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 4 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 5 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 6 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 7 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 8 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 9 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 10 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 11 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 12 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+
+   k = nblock + 8;
+
+   do {
+      /* 1 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 2 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 3 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 4 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 5 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 6 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 7 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 8 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+
+      if (i1 >= nblock) i1 -= nblock;
+      if (i2 >= nblock) i2 -= nblock;
+
+      k -= 8;
+      (*budget)--;
+   }
+      while (k >= 0);
+
+   return False;
+}
+
+
+/*---------------------------------------------*/
+/*--
+   Knuth's increments seem to work better
+   than Incerpi-Sedgewick here.  Possibly
+   because the number of elems to sort is
+   usually small, typically <= 20.
+--*/
+static
+Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280,
+                   9841, 29524, 88573, 265720,
+                   797161, 2391484 };
+
+static
+void mainSimpleSort ( UInt32* ptr,
+                      UChar*  block,
+                      UInt16* quadrant,
+                      Int32   nblock,
+                      Int32   lo, 
+                      Int32   hi, 
+                      Int32   d,
+                      Int32*  budget )
+{
+   Int32 i, j, h, bigN, hp;
+   UInt32 v;
+
+   bigN = hi - lo + 1;
+   if (bigN < 2) return;
+
+   hp = 0;
+   while (incs[hp] < bigN) hp++;
+   hp--;
+
+   for (; hp >= 0; hp--) {
+      h = incs[hp];
+
+      i = lo + h;
+      while (True) {
+
+         /*-- copy 1 --*/
+         if (i > hi) break;
+         v = ptr[i];
+         j = i;
+         while ( mainGtU ( 
+                    ptr[j-h]+d, v+d, block, quadrant, nblock, budget 
+                 ) ) {
+            ptr[j] = ptr[j-h];
+            j = j - h;
+            if (j <= (lo + h - 1)) break;
+         }
+         ptr[j] = v;
+         i++;
+
+         /*-- copy 2 --*/
+         if (i > hi) break;
+         v = ptr[i];
+         j = i;
+         while ( mainGtU ( 
+                    ptr[j-h]+d, v+d, block, quadrant, nblock, budget 
+                 ) ) {
+            ptr[j] = ptr[j-h];
+            j = j - h;
+            if (j <= (lo + h - 1)) break;
+         }
+         ptr[j] = v;
+         i++;
+
+         /*-- copy 3 --*/
+         if (i > hi) break;
+         v = ptr[i];
+         j = i;
+         while ( mainGtU ( 
+                    ptr[j-h]+d, v+d, block, quadrant, nblock, budget 
+                 ) ) {
+            ptr[j] = ptr[j-h];
+            j = j - h;
+            if (j <= (lo + h - 1)) break;
+         }
+         ptr[j] = v;
+         i++;
+
+         if (*budget < 0) return;
+      }
+   }
+}
+
+
+/*---------------------------------------------*/
+/*--
+   The following is an implementation of
+   an elegant 3-way quicksort for strings,
+   described in a paper "Fast Algorithms for
+   Sorting and Searching Strings", by Robert
+   Sedgewick and Jon L. Bentley.
+--*/
+
+#define mswap(zz1, zz2) \
+   { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
+
+#define mvswap(zzp1, zzp2, zzn)       \
+{                                     \
+   Int32 yyp1 = (zzp1);               \
+   Int32 yyp2 = (zzp2);               \
+   Int32 yyn  = (zzn);                \
+   while (yyn > 0) {                  \
+      mswap(ptr[yyp1], ptr[yyp2]);    \
+      yyp1++; yyp2++; yyn--;          \
+   }                                  \
+}
+
+static 
+__inline__
+UChar mmed3 ( UChar a, UChar b, UChar c )
+{
+   UChar t;
+   if (a > b) { t = a; a = b; b = t; };
+   if (b > c) { 
+      b = c;
+      if (a > b) b = a;
+   }
+   return b;
+}
+
+#define mmin(a,b) ((a) < (b)) ? (a) : (b)
+
+#define mpush(lz,hz,dz) { stackLo[sp] = lz; \
+                          stackHi[sp] = hz; \
+                          stackD [sp] = dz; \
+                          sp++; }
+
+#define mpop(lz,hz,dz) { sp--;             \
+                         lz = stackLo[sp]; \
+                         hz = stackHi[sp]; \
+                         dz = stackD [sp]; }
+
+
+#define mnextsize(az) (nextHi[az]-nextLo[az])
+
+#define mnextswap(az,bz)                                        \
+   { Int32 tz;                                                  \
+     tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \
+     tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \
+     tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; }
+
+
+#define MAIN_QSORT_SMALL_THRESH 20
+#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT)
+#define MAIN_QSORT_STACK_SIZE 100
+
+static
+void mainQSort3 ( UInt32* ptr,
+                  UChar*  block,
+                  UInt16* quadrant,
+                  Int32   nblock,
+                  Int32   loSt, 
+                  Int32   hiSt, 
+                  Int32   dSt,
+                  Int32*  budget )
+{
+   Int32 unLo, unHi, ltLo, gtHi, n, m, med;
+   Int32 sp, lo, hi, d;
+
+   Int32 stackLo[MAIN_QSORT_STACK_SIZE];
+   Int32 stackHi[MAIN_QSORT_STACK_SIZE];
+   Int32 stackD [MAIN_QSORT_STACK_SIZE];
+
+   Int32 nextLo[3];
+   Int32 nextHi[3];
+   Int32 nextD [3];
+
+   sp = 0;
+   mpush ( loSt, hiSt, dSt );
+
+   while (sp > 0) {
+
+      AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 );
+
+      mpop ( lo, hi, d );
+      if (hi - lo < MAIN_QSORT_SMALL_THRESH || 
+          d > MAIN_QSORT_DEPTH_THRESH) {
+         mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget );
+         if (*budget < 0) return;
+         continue;
+      }
+
+      med = (Int32) 
+            mmed3 ( block[ptr[ lo         ]+d],
+                    block[ptr[ hi         ]+d],
+                    block[ptr[ (lo+hi)>>1 ]+d] );
+
+      unLo = ltLo = lo;
+      unHi = gtHi = hi;
+
+      while (True) {
+         while (True) {
+            if (unLo > unHi) break;
+            n = ((Int32)block[ptr[unLo]+d]) - med;
+            if (n == 0) { 
+               mswap(ptr[unLo], ptr[ltLo]); 
+               ltLo++; unLo++; continue; 
+            };
+            if (n >  0) break;
+            unLo++;
+         }
+         while (True) {
+            if (unLo > unHi) break;
+            n = ((Int32)block[ptr[unHi]+d]) - med;
+            if (n == 0) { 
+               mswap(ptr[unHi], ptr[gtHi]); 
+               gtHi--; unHi--; continue; 
+            };
+            if (n <  0) break;
+            unHi--;
+         }
+         if (unLo > unHi) break;
+         mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--;
+      }
+
+      AssertD ( unHi == unLo-1, "mainQSort3(2)" );
+
+      if (gtHi < ltLo) {
+         mpush(lo, hi, d+1 );
+         continue;
+      }
+
+      n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n);
+      m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m);
+
+      n = lo + unLo - ltLo - 1;
+      m = hi - (gtHi - unHi) + 1;
+
+      nextLo[0] = lo;  nextHi[0] = n;   nextD[0] = d;
+      nextLo[1] = m;   nextHi[1] = hi;  nextD[1] = d;
+      nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1;
+
+      if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
+      if (mnextsize(1) < mnextsize(2)) mnextswap(1,2);
+      if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
+
+      AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" );
+      AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" );
+
+      mpush (nextLo[0], nextHi[0], nextD[0]);
+      mpush (nextLo[1], nextHi[1], nextD[1]);
+      mpush (nextLo[2], nextHi[2], nextD[2]);
+   }
+}
+
+#undef mswap
+#undef mvswap
+#undef mpush
+#undef mpop
+#undef mmin
+#undef mnextsize
+#undef mnextswap
+#undef MAIN_QSORT_SMALL_THRESH
+#undef MAIN_QSORT_DEPTH_THRESH
+#undef MAIN_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+      nblock > N_OVERSHOOT
+      block32 exists for [0 .. nblock-1 +N_OVERSHOOT]
+      ((UChar*)block32) [0 .. nblock-1] holds block
+      ptr exists for [0 .. nblock-1]
+
+   Post:
+      ((UChar*)block32) [0 .. nblock-1] holds block
+      All other areas of block32 destroyed
+      ftab [0 .. 65536 ] destroyed
+      ptr [0 .. nblock-1] holds sorted order
+      if (*budget < 0), sorting was abandoned
+*/
+
+#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8])
+#define SETMASK (1 << 21)
+#define CLEARMASK (~(SETMASK))
+
+static
+void mainSort ( UInt32* ptr, 
+                UChar*  block,
+                UInt16* quadrant, 
+                UInt32* ftab,
+                Int32   nblock,
+                Int32   verb,
+                Int32*  budget )
+{
+   Int32  i, j, k, ss, sb;
+   Int32  runningOrder[256];
+   Bool   bigDone[256];
+   Int32  copyStart[256];
+   Int32  copyEnd  [256];
+   UChar  c1;
+   Int32  numQSorted;
+   UInt16 s;
+   if (verb >= 4) VPrintf0 ( "        main sort initialise ...\n" );
+
+   /*-- set up the 2-byte frequency table --*/
+   for (i = 65536; i >= 0; i--) ftab[i] = 0;
+
+   j = block[0] << 8;
+   i = nblock-1;
+   for (; i >= 3; i -= 4) {
+      quadrant[i] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i]) << 8);
+      ftab[j]++;
+      quadrant[i-1] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i-1]) << 8);
+      ftab[j]++;
+      quadrant[i-2] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i-2]) << 8);
+      ftab[j]++;
+      quadrant[i-3] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i-3]) << 8);
+      ftab[j]++;
+   }
+   for (; i >= 0; i--) {
+      quadrant[i] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i]) << 8);
+      ftab[j]++;
+   }
+
+   /*-- (emphasises close relationship of block & quadrant) --*/
+   for (i = 0; i < BZ_N_OVERSHOOT; i++) {
+      block   [nblock+i] = block[i];
+      quadrant[nblock+i] = 0;
+   }
+
+   if (verb >= 4) VPrintf0 ( "        bucket sorting ...\n" );
+
+   /*-- Complete the initial radix sort --*/
+   for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1];
+
+   s = block[0] << 8;
+   i = nblock-1;
+   for (; i >= 3; i -= 4) {
+      s = (s >> 8) | (block[i] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i;
+      s = (s >> 8) | (block[i-1] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i-1;
+      s = (s >> 8) | (block[i-2] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i-2;
+      s = (s >> 8) | (block[i-3] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i-3;
+   }
+   for (; i >= 0; i--) {
+      s = (s >> 8) | (block[i] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i;
+   }
+
+   /*--
+      Now ftab contains the first loc of every small bucket.
+      Calculate the running order, from smallest to largest
+      big bucket.
+   --*/
+   for (i = 0; i <= 255; i++) {
+      bigDone     [i] = False;
+      runningOrder[i] = i;
+   }
+
+   {
+      Int32 vv;
+      Int32 h = 1;
+      do h = 3 * h + 1; while (h <= 256);
+      do {
+         h = h / 3;
+         for (i = h; i <= 255; i++) {
+            vv = runningOrder[i];
+            j = i;
+            while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) {
+               runningOrder[j] = runningOrder[j-h];
+               j = j - h;
+               if (j <= (h - 1)) goto zero;
+            }
+            zero:
+            runningOrder[j] = vv;
+         }
+      } while (h != 1);
+   }
+
+   /*--
+      The main sorting loop.
+   --*/
+
+   numQSorted = 0;
+
+   for (i = 0; i <= 255; i++) {
+
+      /*--
+         Process big buckets, starting with the least full.
+         Basically this is a 3-step process in which we call
+         mainQSort3 to sort the small buckets [ss, j], but
+         also make a big effort to avoid the calls if we can.
+      --*/
+      ss = runningOrder[i];
+
+      /*--
+         Step 1:
+         Complete the big bucket [ss] by quicksorting
+         any unsorted small buckets [ss, j], for j != ss.  
+         Hopefully previous pointer-scanning phases have already
+         completed many of the small buckets [ss, j], so
+         we don't have to sort them at all.
+      --*/
+      for (j = 0; j <= 255; j++) {
+         if (j != ss) {
+            sb = (ss << 8) + j;
+            if ( ! (ftab[sb] & SETMASK) ) {
+               Int32 lo = ftab[sb]   & CLEARMASK;
+               Int32 hi = (ftab[sb+1] & CLEARMASK) - 1;
+               if (hi > lo) {
+                  if (verb >= 4)
+                     VPrintf4 ( "        qsort [0x%x, 0x%x]   "
+                                "done %d   this %d\n",
+                                ss, j, numQSorted, hi - lo + 1 );
+                  mainQSort3 ( 
+                     ptr, block, quadrant, nblock, 
+                     lo, hi, BZ_N_RADIX, budget 
+                  );   
+                  numQSorted += (hi - lo + 1);
+                  if (*budget < 0) return;
+               }
+            }
+            ftab[sb] |= SETMASK;
+         }
+      }
+
+      AssertH ( !bigDone[ss], 1006 );
+
+      /*--
+         Step 2:
+         Now scan this big bucket [ss] so as to synthesise the
+         sorted order for small buckets [t, ss] for all t,
+         including, magically, the bucket [ss,ss] too.
+         This will avoid doing Real Work in subsequent Step 1's.
+      --*/
+      {
+         for (j = 0; j <= 255; j++) {
+            copyStart[j] =  ftab[(j << 8) + ss]     & CLEARMASK;
+            copyEnd  [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1;
+         }
+         for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) {
+            k = ptr[j]-1; if (k < 0) k += nblock;
+            c1 = block[k];
+            if (!bigDone[c1])
+               ptr[ copyStart[c1]++ ] = k;
+         }
+         for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) {
+            k = ptr[j]-1; if (k < 0) k += nblock;
+            c1 = block[k];
+            if (!bigDone[c1]) 
+               ptr[ copyEnd[c1]-- ] = k;
+         }
+      }
+
+      AssertH ( (copyStart[ss]-1 == copyEnd[ss])
+                || 
+                /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1.
+                   Necessity for this case is demonstrated by compressing 
+                   a sequence of approximately 48.5 million of character 
+                   251; 1.0.0/1.0.1 will then die here. */
+                (copyStart[ss] == 0 && copyEnd[ss] == nblock-1),
+                1007 )
+
+      for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK;
+
+      /*--
+         Step 3:
+         The [ss] big bucket is now done.  Record this fact,
+         and update the quadrant descriptors.  Remember to
+         update quadrants in the overshoot area too, if
+         necessary.  The "if (i < 255)" test merely skips
+         this updating for the last bucket processed, since
+         updating for the last bucket is pointless.
+
+         The quadrant array provides a way to incrementally
+         cache sort orderings, as they appear, so as to 
+         make subsequent comparisons in fullGtU() complete
+         faster.  For repetitive blocks this makes a big
+         difference (but not big enough to be able to avoid
+         the fallback sorting mechanism, exponential radix sort).
+
+         The precise meaning is: at all times:
+
+            for 0 <= i < nblock and 0 <= j <= nblock
+
+            if block[i] != block[j], 
+
+               then the relative values of quadrant[i] and 
+                    quadrant[j] are meaningless.
+
+               else {
+                  if quadrant[i] < quadrant[j]
+                     then the string starting at i lexicographically
+                     precedes the string starting at j
+
+                  else if quadrant[i] > quadrant[j]
+                     then the string starting at j lexicographically
+                     precedes the string starting at i
+
+                  else
+                     the relative ordering of the strings starting
+                     at i and j has not yet been determined.
+               }
+      --*/
+      bigDone[ss] = True;
+
+      if (i < 255) {
+         Int32 bbStart  = ftab[ss << 8] & CLEARMASK;
+         Int32 bbSize   = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart;
+         Int32 shifts   = 0;
+
+         while ((bbSize >> shifts) > 65534) shifts++;
+
+         for (j = bbSize-1; j >= 0; j--) {
+            Int32 a2update     = ptr[bbStart + j];
+            UInt16 qVal        = (UInt16)(j >> shifts);
+            quadrant[a2update] = qVal;
+            if (a2update < BZ_N_OVERSHOOT)
+               quadrant[a2update + nblock] = qVal;
+         }
+         AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 );
+      }
+
+   }
+
+   if (verb >= 4)
+      VPrintf3 ( "        %d pointers, %d sorted, %d scanned\n",
+                 nblock, numQSorted, nblock - numQSorted );
+}
+
+#undef BIGFREQ
+#undef SETMASK
+#undef CLEARMASK
+
+
+/*---------------------------------------------*/
+/* Pre:
+      nblock > 0
+      arr2 exists for [0 .. nblock-1 +N_OVERSHOOT]
+      ((UChar*)arr2)  [0 .. nblock-1] holds block
+      arr1 exists for [0 .. nblock-1]
+
+   Post:
+      ((UChar*)arr2) [0 .. nblock-1] holds block
+      All other areas of block destroyed
+      ftab [ 0 .. 65536 ] destroyed
+      arr1 [0 .. nblock-1] holds sorted order
+*/
+void BZ2_blockSort ( EState* s )
+{
+   UInt32* ptr    = s->ptr; 
+   UChar*  block  = s->block;
+   UInt32* ftab   = s->ftab;
+   Int32   nblock = s->nblock;
+   Int32   verb   = s->verbosity;
+   Int32   wfact  = s->workFactor;
+   UInt16* quadrant;
+   Int32   budget;
+   Int32   budgetInit;
+   Int32   i;
+
+   if (nblock < 10000) {
+      fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
+   } else {
+      /* Calculate the location for quadrant, remembering to get
+         the alignment right.  Assumes that &(block[0]) is at least
+         2-byte aligned -- this should be ok since block is really
+         the first section of arr2.
+      */
+      i = nblock+BZ_N_OVERSHOOT;
+      if (i & 1) i++;
+      quadrant = (UInt16*)(&(block[i]));
+
+      /* (wfact-1) / 3 puts the default-factor-30
+         transition point at very roughly the same place as 
+         with v0.1 and v0.9.0.  
+         Not that it particularly matters any more, since the
+         resulting compressed stream is now the same regardless
+         of whether or not we use the main sort or fallback sort.
+      */
+      if (wfact < 1  ) wfact = 1;
+      if (wfact > 100) wfact = 100;
+      budgetInit = nblock * ((wfact-1) / 3);
+      budget = budgetInit;
+
+      mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget );
+      if (verb >= 3) 
+         VPrintf3 ( "      %d work, %d block, ratio %5.2f\n",
+                    budgetInit - budget,
+                    nblock, 
+                    (float)(budgetInit - budget) /
+                    (float)(nblock==0 ? 1 : nblock) ); 
+      if (budget < 0) {
+         if (verb >= 2) 
+            VPrintf0 ( "    too repetitive; using fallback"
+                       " sorting algorithm\n" );
+         fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
+      }
+   }
+
+   s->origPtr = -1;
+   for (i = 0; i < s->nblock; i++)
+      if (ptr[i] == 0)
+         { s->origPtr = i; break; };
+
+   AssertH( s->origPtr != -1, 1003 );
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                       blocksort.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2.c
new file mode 100644
index 00000000000..d95d280619a
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2.c
@@ -0,0 +1,2036 @@
+
+/*-----------------------------------------------------------*/
+/*--- A block-sorting, lossless compressor        bzip2.c ---*/
+/*-----------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+/* Place a 1 beside your platform, and 0 elsewhere.
+   Generic 32-bit Unix.
+   Also works on 64-bit Unix boxes.
+   This is the default.
+*/
+#define BZ_UNIX      1
+
+/*--
+  Win32, as seen by Jacob Navia's excellent
+  port of (Chris Fraser & David Hanson)'s excellent
+  lcc compiler.  Or with MS Visual C.
+  This is selected automatically if compiled by a compiler which
+  defines _WIN32, not including the Cygwin GCC.
+--*/
+#define BZ_LCCWIN32  0
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#undef  BZ_LCCWIN32
+#define BZ_LCCWIN32 1
+#undef  BZ_UNIX
+#define BZ_UNIX 0
+#endif
+
+
+/*---------------------------------------------*/
+/*--
+  Some stuff for all platforms.
+--*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "bzlib.h"
+
+#define ERROR_IF_EOF(i)       { if ((i) == EOF)  ioError(); }
+#define ERROR_IF_NOT_ZERO(i)  { if ((i) != 0)    ioError(); }
+#define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); }
+
+
+/*---------------------------------------------*/
+/*--
+   Platform-specific stuff.
+--*/
+
+#if BZ_UNIX
+#   include 
+#   include 
+#   include 
+#   include 
+#   include 
+#   include 
+
+#   define PATH_SEP    '/'
+#   define MY_LSTAT    lstat
+#   define MY_STAT     stat
+#   define MY_S_ISREG  S_ISREG
+#   define MY_S_ISDIR  S_ISDIR
+
+#   define APPEND_FILESPEC(root, name) \
+      root=snocString((root), (name))
+
+#   define APPEND_FLAG(root, name) \
+      root=snocString((root), (name))
+
+#   define SET_BINARY_MODE(fd) /**/
+
+#   ifdef __GNUC__
+#      define NORETURN __attribute__ ((noreturn))
+#   else
+#      define NORETURN /**/
+#   endif
+
+#   ifdef __DJGPP__
+#     include 
+#     include 
+#     undef MY_LSTAT
+#     undef MY_STAT
+#     define MY_LSTAT stat
+#     define MY_STAT stat
+#     undef SET_BINARY_MODE
+#     define SET_BINARY_MODE(fd)                        \
+        do {                                            \
+           int retVal = setmode ( fileno ( fd ),        \
+                                  O_BINARY );           \
+           ERROR_IF_MINUS_ONE ( retVal );               \
+        } while ( 0 )
+#   endif
+
+#   ifdef __CYGWIN__
+#     include 
+#     include 
+#     undef SET_BINARY_MODE
+#     define SET_BINARY_MODE(fd)                        \
+        do {                                            \
+           int retVal = setmode ( fileno ( fd ),        \
+                                  O_BINARY );           \
+           ERROR_IF_MINUS_ONE ( retVal );               \
+        } while ( 0 )
+#   endif
+#endif /* BZ_UNIX */
+
+
+
+#if BZ_LCCWIN32
+#   include 
+#   include 
+#   include 
+
+#   define NORETURN       /**/
+#   define PATH_SEP       '\\'
+#   define MY_LSTAT       _stati64
+#   define MY_STAT        _stati64
+#   define MY_S_ISREG(x)  ((x) & _S_IFREG)
+#   define MY_S_ISDIR(x)  ((x) & _S_IFDIR)
+
+#   define APPEND_FLAG(root, name) \
+      root=snocString((root), (name))
+
+#   define APPEND_FILESPEC(root, name)                \
+      root = snocString ((root), (name))
+
+#   define SET_BINARY_MODE(fd)                        \
+      do {                                            \
+         int retVal = setmode ( fileno ( fd ),        \
+                                O_BINARY );           \
+         ERROR_IF_MINUS_ONE ( retVal );               \
+      } while ( 0 )
+
+#endif /* BZ_LCCWIN32 */
+
+
+/*---------------------------------------------*/
+/*--
+  Some more stuff for all platforms :-)
+--*/
+
+typedef char            Char;
+typedef unsigned char   Bool;
+typedef unsigned char   UChar;
+typedef int             Int32;
+typedef unsigned int    UInt32;
+typedef short           Int16;
+typedef unsigned short  UInt16;
+                                       
+#define True  ((Bool)1)
+#define False ((Bool)0)
+
+/*--
+  IntNative is your platform's `native' int size.
+  Only here to avoid probs with 64-bit platforms.
+--*/
+typedef int IntNative;
+
+
+/*---------------------------------------------------*/
+/*--- Misc (file handling) data decls             ---*/
+/*---------------------------------------------------*/
+
+Int32   verbosity;
+Bool    keepInputFiles, smallMode, deleteOutputOnInterrupt;
+Bool    forceOverwrite, testFailsExist, unzFailsExist, noisy;
+Int32   numFileNames, numFilesProcessed, blockSize100k;
+Int32   exitValue;
+
+/*-- source modes; F==file, I==stdin, O==stdout --*/
+#define SM_I2O           1
+#define SM_F2O           2
+#define SM_F2F           3
+
+/*-- operation modes --*/
+#define OM_Z             1
+#define OM_UNZ           2
+#define OM_TEST          3
+
+Int32   opMode;
+Int32   srcMode;
+
+#define FILE_NAME_LEN 1034
+
+Int32   longestFileName;
+Char    inName [FILE_NAME_LEN];
+Char    outName[FILE_NAME_LEN];
+Char    tmpName[FILE_NAME_LEN];
+Char    *progName;
+Char    progNameReally[FILE_NAME_LEN];
+FILE    *outputHandleJustInCase;
+Int32   workFactor;
+
+static void    panic                 ( const Char* ) NORETURN;
+static void    ioError               ( void )        NORETURN;
+static void    outOfMemory           ( void )        NORETURN;
+static void    configError           ( void )        NORETURN;
+static void    crcError              ( void )        NORETURN;
+static void    cleanUpAndFail        ( Int32 )       NORETURN;
+static void    compressedStreamEOF   ( void )        NORETURN;
+
+static void    copyFileName ( Char*, Char* );
+static void*   myMalloc     ( Int32 );
+static void    applySavedFileAttrToOutputFile ( IntNative fd );
+
+
+
+/*---------------------------------------------------*/
+/*--- An implementation of 64-bit ints.  Sigh.    ---*/
+/*--- Roll on widespread deployment of ANSI C9X ! ---*/
+/*---------------------------------------------------*/
+
+typedef
+   struct { UChar b[8]; } 
+   UInt64;
+
+
+static
+void uInt64_from_UInt32s ( UInt64* n, UInt32 lo32, UInt32 hi32 )
+{
+   n->b[7] = (UChar)((hi32 >> 24) & 0xFF);
+   n->b[6] = (UChar)((hi32 >> 16) & 0xFF);
+   n->b[5] = (UChar)((hi32 >> 8)  & 0xFF);
+   n->b[4] = (UChar) (hi32        & 0xFF);
+   n->b[3] = (UChar)((lo32 >> 24) & 0xFF);
+   n->b[2] = (UChar)((lo32 >> 16) & 0xFF);
+   n->b[1] = (UChar)((lo32 >> 8)  & 0xFF);
+   n->b[0] = (UChar) (lo32        & 0xFF);
+}
+
+
+static
+double uInt64_to_double ( UInt64* n )
+{
+   Int32  i;
+   double base = 1.0;
+   double sum  = 0.0;
+   for (i = 0; i < 8; i++) {
+      sum  += base * (double)(n->b[i]);
+      base *= 256.0;
+   }
+   return sum;
+}
+
+
+static
+Bool uInt64_isZero ( UInt64* n )
+{
+   Int32 i;
+   for (i = 0; i < 8; i++)
+      if (n->b[i] != 0) return 0;
+   return 1;
+}
+
+
+/* Divide *n by 10, and return the remainder.  */
+static 
+Int32 uInt64_qrm10 ( UInt64* n )
+{
+   UInt32 rem, tmp;
+   Int32  i;
+   rem = 0;
+   for (i = 7; i >= 0; i--) {
+      tmp = rem * 256 + n->b[i];
+      n->b[i] = tmp / 10;
+      rem = tmp % 10;
+   }
+   return rem;
+}
+
+
+/* ... and the Whole Entire Point of all this UInt64 stuff is
+   so that we can supply the following function.
+*/
+static
+void uInt64_toAscii ( char* outbuf, UInt64* n )
+{
+   Int32  i, q;
+   UChar  buf[32];
+   Int32  nBuf   = 0;
+   UInt64 n_copy = *n;
+   do {
+      q = uInt64_qrm10 ( &n_copy );
+      buf[nBuf] = q + '0';
+      nBuf++;
+   } while (!uInt64_isZero(&n_copy));
+   outbuf[nBuf] = 0;
+   for (i = 0; i < nBuf; i++) 
+      outbuf[i] = buf[nBuf-i-1];
+}
+
+
+/*---------------------------------------------------*/
+/*--- Processing of complete files and streams    ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+static 
+Bool myfeof ( FILE* f )
+{
+   Int32 c = fgetc ( f );
+   if (c == EOF) return True;
+   ungetc ( c, f );
+   return False;
+}
+
+
+/*---------------------------------------------*/
+static 
+void compressStream ( FILE *stream, FILE *zStream )
+{
+   BZFILE* bzf = NULL;
+   UChar   ibuf[5000];
+   Int32   nIbuf;
+   UInt32  nbytes_in_lo32, nbytes_in_hi32;
+   UInt32  nbytes_out_lo32, nbytes_out_hi32;
+   Int32   bzerr, bzerr_dummy, ret;
+
+   SET_BINARY_MODE(stream);
+   SET_BINARY_MODE(zStream);
+
+   if (ferror(stream)) goto errhandler_io;
+   if (ferror(zStream)) goto errhandler_io;
+
+   bzf = BZ2_bzWriteOpen ( &bzerr, zStream, 
+                           blockSize100k, verbosity, workFactor );   
+   if (bzerr != BZ_OK) goto errhandler;
+
+   if (verbosity >= 2) fprintf ( stderr, "\n" );
+
+   while (True) {
+
+      if (myfeof(stream)) break;
+      nIbuf = fread ( ibuf, sizeof(UChar), 5000, stream );
+      if (ferror(stream)) goto errhandler_io;
+      if (nIbuf > 0) BZ2_bzWrite ( &bzerr, bzf, (void*)ibuf, nIbuf );
+      if (bzerr != BZ_OK) goto errhandler;
+
+   }
+
+   BZ2_bzWriteClose64 ( &bzerr, bzf, 0, 
+                        &nbytes_in_lo32, &nbytes_in_hi32,
+                        &nbytes_out_lo32, &nbytes_out_hi32 );
+   if (bzerr != BZ_OK) goto errhandler;
+
+   if (ferror(zStream)) goto errhandler_io;
+   ret = fflush ( zStream );
+   if (ret == EOF) goto errhandler_io;
+   if (zStream != stdout) {
+      Int32 fd = fileno ( zStream );
+      if (fd < 0) goto errhandler_io;
+      applySavedFileAttrToOutputFile ( fd );
+      ret = fclose ( zStream );
+      outputHandleJustInCase = NULL;
+      if (ret == EOF) goto errhandler_io;
+   }
+   outputHandleJustInCase = NULL;
+   if (ferror(stream)) goto errhandler_io;
+   ret = fclose ( stream );
+   if (ret == EOF) goto errhandler_io;
+
+   if (verbosity >= 1) {
+      if (nbytes_in_lo32 == 0 && nbytes_in_hi32 == 0) {
+	 fprintf ( stderr, " no data compressed.\n");
+      } else {
+	 Char   buf_nin[32], buf_nout[32];
+	 UInt64 nbytes_in,   nbytes_out;
+	 double nbytes_in_d, nbytes_out_d;
+	 uInt64_from_UInt32s ( &nbytes_in, 
+			       nbytes_in_lo32, nbytes_in_hi32 );
+	 uInt64_from_UInt32s ( &nbytes_out, 
+			       nbytes_out_lo32, nbytes_out_hi32 );
+	 nbytes_in_d  = uInt64_to_double ( &nbytes_in );
+	 nbytes_out_d = uInt64_to_double ( &nbytes_out );
+	 uInt64_toAscii ( buf_nin, &nbytes_in );
+	 uInt64_toAscii ( buf_nout, &nbytes_out );
+	 fprintf ( stderr, "%6.3f:1, %6.3f bits/byte, "
+		   "%5.2f%% saved, %s in, %s out.\n",
+		   nbytes_in_d / nbytes_out_d,
+		   (8.0 * nbytes_out_d) / nbytes_in_d,
+		   100.0 * (1.0 - nbytes_out_d / nbytes_in_d),
+		   buf_nin,
+		   buf_nout
+		 );
+      }
+   }
+
+   return;
+
+   errhandler:
+   BZ2_bzWriteClose64 ( &bzerr_dummy, bzf, 1, 
+                        &nbytes_in_lo32, &nbytes_in_hi32,
+                        &nbytes_out_lo32, &nbytes_out_hi32 );
+   switch (bzerr) {
+      case BZ_CONFIG_ERROR:
+         configError(); break;
+      case BZ_MEM_ERROR:
+         outOfMemory (); break;
+      case BZ_IO_ERROR:
+         errhandler_io:
+         ioError(); break;
+      default:
+         panic ( "compress:unexpected error" );
+   }
+
+   panic ( "compress:end" );
+   /*notreached*/
+}
+
+
+
+/*---------------------------------------------*/
+static 
+Bool uncompressStream ( FILE *zStream, FILE *stream )
+{
+   BZFILE* bzf = NULL;
+   Int32   bzerr, bzerr_dummy, ret, nread, streamNo, i;
+   UChar   obuf[5000];
+   UChar   unused[BZ_MAX_UNUSED];
+   Int32   nUnused;
+   void*   unusedTmpV;
+   UChar*  unusedTmp;
+
+   nUnused = 0;
+   streamNo = 0;
+
+   SET_BINARY_MODE(stream);
+   SET_BINARY_MODE(zStream);
+
+   if (ferror(stream)) goto errhandler_io;
+   if (ferror(zStream)) goto errhandler_io;
+
+   while (True) {
+
+      bzf = BZ2_bzReadOpen ( 
+               &bzerr, zStream, verbosity, 
+               (int)smallMode, unused, nUnused
+            );
+      if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
+      streamNo++;
+
+      while (bzerr == BZ_OK) {
+         nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
+         if (bzerr == BZ_DATA_ERROR_MAGIC) goto trycat;
+         if ((bzerr == BZ_OK || bzerr == BZ_STREAM_END) && nread > 0)
+            fwrite ( obuf, sizeof(UChar), nread, stream );
+         if (ferror(stream)) goto errhandler_io;
+      }
+      if (bzerr != BZ_STREAM_END) goto errhandler;
+
+      BZ2_bzReadGetUnused ( &bzerr, bzf, &unusedTmpV, &nUnused );
+      if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
+
+      unusedTmp = (UChar*)unusedTmpV;
+      for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
+
+      BZ2_bzReadClose ( &bzerr, bzf );
+      if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
+
+      if (nUnused == 0 && myfeof(zStream)) break;
+   }
+
+   closeok:
+   if (ferror(zStream)) goto errhandler_io;
+   if (stream != stdout) {
+      Int32 fd = fileno ( stream );
+      if (fd < 0) goto errhandler_io;
+      applySavedFileAttrToOutputFile ( fd );
+   }
+   ret = fclose ( zStream );
+   if (ret == EOF) goto errhandler_io;
+
+   if (ferror(stream)) goto errhandler_io;
+   ret = fflush ( stream );
+   if (ret != 0) goto errhandler_io;
+   if (stream != stdout) {
+      ret = fclose ( stream );
+      outputHandleJustInCase = NULL;
+      if (ret == EOF) goto errhandler_io;
+   }
+   outputHandleJustInCase = NULL;
+   if (verbosity >= 2) fprintf ( stderr, "\n    " );
+   return True;
+
+   trycat: 
+   if (forceOverwrite) {
+      rewind(zStream);
+      while (True) {
+      	 if (myfeof(zStream)) break;
+      	 nread = fread ( obuf, sizeof(UChar), 5000, zStream );
+      	 if (ferror(zStream)) goto errhandler_io;
+      	 if (nread > 0) fwrite ( obuf, sizeof(UChar), nread, stream );
+      	 if (ferror(stream)) goto errhandler_io;
+      }
+      goto closeok;
+   }
+  
+   errhandler:
+   BZ2_bzReadClose ( &bzerr_dummy, bzf );
+   switch (bzerr) {
+      case BZ_CONFIG_ERROR:
+         configError(); break;
+      case BZ_IO_ERROR:
+         errhandler_io:
+         ioError(); break;
+      case BZ_DATA_ERROR:
+         crcError();
+      case BZ_MEM_ERROR:
+         outOfMemory();
+      case BZ_UNEXPECTED_EOF:
+         compressedStreamEOF();
+      case BZ_DATA_ERROR_MAGIC:
+         if (zStream != stdin) fclose(zStream);
+         if (stream != stdout) fclose(stream);
+         if (streamNo == 1) {
+            return False;
+         } else {
+            if (noisy)
+            fprintf ( stderr, 
+                      "\n%s: %s: trailing garbage after EOF ignored\n",
+                      progName, inName );
+            return True;       
+         }
+      default:
+         panic ( "decompress:unexpected error" );
+   }
+
+   panic ( "decompress:end" );
+   return True; /*notreached*/
+}
+
+
+/*---------------------------------------------*/
+static 
+Bool testStream ( FILE *zStream )
+{
+   BZFILE* bzf = NULL;
+   Int32   bzerr, bzerr_dummy, ret, streamNo, i;
+   UChar   obuf[5000];
+   UChar   unused[BZ_MAX_UNUSED];
+   Int32   nUnused;
+   void*   unusedTmpV;
+   UChar*  unusedTmp;
+
+   nUnused = 0;
+   streamNo = 0;
+
+   SET_BINARY_MODE(zStream);
+   if (ferror(zStream)) goto errhandler_io;
+
+   while (True) {
+
+      bzf = BZ2_bzReadOpen ( 
+               &bzerr, zStream, verbosity, 
+               (int)smallMode, unused, nUnused
+            );
+      if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
+      streamNo++;
+
+      while (bzerr == BZ_OK) {
+         BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
+         if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler;
+      }
+      if (bzerr != BZ_STREAM_END) goto errhandler;
+
+      BZ2_bzReadGetUnused ( &bzerr, bzf, &unusedTmpV, &nUnused );
+      if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
+
+      unusedTmp = (UChar*)unusedTmpV;
+      for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
+
+      BZ2_bzReadClose ( &bzerr, bzf );
+      if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
+      if (nUnused == 0 && myfeof(zStream)) break;
+
+   }
+
+   if (ferror(zStream)) goto errhandler_io;
+   ret = fclose ( zStream );
+   if (ret == EOF) goto errhandler_io;
+
+   if (verbosity >= 2) fprintf ( stderr, "\n    " );
+   return True;
+
+   errhandler:
+   BZ2_bzReadClose ( &bzerr_dummy, bzf );
+   if (verbosity == 0) 
+      fprintf ( stderr, "%s: %s: ", progName, inName );
+   switch (bzerr) {
+      case BZ_CONFIG_ERROR:
+         configError(); break;
+      case BZ_IO_ERROR:
+         errhandler_io:
+         ioError(); break;
+      case BZ_DATA_ERROR:
+         fprintf ( stderr,
+                   "data integrity (CRC) error in data\n" );
+         return False;
+      case BZ_MEM_ERROR:
+         outOfMemory();
+      case BZ_UNEXPECTED_EOF:
+         fprintf ( stderr,
+                   "file ends unexpectedly\n" );
+         return False;
+      case BZ_DATA_ERROR_MAGIC:
+         if (zStream != stdin) fclose(zStream);
+         if (streamNo == 1) {
+          fprintf ( stderr, 
+                    "bad magic number (file not created by bzip2)\n" );
+            return False;
+         } else {
+            if (noisy)
+            fprintf ( stderr, 
+                      "trailing garbage after EOF ignored\n" );
+            return True;       
+         }
+      default:
+         panic ( "test:unexpected error" );
+   }
+
+   panic ( "test:end" );
+   return True; /*notreached*/
+}
+
+
+/*---------------------------------------------------*/
+/*--- Error [non-] handling grunge                ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+void setExit ( Int32 v )
+{
+   if (v > exitValue) exitValue = v;
+}
+
+
+/*---------------------------------------------*/
+static 
+void cadvise ( void )
+{
+   if (noisy)
+   fprintf (
+      stderr,
+      "\nIt is possible that the compressed file(s) have become corrupted.\n"
+        "You can use the -tvv option to test integrity of such files.\n\n"
+        "You can use the `bzip2recover' program to attempt to recover\n"
+        "data from undamaged sections of corrupted files.\n\n"
+    );
+}
+
+
+/*---------------------------------------------*/
+static 
+void showFileNames ( void )
+{
+   if (noisy)
+   fprintf (
+      stderr,
+      "\tInput file = %s, output file = %s\n",
+      inName, outName 
+   );
+}
+
+
+/*---------------------------------------------*/
+static 
+void cleanUpAndFail ( Int32 ec )
+{
+   IntNative      retVal;
+   struct MY_STAT statBuf;
+
+   if ( srcMode == SM_F2F 
+        && opMode != OM_TEST
+        && deleteOutputOnInterrupt ) {
+
+      /* Check whether input file still exists.  Delete output file
+         only if input exists to avoid loss of data.  Joerg Prante, 5
+         January 2002.  (JRS 06-Jan-2002: other changes in 1.0.2 mean
+         this is less likely to happen.  But to be ultra-paranoid, we
+         do the check anyway.)  */
+      retVal = MY_STAT ( inName, &statBuf );
+      if (retVal == 0) {
+         if (noisy)
+            fprintf ( stderr, 
+                      "%s: Deleting output file %s, if it exists.\n",
+                      progName, outName );
+         if (outputHandleJustInCase != NULL)
+            fclose ( outputHandleJustInCase );
+         retVal = remove ( outName );
+         if (retVal != 0)
+            fprintf ( stderr,
+                      "%s: WARNING: deletion of output file "
+                      "(apparently) failed.\n",
+                      progName );
+      } else {
+         fprintf ( stderr,
+                   "%s: WARNING: deletion of output file suppressed\n",
+                    progName );
+         fprintf ( stderr,
+                   "%s:    since input file no longer exists.  Output file\n",
+                   progName );
+         fprintf ( stderr,
+                   "%s:    `%s' may be incomplete.\n",
+                   progName, outName );
+         fprintf ( stderr, 
+                   "%s:    I suggest doing an integrity test (bzip2 -tv)"
+                   " of it.\n",
+                   progName );
+      }
+   }
+
+   if (noisy && numFileNames > 0 && numFilesProcessed < numFileNames) {
+      fprintf ( stderr, 
+                "%s: WARNING: some files have not been processed:\n"
+                "%s:    %d specified on command line, %d not processed yet.\n\n",
+                progName, progName,
+                numFileNames, numFileNames - numFilesProcessed );
+   }
+   setExit(ec);
+   exit(exitValue);
+}
+
+
+/*---------------------------------------------*/
+static 
+void panic ( const Char* s )
+{
+   fprintf ( stderr,
+             "\n%s: PANIC -- internal consistency error:\n"
+             "\t%s\n"
+             "\tThis is a BUG.  Please report it to:\n"
+             "\tbzip2-devel@sourceware.org\n",
+             progName, s );
+   showFileNames();
+   cleanUpAndFail( 3 );
+}
+
+
+/*---------------------------------------------*/
+static 
+void crcError ( void )
+{
+   fprintf ( stderr,
+             "\n%s: Data integrity error when decompressing.\n",
+             progName );
+   showFileNames();
+   cadvise();
+   cleanUpAndFail( 2 );
+}
+
+
+/*---------------------------------------------*/
+static 
+void compressedStreamEOF ( void )
+{
+  if (noisy) {
+    fprintf ( stderr,
+	      "\n%s: Compressed file ends unexpectedly;\n\t"
+	      "perhaps it is corrupted?  *Possible* reason follows.\n",
+	      progName );
+    perror ( progName );
+    showFileNames();
+    cadvise();
+  }
+  cleanUpAndFail( 2 );
+}
+
+
+/*---------------------------------------------*/
+static 
+void ioError ( void )
+{
+   fprintf ( stderr,
+             "\n%s: I/O or other error, bailing out.  "
+             "Possible reason follows.\n",
+             progName );
+   perror ( progName );
+   showFileNames();
+   cleanUpAndFail( 1 );
+}
+
+
+/*---------------------------------------------*/
+static 
+void mySignalCatcher ( IntNative n )
+{
+   fprintf ( stderr,
+             "\n%s: Control-C or similar caught, quitting.\n",
+             progName );
+   cleanUpAndFail(1);
+}
+
+
+/*---------------------------------------------*/
+static 
+void mySIGSEGVorSIGBUScatcher ( IntNative n )
+{
+   if (opMode == OM_Z)
+      fprintf ( 
+      stderr,
+      "\n%s: Caught a SIGSEGV or SIGBUS whilst compressing.\n"
+      "\n"
+      "   Possible causes are (most likely first):\n"
+      "   (1) This computer has unreliable memory or cache hardware\n"
+      "       (a surprisingly common problem; try a different machine.)\n"
+      "   (2) A bug in the compiler used to create this executable\n"
+      "       (unlikely, if you didn't compile bzip2 yourself.)\n"
+      "   (3) A real bug in bzip2 -- I hope this should never be the case.\n"
+      "   The user's manual, Section 4.3, has more info on (1) and (2).\n"
+      "   \n"
+      "   If you suspect this is a bug in bzip2, or are unsure about (1)\n"
+      "   or (2), feel free to report it to: bzip2-devel@sourceware.org.\n"
+      "   Section 4.3 of the user's manual describes the info a useful\n"
+      "   bug report should have.  If the manual is available on your\n"
+      "   system, please try and read it before mailing me.  If you don't\n"
+      "   have the manual or can't be bothered to read it, mail me anyway.\n"
+      "\n",
+      progName );
+      else
+      fprintf ( 
+      stderr,
+      "\n%s: Caught a SIGSEGV or SIGBUS whilst decompressing.\n"
+      "\n"
+      "   Possible causes are (most likely first):\n"
+      "   (1) The compressed data is corrupted, and bzip2's usual checks\n"
+      "       failed to detect this.  Try bzip2 -tvv my_file.bz2.\n"
+      "   (2) This computer has unreliable memory or cache hardware\n"
+      "       (a surprisingly common problem; try a different machine.)\n"
+      "   (3) A bug in the compiler used to create this executable\n"
+      "       (unlikely, if you didn't compile bzip2 yourself.)\n"
+      "   (4) A real bug in bzip2 -- I hope this should never be the case.\n"
+      "   The user's manual, Section 4.3, has more info on (2) and (3).\n"
+      "   \n"
+      "   If you suspect this is a bug in bzip2, or are unsure about (2)\n"
+      "   or (3), feel free to report it to: bzip2-devel@sourceware.org.\n"
+      "   Section 4.3 of the user's manual describes the info a useful\n"
+      "   bug report should have.  If the manual is available on your\n"
+      "   system, please try and read it before mailing me.  If you don't\n"
+      "   have the manual or can't be bothered to read it, mail me anyway.\n"
+      "\n",
+      progName );
+
+   showFileNames();
+   if (opMode == OM_Z)
+      cleanUpAndFail( 3 ); else
+      { cadvise(); cleanUpAndFail( 2 ); }
+}
+
+
+/*---------------------------------------------*/
+static 
+void outOfMemory ( void )
+{
+   fprintf ( stderr,
+             "\n%s: couldn't allocate enough memory\n",
+             progName );
+   showFileNames();
+   cleanUpAndFail(1);
+}
+
+
+/*---------------------------------------------*/
+static 
+void configError ( void )
+{
+   fprintf ( stderr,
+             "bzip2: I'm not configured correctly for this platform!\n"
+             "\tI require Int32, Int16 and Char to have sizes\n"
+             "\tof 4, 2 and 1 bytes to run properly, and they don't.\n"
+             "\tProbably you can fix this by defining them correctly,\n"
+             "\tand recompiling.  Bye!\n" );
+   setExit(3);
+   exit(exitValue);
+}
+
+
+/*---------------------------------------------------*/
+/*--- The main driver machinery                   ---*/
+/*---------------------------------------------------*/
+
+/* All rather crufty.  The main problem is that input files
+   are stat()d multiple times before use.  This should be
+   cleaned up. 
+*/
+
+/*---------------------------------------------*/
+static 
+void pad ( Char *s )
+{
+   Int32 i;
+   if ( (Int32)strlen(s) >= longestFileName ) return;
+   for (i = 1; i <= longestFileName - (Int32)strlen(s); i++)
+      fprintf ( stderr, " " );
+}
+
+
+/*---------------------------------------------*/
+static 
+void copyFileName ( Char* to, Char* from ) 
+{
+   if ( strlen(from) > FILE_NAME_LEN-10 )  {
+      fprintf (
+         stderr,
+         "bzip2: file name\n`%s'\n"
+         "is suspiciously (more than %d chars) long.\n"
+         "Try using a reasonable file name instead.  Sorry! :-)\n",
+         from, FILE_NAME_LEN-10
+      );
+      setExit(1);
+      exit(exitValue);
+   }
+
+  strncpy(to,from,FILE_NAME_LEN-10);
+  to[FILE_NAME_LEN-10]='\0';
+}
+
+
+/*---------------------------------------------*/
+static 
+Bool fileExists ( Char* name )
+{
+   FILE *tmp   = fopen ( name, "rb" );
+   Bool exists = (tmp != NULL);
+   if (tmp != NULL) fclose ( tmp );
+   return exists;
+}
+
+
+/*---------------------------------------------*/
+/* Open an output file safely with O_EXCL and good permissions.
+   This avoids a race condition in versions < 1.0.2, in which
+   the file was first opened and then had its interim permissions
+   set safely.  We instead use open() to create the file with
+   the interim permissions required. (--- --- rw-).
+
+   For non-Unix platforms, if we are not worrying about
+   security issues, simple this simply behaves like fopen.
+*/
+static
+FILE* fopen_output_safely ( Char* name, const char* mode )
+{
+#  if BZ_UNIX
+   FILE*     fp;
+   IntNative fh;
+   fh = open(name, O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR);
+   if (fh == -1) return NULL;
+   fp = fdopen(fh, mode);
+   if (fp == NULL) close(fh);
+   return fp;
+#  else
+   return fopen(name, mode);
+#  endif
+}
+
+
+/*---------------------------------------------*/
+/*--
+  if in doubt, return True
+--*/
+static 
+Bool notAStandardFile ( Char* name )
+{
+   IntNative      i;
+   struct MY_STAT statBuf;
+
+   i = MY_LSTAT ( name, &statBuf );
+   if (i != 0) return True;
+   if (MY_S_ISREG(statBuf.st_mode)) return False;
+   return True;
+}
+
+
+/*---------------------------------------------*/
+/*--
+  rac 11/21/98 see if file has hard links to it
+--*/
+static 
+Int32 countHardLinks ( Char* name )
+{  
+   IntNative      i;
+   struct MY_STAT statBuf;
+
+   i = MY_LSTAT ( name, &statBuf );
+   if (i != 0) return 0;
+   return (statBuf.st_nlink - 1);
+}
+
+
+/*---------------------------------------------*/
+/* Copy modification date, access date, permissions and owner from the
+   source to destination file.  We have to copy this meta-info off
+   into fileMetaInfo before starting to compress / decompress it,
+   because doing it afterwards means we get the wrong access time.
+
+   To complicate matters, in compress() and decompress() below, the
+   sequence of tests preceding the call to saveInputFileMetaInfo()
+   involves calling fileExists(), which in turn establishes its result
+   by attempting to fopen() the file, and if successful, immediately
+   fclose()ing it again.  So we have to assume that the fopen() call
+   does not cause the access time field to be updated.
+
+   Reading of the man page for stat() (man 2 stat) on RedHat 7.2 seems
+   to imply that merely doing open() will not affect the access time.
+   Therefore we merely need to hope that the C library only does
+   open() as a result of fopen(), and not any kind of read()-ahead
+   cleverness.
+
+   It sounds pretty fragile to me.  Whether this carries across
+   robustly to arbitrary Unix-like platforms (or even works robustly
+   on this one, RedHat 7.2) is unknown to me.  Nevertheless ...  
+*/
+#if BZ_UNIX
+static 
+struct MY_STAT fileMetaInfo;
+#endif
+
+static 
+void saveInputFileMetaInfo ( Char *srcName )
+{
+#  if BZ_UNIX
+   IntNative retVal;
+   /* Note use of stat here, not lstat. */
+   retVal = MY_STAT( srcName, &fileMetaInfo );
+   ERROR_IF_NOT_ZERO ( retVal );
+#  endif
+}
+
+
+static 
+void applySavedTimeInfoToOutputFile ( Char *dstName )
+{
+#  if BZ_UNIX
+   IntNative      retVal;
+   struct utimbuf uTimBuf;
+
+   uTimBuf.actime = fileMetaInfo.st_atime;
+   uTimBuf.modtime = fileMetaInfo.st_mtime;
+
+   retVal = utime ( dstName, &uTimBuf );
+   ERROR_IF_NOT_ZERO ( retVal );
+#  endif
+}
+
+static 
+void applySavedFileAttrToOutputFile ( IntNative fd )
+{
+#  if BZ_UNIX
+   IntNative retVal;
+
+   retVal = fchmod ( fd, fileMetaInfo.st_mode );
+   ERROR_IF_NOT_ZERO ( retVal );
+
+   (void) fchown ( fd, fileMetaInfo.st_uid, fileMetaInfo.st_gid );
+   /* chown() will in many cases return with EPERM, which can
+      be safely ignored.
+   */
+#  endif
+}
+
+
+/*---------------------------------------------*/
+static 
+Bool containsDubiousChars ( Char* name )
+{
+#  if BZ_UNIX
+   /* On unix, files can contain any characters and the file expansion
+    * is performed by the shell.
+    */
+   return False;
+#  else /* ! BZ_UNIX */
+   /* On non-unix (Win* platforms), wildcard characters are not allowed in 
+    * filenames.
+    */
+   for (; *name != '\0'; name++)
+      if (*name == '?' || *name == '*') return True;
+   return False;
+#  endif /* BZ_UNIX */
+}
+
+
+/*---------------------------------------------*/
+#define BZ_N_SUFFIX_PAIRS 4
+
+const Char* zSuffix[BZ_N_SUFFIX_PAIRS] 
+   = { ".bz2", ".bz", ".tbz2", ".tbz" };
+const Char* unzSuffix[BZ_N_SUFFIX_PAIRS] 
+   = { "", "", ".tar", ".tar" };
+
+static 
+Bool hasSuffix ( Char* s, const Char* suffix )
+{
+   Int32 ns = strlen(s);
+   Int32 nx = strlen(suffix);
+   if (ns < nx) return False;
+   if (strcmp(s + ns - nx, suffix) == 0) return True;
+   return False;
+}
+
+static 
+Bool mapSuffix ( Char* name, 
+                 const Char* oldSuffix, 
+                 const Char* newSuffix )
+{
+   if (!hasSuffix(name,oldSuffix)) return False;
+   name[strlen(name)-strlen(oldSuffix)] = 0;
+   strcat ( name, newSuffix );
+   return True;
+}
+
+
+/*---------------------------------------------*/
+static 
+void compress ( Char *name )
+{
+   FILE  *inStr;
+   FILE  *outStr;
+   Int32 n, i;
+   struct MY_STAT statBuf;
+
+   deleteOutputOnInterrupt = False;
+
+   if (name == NULL && srcMode != SM_I2O)
+      panic ( "compress: bad modes\n" );
+
+   switch (srcMode) {
+      case SM_I2O: 
+         copyFileName ( inName, (Char*)"(stdin)" );
+         copyFileName ( outName, (Char*)"(stdout)" ); 
+         break;
+      case SM_F2F: 
+         copyFileName ( inName, name );
+         copyFileName ( outName, name );
+         strcat ( outName, ".bz2" ); 
+         break;
+      case SM_F2O: 
+         copyFileName ( inName, name );
+         copyFileName ( outName, (Char*)"(stdout)" ); 
+         break;
+   }
+
+   if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
+      if (noisy)
+      fprintf ( stderr, "%s: There are no files matching `%s'.\n",
+                progName, inName );
+      setExit(1);
+      return;
+   }
+   if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
+      fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
+                progName, inName, strerror(errno) );
+      setExit(1);
+      return;
+   }
+   for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++) {
+      if (hasSuffix(inName, zSuffix[i])) {
+         if (noisy)
+         fprintf ( stderr, 
+                   "%s: Input file %s already has %s suffix.\n",
+                   progName, inName, zSuffix[i] );
+         setExit(1);
+         return;
+      }
+   }
+   if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
+      MY_STAT(inName, &statBuf);
+      if ( MY_S_ISDIR(statBuf.st_mode) ) {
+         fprintf( stderr,
+                  "%s: Input file %s is a directory.\n",
+                  progName,inName);
+         setExit(1);
+         return;
+      }
+   }
+   if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
+      if (noisy)
+      fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
+                progName, inName );
+      setExit(1);
+      return;
+   }
+   if ( srcMode == SM_F2F && fileExists ( outName ) ) {
+      if (forceOverwrite) {
+	 remove(outName);
+      } else {
+	 fprintf ( stderr, "%s: Output file %s already exists.\n",
+		   progName, outName );
+	 setExit(1);
+	 return;
+      }
+   }
+   if ( srcMode == SM_F2F && !forceOverwrite &&
+        (n=countHardLinks ( inName )) > 0) {
+      fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
+                progName, inName, n, n > 1 ? "s" : "" );
+      setExit(1);
+      return;
+   }
+
+   if ( srcMode == SM_F2F ) {
+      /* Save the file's meta-info before we open it.  Doing it later
+         means we mess up the access times. */
+      saveInputFileMetaInfo ( inName );
+   }
+
+   switch ( srcMode ) {
+
+      case SM_I2O:
+         inStr = stdin;
+         outStr = stdout;
+         if ( isatty ( fileno ( stdout ) ) ) {
+            fprintf ( stderr,
+                      "%s: I won't write compressed data to a terminal.\n",
+                      progName );
+            fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
+                              progName, progName );
+            setExit(1);
+            return;
+         };
+         break;
+
+      case SM_F2O:
+         inStr = fopen ( inName, "rb" );
+         outStr = stdout;
+         if ( isatty ( fileno ( stdout ) ) ) {
+            fprintf ( stderr,
+                      "%s: I won't write compressed data to a terminal.\n",
+                      progName );
+            fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
+                              progName, progName );
+            if ( inStr != NULL ) fclose ( inStr );
+            setExit(1);
+            return;
+         };
+         if ( inStr == NULL ) {
+            fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
+                      progName, inName, strerror(errno) );
+            setExit(1);
+            return;
+         };
+         break;
+
+      case SM_F2F:
+         inStr = fopen ( inName, "rb" );
+         outStr = fopen_output_safely ( outName, "wb" );
+         if ( outStr == NULL) {
+            fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
+                      progName, outName, strerror(errno) );
+            if ( inStr != NULL ) fclose ( inStr );
+            setExit(1);
+            return;
+         }
+         if ( inStr == NULL ) {
+            fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
+                      progName, inName, strerror(errno) );
+            if ( outStr != NULL ) fclose ( outStr );
+            setExit(1);
+            return;
+         };
+         break;
+
+      default:
+         panic ( "compress: bad srcMode" );
+         break;
+   }
+
+   if (verbosity >= 1) {
+      fprintf ( stderr,  "  %s: ", inName );
+      pad ( inName );
+      fflush ( stderr );
+   }
+
+   /*--- Now the input and output handles are sane.  Do the Biz. ---*/
+   outputHandleJustInCase = outStr;
+   deleteOutputOnInterrupt = True;
+   compressStream ( inStr, outStr );
+   outputHandleJustInCase = NULL;
+
+   /*--- If there was an I/O error, we won't get here. ---*/
+   if ( srcMode == SM_F2F ) {
+      applySavedTimeInfoToOutputFile ( outName );
+      deleteOutputOnInterrupt = False;
+      if ( !keepInputFiles ) {
+         IntNative retVal = remove ( inName );
+         ERROR_IF_NOT_ZERO ( retVal );
+      }
+   }
+
+   deleteOutputOnInterrupt = False;
+}
+
+
+/*---------------------------------------------*/
+static 
+void uncompress ( Char *name )
+{
+   FILE  *inStr;
+   FILE  *outStr;
+   Int32 n, i;
+   Bool  magicNumberOK;
+   Bool  cantGuess;
+   struct MY_STAT statBuf;
+
+   deleteOutputOnInterrupt = False;
+
+   if (name == NULL && srcMode != SM_I2O)
+      panic ( "uncompress: bad modes\n" );
+
+   cantGuess = False;
+   switch (srcMode) {
+      case SM_I2O: 
+         copyFileName ( inName, (Char*)"(stdin)" );
+         copyFileName ( outName, (Char*)"(stdout)" ); 
+         break;
+      case SM_F2F: 
+         copyFileName ( inName, name );
+         copyFileName ( outName, name );
+         for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++)
+            if (mapSuffix(outName,zSuffix[i],unzSuffix[i]))
+               goto zzz; 
+         cantGuess = True;
+         strcat ( outName, ".out" );
+         break;
+      case SM_F2O: 
+         copyFileName ( inName, name );
+         copyFileName ( outName, (Char*)"(stdout)" ); 
+         break;
+   }
+
+   zzz:
+   if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
+      if (noisy)
+      fprintf ( stderr, "%s: There are no files matching `%s'.\n",
+                progName, inName );
+      setExit(1);
+      return;
+   }
+   if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
+      fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
+                progName, inName, strerror(errno) );
+      setExit(1);
+      return;
+   }
+   if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
+      MY_STAT(inName, &statBuf);
+      if ( MY_S_ISDIR(statBuf.st_mode) ) {
+         fprintf( stderr,
+                  "%s: Input file %s is a directory.\n",
+                  progName,inName);
+         setExit(1);
+         return;
+      }
+   }
+   if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
+      if (noisy)
+      fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
+                progName, inName );
+      setExit(1);
+      return;
+   }
+   if ( /* srcMode == SM_F2F implied && */ cantGuess ) {
+      if (noisy)
+      fprintf ( stderr, 
+                "%s: Can't guess original name for %s -- using %s\n",
+                progName, inName, outName );
+      /* just a warning, no return */
+   }   
+   if ( srcMode == SM_F2F && fileExists ( outName ) ) {
+      if (forceOverwrite) {
+	remove(outName);
+      } else {
+        fprintf ( stderr, "%s: Output file %s already exists.\n",
+                  progName, outName );
+        setExit(1);
+        return;
+      }
+   }
+   if ( srcMode == SM_F2F && !forceOverwrite &&
+        (n=countHardLinks ( inName ) ) > 0) {
+      fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
+                progName, inName, n, n > 1 ? "s" : "" );
+      setExit(1);
+      return;
+   }
+
+   if ( srcMode == SM_F2F ) {
+      /* Save the file's meta-info before we open it.  Doing it later
+         means we mess up the access times. */
+      saveInputFileMetaInfo ( inName );
+   }
+
+   switch ( srcMode ) {
+
+      case SM_I2O:
+         inStr = stdin;
+         outStr = stdout;
+         if ( isatty ( fileno ( stdin ) ) ) {
+            fprintf ( stderr,
+                      "%s: I won't read compressed data from a terminal.\n",
+                      progName );
+            fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
+                              progName, progName );
+            setExit(1);
+            return;
+         };
+         break;
+
+      case SM_F2O:
+         inStr = fopen ( inName, "rb" );
+         outStr = stdout;
+         if ( inStr == NULL ) {
+            fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
+                      progName, inName, strerror(errno) );
+            if ( inStr != NULL ) fclose ( inStr );
+            setExit(1);
+            return;
+         };
+         break;
+
+      case SM_F2F:
+         inStr = fopen ( inName, "rb" );
+         outStr = fopen_output_safely ( outName, "wb" );
+         if ( outStr == NULL) {
+            fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
+                      progName, outName, strerror(errno) );
+            if ( inStr != NULL ) fclose ( inStr );
+            setExit(1);
+            return;
+         }
+         if ( inStr == NULL ) {
+            fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
+                      progName, inName, strerror(errno) );
+            if ( outStr != NULL ) fclose ( outStr );
+            setExit(1);
+            return;
+         };
+         break;
+
+      default:
+         panic ( "uncompress: bad srcMode" );
+         break;
+   }
+
+   if (verbosity >= 1) {
+      fprintf ( stderr, "  %s: ", inName );
+      pad ( inName );
+      fflush ( stderr );
+   }
+
+   /*--- Now the input and output handles are sane.  Do the Biz. ---*/
+   outputHandleJustInCase = outStr;
+   deleteOutputOnInterrupt = True;
+   magicNumberOK = uncompressStream ( inStr, outStr );
+   outputHandleJustInCase = NULL;
+
+   /*--- If there was an I/O error, we won't get here. ---*/
+   if ( magicNumberOK ) {
+      if ( srcMode == SM_F2F ) {
+         applySavedTimeInfoToOutputFile ( outName );
+         deleteOutputOnInterrupt = False;
+         if ( !keepInputFiles ) {
+            IntNative retVal = remove ( inName );
+            ERROR_IF_NOT_ZERO ( retVal );
+         }
+      }
+   } else {
+      unzFailsExist = True;
+      deleteOutputOnInterrupt = False;
+      if ( srcMode == SM_F2F ) {
+         IntNative retVal = remove ( outName );
+         ERROR_IF_NOT_ZERO ( retVal );
+      }
+   }
+   deleteOutputOnInterrupt = False;
+
+   if ( magicNumberOK ) {
+      if (verbosity >= 1)
+         fprintf ( stderr, "done\n" );
+   } else {
+      setExit(2);
+      if (verbosity >= 1)
+         fprintf ( stderr, "not a bzip2 file.\n" ); else
+         fprintf ( stderr,
+                   "%s: %s is not a bzip2 file.\n",
+                   progName, inName );
+   }
+
+}
+
+
+/*---------------------------------------------*/
+static 
+void testf ( Char *name )
+{
+   FILE *inStr;
+   Bool allOK;
+   struct MY_STAT statBuf;
+
+   deleteOutputOnInterrupt = False;
+
+   if (name == NULL && srcMode != SM_I2O)
+      panic ( "testf: bad modes\n" );
+
+   copyFileName ( outName, (Char*)"(none)" );
+   switch (srcMode) {
+      case SM_I2O: copyFileName ( inName, (Char*)"(stdin)" ); break;
+      case SM_F2F: copyFileName ( inName, name ); break;
+      case SM_F2O: copyFileName ( inName, name ); break;
+   }
+
+   if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
+      if (noisy)
+      fprintf ( stderr, "%s: There are no files matching `%s'.\n",
+                progName, inName );
+      setExit(1);
+      return;
+   }
+   if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
+      fprintf ( stderr, "%s: Can't open input %s: %s.\n",
+                progName, inName, strerror(errno) );
+      setExit(1);
+      return;
+   }
+   if ( srcMode != SM_I2O ) {
+      MY_STAT(inName, &statBuf);
+      if ( MY_S_ISDIR(statBuf.st_mode) ) {
+         fprintf( stderr,
+                  "%s: Input file %s is a directory.\n",
+                  progName,inName);
+         setExit(1);
+         return;
+      }
+   }
+
+   switch ( srcMode ) {
+
+      case SM_I2O:
+         if ( isatty ( fileno ( stdin ) ) ) {
+            fprintf ( stderr,
+                      "%s: I won't read compressed data from a terminal.\n",
+                      progName );
+            fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
+                              progName, progName );
+            setExit(1);
+            return;
+         };
+         inStr = stdin;
+         break;
+
+      case SM_F2O: case SM_F2F:
+         inStr = fopen ( inName, "rb" );
+         if ( inStr == NULL ) {
+            fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
+                      progName, inName, strerror(errno) );
+            setExit(1);
+            return;
+         };
+         break;
+
+      default:
+         panic ( "testf: bad srcMode" );
+         break;
+   }
+
+   if (verbosity >= 1) {
+      fprintf ( stderr, "  %s: ", inName );
+      pad ( inName );
+      fflush ( stderr );
+   }
+
+   /*--- Now the input handle is sane.  Do the Biz. ---*/
+   outputHandleJustInCase = NULL;
+   allOK = testStream ( inStr );
+
+   if (allOK && verbosity >= 1) fprintf ( stderr, "ok\n" );
+   if (!allOK) testFailsExist = True;
+}
+
+
+/*---------------------------------------------*/
+static 
+void license ( void )
+{
+   fprintf ( stderr,
+
+    "bzip2, a block-sorting file compressor.  "
+    "Version %s.\n"
+    "   \n"
+    "   Copyright (C) 1996-2019 by Julian Seward.\n"
+    "   \n"
+    "   This program is free software; you can redistribute it and/or modify\n"
+    "   it under the terms set out in the LICENSE file, which is included\n"
+    "   in the bzip2 source distribution.\n"
+    "   \n"
+    "   This program is distributed in the hope that it will be useful,\n"
+    "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+    "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
+    "   LICENSE file for more details.\n"
+    "   \n",
+    BZ2_bzlibVersion()
+   );
+}
+
+
+/*---------------------------------------------*/
+static 
+void usage ( Char *fullProgName )
+{
+   fprintf (
+      stderr,
+      "bzip2, a block-sorting file compressor.  "
+      "Version %s.\n"
+      "\n   usage: %s [flags and input files in any order]\n"
+      "\n"
+      "   -h --help           print this message\n"
+      "   -d --decompress     force decompression\n"
+      "   -z --compress       force compression\n"
+      "   -k --keep           keep (don't delete) input files\n"
+      "   -f --force          overwrite existing output files\n"
+      "   -t --test           test compressed file integrity\n"
+      "   -c --stdout         output to standard out\n"
+      "   -q --quiet          suppress noncritical error messages\n"
+      "   -v --verbose        be verbose (a 2nd -v gives more)\n"
+      "   -L --license        display software version & license\n"
+      "   -V --version        display software version & license\n"
+      "   -s --small          use less memory (at most 2500k)\n"
+      "   -1 .. -9            set block size to 100k .. 900k\n"
+      "   --fast              alias for -1\n"
+      "   --best              alias for -9\n"
+      "\n"
+      "   If invoked as `bzip2', default action is to compress.\n"
+      "              as `bunzip2',  default action is to decompress.\n"
+      "              as `bzcat', default action is to decompress to stdout.\n"
+      "\n"
+      "   If no file names are given, bzip2 compresses or decompresses\n"
+      "   from standard input to standard output.  You can combine\n"
+      "   short flags, so `-v -4' means the same as -v4 or -4v, &c.\n"
+#     if BZ_UNIX
+      "\n"
+#     endif
+      ,
+
+      BZ2_bzlibVersion(),
+      fullProgName
+   );
+}
+
+
+/*---------------------------------------------*/
+static 
+void redundant ( Char* flag )
+{
+   fprintf ( 
+      stderr, 
+      "%s: %s is redundant in versions 0.9.5 and above\n",
+      progName, flag );
+}
+
+
+/*---------------------------------------------*/
+/*--
+  All the garbage from here to main() is purely to
+  implement a linked list of command-line arguments,
+  into which main() copies argv[1 .. argc-1].
+
+  The purpose of this exercise is to facilitate 
+  the expansion of wildcard characters * and ? in 
+  filenames for OSs which don't know how to do it
+  themselves, like MSDOS, Windows 95 and NT.
+
+  The actual Dirty Work is done by the platform-
+  specific macro APPEND_FILESPEC.
+--*/
+
+typedef
+   struct zzzz {
+      Char        *name;
+      struct zzzz *link;
+   }
+   Cell;
+
+
+/*---------------------------------------------*/
+static 
+void *myMalloc ( Int32 n )
+{
+   void* p;
+
+   p = malloc ( (size_t)n );
+   if (p == NULL) outOfMemory ();
+   return p;
+}
+
+
+/*---------------------------------------------*/
+static 
+Cell *mkCell ( void )
+{
+   Cell *c;
+
+   c = (Cell*) myMalloc ( sizeof ( Cell ) );
+   c->name = NULL;
+   c->link = NULL;
+   return c;
+}
+
+
+/*---------------------------------------------*/
+static 
+Cell *snocString ( Cell *root, Char *name )
+{
+   if (root == NULL) {
+      Cell *tmp = mkCell();
+      tmp->name = (Char*) myMalloc ( 5 + strlen(name) );
+      strcpy ( tmp->name, name );
+      return tmp;
+   } else {
+      Cell *tmp = root;
+      while (tmp->link != NULL) tmp = tmp->link;
+      tmp->link = snocString ( tmp->link, name );
+      return root;
+   }
+}
+
+
+/*---------------------------------------------*/
+static 
+void addFlagsFromEnvVar ( Cell** argList, Char* varName ) 
+{
+   Int32 i, j, k;
+   Char *envbase, *p;
+
+   envbase = getenv(varName);
+   if (envbase != NULL) {
+      p = envbase;
+      i = 0;
+      while (True) {
+         if (p[i] == 0) break;
+         p += i;
+         i = 0;
+         while (isspace((Int32)(p[0]))) p++;
+         while (p[i] != 0 && !isspace((Int32)(p[i]))) i++;
+         if (i > 0) {
+            k = i; if (k > FILE_NAME_LEN-10) k = FILE_NAME_LEN-10;
+            for (j = 0; j < k; j++) tmpName[j] = p[j];
+            tmpName[k] = 0;
+            APPEND_FLAG(*argList, tmpName);
+         }
+      }
+   }
+}
+
+
+/*---------------------------------------------*/
+#define ISFLAG(s) (strcmp(aa->name, (s))==0)
+
+IntNative main ( IntNative argc, Char *argv[] )
+{
+   Int32  i, j;
+   Char   *tmp;
+   Cell   *argList;
+   Cell   *aa;
+   Bool   decode;
+
+   /*-- Be really really really paranoid :-) --*/
+   if (sizeof(Int32) != 4 || sizeof(UInt32) != 4  ||
+       sizeof(Int16) != 2 || sizeof(UInt16) != 2  ||
+       sizeof(Char)  != 1 || sizeof(UChar)  != 1)
+      configError();
+
+   /*-- Initialise --*/
+   outputHandleJustInCase  = NULL;
+   smallMode               = False;
+   keepInputFiles          = False;
+   forceOverwrite          = False;
+   noisy                   = True;
+   verbosity               = 0;
+   blockSize100k           = 9;
+   testFailsExist          = False;
+   unzFailsExist           = False;
+   numFileNames            = 0;
+   numFilesProcessed       = 0;
+   workFactor              = 30;
+   deleteOutputOnInterrupt = False;
+   exitValue               = 0;
+   i = j = 0; /* avoid bogus warning from egcs-1.1.X */
+
+   /*-- Set up signal handlers for mem access errors --*/
+   signal (SIGSEGV, mySIGSEGVorSIGBUScatcher);
+#  if BZ_UNIX
+#  ifndef __DJGPP__
+   signal (SIGBUS,  mySIGSEGVorSIGBUScatcher);
+#  endif
+#  endif
+
+   copyFileName ( inName,  (Char*)"(none)" );
+   copyFileName ( outName, (Char*)"(none)" );
+
+   copyFileName ( progNameReally, argv[0] );
+   progName = &progNameReally[0];
+   for (tmp = &progNameReally[0]; *tmp != '\0'; tmp++)
+      if (*tmp == PATH_SEP) progName = tmp + 1;
+
+
+   /*-- Copy flags from env var BZIP2, and 
+        expand filename wildcards in arg list.
+   --*/
+   argList = NULL;
+   addFlagsFromEnvVar ( &argList,  (Char*)"BZIP2" );
+   addFlagsFromEnvVar ( &argList,  (Char*)"BZIP" );
+   for (i = 1; i <= argc-1; i++)
+      APPEND_FILESPEC(argList, argv[i]);
+
+
+   /*-- Find the length of the longest filename --*/
+   longestFileName = 7;
+   numFileNames    = 0;
+   decode          = True;
+   for (aa = argList; aa != NULL; aa = aa->link) {
+      if (ISFLAG("--")) { decode = False; continue; }
+      if (aa->name[0] == '-' && decode) continue;
+      numFileNames++;
+      if (longestFileName < (Int32)strlen(aa->name) )
+         longestFileName = (Int32)strlen(aa->name);
+   }
+
+
+   /*-- Determine source modes; flag handling may change this too. --*/
+   if (numFileNames == 0)
+      srcMode = SM_I2O; else srcMode = SM_F2F;
+
+
+   /*-- Determine what to do (compress/uncompress/test/cat). --*/
+   /*-- Note that subsequent flag handling may change this. --*/
+   opMode = OM_Z;
+
+   if ( (strstr ( progName, "unzip" ) != 0) ||
+        (strstr ( progName, "UNZIP" ) != 0) )
+      opMode = OM_UNZ;
+
+   if ( (strstr ( progName, "z2cat" ) != 0) ||
+        (strstr ( progName, "Z2CAT" ) != 0) ||
+        (strstr ( progName, "zcat" ) != 0)  ||
+        (strstr ( progName, "ZCAT" ) != 0) )  {
+      opMode = OM_UNZ;
+      srcMode = (numFileNames == 0) ? SM_I2O : SM_F2O;
+   }
+
+
+   /*-- Look at the flags. --*/
+   for (aa = argList; aa != NULL; aa = aa->link) {
+      if (ISFLAG("--")) break;
+      if (aa->name[0] == '-' && aa->name[1] != '-') {
+         for (j = 1; aa->name[j] != '\0'; j++) {
+            switch (aa->name[j]) {
+               case 'c': srcMode          = SM_F2O; break;
+               case 'd': opMode           = OM_UNZ; break;
+               case 'z': opMode           = OM_Z; break;
+               case 'f': forceOverwrite   = True; break;
+               case 't': opMode           = OM_TEST; break;
+               case 'k': keepInputFiles   = True; break;
+               case 's': smallMode        = True; break;
+               case 'q': noisy            = False; break;
+               case '1': blockSize100k    = 1; break;
+               case '2': blockSize100k    = 2; break;
+               case '3': blockSize100k    = 3; break;
+               case '4': blockSize100k    = 4; break;
+               case '5': blockSize100k    = 5; break;
+               case '6': blockSize100k    = 6; break;
+               case '7': blockSize100k    = 7; break;
+               case '8': blockSize100k    = 8; break;
+               case '9': blockSize100k    = 9; break;
+               case 'V':
+               case 'L': license();            break;
+               case 'v': verbosity++; break;
+               case 'h': usage ( progName );
+                         exit ( 0 );
+                         break;
+               default:  fprintf ( stderr, "%s: Bad flag `%s'\n",
+                                   progName, aa->name );
+                         usage ( progName );
+                         exit ( 1 );
+                         break;
+            }
+         }
+      }
+   }
+   
+   /*-- And again ... --*/
+   for (aa = argList; aa != NULL; aa = aa->link) {
+      if (ISFLAG("--")) break;
+      if (ISFLAG("--stdout"))            srcMode          = SM_F2O;  else
+      if (ISFLAG("--decompress"))        opMode           = OM_UNZ;  else
+      if (ISFLAG("--compress"))          opMode           = OM_Z;    else
+      if (ISFLAG("--force"))             forceOverwrite   = True;    else
+      if (ISFLAG("--test"))              opMode           = OM_TEST; else
+      if (ISFLAG("--keep"))              keepInputFiles   = True;    else
+      if (ISFLAG("--small"))             smallMode        = True;    else
+      if (ISFLAG("--quiet"))             noisy            = False;   else
+      if (ISFLAG("--version"))           license();                  else
+      if (ISFLAG("--license"))           license();                  else
+      if (ISFLAG("--exponential"))       workFactor = 1;             else 
+      if (ISFLAG("--repetitive-best"))   redundant(aa->name);        else
+      if (ISFLAG("--repetitive-fast"))   redundant(aa->name);        else
+      if (ISFLAG("--fast"))              blockSize100k = 1;          else
+      if (ISFLAG("--best"))              blockSize100k = 9;          else
+      if (ISFLAG("--verbose"))           verbosity++;                else
+      if (ISFLAG("--help"))              { usage ( progName ); exit ( 0 ); }
+         else
+         if (strncmp ( aa->name, "--", 2) == 0) {
+            fprintf ( stderr, "%s: Bad flag `%s'\n", progName, aa->name );
+            usage ( progName );
+            exit ( 1 );
+         }
+   }
+
+   if (verbosity > 4) verbosity = 4;
+   if (opMode == OM_Z && smallMode && blockSize100k > 2) 
+      blockSize100k = 2;
+
+   if (opMode == OM_TEST && srcMode == SM_F2O) {
+      fprintf ( stderr, "%s: -c and -t cannot be used together.\n",
+                progName );
+      exit ( 1 );
+   }
+
+   if (srcMode == SM_F2O && numFileNames == 0)
+      srcMode = SM_I2O;
+
+   if (opMode != OM_Z) blockSize100k = 0;
+
+   if (srcMode == SM_F2F) {
+      signal (SIGINT,  mySignalCatcher);
+      signal (SIGTERM, mySignalCatcher);
+#     if BZ_UNIX
+      signal (SIGHUP,  mySignalCatcher);
+#     endif
+   }
+
+   if (opMode == OM_Z) {
+     if (srcMode == SM_I2O) {
+        compress ( NULL );
+     } else {
+        decode = True;
+        for (aa = argList; aa != NULL; aa = aa->link) {
+           if (ISFLAG("--")) { decode = False; continue; }
+           if (aa->name[0] == '-' && decode) continue;
+           numFilesProcessed++;
+           compress ( aa->name );
+        }
+     }
+   } 
+   else
+
+   if (opMode == OM_UNZ) {
+      unzFailsExist = False;
+      if (srcMode == SM_I2O) {
+         uncompress ( NULL );
+      } else {
+         decode = True;
+         for (aa = argList; aa != NULL; aa = aa->link) {
+            if (ISFLAG("--")) { decode = False; continue; }
+            if (aa->name[0] == '-' && decode) continue;
+            numFilesProcessed++;
+            uncompress ( aa->name );
+         }      
+      }
+      if (unzFailsExist) { 
+         setExit(2); 
+         exit(exitValue);
+      }
+   } 
+
+   else {
+      testFailsExist = False;
+      if (srcMode == SM_I2O) {
+         testf ( NULL );
+      } else {
+         decode = True;
+         for (aa = argList; aa != NULL; aa = aa->link) {
+	    if (ISFLAG("--")) { decode = False; continue; }
+            if (aa->name[0] == '-' && decode) continue;
+            numFilesProcessed++;
+            testf ( aa->name );
+	 }
+      }
+      if (testFailsExist) {
+	 if (noisy) {
+            fprintf ( stderr,
+               "\n"
+               "You can use the `bzip2recover' program to attempt to recover\n"
+               "data from undamaged sections of corrupted files.\n\n"
+            );
+	 }
+         setExit(2);
+         exit(exitValue);
+      }
+   }
+
+   /* Free the argument list memory to mollify leak detectors 
+      (eg) Purify, Checker.  Serves no other useful purpose.
+   */
+   aa = argList;
+   while (aa != NULL) {
+      Cell* aa2 = aa->link;
+      if (aa->name != NULL) free(aa->name);
+      free(aa);
+      aa = aa2;
+   }
+
+   return exitValue;
+}
+
+
+/*-----------------------------------------------------------*/
+/*--- end                                         bzip2.c ---*/
+/*-----------------------------------------------------------*/
diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2recover.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2recover.c
new file mode 100644
index 00000000000..a8131e0611e
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzip2recover.c
@@ -0,0 +1,516 @@
+/*-----------------------------------------------------------*/
+/*--- Block recoverer program for bzip2                   ---*/
+/*---                                      bzip2recover.c ---*/
+/*-----------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+/* This program is a complete hack and should be rewritten properly.
+	 It isn't very complicated. */
+
+#include 
+#include 
+#include 
+#include 
+
+
+/* This program records bit locations in the file to be recovered.
+   That means that if 64-bit ints are not supported, we will not
+   be able to recover .bz2 files over 512MB (2^32 bits) long.
+   On GNU supported platforms, we take advantage of the 64-bit
+   int support to circumvent this problem.  Ditto MSVC.
+
+   This change occurred in version 1.0.2; all prior versions have
+   the 512MB limitation.
+*/
+#ifdef __GNUC__
+   typedef  unsigned long long int  MaybeUInt64;
+#  define MaybeUInt64_FMT "%Lu"
+#else
+#ifdef _MSC_VER
+   typedef  unsigned __int64  MaybeUInt64;
+#  define MaybeUInt64_FMT "%I64u"
+#else
+   typedef  unsigned int   MaybeUInt64;
+#  define MaybeUInt64_FMT "%u"
+#endif
+#endif
+
+typedef  unsigned int   UInt32;
+typedef  int            Int32;
+typedef  unsigned char  UChar;
+typedef  char           Char;
+typedef  unsigned char  Bool;
+#define True    ((Bool)1)
+#define False   ((Bool)0)
+
+
+#define BZ_MAX_FILENAME 2000
+
+Char inFileName[BZ_MAX_FILENAME];
+Char outFileName[BZ_MAX_FILENAME];
+Char progName[BZ_MAX_FILENAME];
+
+MaybeUInt64 bytesOut = 0;
+MaybeUInt64 bytesIn  = 0;
+
+
+/*---------------------------------------------------*/
+/*--- Header bytes                                ---*/
+/*---------------------------------------------------*/
+
+#define BZ_HDR_B 0x42                         /* 'B' */
+#define BZ_HDR_Z 0x5a                         /* 'Z' */
+#define BZ_HDR_h 0x68                         /* 'h' */
+#define BZ_HDR_0 0x30                         /* '0' */
+ 
+
+/*---------------------------------------------------*/
+/*--- I/O errors                                  ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+static void readError ( void )
+{
+   fprintf ( stderr,
+             "%s: I/O error reading `%s', possible reason follows.\n",
+            progName, inFileName );
+   perror ( progName );
+   fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
+             progName );
+   exit ( 1 );
+}
+
+
+/*---------------------------------------------*/
+static void writeError ( void )
+{
+   fprintf ( stderr,
+             "%s: I/O error reading `%s', possible reason follows.\n",
+            progName, inFileName );
+   perror ( progName );
+   fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
+             progName );
+   exit ( 1 );
+}
+
+
+/*---------------------------------------------*/
+static void mallocFail ( Int32 n )
+{
+   fprintf ( stderr,
+             "%s: malloc failed on request for %d bytes.\n",
+            progName, n );
+   fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
+             progName );
+   exit ( 1 );
+}
+
+
+/*---------------------------------------------*/
+static void tooManyBlocks ( Int32 max_handled_blocks )
+{
+   fprintf ( stderr,
+             "%s: `%s' appears to contain more than %d blocks\n",
+            progName, inFileName, max_handled_blocks );
+   fprintf ( stderr,
+             "%s: and cannot be handled.  To fix, increase\n",
+             progName );
+   fprintf ( stderr, 
+             "%s: BZ_MAX_HANDLED_BLOCKS in bzip2recover.c, and recompile.\n",
+             progName );
+   exit ( 1 );
+}
+
+
+
+/*---------------------------------------------------*/
+/*--- Bit stream I/O                              ---*/
+/*---------------------------------------------------*/
+
+typedef
+   struct {
+      FILE*  handle;
+      Int32  buffer;
+      Int32  buffLive;
+      Char   mode;
+   }
+   BitStream;
+
+
+/*---------------------------------------------*/
+static BitStream* bsOpenReadStream ( FILE* stream )
+{
+   BitStream *bs = malloc ( sizeof(BitStream) );
+   if (bs == NULL) mallocFail ( sizeof(BitStream) );
+   bs->handle = stream;
+   bs->buffer = 0;
+   bs->buffLive = 0;
+   bs->mode = 'r';
+   return bs;
+}
+
+
+/*---------------------------------------------*/
+static BitStream* bsOpenWriteStream ( FILE* stream )
+{
+   BitStream *bs = malloc ( sizeof(BitStream) );
+   if (bs == NULL) mallocFail ( sizeof(BitStream) );
+   bs->handle = stream;
+   bs->buffer = 0;
+   bs->buffLive = 0;
+   bs->mode = 'w';
+   return bs;
+}
+
+
+/*---------------------------------------------*/
+static void bsPutBit ( BitStream* bs, Int32 bit )
+{
+   if (bs->buffLive == 8) {
+      Int32 retVal = putc ( (UChar) bs->buffer, bs->handle );
+      if (retVal == EOF) writeError();
+      bytesOut++;
+      bs->buffLive = 1;
+      bs->buffer = bit & 0x1;
+   } else {
+      bs->buffer = ( (bs->buffer << 1) | (bit & 0x1) );
+      bs->buffLive++;
+   };
+}
+
+
+/*---------------------------------------------*/
+/*--
+   Returns 0 or 1, or 2 to indicate EOF.
+--*/
+static Int32 bsGetBit ( BitStream* bs )
+{
+   if (bs->buffLive > 0) {
+      bs->buffLive --;
+      return ( ((bs->buffer) >> (bs->buffLive)) & 0x1 );
+   } else {
+      Int32 retVal = getc ( bs->handle );
+      if ( retVal == EOF ) {
+         if (errno != 0) readError();
+         return 2;
+      }
+      bs->buffLive = 7;
+      bs->buffer = retVal;
+      return ( ((bs->buffer) >> 7) & 0x1 );
+   }
+}
+
+
+/*---------------------------------------------*/
+static void bsClose ( BitStream* bs )
+{
+   Int32 retVal;
+
+   if ( bs->mode == 'w' ) {
+      while ( bs->buffLive < 8 ) {
+         bs->buffLive++;
+         bs->buffer <<= 1;
+      };
+      retVal = putc ( (UChar) (bs->buffer), bs->handle );
+      if (retVal == EOF) writeError();
+      bytesOut++;
+      retVal = fflush ( bs->handle );
+      if (retVal == EOF) writeError();
+   }
+   retVal = fclose ( bs->handle );
+   if (retVal == EOF) {
+      if (bs->mode == 'w') writeError(); else readError();
+   }
+   free ( bs );
+}
+
+
+/*---------------------------------------------*/
+static void bsPutUChar ( BitStream* bs, UChar c )
+{
+   Int32 i;
+   for (i = 7; i >= 0; i--)
+      bsPutBit ( bs, (((UInt32) c) >> i) & 0x1 );
+}
+
+
+/*---------------------------------------------*/
+static void bsPutUInt32 ( BitStream* bs, UInt32 c )
+{
+   Int32 i;
+
+   for (i = 31; i >= 0; i--)
+      bsPutBit ( bs, (c >> i) & 0x1 );
+}
+
+
+/*---------------------------------------------*/
+static Bool endsInBz2 ( Char* name )
+{
+   Int32 n = strlen ( name );
+   if (n <= 4) return False;
+   return
+      (name[n-4] == '.' &&
+       name[n-3] == 'b' &&
+       name[n-2] == 'z' &&
+       name[n-1] == '2');
+}
+
+
+/*---------------------------------------------------*/
+/*---                                             ---*/
+/*---------------------------------------------------*/
+
+/* This logic isn't really right when it comes to Cygwin. */
+#ifdef _WIN32
+#  define  BZ_SPLIT_SYM  '\\'  /* path splitter on Windows platform */
+#else
+#  define  BZ_SPLIT_SYM  '/'   /* path splitter on Unix platform */
+#endif
+
+#define BLOCK_HEADER_HI  0x00003141UL
+#define BLOCK_HEADER_LO  0x59265359UL
+
+#define BLOCK_ENDMARK_HI 0x00001772UL
+#define BLOCK_ENDMARK_LO 0x45385090UL
+
+/* Increase if necessary.  However, a .bz2 file with > 50000 blocks
+   would have an uncompressed size of at least 40GB, so the chances
+   are low you'll need to up this.
+*/
+#define BZ_MAX_HANDLED_BLOCKS 50000
+
+MaybeUInt64 bStart [BZ_MAX_HANDLED_BLOCKS];
+MaybeUInt64 bEnd   [BZ_MAX_HANDLED_BLOCKS];
+MaybeUInt64 rbStart[BZ_MAX_HANDLED_BLOCKS];
+MaybeUInt64 rbEnd  [BZ_MAX_HANDLED_BLOCKS];
+
+Int32 main ( Int32 argc, Char** argv )
+{
+   FILE*       inFile;
+   FILE*       outFile;
+   BitStream*  bsIn, *bsWr;
+   Int32       b, wrBlock, currBlock, rbCtr;
+   MaybeUInt64 bitsRead;
+
+   UInt32      buffHi, buffLo, blockCRC;
+   Char*       p;
+
+   strncpy ( progName, argv[0], BZ_MAX_FILENAME-1);
+   progName[BZ_MAX_FILENAME-1]='\0';
+   inFileName[0] = outFileName[0] = 0;
+
+   fprintf ( stderr, 
+             "bzip2recover 1.0.8: extracts blocks from damaged .bz2 files.\n" );
+
+   if (argc != 2) {
+      fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n",
+                        progName, progName );
+      switch (sizeof(MaybeUInt64)) {
+         case 8:
+            fprintf(stderr, 
+                    "\trestrictions on size of recovered file: None\n");
+            break;
+         case 4:
+            fprintf(stderr, 
+                    "\trestrictions on size of recovered file: 512 MB\n");
+            fprintf(stderr, 
+                    "\tto circumvent, recompile with MaybeUInt64 as an\n"
+                    "\tunsigned 64-bit int.\n");
+            break;
+         default:
+            fprintf(stderr, 
+                    "\tsizeof(MaybeUInt64) is not 4 or 8 -- "
+                    "configuration error.\n");
+            break;
+      }
+      exit(1);
+   }
+
+   if (strlen(argv[1]) >= BZ_MAX_FILENAME-20) {
+      fprintf ( stderr, 
+                "%s: supplied filename is suspiciously (>= %d chars) long.  Bye!\n",
+                progName, (int)strlen(argv[1]) );
+      exit(1);
+   }
+
+   strcpy ( inFileName, argv[1] );
+
+   inFile = fopen ( inFileName, "rb" );
+   if (inFile == NULL) {
+      fprintf ( stderr, "%s: can't read `%s'\n", progName, inFileName );
+      exit(1);
+   }
+
+   bsIn = bsOpenReadStream ( inFile );
+   fprintf ( stderr, "%s: searching for block boundaries ...\n", progName );
+
+   bitsRead = 0;
+   buffHi = buffLo = 0;
+   currBlock = 0;
+   bStart[currBlock] = 0;
+
+   rbCtr = 0;
+
+   while (True) {
+      b = bsGetBit ( bsIn );
+      bitsRead++;
+      if (b == 2) {
+         if (bitsRead >= bStart[currBlock] &&
+            (bitsRead - bStart[currBlock]) >= 40) {
+            bEnd[currBlock] = bitsRead-1;
+            if (currBlock > 0)
+               fprintf ( stderr, "   block %d runs from " MaybeUInt64_FMT 
+                                 " to " MaybeUInt64_FMT " (incomplete)\n",
+                         currBlock,  bStart[currBlock], bEnd[currBlock] );
+         } else
+            currBlock--;
+         break;
+      }
+      buffHi = (buffHi << 1) | (buffLo >> 31);
+      buffLo = (buffLo << 1) | (b & 1);
+      if ( ( (buffHi & 0x0000ffff) == BLOCK_HEADER_HI 
+             && buffLo == BLOCK_HEADER_LO)
+           || 
+           ( (buffHi & 0x0000ffff) == BLOCK_ENDMARK_HI 
+             && buffLo == BLOCK_ENDMARK_LO)
+         ) {
+         if (bitsRead > 49) {
+            bEnd[currBlock] = bitsRead-49;
+         } else {
+            bEnd[currBlock] = 0;
+         }
+         if (currBlock > 0 &&
+	     (bEnd[currBlock] - bStart[currBlock]) >= 130) {
+            fprintf ( stderr, "   block %d runs from " MaybeUInt64_FMT 
+                              " to " MaybeUInt64_FMT "\n",
+                      rbCtr+1,  bStart[currBlock], bEnd[currBlock] );
+            rbStart[rbCtr] = bStart[currBlock];
+            rbEnd[rbCtr] = bEnd[currBlock];
+            rbCtr++;
+         }
+         if (currBlock >= BZ_MAX_HANDLED_BLOCKS)
+            tooManyBlocks(BZ_MAX_HANDLED_BLOCKS);
+         currBlock++;
+
+         bStart[currBlock] = bitsRead;
+      }
+   }
+
+   bsClose ( bsIn );
+
+   /*-- identified blocks run from 1 to rbCtr inclusive. --*/
+
+   if (rbCtr < 1) {
+      fprintf ( stderr,
+                "%s: sorry, I couldn't find any block boundaries.\n",
+                progName );
+      exit(1);
+   };
+
+   fprintf ( stderr, "%s: splitting into blocks\n", progName );
+
+   inFile = fopen ( inFileName, "rb" );
+   if (inFile == NULL) {
+      fprintf ( stderr, "%s: can't open `%s'\n", progName, inFileName );
+      exit(1);
+   }
+   bsIn = bsOpenReadStream ( inFile );
+
+   /*-- placate gcc's dataflow analyser --*/
+   blockCRC = 0; bsWr = 0;
+
+   bitsRead = 0;
+   outFile = NULL;
+   wrBlock = 0;
+   while (True) {
+      b = bsGetBit(bsIn);
+      if (b == 2) break;
+      buffHi = (buffHi << 1) | (buffLo >> 31);
+      buffLo = (buffLo << 1) | (b & 1);
+      if (bitsRead == 47+rbStart[wrBlock]) 
+         blockCRC = (buffHi << 16) | (buffLo >> 16);
+
+      if (outFile != NULL && bitsRead >= rbStart[wrBlock]
+                          && bitsRead <= rbEnd[wrBlock]) {
+         bsPutBit ( bsWr, b );
+      }
+
+      bitsRead++;
+
+      if (bitsRead == rbEnd[wrBlock]+1) {
+         if (outFile != NULL) {
+            bsPutUChar ( bsWr, 0x17 ); bsPutUChar ( bsWr, 0x72 );
+            bsPutUChar ( bsWr, 0x45 ); bsPutUChar ( bsWr, 0x38 );
+            bsPutUChar ( bsWr, 0x50 ); bsPutUChar ( bsWr, 0x90 );
+            bsPutUInt32 ( bsWr, blockCRC );
+            bsClose ( bsWr );
+            outFile = NULL;
+         }
+         if (wrBlock >= rbCtr) break;
+         wrBlock++;
+      } else
+      if (bitsRead == rbStart[wrBlock]) {
+         /* Create the output file name, correctly handling leading paths. 
+            (31.10.2001 by Sergey E. Kusikov) */
+         Char* split;
+         Int32 ofs, k;
+         for (k = 0; k < BZ_MAX_FILENAME; k++) 
+            outFileName[k] = 0;
+         strcpy (outFileName, inFileName);
+         split = strrchr (outFileName, BZ_SPLIT_SYM);
+         if (split == NULL) {
+            split = outFileName;
+         } else {
+            ++split;
+	 }
+	 /* Now split points to the start of the basename. */
+         ofs  = split - outFileName;
+         sprintf (split, "rec%5d", wrBlock+1);
+         for (p = split; *p != 0; p++) if (*p == ' ') *p = '0';
+         strcat (outFileName, inFileName + ofs);
+
+         if ( !endsInBz2(outFileName)) strcat ( outFileName, ".bz2" );
+
+         fprintf ( stderr, "   writing block %d to `%s' ...\n",
+                           wrBlock+1, outFileName );
+
+         outFile = fopen ( outFileName, "wb" );
+         if (outFile == NULL) {
+            fprintf ( stderr, "%s: can't write `%s'\n",
+                      progName, outFileName );
+            exit(1);
+         }
+         bsWr = bsOpenWriteStream ( outFile );
+         bsPutUChar ( bsWr, BZ_HDR_B );    
+         bsPutUChar ( bsWr, BZ_HDR_Z );    
+         bsPutUChar ( bsWr, BZ_HDR_h );    
+         bsPutUChar ( bsWr, BZ_HDR_0 + 9 );
+         bsPutUChar ( bsWr, 0x31 ); bsPutUChar ( bsWr, 0x41 );
+         bsPutUChar ( bsWr, 0x59 ); bsPutUChar ( bsWr, 0x26 );
+         bsPutUChar ( bsWr, 0x53 ); bsPutUChar ( bsWr, 0x59 );
+      }
+   }
+
+   fprintf ( stderr, "%s: finished\n", progName );
+   return 0;
+}
+
+
+
+/*-----------------------------------------------------------*/
+/*--- end                                  bzip2recover.c ---*/
+/*-----------------------------------------------------------*/
diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.c
new file mode 100644
index 00000000000..21786551b60
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.c
@@ -0,0 +1,1572 @@
+
+/*-------------------------------------------------------------*/
+/*--- Library top-level functions.                          ---*/
+/*---                                               bzlib.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+/* CHANGES
+   0.9.0    -- original version.
+   0.9.0a/b -- no changes in this file.
+   0.9.0c   -- made zero-length BZ_FLUSH work correctly in bzCompress().
+     fixed bzWrite/bzRead to ignore zero-length requests.
+     fixed bzread to correctly handle read requests after EOF.
+     wrong parameter order in call to bzDecompressInit in
+     bzBuffToBuffDecompress.  Fixed.
+*/
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+/*--- Compression stuff                           ---*/
+/*---------------------------------------------------*/
+
+
+/*---------------------------------------------------*/
+#ifndef BZ_NO_STDIO
+void BZ2_bz__AssertH__fail ( int errcode )
+{
+   fprintf(stderr, 
+      "\n\nbzip2/libbzip2: internal error number %d.\n"
+      "This is a bug in bzip2/libbzip2, %s.\n"
+      "Please report it to: bzip2-devel@sourceware.org.  If this happened\n"
+      "when you were using some program which uses libbzip2 as a\n"
+      "component, you should also report this bug to the author(s)\n"
+      "of that program.  Please make an effort to report this bug;\n"
+      "timely and accurate bug reports eventually lead to higher\n"
+      "quality software.  Thanks.\n\n",
+      errcode,
+      BZ2_bzlibVersion()
+   );
+
+   if (errcode == 1007) {
+   fprintf(stderr,
+      "\n*** A special note about internal error number 1007 ***\n"
+      "\n"
+      "Experience suggests that a common cause of i.e. 1007\n"
+      "is unreliable memory or other hardware.  The 1007 assertion\n"
+      "just happens to cross-check the results of huge numbers of\n"
+      "memory reads/writes, and so acts (unintendedly) as a stress\n"
+      "test of your memory system.\n"
+      "\n"
+      "I suggest the following: try compressing the file again,\n"
+      "possibly monitoring progress in detail with the -vv flag.\n"
+      "\n"
+      "* If the error cannot be reproduced, and/or happens at different\n"
+      "  points in compression, you may have a flaky memory system.\n"
+      "  Try a memory-test program.  I have used Memtest86\n"
+      "  (www.memtest86.com).  At the time of writing it is free (GPLd).\n"
+      "  Memtest86 tests memory much more thorougly than your BIOSs\n"
+      "  power-on test, and may find failures that the BIOS doesn't.\n"
+      "\n"
+      "* If the error can be repeatably reproduced, this is a bug in\n"
+      "  bzip2, and I would very much like to hear about it.  Please\n"
+      "  let me know, and, ideally, save a copy of the file causing the\n"
+      "  problem -- without which I will be unable to investigate it.\n"
+      "\n"
+   );
+   }
+
+   exit(3);
+}
+#endif
+
+
+/*---------------------------------------------------*/
+static
+int bz_config_ok ( void )
+{
+   if (sizeof(int)   != 4) return 0;
+   if (sizeof(short) != 2) return 0;
+   if (sizeof(char)  != 1) return 0;
+   return 1;
+}
+
+
+/*---------------------------------------------------*/
+static
+void* default_bzalloc ( void* opaque, Int32 items, Int32 size )
+{
+   void* v = malloc ( items * size );
+   return v;
+}
+
+static
+void default_bzfree ( void* opaque, void* addr )
+{
+   if (addr != NULL) free ( addr );
+}
+
+
+/*---------------------------------------------------*/
+static
+void prepare_new_block ( EState* s )
+{
+   Int32 i;
+   s->nblock = 0;
+   s->numZ = 0;
+   s->state_out_pos = 0;
+   BZ_INITIALISE_CRC ( s->blockCRC );
+   for (i = 0; i < 256; i++) s->inUse[i] = False;
+   s->blockNo++;
+}
+
+
+/*---------------------------------------------------*/
+static
+void init_RL ( EState* s )
+{
+   s->state_in_ch  = 256;
+   s->state_in_len = 0;
+}
+
+
+static
+Bool isempty_RL ( EState* s )
+{
+   if (s->state_in_ch < 256 && s->state_in_len > 0)
+      return False; else
+      return True;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompressInit) 
+                    ( bz_stream* strm, 
+                     int        blockSize100k,
+                     int        verbosity,
+                     int        workFactor )
+{
+   Int32   n;
+   EState* s;
+
+   if (!bz_config_ok()) return BZ_CONFIG_ERROR;
+
+   if (strm == NULL || 
+       blockSize100k < 1 || blockSize100k > 9 ||
+       workFactor < 0 || workFactor > 250)
+     return BZ_PARAM_ERROR;
+
+   if (workFactor == 0) workFactor = 30;
+   if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
+   if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
+
+   s = BZALLOC( sizeof(EState) );
+   if (s == NULL) return BZ_MEM_ERROR;
+   s->strm = strm;
+
+   s->arr1 = NULL;
+   s->arr2 = NULL;
+   s->ftab = NULL;
+
+   n       = 100000 * blockSize100k;
+   s->arr1 = BZALLOC( n                  * sizeof(UInt32) );
+   s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) );
+   s->ftab = BZALLOC( 65537              * sizeof(UInt32) );
+
+   if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) {
+      if (s->arr1 != NULL) BZFREE(s->arr1);
+      if (s->arr2 != NULL) BZFREE(s->arr2);
+      if (s->ftab != NULL) BZFREE(s->ftab);
+      if (s       != NULL) BZFREE(s);
+      return BZ_MEM_ERROR;
+   }
+
+   s->blockNo           = 0;
+   s->state             = BZ_S_INPUT;
+   s->mode              = BZ_M_RUNNING;
+   s->combinedCRC       = 0;
+   s->blockSize100k     = blockSize100k;
+   s->nblockMAX         = 100000 * blockSize100k - 19;
+   s->verbosity         = verbosity;
+   s->workFactor        = workFactor;
+
+   s->block             = (UChar*)s->arr2;
+   s->mtfv              = (UInt16*)s->arr1;
+   s->zbits             = NULL;
+   s->ptr               = (UInt32*)s->arr1;
+
+   strm->state          = s;
+   strm->total_in_lo32  = 0;
+   strm->total_in_hi32  = 0;
+   strm->total_out_lo32 = 0;
+   strm->total_out_hi32 = 0;
+   init_RL ( s );
+   prepare_new_block ( s );
+   return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+static
+void add_pair_to_block ( EState* s )
+{
+   Int32 i;
+   UChar ch = (UChar)(s->state_in_ch);
+   for (i = 0; i < s->state_in_len; i++) {
+      BZ_UPDATE_CRC( s->blockCRC, ch );
+   }
+   s->inUse[s->state_in_ch] = True;
+   switch (s->state_in_len) {
+      case 1:
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         break;
+      case 2:
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         break;
+      case 3:
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         break;
+      default:
+         s->inUse[s->state_in_len-4] = True;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = ((UChar)(s->state_in_len-4));
+         s->nblock++;
+         break;
+   }
+}
+
+
+/*---------------------------------------------------*/
+static
+void flush_RL ( EState* s )
+{
+   if (s->state_in_ch < 256) add_pair_to_block ( s );
+   init_RL ( s );
+}
+
+
+/*---------------------------------------------------*/
+#define ADD_CHAR_TO_BLOCK(zs,zchh0)               \
+{                                                 \
+   UInt32 zchh = (UInt32)(zchh0);                 \
+   /*-- fast track the common case --*/           \
+   if (zchh != zs->state_in_ch &&                 \
+       zs->state_in_len == 1) {                   \
+      UChar ch = (UChar)(zs->state_in_ch);        \
+      BZ_UPDATE_CRC( zs->blockCRC, ch );          \
+      zs->inUse[zs->state_in_ch] = True;          \
+      zs->block[zs->nblock] = (UChar)ch;          \
+      zs->nblock++;                               \
+      zs->state_in_ch = zchh;                     \
+   }                                              \
+   else                                           \
+   /*-- general, uncommon cases --*/              \
+   if (zchh != zs->state_in_ch ||                 \
+      zs->state_in_len == 255) {                  \
+      if (zs->state_in_ch < 256)                  \
+         add_pair_to_block ( zs );                \
+      zs->state_in_ch = zchh;                     \
+      zs->state_in_len = 1;                       \
+   } else {                                       \
+      zs->state_in_len++;                         \
+   }                                              \
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool copy_input_until_stop ( EState* s )
+{
+   Bool progress_in = False;
+
+   if (s->mode == BZ_M_RUNNING) {
+
+      /*-- fast track the common case --*/
+      while (True) {
+         /*-- block full? --*/
+         if (s->nblock >= s->nblockMAX) break;
+         /*-- no input? --*/
+         if (s->strm->avail_in == 0) break;
+         progress_in = True;
+         ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); 
+         s->strm->next_in++;
+         s->strm->avail_in--;
+         s->strm->total_in_lo32++;
+         if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
+      }
+
+   } else {
+
+      /*-- general, uncommon case --*/
+      while (True) {
+         /*-- block full? --*/
+         if (s->nblock >= s->nblockMAX) break;
+         /*-- no input? --*/
+         if (s->strm->avail_in == 0) break;
+         /*-- flush/finish end? --*/
+         if (s->avail_in_expect == 0) break;
+         progress_in = True;
+         ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); 
+         s->strm->next_in++;
+         s->strm->avail_in--;
+         s->strm->total_in_lo32++;
+         if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
+         s->avail_in_expect--;
+      }
+   }
+   return progress_in;
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool copy_output_until_stop ( EState* s )
+{
+   Bool progress_out = False;
+
+   while (True) {
+
+      /*-- no output space? --*/
+      if (s->strm->avail_out == 0) break;
+
+      /*-- block done? --*/
+      if (s->state_out_pos >= s->numZ) break;
+
+      progress_out = True;
+      *(s->strm->next_out) = s->zbits[s->state_out_pos];
+      s->state_out_pos++;
+      s->strm->avail_out--;
+      s->strm->next_out++;
+      s->strm->total_out_lo32++;
+      if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+   }
+
+   return progress_out;
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool handle_compress ( bz_stream* strm )
+{
+   Bool progress_in  = False;
+   Bool progress_out = False;
+   EState* s = strm->state;
+   
+   while (True) {
+
+      if (s->state == BZ_S_OUTPUT) {
+         progress_out |= copy_output_until_stop ( s );
+         if (s->state_out_pos < s->numZ) break;
+         if (s->mode == BZ_M_FINISHING && 
+             s->avail_in_expect == 0 &&
+             isempty_RL(s)) break;
+         prepare_new_block ( s );
+         s->state = BZ_S_INPUT;
+         if (s->mode == BZ_M_FLUSHING && 
+             s->avail_in_expect == 0 &&
+             isempty_RL(s)) break;
+      }
+
+      if (s->state == BZ_S_INPUT) {
+         progress_in |= copy_input_until_stop ( s );
+         if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
+            flush_RL ( s );
+            BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) );
+            s->state = BZ_S_OUTPUT;
+         }
+         else
+         if (s->nblock >= s->nblockMAX) {
+            BZ2_compressBlock ( s, False );
+            s->state = BZ_S_OUTPUT;
+         }
+         else
+         if (s->strm->avail_in == 0) {
+            break;
+         }
+      }
+
+   }
+
+   return progress_in || progress_out;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action )
+{
+   Bool progress;
+   EState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   preswitch:
+   switch (s->mode) {
+
+      case BZ_M_IDLE:
+         return BZ_SEQUENCE_ERROR;
+
+      case BZ_M_RUNNING:
+         if (action == BZ_RUN) {
+            progress = handle_compress ( strm );
+            return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;
+         } 
+         else
+	 if (action == BZ_FLUSH) {
+            s->avail_in_expect = strm->avail_in;
+            s->mode = BZ_M_FLUSHING;
+            goto preswitch;
+         }
+         else
+         if (action == BZ_FINISH) {
+            s->avail_in_expect = strm->avail_in;
+            s->mode = BZ_M_FINISHING;
+            goto preswitch;
+         }
+         else 
+            return BZ_PARAM_ERROR;
+
+      case BZ_M_FLUSHING:
+         if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR;
+         if (s->avail_in_expect != s->strm->avail_in) 
+            return BZ_SEQUENCE_ERROR;
+         progress = handle_compress ( strm );
+         if (s->avail_in_expect > 0 || !isempty_RL(s) ||
+             s->state_out_pos < s->numZ) return BZ_FLUSH_OK;
+         s->mode = BZ_M_RUNNING;
+         return BZ_RUN_OK;
+
+      case BZ_M_FINISHING:
+         if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR;
+         if (s->avail_in_expect != s->strm->avail_in) 
+            return BZ_SEQUENCE_ERROR;
+         progress = handle_compress ( strm );
+         if (!progress) return BZ_SEQUENCE_ERROR;
+         if (s->avail_in_expect > 0 || !isempty_RL(s) ||
+             s->state_out_pos < s->numZ) return BZ_FINISH_OK;
+         s->mode = BZ_M_IDLE;
+         return BZ_STREAM_END;
+   }
+   return BZ_OK; /*--not reached--*/
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompressEnd)  ( bz_stream *strm )
+{
+   EState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   if (s->arr1 != NULL) BZFREE(s->arr1);
+   if (s->arr2 != NULL) BZFREE(s->arr2);
+   if (s->ftab != NULL) BZFREE(s->ftab);
+   BZFREE(strm->state);
+
+   strm->state = NULL;   
+
+   return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+/*--- Decompression stuff                         ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompressInit) 
+                     ( bz_stream* strm, 
+                       int        verbosity,
+                       int        small )
+{
+   DState* s;
+
+   if (!bz_config_ok()) return BZ_CONFIG_ERROR;
+
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   if (small != 0 && small != 1) return BZ_PARAM_ERROR;
+   if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR;
+
+   if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
+   if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
+
+   s = BZALLOC( sizeof(DState) );
+   if (s == NULL) return BZ_MEM_ERROR;
+   s->strm                  = strm;
+   strm->state              = s;
+   s->state                 = BZ_X_MAGIC_1;
+   s->bsLive                = 0;
+   s->bsBuff                = 0;
+   s->calculatedCombinedCRC = 0;
+   strm->total_in_lo32      = 0;
+   strm->total_in_hi32      = 0;
+   strm->total_out_lo32     = 0;
+   strm->total_out_hi32     = 0;
+   s->smallDecompress       = (Bool)small;
+   s->ll4                   = NULL;
+   s->ll16                  = NULL;
+   s->tt                    = NULL;
+   s->currBlockNo           = 0;
+   s->verbosity             = verbosity;
+
+   return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+/* Return  True iff data corruption is discovered.
+   Returns False if there is no problem.
+*/
+static
+Bool unRLE_obuf_to_output_FAST ( DState* s )
+{
+   UChar k1;
+
+   if (s->blockRandomised) {
+
+      while (True) {
+         /* try to finish existing run */
+         while (True) {
+            if (s->strm->avail_out == 0) return False;
+            if (s->state_out_len == 0) break;
+            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+            s->state_out_len--;
+            s->strm->next_out++;
+            s->strm->avail_out--;
+            s->strm->total_out_lo32++;
+            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+         }
+
+         /* can a new run be started? */
+         if (s->nblock_used == s->save_nblock+1) return False;
+               
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
+   
+         s->state_out_len = 1;
+         s->state_out_ch = s->k0;
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 2;
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 3;
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         s->state_out_len = ((Int32)k1) + 4;
+         BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; 
+         s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
+      }
+
+   } else {
+
+      /* restore */
+      UInt32        c_calculatedBlockCRC = s->calculatedBlockCRC;
+      UChar         c_state_out_ch       = s->state_out_ch;
+      Int32         c_state_out_len      = s->state_out_len;
+      Int32         c_nblock_used        = s->nblock_used;
+      Int32         c_k0                 = s->k0;
+      UInt32*       c_tt                 = s->tt;
+      UInt32        c_tPos               = s->tPos;
+      char*         cs_next_out          = s->strm->next_out;
+      unsigned int  cs_avail_out         = s->strm->avail_out;
+      Int32         ro_blockSize100k     = s->blockSize100k;
+      /* end restore */
+
+      UInt32       avail_out_INIT = cs_avail_out;
+      Int32        s_save_nblockPP = s->save_nblock+1;
+      unsigned int total_out_lo32_old;
+
+      while (True) {
+
+         /* try to finish existing run */
+         if (c_state_out_len > 0) {
+            while (True) {
+               if (cs_avail_out == 0) goto return_notr;
+               if (c_state_out_len == 1) break;
+               *( (UChar*)(cs_next_out) ) = c_state_out_ch;
+               BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
+               c_state_out_len--;
+               cs_next_out++;
+               cs_avail_out--;
+            }
+            s_state_out_len_eq_one:
+            {
+               if (cs_avail_out == 0) { 
+                  c_state_out_len = 1; goto return_notr;
+               };
+               *( (UChar*)(cs_next_out) ) = c_state_out_ch;
+               BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
+               cs_next_out++;
+               cs_avail_out--;
+            }
+         }   
+         /* Only caused by corrupt data stream? */
+         if (c_nblock_used > s_save_nblockPP)
+            return True;
+
+         /* can a new run be started? */
+         if (c_nblock_used == s_save_nblockPP) {
+            c_state_out_len = 0; goto return_notr;
+         };   
+         c_state_out_ch = c_k0;
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         if (k1 != c_k0) { 
+            c_k0 = k1; goto s_state_out_len_eq_one; 
+         };
+         if (c_nblock_used == s_save_nblockPP) 
+            goto s_state_out_len_eq_one;
+   
+         c_state_out_len = 2;
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         if (c_nblock_used == s_save_nblockPP) continue;
+         if (k1 != c_k0) { c_k0 = k1; continue; };
+   
+         c_state_out_len = 3;
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         if (c_nblock_used == s_save_nblockPP) continue;
+         if (k1 != c_k0) { c_k0 = k1; continue; };
+   
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         c_state_out_len = ((Int32)k1) + 4;
+         BZ_GET_FAST_C(c_k0); c_nblock_used++;
+      }
+
+      return_notr:
+      total_out_lo32_old = s->strm->total_out_lo32;
+      s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
+      if (s->strm->total_out_lo32 < total_out_lo32_old)
+         s->strm->total_out_hi32++;
+
+      /* save */
+      s->calculatedBlockCRC = c_calculatedBlockCRC;
+      s->state_out_ch       = c_state_out_ch;
+      s->state_out_len      = c_state_out_len;
+      s->nblock_used        = c_nblock_used;
+      s->k0                 = c_k0;
+      s->tt                 = c_tt;
+      s->tPos               = c_tPos;
+      s->strm->next_out     = cs_next_out;
+      s->strm->avail_out    = cs_avail_out;
+      /* end save */
+   }
+   return False;
+}
+
+
+
+/*---------------------------------------------------*/
+__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab )
+{
+   Int32 nb, na, mid;
+   nb = 0;
+   na = 256;
+   do {
+      mid = (nb + na) >> 1;
+      if (indx >= cftab[mid]) nb = mid; else na = mid;
+   }
+   while (na - nb != 1);
+   return nb;
+}
+
+
+/*---------------------------------------------------*/
+/* Return  True iff data corruption is discovered.
+   Returns False if there is no problem.
+*/
+static
+Bool unRLE_obuf_to_output_SMALL ( DState* s )
+{
+   UChar k1;
+
+   if (s->blockRandomised) {
+
+      while (True) {
+         /* try to finish existing run */
+         while (True) {
+            if (s->strm->avail_out == 0) return False;
+            if (s->state_out_len == 0) break;
+            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+            s->state_out_len--;
+            s->strm->next_out++;
+            s->strm->avail_out--;
+            s->strm->total_out_lo32++;
+            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+         }
+   
+         /* can a new run be started? */
+         if (s->nblock_used == s->save_nblock+1) return False;
+
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
+   
+         s->state_out_len = 1;
+         s->state_out_ch = s->k0;
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 2;
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 3;
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         s->state_out_len = ((Int32)k1) + 4;
+         BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; 
+         s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
+      }
+
+   } else {
+
+      while (True) {
+         /* try to finish existing run */
+         while (True) {
+            if (s->strm->avail_out == 0) return False;
+            if (s->state_out_len == 0) break;
+            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+            s->state_out_len--;
+            s->strm->next_out++;
+            s->strm->avail_out--;
+            s->strm->total_out_lo32++;
+            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+         }
+   
+         /* can a new run be started? */
+         if (s->nblock_used == s->save_nblock+1) return False;
+
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
+   
+         s->state_out_len = 1;
+         s->state_out_ch = s->k0;
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 2;
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 3;
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         s->state_out_len = ((Int32)k1) + 4;
+         BZ_GET_SMALL(s->k0); s->nblock_used++;
+      }
+
+   }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
+{
+   Bool    corrupt;
+   DState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   while (True) {
+      if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
+      if (s->state == BZ_X_OUTPUT) {
+         if (s->smallDecompress)
+            corrupt = unRLE_obuf_to_output_SMALL ( s ); else
+            corrupt = unRLE_obuf_to_output_FAST  ( s );
+         if (corrupt) return BZ_DATA_ERROR;
+         if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
+            BZ_FINALISE_CRC ( s->calculatedBlockCRC );
+            if (s->verbosity >= 3) 
+               VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, 
+                          s->calculatedBlockCRC );
+            if (s->verbosity >= 2) VPrintf0 ( "]" );
+            if (s->calculatedBlockCRC != s->storedBlockCRC)
+               return BZ_DATA_ERROR;
+            s->calculatedCombinedCRC 
+               = (s->calculatedCombinedCRC << 1) | 
+                    (s->calculatedCombinedCRC >> 31);
+            s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
+            s->state = BZ_X_BLKHDR_1;
+         } else {
+            return BZ_OK;
+         }
+      }
+      if (s->state >= BZ_X_MAGIC_1) {
+         Int32 r = BZ2_decompress ( s );
+         if (r == BZ_STREAM_END) {
+            if (s->verbosity >= 3)
+               VPrintf2 ( "\n    combined CRCs: stored = 0x%08x, computed = 0x%08x", 
+                          s->storedCombinedCRC, s->calculatedCombinedCRC );
+            if (s->calculatedCombinedCRC != s->storedCombinedCRC)
+               return BZ_DATA_ERROR;
+            return r;
+         }
+         if (s->state != BZ_X_OUTPUT) return r;
+      }
+   }
+
+   AssertH ( 0, 6001 );
+
+   return 0;  /*NOTREACHED*/
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompressEnd)  ( bz_stream *strm )
+{
+   DState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   if (s->tt   != NULL) BZFREE(s->tt);
+   if (s->ll16 != NULL) BZFREE(s->ll16);
+   if (s->ll4  != NULL) BZFREE(s->ll4);
+
+   BZFREE(strm->state);
+   strm->state = NULL;
+
+   return BZ_OK;
+}
+
+
+#ifndef BZ_NO_STDIO
+/*---------------------------------------------------*/
+/*--- File I/O stuff                              ---*/
+/*---------------------------------------------------*/
+
+#define BZ_SETERR(eee)                    \
+{                                         \
+   if (bzerror != NULL) *bzerror = eee;   \
+   if (bzf != NULL) bzf->lastErr = eee;   \
+}
+
+typedef 
+   struct {
+      FILE*     handle;
+      Char      buf[BZ_MAX_UNUSED];
+      Int32     bufN;
+      Bool      writing;
+      bz_stream strm;
+      Int32     lastErr;
+      Bool      initialisedOk;
+   }
+   bzFile;
+
+
+/*---------------------------------------------*/
+static Bool myfeof ( FILE* f )
+{
+   Int32 c = fgetc ( f );
+   if (c == EOF) return True;
+   ungetc ( c, f );
+   return False;
+}
+
+
+/*---------------------------------------------------*/
+BZFILE* BZ_API(BZ2_bzWriteOpen) 
+                    ( int*  bzerror,      
+                      FILE* f, 
+                      int   blockSize100k, 
+                      int   verbosity,
+                      int   workFactor )
+{
+   Int32   ret;
+   bzFile* bzf = NULL;
+
+   BZ_SETERR(BZ_OK);
+
+   if (f == NULL ||
+       (blockSize100k < 1 || blockSize100k > 9) ||
+       (workFactor < 0 || workFactor > 250) ||
+       (verbosity < 0 || verbosity > 4))
+      { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
+
+   if (ferror(f))
+      { BZ_SETERR(BZ_IO_ERROR); return NULL; };
+
+   bzf = malloc ( sizeof(bzFile) );
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
+
+   BZ_SETERR(BZ_OK);
+   bzf->initialisedOk = False;
+   bzf->bufN          = 0;
+   bzf->handle        = f;
+   bzf->writing       = True;
+   bzf->strm.bzalloc  = NULL;
+   bzf->strm.bzfree   = NULL;
+   bzf->strm.opaque   = NULL;
+
+   if (workFactor == 0) workFactor = 30;
+   ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, 
+                              verbosity, workFactor );
+   if (ret != BZ_OK)
+      { BZ_SETERR(ret); free(bzf); return NULL; };
+
+   bzf->strm.avail_in = 0;
+   bzf->initialisedOk = True;
+   return bzf;   
+}
+
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzWrite)
+             ( int*    bzerror, 
+               BZFILE* b, 
+               void*   buf, 
+               int     len )
+{
+   Int32 n, n2, ret;
+   bzFile* bzf = (bzFile*)b;
+
+   BZ_SETERR(BZ_OK);
+   if (bzf == NULL || buf == NULL || len < 0)
+      { BZ_SETERR(BZ_PARAM_ERROR); return; };
+   if (!(bzf->writing))
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+   if (ferror(bzf->handle))
+      { BZ_SETERR(BZ_IO_ERROR); return; };
+
+   if (len == 0)
+      { BZ_SETERR(BZ_OK); return; };
+
+   bzf->strm.avail_in = len;
+   bzf->strm.next_in  = buf;
+
+   while (True) {
+      bzf->strm.avail_out = BZ_MAX_UNUSED;
+      bzf->strm.next_out = bzf->buf;
+      ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN );
+      if (ret != BZ_RUN_OK)
+         { BZ_SETERR(ret); return; };
+
+      if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
+         n = BZ_MAX_UNUSED - bzf->strm.avail_out;
+         n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), 
+                       n, bzf->handle );
+         if (n != n2 || ferror(bzf->handle))
+            { BZ_SETERR(BZ_IO_ERROR); return; };
+      }
+
+      if (bzf->strm.avail_in == 0)
+         { BZ_SETERR(BZ_OK); return; };
+   }
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzWriteClose)
+                  ( int*          bzerror, 
+                    BZFILE*       b, 
+                    int           abandon,
+                    unsigned int* nbytes_in,
+                    unsigned int* nbytes_out )
+{
+   BZ2_bzWriteClose64 ( bzerror, b, abandon, 
+                        nbytes_in, NULL, nbytes_out, NULL );
+}
+
+
+void BZ_API(BZ2_bzWriteClose64)
+                  ( int*          bzerror, 
+                    BZFILE*       b, 
+                    int           abandon,
+                    unsigned int* nbytes_in_lo32,
+                    unsigned int* nbytes_in_hi32,
+                    unsigned int* nbytes_out_lo32,
+                    unsigned int* nbytes_out_hi32 )
+{
+   Int32   n, n2, ret;
+   bzFile* bzf = (bzFile*)b;
+
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_OK); return; };
+   if (!(bzf->writing))
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+   if (ferror(bzf->handle))
+      { BZ_SETERR(BZ_IO_ERROR); return; };
+
+   if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0;
+   if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0;
+   if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0;
+   if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0;
+
+   if ((!abandon) && bzf->lastErr == BZ_OK) {
+      while (True) {
+         bzf->strm.avail_out = BZ_MAX_UNUSED;
+         bzf->strm.next_out = bzf->buf;
+         ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH );
+         if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
+            { BZ_SETERR(ret); return; };
+
+         if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
+            n = BZ_MAX_UNUSED - bzf->strm.avail_out;
+            n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), 
+                          n, bzf->handle );
+            if (n != n2 || ferror(bzf->handle))
+               { BZ_SETERR(BZ_IO_ERROR); return; };
+         }
+
+         if (ret == BZ_STREAM_END) break;
+      }
+   }
+
+   if ( !abandon && !ferror ( bzf->handle ) ) {
+      fflush ( bzf->handle );
+      if (ferror(bzf->handle))
+         { BZ_SETERR(BZ_IO_ERROR); return; };
+   }
+
+   if (nbytes_in_lo32 != NULL)
+      *nbytes_in_lo32 = bzf->strm.total_in_lo32;
+   if (nbytes_in_hi32 != NULL)
+      *nbytes_in_hi32 = bzf->strm.total_in_hi32;
+   if (nbytes_out_lo32 != NULL)
+      *nbytes_out_lo32 = bzf->strm.total_out_lo32;
+   if (nbytes_out_hi32 != NULL)
+      *nbytes_out_hi32 = bzf->strm.total_out_hi32;
+
+   BZ_SETERR(BZ_OK);
+   BZ2_bzCompressEnd ( &(bzf->strm) );
+   free ( bzf );
+}
+
+
+/*---------------------------------------------------*/
+BZFILE* BZ_API(BZ2_bzReadOpen) 
+                   ( int*  bzerror, 
+                     FILE* f, 
+                     int   verbosity,
+                     int   small,
+                     void* unused,
+                     int   nUnused )
+{
+   bzFile* bzf = NULL;
+   int     ret;
+
+   BZ_SETERR(BZ_OK);
+
+   if (f == NULL || 
+       (small != 0 && small != 1) ||
+       (verbosity < 0 || verbosity > 4) ||
+       (unused == NULL && nUnused != 0) ||
+       (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)))
+      { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
+
+   if (ferror(f))
+      { BZ_SETERR(BZ_IO_ERROR); return NULL; };
+
+   bzf = malloc ( sizeof(bzFile) );
+   if (bzf == NULL) 
+      { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
+
+   BZ_SETERR(BZ_OK);
+
+   bzf->initialisedOk = False;
+   bzf->handle        = f;
+   bzf->bufN          = 0;
+   bzf->writing       = False;
+   bzf->strm.bzalloc  = NULL;
+   bzf->strm.bzfree   = NULL;
+   bzf->strm.opaque   = NULL;
+   
+   while (nUnused > 0) {
+      bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++;
+      unused = ((void*)( 1 + ((UChar*)(unused))  ));
+      nUnused--;
+   }
+
+   ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small );
+   if (ret != BZ_OK)
+      { BZ_SETERR(ret); free(bzf); return NULL; };
+
+   bzf->strm.avail_in = bzf->bufN;
+   bzf->strm.next_in  = bzf->buf;
+
+   bzf->initialisedOk = True;
+   return bzf;   
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b )
+{
+   bzFile* bzf = (bzFile*)b;
+
+   BZ_SETERR(BZ_OK);
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_OK); return; };
+
+   if (bzf->writing)
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+
+   if (bzf->initialisedOk)
+      (void)BZ2_bzDecompressEnd ( &(bzf->strm) );
+   free ( bzf );
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzRead) 
+           ( int*    bzerror, 
+             BZFILE* b, 
+             void*   buf, 
+             int     len )
+{
+   Int32   n, ret;
+   bzFile* bzf = (bzFile*)b;
+
+   BZ_SETERR(BZ_OK);
+
+   if (bzf == NULL || buf == NULL || len < 0)
+      { BZ_SETERR(BZ_PARAM_ERROR); return 0; };
+
+   if (bzf->writing)
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; };
+
+   if (len == 0)
+      { BZ_SETERR(BZ_OK); return 0; };
+
+   bzf->strm.avail_out = len;
+   bzf->strm.next_out = buf;
+
+   while (True) {
+
+      if (ferror(bzf->handle)) 
+         { BZ_SETERR(BZ_IO_ERROR); return 0; };
+
+      if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) {
+         n = fread ( bzf->buf, sizeof(UChar), 
+                     BZ_MAX_UNUSED, bzf->handle );
+         if (ferror(bzf->handle))
+            { BZ_SETERR(BZ_IO_ERROR); return 0; };
+         bzf->bufN = n;
+         bzf->strm.avail_in = bzf->bufN;
+         bzf->strm.next_in = bzf->buf;
+      }
+
+      ret = BZ2_bzDecompress ( &(bzf->strm) );
+
+      if (ret != BZ_OK && ret != BZ_STREAM_END)
+         { BZ_SETERR(ret); return 0; };
+
+      if (ret == BZ_OK && myfeof(bzf->handle) && 
+          bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0)
+         { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; };
+
+      if (ret == BZ_STREAM_END)
+         { BZ_SETERR(BZ_STREAM_END);
+           return len - bzf->strm.avail_out; };
+      if (bzf->strm.avail_out == 0)
+         { BZ_SETERR(BZ_OK); return len; };
+      
+   }
+
+   return 0; /*not reached*/
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzReadGetUnused) 
+                     ( int*    bzerror, 
+                       BZFILE* b, 
+                       void**  unused, 
+                       int*    nUnused )
+{
+   bzFile* bzf = (bzFile*)b;
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_PARAM_ERROR); return; };
+   if (bzf->lastErr != BZ_STREAM_END)
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+   if (unused == NULL || nUnused == NULL)
+      { BZ_SETERR(BZ_PARAM_ERROR); return; };
+
+   BZ_SETERR(BZ_OK);
+   *nUnused = bzf->strm.avail_in;
+   *unused = bzf->strm.next_in;
+}
+#endif
+
+
+/*---------------------------------------------------*/
+/*--- Misc convenience stuff                      ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzBuffToBuffCompress) 
+                         ( char*         dest, 
+                           unsigned int* destLen,
+                           char*         source, 
+                           unsigned int  sourceLen,
+                           int           blockSize100k, 
+                           int           verbosity, 
+                           int           workFactor )
+{
+   bz_stream strm;
+   int ret;
+
+   if (dest == NULL || destLen == NULL || 
+       source == NULL ||
+       blockSize100k < 1 || blockSize100k > 9 ||
+       verbosity < 0 || verbosity > 4 ||
+       workFactor < 0 || workFactor > 250) 
+      return BZ_PARAM_ERROR;
+
+   if (workFactor == 0) workFactor = 30;
+   strm.bzalloc = NULL;
+   strm.bzfree = NULL;
+   strm.opaque = NULL;
+   ret = BZ2_bzCompressInit ( &strm, blockSize100k, 
+                              verbosity, workFactor );
+   if (ret != BZ_OK) return ret;
+
+   strm.next_in = source;
+   strm.next_out = dest;
+   strm.avail_in = sourceLen;
+   strm.avail_out = *destLen;
+
+   ret = BZ2_bzCompress ( &strm, BZ_FINISH );
+   if (ret == BZ_FINISH_OK) goto output_overflow;
+   if (ret != BZ_STREAM_END) goto errhandler;
+
+   /* normal termination */
+   *destLen -= strm.avail_out;   
+   BZ2_bzCompressEnd ( &strm );
+   return BZ_OK;
+
+   output_overflow:
+   BZ2_bzCompressEnd ( &strm );
+   return BZ_OUTBUFF_FULL;
+
+   errhandler:
+   BZ2_bzCompressEnd ( &strm );
+   return ret;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzBuffToBuffDecompress) 
+                           ( char*         dest, 
+                             unsigned int* destLen,
+                             char*         source, 
+                             unsigned int  sourceLen,
+                             int           small,
+                             int           verbosity )
+{
+   bz_stream strm;
+   int ret;
+
+   if (dest == NULL || destLen == NULL || 
+       source == NULL ||
+       (small != 0 && small != 1) ||
+       verbosity < 0 || verbosity > 4) 
+          return BZ_PARAM_ERROR;
+
+   strm.bzalloc = NULL;
+   strm.bzfree = NULL;
+   strm.opaque = NULL;
+   ret = BZ2_bzDecompressInit ( &strm, verbosity, small );
+   if (ret != BZ_OK) return ret;
+
+   strm.next_in = source;
+   strm.next_out = dest;
+   strm.avail_in = sourceLen;
+   strm.avail_out = *destLen;
+
+   ret = BZ2_bzDecompress ( &strm );
+   if (ret == BZ_OK) goto output_overflow_or_eof;
+   if (ret != BZ_STREAM_END) goto errhandler;
+
+   /* normal termination */
+   *destLen -= strm.avail_out;
+   BZ2_bzDecompressEnd ( &strm );
+   return BZ_OK;
+
+   output_overflow_or_eof:
+   if (strm.avail_out > 0) {
+      BZ2_bzDecompressEnd ( &strm );
+      return BZ_UNEXPECTED_EOF;
+   } else {
+      BZ2_bzDecompressEnd ( &strm );
+      return BZ_OUTBUFF_FULL;
+   };      
+
+   errhandler:
+   BZ2_bzDecompressEnd ( &strm );
+   return ret; 
+}
+
+
+/*---------------------------------------------------*/
+/*--
+   Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
+   to support better zlib compatibility.
+   This code is not _officially_ part of libbzip2 (yet);
+   I haven't tested it, documented it, or considered the
+   threading-safeness of it.
+   If this code breaks, please contact both Yoshioka and me.
+--*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+/*--
+   return version like "0.9.5d, 4-Sept-1999".
+--*/
+const char * BZ_API(BZ2_bzlibVersion)(void)
+{
+   return BZ_VERSION;
+}
+
+
+#ifndef BZ_NO_STDIO
+/*---------------------------------------------------*/
+
+#if defined(_WIN32) || defined(OS2) || defined(MSDOS)
+#   include 
+#   include 
+#   define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
+#else
+#   define SET_BINARY_MODE(file)
+#endif
+static
+BZFILE * bzopen_or_bzdopen
+               ( const char *path,   /* no use when bzdopen */
+                 int fd,             /* no use when bzdopen */
+                 const char *mode,
+                 int open_mode)      /* bzopen: 0, bzdopen:1 */
+{
+   int    bzerr;
+   char   unused[BZ_MAX_UNUSED];
+   int    blockSize100k = 9;
+   int    writing       = 0;
+   char   mode2[10]     = "";
+   FILE   *fp           = NULL;
+   BZFILE *bzfp         = NULL;
+   int    verbosity     = 0;
+   int    workFactor    = 30;
+   int    smallMode     = 0;
+   int    nUnused       = 0; 
+
+   if (mode == NULL) return NULL;
+   while (*mode) {
+      switch (*mode) {
+      case 'r':
+         writing = 0; break;
+      case 'w':
+         writing = 1; break;
+      case 's':
+         smallMode = 1; break;
+      default:
+         if (isdigit((int)(*mode))) {
+            blockSize100k = *mode-BZ_HDR_0;
+         }
+      }
+      mode++;
+   }
+   strcat(mode2, writing ? "w" : "r" );
+   strcat(mode2,"b");   /* binary mode */
+
+   if (open_mode==0) {
+      if (path==NULL || strcmp(path,"")==0) {
+        fp = (writing ? stdout : stdin);
+        SET_BINARY_MODE(fp);
+      } else {
+        fp = fopen(path,mode2);
+      }
+   } else {
+#ifdef BZ_STRICT_ANSI
+      fp = NULL;
+#else
+      fp = fdopen(fd,mode2);
+#endif
+   }
+   if (fp == NULL) return NULL;
+
+   if (writing) {
+      /* Guard against total chaos and anarchy -- JRS */
+      if (blockSize100k < 1) blockSize100k = 1;
+      if (blockSize100k > 9) blockSize100k = 9; 
+      bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k,
+                             verbosity,workFactor);
+   } else {
+      bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode,
+                            unused,nUnused);
+   }
+   if (bzfp == NULL) {
+      if (fp != stdin && fp != stdout) fclose(fp);
+      return NULL;
+   }
+   return bzfp;
+}
+
+
+/*---------------------------------------------------*/
+/*--
+   open file for read or write.
+      ex) bzopen("file","w9")
+      case path="" or NULL => use stdin or stdout.
+--*/
+BZFILE * BZ_API(BZ2_bzopen)
+               ( const char *path,
+                 const char *mode )
+{
+   return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0);
+}
+
+
+/*---------------------------------------------------*/
+BZFILE * BZ_API(BZ2_bzdopen)
+               ( int fd,
+                 const char *mode )
+{
+   return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1);
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len )
+{
+   int bzerr, nread;
+   if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0;
+   nread = BZ2_bzRead(&bzerr,b,buf,len);
+   if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) {
+      return nread;
+   } else {
+      return -1;
+   }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len )
+{
+   int bzerr;
+
+   BZ2_bzWrite(&bzerr,b,buf,len);
+   if(bzerr == BZ_OK){
+      return len;
+   }else{
+      return -1;
+   }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzflush) (BZFILE *b)
+{
+   /* do nothing now... */
+   return 0;
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzclose) (BZFILE* b)
+{
+   int bzerr;
+   FILE *fp;
+   
+   if (b==NULL) {return;}
+   fp = ((bzFile *)b)->handle;
+   if(((bzFile*)b)->writing){
+      BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL);
+      if(bzerr != BZ_OK){
+         BZ2_bzWriteClose(NULL,b,1,NULL,NULL);
+      }
+   }else{
+      BZ2_bzReadClose(&bzerr,b);
+   }
+   if(fp!=stdin && fp!=stdout){
+      fclose(fp);
+   }
+}
+
+
+/*---------------------------------------------------*/
+/*--
+   return last error code 
+--*/
+static const char *bzerrorstrings[] = {
+       "OK"
+      ,"SEQUENCE_ERROR"
+      ,"PARAM_ERROR"
+      ,"MEM_ERROR"
+      ,"DATA_ERROR"
+      ,"DATA_ERROR_MAGIC"
+      ,"IO_ERROR"
+      ,"UNEXPECTED_EOF"
+      ,"OUTBUFF_FULL"
+      ,"CONFIG_ERROR"
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+};
+
+
+const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum)
+{
+   int err = ((bzFile *)b)->lastErr;
+
+   if(err>0) err = 0;
+   *errnum = err;
+   return bzerrorstrings[err*-1];
+}
+#endif
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                           bzlib.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.h b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.h
new file mode 100644
index 00000000000..b68a3f4c163
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib.h
@@ -0,0 +1,281 @@
+
+/*-------------------------------------------------------------*/
+/*--- Public header file for the library.                   ---*/
+/*---                                               bzlib.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+#ifndef _BZLIB_H
+#define _BZLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BZ_RUN               0
+#define BZ_FLUSH             1
+#define BZ_FINISH            2
+
+#define BZ_OK                0
+#define BZ_RUN_OK            1
+#define BZ_FLUSH_OK          2
+#define BZ_FINISH_OK         3
+#define BZ_STREAM_END        4
+#define BZ_SEQUENCE_ERROR    (-1)
+#define BZ_PARAM_ERROR       (-2)
+#define BZ_MEM_ERROR         (-3)
+#define BZ_DATA_ERROR        (-4)
+#define BZ_DATA_ERROR_MAGIC  (-5)
+#define BZ_IO_ERROR          (-6)
+#define BZ_UNEXPECTED_EOF    (-7)
+#define BZ_OUTBUFF_FULL      (-8)
+#define BZ_CONFIG_ERROR      (-9)
+
+typedef 
+   struct {
+      char *next_in;
+      unsigned int avail_in;
+      unsigned int total_in_lo32;
+      unsigned int total_in_hi32;
+
+      char *next_out;
+      unsigned int avail_out;
+      unsigned int total_out_lo32;
+      unsigned int total_out_hi32;
+
+      void *state;
+
+      void *(*bzalloc)(void *,int,int);
+      void (*bzfree)(void *,void *);
+      void *opaque;
+   } 
+   bz_stream;
+
+
+#ifndef BZ_IMPORT
+#define BZ_EXPORT
+#endif
+
+#ifndef BZ_NO_STDIO
+/* Need a definitition for FILE */
+#include 
+#endif
+
+#ifdef _WIN32
+#   include 
+#   ifdef small
+      /* windows.h define small to char */
+#      undef small
+#   endif
+#   ifdef BZ_EXPORT
+#   define BZ_API(func) WINAPI func
+#   define BZ_EXTERN extern
+#   else
+   /* import windows dll dynamically */
+#   define BZ_API(func) (WINAPI * func)
+#   define BZ_EXTERN
+#   endif
+#else
+#   define BZ_API(func) func
+#   define BZ_EXTERN extern
+#endif
+
+
+/*-- Core (low-level) library functions --*/
+
+BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( 
+      bz_stream* strm, 
+      int        blockSize100k, 
+      int        verbosity, 
+      int        workFactor 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompress) ( 
+      bz_stream* strm, 
+      int action 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( 
+      bz_stream* strm 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( 
+      bz_stream *strm, 
+      int       verbosity, 
+      int       small
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( 
+      bz_stream* strm 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( 
+      bz_stream *strm 
+   );
+
+
+
+/*-- High(er) level library functions --*/
+
+#ifndef BZ_NO_STDIO
+#define BZ_MAX_UNUSED 5000
+
+typedef void BZFILE;
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( 
+      int*  bzerror,   
+      FILE* f, 
+      int   verbosity, 
+      int   small,
+      void* unused,    
+      int   nUnused 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( 
+      int*    bzerror, 
+      BZFILE* b 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( 
+      int*    bzerror, 
+      BZFILE* b, 
+      void**  unused,  
+      int*    nUnused 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzRead) ( 
+      int*    bzerror, 
+      BZFILE* b, 
+      void*   buf, 
+      int     len 
+   );
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( 
+      int*  bzerror,      
+      FILE* f, 
+      int   blockSize100k, 
+      int   verbosity, 
+      int   workFactor 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzWrite) ( 
+      int*    bzerror, 
+      BZFILE* b, 
+      void*   buf, 
+      int     len 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( 
+      int*          bzerror, 
+      BZFILE*       b, 
+      int           abandon, 
+      unsigned int* nbytes_in, 
+      unsigned int* nbytes_out 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( 
+      int*          bzerror, 
+      BZFILE*       b, 
+      int           abandon, 
+      unsigned int* nbytes_in_lo32, 
+      unsigned int* nbytes_in_hi32, 
+      unsigned int* nbytes_out_lo32, 
+      unsigned int* nbytes_out_hi32
+   );
+#endif
+
+
+/*-- Utility functions --*/
+
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( 
+      char*         dest, 
+      unsigned int* destLen,
+      char*         source, 
+      unsigned int  sourceLen,
+      int           blockSize100k, 
+      int           verbosity, 
+      int           workFactor 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( 
+      char*         dest, 
+      unsigned int* destLen,
+      char*         source, 
+      unsigned int  sourceLen,
+      int           small, 
+      int           verbosity 
+   );
+
+
+/*--
+   Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
+   to support better zlib compatibility.
+   This code is not _officially_ part of libbzip2 (yet);
+   I haven't tested it, documented it, or considered the
+   threading-safeness of it.
+   If this code breaks, please contact both Yoshioka and me.
+--*/
+
+BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) (
+      void
+   );
+
+#ifndef BZ_NO_STDIO
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) (
+      const char *path,
+      const char *mode
+   );
+
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) (
+      int        fd,
+      const char *mode
+   );
+         
+BZ_EXTERN int BZ_API(BZ2_bzread) (
+      BZFILE* b, 
+      void* buf, 
+      int len 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzwrite) (
+      BZFILE* b, 
+      void*   buf, 
+      int     len 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzflush) (
+      BZFILE* b
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzclose) (
+      BZFILE* b
+   );
+
+BZ_EXTERN const char * BZ_API(BZ2_bzerror) (
+      BZFILE *b, 
+      int    *errnum
+   );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*-------------------------------------------------------------*/
+/*--- end                                           bzlib.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib_private.h b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib_private.h
new file mode 100644
index 00000000000..3755a6f701e
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/bzlib_private.h
@@ -0,0 +1,509 @@
+
+/*-------------------------------------------------------------*/
+/*--- Private header file for the library.                  ---*/
+/*---                                       bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#ifndef _BZLIB_PRIVATE_H
+#define _BZLIB_PRIVATE_H
+
+#include 
+
+#ifndef BZ_NO_STDIO
+#include 
+#include 
+#include 
+#endif
+
+#include "bzlib.h"
+
+
+
+/*-- General stuff. --*/
+
+#define BZ_VERSION  "1.0.8, 13-Jul-2019"
+
+typedef char            Char;
+typedef unsigned char   Bool;
+typedef unsigned char   UChar;
+typedef int             Int32;
+typedef unsigned int    UInt32;
+typedef short           Int16;
+typedef unsigned short  UInt16;
+
+#define True  ((Bool)1)
+#define False ((Bool)0)
+
+#ifndef __GNUC__
+#define __inline__  /* */
+#endif 
+
+#ifndef BZ_NO_STDIO
+
+extern void BZ2_bz__AssertH__fail ( int errcode );
+#define AssertH(cond,errcode) \
+   { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); }
+
+#if BZ_DEBUG
+#define AssertD(cond,msg) \
+   { if (!(cond)) {       \
+      fprintf ( stderr,   \
+        "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\
+      exit(1); \
+   }}
+#else
+#define AssertD(cond,msg) /* */
+#endif
+
+#define VPrintf0(zf) \
+   fprintf(stderr,zf)
+#define VPrintf1(zf,za1) \
+   fprintf(stderr,zf,za1)
+#define VPrintf2(zf,za1,za2) \
+   fprintf(stderr,zf,za1,za2)
+#define VPrintf3(zf,za1,za2,za3) \
+   fprintf(stderr,zf,za1,za2,za3)
+#define VPrintf4(zf,za1,za2,za3,za4) \
+   fprintf(stderr,zf,za1,za2,za3,za4)
+#define VPrintf5(zf,za1,za2,za3,za4,za5) \
+   fprintf(stderr,zf,za1,za2,za3,za4,za5)
+
+#else
+
+extern void bz_internal_error ( int errcode );
+#define AssertH(cond,errcode) \
+   { if (!(cond)) bz_internal_error ( errcode ); }
+#define AssertD(cond,msg)                do { } while (0)
+#define VPrintf0(zf)                     do { } while (0)
+#define VPrintf1(zf,za1)                 do { } while (0)
+#define VPrintf2(zf,za1,za2)             do { } while (0)
+#define VPrintf3(zf,za1,za2,za3)         do { } while (0)
+#define VPrintf4(zf,za1,za2,za3,za4)     do { } while (0)
+#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0)
+
+#endif
+
+
+#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1)
+#define BZFREE(ppp)  (strm->bzfree)(strm->opaque,(ppp))
+
+
+/*-- Header bytes. --*/
+
+#define BZ_HDR_B 0x42   /* 'B' */
+#define BZ_HDR_Z 0x5a   /* 'Z' */
+#define BZ_HDR_h 0x68   /* 'h' */
+#define BZ_HDR_0 0x30   /* '0' */
+  
+/*-- Constants for the back end. --*/
+
+#define BZ_MAX_ALPHA_SIZE 258
+#define BZ_MAX_CODE_LEN    23
+
+#define BZ_RUNA 0
+#define BZ_RUNB 1
+
+#define BZ_N_GROUPS 6
+#define BZ_G_SIZE   50
+#define BZ_N_ITERS  4
+
+#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
+
+
+
+/*-- Stuff for randomising repetitive blocks. --*/
+
+extern Int32 BZ2_rNums[512];
+
+#define BZ_RAND_DECLS                          \
+   Int32 rNToGo;                               \
+   Int32 rTPos                                 \
+
+#define BZ_RAND_INIT_MASK                      \
+   s->rNToGo = 0;                              \
+   s->rTPos  = 0                               \
+
+#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0)
+
+#define BZ_RAND_UPD_MASK                       \
+   if (s->rNToGo == 0) {                       \
+      s->rNToGo = BZ2_rNums[s->rTPos];         \
+      s->rTPos++;                              \
+      if (s->rTPos == 512) s->rTPos = 0;       \
+   }                                           \
+   s->rNToGo--;
+
+
+
+/*-- Stuff for doing CRCs. --*/
+
+extern UInt32 BZ2_crc32Table[256];
+
+#define BZ_INITIALISE_CRC(crcVar)              \
+{                                              \
+   crcVar = 0xffffffffL;                       \
+}
+
+#define BZ_FINALISE_CRC(crcVar)                \
+{                                              \
+   crcVar = ~(crcVar);                         \
+}
+
+#define BZ_UPDATE_CRC(crcVar,cha)              \
+{                                              \
+   crcVar = (crcVar << 8) ^                    \
+            BZ2_crc32Table[(crcVar >> 24) ^    \
+                           ((UChar)cha)];      \
+}
+
+
+
+/*-- States and modes for compression. --*/
+
+#define BZ_M_IDLE      1
+#define BZ_M_RUNNING   2
+#define BZ_M_FLUSHING  3
+#define BZ_M_FINISHING 4
+
+#define BZ_S_OUTPUT    1
+#define BZ_S_INPUT     2
+
+#define BZ_N_RADIX 2
+#define BZ_N_QSORT 12
+#define BZ_N_SHELL 18
+#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2)
+
+
+
+
+/*-- Structure holding all the compression-side stuff. --*/
+
+typedef
+   struct {
+      /* pointer back to the struct bz_stream */
+      bz_stream* strm;
+
+      /* mode this stream is in, and whether inputting */
+      /* or outputting data */
+      Int32    mode;
+      Int32    state;
+
+      /* remembers avail_in when flush/finish requested */
+      UInt32   avail_in_expect;
+
+      /* for doing the block sorting */
+      UInt32*  arr1;
+      UInt32*  arr2;
+      UInt32*  ftab;
+      Int32    origPtr;
+
+      /* aliases for arr1 and arr2 */
+      UInt32*  ptr;
+      UChar*   block;
+      UInt16*  mtfv;
+      UChar*   zbits;
+
+      /* for deciding when to use the fallback sorting algorithm */
+      Int32    workFactor;
+
+      /* run-length-encoding of the input */
+      UInt32   state_in_ch;
+      Int32    state_in_len;
+      BZ_RAND_DECLS;
+
+      /* input and output limits and current posns */
+      Int32    nblock;
+      Int32    nblockMAX;
+      Int32    numZ;
+      Int32    state_out_pos;
+
+      /* map of bytes used in block */
+      Int32    nInUse;
+      Bool     inUse[256];
+      UChar    unseqToSeq[256];
+
+      /* the buffer for bit stream creation */
+      UInt32   bsBuff;
+      Int32    bsLive;
+
+      /* block and combined CRCs */
+      UInt32   blockCRC;
+      UInt32   combinedCRC;
+
+      /* misc administratium */
+      Int32    verbosity;
+      Int32    blockNo;
+      Int32    blockSize100k;
+
+      /* stuff for coding the MTF values */
+      Int32    nMTF;
+      Int32    mtfFreq    [BZ_MAX_ALPHA_SIZE];
+      UChar    selector   [BZ_MAX_SELECTORS];
+      UChar    selectorMtf[BZ_MAX_SELECTORS];
+
+      UChar    len     [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    code    [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    rfreq   [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      /* second dimension: only 3 needed; 4 makes index calculations faster */
+      UInt32   len_pack[BZ_MAX_ALPHA_SIZE][4];
+
+   }
+   EState;
+
+
+
+/*-- externs for compression. --*/
+
+extern void 
+BZ2_blockSort ( EState* );
+
+extern void 
+BZ2_compressBlock ( EState*, Bool );
+
+extern void 
+BZ2_bsInitWrite ( EState* );
+
+extern void 
+BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 );
+
+extern void 
+BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 );
+
+
+
+/*-- states for decompression. --*/
+
+#define BZ_X_IDLE        1
+#define BZ_X_OUTPUT      2
+
+#define BZ_X_MAGIC_1     10
+#define BZ_X_MAGIC_2     11
+#define BZ_X_MAGIC_3     12
+#define BZ_X_MAGIC_4     13
+#define BZ_X_BLKHDR_1    14
+#define BZ_X_BLKHDR_2    15
+#define BZ_X_BLKHDR_3    16
+#define BZ_X_BLKHDR_4    17
+#define BZ_X_BLKHDR_5    18
+#define BZ_X_BLKHDR_6    19
+#define BZ_X_BCRC_1      20
+#define BZ_X_BCRC_2      21
+#define BZ_X_BCRC_3      22
+#define BZ_X_BCRC_4      23
+#define BZ_X_RANDBIT     24
+#define BZ_X_ORIGPTR_1   25
+#define BZ_X_ORIGPTR_2   26
+#define BZ_X_ORIGPTR_3   27
+#define BZ_X_MAPPING_1   28
+#define BZ_X_MAPPING_2   29
+#define BZ_X_SELECTOR_1  30
+#define BZ_X_SELECTOR_2  31
+#define BZ_X_SELECTOR_3  32
+#define BZ_X_CODING_1    33
+#define BZ_X_CODING_2    34
+#define BZ_X_CODING_3    35
+#define BZ_X_MTF_1       36
+#define BZ_X_MTF_2       37
+#define BZ_X_MTF_3       38
+#define BZ_X_MTF_4       39
+#define BZ_X_MTF_5       40
+#define BZ_X_MTF_6       41
+#define BZ_X_ENDHDR_2    42
+#define BZ_X_ENDHDR_3    43
+#define BZ_X_ENDHDR_4    44
+#define BZ_X_ENDHDR_5    45
+#define BZ_X_ENDHDR_6    46
+#define BZ_X_CCRC_1      47
+#define BZ_X_CCRC_2      48
+#define BZ_X_CCRC_3      49
+#define BZ_X_CCRC_4      50
+
+
+
+/*-- Constants for the fast MTF decoder. --*/
+
+#define MTFA_SIZE 4096
+#define MTFL_SIZE 16
+
+
+
+/*-- Structure holding all the decompression-side stuff. --*/
+
+typedef
+   struct {
+      /* pointer back to the struct bz_stream */
+      bz_stream* strm;
+
+      /* state indicator for this stream */
+      Int32    state;
+
+      /* for doing the final run-length decoding */
+      UChar    state_out_ch;
+      Int32    state_out_len;
+      Bool     blockRandomised;
+      BZ_RAND_DECLS;
+
+      /* the buffer for bit stream reading */
+      UInt32   bsBuff;
+      Int32    bsLive;
+
+      /* misc administratium */
+      Int32    blockSize100k;
+      Bool     smallDecompress;
+      Int32    currBlockNo;
+      Int32    verbosity;
+
+      /* for undoing the Burrows-Wheeler transform */
+      Int32    origPtr;
+      UInt32   tPos;
+      Int32    k0;
+      Int32    unzftab[256];
+      Int32    nblock_used;
+      Int32    cftab[257];
+      Int32    cftabCopy[257];
+
+      /* for undoing the Burrows-Wheeler transform (FAST) */
+      UInt32   *tt;
+
+      /* for undoing the Burrows-Wheeler transform (SMALL) */
+      UInt16   *ll16;
+      UChar    *ll4;
+
+      /* stored and calculated CRCs */
+      UInt32   storedBlockCRC;
+      UInt32   storedCombinedCRC;
+      UInt32   calculatedBlockCRC;
+      UInt32   calculatedCombinedCRC;
+
+      /* map of bytes used in block */
+      Int32    nInUse;
+      Bool     inUse[256];
+      Bool     inUse16[16];
+      UChar    seqToUnseq[256];
+
+      /* for decoding the MTF values */
+      UChar    mtfa   [MTFA_SIZE];
+      Int32    mtfbase[256 / MTFL_SIZE];
+      UChar    selector   [BZ_MAX_SELECTORS];
+      UChar    selectorMtf[BZ_MAX_SELECTORS];
+      UChar    len  [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+
+      Int32    limit  [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    base   [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    perm   [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    minLens[BZ_N_GROUPS];
+
+      /* save area for scalars in the main decompress code */
+      Int32    save_i;
+      Int32    save_j;
+      Int32    save_t;
+      Int32    save_alphaSize;
+      Int32    save_nGroups;
+      Int32    save_nSelectors;
+      Int32    save_EOB;
+      Int32    save_groupNo;
+      Int32    save_groupPos;
+      Int32    save_nextSym;
+      Int32    save_nblockMAX;
+      Int32    save_nblock;
+      Int32    save_es;
+      Int32    save_N;
+      Int32    save_curr;
+      Int32    save_zt;
+      Int32    save_zn; 
+      Int32    save_zvec;
+      Int32    save_zj;
+      Int32    save_gSel;
+      Int32    save_gMinlen;
+      Int32*   save_gLimit;
+      Int32*   save_gBase;
+      Int32*   save_gPerm;
+
+   }
+   DState;
+
+
+
+/*-- Macros for decompression. --*/
+
+#define BZ_GET_FAST(cccc)                     \
+    /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+    if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
+    s->tPos = s->tt[s->tPos];                 \
+    cccc = (UChar)(s->tPos & 0xff);           \
+    s->tPos >>= 8;
+
+#define BZ_GET_FAST_C(cccc)                   \
+    /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+    if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \
+    c_tPos = c_tt[c_tPos];                    \
+    cccc = (UChar)(c_tPos & 0xff);            \
+    c_tPos >>= 8;
+
+#define SET_LL4(i,n)                                          \
+   { if (((i) & 0x1) == 0)                                    \
+        s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else    \
+        s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4);  \
+   }
+
+#define GET_LL4(i)                             \
+   ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF)
+
+#define SET_LL(i,n)                          \
+   { s->ll16[i] = (UInt16)(n & 0x0000ffff);  \
+     SET_LL4(i, n >> 16);                    \
+   }
+
+#define GET_LL(i) \
+   (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16))
+
+#define BZ_GET_SMALL(cccc)                            \
+    /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+    if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
+    cccc = BZ2_indexIntoF ( s->tPos, s->cftab );    \
+    s->tPos = GET_LL(s->tPos);
+
+
+/*-- externs for decompression. --*/
+
+extern Int32 
+BZ2_indexIntoF ( Int32, Int32* );
+
+extern Int32 
+BZ2_decompress ( DState* );
+
+extern void 
+BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*,
+                           Int32,  Int32, Int32 );
+
+
+#endif
+
+
+/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/
+
+#ifdef BZ_NO_STDIO
+#ifndef NULL
+#define NULL 0
+#endif
+#endif
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                   bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/compress.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/compress.c
new file mode 100644
index 00000000000..5dfa00231b0
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/compress.c
@@ -0,0 +1,672 @@
+
+/*-------------------------------------------------------------*/
+/*--- Compression machinery (not incl block sorting)        ---*/
+/*---                                            compress.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+/* CHANGES
+    0.9.0    -- original version.
+    0.9.0a/b -- no changes in this file.
+    0.9.0c   -- changed setting of nGroups in sendMTFValues() 
+                so as to do a bit better on small files
+*/
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+/*--- Bit stream I/O                              ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+void BZ2_bsInitWrite ( EState* s )
+{
+   s->bsLive = 0;
+   s->bsBuff = 0;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsFinishWrite ( EState* s )
+{
+   while (s->bsLive > 0) {
+      s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24);
+      s->numZ++;
+      s->bsBuff <<= 8;
+      s->bsLive -= 8;
+   }
+}
+
+
+/*---------------------------------------------------*/
+#define bsNEEDW(nz)                           \
+{                                             \
+   while (s->bsLive >= 8) {                   \
+      s->zbits[s->numZ]                       \
+         = (UChar)(s->bsBuff >> 24);          \
+      s->numZ++;                              \
+      s->bsBuff <<= 8;                        \
+      s->bsLive -= 8;                         \
+   }                                          \
+}
+
+
+/*---------------------------------------------------*/
+static
+__inline__
+void bsW ( EState* s, Int32 n, UInt32 v )
+{
+   bsNEEDW ( n );
+   s->bsBuff |= (v << (32 - s->bsLive - n));
+   s->bsLive += n;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutUInt32 ( EState* s, UInt32 u )
+{
+   bsW ( s, 8, (u >> 24) & 0xffL );
+   bsW ( s, 8, (u >> 16) & 0xffL );
+   bsW ( s, 8, (u >>  8) & 0xffL );
+   bsW ( s, 8,  u        & 0xffL );
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutUChar ( EState* s, UChar c )
+{
+   bsW( s, 8, (UInt32)c );
+}
+
+
+/*---------------------------------------------------*/
+/*--- The back end proper                         ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+static
+void makeMaps_e ( EState* s )
+{
+   Int32 i;
+   s->nInUse = 0;
+   for (i = 0; i < 256; i++)
+      if (s->inUse[i]) {
+         s->unseqToSeq[i] = s->nInUse;
+         s->nInUse++;
+      }
+}
+
+
+/*---------------------------------------------------*/
+static
+void generateMTFValues ( EState* s )
+{
+   UChar   yy[256];
+   Int32   i, j;
+   Int32   zPend;
+   Int32   wr;
+   Int32   EOB;
+
+   /* 
+      After sorting (eg, here),
+         s->arr1 [ 0 .. s->nblock-1 ] holds sorted order,
+         and
+         ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] 
+         holds the original block data.
+
+      The first thing to do is generate the MTF values,
+      and put them in
+         ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ].
+      Because there are strictly fewer or equal MTF values
+      than block values, ptr values in this area are overwritten
+      with MTF values only when they are no longer needed.
+
+      The final compressed bitstream is generated into the
+      area starting at
+         (UChar*) (&((UChar*)s->arr2)[s->nblock])
+
+      These storage aliases are set up in bzCompressInit(),
+      except for the last one, which is arranged in 
+      compressBlock().
+   */
+   UInt32* ptr   = s->ptr;
+   UChar* block  = s->block;
+   UInt16* mtfv  = s->mtfv;
+
+   makeMaps_e ( s );
+   EOB = s->nInUse+1;
+
+   for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0;
+
+   wr = 0;
+   zPend = 0;
+   for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i;
+
+   for (i = 0; i < s->nblock; i++) {
+      UChar ll_i;
+      AssertD ( wr <= i, "generateMTFValues(1)" );
+      j = ptr[i]-1; if (j < 0) j += s->nblock;
+      ll_i = s->unseqToSeq[block[j]];
+      AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" );
+
+      if (yy[0] == ll_i) { 
+         zPend++;
+      } else {
+
+         if (zPend > 0) {
+            zPend--;
+            while (True) {
+               if (zPend & 1) {
+                  mtfv[wr] = BZ_RUNB; wr++; 
+                  s->mtfFreq[BZ_RUNB]++; 
+               } else {
+                  mtfv[wr] = BZ_RUNA; wr++; 
+                  s->mtfFreq[BZ_RUNA]++; 
+               }
+               if (zPend < 2) break;
+               zPend = (zPend - 2) / 2;
+            };
+            zPend = 0;
+         }
+         {
+            register UChar  rtmp;
+            register UChar* ryy_j;
+            register UChar  rll_i;
+            rtmp  = yy[1];
+            yy[1] = yy[0];
+            ryy_j = &(yy[1]);
+            rll_i = ll_i;
+            while ( rll_i != rtmp ) {
+               register UChar rtmp2;
+               ryy_j++;
+               rtmp2  = rtmp;
+               rtmp   = *ryy_j;
+               *ryy_j = rtmp2;
+            };
+            yy[0] = rtmp;
+            j = ryy_j - &(yy[0]);
+            mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++;
+         }
+
+      }
+   }
+
+   if (zPend > 0) {
+      zPend--;
+      while (True) {
+         if (zPend & 1) {
+            mtfv[wr] = BZ_RUNB; wr++; 
+            s->mtfFreq[BZ_RUNB]++; 
+         } else {
+            mtfv[wr] = BZ_RUNA; wr++; 
+            s->mtfFreq[BZ_RUNA]++; 
+         }
+         if (zPend < 2) break;
+         zPend = (zPend - 2) / 2;
+      };
+      zPend = 0;
+   }
+
+   mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++;
+
+   s->nMTF = wr;
+}
+
+
+/*---------------------------------------------------*/
+#define BZ_LESSER_ICOST  0
+#define BZ_GREATER_ICOST 15
+
+static
+void sendMTFValues ( EState* s )
+{
+   Int32 v, t, i, j, gs, ge, totc, bt, bc, iter;
+   Int32 nSelectors, alphaSize, minLen, maxLen, selCtr;
+   Int32 nGroups, nBytes;
+
+   /*--
+   UChar  len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+   is a global since the decoder also needs it.
+
+   Int32  code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+   Int32  rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+   are also globals only used in this proc.
+   Made global to keep stack frame size small.
+   --*/
+
+
+   UInt16 cost[BZ_N_GROUPS];
+   Int32  fave[BZ_N_GROUPS];
+
+   UInt16* mtfv = s->mtfv;
+
+   if (s->verbosity >= 3)
+      VPrintf3( "      %d in block, %d after MTF & 1-2 coding, "
+                "%d+2 syms in use\n", 
+                s->nblock, s->nMTF, s->nInUse );
+
+   alphaSize = s->nInUse+2;
+   for (t = 0; t < BZ_N_GROUPS; t++)
+      for (v = 0; v < alphaSize; v++)
+         s->len[t][v] = BZ_GREATER_ICOST;
+
+   /*--- Decide how many coding tables to use ---*/
+   AssertH ( s->nMTF > 0, 3001 );
+   if (s->nMTF < 200)  nGroups = 2; else
+   if (s->nMTF < 600)  nGroups = 3; else
+   if (s->nMTF < 1200) nGroups = 4; else
+   if (s->nMTF < 2400) nGroups = 5; else
+                       nGroups = 6;
+
+   /*--- Generate an initial set of coding tables ---*/
+   { 
+      Int32 nPart, remF, tFreq, aFreq;
+
+      nPart = nGroups;
+      remF  = s->nMTF;
+      gs = 0;
+      while (nPart > 0) {
+         tFreq = remF / nPart;
+         ge = gs-1;
+         aFreq = 0;
+         while (aFreq < tFreq && ge < alphaSize-1) {
+            ge++;
+            aFreq += s->mtfFreq[ge];
+         }
+
+         if (ge > gs 
+             && nPart != nGroups && nPart != 1 
+             && ((nGroups-nPart) % 2 == 1)) {
+            aFreq -= s->mtfFreq[ge];
+            ge--;
+         }
+
+         if (s->verbosity >= 3)
+            VPrintf5( "      initial group %d, [%d .. %d], "
+                      "has %d syms (%4.1f%%)\n",
+                      nPart, gs, ge, aFreq, 
+                      (100.0 * (float)aFreq) / (float)(s->nMTF) );
+ 
+         for (v = 0; v < alphaSize; v++)
+            if (v >= gs && v <= ge) 
+               s->len[nPart-1][v] = BZ_LESSER_ICOST; else
+               s->len[nPart-1][v] = BZ_GREATER_ICOST;
+ 
+         nPart--;
+         gs = ge+1;
+         remF -= aFreq;
+      }
+   }
+
+   /*--- 
+      Iterate up to BZ_N_ITERS times to improve the tables.
+   ---*/
+   for (iter = 0; iter < BZ_N_ITERS; iter++) {
+
+      for (t = 0; t < nGroups; t++) fave[t] = 0;
+
+      for (t = 0; t < nGroups; t++)
+         for (v = 0; v < alphaSize; v++)
+            s->rfreq[t][v] = 0;
+
+      /*---
+        Set up an auxiliary length table which is used to fast-track
+	the common case (nGroups == 6). 
+      ---*/
+      if (nGroups == 6) {
+         for (v = 0; v < alphaSize; v++) {
+            s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
+            s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
+            s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
+	 }
+      }
+
+      nSelectors = 0;
+      totc = 0;
+      gs = 0;
+      while (True) {
+
+         /*--- Set group start & end marks. --*/
+         if (gs >= s->nMTF) break;
+         ge = gs + BZ_G_SIZE - 1; 
+         if (ge >= s->nMTF) ge = s->nMTF-1;
+
+         /*-- 
+            Calculate the cost of this group as coded
+            by each of the coding tables.
+         --*/
+         for (t = 0; t < nGroups; t++) cost[t] = 0;
+
+         if (nGroups == 6 && 50 == ge-gs+1) {
+            /*--- fast track the common case ---*/
+            register UInt32 cost01, cost23, cost45;
+            register UInt16 icv;
+            cost01 = cost23 = cost45 = 0;
+
+#           define BZ_ITER(nn)                \
+               icv = mtfv[gs+(nn)];           \
+               cost01 += s->len_pack[icv][0]; \
+               cost23 += s->len_pack[icv][1]; \
+               cost45 += s->len_pack[icv][2]; \
+
+            BZ_ITER(0);  BZ_ITER(1);  BZ_ITER(2);  BZ_ITER(3);  BZ_ITER(4);
+            BZ_ITER(5);  BZ_ITER(6);  BZ_ITER(7);  BZ_ITER(8);  BZ_ITER(9);
+            BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
+            BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
+            BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
+            BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
+            BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
+            BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
+            BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
+            BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
+
+#           undef BZ_ITER
+
+            cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
+            cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
+            cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
+
+         } else {
+	    /*--- slow version which correctly handles all situations ---*/
+            for (i = gs; i <= ge; i++) { 
+               UInt16 icv = mtfv[i];
+               for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv];
+            }
+         }
+ 
+         /*-- 
+            Find the coding table which is best for this group,
+            and record its identity in the selector table.
+         --*/
+         bc = 999999999; bt = -1;
+         for (t = 0; t < nGroups; t++)
+            if (cost[t] < bc) { bc = cost[t]; bt = t; };
+         totc += bc;
+         fave[bt]++;
+         s->selector[nSelectors] = bt;
+         nSelectors++;
+
+         /*-- 
+            Increment the symbol frequencies for the selected table.
+          --*/
+         if (nGroups == 6 && 50 == ge-gs+1) {
+            /*--- fast track the common case ---*/
+
+#           define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++
+
+            BZ_ITUR(0);  BZ_ITUR(1);  BZ_ITUR(2);  BZ_ITUR(3);  BZ_ITUR(4);
+            BZ_ITUR(5);  BZ_ITUR(6);  BZ_ITUR(7);  BZ_ITUR(8);  BZ_ITUR(9);
+            BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
+            BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
+            BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
+            BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
+            BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
+            BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
+            BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
+            BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
+
+#           undef BZ_ITUR
+
+         } else {
+	    /*--- slow version which correctly handles all situations ---*/
+            for (i = gs; i <= ge; i++)
+               s->rfreq[bt][ mtfv[i] ]++;
+         }
+
+         gs = ge+1;
+      }
+      if (s->verbosity >= 3) {
+         VPrintf2 ( "      pass %d: size is %d, grp uses are ", 
+                   iter+1, totc/8 );
+         for (t = 0; t < nGroups; t++)
+            VPrintf1 ( "%d ", fave[t] );
+         VPrintf0 ( "\n" );
+      }
+
+      /*--
+        Recompute the tables based on the accumulated frequencies.
+      --*/
+      /* maxLen was changed from 20 to 17 in bzip2-1.0.3.  See 
+         comment in huffman.c for details. */
+      for (t = 0; t < nGroups; t++)
+         BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), 
+                                 alphaSize, 17 /*20*/ );
+   }
+
+
+   AssertH( nGroups < 8, 3002 );
+   AssertH( nSelectors < 32768 &&
+            nSelectors <= BZ_MAX_SELECTORS,
+            3003 );
+
+
+   /*--- Compute MTF values for the selectors. ---*/
+   {
+      UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
+      for (i = 0; i < nGroups; i++) pos[i] = i;
+      for (i = 0; i < nSelectors; i++) {
+         ll_i = s->selector[i];
+         j = 0;
+         tmp = pos[j];
+         while ( ll_i != tmp ) {
+            j++;
+            tmp2 = tmp;
+            tmp = pos[j];
+            pos[j] = tmp2;
+         };
+         pos[0] = tmp;
+         s->selectorMtf[i] = j;
+      }
+   };
+
+   /*--- Assign actual codes for the tables. --*/
+   for (t = 0; t < nGroups; t++) {
+      minLen = 32;
+      maxLen = 0;
+      for (i = 0; i < alphaSize; i++) {
+         if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+         if (s->len[t][i] < minLen) minLen = s->len[t][i];
+      }
+      AssertH ( !(maxLen > 17 /*20*/ ), 3004 );
+      AssertH ( !(minLen < 1),  3005 );
+      BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), 
+                          minLen, maxLen, alphaSize );
+   }
+
+   /*--- Transmit the mapping table. ---*/
+   { 
+      Bool inUse16[16];
+      for (i = 0; i < 16; i++) {
+          inUse16[i] = False;
+          for (j = 0; j < 16; j++)
+             if (s->inUse[i * 16 + j]) inUse16[i] = True;
+      }
+     
+      nBytes = s->numZ;
+      for (i = 0; i < 16; i++)
+         if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0);
+
+      for (i = 0; i < 16; i++)
+         if (inUse16[i])
+            for (j = 0; j < 16; j++) {
+               if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0);
+            }
+
+      if (s->verbosity >= 3) 
+         VPrintf1( "      bytes: mapping %d, ", s->numZ-nBytes );
+   }
+
+   /*--- Now the selectors. ---*/
+   nBytes = s->numZ;
+   bsW ( s, 3, nGroups );
+   bsW ( s, 15, nSelectors );
+   for (i = 0; i < nSelectors; i++) { 
+      for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1);
+      bsW(s,1,0);
+   }
+   if (s->verbosity >= 3)
+      VPrintf1( "selectors %d, ", s->numZ-nBytes );
+
+   /*--- Now the coding tables. ---*/
+   nBytes = s->numZ;
+
+   for (t = 0; t < nGroups; t++) {
+      Int32 curr = s->len[t][0];
+      bsW ( s, 5, curr );
+      for (i = 0; i < alphaSize; i++) {
+         while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ };
+         while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ };
+         bsW ( s, 1, 0 );
+      }
+   }
+
+   if (s->verbosity >= 3)
+      VPrintf1 ( "code lengths %d, ", s->numZ-nBytes );
+
+   /*--- And finally, the block data proper ---*/
+   nBytes = s->numZ;
+   selCtr = 0;
+   gs = 0;
+   while (True) {
+      if (gs >= s->nMTF) break;
+      ge = gs + BZ_G_SIZE - 1; 
+      if (ge >= s->nMTF) ge = s->nMTF-1;
+      AssertH ( s->selector[selCtr] < nGroups, 3006 );
+
+      if (nGroups == 6 && 50 == ge-gs+1) {
+            /*--- fast track the common case ---*/
+            UInt16 mtfv_i;
+            UChar* s_len_sel_selCtr 
+               = &(s->len[s->selector[selCtr]][0]);
+            Int32* s_code_sel_selCtr
+               = &(s->code[s->selector[selCtr]][0]);
+
+#           define BZ_ITAH(nn)                      \
+               mtfv_i = mtfv[gs+(nn)];              \
+               bsW ( s,                             \
+                     s_len_sel_selCtr[mtfv_i],      \
+                     s_code_sel_selCtr[mtfv_i] )
+
+            BZ_ITAH(0);  BZ_ITAH(1);  BZ_ITAH(2);  BZ_ITAH(3);  BZ_ITAH(4);
+            BZ_ITAH(5);  BZ_ITAH(6);  BZ_ITAH(7);  BZ_ITAH(8);  BZ_ITAH(9);
+            BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
+            BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
+            BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
+            BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
+            BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
+            BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
+            BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
+            BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
+
+#           undef BZ_ITAH
+
+      } else {
+	 /*--- slow version which correctly handles all situations ---*/
+         for (i = gs; i <= ge; i++) {
+            bsW ( s, 
+                  s->len  [s->selector[selCtr]] [mtfv[i]],
+                  s->code [s->selector[selCtr]] [mtfv[i]] );
+         }
+      }
+
+
+      gs = ge+1;
+      selCtr++;
+   }
+   AssertH( selCtr == nSelectors, 3007 );
+
+   if (s->verbosity >= 3)
+      VPrintf1( "codes %d\n", s->numZ-nBytes );
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_compressBlock ( EState* s, Bool is_last_block )
+{
+   if (s->nblock > 0) {
+
+      BZ_FINALISE_CRC ( s->blockCRC );
+      s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
+      s->combinedCRC ^= s->blockCRC;
+      if (s->blockNo > 1) s->numZ = 0;
+
+      if (s->verbosity >= 2)
+         VPrintf4( "    block %d: crc = 0x%08x, "
+                   "combined CRC = 0x%08x, size = %d\n",
+                   s->blockNo, s->blockCRC, s->combinedCRC, s->nblock );
+
+      BZ2_blockSort ( s );
+   }
+
+   s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]);
+
+   /*-- If this is the first block, create the stream header. --*/
+   if (s->blockNo == 1) {
+      BZ2_bsInitWrite ( s );
+      bsPutUChar ( s, BZ_HDR_B );
+      bsPutUChar ( s, BZ_HDR_Z );
+      bsPutUChar ( s, BZ_HDR_h );
+      bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) );
+   }
+
+   if (s->nblock > 0) {
+
+      bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 );
+      bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 );
+      bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 );
+
+      /*-- Now the block's CRC, so it is in a known place. --*/
+      bsPutUInt32 ( s, s->blockCRC );
+
+      /*-- 
+         Now a single bit indicating (non-)randomisation. 
+         As of version 0.9.5, we use a better sorting algorithm
+         which makes randomisation unnecessary.  So always set
+         the randomised bit to 'no'.  Of course, the decoder
+         still needs to be able to handle randomised blocks
+         so as to maintain backwards compatibility with
+         older versions of bzip2.
+      --*/
+      bsW(s,1,0);
+
+      bsW ( s, 24, s->origPtr );
+      generateMTFValues ( s );
+      sendMTFValues ( s );
+   }
+
+
+   /*-- If this is the last block, add the stream trailer. --*/
+   if (is_last_block) {
+
+      bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 );
+      bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 );
+      bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 );
+      bsPutUInt32 ( s, s->combinedCRC );
+      if (s->verbosity >= 2)
+         VPrintf1( "    final combined CRC = 0x%08x\n   ", s->combinedCRC );
+      bsFinishWrite ( s );
+   }
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                        compress.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/crctable.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/crctable.c
new file mode 100644
index 00000000000..2b33c253533
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/crctable.c
@@ -0,0 +1,104 @@
+
+/*-------------------------------------------------------------*/
+/*--- Table for doing CRCs                                  ---*/
+/*---                                            crctable.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*--
+  I think this is an implementation of the AUTODIN-II,
+  Ethernet & FDDI 32-bit CRC standard.  Vaguely derived
+  from code by Rob Warnock, in Section 51 of the
+  comp.compression FAQ.
+--*/
+
+UInt32 BZ2_crc32Table[256] = {
+
+   /*-- Ugly, innit? --*/
+
+   0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L,
+   0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L,
+   0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L,
+   0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL,
+   0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L,
+   0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L,
+   0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L,
+   0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL,
+   0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L,
+   0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L,
+   0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L,
+   0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL,
+   0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L,
+   0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L,
+   0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L,
+   0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL,
+   0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL,
+   0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L,
+   0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L,
+   0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL,
+   0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL,
+   0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L,
+   0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L,
+   0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL,
+   0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL,
+   0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L,
+   0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L,
+   0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL,
+   0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL,
+   0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L,
+   0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L,
+   0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL,
+   0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L,
+   0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL,
+   0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL,
+   0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L,
+   0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L,
+   0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL,
+   0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL,
+   0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L,
+   0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L,
+   0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL,
+   0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL,
+   0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L,
+   0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L,
+   0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL,
+   0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL,
+   0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L,
+   0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L,
+   0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL,
+   0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L,
+   0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L,
+   0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L,
+   0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL,
+   0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L,
+   0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L,
+   0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L,
+   0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL,
+   0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L,
+   0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L,
+   0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L,
+   0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL,
+   0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L,
+   0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L
+};
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                        crctable.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/decompress.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/decompress.c
new file mode 100644
index 00000000000..a1a0bac8922
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/decompress.c
@@ -0,0 +1,652 @@
+
+/*-------------------------------------------------------------*/
+/*--- Decompression machinery                               ---*/
+/*---                                          decompress.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+static
+void makeMaps_d ( DState* s )
+{
+   Int32 i;
+   s->nInUse = 0;
+   for (i = 0; i < 256; i++)
+      if (s->inUse[i]) {
+         s->seqToUnseq[s->nInUse] = i;
+         s->nInUse++;
+      }
+}
+
+
+/*---------------------------------------------------*/
+#define RETURN(rrr)                               \
+   { retVal = rrr; goto save_state_and_return; };
+
+#define GET_BITS(lll,vvv,nnn)                     \
+   case lll: s->state = lll;                      \
+   while (True) {                                 \
+      if (s->bsLive >= nnn) {                     \
+         UInt32 v;                                \
+         v = (s->bsBuff >>                        \
+             (s->bsLive-nnn)) & ((1 << nnn)-1);   \
+         s->bsLive -= nnn;                        \
+         vvv = v;                                 \
+         break;                                   \
+      }                                           \
+      if (s->strm->avail_in == 0) RETURN(BZ_OK);  \
+      s->bsBuff                                   \
+         = (s->bsBuff << 8) |                     \
+           ((UInt32)                              \
+              (*((UChar*)(s->strm->next_in))));   \
+      s->bsLive += 8;                             \
+      s->strm->next_in++;                         \
+      s->strm->avail_in--;                        \
+      s->strm->total_in_lo32++;                   \
+      if (s->strm->total_in_lo32 == 0)            \
+         s->strm->total_in_hi32++;                \
+   }
+
+#define GET_UCHAR(lll,uuu)                        \
+   GET_BITS(lll,uuu,8)
+
+#define GET_BIT(lll,uuu)                          \
+   GET_BITS(lll,uuu,1)
+
+/*---------------------------------------------------*/
+#define GET_MTF_VAL(label1,label2,lval)           \
+{                                                 \
+   if (groupPos == 0) {                           \
+      groupNo++;                                  \
+      if (groupNo >= nSelectors)                  \
+         RETURN(BZ_DATA_ERROR);                   \
+      groupPos = BZ_G_SIZE;                       \
+      gSel = s->selector[groupNo];                \
+      gMinlen = s->minLens[gSel];                 \
+      gLimit = &(s->limit[gSel][0]);              \
+      gPerm = &(s->perm[gSel][0]);                \
+      gBase = &(s->base[gSel][0]);                \
+   }                                              \
+   groupPos--;                                    \
+   zn = gMinlen;                                  \
+   GET_BITS(label1, zvec, zn);                    \
+   while (1) {                                    \
+      if (zn > 20 /* the longest code */)         \
+         RETURN(BZ_DATA_ERROR);                   \
+      if (zvec <= gLimit[zn]) break;              \
+      zn++;                                       \
+      GET_BIT(label2, zj);                        \
+      zvec = (zvec << 1) | zj;                    \
+   };                                             \
+   if (zvec - gBase[zn] < 0                       \
+       || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE)  \
+      RETURN(BZ_DATA_ERROR);                      \
+   lval = gPerm[zvec - gBase[zn]];                \
+}
+
+
+/*---------------------------------------------------*/
+Int32 BZ2_decompress ( DState* s )
+{
+   UChar      uc;
+   Int32      retVal;
+   Int32      minLen, maxLen;
+   bz_stream* strm = s->strm;
+
+   /* stuff that needs to be saved/restored */
+   Int32  i;
+   Int32  j;
+   Int32  t;
+   Int32  alphaSize;
+   Int32  nGroups;
+   Int32  nSelectors;
+   Int32  EOB;
+   Int32  groupNo;
+   Int32  groupPos;
+   Int32  nextSym;
+   Int32  nblockMAX;
+   Int32  nblock;
+   Int32  es;
+   Int32  N;
+   Int32  curr;
+   Int32  zt;
+   Int32  zn; 
+   Int32  zvec;
+   Int32  zj;
+   Int32  gSel;
+   Int32  gMinlen;
+   Int32* gLimit;
+   Int32* gBase;
+   Int32* gPerm;
+
+   if (s->state == BZ_X_MAGIC_1) {
+      /*initialise the save area*/
+      s->save_i           = 0;
+      s->save_j           = 0;
+      s->save_t           = 0;
+      s->save_alphaSize   = 0;
+      s->save_nGroups     = 0;
+      s->save_nSelectors  = 0;
+      s->save_EOB         = 0;
+      s->save_groupNo     = 0;
+      s->save_groupPos    = 0;
+      s->save_nextSym     = 0;
+      s->save_nblockMAX   = 0;
+      s->save_nblock      = 0;
+      s->save_es          = 0;
+      s->save_N           = 0;
+      s->save_curr        = 0;
+      s->save_zt          = 0;
+      s->save_zn          = 0;
+      s->save_zvec        = 0;
+      s->save_zj          = 0;
+      s->save_gSel        = 0;
+      s->save_gMinlen     = 0;
+      s->save_gLimit      = NULL;
+      s->save_gBase       = NULL;
+      s->save_gPerm       = NULL;
+   }
+
+   /*restore from the save area*/
+   i           = s->save_i;
+   j           = s->save_j;
+   t           = s->save_t;
+   alphaSize   = s->save_alphaSize;
+   nGroups     = s->save_nGroups;
+   nSelectors  = s->save_nSelectors;
+   EOB         = s->save_EOB;
+   groupNo     = s->save_groupNo;
+   groupPos    = s->save_groupPos;
+   nextSym     = s->save_nextSym;
+   nblockMAX   = s->save_nblockMAX;
+   nblock      = s->save_nblock;
+   es          = s->save_es;
+   N           = s->save_N;
+   curr        = s->save_curr;
+   zt          = s->save_zt;
+   zn          = s->save_zn; 
+   zvec        = s->save_zvec;
+   zj          = s->save_zj;
+   gSel        = s->save_gSel;
+   gMinlen     = s->save_gMinlen;
+   gLimit      = s->save_gLimit;
+   gBase       = s->save_gBase;
+   gPerm       = s->save_gPerm;
+
+   retVal = BZ_OK;
+
+   switch (s->state) {
+
+      GET_UCHAR(BZ_X_MAGIC_1, uc);
+      if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC);
+
+      GET_UCHAR(BZ_X_MAGIC_2, uc);
+      if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC);
+
+      GET_UCHAR(BZ_X_MAGIC_3, uc)
+      if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC);
+
+      GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
+      if (s->blockSize100k < (BZ_HDR_0 + 1) || 
+          s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC);
+      s->blockSize100k -= BZ_HDR_0;
+
+      if (s->smallDecompress) {
+         s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
+         s->ll4  = BZALLOC( 
+                      ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) 
+                   );
+         if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
+      } else {
+         s->tt  = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
+         if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
+      }
+
+      GET_UCHAR(BZ_X_BLKHDR_1, uc);
+
+      if (uc == 0x17) goto endhdr_2;
+      if (uc != 0x31) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_2, uc);
+      if (uc != 0x41) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_3, uc);
+      if (uc != 0x59) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_4, uc);
+      if (uc != 0x26) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_5, uc);
+      if (uc != 0x53) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_6, uc);
+      if (uc != 0x59) RETURN(BZ_DATA_ERROR);
+
+      s->currBlockNo++;
+      if (s->verbosity >= 2)
+         VPrintf1 ( "\n    [%d: huff+mtf ", s->currBlockNo );
+ 
+      s->storedBlockCRC = 0;
+      GET_UCHAR(BZ_X_BCRC_1, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_BCRC_2, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_BCRC_3, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_BCRC_4, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+
+      GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
+
+      s->origPtr = 0;
+      GET_UCHAR(BZ_X_ORIGPTR_1, uc);
+      s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+      GET_UCHAR(BZ_X_ORIGPTR_2, uc);
+      s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+      GET_UCHAR(BZ_X_ORIGPTR_3, uc);
+      s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+
+      if (s->origPtr < 0)
+         RETURN(BZ_DATA_ERROR);
+      if (s->origPtr > 10 + 100000*s->blockSize100k) 
+         RETURN(BZ_DATA_ERROR);
+
+      /*--- Receive the mapping table ---*/
+      for (i = 0; i < 16; i++) {
+         GET_BIT(BZ_X_MAPPING_1, uc);
+         if (uc == 1) 
+            s->inUse16[i] = True; else 
+            s->inUse16[i] = False;
+      }
+
+      for (i = 0; i < 256; i++) s->inUse[i] = False;
+
+      for (i = 0; i < 16; i++)
+         if (s->inUse16[i])
+            for (j = 0; j < 16; j++) {
+               GET_BIT(BZ_X_MAPPING_2, uc);
+               if (uc == 1) s->inUse[i * 16 + j] = True;
+            }
+      makeMaps_d ( s );
+      if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
+      alphaSize = s->nInUse+2;
+
+      /*--- Now the selectors ---*/
+      GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
+      if (nGroups < 2 || nGroups > BZ_N_GROUPS) RETURN(BZ_DATA_ERROR);
+      GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
+      if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
+      for (i = 0; i < nSelectors; i++) {
+         j = 0;
+         while (True) {
+            GET_BIT(BZ_X_SELECTOR_3, uc);
+            if (uc == 0) break;
+            j++;
+            if (j >= nGroups) RETURN(BZ_DATA_ERROR);
+         }
+         /* Having more than BZ_MAX_SELECTORS doesn't make much sense
+            since they will never be used, but some implementations might
+            "round up" the number of selectors, so just ignore those. */
+         if (i < BZ_MAX_SELECTORS)
+           s->selectorMtf[i] = j;
+      }
+      if (nSelectors > BZ_MAX_SELECTORS)
+        nSelectors = BZ_MAX_SELECTORS;
+
+      /*--- Undo the MTF values for the selectors. ---*/
+      {
+         UChar pos[BZ_N_GROUPS], tmp, v;
+         for (v = 0; v < nGroups; v++) pos[v] = v;
+   
+         for (i = 0; i < nSelectors; i++) {
+            v = s->selectorMtf[i];
+            tmp = pos[v];
+            while (v > 0) { pos[v] = pos[v-1]; v--; }
+            pos[0] = tmp;
+            s->selector[i] = tmp;
+         }
+      }
+
+      /*--- Now the coding tables ---*/
+      for (t = 0; t < nGroups; t++) {
+         GET_BITS(BZ_X_CODING_1, curr, 5);
+         for (i = 0; i < alphaSize; i++) {
+            while (True) {
+               if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
+               GET_BIT(BZ_X_CODING_2, uc);
+               if (uc == 0) break;
+               GET_BIT(BZ_X_CODING_3, uc);
+               if (uc == 0) curr++; else curr--;
+            }
+            s->len[t][i] = curr;
+         }
+      }
+
+      /*--- Create the Huffman decoding tables ---*/
+      for (t = 0; t < nGroups; t++) {
+         minLen = 32;
+         maxLen = 0;
+         for (i = 0; i < alphaSize; i++) {
+            if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+            if (s->len[t][i] < minLen) minLen = s->len[t][i];
+         }
+         BZ2_hbCreateDecodeTables ( 
+            &(s->limit[t][0]), 
+            &(s->base[t][0]), 
+            &(s->perm[t][0]), 
+            &(s->len[t][0]),
+            minLen, maxLen, alphaSize
+         );
+         s->minLens[t] = minLen;
+      }
+
+      /*--- Now the MTF values ---*/
+
+      EOB      = s->nInUse+1;
+      nblockMAX = 100000 * s->blockSize100k;
+      groupNo  = -1;
+      groupPos = 0;
+
+      for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
+
+      /*-- MTF init --*/
+      {
+         Int32 ii, jj, kk;
+         kk = MTFA_SIZE-1;
+         for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
+            for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
+               s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
+               kk--;
+            }
+            s->mtfbase[ii] = kk + 1;
+         }
+      }
+      /*-- end MTF init --*/
+
+      nblock = 0;
+      GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
+
+      while (True) {
+
+         if (nextSym == EOB) break;
+
+         if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
+
+            es = -1;
+            N = 1;
+            do {
+               /* Check that N doesn't get too big, so that es doesn't
+                  go negative.  The maximum value that can be
+                  RUNA/RUNB encoded is equal to the block size (post
+                  the initial RLE), viz, 900k, so bounding N at 2
+                  million should guard against overflow without
+                  rejecting any legitimate inputs. */
+               if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR);
+               if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
+               if (nextSym == BZ_RUNB) es = es + (1+1) * N;
+               N = N * 2;
+               GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
+            }
+               while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
+
+            es++;
+            uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
+            s->unzftab[uc] += es;
+
+            if (s->smallDecompress)
+               while (es > 0) {
+                  if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+                  s->ll16[nblock] = (UInt16)uc;
+                  nblock++;
+                  es--;
+               }
+            else
+               while (es > 0) {
+                  if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+                  s->tt[nblock] = (UInt32)uc;
+                  nblock++;
+                  es--;
+               };
+
+            continue;
+
+         } else {
+
+            if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+
+            /*-- uc = MTF ( nextSym-1 ) --*/
+            {
+               Int32 ii, jj, kk, pp, lno, off;
+               UInt32 nn;
+               nn = (UInt32)(nextSym - 1);
+
+               if (nn < MTFL_SIZE) {
+                  /* avoid general-case expense */
+                  pp = s->mtfbase[0];
+                  uc = s->mtfa[pp+nn];
+                  while (nn > 3) {
+                     Int32 z = pp+nn;
+                     s->mtfa[(z)  ] = s->mtfa[(z)-1];
+                     s->mtfa[(z)-1] = s->mtfa[(z)-2];
+                     s->mtfa[(z)-2] = s->mtfa[(z)-3];
+                     s->mtfa[(z)-3] = s->mtfa[(z)-4];
+                     nn -= 4;
+                  }
+                  while (nn > 0) { 
+                     s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; 
+                  };
+                  s->mtfa[pp] = uc;
+               } else { 
+                  /* general case */
+                  lno = nn / MTFL_SIZE;
+                  off = nn % MTFL_SIZE;
+                  pp = s->mtfbase[lno] + off;
+                  uc = s->mtfa[pp];
+                  while (pp > s->mtfbase[lno]) { 
+                     s->mtfa[pp] = s->mtfa[pp-1]; pp--; 
+                  };
+                  s->mtfbase[lno]++;
+                  while (lno > 0) {
+                     s->mtfbase[lno]--;
+                     s->mtfa[s->mtfbase[lno]] 
+                        = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
+                     lno--;
+                  }
+                  s->mtfbase[0]--;
+                  s->mtfa[s->mtfbase[0]] = uc;
+                  if (s->mtfbase[0] == 0) {
+                     kk = MTFA_SIZE-1;
+                     for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
+                        for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
+                           s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
+                           kk--;
+                        }
+                        s->mtfbase[ii] = kk + 1;
+                     }
+                  }
+               }
+            }
+            /*-- end uc = MTF ( nextSym-1 ) --*/
+
+            s->unzftab[s->seqToUnseq[uc]]++;
+            if (s->smallDecompress)
+               s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
+               s->tt[nblock]   = (UInt32)(s->seqToUnseq[uc]);
+            nblock++;
+
+            GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
+            continue;
+         }
+      }
+
+      /* Now we know what nblock is, we can do a better sanity
+         check on s->origPtr.
+      */
+      if (s->origPtr < 0 || s->origPtr >= nblock)
+         RETURN(BZ_DATA_ERROR);
+
+      /*-- Set up cftab to facilitate generation of T^(-1) --*/
+      /* Check: unzftab entries in range. */
+      for (i = 0; i <= 255; i++) {
+         if (s->unzftab[i] < 0 || s->unzftab[i] > nblock)
+            RETURN(BZ_DATA_ERROR);
+      }
+      /* Actually generate cftab. */
+      s->cftab[0] = 0;
+      for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
+      for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
+      /* Check: cftab entries in range. */
+      for (i = 0; i <= 256; i++) {
+         if (s->cftab[i] < 0 || s->cftab[i] > nblock) {
+            /* s->cftab[i] can legitimately be == nblock */
+            RETURN(BZ_DATA_ERROR);
+         }
+      }
+      /* Check: cftab entries non-descending. */
+      for (i = 1; i <= 256; i++) {
+         if (s->cftab[i-1] > s->cftab[i]) {
+            RETURN(BZ_DATA_ERROR);
+         }
+      }
+
+      s->state_out_len = 0;
+      s->state_out_ch  = 0;
+      BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
+      s->state = BZ_X_OUTPUT;
+      if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
+
+      if (s->smallDecompress) {
+
+         /*-- Make a copy of cftab, used in generation of T --*/
+         for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
+
+         /*-- compute the T vector --*/
+         for (i = 0; i < nblock; i++) {
+            uc = (UChar)(s->ll16[i]);
+            SET_LL(i, s->cftabCopy[uc]);
+            s->cftabCopy[uc]++;
+         }
+
+         /*-- Compute T^(-1) by pointer reversal on T --*/
+         i = s->origPtr;
+         j = GET_LL(i);
+         do {
+            Int32 tmp = GET_LL(j);
+            SET_LL(j, i);
+            i = j;
+            j = tmp;
+         }
+            while (i != s->origPtr);
+
+         s->tPos = s->origPtr;
+         s->nblock_used = 0;
+         if (s->blockRandomised) {
+            BZ_RAND_INIT_MASK;
+            BZ_GET_SMALL(s->k0); s->nblock_used++;
+            BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; 
+         } else {
+            BZ_GET_SMALL(s->k0); s->nblock_used++;
+         }
+
+      } else {
+
+         /*-- compute the T^(-1) vector --*/
+         for (i = 0; i < nblock; i++) {
+            uc = (UChar)(s->tt[i] & 0xff);
+            s->tt[s->cftab[uc]] |= (i << 8);
+            s->cftab[uc]++;
+         }
+
+         s->tPos = s->tt[s->origPtr] >> 8;
+         s->nblock_used = 0;
+         if (s->blockRandomised) {
+            BZ_RAND_INIT_MASK;
+            BZ_GET_FAST(s->k0); s->nblock_used++;
+            BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; 
+         } else {
+            BZ_GET_FAST(s->k0); s->nblock_used++;
+         }
+
+      }
+
+      RETURN(BZ_OK);
+
+
+
+    endhdr_2:
+
+      GET_UCHAR(BZ_X_ENDHDR_2, uc);
+      if (uc != 0x72) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_3, uc);
+      if (uc != 0x45) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_4, uc);
+      if (uc != 0x38) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_5, uc);
+      if (uc != 0x50) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_6, uc);
+      if (uc != 0x90) RETURN(BZ_DATA_ERROR);
+
+      s->storedCombinedCRC = 0;
+      GET_UCHAR(BZ_X_CCRC_1, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_CCRC_2, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_CCRC_3, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_CCRC_4, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+
+      s->state = BZ_X_IDLE;
+      RETURN(BZ_STREAM_END);
+
+      default: AssertH ( False, 4001 );
+   }
+
+   AssertH ( False, 4002 );
+
+   save_state_and_return:
+
+   s->save_i           = i;
+   s->save_j           = j;
+   s->save_t           = t;
+   s->save_alphaSize   = alphaSize;
+   s->save_nGroups     = nGroups;
+   s->save_nSelectors  = nSelectors;
+   s->save_EOB         = EOB;
+   s->save_groupNo     = groupNo;
+   s->save_groupPos    = groupPos;
+   s->save_nextSym     = nextSym;
+   s->save_nblockMAX   = nblockMAX;
+   s->save_nblock      = nblock;
+   s->save_es          = es;
+   s->save_N           = N;
+   s->save_curr        = curr;
+   s->save_zt          = zt;
+   s->save_zn          = zn;
+   s->save_zvec        = zvec;
+   s->save_zj          = zj;
+   s->save_gSel        = gSel;
+   s->save_gMinlen     = gMinlen;
+   s->save_gLimit      = gLimit;
+   s->save_gBase       = gBase;
+   s->save_gPerm       = gPerm;
+
+   return retVal;   
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                      decompress.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/huffman.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/huffman.c
new file mode 100644
index 00000000000..43a1899e468
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/huffman.c
@@ -0,0 +1,205 @@
+
+/*-------------------------------------------------------------*/
+/*--- Huffman coding low-level stuff                        ---*/
+/*---                                             huffman.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*---------------------------------------------------*/
+#define WEIGHTOF(zz0)  ((zz0) & 0xffffff00)
+#define DEPTHOF(zz1)   ((zz1) & 0x000000ff)
+#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3))
+
+#define ADDWEIGHTS(zw1,zw2)                           \
+   (WEIGHTOF(zw1)+WEIGHTOF(zw2)) |                    \
+   (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2)))
+
+#define UPHEAP(z)                                     \
+{                                                     \
+   Int32 zz, tmp;                                     \
+   zz = z; tmp = heap[zz];                            \
+   while (weight[tmp] < weight[heap[zz >> 1]]) {      \
+      heap[zz] = heap[zz >> 1];                       \
+      zz >>= 1;                                       \
+   }                                                  \
+   heap[zz] = tmp;                                    \
+}
+
+#define DOWNHEAP(z)                                   \
+{                                                     \
+   Int32 zz, yy, tmp;                                 \
+   zz = z; tmp = heap[zz];                            \
+   while (True) {                                     \
+      yy = zz << 1;                                   \
+      if (yy > nHeap) break;                          \
+      if (yy < nHeap &&                               \
+          weight[heap[yy+1]] < weight[heap[yy]])      \
+         yy++;                                        \
+      if (weight[tmp] < weight[heap[yy]]) break;      \
+      heap[zz] = heap[yy];                            \
+      zz = yy;                                        \
+   }                                                  \
+   heap[zz] = tmp;                                    \
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbMakeCodeLengths ( UChar *len, 
+                             Int32 *freq,
+                             Int32 alphaSize,
+                             Int32 maxLen )
+{
+   /*--
+      Nodes and heap entries run from 1.  Entry 0
+      for both the heap and nodes is a sentinel.
+   --*/
+   Int32 nNodes, nHeap, n1, n2, i, j, k;
+   Bool  tooLong;
+
+   Int32 heap   [ BZ_MAX_ALPHA_SIZE + 2 ];
+   Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ];
+   Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; 
+
+   for (i = 0; i < alphaSize; i++)
+      weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
+
+   while (True) {
+
+      nNodes = alphaSize;
+      nHeap = 0;
+
+      heap[0] = 0;
+      weight[0] = 0;
+      parent[0] = -2;
+
+      for (i = 1; i <= alphaSize; i++) {
+         parent[i] = -1;
+         nHeap++;
+         heap[nHeap] = i;
+         UPHEAP(nHeap);
+      }
+
+      AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 );
+   
+      while (nHeap > 1) {
+         n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
+         n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
+         nNodes++;
+         parent[n1] = parent[n2] = nNodes;
+         weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
+         parent[nNodes] = -1;
+         nHeap++;
+         heap[nHeap] = nNodes;
+         UPHEAP(nHeap);
+      }
+
+      AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 );
+
+      tooLong = False;
+      for (i = 1; i <= alphaSize; i++) {
+         j = 0;
+         k = i;
+         while (parent[k] >= 0) { k = parent[k]; j++; }
+         len[i-1] = j;
+         if (j > maxLen) tooLong = True;
+      }
+      
+      if (! tooLong) break;
+
+      /* 17 Oct 04: keep-going condition for the following loop used
+         to be 'i < alphaSize', which missed the last element,
+         theoretically leading to the possibility of the compressor
+         looping.  However, this count-scaling step is only needed if
+         one of the generated Huffman code words is longer than
+         maxLen, which up to and including version 1.0.2 was 20 bits,
+         which is extremely unlikely.  In version 1.0.3 maxLen was
+         changed to 17 bits, which has minimal effect on compression
+         ratio, but does mean this scaling step is used from time to
+         time, enough to verify that it works.
+
+         This means that bzip2-1.0.3 and later will only produce
+         Huffman codes with a maximum length of 17 bits.  However, in
+         order to preserve backwards compatibility with bitstreams
+         produced by versions pre-1.0.3, the decompressor must still
+         handle lengths of up to 20. */
+
+      for (i = 1; i <= alphaSize; i++) {
+         j = weight[i] >> 8;
+         j = 1 + (j / 2);
+         weight[i] = j << 8;
+      }
+   }
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbAssignCodes ( Int32 *code,
+                         UChar *length,
+                         Int32 minLen,
+                         Int32 maxLen,
+                         Int32 alphaSize )
+{
+   Int32 n, vec, i;
+
+   vec = 0;
+   for (n = minLen; n <= maxLen; n++) {
+      for (i = 0; i < alphaSize; i++)
+         if (length[i] == n) { code[i] = vec; vec++; };
+      vec <<= 1;
+   }
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbCreateDecodeTables ( Int32 *limit,
+                                Int32 *base,
+                                Int32 *perm,
+                                UChar *length,
+                                Int32 minLen,
+                                Int32 maxLen,
+                                Int32 alphaSize )
+{
+   Int32 pp, i, j, vec;
+
+   pp = 0;
+   for (i = minLen; i <= maxLen; i++)
+      for (j = 0; j < alphaSize; j++)
+         if (length[j] == i) { perm[pp] = j; pp++; };
+
+   for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0;
+   for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
+
+   for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1];
+
+   for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0;
+   vec = 0;
+
+   for (i = minLen; i <= maxLen; i++) {
+      vec += (base[i+1] - base[i]);
+      limit[i] = vec-1;
+      vec <<= 1;
+   }
+   for (i = minLen + 1; i <= maxLen; i++)
+      base[i] = ((limit[i-1] + 1) << 1) - base[i];
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                         huffman.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/mk251.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/mk251.c
new file mode 100644
index 00000000000..6c5bbf9350e
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/mk251.c
@@ -0,0 +1,31 @@
+
+/* Spew out a long sequence of the byte 251.  When fed to bzip2
+   versions 1.0.0 or 1.0.1, causes it to die with internal error
+   1007 in blocksort.c.  This assertion misses an extremely rare
+   case, which is fixed in this version (1.0.2) and above.
+*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include 
+
+int main ()
+{
+   int i;
+   for (i = 0; i < 48500000 ; i++)
+     putchar(251);
+   return 0;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/bzip2/randtable.c b/src/libs/3rdparty/karchive/3rdparty/bzip2/randtable.c
new file mode 100644
index 00000000000..bdc6d4a4cc9
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/bzip2/randtable.c
@@ -0,0 +1,84 @@
+
+/*-------------------------------------------------------------*/
+/*--- Table for randomising repetitive blocks               ---*/
+/*---                                           randtable.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------*/
+Int32 BZ2_rNums[512] = { 
+   619, 720, 127, 481, 931, 816, 813, 233, 566, 247, 
+   985, 724, 205, 454, 863, 491, 741, 242, 949, 214, 
+   733, 859, 335, 708, 621, 574, 73, 654, 730, 472, 
+   419, 436, 278, 496, 867, 210, 399, 680, 480, 51, 
+   878, 465, 811, 169, 869, 675, 611, 697, 867, 561, 
+   862, 687, 507, 283, 482, 129, 807, 591, 733, 623, 
+   150, 238, 59, 379, 684, 877, 625, 169, 643, 105, 
+   170, 607, 520, 932, 727, 476, 693, 425, 174, 647, 
+   73, 122, 335, 530, 442, 853, 695, 249, 445, 515, 
+   909, 545, 703, 919, 874, 474, 882, 500, 594, 612, 
+   641, 801, 220, 162, 819, 984, 589, 513, 495, 799, 
+   161, 604, 958, 533, 221, 400, 386, 867, 600, 782, 
+   382, 596, 414, 171, 516, 375, 682, 485, 911, 276, 
+   98, 553, 163, 354, 666, 933, 424, 341, 533, 870, 
+   227, 730, 475, 186, 263, 647, 537, 686, 600, 224, 
+   469, 68, 770, 919, 190, 373, 294, 822, 808, 206, 
+   184, 943, 795, 384, 383, 461, 404, 758, 839, 887, 
+   715, 67, 618, 276, 204, 918, 873, 777, 604, 560, 
+   951, 160, 578, 722, 79, 804, 96, 409, 713, 940, 
+   652, 934, 970, 447, 318, 353, 859, 672, 112, 785, 
+   645, 863, 803, 350, 139, 93, 354, 99, 820, 908, 
+   609, 772, 154, 274, 580, 184, 79, 626, 630, 742, 
+   653, 282, 762, 623, 680, 81, 927, 626, 789, 125, 
+   411, 521, 938, 300, 821, 78, 343, 175, 128, 250, 
+   170, 774, 972, 275, 999, 639, 495, 78, 352, 126, 
+   857, 956, 358, 619, 580, 124, 737, 594, 701, 612, 
+   669, 112, 134, 694, 363, 992, 809, 743, 168, 974, 
+   944, 375, 748, 52, 600, 747, 642, 182, 862, 81, 
+   344, 805, 988, 739, 511, 655, 814, 334, 249, 515, 
+   897, 955, 664, 981, 649, 113, 974, 459, 893, 228, 
+   433, 837, 553, 268, 926, 240, 102, 654, 459, 51, 
+   686, 754, 806, 760, 493, 403, 415, 394, 687, 700, 
+   946, 670, 656, 610, 738, 392, 760, 799, 887, 653, 
+   978, 321, 576, 617, 626, 502, 894, 679, 243, 440, 
+   680, 879, 194, 572, 640, 724, 926, 56, 204, 700, 
+   707, 151, 457, 449, 797, 195, 791, 558, 945, 679, 
+   297, 59, 87, 824, 713, 663, 412, 693, 342, 606, 
+   134, 108, 571, 364, 631, 212, 174, 643, 304, 329, 
+   343, 97, 430, 751, 497, 314, 983, 374, 822, 928, 
+   140, 206, 73, 263, 980, 736, 876, 478, 430, 305, 
+   170, 514, 364, 692, 829, 82, 855, 953, 676, 246, 
+   369, 970, 294, 750, 807, 827, 150, 790, 288, 923, 
+   804, 378, 215, 828, 592, 281, 565, 555, 710, 82, 
+   896, 831, 547, 261, 524, 462, 293, 465, 502, 56, 
+   661, 821, 976, 991, 658, 869, 905, 758, 745, 193, 
+   768, 550, 608, 933, 378, 286, 215, 979, 792, 961, 
+   61, 688, 793, 644, 986, 403, 106, 366, 905, 644, 
+   372, 567, 466, 434, 645, 210, 389, 550, 919, 135, 
+   780, 773, 635, 389, 707, 100, 626, 958, 165, 504, 
+   920, 176, 193, 713, 857, 265, 203, 50, 668, 108, 
+   645, 990, 626, 197, 510, 357, 358, 850, 858, 364, 
+   936, 638
+};
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                       randtable.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/AUTHORS b/src/libs/3rdparty/karchive/3rdparty/xz/AUTHORS
new file mode 100644
index 00000000000..5eff238ae41
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/AUTHORS
@@ -0,0 +1,58 @@
+
+Authors of XZ Utils
+===================
+
+    XZ Utils is developed and maintained by
+    Lasse Collin .
+
+    Major parts of liblzma are based on code written by Igor Pavlov,
+    specifically the LZMA SDK . Without
+    this code, XZ Utils wouldn't exist.
+
+    The SHA-256 implementation in liblzma is based on code written by
+    Wei Dai in Crypto++ Library .
+
+    A few scripts have been adapted from GNU gzip. The original
+    versions were written by Jean-loup Gailly, Charles Levert, and
+    Paul Eggert. Andrew Dudman helped adapting the scripts and their
+    man pages for XZ Utils.
+
+    The initial version of the threaded .xz decompressor was written
+    by Sebastian Andrzej Siewior.
+
+    The initial version of the .lz (lzip) decoder was written
+    by Michał Górny.
+
+    Architecture-specific CRC optimizations were contributed by
+    Ilya Kurdyukov, Hans Jansen, and Chenxi Mao.
+
+    Other authors:
+      - Jonathan Nieder
+      - Joachim Henke
+
+    Special author: Jia Tan was a co-maintainer in 2022-2024. He and
+    the team behind him inserted a backdoor (CVE-2024-3094) into
+    XZ Utils 5.6.0 and 5.6.1 releases. He suddenly disappeared when
+    this was discovered.
+
+    Many people have contributed improvements or reported bugs.
+    Most of these people are mentioned in the file THANKS.
+
+    The translations of the command line tools and man pages have been
+    contributed by many people via the Translation Project:
+
+      - https://translationproject.org/domain/xz.html
+      - https://translationproject.org/domain/xz-man.html
+
+    The authors of the translated man pages are in the header comments
+    of the man page files. In the source package, the authors of the
+    translations are in po/*.po and po4a/*.po files.
+
+    Third-party code whose authors aren't listed here:
+
+      - GNU getopt_long() in the 'lib' directory is included for
+        platforms that don't have a usable getopt_long().
+
+      - The build system files from GNU Autoconf, GNU Automake,
+        GNU Libtool, GNU Gettext, Autoconf Archive, and related files.
+
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/COPYING b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING
new file mode 100644
index 00000000000..aed21531497
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING
@@ -0,0 +1,83 @@
+
+XZ Utils Licensing
+==================
+
+    Different licenses apply to different files in this package. Here
+    is a summary of which licenses apply to which parts of this package:
+
+      - liblzma is under the BSD Zero Clause License (0BSD).
+
+      - The command line tools xz, xzdec, lzmadec, and lzmainfo are
+        under 0BSD except that, on systems that don't have a usable
+        getopt_long, GNU getopt_long is compiled and linked in from the
+        'lib' directory. The getopt_long code is under GNU LGPLv2.1+.
+
+      - The scripts to grep, diff, and view compressed files have been
+        adapted from GNU gzip. These scripts (xzgrep, xzdiff, xzless,
+        and xzmore) are under GNU GPLv2+. The man pages of the scripts
+        are under 0BSD; they aren't based on the man pages of GNU gzip.
+
+      - Most of the XZ Utils specific documentation that is in
+        plain text files (like README, INSTALL, PACKAGERS, NEWS,
+        and ChangeLog) are under 0BSD unless stated otherwise in
+        the file itself. The files xz-file-format.txt and
+        lzma-file-format.xt are in the public domain but may
+        be distributed under the terms of 0BSD too.
+
+      - Translated messages and man pages are under 0BSD except that
+        some old translations are in the public domain.
+
+      - Test files and test code in the 'tests' directory, and
+        debugging utilities in the 'debug' directory are under
+        the BSD Zero Clause License (0BSD).
+
+      - The GNU Autotools based build system contains files that are
+        under GNU GPLv2+, GNU GPLv3+, and a few permissive licenses.
+        These files don't affect the licensing of the binaries being
+        built.
+
+      - The 'extra' directory contains files that are under various
+        free software licenses. These aren't built or installed as
+        part of XZ Utils.
+
+    For the files under the BSD Zero Clause License (0BSD), if
+    a copyright notice is needed, the following is sufficient:
+
+        Copyright (C) The XZ Utils authors and contributors
+
+    If you copy significant amounts of 0BSD-licensed code from XZ Utils
+    into your project, acknowledging this somewhere in your software is
+    polite (especially if it is proprietary, non-free software), but
+    it is not legally required by the license terms. Here is an example
+    of a good notice to put into "about box" or into documentation:
+
+        This software includes code from XZ Utils .
+
+    The following license texts are included in the following files:
+      - COPYING.0BSD: BSD Zero Clause License
+      - COPYING.LGPLv2.1: GNU Lesser General Public License version 2.1
+      - COPYING.GPLv2: GNU General Public License version 2
+      - COPYING.GPLv3: GNU General Public License version 3
+
+    A note about old XZ Utils releases:
+
+        XZ Utils releases 5.4.6 and older and 5.5.1alpha have a
+        significant amount of code put into the public domain and
+        that obviously remains so. The switch from public domain to
+        0BSD for newer releases was made in Febrary 2024 because
+        public domain has (real or perceived) legal ambiguities in
+        some jurisdictions.
+
+        There is very little *practical* difference between public
+        domain and 0BSD. The main difference likely is that one
+        shouldn't claim that 0BSD-licensed code is in the public
+        domain; 0BSD-licensed code is copyrighted but available under
+        an extremely permissive license. Neither 0BSD nor public domain
+        require retaining or reproducing author, copyright holder, or
+        license notices when distributing the software. (Compare to,
+        for example, BSD 2-Clause "Simplified" License which does have
+        such requirements.)
+
+    If you have questions, don't hesitate to ask for more information.
+    The contact information is in the README file.
+
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.0BSD b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.0BSD
new file mode 100644
index 00000000000..4322122aecf
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.0BSD
@@ -0,0 +1,11 @@
+Permission to use, copy, modify, and/or distribute this
+software for any purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv2 b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv2
new file mode 100644
index 00000000000..d159169d105
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv2
@@ -0,0 +1,339 @@
+                    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 Lesser 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.
+
+    
+    Copyright (C)   
+
+    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) year 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.
+
+  , 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 Lesser General
+Public License instead of this License.
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv3 b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv3
new file mode 100644
index 00000000000..f288702d2fa
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.GPLv3
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. 
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  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.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  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.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     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
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    
+    Copyright (C)   
+
+    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 3 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, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+      Copyright (C)   
+    This program 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, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+  The GNU 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 Lesser General
+Public License instead of this License.  But first, please read
+.
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.LGPLv2.1 b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.LGPLv2.1
new file mode 100644
index 00000000000..4362b49151d
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/COPYING.LGPLv2.1
@@ -0,0 +1,502 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 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.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, 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 library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+  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 Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+  If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be 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.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+  9. 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 Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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 with
+this License.
+
+  11. 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 Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  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.
+
+    
+    Copyright (C)   
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; 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.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  , 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/README b/src/libs/3rdparty/karchive/3rdparty/xz/README
new file mode 100644
index 00000000000..9d097deff37
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/README
@@ -0,0 +1,310 @@
+
+XZ Utils
+========
+
+    0. Overview
+    1. Documentation
+       1.1. Overall documentation
+       1.2. Documentation for command-line tools
+       1.3. Documentation for liblzma
+    2. Version numbering
+    3. Reporting bugs
+    4. Translations
+    5. Other implementations of the .xz format
+    6. Contact information
+
+
+0. Overview
+-----------
+
+    XZ Utils provide a general-purpose data-compression library plus
+    command-line tools. The native file format is the .xz format, but
+    also the legacy .lzma format is supported. The .xz format supports
+    multiple compression algorithms, which are called "filters" in the
+    context of XZ Utils. The primary filter is currently LZMA2. With
+    typical files, XZ Utils create about 30 % smaller files than gzip.
+
+    To ease adapting support for the .xz format into existing applications
+    and scripts, the API of liblzma is somewhat similar to the API of the
+    popular zlib library. For the same reason, the command-line tool xz
+    has a command-line syntax similar to that of gzip.
+
+    When aiming for the highest compression ratio, the LZMA2 encoder uses
+    a lot of CPU time and may use, depending on the settings, even
+    hundreds of megabytes of RAM. However, in fast modes, the LZMA2 encoder
+    competes with bzip2 in compression speed, RAM usage, and compression
+    ratio.
+
+    LZMA2 is reasonably fast to decompress. It is a little slower than
+    gzip, but a lot faster than bzip2. Being fast to decompress means
+    that the .xz format is especially nice when the same file will be
+    decompressed very many times (usually on different computers), which
+    is the case e.g. when distributing software packages. In such
+    situations, it's not too bad if the compression takes some time,
+    since that needs to be done only once to benefit many people.
+
+    With some file types, combining (or "chaining") LZMA2 with an
+    additional filter can improve the compression ratio. A filter chain may
+    contain up to four filters, although usually only one or two are used.
+    For example, putting a BCJ (Branch/Call/Jump) filter before LZMA2
+    in the filter chain can improve compression ratio of executable files.
+
+    Since the .xz format allows adding new filter IDs, it is possible that
+    some day there will be a filter that is, for example, much faster to
+    compress than LZMA2 (but probably with worse compression ratio).
+    Similarly, it is possible that some day there is a filter that will
+    compress better than LZMA2.
+
+    XZ Utils supports multithreaded compression. XZ Utils doesn't support
+    multithreaded decompression yet. It has been planned though and taken
+    into account when designing the .xz file format. In the future, files
+    that were created in threaded mode can be decompressed in threaded
+    mode too.
+
+
+1. Documentation
+----------------
+
+1.1. Overall documentation
+
+    README                This file
+
+    INSTALL.generic       Generic install instructions for those not
+                          familiar with packages using GNU Autotools
+    INSTALL               Installation instructions specific to XZ Utils
+    PACKAGERS             Information to packagers of XZ Utils
+
+    COPYING               XZ Utils copyright and license information
+    COPYING.0BSD          BSD Zero Clause License
+    COPYING.GPLv2         GNU General Public License version 2
+    COPYING.GPLv3         GNU General Public License version 3
+    COPYING.LGPLv2.1      GNU Lesser General Public License version 2.1
+
+    AUTHORS               The main authors of XZ Utils
+    THANKS                Incomplete list of people who have helped making
+                          this software
+    NEWS                  User-visible changes between XZ Utils releases
+    ChangeLog             Detailed list of changes (commit log)
+    TODO                  Known bugs and some sort of to-do list
+
+    Note that only some of the above files are included in binary
+    packages.
+
+
+1.2. Documentation for command-line tools
+
+    The command-line tools are documented as man pages. In source code
+    releases (and possibly also in some binary packages), the man pages
+    are also provided in plain text (ASCII only) format in the directory
+    "doc/man" to make the man pages more accessible to those whose
+    operating system doesn't provide an easy way to view man pages.
+
+
+1.3. Documentation for liblzma
+
+    The liblzma API headers include short docs about each function
+    and data type as Doxygen tags. These docs should be quite OK as
+    a quick reference.
+
+    There are a few example/tutorial programs that should help in
+    getting started with liblzma. In the source package the examples
+    are in "doc/examples" and in binary packages they may be under
+    "examples" in the same directory as this README.
+
+    Since the liblzma API has similarities to the zlib API, some people
+    may find it useful to read the zlib docs and tutorial too:
+
+        https://zlib.net/manual.html
+        https://zlib.net/zlib_how.html
+
+
+2. Version numbering
+--------------------
+
+    The version number format of XZ Utils is X.Y.ZS:
+
+      - X is the major version. When this is incremented, the library
+        API and ABI break.
+
+      - Y is the minor version. It is incremented when new features
+        are added without breaking the existing API or ABI. An even Y
+        indicates a stable release and an odd Y indicates unstable
+        (alpha or beta version).
+
+      - Z is the revision. This has a different meaning for stable and
+        unstable releases:
+
+          * Stable: Z is incremented when bugs get fixed without adding
+            any new features. This is intended to be convenient for
+            downstream distributors that want bug fixes but don't want
+            any new features to minimize the risk of introducing new bugs.
+
+          * Unstable: Z is just a counter. API or ABI of features added
+            in earlier unstable releases having the same X.Y may break.
+
+      - S indicates stability of the release. It is missing from the
+        stable releases, where Y is an even number. When Y is odd, S
+        is either "alpha" or "beta" to make it very clear that such
+        versions are not stable releases. The same X.Y.Z combination is
+        not used for more than one stability level, i.e. after X.Y.Zalpha,
+        the next version can be X.Y.(Z+1)beta but not X.Y.Zbeta.
+
+
+3. Reporting bugs
+-----------------
+
+    Naturally it is easiest for me if you already know what causes the
+    unexpected behavior. Even better if you have a patch to propose.
+    However, quite often the reason for unexpected behavior is unknown,
+    so here are a few things to do before sending a bug report:
+
+      1. Try to create a small example how to reproduce the issue.
+
+      2. Compile XZ Utils with debugging code using configure switches
+         --enable-debug and, if possible, --disable-shared. If you are
+         using GCC, use CFLAGS='-O0 -ggdb3'. Don't strip the resulting
+         binaries.
+
+      3. Turn on core dumps. The exact command depends on your shell;
+         for example in GNU bash it is done with "ulimit -c unlimited",
+         and in tcsh with "limit coredumpsize unlimited".
+
+      4. Try to reproduce the suspected bug. If you get "assertion failed"
+         message, be sure to include the complete message in your bug
+         report. If the application leaves a coredump, get a backtrace
+         using gdb:
+           $ gdb /path/to/app-binary   # Load the app to the debugger.
+           (gdb) core core   # Open the coredump.
+           (gdb) bt   # Print the backtrace. Copy & paste to bug report.
+           (gdb) quit   # Quit gdb.
+
+    Report your bug via email or IRC (see Contact information below).
+    Don't send core dump files or any executables. If you have a small
+    example file(s) (total size less than 256 KiB), please include
+    it/them as an attachment. If you have bigger test files, put them
+    online somewhere and include a URL to the file(s) in the bug report.
+
+    Always include the exact version number of XZ Utils in the bug report.
+    If you are using a snapshot from the git repository, use "git describe"
+    to get the exact snapshot version. If you are using XZ Utils shipped
+    in an operating system distribution, mention the distribution name,
+    distribution version, and exact xz package version; if you cannot
+    repeat the bug with the code compiled from unpatched source code,
+    you probably need to report a bug to your distribution's bug tracking
+    system.
+
+
+4. Translations
+---------------
+
+    The xz command line tool and all man pages can be translated.
+    The translations are handled via the Translation Project. If you
+    wish to help translating xz, please join the Translation Project:
+
+        https://translationproject.org/html/translators.html
+
+    Below are notes and testing instructions specific to xz
+    translations.
+
+    Testing can be done by installing xz into a temporary directory:
+
+        ./configure --disable-shared --prefix=/tmp/xz-test
+        # 
+        make -C po update-po
+        make install
+        bash debug/translation.bash | less
+        bash debug/translation.bash | less -S  # For --list outputs
+
+    Repeat the above as needed (no need to re-run configure though).
+
+    Note especially the following:
+
+      - The output of --help and --long-help must look nice on
+        an 80-column terminal. It's OK to add extra lines if needed.
+
+      - In contrast, don't add extra lines to error messages and such.
+        They are often preceded with e.g. a filename on the same line,
+        so you have no way to predict where to put a \n. Let the terminal
+        do the wrapping even if it looks ugly. Adding new lines will be
+        even uglier in the generic case even if it looks nice in a few
+        limited examples.
+
+      - Be careful with column alignment in tables and table-like output
+        (--list, --list --verbose --verbose, --info-memory, --help, and
+        --long-help):
+
+          * All descriptions of options in --help should start in the
+            same column (but it doesn't need to be the same column as
+            in the English messages; just be consistent if you change it).
+            Check that both --help and --long-help look OK, since they
+            share several strings.
+
+          * --list --verbose and --info-memory print lines that have
+            the format "Description:   %s". If you need a longer
+            description, you can put extra space between the colon
+            and %s. Then you may need to add extra space to other
+            strings too so that the result as a whole looks good (all
+            values start at the same column).
+
+          * The columns of the actual tables in --list --verbose --verbose
+            should be aligned properly. Abbreviate if necessary. It might
+            be good to keep at least 2 or 3 spaces between column headings
+            and avoid spaces in the headings so that the columns stand out
+            better, but this is a matter of opinion. Do what you think
+            looks best.
+
+      - Be careful to put a period at the end of a sentence when the
+        original version has it, and don't put it when the original
+        doesn't have it. Similarly, be careful with \n characters
+        at the beginning and end of the strings.
+
+      - Read the TRANSLATORS comments that have been extracted from the
+        source code and included in xz.pot. Some comments suggest
+        testing with a specific command which needs an .xz file. You
+        may use e.g. any tests/files/good-*.xz. However, these test
+        commands are included in translations.bash output, so reading
+        translations.bash output carefully can be enough.
+
+      - If you find language problems in the original English strings,
+        feel free to suggest improvements. Ask if something is unclear.
+
+      - The translated messages should be understandable (sometimes this
+        may be a problem with the original English messages too). Don't
+        make a direct word-by-word translation from English especially if
+        the result doesn't sound good in your language.
+
+    Thanks for your help!
+
+
+5. Other implementations of the .xz format
+------------------------------------------
+
+    7-Zip and the p7zip port of 7-Zip support the .xz format starting
+    from the version 9.00alpha.
+
+        https://7-zip.org/
+        https://p7zip.sourceforge.net/
+
+    XZ Embedded is a limited implementation written for use in the Linux
+    kernel, but it is also suitable for other embedded use.
+
+        https://tukaani.org/xz/embedded.html
+
+    XZ for Java is a complete implementation written in pure Java.
+
+        https://tukaani.org/xz/java.html
+
+
+6. Contact information
+----------------------
+
+    XZ Utils in general:
+      - Home page: https://tukaani.org/xz/
+      - Email to maintainer(s): xz@tukaani.org
+      - IRC: #tukaani on Libera Chat
+      - GitHub: https://github.com/tukaani-project/xz
+
+    Lead maintainer:
+      - Email: Lasse Collin 
+      - IRC: Larhzu on Libera Chat
+
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/README.qtcreator b/src/libs/3rdparty/karchive/3rdparty/xz/README.qtcreator
new file mode 100644
index 00000000000..4c1e7fef3df
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/README.qtcreator
@@ -0,0 +1,4 @@
+This directory contains a stripped down version of `https://github.com/tukaani-project/xz` with the following modifications:
+
+* Branch v5.6 was checked out (6084b25c29ce50a5ec86daa1bb0bcb5e9afb5c32)
+* All unnecessary files have been removed.
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/THANKS b/src/libs/3rdparty/karchive/3rdparty/xz/THANKS
new file mode 100644
index 00000000000..5ed0743b50f
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/THANKS
@@ -0,0 +1,202 @@
+
+Thanks
+======
+
+Some people have helped more, some less, but nevertheless everyone's help
+has been important. :-) In alphabetical order:
+  - Mark Adler
+  - Kian-Meng Ang
+  - H. Peter Anvin
+  - Jeff Bastian
+  - Nelson H. F. Beebe
+  - Karl Beldan
+  - Karl Berry
+  - Anders F. Björklund
+  - Emmanuel Blot
+  - Melanie Blower
+  - Alexander Bluhm
+  - Martin Blumenstingl
+  - Ben Boeckel
+  - Jakub Bogusz
+  - Adam Borowski
+  - Maarten Bosmans
+  - Lukas Braune
+  - Benjamin Buch
+  - Trent W. Buck
+  - Kevin R. Bulgrien
+  - James Buren
+  - David Burklund
+  - Frank Busse
+  - Daniel Mealha Cabrita
+  - Milo Casagrande
+  - Marek Černocký
+  - Tomer Chachamu
+  - Vitaly Chikunov
+  - Antoine Cœur
+  - Felix Collin
+  - Gabi Davar
+  - İhsan Doğan
+  - Chris Donawa
+  - Andrew Dudman
+  - Markus Duft
+  - İsmail Dönmez
+  - Paul Eggert
+  - Robert Elz
+  - Gilles Espinasse
+  - Denis Excoffier
+  - Vincent Fazio
+  - Michael Felt
+  - Michael Fox
+  - Andres Freund
+  - Mike Frysinger
+  - Daniel Richard G.
+  - Tomasz Gajc
+  - Bjarni Ingi Gislason
+  - John Paul Adrian Glaubitz
+  - Bill Glessner
+  - Matthew Good
+  - Michał Górny
+  - Jason Gorski
+  - Juan Manuel Guerrero
+  - Gabriela Gutierrez
+  - Diederik de Haas
+  - Joachim Henke
+  - Christian Hesse
+  - Vincenzo Innocente
+  - Peter Ivanov
+  - Nicholas Jackson
+  - Sam James
+  - Hajin Jang
+  - Hans Jansen
+  - Jouk Jansen
+  - Jun I Jin
+  - Christoph Junghans
+  - Kiyoshi Kanazawa
+  - Joona Kannisto
+  - Per Øyvind Karlsen
+  - Firas Khalil Khana
+  - Iouri Kharon
+  - Thomas Klausner
+  - Richard Koch
+  - Anton Kochkov
+  - Ville Koskinen
+  - Sergey Kosukhin
+  - Marcin Kowalczyk
+  - Jan Kratochvil
+  - Christian Kujau
+  - Stephan Kulow
+  - Ilya Kurdyukov
+  - Peter Lawler
+  - James M Leddy
+  - Kelvin Lee
+  - Vincent Lefevre
+  - Hin-Tak Leung
+  - Andraž 'ruskie' Levstik
+  - Cary Lewis
+  - Wim Lewis
+  - Xin Li
+  - Yifeng Li
+  - Eric Lindblad
+  - Lorenzo De Liso
+  - H.J. Lu
+  - Bela Lubkin
+  - Chenxi Mao
+  - Gregory Margo
+  - Julien Marrec
+  - Ed Maste
+  - Martin Matuška
+  - Ivan A. Melnikov
+  - Jim Meyering
+  - Arkadiusz Miskiewicz
+  - Nathan Moinvaziri
+  - Étienne Mollier
+  - Conley Moorhous
+  - Andrew Murray
+  - Rafał Mużyło
+  - Adrien Nader
+  - Evan Nemerson
+  - Alexander Neumann
+  - Hongbo Ni
+  - Jonathan Nieder
+  - Andre Noll
+  - Peter O'Gorman
+  - Dimitri Papadopoulos Orfanos
+  - Daniel Packard
+  - Filip Palian
+  - Peter Pallinger
+  - Kai Pastor
+  - Rui Paulo
+  - Igor Pavlov
+  - Diego Elio Pettenò
+  - Elbert Pol
+  - Mikko Pouru
+  - Frank Prochnow
+  - Rich Prohaska
+  - Trần Ngọc Quân
+  - Pavel Raiskup
+  - Ole André Vadla Ravnås
+  - Eric S. Raymond
+  - Robert Readman
+  - Bernhard Reutner-Fischer
+  - Markus Rickert
+  - Cristian Rodríguez
+  - Christian von Roques
+  - Boud Roukema
+  - Torsten Rupp
+  - Stephen Sachs
+  - Jukka Salmi
+  - Agostino Sarubbo
+  - Vijay Sarvepalli
+  - Alexandre Sauvé
+  - Benno Schulenberg
+  - Andreas Schwab
+  - Eli Schwartz
+  - Peter Seiderer
+  - Bhargava Shastry
+  - Dan Shechter
+  - Stuart Shelton
+  - Sebastian Andrzej Siewior
+  - Ville Skyttä
+  - Brad Smith
+  - Bruce Stark
+  - Pippijn van Steenhoven
+  - Tobias Stoeckmann
+  - Martin Storsjö
+  - Jonathan Stott
+  - Dan Stromberg
+  - Douglas Thor
+  - Vincent Torri
+  - Alexey Tourbin
+  - Paul Townsend
+  - Mohammed Adnène Trojette
+  - Orange Tsai
+  - Taiki Tsunekawa
+  - Mathieu Vachon
+  - Maksym Vatsyk
+  - Loganaden Velvindron
+  - Patrick J. Volkerding
+  - Martin Väth
+  - Adam Walling
+  - Jeffrey Walton
+  - Christian Weisgerber
+  - Dan Weiss
+  - Bert Wesarg
+  - Fredrik Wikstrom
+  - Jim Wilcoxson
+  - Ralf Wildenhues
+  - Charles Wilson
+  - Lars Wirzenius
+  - Pilorz Wojciech
+  - Chien Wong
+  - Ryan Young
+  - Andreas Zieringer
+
+Companies:
+  - Google
+  - Sandfly Security
+
+Also thanks to all the people who have participated in the Tukaani project.
+
+I have probably forgot to add some names to the above list. Sorry about
+that and thanks for your help.
+
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/TODO b/src/libs/3rdparty/karchive/3rdparty/xz/TODO
new file mode 100644
index 00000000000..ad37f3f559a
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/TODO
@@ -0,0 +1,105 @@
+
+XZ Utils To-Do List
+===================
+
+Known bugs
+----------
+
+    The test suite is too incomplete.
+
+    If the memory usage limit is less than about 13 MiB, xz is unable to
+    automatically scale down the compression settings enough even though
+    it would be  possible by switching from BT2/BT3/BT4 match finder to
+    HC3/HC4.
+
+    XZ Utils compress some files significantly worse than LZMA Utils.
+    This is due to faster compression presets used by XZ Utils, and
+    can often be worked around by using "xz --extreme". With some files
+    --extreme isn't enough though: it's most likely with files that
+    compress extremely well, so going from compression ratio of 0.003
+    to 0.004 means big relative increase in the compressed file size.
+
+    xz doesn't quote unprintable characters when it displays file names
+    given on the command line.
+
+    tuklib_exit() doesn't block signals => EINTR is possible.
+
+    If liblzma has created threads and fork() gets called, liblzma
+    code will break in the child process unless it calls exec() and
+    doesn't touch liblzma.
+
+
+Missing features
+----------------
+
+    Add support for storing metadata in .xz files. A preliminary
+    idea is to create a new Stream type for metadata. When both
+    metadata and data are wanted in the same .xz file, two or more
+    Streams would be concatenated.
+
+    The state stored in lzma_stream should be cloneable, which would
+    be mostly useful when using a preset dictionary in LZMA2, but
+    it may have other uses too. Compare to deflateCopy() in zlib.
+
+    Support LZMA_FINISH in raw decoder to indicate end of LZMA1 and
+    other streams that don't have an end of payload marker.
+
+    Adjust dictionary size when the input file size is known.
+    Maybe do this only if an option is given.
+
+    xz doesn't support copying extended attributes, access control
+    lists etc. from source to target file.
+
+    Multithreaded compression:
+      - Reduce memory usage of the current method.
+      - Implement threaded match finders.
+      - Implement pigz-style threading in LZMA2.
+
+    Buffer-to-buffer coding could use less RAM (especially when
+    decompressing LZMA1 or LZMA2).
+
+    I/O library is not implemented (similar to gzopen() in zlib).
+    It will be a separate library that supports uncompressed, .gz,
+    .bz2, .lzma, and .xz files.
+
+    Support changing lzma_options_lzma.mode with lzma_filters_update().
+
+    Support LZMA_FULL_FLUSH for lzma_stream_decoder() to stop at
+    Block and Stream boundaries.
+
+    lzma_strerror() to convert lzma_ret to human readable form?
+    This is tricky, because the same error codes are used with
+    slightly different meanings, and this cannot be fixed anymore.
+
+    Make it possible to adjust LZMA2 options in the middle of a Block
+    so that the encoding speed vs. compression ratio can be optimized
+    when the compressed data is streamed over network.
+
+    Improved BCJ filters. The current filters are small but they aren't
+    so great when compressing binary packages that contain various file
+    types. Specifically, they make things worse if there are static
+    libraries or Linux kernel modules. The filtering could also be
+    more effective (without getting overly complex), for example,
+    streamable variant BCJ2 from 7-Zip could be implemented.
+
+    Filter that autodetects specific data types in the input stream
+    and applies appropriate filters for the corrects parts of the input.
+    Perhaps combine this with the BCJ filter improvement point above.
+
+    Long-range LZ77 method as a separate filter or as a new LZMA2
+    match finder.
+
+
+Documentation
+-------------
+
+    More tutorial programs are needed for liblzma.
+
+    Document the LZMA1 and LZMA2 algorithms.
+
+
+Miscellaneous
+------------
+
+    Try to get the media type for .xz registered at IANA.
+
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/mythread.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/mythread.h
new file mode 100644
index 00000000000..10ea2d42c24
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/mythread.h
@@ -0,0 +1,548 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       mythread.h
+/// \brief      Some threading related helper macros and functions
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef MYTHREAD_H
+#define MYTHREAD_H
+
+#include "sysdefs.h"
+
+// If any type of threading is enabled, #define MYTHREAD_ENABLED.
+#if defined(MYTHREAD_POSIX) || defined(MYTHREAD_WIN95) \
+		|| defined(MYTHREAD_VISTA)
+#	define MYTHREAD_ENABLED 1
+#endif
+
+
+#ifdef MYTHREAD_ENABLED
+
+////////////////////////////////////////
+// Shared between all threading types //
+////////////////////////////////////////
+
+// Locks a mutex for a duration of a block.
+//
+// Perform mythread_mutex_lock(&mutex) in the beginning of a block
+// and mythread_mutex_unlock(&mutex) at the end of the block. "break"
+// may be used to unlock the mutex and jump out of the block.
+// mythread_sync blocks may be nested.
+//
+// Example:
+//
+//     mythread_sync(mutex) {
+//         foo();
+//         if (some_error)
+//             break; // Skips bar()
+//         bar();
+//     }
+//
+// At least GCC optimizes the loops completely away so it doesn't slow
+// things down at all compared to plain mythread_mutex_lock(&mutex)
+// and mythread_mutex_unlock(&mutex) calls.
+//
+#define mythread_sync(mutex) mythread_sync_helper1(mutex, __LINE__)
+#define mythread_sync_helper1(mutex, line) mythread_sync_helper2(mutex, line)
+#define mythread_sync_helper2(mutex, line) \
+	for (unsigned int mythread_i_ ## line = 0; \
+			mythread_i_ ## line \
+				? (mythread_mutex_unlock(&(mutex)), 0) \
+				: (mythread_mutex_lock(&(mutex)), 1); \
+			mythread_i_ ## line = 1) \
+		for (unsigned int mythread_j_ ## line = 0; \
+				!mythread_j_ ## line; \
+				mythread_j_ ## line = 1)
+#endif
+
+
+#if !defined(MYTHREAD_ENABLED)
+
+//////////////////
+// No threading //
+//////////////////
+
+// Calls the given function once. This isn't thread safe.
+#define mythread_once(func) \
+do { \
+	static bool once_ = false; \
+	if (!once_) { \
+		func(); \
+		once_ = true; \
+	} \
+} while (0)
+
+
+#if !(defined(_WIN32) && !defined(__CYGWIN__)) && !defined(__wasm__)
+// Use sigprocmask() to set the signal mask in single-threaded programs.
+#include 
+
+static inline void
+mythread_sigmask(int how, const sigset_t *restrict set,
+		sigset_t *restrict oset)
+{
+	int ret = sigprocmask(how, set, oset);
+	assert(ret == 0);
+	(void)ret;
+}
+#endif
+
+
+#elif defined(MYTHREAD_POSIX)
+
+////////////////////
+// Using pthreads //
+////////////////////
+
+#include 
+#include 
+#include 
+#include 
+
+// If clock_gettime() isn't available, use gettimeofday() from 
+// as a fallback. gettimeofday() is in SUSv2 and thus is supported on all
+// relevant POSIX systems.
+#ifndef HAVE_CLOCK_GETTIME
+#	include 
+#endif
+
+// MinGW-w64 with winpthreads:
+//
+// NOTE: Typical builds with MinGW-w64 don't use this code (MYTHREAD_POSIX).
+// Instead, native Windows threading APIs are used (MYTHREAD_VISTA or
+// MYTHREAD_WIN95).
+//
+// MinGW-w64 has _sigset_t (an integer type) in .
+// If _POSIX was #defined, the header would add the alias sigset_t too.
+// Let's keep this working even without _POSIX.
+//
+// There are no functions that actually do something with sigset_t
+// because signals barely exist on Windows. The sigfillset macro below
+// is just to silence warnings. There is no sigfillset() in MinGW-w64.
+#ifdef __MINGW32__
+#	include 
+#	define sigset_t _sigset_t
+#	define sigfillset(set_ptr) do { *(set_ptr) = 0; } while (0)
+#endif
+
+#define MYTHREAD_RET_TYPE void *
+#define MYTHREAD_RET_VALUE NULL
+
+typedef pthread_t mythread;
+typedef pthread_mutex_t mythread_mutex;
+
+typedef struct {
+	pthread_cond_t cond;
+#ifdef HAVE_CLOCK_GETTIME
+	// Clock ID (CLOCK_REALTIME or CLOCK_MONOTONIC) associated with
+	// the condition variable.
+	clockid_t clk_id;
+#endif
+} mythread_cond;
+
+typedef struct timespec mythread_condtime;
+
+
+// Calls the given function once in a thread-safe way.
+#define mythread_once(func) \
+	do { \
+		static pthread_once_t once_ = PTHREAD_ONCE_INIT; \
+		pthread_once(&once_, &func); \
+	} while (0)
+
+
+// Use pthread_sigmask() to set the signal mask in multi-threaded programs.
+// Do nothing on OpenVMS since it lacks pthread_sigmask().
+// Do nothing on MinGW-w64 too to silence warnings (its pthread_sigmask()
+// is #defined to 0 so it's a no-op).
+static inline void
+mythread_sigmask(int how, const sigset_t *restrict set,
+		sigset_t *restrict oset)
+{
+#if defined(__VMS) || defined(__MINGW32__)
+	(void)how;
+	(void)set;
+	(void)oset;
+#else
+	int ret = pthread_sigmask(how, set, oset);
+	assert(ret == 0);
+	(void)ret;
+#endif
+}
+
+
+// Creates a new thread with all signals blocked. Returns zero on success
+// and non-zero on error.
+static inline int
+mythread_create(mythread *thread, void *(*func)(void *arg), void *arg)
+{
+	sigset_t old;
+	sigset_t all;
+	sigfillset(&all);
+
+	mythread_sigmask(SIG_SETMASK, &all, &old);
+	const int ret = pthread_create(thread, NULL, func, arg);
+	mythread_sigmask(SIG_SETMASK, &old, NULL);
+
+	return ret;
+}
+
+// Joins a thread. Returns zero on success and non-zero on error.
+static inline int
+mythread_join(mythread thread)
+{
+	return pthread_join(thread, NULL);
+}
+
+
+// Initializes a mutex. Returns zero on success and non-zero on error.
+static inline int
+mythread_mutex_init(mythread_mutex *mutex)
+{
+	return pthread_mutex_init(mutex, NULL);
+}
+
+static inline void
+mythread_mutex_destroy(mythread_mutex *mutex)
+{
+	int ret = pthread_mutex_destroy(mutex);
+	assert(ret == 0);
+	(void)ret;
+}
+
+static inline void
+mythread_mutex_lock(mythread_mutex *mutex)
+{
+	int ret = pthread_mutex_lock(mutex);
+	assert(ret == 0);
+	(void)ret;
+}
+
+static inline void
+mythread_mutex_unlock(mythread_mutex *mutex)
+{
+	int ret = pthread_mutex_unlock(mutex);
+	assert(ret == 0);
+	(void)ret;
+}
+
+
+// Initializes a condition variable.
+//
+// Using CLOCK_MONOTONIC instead of the default CLOCK_REALTIME makes the
+// timeout in pthread_cond_timedwait() work correctly also if system time
+// is suddenly changed. Unfortunately CLOCK_MONOTONIC isn't available
+// everywhere while the default CLOCK_REALTIME is, so the default is
+// used if CLOCK_MONOTONIC isn't available.
+//
+// If clock_gettime() isn't available at all, gettimeofday() will be used.
+static inline int
+mythread_cond_init(mythread_cond *mycond)
+{
+#ifdef HAVE_CLOCK_GETTIME
+#	if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && \
+		defined(HAVE_CLOCK_MONOTONIC)
+	struct timespec ts;
+	pthread_condattr_t condattr;
+
+	// POSIX doesn't seem to *require* that pthread_condattr_setclock()
+	// will fail if given an unsupported clock ID. Test that
+	// CLOCK_MONOTONIC really is supported using clock_gettime().
+	if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0
+			&& pthread_condattr_init(&condattr) == 0) {
+		int ret = pthread_condattr_setclock(
+				&condattr, CLOCK_MONOTONIC);
+		if (ret == 0)
+			ret = pthread_cond_init(&mycond->cond, &condattr);
+
+		pthread_condattr_destroy(&condattr);
+
+		if (ret == 0) {
+			mycond->clk_id = CLOCK_MONOTONIC;
+			return 0;
+		}
+	}
+
+	// If anything above fails, fall back to the default CLOCK_REALTIME.
+	// POSIX requires that all implementations of clock_gettime() must
+	// support at least CLOCK_REALTIME.
+#	endif
+
+	mycond->clk_id = CLOCK_REALTIME;
+#endif
+
+	return pthread_cond_init(&mycond->cond, NULL);
+}
+
+static inline void
+mythread_cond_destroy(mythread_cond *cond)
+{
+	int ret = pthread_cond_destroy(&cond->cond);
+	assert(ret == 0);
+	(void)ret;
+}
+
+static inline void
+mythread_cond_signal(mythread_cond *cond)
+{
+	int ret = pthread_cond_signal(&cond->cond);
+	assert(ret == 0);
+	(void)ret;
+}
+
+static inline void
+mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
+{
+	int ret = pthread_cond_wait(&cond->cond, mutex);
+	assert(ret == 0);
+	(void)ret;
+}
+
+// Waits on a condition or until a timeout expires. If the timeout expires,
+// non-zero is returned, otherwise zero is returned.
+static inline int
+mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
+		const mythread_condtime *condtime)
+{
+	int ret = pthread_cond_timedwait(&cond->cond, mutex, condtime);
+	assert(ret == 0 || ret == ETIMEDOUT);
+	return ret;
+}
+
+// Sets condtime to the absolute time that is timeout_ms milliseconds
+// in the future. The type of the clock to use is taken from cond.
+static inline void
+mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
+		uint32_t timeout_ms)
+{
+	condtime->tv_sec = (time_t)(timeout_ms / 1000);
+	condtime->tv_nsec = (long)((timeout_ms % 1000) * 1000000);
+
+#ifdef HAVE_CLOCK_GETTIME
+	struct timespec now;
+	int ret = clock_gettime(cond->clk_id, &now);
+	assert(ret == 0);
+	(void)ret;
+
+	condtime->tv_sec += now.tv_sec;
+	condtime->tv_nsec += now.tv_nsec;
+#else
+	(void)cond;
+
+	struct timeval now;
+	gettimeofday(&now, NULL);
+
+	condtime->tv_sec += now.tv_sec;
+	condtime->tv_nsec += now.tv_usec * 1000L;
+#endif
+
+	// tv_nsec must stay in the range [0, 999_999_999].
+	if (condtime->tv_nsec >= 1000000000L) {
+		condtime->tv_nsec -= 1000000000L;
+		++condtime->tv_sec;
+	}
+}
+
+
+#elif defined(MYTHREAD_WIN95) || defined(MYTHREAD_VISTA)
+
+/////////////////////
+// Windows threads //
+/////////////////////
+
+#define WIN32_LEAN_AND_MEAN
+#ifdef MYTHREAD_VISTA
+#	undef _WIN32_WINNT
+#	define _WIN32_WINNT 0x0600
+#endif
+#include 
+#include 
+
+#define MYTHREAD_RET_TYPE unsigned int __stdcall
+#define MYTHREAD_RET_VALUE 0
+
+typedef HANDLE mythread;
+typedef CRITICAL_SECTION mythread_mutex;
+
+#ifdef MYTHREAD_WIN95
+typedef HANDLE mythread_cond;
+#else
+typedef CONDITION_VARIABLE mythread_cond;
+#endif
+
+typedef struct {
+	// Tick count (milliseconds) in the beginning of the timeout.
+	// NOTE: This is 32 bits so it wraps around after 49.7 days.
+	// Multi-day timeouts may not work as expected.
+	DWORD start;
+
+	// Length of the timeout in milliseconds. The timeout expires
+	// when the current tick count minus "start" is equal or greater
+	// than "timeout".
+	DWORD timeout;
+} mythread_condtime;
+
+
+// mythread_once() is only available with Vista threads.
+#ifdef MYTHREAD_VISTA
+#define mythread_once(func) \
+	do { \
+		static INIT_ONCE once_ = INIT_ONCE_STATIC_INIT; \
+		BOOL pending_; \
+		if (!InitOnceBeginInitialize(&once_, 0, &pending_, NULL)) \
+			abort(); \
+		if (pending_) { \
+			func(); \
+			if (!InitOnceComplete(&once_, 0, NULL)) \
+				abort(); \
+		} \
+	} while (0)
+#endif
+
+
+// mythread_sigmask() isn't available on Windows. Even a dummy version would
+// make no sense because the other POSIX signal functions are missing anyway.
+
+
+static inline int
+mythread_create(mythread *thread,
+		unsigned int (__stdcall *func)(void *arg), void *arg)
+{
+	uintptr_t ret = _beginthreadex(NULL, 0, func, arg, 0, NULL);
+	if (ret == 0)
+		return -1;
+
+	*thread = (HANDLE)ret;
+	return 0;
+}
+
+static inline int
+mythread_join(mythread thread)
+{
+	int ret = 0;
+
+	if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0)
+		ret = -1;
+
+	if (!CloseHandle(thread))
+		ret = -1;
+
+	return ret;
+}
+
+
+static inline int
+mythread_mutex_init(mythread_mutex *mutex)
+{
+	InitializeCriticalSection(mutex);
+	return 0;
+}
+
+static inline void
+mythread_mutex_destroy(mythread_mutex *mutex)
+{
+	DeleteCriticalSection(mutex);
+}
+
+static inline void
+mythread_mutex_lock(mythread_mutex *mutex)
+{
+	EnterCriticalSection(mutex);
+}
+
+static inline void
+mythread_mutex_unlock(mythread_mutex *mutex)
+{
+	LeaveCriticalSection(mutex);
+}
+
+
+static inline int
+mythread_cond_init(mythread_cond *cond)
+{
+#ifdef MYTHREAD_WIN95
+	*cond = CreateEvent(NULL, FALSE, FALSE, NULL);
+	return *cond == NULL ? -1 : 0;
+#else
+	InitializeConditionVariable(cond);
+	return 0;
+#endif
+}
+
+static inline void
+mythread_cond_destroy(mythread_cond *cond)
+{
+#ifdef MYTHREAD_WIN95
+	CloseHandle(*cond);
+#else
+	(void)cond;
+#endif
+}
+
+static inline void
+mythread_cond_signal(mythread_cond *cond)
+{
+#ifdef MYTHREAD_WIN95
+	SetEvent(*cond);
+#else
+	WakeConditionVariable(cond);
+#endif
+}
+
+static inline void
+mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
+{
+#ifdef MYTHREAD_WIN95
+	LeaveCriticalSection(mutex);
+	WaitForSingleObject(*cond, INFINITE);
+	EnterCriticalSection(mutex);
+#else
+	BOOL ret = SleepConditionVariableCS(cond, mutex, INFINITE);
+	assert(ret);
+	(void)ret;
+#endif
+}
+
+static inline int
+mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
+		const mythread_condtime *condtime)
+{
+#ifdef MYTHREAD_WIN95
+	LeaveCriticalSection(mutex);
+#endif
+
+	DWORD elapsed = GetTickCount() - condtime->start;
+	DWORD timeout = elapsed >= condtime->timeout
+			? 0 : condtime->timeout - elapsed;
+
+#ifdef MYTHREAD_WIN95
+	DWORD ret = WaitForSingleObject(*cond, timeout);
+	assert(ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT);
+
+	EnterCriticalSection(mutex);
+
+	return ret == WAIT_TIMEOUT;
+#else
+	BOOL ret = SleepConditionVariableCS(cond, mutex, timeout);
+	assert(ret || GetLastError() == ERROR_TIMEOUT);
+	return !ret;
+#endif
+}
+
+static inline void
+mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
+		uint32_t timeout)
+{
+	(void)cond;
+	condtime->start = GetTickCount();
+	condtime->timeout = timeout;
+}
+
+#endif
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/sysdefs.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/sysdefs.h
new file mode 100644
index 00000000000..5f3785b5137
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/sysdefs.h
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       sysdefs.h
+/// \brief      Common includes, definitions, system-specific things etc.
+///
+/// This file is used also by the lzma command line tool, that's why this
+/// file is separate from common.h.
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_SYSDEFS_H
+#define LZMA_SYSDEFS_H
+
+//////////////
+// Includes //
+//////////////
+
+#ifdef HAVE_CONFIG_H
+#	include 
+#endif
+
+// This #define ensures that C99 and POSIX compliant stdio functions are
+// available with MinGW-w64 (both 32-bit and 64-bit). Modern MinGW-w64 adds
+// this automatically, for example, when the compiler is in C99 (or later)
+// mode when building against msvcrt.dll. It still doesn't hurt to be explicit
+// that we always want this and #define this unconditionally.
+//
+// With Universal CRT (UCRT) this is less important because UCRT contains
+// C99-compatible stdio functions. It's still nice to #define this as UCRT
+// doesn't support the POSIX thousand separator flag in printf (like "%'u").
+#ifdef __MINGW32__
+#	define __USE_MINGW_ANSI_STDIO 1
+#endif
+
+// size_t and NULL
+#include 
+
+#ifdef HAVE_INTTYPES_H
+#	include 
+#endif
+
+// C99 says that inttypes.h always includes stdint.h, but some systems
+// don't do that, and require including stdint.h separately.
+#ifdef HAVE_STDINT_H
+#	include 
+#endif
+
+// Some pre-C99 systems have SIZE_MAX in limits.h instead of stdint.h. The
+// limits are also used to figure out some macros missing from pre-C99 systems.
+#include 
+
+// Be more compatible with systems that have non-conforming inttypes.h.
+// We assume that int is 32-bit and that long is either 32-bit or 64-bit.
+// Full Autoconf test could be more correct, but this should work well enough.
+// Note that this duplicates some code from lzma.h, but this is better since
+// we can work without inttypes.h thanks to Autoconf tests.
+#ifndef UINT32_C
+#	if UINT_MAX != 4294967295U
+#		error UINT32_C is not defined and unsigned int is not 32-bit.
+#	endif
+#	define UINT32_C(n) n ## U
+#endif
+#ifndef UINT32_MAX
+#	define UINT32_MAX UINT32_C(4294967295)
+#endif
+#ifndef PRIu32
+#	define PRIu32 "u"
+#endif
+#ifndef PRIx32
+#	define PRIx32 "x"
+#endif
+#ifndef PRIX32
+#	define PRIX32 "X"
+#endif
+
+#if ULONG_MAX == 4294967295UL
+#	ifndef UINT64_C
+#		define UINT64_C(n) n ## ULL
+#	endif
+#	ifndef PRIu64
+#		define PRIu64 "llu"
+#	endif
+#	ifndef PRIx64
+#		define PRIx64 "llx"
+#	endif
+#	ifndef PRIX64
+#		define PRIX64 "llX"
+#	endif
+#else
+#	ifndef UINT64_C
+#		define UINT64_C(n) n ## UL
+#	endif
+#	ifndef PRIu64
+#		define PRIu64 "lu"
+#	endif
+#	ifndef PRIx64
+#		define PRIx64 "lx"
+#	endif
+#	ifndef PRIX64
+#		define PRIX64 "lX"
+#	endif
+#endif
+#ifndef UINT64_MAX
+#	define UINT64_MAX UINT64_C(18446744073709551615)
+#endif
+
+// Incorrect(?) SIZE_MAX:
+//   - Interix headers typedef size_t to unsigned long,
+//     but a few lines later define SIZE_MAX to INT32_MAX.
+//   - SCO OpenServer (x86) headers typedef size_t to unsigned int
+//     but define SIZE_MAX to INT32_MAX.
+#if defined(__INTERIX) || defined(_SCO_DS)
+#	undef SIZE_MAX
+#endif
+
+// The code currently assumes that size_t is either 32-bit or 64-bit.
+#ifndef SIZE_MAX
+#	if SIZEOF_SIZE_T == 4
+#		define SIZE_MAX UINT32_MAX
+#	elif SIZEOF_SIZE_T == 8
+#		define SIZE_MAX UINT64_MAX
+#	else
+#		error size_t is not 32-bit or 64-bit
+#	endif
+#endif
+#if SIZE_MAX != UINT32_MAX && SIZE_MAX != UINT64_MAX
+#	error size_t is not 32-bit or 64-bit
+#endif
+
+#include 
+#include 
+
+// Pre-C99 systems lack stdbool.h. All the code in XZ Utils must be written
+// so that it works with fake bool type, for example:
+//
+//    bool foo = (flags & 0x100) != 0;
+//    bool bar = !!(flags & 0x100);
+//
+// This works with the real C99 bool but breaks with fake bool:
+//
+//    bool baz = (flags & 0x100);
+//
+#ifdef HAVE_STDBOOL_H
+#	include 
+#else
+#	if ! HAVE__BOOL
+typedef unsigned char _Bool;
+#	endif
+#	define bool _Bool
+#	define false 0
+#	define true 1
+#	define __bool_true_false_are_defined 1
+#endif
+
+#include 
+
+// Visual Studio 2013 update 2 supports only __inline, not inline.
+// MSVC v19.0 / VS 2015 and newer support both.
+//
+// MSVC v19.27 (VS 2019 version 16.7) added support for restrict.
+// Older ones support only __restrict.
+#ifdef _MSC_VER
+#	if _MSC_VER < 1900 && !defined(inline)
+#		define inline __inline
+#	endif
+#	if _MSC_VER < 1927 && !defined(restrict)
+#		define restrict __restrict
+#	endif
+#endif
+
+////////////
+// Macros //
+////////////
+
+#undef memzero
+#define memzero(s, n) memset(s, 0, n)
+
+// NOTE: Avoid using MIN() and MAX(), because even conditionally defining
+// those macros can cause some portability trouble, since on some systems
+// the system headers insist defining their own versions.
+#define my_min(x, y) ((x) < (y) ? (x) : (y))
+#define my_max(x, y) ((x) > (y) ? (x) : (y))
+
+#ifndef ARRAY_SIZE
+#	define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
+#endif
+
+#if defined(__GNUC__) \
+		&& ((__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4)
+#	define lzma_attr_alloc_size(x) __attribute__((__alloc_size__(x)))
+#else
+#	define lzma_attr_alloc_size(x)
+#endif
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_common.h
new file mode 100644
index 00000000000..7554dfc86fb
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_common.h
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_common.h
+/// \brief      Common definitions for tuklib modules
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TUKLIB_COMMON_H
+#define TUKLIB_COMMON_H
+
+// The config file may be replaced by a package-specific file.
+// It should include at least stddef.h, stdbool.h, inttypes.h, and limits.h.
+#include "tuklib_config.h"
+
+// TUKLIB_SYMBOL_PREFIX is prefixed to all symbols exported by
+// the tuklib modules. If you use a tuklib module in a library,
+// you should use TUKLIB_SYMBOL_PREFIX to make sure that there
+// are no symbol conflicts in case someone links your library
+// into application that also uses the same tuklib module.
+#ifndef TUKLIB_SYMBOL_PREFIX
+#	define TUKLIB_SYMBOL_PREFIX
+#endif
+
+#define TUKLIB_CAT_X(a, b) a ## b
+#define TUKLIB_CAT(a, b) TUKLIB_CAT_X(a, b)
+
+#ifndef TUKLIB_SYMBOL
+#	define TUKLIB_SYMBOL(sym) TUKLIB_CAT(TUKLIB_SYMBOL_PREFIX, sym)
+#endif
+
+#ifndef TUKLIB_DECLS_BEGIN
+#	ifdef __cplusplus
+#		define TUKLIB_DECLS_BEGIN extern "C" {
+#	else
+#		define TUKLIB_DECLS_BEGIN
+#	endif
+#endif
+
+#ifndef TUKLIB_DECLS_END
+#	ifdef __cplusplus
+#		define TUKLIB_DECLS_END }
+#	else
+#		define TUKLIB_DECLS_END
+#	endif
+#endif
+
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+#	define TUKLIB_GNUC_REQ(major, minor) \
+		((__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)) \
+			|| __GNUC__ > (major))
+#else
+#	define TUKLIB_GNUC_REQ(major, minor) 0
+#endif
+
+// tuklib_attr_noreturn attribute is used to mark functions as non-returning.
+// We cannot use "noreturn" as the macro name because then C23 code that
+// uses [[noreturn]] would break as it would expand to [[ [[noreturn]] ]].
+//
+// tuklib_attr_noreturn must be used at the beginning of function declaration
+// to work in all cases. The [[noreturn]] syntax is the most limiting, it
+// must be even before any GNU C's __attribute__ keywords:
+//
+//     tuklib_attr_noreturn
+//     __attribute__((nonnull(1)))
+//     extern void foo(const char *s);
+//
+// FIXME: Update __STDC_VERSION__ for the final C23 version. 202000 is used
+// by GCC 13 and Clang 15 with -std=c2x.
+#if   defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000
+#	define tuklib_attr_noreturn [[noreturn]]
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112
+#	define tuklib_attr_noreturn _Noreturn
+#elif TUKLIB_GNUC_REQ(2, 5)
+#	define tuklib_attr_noreturn __attribute__((__noreturn__))
+#elif defined(_MSC_VER)
+#	define tuklib_attr_noreturn __declspec(noreturn)
+#else
+#	define tuklib_attr_noreturn
+#endif
+
+#if (defined(_WIN32) && !defined(__CYGWIN__)) \
+		|| defined(__OS2__) || defined(__MSDOS__)
+#	define TUKLIB_DOSLIKE 1
+#endif
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_config.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_config.h
new file mode 100644
index 00000000000..b27251dc276
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_config.h
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: 0BSD
+
+// If config.h isn't available, assume that the headers required by
+// tuklib_common.h are available. This is required by crc32_tablegen.c.
+#ifdef HAVE_CONFIG_H
+#	include "sysdefs.h"
+#else
+#	include 
+#	include 
+#	include 
+#	include 
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.c
new file mode 100644
index 00000000000..c4a781ac387
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_cpucores.c
+/// \brief      Get the number of CPU cores online
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tuklib_cpucores.h"
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+#	ifndef _WIN32_WINNT
+#		define _WIN32_WINNT 0x0500
+#	endif
+#	include 
+
+// glibc >= 2.9
+#elif defined(TUKLIB_CPUCORES_SCHED_GETAFFINITY)
+#	include 
+
+// FreeBSD
+#elif defined(TUKLIB_CPUCORES_CPUSET)
+#	include 
+#	include 
+
+#elif defined(TUKLIB_CPUCORES_SYSCTL)
+#	ifdef HAVE_SYS_PARAM_H
+#		include 
+#	endif
+#	include 
+
+#elif defined(TUKLIB_CPUCORES_SYSCONF)
+#	include 
+
+// HP-UX
+#elif defined(TUKLIB_CPUCORES_PSTAT_GETDYNAMIC)
+#	include 
+#	include 
+#endif
+
+
+extern uint32_t
+tuklib_cpucores(void)
+{
+	uint32_t ret = 0;
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+	SYSTEM_INFO sysinfo;
+	GetSystemInfo(&sysinfo);
+	ret = sysinfo.dwNumberOfProcessors;
+
+#elif defined(TUKLIB_CPUCORES_SCHED_GETAFFINITY)
+	cpu_set_t cpu_mask;
+	if (sched_getaffinity(0, sizeof(cpu_mask), &cpu_mask) == 0)
+		ret = (uint32_t)CPU_COUNT(&cpu_mask);
+
+#elif defined(TUKLIB_CPUCORES_CPUSET)
+	cpuset_t set;
+	if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
+			sizeof(set), &set) == 0) {
+#	ifdef CPU_COUNT
+		ret = (uint32_t)CPU_COUNT(&set);
+#	else
+		for (unsigned i = 0; i < CPU_SETSIZE; ++i)
+			if (CPU_ISSET(i, &set))
+				++ret;
+#	endif
+	}
+
+#elif defined(TUKLIB_CPUCORES_SYSCTL)
+	// On OpenBSD HW_NCPUONLINE tells the number of processor cores that
+	// are online so it is preferred over HW_NCPU which also counts cores
+	// that aren't currently available. The number of cores online is
+	// often less than HW_NCPU because OpenBSD disables simultaneous
+	// multi-threading (SMT) by default.
+#	ifdef HW_NCPUONLINE
+	int name[2] = { CTL_HW, HW_NCPUONLINE };
+#	else
+	int name[2] = { CTL_HW, HW_NCPU };
+#	endif
+	int cpus;
+	size_t cpus_size = sizeof(cpus);
+	if (sysctl(name, 2, &cpus, &cpus_size, NULL, 0) != -1
+			&& cpus_size == sizeof(cpus) && cpus > 0)
+		ret = (uint32_t)cpus;
+
+#elif defined(TUKLIB_CPUCORES_SYSCONF)
+#	ifdef _SC_NPROCESSORS_ONLN
+	// Most systems
+	const long cpus = sysconf(_SC_NPROCESSORS_ONLN);
+#	else
+	// IRIX
+	const long cpus = sysconf(_SC_NPROC_ONLN);
+#	endif
+	if (cpus > 0)
+		ret = (uint32_t)cpus;
+
+#elif defined(TUKLIB_CPUCORES_PSTAT_GETDYNAMIC)
+	struct pst_dynamic pst;
+	if (pstat_getdynamic(&pst, sizeof(pst), 1, 0) != -1)
+		ret = (uint32_t)pst.psd_proc_cnt;
+#endif
+
+	return ret;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.h
new file mode 100644
index 00000000000..edff9395e41
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_cpucores.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_cpucores.h
+/// \brief      Get the number of CPU cores online
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TUKLIB_CPUCORES_H
+#define TUKLIB_CPUCORES_H
+
+#include "tuklib_common.h"
+TUKLIB_DECLS_BEGIN
+
+#define tuklib_cpucores TUKLIB_SYMBOL(tuklib_cpucores)
+extern uint32_t tuklib_cpucores(void);
+
+TUKLIB_DECLS_END
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.c
new file mode 100644
index 00000000000..c84e0f679a6
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_exit.c
+/// \brief      Close stdout and stderr, and exit
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tuklib_common.h"
+
+#include 
+#include 
+#include 
+
+#include "tuklib_gettext.h"
+#include "tuklib_progname.h"
+#include "tuklib_exit.h"
+
+
+extern void
+tuklib_exit(int status, int err_status, int show_error)
+{
+	if (status != err_status) {
+		// Close stdout. If something goes wrong,
+		// print an error message to stderr.
+		const int ferror_err = ferror(stdout);
+		const int fclose_err = fclose(stdout);
+		if (ferror_err || fclose_err) {
+			status = err_status;
+
+			// If it was fclose() that failed, we have the reason
+			// in errno. If only ferror() indicated an error,
+			// we have no idea what the reason was.
+			if (show_error)
+				fprintf(stderr, "%s: %s: %s\n", progname,
+						_("Writing to standard "
+							"output failed"),
+						fclose_err ? strerror(errno)
+							: _("Unknown error"));
+		}
+	}
+
+	if (status != err_status) {
+		// Close stderr. If something goes wrong, there's
+		// nothing where we could print an error message.
+		// Just set the exit status.
+		const int ferror_err = ferror(stderr);
+		const int fclose_err = fclose(stderr);
+		if (fclose_err || ferror_err)
+			status = err_status;
+	}
+
+	exit(status);
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.h
new file mode 100644
index 00000000000..d4e6b4a7e83
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_exit.h
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_exit.h
+/// \brief      Close stdout and stderr, and exit
+/// \note       Requires tuklib_progname and tuklib_gettext modules
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TUKLIB_EXIT_H
+#define TUKLIB_EXIT_H
+
+#include "tuklib_common.h"
+TUKLIB_DECLS_BEGIN
+
+#define tuklib_exit TUKLIB_SYMBOL(tuklib_exit)
+tuklib_attr_noreturn
+extern void tuklib_exit(int status, int err_status, int show_error);
+
+TUKLIB_DECLS_END
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_gettext.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_gettext.h
new file mode 100644
index 00000000000..3ef5cb7292b
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_gettext.h
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_gettext.h
+/// \brief      Wrapper for gettext and friends
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TUKLIB_GETTEXT_H
+#define TUKLIB_GETTEXT_H
+
+#include "tuklib_common.h"
+#include 
+
+#ifndef TUKLIB_GETTEXT
+#	ifdef ENABLE_NLS
+#		define TUKLIB_GETTEXT 1
+#	else
+#		define TUKLIB_GETTEXT 0
+#	endif
+#endif
+
+#if TUKLIB_GETTEXT
+#	include 
+#	define tuklib_gettext_init(package, localedir) \
+		do { \
+			setlocale(LC_ALL, ""); \
+			bindtextdomain(package, localedir); \
+			textdomain(package); \
+		} while (0)
+#	define _(msgid) gettext(msgid)
+#else
+#	define tuklib_gettext_init(package, localedir) \
+		setlocale(LC_ALL, "")
+#	define _(msgid) (msgid)
+#	define ngettext(msgid1, msgid2, n) ((n) == 1 ? (msgid1) : (msgid2))
+#endif
+#define N_(msgid) msgid
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_integer.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_integer.h
new file mode 100644
index 00000000000..4026249e546
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_integer.h
@@ -0,0 +1,954 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_integer.h
+/// \brief      Various integer and bit operations
+///
+/// This file provides macros or functions to do some basic integer and bit
+/// operations.
+///
+/// Native endian inline functions (XX = 16, 32, or 64):
+///   - Unaligned native endian reads: readXXne(ptr)
+///   - Unaligned native endian writes: writeXXne(ptr, num)
+///   - Aligned native endian reads: aligned_readXXne(ptr)
+///   - Aligned native endian writes: aligned_writeXXne(ptr, num)
+///
+/// Endianness-converting integer operations (these can be macros!)
+/// (XX = 16, 32, or 64; Y = b or l):
+///   - Byte swapping: byteswapXX(num)
+///   - Byte order conversions to/from native (byteswaps if Y isn't
+///     the native endianness): convXXYe(num)
+///   - Unaligned reads: readXXYe(ptr)
+///   - Unaligned writes: writeXXYe(ptr, num)
+///   - Aligned reads: aligned_readXXYe(ptr)
+///   - Aligned writes: aligned_writeXXYe(ptr, num)
+///
+/// Since the above can macros, the arguments should have no side effects
+/// because they may be evaluated more than once.
+///
+/// Bit scan operations for non-zero 32-bit integers (inline functions):
+///   - Bit scan reverse (find highest non-zero bit): bsr32(num)
+///   - Count leading zeros: clz32(num)
+///   - Count trailing zeros: ctz32(num)
+///   - Bit scan forward (simply an alias for ctz32()): bsf32(num)
+///
+/// The above bit scan operations return 0-31. If num is zero,
+/// the result is undefined.
+//
+//  Authors:    Lasse Collin
+//              Joachim Henke
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TUKLIB_INTEGER_H
+#define TUKLIB_INTEGER_H
+
+#include "tuklib_common.h"
+#include 
+
+// Newer Intel C compilers require immintrin.h for _bit_scan_reverse()
+// and such functions.
+#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500)
+#	include 
+// Only include  when it is needed. GCC and Clang can both
+// use __builtin's, so we only need Windows instrincs when using MSVC.
+// GCC and Clang can set _MSC_VER on Windows, so we need to exclude these
+// cases explicitly.
+#elif defined(_MSC_VER) && !TUKLIB_GNUC_REQ(3, 4) && !defined(__clang__)
+#	include 
+#endif
+
+
+///////////////////
+// Byte swapping //
+///////////////////
+
+#if defined(HAVE___BUILTIN_BSWAPXX)
+	// GCC >= 4.8 and Clang
+#	define byteswap16(num) __builtin_bswap16(num)
+#	define byteswap32(num) __builtin_bswap32(num)
+#	define byteswap64(num) __builtin_bswap64(num)
+
+#elif defined(HAVE_BYTESWAP_H)
+	// glibc, uClibc, dietlibc
+#	include 
+#	ifdef HAVE_BSWAP_16
+#		define byteswap16(num) bswap_16(num)
+#	endif
+#	ifdef HAVE_BSWAP_32
+#		define byteswap32(num) bswap_32(num)
+#	endif
+#	ifdef HAVE_BSWAP_64
+#		define byteswap64(num) bswap_64(num)
+#	endif
+
+#elif defined(HAVE_SYS_ENDIAN_H)
+	// *BSDs and Darwin
+#	include 
+#	ifdef __OpenBSD__
+#		define byteswap16(num) swap16(num)
+#		define byteswap32(num) swap32(num)
+#		define byteswap64(num) swap64(num)
+#	else
+#		define byteswap16(num) bswap16(num)
+#		define byteswap32(num) bswap32(num)
+#		define byteswap64(num) bswap64(num)
+#	endif
+
+#elif defined(HAVE_SYS_BYTEORDER_H)
+	// Solaris
+#	include 
+#	ifdef BSWAP_16
+#		define byteswap16(num) BSWAP_16(num)
+#	endif
+#	ifdef BSWAP_32
+#		define byteswap32(num) BSWAP_32(num)
+#	endif
+#	ifdef BSWAP_64
+#		define byteswap64(num) BSWAP_64(num)
+#	endif
+#	ifdef BE_16
+#		define conv16be(num) BE_16(num)
+#	endif
+#	ifdef BE_32
+#		define conv32be(num) BE_32(num)
+#	endif
+#	ifdef BE_64
+#		define conv64be(num) BE_64(num)
+#	endif
+#	ifdef LE_16
+#		define conv16le(num) LE_16(num)
+#	endif
+#	ifdef LE_32
+#		define conv32le(num) LE_32(num)
+#	endif
+#	ifdef LE_64
+#		define conv64le(num) LE_64(num)
+#	endif
+#endif
+
+#ifndef byteswap16
+#	define byteswap16(n) (uint16_t)( \
+		  (((n) & 0x00FFU) << 8) \
+		| (((n) & 0xFF00U) >> 8) \
+	)
+#endif
+
+#ifndef byteswap32
+#	define byteswap32(n) (uint32_t)( \
+		  (((n) & UINT32_C(0x000000FF)) << 24) \
+		| (((n) & UINT32_C(0x0000FF00)) << 8) \
+		| (((n) & UINT32_C(0x00FF0000)) >> 8) \
+		| (((n) & UINT32_C(0xFF000000)) >> 24) \
+	)
+#endif
+
+#ifndef byteswap64
+#	define byteswap64(n) (uint64_t)( \
+		  (((n) & UINT64_C(0x00000000000000FF)) << 56) \
+		| (((n) & UINT64_C(0x000000000000FF00)) << 40) \
+		| (((n) & UINT64_C(0x0000000000FF0000)) << 24) \
+		| (((n) & UINT64_C(0x00000000FF000000)) << 8) \
+		| (((n) & UINT64_C(0x000000FF00000000)) >> 8) \
+		| (((n) & UINT64_C(0x0000FF0000000000)) >> 24) \
+		| (((n) & UINT64_C(0x00FF000000000000)) >> 40) \
+		| (((n) & UINT64_C(0xFF00000000000000)) >> 56) \
+	)
+#endif
+
+// Define conversion macros using the basic byte swapping macros.
+#ifdef WORDS_BIGENDIAN
+#	ifndef conv16be
+#		define conv16be(num) ((uint16_t)(num))
+#	endif
+#	ifndef conv32be
+#		define conv32be(num) ((uint32_t)(num))
+#	endif
+#	ifndef conv64be
+#		define conv64be(num) ((uint64_t)(num))
+#	endif
+#	ifndef conv16le
+#		define conv16le(num) byteswap16(num)
+#	endif
+#	ifndef conv32le
+#		define conv32le(num) byteswap32(num)
+#	endif
+#	ifndef conv64le
+#		define conv64le(num) byteswap64(num)
+#	endif
+#else
+#	ifndef conv16be
+#		define conv16be(num) byteswap16(num)
+#	endif
+#	ifndef conv32be
+#		define conv32be(num) byteswap32(num)
+#	endif
+#	ifndef conv64be
+#		define conv64be(num) byteswap64(num)
+#	endif
+#	ifndef conv16le
+#		define conv16le(num) ((uint16_t)(num))
+#	endif
+#	ifndef conv32le
+#		define conv32le(num) ((uint32_t)(num))
+#	endif
+#	ifndef conv64le
+#		define conv64le(num) ((uint64_t)(num))
+#	endif
+#endif
+
+
+////////////////////////////////
+// Unaligned reads and writes //
+////////////////////////////////
+
+// No-strict-align archs like x86-64
+// ---------------------------------
+//
+// The traditional way of casting e.g. *(const uint16_t *)uint8_pointer
+// is bad even if the uint8_pointer is properly aligned because this kind
+// of casts break strict aliasing rules and result in undefined behavior.
+// With unaligned pointers it's even worse: compilers may emit vector
+// instructions that require aligned pointers even if non-vector
+// instructions work with unaligned pointers.
+//
+// Using memcpy() is the standard compliant way to do unaligned access.
+// Many modern compilers inline it so there is no function call overhead.
+// For those compilers that don't handle the memcpy() method well, the
+// old casting method (that violates strict aliasing) can be requested at
+// build time. A third method, casting to a packed struct, would also be
+// an option but isn't provided to keep things simpler (it's already a mess).
+// Hopefully this is flexible enough in practice.
+//
+// Some compilers on x86-64 like Clang >= 10 and GCC >= 5.1 detect that
+//
+//     buf[0] | (buf[1] << 8)
+//
+// reads a 16-bit value and can emit a single 16-bit load and produce
+// identical code than with the memcpy() method. In other cases Clang and GCC
+// produce either the same or better code with memcpy(). For example, Clang 9
+// on x86-64 can detect 32-bit load but not 16-bit load.
+//
+// MSVC uses unaligned access with the memcpy() method but emits byte-by-byte
+// code for "buf[0] | (buf[1] << 8)".
+//
+// Conclusion: The memcpy() method is the best choice when unaligned access
+// is supported.
+//
+// Strict-align archs like SPARC
+// -----------------------------
+//
+// GCC versions from around 4.x to to at least 13.2.0 produce worse code
+// from the memcpy() method than from simple byte-by-byte shift-or code
+// when reading a 32-bit integer:
+//
+//     (1) It may be constructed on stack using four 8-bit loads,
+//         four 8-bit stores to stack, and finally one 32-bit load from stack.
+//
+//     (2) Especially with -Os, an actual memcpy() call may be emitted.
+//
+// This is true on at least on ARM, ARM64, SPARC, SPARC64, MIPS64EL, and
+// RISC-V. Of these, ARM, ARM64, and RISC-V support unaligned access in
+// some processors but not all so this is relevant only in the case when
+// GCC assumes that unaligned is not supported or -mstrict-align or
+// -mno-unaligned-access is used.
+//
+// For Clang it makes little difference. ARM64 with -O2 -mstrict-align
+// was one the very few with a minor difference: the memcpy() version
+// was one instruction longer.
+//
+// Conclusion: At least in case of GCC and Clang, byte-by-byte code is
+// the best choice for strict-align archs to do unaligned access.
+//
+// See also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111502
+//
+// Thanks to  it was easy to test different compilers.
+// The following is for little endian targets:
+/*
+#include 
+#include 
+
+uint32_t bytes16(const uint8_t *b)
+{
+    return (uint32_t)b[0]
+        | ((uint32_t)b[1] << 8);
+}
+
+uint32_t copy16(const uint8_t *b)
+{
+    uint16_t v;
+    memcpy(&v, b, sizeof(v));
+    return v;
+}
+
+uint32_t bytes32(const uint8_t *b)
+{
+    return (uint32_t)b[0]
+        | ((uint32_t)b[1] << 8)
+        | ((uint32_t)b[2] << 16)
+        | ((uint32_t)b[3] << 24);
+}
+
+uint32_t copy32(const uint8_t *b)
+{
+    uint32_t v;
+    memcpy(&v, b, sizeof(v));
+    return v;
+}
+
+void wbytes16(uint8_t *b, uint16_t v)
+{
+    b[0] = (uint8_t)v;
+    b[1] = (uint8_t)(v >> 8);
+}
+
+void wcopy16(uint8_t *b, uint16_t v)
+{
+    memcpy(b, &v, sizeof(v));
+}
+
+void wbytes32(uint8_t *b, uint32_t v)
+{
+    b[0] = (uint8_t)v;
+    b[1] = (uint8_t)(v >> 8);
+    b[2] = (uint8_t)(v >> 16);
+    b[3] = (uint8_t)(v >> 24);
+}
+
+void wcopy32(uint8_t *b, uint32_t v)
+{
+    memcpy(b, &v, sizeof(v));
+}
+*/
+
+
+#ifdef TUKLIB_FAST_UNALIGNED_ACCESS
+
+static inline uint16_t
+read16ne(const uint8_t *buf)
+{
+#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
+	return *(const uint16_t *)buf;
+#else
+	uint16_t num;
+	memcpy(&num, buf, sizeof(num));
+	return num;
+#endif
+}
+
+
+static inline uint32_t
+read32ne(const uint8_t *buf)
+{
+#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
+	return *(const uint32_t *)buf;
+#else
+	uint32_t num;
+	memcpy(&num, buf, sizeof(num));
+	return num;
+#endif
+}
+
+
+static inline uint64_t
+read64ne(const uint8_t *buf)
+{
+#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
+	return *(const uint64_t *)buf;
+#else
+	uint64_t num;
+	memcpy(&num, buf, sizeof(num));
+	return num;
+#endif
+}
+
+
+static inline void
+write16ne(uint8_t *buf, uint16_t num)
+{
+#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
+	*(uint16_t *)buf = num;
+#else
+	memcpy(buf, &num, sizeof(num));
+#endif
+	return;
+}
+
+
+static inline void
+write32ne(uint8_t *buf, uint32_t num)
+{
+#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
+	*(uint32_t *)buf = num;
+#else
+	memcpy(buf, &num, sizeof(num));
+#endif
+	return;
+}
+
+
+static inline void
+write64ne(uint8_t *buf, uint64_t num)
+{
+#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
+	*(uint64_t *)buf = num;
+#else
+	memcpy(buf, &num, sizeof(num));
+#endif
+	return;
+}
+
+
+static inline uint16_t
+read16be(const uint8_t *buf)
+{
+	uint16_t num = read16ne(buf);
+	return conv16be(num);
+}
+
+
+static inline uint16_t
+read16le(const uint8_t *buf)
+{
+	uint16_t num = read16ne(buf);
+	return conv16le(num);
+}
+
+
+static inline uint32_t
+read32be(const uint8_t *buf)
+{
+	uint32_t num = read32ne(buf);
+	return conv32be(num);
+}
+
+
+static inline uint32_t
+read32le(const uint8_t *buf)
+{
+	uint32_t num = read32ne(buf);
+	return conv32le(num);
+}
+
+
+static inline uint64_t
+read64be(const uint8_t *buf)
+{
+	uint64_t num = read64ne(buf);
+	return conv64be(num);
+}
+
+
+static inline uint64_t
+read64le(const uint8_t *buf)
+{
+	uint64_t num = read64ne(buf);
+	return conv64le(num);
+}
+
+
+// NOTE: Possible byte swapping must be done in a macro to allow the compiler
+// to optimize byte swapping of constants when using glibc's or *BSD's
+// byte swapping macros. The actual write is done in an inline function
+// to make type checking of the buf pointer possible.
+#define write16be(buf, num) write16ne(buf, conv16be(num))
+#define write32be(buf, num) write32ne(buf, conv32be(num))
+#define write64be(buf, num) write64ne(buf, conv64be(num))
+#define write16le(buf, num) write16ne(buf, conv16le(num))
+#define write32le(buf, num) write32ne(buf, conv32le(num))
+#define write64le(buf, num) write64ne(buf, conv64le(num))
+
+#else
+
+#ifdef WORDS_BIGENDIAN
+#	define read16ne read16be
+#	define read32ne read32be
+#	define read64ne read64be
+#	define write16ne write16be
+#	define write32ne write32be
+#	define write64ne write64be
+#else
+#	define read16ne read16le
+#	define read32ne read32le
+#	define read64ne read64le
+#	define write16ne write16le
+#	define write32ne write32le
+#	define write64ne write64le
+#endif
+
+
+static inline uint16_t
+read16be(const uint8_t *buf)
+{
+	uint16_t num = ((uint16_t)buf[0] << 8) | (uint16_t)buf[1];
+	return num;
+}
+
+
+static inline uint16_t
+read16le(const uint8_t *buf)
+{
+	uint16_t num = ((uint16_t)buf[0]) | ((uint16_t)buf[1] << 8);
+	return num;
+}
+
+
+static inline uint32_t
+read32be(const uint8_t *buf)
+{
+	uint32_t num = (uint32_t)buf[0] << 24;
+	num |= (uint32_t)buf[1] << 16;
+	num |= (uint32_t)buf[2] << 8;
+	num |= (uint32_t)buf[3];
+	return num;
+}
+
+
+static inline uint32_t
+read32le(const uint8_t *buf)
+{
+	uint32_t num = (uint32_t)buf[0];
+	num |= (uint32_t)buf[1] << 8;
+	num |= (uint32_t)buf[2] << 16;
+	num |= (uint32_t)buf[3] << 24;
+	return num;
+}
+
+
+static inline uint64_t
+read64be(const uint8_t *buf)
+{
+	uint64_t num = (uint64_t)buf[0] << 56;
+	num |= (uint64_t)buf[1] << 48;
+	num |= (uint64_t)buf[2] << 40;
+	num |= (uint64_t)buf[3] << 32;
+	num |= (uint64_t)buf[4] << 24;
+	num |= (uint64_t)buf[5] << 16;
+	num |= (uint64_t)buf[6] << 8;
+	num |= (uint64_t)buf[7];
+	return num;
+}
+
+
+static inline uint64_t
+read64le(const uint8_t *buf)
+{
+	uint64_t num = (uint64_t)buf[0];
+	num |= (uint64_t)buf[1] << 8;
+	num |= (uint64_t)buf[2] << 16;
+	num |= (uint64_t)buf[3] << 24;
+	num |= (uint64_t)buf[4] << 32;
+	num |= (uint64_t)buf[5] << 40;
+	num |= (uint64_t)buf[6] << 48;
+	num |= (uint64_t)buf[7] << 56;
+	return num;
+}
+
+
+static inline void
+write16be(uint8_t *buf, uint16_t num)
+{
+	buf[0] = (uint8_t)(num >> 8);
+	buf[1] = (uint8_t)num;
+	return;
+}
+
+
+static inline void
+write16le(uint8_t *buf, uint16_t num)
+{
+	buf[0] = (uint8_t)num;
+	buf[1] = (uint8_t)(num >> 8);
+	return;
+}
+
+
+static inline void
+write32be(uint8_t *buf, uint32_t num)
+{
+	buf[0] = (uint8_t)(num >> 24);
+	buf[1] = (uint8_t)(num >> 16);
+	buf[2] = (uint8_t)(num >> 8);
+	buf[3] = (uint8_t)num;
+	return;
+}
+
+
+static inline void
+write32le(uint8_t *buf, uint32_t num)
+{
+	buf[0] = (uint8_t)num;
+	buf[1] = (uint8_t)(num >> 8);
+	buf[2] = (uint8_t)(num >> 16);
+	buf[3] = (uint8_t)(num >> 24);
+	return;
+}
+
+
+static inline void
+write64be(uint8_t *buf, uint64_t num)
+{
+	buf[0] = (uint8_t)(num >> 56);
+	buf[1] = (uint8_t)(num >> 48);
+	buf[2] = (uint8_t)(num >> 40);
+	buf[3] = (uint8_t)(num >> 32);
+	buf[4] = (uint8_t)(num >> 24);
+	buf[5] = (uint8_t)(num >> 16);
+	buf[6] = (uint8_t)(num >> 8);
+	buf[7] = (uint8_t)num;
+	return;
+}
+
+
+static inline void
+write64le(uint8_t *buf, uint64_t num)
+{
+	buf[0] = (uint8_t)num;
+	buf[1] = (uint8_t)(num >> 8);
+	buf[2] = (uint8_t)(num >> 16);
+	buf[3] = (uint8_t)(num >> 24);
+	buf[4] = (uint8_t)(num >> 32);
+	buf[5] = (uint8_t)(num >> 40);
+	buf[6] = (uint8_t)(num >> 48);
+	buf[7] = (uint8_t)(num >> 56);
+	return;
+}
+
+#endif
+
+
+//////////////////////////////
+// Aligned reads and writes //
+//////////////////////////////
+
+// Separate functions for aligned reads and writes are provided since on
+// strict-align archs aligned access is much faster than unaligned access.
+//
+// Just like in the unaligned case, memcpy() is needed to avoid
+// strict aliasing violations. However, on archs that don't support
+// unaligned access the compiler cannot know that the pointers given
+// to memcpy() are aligned which results in slow code. As of C11 there is
+// no standard way to tell the compiler that we know that the address is
+// aligned but some compilers have language extensions to do that. With
+// such language extensions the memcpy() method gives excellent results.
+//
+// What to do on a strict-align system when no known language extensions
+// are available? Falling back to byte-by-byte access would be safe but ruin
+// optimizations that have been made specifically with aligned access in mind.
+// As a compromise, aligned reads will fall back to non-compliant type punning
+// but aligned writes will be byte-by-byte, that is, fast reads are preferred
+// over fast writes. This obviously isn't great but hopefully it's a working
+// compromise for now.
+//
+// __builtin_assume_aligned is support by GCC >= 4.7 and clang >= 3.6.
+#ifdef HAVE___BUILTIN_ASSUME_ALIGNED
+#	define tuklib_memcpy_aligned(dest, src, size) \
+		memcpy(dest, __builtin_assume_aligned(src, size), size)
+#else
+#	define tuklib_memcpy_aligned(dest, src, size) \
+		memcpy(dest, src, size)
+#	ifndef TUKLIB_FAST_UNALIGNED_ACCESS
+#		define TUKLIB_USE_UNSAFE_ALIGNED_READS 1
+#	endif
+#endif
+
+
+static inline uint16_t
+aligned_read16ne(const uint8_t *buf)
+{
+#if defined(TUKLIB_USE_UNSAFE_TYPE_PUNNING) \
+		|| defined(TUKLIB_USE_UNSAFE_ALIGNED_READS)
+	return *(const uint16_t *)buf;
+#else
+	uint16_t num;
+	tuklib_memcpy_aligned(&num, buf, sizeof(num));
+	return num;
+#endif
+}
+
+
+static inline uint32_t
+aligned_read32ne(const uint8_t *buf)
+{
+#if defined(TUKLIB_USE_UNSAFE_TYPE_PUNNING) \
+		|| defined(TUKLIB_USE_UNSAFE_ALIGNED_READS)
+	return *(const uint32_t *)buf;
+#else
+	uint32_t num;
+	tuklib_memcpy_aligned(&num, buf, sizeof(num));
+	return num;
+#endif
+}
+
+
+static inline uint64_t
+aligned_read64ne(const uint8_t *buf)
+{
+#if defined(TUKLIB_USE_UNSAFE_TYPE_PUNNING) \
+		|| defined(TUKLIB_USE_UNSAFE_ALIGNED_READS)
+	return *(const uint64_t *)buf;
+#else
+	uint64_t num;
+	tuklib_memcpy_aligned(&num, buf, sizeof(num));
+	return num;
+#endif
+}
+
+
+static inline void
+aligned_write16ne(uint8_t *buf, uint16_t num)
+{
+#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
+	*(uint16_t *)buf = num;
+#else
+	tuklib_memcpy_aligned(buf, &num, sizeof(num));
+#endif
+	return;
+}
+
+
+static inline void
+aligned_write32ne(uint8_t *buf, uint32_t num)
+{
+#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
+	*(uint32_t *)buf = num;
+#else
+	tuklib_memcpy_aligned(buf, &num, sizeof(num));
+#endif
+	return;
+}
+
+
+static inline void
+aligned_write64ne(uint8_t *buf, uint64_t num)
+{
+#ifdef TUKLIB_USE_UNSAFE_TYPE_PUNNING
+	*(uint64_t *)buf = num;
+#else
+	tuklib_memcpy_aligned(buf, &num, sizeof(num));
+#endif
+	return;
+}
+
+
+static inline uint16_t
+aligned_read16be(const uint8_t *buf)
+{
+	uint16_t num = aligned_read16ne(buf);
+	return conv16be(num);
+}
+
+
+static inline uint16_t
+aligned_read16le(const uint8_t *buf)
+{
+	uint16_t num = aligned_read16ne(buf);
+	return conv16le(num);
+}
+
+
+static inline uint32_t
+aligned_read32be(const uint8_t *buf)
+{
+	uint32_t num = aligned_read32ne(buf);
+	return conv32be(num);
+}
+
+
+static inline uint32_t
+aligned_read32le(const uint8_t *buf)
+{
+	uint32_t num = aligned_read32ne(buf);
+	return conv32le(num);
+}
+
+
+static inline uint64_t
+aligned_read64be(const uint8_t *buf)
+{
+	uint64_t num = aligned_read64ne(buf);
+	return conv64be(num);
+}
+
+
+static inline uint64_t
+aligned_read64le(const uint8_t *buf)
+{
+	uint64_t num = aligned_read64ne(buf);
+	return conv64le(num);
+}
+
+
+// These need to be macros like in the unaligned case.
+#define aligned_write16be(buf, num) aligned_write16ne((buf), conv16be(num))
+#define aligned_write16le(buf, num) aligned_write16ne((buf), conv16le(num))
+#define aligned_write32be(buf, num) aligned_write32ne((buf), conv32be(num))
+#define aligned_write32le(buf, num) aligned_write32ne((buf), conv32le(num))
+#define aligned_write64be(buf, num) aligned_write64ne((buf), conv64be(num))
+#define aligned_write64le(buf, num) aligned_write64ne((buf), conv64le(num))
+
+
+////////////////////
+// Bit operations //
+////////////////////
+
+static inline uint32_t
+bsr32(uint32_t n)
+{
+	// Check for ICC first, since it tends to define __GNUC__ too.
+#if defined(__INTEL_COMPILER)
+	return _bit_scan_reverse(n);
+
+#elif (TUKLIB_GNUC_REQ(3, 4) || defined(__clang__)) && UINT_MAX == UINT32_MAX
+	// GCC >= 3.4 has __builtin_clz(), which gives good results on
+	// multiple architectures. On x86, __builtin_clz() ^ 31U becomes
+	// either plain BSR (so the XOR gets optimized away) or LZCNT and
+	// XOR (if -march indicates that SSE4a instructions are supported).
+	return (uint32_t)__builtin_clz(n) ^ 31U;
+
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+	uint32_t i;
+	__asm__("bsrl %1, %0" : "=r" (i) : "rm" (n));
+	return i;
+
+#elif defined(_MSC_VER)
+	unsigned long i;
+	_BitScanReverse(&i, n);
+	return i;
+
+#else
+	uint32_t i = 31;
+
+	if ((n & 0xFFFF0000) == 0) {
+		n <<= 16;
+		i = 15;
+	}
+
+	if ((n & 0xFF000000) == 0) {
+		n <<= 8;
+		i -= 8;
+	}
+
+	if ((n & 0xF0000000) == 0) {
+		n <<= 4;
+		i -= 4;
+	}
+
+	if ((n & 0xC0000000) == 0) {
+		n <<= 2;
+		i -= 2;
+	}
+
+	if ((n & 0x80000000) == 0)
+		--i;
+
+	return i;
+#endif
+}
+
+
+static inline uint32_t
+clz32(uint32_t n)
+{
+#if defined(__INTEL_COMPILER)
+	return _bit_scan_reverse(n) ^ 31U;
+
+#elif (TUKLIB_GNUC_REQ(3, 4) || defined(__clang__)) && UINT_MAX == UINT32_MAX
+	return (uint32_t)__builtin_clz(n);
+
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+	uint32_t i;
+	__asm__("bsrl %1, %0\n\t"
+		"xorl $31, %0"
+		: "=r" (i) : "rm" (n));
+	return i;
+
+#elif defined(_MSC_VER)
+	unsigned long i;
+	_BitScanReverse(&i, n);
+	return i ^ 31U;
+
+#else
+	uint32_t i = 0;
+
+	if ((n & 0xFFFF0000) == 0) {
+		n <<= 16;
+		i = 16;
+	}
+
+	if ((n & 0xFF000000) == 0) {
+		n <<= 8;
+		i += 8;
+	}
+
+	if ((n & 0xF0000000) == 0) {
+		n <<= 4;
+		i += 4;
+	}
+
+	if ((n & 0xC0000000) == 0) {
+		n <<= 2;
+		i += 2;
+	}
+
+	if ((n & 0x80000000) == 0)
+		++i;
+
+	return i;
+#endif
+}
+
+
+static inline uint32_t
+ctz32(uint32_t n)
+{
+#if defined(__INTEL_COMPILER)
+	return _bit_scan_forward(n);
+
+#elif (TUKLIB_GNUC_REQ(3, 4) || defined(__clang__)) && UINT_MAX >= UINT32_MAX
+	return (uint32_t)__builtin_ctz(n);
+
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+	uint32_t i;
+	__asm__("bsfl %1, %0" : "=r" (i) : "rm" (n));
+	return i;
+
+#elif defined(_MSC_VER)
+	unsigned long i;
+	_BitScanForward(&i, n);
+	return i;
+
+#else
+	uint32_t i = 0;
+
+	if ((n & 0x0000FFFF) == 0) {
+		n >>= 16;
+		i = 16;
+	}
+
+	if ((n & 0x000000FF) == 0) {
+		n >>= 8;
+		i += 8;
+	}
+
+	if ((n & 0x0000000F) == 0) {
+		n >>= 4;
+		i += 4;
+	}
+
+	if ((n & 0x00000003) == 0) {
+		n >>= 2;
+		i += 2;
+	}
+
+	if ((n & 0x00000001) == 0)
+		++i;
+
+	return i;
+#endif
+}
+
+#define bsf32 ctz32
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr.h
new file mode 100644
index 00000000000..4c8eeb7e370
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr.h
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_mbstr.h
+/// \brief      Utility functions for handling multibyte strings
+///
+/// If not enough multibyte string support is available in the C library,
+/// these functions keep working with the assumption that all strings
+/// are in a single-byte character set without combining characters, e.g.
+/// US-ASCII or ISO-8859-*.
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TUKLIB_MBSTR_H
+#define TUKLIB_MBSTR_H
+
+#include "tuklib_common.h"
+TUKLIB_DECLS_BEGIN
+
+#define tuklib_mbstr_width TUKLIB_SYMBOL(tuklib_mbstr_width)
+extern size_t tuklib_mbstr_width(const char *str, size_t *bytes);
+///<
+/// \brief      Get the number of columns needed for the multibyte string
+///
+/// This is somewhat similar to wcswidth() but works on multibyte strings.
+///
+/// \param      str         String whose width is to be calculated. If the
+///                         current locale uses a multibyte character set
+///                         that has shift states, the string must begin
+///                         and end in the initial shift state.
+/// \param      bytes       If this is not NULL, *bytes is set to the
+///                         value returned by strlen(str) (even if an
+///                         error occurs when calculating the width).
+///
+/// \return     On success, the number of columns needed to display the
+///             string e.g. in a terminal emulator is returned. On error,
+///             (size_t)-1 is returned. Possible errors include invalid,
+///             partial, or non-printable multibyte character in str, or
+///             that str doesn't end in the initial shift state.
+
+#define tuklib_mbstr_fw TUKLIB_SYMBOL(tuklib_mbstr_fw)
+extern int tuklib_mbstr_fw(const char *str, int columns_min);
+///<
+/// \brief      Get the field width for printf() e.g. to align table columns
+///
+/// Printing simple tables to a terminal can be done using the field field
+/// feature in the printf() format string, but it works only with single-byte
+/// character sets. To do the same with multibyte strings, tuklib_mbstr_fw()
+/// can be used to calculate appropriate field width.
+///
+/// The behavior of this function is undefined, if
+///   - str is NULL or not terminated with '\0';
+///   - columns_min <= 0; or
+///   - the calculated field width exceeds INT_MAX.
+///
+/// \return     If tuklib_mbstr_width(str, NULL) fails, -1 is returned.
+///             If str needs more columns than columns_min, zero is returned.
+///             Otherwise a positive integer is returned, which can be
+///             used as the field width, e.g. printf("%*s", fw, str).
+
+TUKLIB_DECLS_END
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_fw.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_fw.c
new file mode 100644
index 00000000000..22d883b569f
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_fw.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_mbstr_fw.c
+/// \brief      Get the field width for printf() e.g. to align table columns
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tuklib_mbstr.h"
+
+
+extern int
+tuklib_mbstr_fw(const char *str, int columns_min)
+{
+	size_t len;
+	const size_t width = tuklib_mbstr_width(str, &len);
+	if (width == (size_t)-1)
+		return -1;
+
+	if (width > (size_t)columns_min)
+		return 0;
+
+	if (width < (size_t)columns_min)
+		len += (size_t)columns_min - width;
+
+	return (int)len;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_width.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_width.c
new file mode 100644
index 00000000000..7a8bf070751
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_mbstr_width.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_mbstr_width.c
+/// \brief      Calculate width of a multibyte string
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tuklib_mbstr.h"
+#include 
+
+#if defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
+#	include 
+#endif
+
+
+extern size_t
+tuklib_mbstr_width(const char *str, size_t *bytes)
+{
+	const size_t len = strlen(str);
+	if (bytes != NULL)
+		*bytes = len;
+
+#if !(defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH))
+	// In single-byte mode, the width of the string is the same
+	// as its length.
+	return len;
+
+#else
+	mbstate_t state;
+	memset(&state, 0, sizeof(state));
+
+	size_t width = 0;
+	size_t i = 0;
+
+	// Convert one multibyte character at a time to wchar_t
+	// and get its width using wcwidth().
+	while (i < len) {
+		wchar_t wc;
+		const size_t ret = mbrtowc(&wc, str + i, len - i, &state);
+		if (ret < 1 || ret > len)
+			return (size_t)-1;
+
+		i += ret;
+
+		const int wc_width = wcwidth(wc);
+		if (wc_width < 0)
+			return (size_t)-1;
+
+		width += (size_t)wc_width;
+	}
+
+	// Require that the string ends in the initial shift state.
+	// This way the caller can be combine the string with other
+	// strings without needing to worry about the shift states.
+	if (!mbsinit(&state))
+		return (size_t)-1;
+
+	return width;
+#endif
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.c
new file mode 100644
index 00000000000..b93e61d3b68
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_open_stdxxx.c
+/// \brief      Make sure that file descriptors 0, 1, and 2 are open
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tuklib_open_stdxxx.h"
+
+#ifndef TUKLIB_DOSLIKE
+#	include 
+#	include 
+#	include 
+#	include 
+#endif
+
+
+extern void
+tuklib_open_stdxxx(int err_status)
+{
+#ifdef TUKLIB_DOSLIKE
+	// Do nothing, just silence warnings.
+	(void)err_status;
+
+#else
+	for (int i = 0; i <= 2; ++i) {
+		// We use fcntl() to check if the file descriptor is open.
+		if (fcntl(i, F_GETFD) == -1 && errno == EBADF) {
+			// With stdin, we could use /dev/full so that
+			// writing to stdin would fail. However, /dev/full
+			// is Linux specific, and if the program tries to
+			// write to stdin, there's already a problem anyway.
+			const int fd = open("/dev/null", O_NOCTTY
+					| (i == 0 ? O_WRONLY : O_RDONLY));
+
+			if (fd != i) {
+				if (fd != -1)
+					(void)close(fd);
+
+				// Something went wrong. Exit with the
+				// exit status we were given. Don't try
+				// to print an error message, since stderr
+				// may very well be non-existent. This
+				// error should be extremely rare.
+				exit(err_status);
+			}
+		}
+	}
+#endif
+
+	return;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.h
new file mode 100644
index 00000000000..3ee3ade3552
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_open_stdxxx.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_open_stdxxx.h
+/// \brief      Make sure that file descriptors 0, 1, and 2 are open
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TUKLIB_OPEN_STDXXX_H
+#define TUKLIB_OPEN_STDXXX_H
+
+#include "tuklib_common.h"
+TUKLIB_DECLS_BEGIN
+
+#define tuklib_open_stdxx TUKLIB_SYMBOL(tuklib_open_stdxxx)
+extern void tuklib_open_stdxxx(int err_status);
+
+TUKLIB_DECLS_END
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.c
new file mode 100644
index 00000000000..1009df14d9d
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_physmem.c
+/// \brief      Get the amount of physical memory
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tuklib_physmem.h"
+
+// We want to use Windows-specific code on Cygwin, which also has memory
+// information available via sysconf(), but on Cygwin 1.5 and older it
+// gives wrong results (from our point of view).
+#if defined(_WIN32) || defined(__CYGWIN__)
+#	ifndef _WIN32_WINNT
+#		define _WIN32_WINNT 0x0500
+#	endif
+#	include 
+
+#elif defined(__OS2__)
+#	define INCL_DOSMISC
+#	include 
+
+#elif defined(__DJGPP__)
+#	include 
+
+#elif defined(__VMS)
+#	include 
+#	include 
+#	include 
+
+#elif defined(AMIGA) || defined(__AROS__)
+#	define __USE_INLINE__
+#	include 
+
+#elif defined(__QNX__)
+#	include 
+#	include 
+
+#elif defined(TUKLIB_PHYSMEM_AIX)
+#	include 
+
+#elif defined(TUKLIB_PHYSMEM_SYSCONF)
+#	include 
+
+#elif defined(TUKLIB_PHYSMEM_SYSCTL)
+#	ifdef HAVE_SYS_PARAM_H
+#		include 
+#	endif
+#	include 
+
+// Tru64
+#elif defined(TUKLIB_PHYSMEM_GETSYSINFO)
+#	include 
+#	include 
+
+// HP-UX
+#elif defined(TUKLIB_PHYSMEM_PSTAT_GETSTATIC)
+#	include 
+#	include 
+
+// IRIX
+#elif defined(TUKLIB_PHYSMEM_GETINVENT_R)
+#	include 
+
+// This sysinfo() is Linux-specific.
+#elif defined(TUKLIB_PHYSMEM_SYSINFO)
+#	include 
+#endif
+
+
+extern uint64_t
+tuklib_physmem(void)
+{
+	uint64_t ret = 0;
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+	// This requires Windows 2000 or later.
+	MEMORYSTATUSEX meminfo;
+	meminfo.dwLength = sizeof(meminfo);
+	if (GlobalMemoryStatusEx(&meminfo))
+		ret = meminfo.ullTotalPhys;
+
+/*
+	// Old version that is compatible with even Win95:
+	if ((GetVersion() & 0xFF) >= 5) {
+		// Windows 2000 and later have GlobalMemoryStatusEx() which
+		// supports reporting values greater than 4 GiB. To keep the
+		// code working also on older Windows versions, use
+		// GlobalMemoryStatusEx() conditionally.
+		HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
+		if (kernel32 != NULL) {
+			typedef BOOL (WINAPI *gmse_type)(LPMEMORYSTATUSEX);
+#ifdef CAN_DISABLE_WCAST_FUNCTION_TYPE
+#	pragma GCC diagnostic push
+#	pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+			gmse_type gmse = (gmse_type)GetProcAddress(
+					kernel32, "GlobalMemoryStatusEx");
+#ifdef CAN_DISABLE_WCAST_FUNCTION_TYPE
+#	pragma GCC diagnostic pop
+#endif
+			if (gmse != NULL) {
+				MEMORYSTATUSEX meminfo;
+				meminfo.dwLength = sizeof(meminfo);
+				if (gmse(&meminfo))
+					ret = meminfo.ullTotalPhys;
+			}
+		}
+	}
+
+	if (ret == 0) {
+		// GlobalMemoryStatus() is supported by Windows 95 and later,
+		// so it is fine to link against it unconditionally. Note that
+		// GlobalMemoryStatus() has no return value.
+		MEMORYSTATUS meminfo;
+		meminfo.dwLength = sizeof(meminfo);
+		GlobalMemoryStatus(&meminfo);
+		ret = meminfo.dwTotalPhys;
+	}
+*/
+
+#elif defined(__OS2__)
+	unsigned long mem;
+	if (DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM,
+			&mem, sizeof(mem)) == 0)
+		ret = mem;
+
+#elif defined(__DJGPP__)
+	__dpmi_free_mem_info meminfo;
+	if (__dpmi_get_free_memory_information(&meminfo) == 0
+			&& meminfo.total_number_of_physical_pages
+				!= (unsigned long)-1)
+		ret = (uint64_t)meminfo.total_number_of_physical_pages * 4096;
+
+#elif defined(__VMS)
+	int vms_mem;
+	int val = SYI$_MEMSIZE;
+	if (LIB$GETSYI(&val, &vms_mem, 0, 0, 0, 0) == SS$_NORMAL)
+		ret = (uint64_t)vms_mem * 8192;
+
+#elif defined(AMIGA) || defined(__AROS__)
+	ret = AvailMem(MEMF_TOTAL);
+
+#elif defined(__QNX__)
+	const struct asinfo_entry *entries = SYSPAGE_ENTRY(asinfo);
+	size_t count = SYSPAGE_ENTRY_SIZE(asinfo) / sizeof(struct asinfo_entry);
+	const char *strings = SYSPAGE_ENTRY(strings)->data;
+
+	for (size_t i = 0; i < count; ++i)
+		if (strcmp(strings + entries[i].name, "ram") == 0)
+			ret += entries[i].end - entries[i].start + 1;
+
+#elif defined(TUKLIB_PHYSMEM_AIX)
+	ret = _system_configuration.physmem;
+
+#elif defined(TUKLIB_PHYSMEM_SYSCONF)
+	const long pagesize = sysconf(_SC_PAGESIZE);
+	const long pages = sysconf(_SC_PHYS_PAGES);
+	if (pagesize != -1 && pages != -1)
+		// According to docs, pagesize * pages can overflow.
+		// Simple case is 32-bit box with 4 GiB or more RAM,
+		// which may report exactly 4 GiB of RAM, and "long"
+		// being 32-bit will overflow. Casting to uint64_t
+		// hopefully avoids overflows in the near future.
+		ret = (uint64_t)pagesize * (uint64_t)pages;
+
+#elif defined(TUKLIB_PHYSMEM_SYSCTL)
+	int name[2] = {
+		CTL_HW,
+#ifdef HW_PHYSMEM64
+		HW_PHYSMEM64
+#else
+		HW_PHYSMEM
+#endif
+	};
+	union {
+		uint32_t u32;
+		uint64_t u64;
+	} mem;
+	size_t mem_ptr_size = sizeof(mem.u64);
+	if (sysctl(name, 2, &mem.u64, &mem_ptr_size, NULL, 0) != -1) {
+		// IIRC, 64-bit "return value" is possible on some 64-bit
+		// BSD systems even with HW_PHYSMEM (instead of HW_PHYSMEM64),
+		// so support both.
+		if (mem_ptr_size == sizeof(mem.u64))
+			ret = mem.u64;
+		else if (mem_ptr_size == sizeof(mem.u32))
+			ret = mem.u32;
+	}
+
+#elif defined(TUKLIB_PHYSMEM_GETSYSINFO)
+	// Docs are unclear if "start" is needed, but it doesn't hurt
+	// much to have it.
+	int memkb;
+	int start = 0;
+	if (getsysinfo(GSI_PHYSMEM, (caddr_t)&memkb, sizeof(memkb), &start)
+			!= -1)
+		ret = (uint64_t)memkb * 1024;
+
+#elif defined(TUKLIB_PHYSMEM_PSTAT_GETSTATIC)
+	struct pst_static pst;
+	if (pstat_getstatic(&pst, sizeof(pst), 1, 0) != -1)
+		ret = (uint64_t)pst.physical_memory * (uint64_t)pst.page_size;
+
+#elif defined(TUKLIB_PHYSMEM_GETINVENT_R)
+	inv_state_t *st = NULL;
+	if (setinvent_r(&st) != -1) {
+		inventory_t *i;
+		while ((i = getinvent_r(st)) != NULL) {
+			if (i->inv_class == INV_MEMORY
+					&& i->inv_type == INV_MAIN_MB) {
+				ret = (uint64_t)i->inv_state << 20;
+				break;
+			}
+		}
+
+		endinvent_r(st);
+	}
+
+#elif defined(TUKLIB_PHYSMEM_SYSINFO)
+	struct sysinfo si;
+	if (sysinfo(&si) == 0)
+		ret = (uint64_t)si.totalram * si.mem_unit;
+#endif
+
+	return ret;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.h
new file mode 100644
index 00000000000..f35bfbab9c1
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_physmem.h
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_physmem.h
+/// \brief      Get the amount of physical memory
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TUKLIB_PHYSMEM_H
+#define TUKLIB_PHYSMEM_H
+
+#include "tuklib_common.h"
+TUKLIB_DECLS_BEGIN
+
+#define tuklib_physmem TUKLIB_SYMBOL(tuklib_physmem)
+extern uint64_t tuklib_physmem(void);
+///<
+/// \brief      Get the amount of physical memory in bytes
+///
+/// \return     Amount of physical memory in bytes. On error, zero is
+///             returned.
+
+TUKLIB_DECLS_END
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.c
new file mode 100644
index 00000000000..959c1270ce3
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_progname.c
+/// \brief      Program name to be displayed in messages
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tuklib_progname.h"
+#include 
+
+
+#ifndef HAVE_PROGRAM_INVOCATION_NAME
+char *progname = NULL;
+#endif
+
+
+extern void
+tuklib_progname_init(char **argv)
+{
+#ifdef TUKLIB_DOSLIKE
+	// On these systems, argv[0] always has the full path and .exe
+	// suffix even if the user just types the plain program name.
+	// We modify argv[0] to make it nicer to read.
+
+	// Strip the leading path.
+	char *p = argv[0] + strlen(argv[0]);
+	while (argv[0] < p && p[-1] != '/' && p[-1] != '\\')
+		--p;
+
+	argv[0] = p;
+
+	// Strip the .exe suffix.
+	p = strrchr(p, '.');
+	if (p != NULL)
+		*p = '\0';
+
+	// Make it lowercase.
+	for (p = argv[0]; *p != '\0'; ++p)
+		if (*p >= 'A' && *p <= 'Z')
+			*p = *p - 'A' + 'a';
+#endif
+
+	progname = argv[0];
+	return;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.h
new file mode 100644
index 00000000000..a3d90cb1f21
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/tuklib_progname.h
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       tuklib_progname.h
+/// \brief      Program name to be displayed in messages
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TUKLIB_PROGNAME_H
+#define TUKLIB_PROGNAME_H
+
+#include "tuklib_common.h"
+#include 
+
+TUKLIB_DECLS_BEGIN
+
+#ifdef HAVE_PROGRAM_INVOCATION_NAME
+#	define progname program_invocation_name
+#else
+#	define progname TUKLIB_SYMBOL(tuklib_progname)
+	extern char *progname;
+#endif
+
+#define tuklib_progname_init TUKLIB_SYMBOL(tuklib_progname_init)
+extern void tuklib_progname_init(char **argv);
+
+TUKLIB_DECLS_END
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest
new file mode 100644
index 00000000000..2f8750879b1
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest
@@ -0,0 +1,28 @@
+
+
+
+    
+        
+             
+             
+             
+             
+             
+        
+    
+
+    
+        
+            
+                
+            
+        
+    
+
+    
+        
+            true
+            UTF-8
+        
+    
+
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest.comments.txt b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest.comments.txt
new file mode 100644
index 00000000000..ad0835ccb0b
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/common/w32_application.manifest.comments.txt
@@ -0,0 +1,178 @@
+
+Windows application manifest for UTF-8 and long paths
+=====================================================
+
+The .manifest file is embedded as is in the executables, thus
+the comments are here in a separate file. These comments were
+written in context of XZ Utils but might be useful when porting
+other command line tools from POSIX environments to Windows.
+
+    NOTE: On Cygwin and MSYS2, command line arguments and file
+    system access aren't tied to a Windows code page. Cygwin
+    and MSYS2 include a default application manifest. Replacing
+    it doesn't seem useful and might even be harmful if Cygwin
+    and MSYS2 some day change their default manifest.
+
+
+UTF-8 code page
+---------------
+
+On Windows, command line applications can use main() or wmain().
+With the Windows-specific wmain(), argv contains UTF-16 code units
+which is the native encoding on Windows. With main(), argv uses the
+system active code page by default. It typically is a legacy code
+page like Windows-1252.
+
+    NOTE: On POSIX, argv for main() is constructed by the calling
+    process. On Windows, argv is constructed by a new process
+    itself: a program receives the command line as a single string,
+    and the startup code splits it into individual arguments,
+    including quote removal and wildcard expansion. Then main() or
+    wmain() is called.
+
+This application manifest forces the process code page to UTF-8
+when the application runs on Windows 10 version 1903 or later.
+This is useful for programs that use main():
+
+  * UTF-8 allows such programs to access files whose names contain
+    characters that don't exist in the current legacy code page.
+    However, filenames on Windows may contain unpaired surrogates
+    (invalid UTF-16). Such files cannot be accesses even with the
+    UTF-8 code page.
+
+  * UTF-8 avoids a security issue in command line argument handling:
+    If a command line contains Unicode characters (for example,
+    filenames) that don't exist in the current legacy code page,
+    the characters are converted to similar-looking characters
+    with best-fit mapping. Some best-fit mappings result in ASCII
+    characters that change the meaning of the command line, which
+    can be exploited with malicious filenames. For example:
+
+      - Double quote (") breaks quoting and makes argument
+        injection possible.
+
+      - Question mark (?) is a wildcard character which may
+        expand to one or more filenames.
+
+      - Forward slash (/) makes a directory traversal attack
+        possible. This character can appear in a dangerous way
+        even from a wildcard expansion; a look-alike character
+        doesn't need to be passed directly on the command line.
+
+    UTF-8 avoids best-fit mappings. However, it's still not
+    perfect. Unpaired surrogates (invalid UTF-16) on the command
+    line (including those from wildcard expansion) are converted
+    to the replacement character U+FFFD. Thus, filenames with
+    different unpaired surrogates appear identical when converted
+    to the UTF-8 code page and aren't distinguishable from
+    filenames that contain the actual replacement character U+FFFD.
+
+If different programs use different code pages, compatibility issues
+are possible. For example, if one program produces a list of
+filenames and another program reads it, both programs should use
+the same code page because the code page affects filenames in the
+char-based file system APIs.
+
+If building with a MinGW-w64 toolchain, it is strongly recommended
+to use UCRT instead of the old MSVCRT. For example, with the UTF-8
+code page, MSVCRT doesn't convert non-ASCII characters correctly
+when writing to console with printf(). With UCRT it works.
+
+
+Long path names
+---------------
+
+The manifest enables support for path names longer than 259
+characters if the feature has been enabled in the Windows registry.
+Omit the longPathAware element from the manifest if the application
+isn't compatible with it. For example, uses of MAX_PATH might be
+a sign of incompatibility.
+
+Documentation of the registry setting:
+https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry#enable-long-paths-in-windows-10-version-1607-and-later
+
+
+Summary of the manifest contents
+--------------------------------
+
+See also Microsoft's documentation:
+https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests
+
+assemblyIdentity (omitted)
+
+    This is documented as mandatory but not all apps in the real world
+    have it, and of those that do, not all put an up-to-date version
+    number there. Things seem to work correctly without
+     so let's keep this simpler and omit it.
+
+compatibility
+
+    Declare the application compatible with different Windows versions.
+    Without this, Windows versions newer than Vista will run the
+    application using Vista as the Operating System Context.
+
+trustInfo
+
+    Declare the application as UAC-compliant. This avoids file system
+    and registry virtualization that Windows otherwise does with 32-bit
+    executables to make some ancient applications work. UAC-compliancy
+    also stops Windows from using heuristics based on the filename
+    (like setup.exe) to guess when elevated privileges might be
+    needed which would then bring up the UAC prompt.
+
+longPathAware
+
+    Declare the application as long path aware. This way many file
+    system operations aren't limited by MAX_PATH (260 characters
+    including the terminating null character) if the feature has
+    also been enabled in the Windows registry.
+
+activeCodePage
+
+    Force the process code page to UTF-8 on Windows 10 version 1903
+    and later. For example:
+
+      - main() gets the command line arguments in UTF-8 instead of
+        in a legacy code page.
+
+      - File system APIs that take char-based strings use UTF-8
+        instead of a legacy code page.
+
+      - Text written to the console via stdio.h's stdout or stderr
+        (like calling printf()) are expected to be in UTF-8.
+
+
+CMake notes
+-----------
+
+As of CMake 3.30, one can add a .manifest file as a source file but
+it only works with MSVC; it's ignored with MinGW-w64 toolchains.
+Embedding the manifest with a resource file works with all
+toolchains. However, then the default manifest needs to be
+disabled with MSVC in CMakeLists.txt to avoid duplicate
+manifests which would break the build.
+
+w32_application.manifest.rc:
+
+    #include 
+    CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "w32_application.manifest"
+
+Or the same thing without the #include:
+
+    1 24 "w32_application.manifest"
+
+CMakeLists.txt:
+
+    if(MSVC)
+        set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO")
+    endif()
+
+    add_executable(foo foo.c)
+
+    # WIN32 isn't set on Cygwin or MSYS2, thus if(WIN32) is correct here.
+    if(WIN32)
+        target_sources(foo PRIVATE w32_application.manifest.rc)
+        set_source_files_properties(w32_application.manifest.rc PROPERTIES
+            OBJECT_DEPENDS w32_application.manifest
+        )
+    endif()
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma.h
new file mode 100644
index 00000000000..6ca6e503d8a
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma.h
@@ -0,0 +1,327 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/**
+ * \file        api/lzma.h
+ * \brief       The public API of liblzma data compression library
+ * \mainpage
+ *
+ * liblzma is a general-purpose data compression library with a zlib-like API.
+ * The native file format is .xz, but also the old .lzma format and raw (no
+ * headers) streams are supported. Multiple compression algorithms (filters)
+ * are supported. Currently LZMA2 is the primary filter.
+ *
+ * liblzma is part of XZ Utils . XZ Utils
+ * includes a gzip-like command line tool named xz and some other tools.
+ * XZ Utils is developed and maintained by Lasse Collin.
+ *
+ * Major parts of liblzma are based on code written by Igor Pavlov,
+ * specifically the LZMA SDK .
+ *
+ * The SHA-256 implementation in liblzma is based on code written by
+ * Wei Dai in Crypto++ Library .
+ *
+ * liblzma is distributed under the BSD Zero Clause License (0BSD).
+ */
+
+/*
+ * Author: Lasse Collin
+ */
+
+#ifndef LZMA_H
+#define LZMA_H
+
+/*****************************
+ * Required standard headers *
+ *****************************/
+
+/*
+ * liblzma API headers need some standard types and macros. To allow
+ * including lzma.h without requiring the application to include other
+ * headers first, lzma.h includes the required standard headers unless
+ * they already seem to be included already or if LZMA_MANUAL_HEADERS
+ * has been defined.
+ *
+ * Here's what types and macros are needed and from which headers:
+ *  - stddef.h: size_t, NULL
+ *  - stdint.h: uint8_t, uint32_t, uint64_t, UINT32_C(n), uint64_C(n),
+ *    UINT32_MAX, UINT64_MAX
+ *
+ * However, inttypes.h is a little more portable than stdint.h, although
+ * inttypes.h declares some unneeded things compared to plain stdint.h.
+ *
+ * The hacks below aren't perfect, specifically they assume that inttypes.h
+ * exists and that it typedefs at least uint8_t, uint32_t, and uint64_t,
+ * and that, in case of incomplete inttypes.h, unsigned int is 32-bit.
+ * If the application already takes care of setting up all the types and
+ * macros properly (for example by using gnulib's stdint.h or inttypes.h),
+ * we try to detect that the macros are already defined and don't include
+ * inttypes.h here again. However, you may define LZMA_MANUAL_HEADERS to
+ * force this file to never include any system headers.
+ *
+ * Some could argue that liblzma API should provide all the required types,
+ * for example lzma_uint64, LZMA_UINT64_C(n), and LZMA_UINT64_MAX. This was
+ * seen as an unnecessary mess, since most systems already provide all the
+ * necessary types and macros in the standard headers.
+ *
+ * Note that liblzma API still has lzma_bool, because using stdbool.h would
+ * break C89 and C++ programs on many systems. sizeof(bool) in C99 isn't
+ * necessarily the same as sizeof(bool) in C++.
+ */
+
+#ifndef LZMA_MANUAL_HEADERS
+	/*
+	 * I suppose this works portably also in C++. Note that in C++,
+	 * we need to get size_t into the global namespace.
+	 */
+#	include 
+
+	/*
+	 * Skip inttypes.h if we already have all the required macros. If we
+	 * have the macros, we assume that we have the matching typedefs too.
+	 */
+#	if !defined(UINT32_C) || !defined(UINT64_C) \
+			|| !defined(UINT32_MAX) || !defined(UINT64_MAX)
+		/*
+		 * MSVC versions older than 2013 have no C99 support, and
+		 * thus they cannot be used to compile liblzma. Using an
+		 * existing liblzma.dll with old MSVC can work though(*),
+		 * but we need to define the required standard integer
+		 * types here in a MSVC-specific way.
+		 *
+		 * (*) If you do this, the existing liblzma.dll probably uses
+		 *     a different runtime library than your MSVC-built
+		 *     application. Mixing runtimes is generally bad, but
+		 *     in this case it should work as long as you avoid
+		 *     the few rarely-needed liblzma functions that allocate
+		 *     memory and expect the caller to free it using free().
+		 */
+#		if defined(_WIN32) && defined(_MSC_VER) && _MSC_VER < 1800
+			typedef unsigned __int8 uint8_t;
+			typedef unsigned __int32 uint32_t;
+			typedef unsigned __int64 uint64_t;
+#		else
+			/* Use the standard inttypes.h. */
+#			ifdef __cplusplus
+				/*
+				 * C99 sections 7.18.2 and 7.18.4 specify
+				 * that C++ implementations define the limit
+				 * and constant macros only if specifically
+				 * requested. Note that if you want the
+				 * format macros (PRIu64 etc.) too, you need
+				 * to define __STDC_FORMAT_MACROS before
+				 * including lzma.h, since re-including
+				 * inttypes.h with __STDC_FORMAT_MACROS
+				 * defined doesn't necessarily work.
+				 */
+#				ifndef __STDC_LIMIT_MACROS
+#					define __STDC_LIMIT_MACROS 1
+#				endif
+#				ifndef __STDC_CONSTANT_MACROS
+#					define __STDC_CONSTANT_MACROS 1
+#				endif
+#			endif
+
+#			include 
+#		endif
+
+		/*
+		 * Some old systems have only the typedefs in inttypes.h, and
+		 * lack all the macros. For those systems, we need a few more
+		 * hacks. We assume that unsigned int is 32-bit and unsigned
+		 * long is either 32-bit or 64-bit. If these hacks aren't
+		 * enough, the application has to setup the types manually
+		 * before including lzma.h.
+		 */
+#		ifndef UINT32_C
+#			if defined(_WIN32) && defined(_MSC_VER)
+#				define UINT32_C(n) n ## UI32
+#			else
+#				define UINT32_C(n) n ## U
+#			endif
+#		endif
+
+#		ifndef UINT64_C
+#			if defined(_WIN32) && defined(_MSC_VER)
+#				define UINT64_C(n) n ## UI64
+#			else
+				/* Get ULONG_MAX. */
+#				include 
+#				if ULONG_MAX == 4294967295UL
+#					define UINT64_C(n) n ## ULL
+#				else
+#					define UINT64_C(n) n ## UL
+#				endif
+#			endif
+#		endif
+
+#		ifndef UINT32_MAX
+#			define UINT32_MAX (UINT32_C(4294967295))
+#		endif
+
+#		ifndef UINT64_MAX
+#			define UINT64_MAX (UINT64_C(18446744073709551615))
+#		endif
+#	endif
+#endif /* ifdef LZMA_MANUAL_HEADERS */
+
+
+/******************
+ * LZMA_API macro *
+ ******************/
+
+/*
+ * Some systems require that the functions and function pointers are
+ * declared specially in the headers. LZMA_API_IMPORT is for importing
+ * symbols and LZMA_API_CALL is to specify the calling convention.
+ *
+ * By default it is assumed that the application will link dynamically
+ * against liblzma. #define LZMA_API_STATIC in your application if you
+ * want to link against static liblzma. If you don't care about portability
+ * to operating systems like Windows, or at least don't care about linking
+ * against static liblzma on them, don't worry about LZMA_API_STATIC. That
+ * is, most developers will never need to use LZMA_API_STATIC.
+ *
+ * The GCC variants are a special case on Windows (Cygwin and MinGW-w64).
+ * We rely on GCC doing the right thing with its auto-import feature,
+ * and thus don't use __declspec(dllimport). This way developers don't
+ * need to worry about LZMA_API_STATIC. Also the calling convention is
+ * omitted on Cygwin but not on MinGW-w64.
+ */
+#ifndef LZMA_API_IMPORT
+#	if !defined(LZMA_API_STATIC) && defined(_WIN32) && !defined(__GNUC__)
+#		define LZMA_API_IMPORT __declspec(dllimport)
+#	else
+#		define LZMA_API_IMPORT
+#	endif
+#endif
+
+#ifndef LZMA_API_CALL
+#	if defined(_WIN32) && !defined(__CYGWIN__)
+#		define LZMA_API_CALL __cdecl
+#	else
+#		define LZMA_API_CALL
+#	endif
+#endif
+
+#ifndef LZMA_API
+#	define LZMA_API(type) LZMA_API_IMPORT type LZMA_API_CALL
+#endif
+
+
+/***********
+ * nothrow *
+ ***********/
+
+/*
+ * None of the functions in liblzma may throw an exception. Even
+ * the functions that use callback functions won't throw exceptions,
+ * because liblzma would break if a callback function threw an exception.
+ */
+#ifndef lzma_nothrow
+#	if defined(__cplusplus)
+#		if __cplusplus >= 201103L || (defined(_MSVC_LANG) \
+				&& _MSVC_LANG >= 201103L)
+#			define lzma_nothrow noexcept
+#		else
+#			define lzma_nothrow throw()
+#		endif
+#	elif defined(__GNUC__) && (__GNUC__ > 3 \
+			|| (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))
+#		define lzma_nothrow __attribute__((__nothrow__))
+#	else
+#		define lzma_nothrow
+#	endif
+#endif
+
+
+/********************
+ * GNU C extensions *
+ ********************/
+
+/*
+ * GNU C extensions are used conditionally in the public API. It doesn't
+ * break anything if these are sometimes enabled and sometimes not, only
+ * affects warnings and optimizations.
+ */
+#if defined(__GNUC__) && __GNUC__ >= 3
+#	ifndef lzma_attribute
+#		define lzma_attribute(attr) __attribute__(attr)
+#	endif
+
+	/* warn_unused_result was added in GCC 3.4. */
+#	ifndef lzma_attr_warn_unused_result
+#		if __GNUC__ == 3 && __GNUC_MINOR__ < 4
+#			define lzma_attr_warn_unused_result
+#		endif
+#	endif
+
+#else
+#	ifndef lzma_attribute
+#		define lzma_attribute(attr)
+#	endif
+#endif
+
+
+#ifndef lzma_attr_pure
+#	define lzma_attr_pure lzma_attribute((__pure__))
+#endif
+
+#ifndef lzma_attr_const
+#	define lzma_attr_const lzma_attribute((__const__))
+#endif
+
+#ifndef lzma_attr_warn_unused_result
+#	define lzma_attr_warn_unused_result \
+		lzma_attribute((__warn_unused_result__))
+#endif
+
+
+/**************
+ * Subheaders *
+ **************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Subheaders check that this is defined. It is to prevent including
+ * them directly from applications.
+ */
+#define LZMA_H_INTERNAL 1
+
+/* Basic features */
+#include "lzma/version.h"
+#include "lzma/base.h"
+#include "lzma/vli.h"
+#include "lzma/check.h"
+
+/* Filters */
+#include "lzma/filter.h"
+#include "lzma/bcj.h"
+#include "lzma/delta.h"
+#include "lzma/lzma12.h"
+
+/* Container formats */
+#include "lzma/container.h"
+
+/* Advanced features */
+#include "lzma/stream_flags.h"
+#include "lzma/block.h"
+#include "lzma/index.h"
+#include "lzma/index_hash.h"
+
+/* Hardware information */
+#include "lzma/hardware.h"
+
+/*
+ * All subheaders included. Undefine LZMA_H_INTERNAL to prevent applications
+ * re-including the subheaders.
+ */
+#undef LZMA_H_INTERNAL
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ifndef LZMA_H */
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/base.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/base.h
new file mode 100644
index 00000000000..590e1d22bb0
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/base.h
@@ -0,0 +1,747 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/**
+ * \file        lzma/base.h
+ * \brief       Data types and functions used in many places in liblzma API
+ * \note        Never include this file directly. Use  instead.
+ */
+
+/*
+ * Author: Lasse Collin
+ */
+
+#ifndef LZMA_H_INTERNAL
+#	error Never include this file directly. Use  instead.
+#endif
+
+
+/**
+ * \brief       Boolean
+ *
+ * This is here because C89 doesn't have stdbool.h. To set a value for
+ * variables having type lzma_bool, you can use
+ *   - C99's 'true' and 'false' from stdbool.h;
+ *   - C++'s internal 'true' and 'false'; or
+ *   - integers one (true) and zero (false).
+ */
+typedef unsigned char lzma_bool;
+
+
+/**
+ * \brief       Type of reserved enumeration variable in structures
+ *
+ * To avoid breaking library ABI when new features are added, several
+ * structures contain extra variables that may be used in future. Since
+ * sizeof(enum) can be different than sizeof(int), and sizeof(enum) may
+ * even vary depending on the range of enumeration constants, we specify
+ * a separate type to be used for reserved enumeration variables. All
+ * enumeration constants in liblzma API will be non-negative and less
+ * than 128, which should guarantee that the ABI won't break even when
+ * new constants are added to existing enumerations.
+ */
+typedef enum {
+	LZMA_RESERVED_ENUM      = 0
+} lzma_reserved_enum;
+
+
+/**
+ * \brief       Return values used by several functions in liblzma
+ *
+ * Check the descriptions of specific functions to find out which return
+ * values they can return. With some functions the return values may have
+ * more specific meanings than described here; those differences are
+ * described per-function basis.
+ */
+typedef enum {
+	LZMA_OK                 = 0,
+		/**<
+		 * \brief       Operation completed successfully
+		 */
+
+	LZMA_STREAM_END         = 1,
+		/**<
+		 * \brief       End of stream was reached
+		 *
+		 * In encoder, LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, or
+		 * LZMA_FINISH was finished. In decoder, this indicates
+		 * that all the data was successfully decoded.
+		 *
+		 * In all cases, when LZMA_STREAM_END is returned, the last
+		 * output bytes should be picked from strm->next_out.
+		 */
+
+	LZMA_NO_CHECK           = 2,
+		/**<
+		 * \brief       Input stream has no integrity check
+		 *
+		 * This return value can be returned only if the
+		 * LZMA_TELL_NO_CHECK flag was used when initializing
+		 * the decoder. LZMA_NO_CHECK is just a warning, and
+		 * the decoding can be continued normally.
+		 *
+		 * It is possible to call lzma_get_check() immediately after
+		 * lzma_code has returned LZMA_NO_CHECK. The result will
+		 * naturally be LZMA_CHECK_NONE, but the possibility to call
+		 * lzma_get_check() may be convenient in some applications.
+		 */
+
+	LZMA_UNSUPPORTED_CHECK  = 3,
+		/**<
+		 * \brief       Cannot calculate the integrity check
+		 *
+		 * The usage of this return value is different in encoders
+		 * and decoders.
+		 *
+		 * Encoders can return this value only from the initialization
+		 * function. If initialization fails with this value, the
+		 * encoding cannot be done, because there's no way to produce
+		 * output with the correct integrity check.
+		 *
+		 * Decoders can return this value only from lzma_code() and
+		 * only if the LZMA_TELL_UNSUPPORTED_CHECK flag was used when
+		 * initializing the decoder. The decoding can still be
+		 * continued normally even if the check type is unsupported,
+		 * but naturally the check will not be validated, and possible
+		 * errors may go undetected.
+		 *
+		 * With decoder, it is possible to call lzma_get_check()
+		 * immediately after lzma_code() has returned
+		 * LZMA_UNSUPPORTED_CHECK. This way it is possible to find
+		 * out what the unsupported Check ID was.
+		 */
+
+	LZMA_GET_CHECK          = 4,
+		/**<
+		 * \brief       Integrity check type is now available
+		 *
+		 * This value can be returned only by the lzma_code() function
+		 * and only if the decoder was initialized with the
+		 * LZMA_TELL_ANY_CHECK flag. LZMA_GET_CHECK tells the
+		 * application that it may now call lzma_get_check() to find
+		 * out the Check ID. This can be used, for example, to
+		 * implement a decoder that accepts only files that have
+		 * strong enough integrity check.
+		 */
+
+	LZMA_MEM_ERROR          = 5,
+		/**<
+		 * \brief       Cannot allocate memory
+		 *
+		 * Memory allocation failed, or the size of the allocation
+		 * would be greater than SIZE_MAX.
+		 *
+		 * Due to internal implementation reasons, the coding cannot
+		 * be continued even if more memory were made available after
+		 * LZMA_MEM_ERROR.
+		 */
+
+	LZMA_MEMLIMIT_ERROR     = 6,
+		/**<
+		 * \brief       Memory usage limit was reached
+		 *
+		 * Decoder would need more memory than allowed by the
+		 * specified memory usage limit. To continue decoding,
+		 * the memory usage limit has to be increased with
+		 * lzma_memlimit_set().
+		 *
+		 * liblzma 5.2.6 and earlier had a bug in single-threaded .xz
+		 * decoder (lzma_stream_decoder()) which made it impossible
+		 * to continue decoding after LZMA_MEMLIMIT_ERROR even if
+		 * the limit was increased using lzma_memlimit_set().
+		 * Other decoders worked correctly.
+		 */
+
+	LZMA_FORMAT_ERROR       = 7,
+		/**<
+		 * \brief       File format not recognized
+		 *
+		 * The decoder did not recognize the input as supported file
+		 * format. This error can occur, for example, when trying to
+		 * decode .lzma format file with lzma_stream_decoder,
+		 * because lzma_stream_decoder accepts only the .xz format.
+		 */
+
+	LZMA_OPTIONS_ERROR      = 8,
+		/**<
+		 * \brief       Invalid or unsupported options
+		 *
+		 * Invalid or unsupported options, for example
+		 *  - unsupported filter(s) or filter options; or
+		 *  - reserved bits set in headers (decoder only).
+		 *
+		 * Rebuilding liblzma with more features enabled, or
+		 * upgrading to a newer version of liblzma may help.
+		 */
+
+	LZMA_DATA_ERROR         = 9,
+		/**<
+		 * \brief       Data is corrupt
+		 *
+		 * The usage of this return value is different in encoders
+		 * and decoders. In both encoder and decoder, the coding
+		 * cannot continue after this error.
+		 *
+		 * Encoders return this if size limits of the target file
+		 * format would be exceeded. These limits are huge, thus
+		 * getting this error from an encoder is mostly theoretical.
+		 * For example, the maximum compressed and uncompressed
+		 * size of a .xz Stream is roughly 8 EiB (2^63 bytes).
+		 *
+		 * Decoders return this error if the input data is corrupt.
+		 * This can mean, for example, invalid CRC32 in headers
+		 * or invalid check of uncompressed data.
+		 */
+
+	LZMA_BUF_ERROR          = 10,
+		/**<
+		 * \brief       No progress is possible
+		 *
+		 * This error code is returned when the coder cannot consume
+		 * any new input and produce any new output. The most common
+		 * reason for this error is that the input stream being
+		 * decoded is truncated or corrupt.
+		 *
+		 * This error is not fatal. Coding can be continued normally
+		 * by providing more input and/or more output space, if
+		 * possible.
+		 *
+		 * Typically the first call to lzma_code() that can do no
+		 * progress returns LZMA_OK instead of LZMA_BUF_ERROR. Only
+		 * the second consecutive call doing no progress will return
+		 * LZMA_BUF_ERROR. This is intentional.
+		 *
+		 * With zlib, Z_BUF_ERROR may be returned even if the
+		 * application is doing nothing wrong, so apps will need
+		 * to handle Z_BUF_ERROR specially. The above hack
+		 * guarantees that liblzma never returns LZMA_BUF_ERROR
+		 * to properly written applications unless the input file
+		 * is truncated or corrupt. This should simplify the
+		 * applications a little.
+		 */
+
+	LZMA_PROG_ERROR         = 11,
+		/**<
+		 * \brief       Programming error
+		 *
+		 * This indicates that the arguments given to the function are
+		 * invalid or the internal state of the decoder is corrupt.
+		 *   - Function arguments are invalid or the structures
+		 *     pointed by the argument pointers are invalid
+		 *     e.g. if strm->next_out has been set to NULL and
+		 *     strm->avail_out > 0 when calling lzma_code().
+		 *   - lzma_* functions have been called in wrong order
+		 *     e.g. lzma_code() was called right after lzma_end().
+		 *   - If errors occur randomly, the reason might be flaky
+		 *     hardware.
+		 *
+		 * If you think that your code is correct, this error code
+		 * can be a sign of a bug in liblzma. See the documentation
+		 * how to report bugs.
+		 */
+
+	LZMA_SEEK_NEEDED        = 12,
+		/**<
+		 * \brief       Request to change the input file position
+		 *
+		 * Some coders can do random access in the input file. The
+		 * initialization functions of these coders take the file size
+		 * as an argument. No other coders can return LZMA_SEEK_NEEDED.
+		 *
+		 * When this value is returned, the application must seek to
+		 * the file position given in lzma_stream.seek_pos. This value
+		 * is guaranteed to never exceed the file size that was
+		 * specified at the coder initialization.
+		 *
+		 * After seeking the application should read new input and
+		 * pass it normally via lzma_stream.next_in and .avail_in.
+		 */
+
+	/*
+	 * These enumerations may be used internally by liblzma
+	 * but they will never be returned to applications.
+	 */
+	LZMA_RET_INTERNAL1      = 101,
+	LZMA_RET_INTERNAL2      = 102,
+	LZMA_RET_INTERNAL3      = 103,
+	LZMA_RET_INTERNAL4      = 104,
+	LZMA_RET_INTERNAL5      = 105,
+	LZMA_RET_INTERNAL6      = 106,
+	LZMA_RET_INTERNAL7      = 107,
+	LZMA_RET_INTERNAL8      = 108
+} lzma_ret;
+
+
+/**
+ * \brief       The 'action' argument for lzma_code()
+ *
+ * After the first use of LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, LZMA_FULL_BARRIER,
+ * or LZMA_FINISH, the same 'action' must be used until lzma_code() returns
+ * LZMA_STREAM_END. Also, the amount of input (that is, strm->avail_in) must
+ * not be modified by the application until lzma_code() returns
+ * LZMA_STREAM_END. Changing the 'action' or modifying the amount of input
+ * will make lzma_code() return LZMA_PROG_ERROR.
+ */
+typedef enum {
+	LZMA_RUN = 0,
+		/**<
+		 * \brief       Continue coding
+		 *
+		 * Encoder: Encode as much input as possible. Some internal
+		 * buffering will probably be done (depends on the filter
+		 * chain in use), which causes latency: the input used won't
+		 * usually be decodeable from the output of the same
+		 * lzma_code() call.
+		 *
+		 * Decoder: Decode as much input as possible and produce as
+		 * much output as possible.
+		 */
+
+	LZMA_SYNC_FLUSH = 1,
+		/**<
+		 * \brief       Make all the input available at output
+		 *
+		 * Normally the encoder introduces some latency.
+		 * LZMA_SYNC_FLUSH forces all the buffered data to be
+		 * available at output without resetting the internal
+		 * state of the encoder. This way it is possible to use
+		 * compressed stream for example for communication over
+		 * network.
+		 *
+		 * Only some filters support LZMA_SYNC_FLUSH. Trying to use
+		 * LZMA_SYNC_FLUSH with filters that don't support it will
+		 * make lzma_code() return LZMA_OPTIONS_ERROR. For example,
+		 * LZMA1 doesn't support LZMA_SYNC_FLUSH but LZMA2 does.
+		 *
+		 * Using LZMA_SYNC_FLUSH very often can dramatically reduce
+		 * the compression ratio. With some filters (for example,
+		 * LZMA2), fine-tuning the compression options may help
+		 * mitigate this problem significantly (for example,
+		 * match finder with LZMA2).
+		 *
+		 * Decoders don't support LZMA_SYNC_FLUSH.
+		 */
+
+	LZMA_FULL_FLUSH = 2,
+		/**<
+		 * \brief       Finish encoding of the current Block
+		 *
+		 * All the input data going to the current Block must have
+		 * been given to the encoder (the last bytes can still be
+		 * pending in *next_in). Call lzma_code() with LZMA_FULL_FLUSH
+		 * until it returns LZMA_STREAM_END. Then continue normally
+		 * with LZMA_RUN or finish the Stream with LZMA_FINISH.
+		 *
+		 * This action is currently supported only by Stream encoder
+		 * and easy encoder (which uses Stream encoder). If there is
+		 * no unfinished Block, no empty Block is created.
+		 */
+
+	LZMA_FULL_BARRIER = 4,
+		/**<
+		 * \brief       Finish encoding of the current Block
+		 *
+		 * This is like LZMA_FULL_FLUSH except that this doesn't
+		 * necessarily wait until all the input has been made
+		 * available via the output buffer. That is, lzma_code()
+		 * might return LZMA_STREAM_END as soon as all the input
+		 * has been consumed (avail_in == 0).
+		 *
+		 * LZMA_FULL_BARRIER is useful with a threaded encoder if
+		 * one wants to split the .xz Stream into Blocks at specific
+		 * offsets but doesn't care if the output isn't flushed
+		 * immediately. Using LZMA_FULL_BARRIER allows keeping
+		 * the threads busy while LZMA_FULL_FLUSH would make
+		 * lzma_code() wait until all the threads have finished
+		 * until more data could be passed to the encoder.
+		 *
+		 * With a lzma_stream initialized with the single-threaded
+		 * lzma_stream_encoder() or lzma_easy_encoder(),
+		 * LZMA_FULL_BARRIER is an alias for LZMA_FULL_FLUSH.
+		 */
+
+	LZMA_FINISH = 3
+		/**<
+		 * \brief       Finish the coding operation
+		 *
+		 * All the input data must have been given to the encoder
+		 * (the last bytes can still be pending in next_in).
+		 * Call lzma_code() with LZMA_FINISH until it returns
+		 * LZMA_STREAM_END. Once LZMA_FINISH has been used,
+		 * the amount of input must no longer be changed by
+		 * the application.
+		 *
+		 * When decoding, using LZMA_FINISH is optional unless the
+		 * LZMA_CONCATENATED flag was used when the decoder was
+		 * initialized. When LZMA_CONCATENATED was not used, the only
+		 * effect of LZMA_FINISH is that the amount of input must not
+		 * be changed just like in the encoder.
+		 */
+} lzma_action;
+
+
+/**
+ * \brief       Custom functions for memory handling
+ *
+ * A pointer to lzma_allocator may be passed via lzma_stream structure
+ * to liblzma, and some advanced functions take a pointer to lzma_allocator
+ * as a separate function argument. The library will use the functions
+ * specified in lzma_allocator for memory handling instead of the default
+ * malloc() and free(). C++ users should note that the custom memory
+ * handling functions must not throw exceptions.
+ *
+ * Single-threaded mode only: liblzma doesn't make an internal copy of
+ * lzma_allocator. Thus, it is OK to change these function pointers in
+ * the middle of the coding process, but obviously it must be done
+ * carefully to make sure that the replacement 'free' can deallocate
+ * memory allocated by the earlier 'alloc' function(s).
+ *
+ * Multithreaded mode: liblzma might internally store pointers to the
+ * lzma_allocator given via the lzma_stream structure. The application
+ * must not change the allocator pointer in lzma_stream or the contents
+ * of the pointed lzma_allocator structure until lzma_end() has been used
+ * to free the memory associated with that lzma_stream. The allocation
+ * functions might be called simultaneously from multiple threads, and
+ * thus they must be thread safe.
+ */
+typedef struct {
+	/**
+	 * \brief       Pointer to a custom memory allocation function
+	 *
+	 * If you don't want a custom allocator, but still want
+	 * custom free(), set this to NULL and liblzma will use
+	 * the standard malloc().
+	 *
+	 * \param       opaque  lzma_allocator.opaque (see below)
+	 * \param       nmemb   Number of elements like in calloc(). liblzma
+	 *                      will always set nmemb to 1, so it is safe to
+	 *                      ignore nmemb in a custom allocator if you like.
+	 *                      The nmemb argument exists only for
+	 *                      compatibility with zlib and libbzip2.
+	 * \param       size    Size of an element in bytes.
+	 *                      liblzma never sets this to zero.
+	 *
+	 * \return      Pointer to the beginning of a memory block of
+	 *              'size' bytes, or NULL if allocation fails
+	 *              for some reason. When allocation fails, functions
+	 *              of liblzma return LZMA_MEM_ERROR.
+	 *
+	 * The allocator should not waste time zeroing the allocated buffers.
+	 * This is not only about speed, but also memory usage, since the
+	 * operating system kernel doesn't necessarily allocate the requested
+	 * memory in physical memory until it is actually used. With small
+	 * input files, liblzma may actually need only a fraction of the
+	 * memory that it requested for allocation.
+	 *
+	 * \note        LZMA_MEM_ERROR is also used when the size of the
+	 *              allocation would be greater than SIZE_MAX. Thus,
+	 *              don't assume that the custom allocator must have
+	 *              returned NULL if some function from liblzma
+	 *              returns LZMA_MEM_ERROR.
+	 */
+	void *(LZMA_API_CALL *alloc)(void *opaque, size_t nmemb, size_t size);
+
+	/**
+	 * \brief       Pointer to a custom memory freeing function
+	 *
+	 * If you don't want a custom freeing function, but still
+	 * want a custom allocator, set this to NULL and liblzma
+	 * will use the standard free().
+	 *
+	 * \param       opaque  lzma_allocator.opaque (see below)
+	 * \param       ptr     Pointer returned by lzma_allocator.alloc(),
+	 *                      or when it is set to NULL, a pointer returned
+	 *                      by the standard malloc().
+	 */
+	void (LZMA_API_CALL *free)(void *opaque, void *ptr);
+
+	/**
+	 * \brief       Pointer passed to .alloc() and .free()
+	 *
+	 * opaque is passed as the first argument to lzma_allocator.alloc()
+	 * and lzma_allocator.free(). This intended to ease implementing
+	 * custom memory allocation functions for use with liblzma.
+	 *
+	 * If you don't need this, you should set this to NULL.
+	 */
+	void *opaque;
+
+} lzma_allocator;
+
+
+/**
+ * \brief       Internal data structure
+ *
+ * The contents of this structure is not visible outside the library.
+ */
+typedef struct lzma_internal_s lzma_internal;
+
+
+/**
+ * \brief       Passing data to and from liblzma
+ *
+ * The lzma_stream structure is used for
+ *  - passing pointers to input and output buffers to liblzma;
+ *  - defining custom memory handler functions; and
+ *  - holding a pointer to coder-specific internal data structures.
+ *
+ * Typical usage:
+ *
+ *  - After allocating lzma_stream (on stack or with malloc()), it must be
+ *    initialized to LZMA_STREAM_INIT (see LZMA_STREAM_INIT for details).
+ *
+ *  - Initialize a coder to the lzma_stream, for example by using
+ *    lzma_easy_encoder() or lzma_auto_decoder(). Some notes:
+ *      - In contrast to zlib, strm->next_in and strm->next_out are
+ *        ignored by all initialization functions, thus it is safe
+ *        to not initialize them yet.
+ *      - The initialization functions always set strm->total_in and
+ *        strm->total_out to zero.
+ *      - If the initialization function fails, no memory is left allocated
+ *        that would require freeing with lzma_end() even if some memory was
+ *        associated with the lzma_stream structure when the initialization
+ *        function was called.
+ *
+ *  - Use lzma_code() to do the actual work.
+ *
+ *  - Once the coding has been finished, the existing lzma_stream can be
+ *    reused. It is OK to reuse lzma_stream with different initialization
+ *    function without calling lzma_end() first. Old allocations are
+ *    automatically freed.
+ *
+ *  - Finally, use lzma_end() to free the allocated memory. lzma_end() never
+ *    frees the lzma_stream structure itself.
+ *
+ * Application may modify the values of total_in and total_out as it wants.
+ * They are updated by liblzma to match the amount of data read and
+ * written but aren't used for anything else except as a possible return
+ * values from lzma_get_progress().
+ */
+typedef struct {
+	const uint8_t *next_in; /**< Pointer to the next input byte. */
+	size_t avail_in;    /**< Number of available input bytes in next_in. */
+	uint64_t total_in;  /**< Total number of bytes read by liblzma. */
+
+	uint8_t *next_out;  /**< Pointer to the next output position. */
+	size_t avail_out;   /**< Amount of free space in next_out. */
+	uint64_t total_out; /**< Total number of bytes written by liblzma. */
+
+	/**
+	 * \brief       Custom memory allocation functions
+	 *
+	 * In most cases this is NULL which makes liblzma use
+	 * the standard malloc() and free().
+	 *
+	 * \note        In 5.0.x this is not a const pointer.
+	 */
+	const lzma_allocator *allocator;
+
+	/** Internal state is not visible to applications. */
+	lzma_internal *internal;
+
+	/*
+	 * Reserved space to allow possible future extensions without
+	 * breaking the ABI. Excluding the initialization of this structure,
+	 * you should not touch these, because the names of these variables
+	 * may change.
+	 */
+
+	/** \private     Reserved member. */
+	void *reserved_ptr1;
+
+	/** \private     Reserved member. */
+	void *reserved_ptr2;
+
+	/** \private     Reserved member. */
+	void *reserved_ptr3;
+
+	/** \private     Reserved member. */
+	void *reserved_ptr4;
+
+	/**
+	 * \brief       New seek input position for LZMA_SEEK_NEEDED
+	 *
+	 * When lzma_code() returns LZMA_SEEK_NEEDED, the new input position
+	 * needed by liblzma will be available seek_pos. The value is
+	 * guaranteed to not exceed the file size that was specified when
+	 * this lzma_stream was initialized.
+	 *
+	 * In all other situations the value of this variable is undefined.
+	 */
+	uint64_t seek_pos;
+
+	/** \private     Reserved member. */
+	uint64_t reserved_int2;
+
+	/** \private     Reserved member. */
+	size_t reserved_int3;
+
+	/** \private     Reserved member. */
+	size_t reserved_int4;
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum1;
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum2;
+
+} lzma_stream;
+
+
+/**
+ * \brief       Initialization for lzma_stream
+ *
+ * When you declare an instance of lzma_stream, you can immediately
+ * initialize it so that initialization functions know that no memory
+ * has been allocated yet:
+ *
+ *     lzma_stream strm = LZMA_STREAM_INIT;
+ *
+ * If you need to initialize a dynamically allocated lzma_stream, you can use
+ * memset(strm_pointer, 0, sizeof(lzma_stream)). Strictly speaking, this
+ * violates the C standard since NULL may have different internal
+ * representation than zero, but it should be portable enough in practice.
+ * Anyway, for maximum portability, you can use something like this:
+ *
+ *     lzma_stream tmp = LZMA_STREAM_INIT;
+ *     *strm = tmp;
+ */
+#define LZMA_STREAM_INIT \
+	{ NULL, 0, 0, NULL, 0, 0, NULL, NULL, \
+	NULL, NULL, NULL, NULL, 0, 0, 0, 0, \
+	LZMA_RESERVED_ENUM, LZMA_RESERVED_ENUM }
+
+
+/**
+ * \brief       Encode or decode data
+ *
+ * Once the lzma_stream has been successfully initialized (e.g. with
+ * lzma_stream_encoder()), the actual encoding or decoding is done
+ * using this function. The application has to update strm->next_in,
+ * strm->avail_in, strm->next_out, and strm->avail_out to pass input
+ * to and get output from liblzma.
+ *
+ * See the description of the coder-specific initialization function to find
+ * out what 'action' values are supported by the coder.
+ *
+ * \param       strm    Pointer to lzma_stream that is at least initialized
+ *                      with LZMA_STREAM_INIT.
+ * \param       action  Action for this function to take. Must be a valid
+ *                      lzma_action enum value.
+ *
+ * \return      Any valid lzma_ret. See the lzma_ret enum description for more
+ *              information.
+ */
+extern LZMA_API(lzma_ret) lzma_code(lzma_stream *strm, lzma_action action)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Free memory allocated for the coder data structures
+ *
+ * After lzma_end(strm), strm->internal is guaranteed to be NULL. No other
+ * members of the lzma_stream structure are touched.
+ *
+ * \note        zlib indicates an error if application end()s unfinished
+ *              stream structure. liblzma doesn't do this, and assumes that
+ *              application knows what it is doing.
+ *
+ * \param       strm    Pointer to lzma_stream that is at least initialized
+ *                      with LZMA_STREAM_INIT.
+ */
+extern LZMA_API(void) lzma_end(lzma_stream *strm) lzma_nothrow;
+
+
+/**
+ * \brief       Get progress information
+ *
+ * In single-threaded mode, applications can get progress information from
+ * strm->total_in and strm->total_out. In multi-threaded mode this is less
+ * useful because a significant amount of both input and output data gets
+ * buffered internally by liblzma. This makes total_in and total_out give
+ * misleading information and also makes the progress indicator updates
+ * non-smooth.
+ *
+ * This function gives realistic progress information also in multi-threaded
+ * mode by taking into account the progress made by each thread. In
+ * single-threaded mode *progress_in and *progress_out are set to
+ * strm->total_in and strm->total_out, respectively.
+ *
+ * \param       strm          Pointer to lzma_stream that is at least
+ *                            initialized with LZMA_STREAM_INIT.
+ * \param[out]  progress_in   Pointer to the number of input bytes processed.
+ * \param[out]  progress_out  Pointer to the number of output bytes processed.
+ */
+extern LZMA_API(void) lzma_get_progress(lzma_stream *strm,
+		uint64_t *progress_in, uint64_t *progress_out) lzma_nothrow;
+
+
+/**
+ * \brief       Get the memory usage of decoder filter chain
+ *
+ * This function is currently supported only when *strm has been initialized
+ * with a function that takes a memlimit argument. With other functions, you
+ * should use e.g. lzma_raw_encoder_memusage() or lzma_raw_decoder_memusage()
+ * to estimate the memory requirements.
+ *
+ * This function is useful e.g. after LZMA_MEMLIMIT_ERROR to find out how big
+ * the memory usage limit should have been to decode the input. Note that
+ * this may give misleading information if decoding .xz Streams that have
+ * multiple Blocks, because each Block can have different memory requirements.
+ *
+ * \param       strm    Pointer to lzma_stream that is at least initialized
+ *                      with LZMA_STREAM_INIT.
+ *
+ * \return      How much memory is currently allocated for the filter
+ *              decoders. If no filter chain is currently allocated,
+ *              some non-zero value is still returned, which is less than
+ *              or equal to what any filter chain would indicate as its
+ *              memory requirement.
+ *
+ *              If this function isn't supported by *strm or some other error
+ *              occurs, zero is returned.
+ */
+extern LZMA_API(uint64_t) lzma_memusage(const lzma_stream *strm)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Get the current memory usage limit
+ *
+ * This function is supported only when *strm has been initialized with
+ * a function that takes a memlimit argument.
+ *
+ * \param       strm    Pointer to lzma_stream that is at least initialized
+ *                      with LZMA_STREAM_INIT.
+ *
+ * \return      On success, the current memory usage limit is returned
+ *              (always non-zero). On error, zero is returned.
+ */
+extern LZMA_API(uint64_t) lzma_memlimit_get(const lzma_stream *strm)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Set the memory usage limit
+ *
+ * This function is supported only when *strm has been initialized with
+ * a function that takes a memlimit argument.
+ *
+ * liblzma 5.2.3 and earlier has a bug where memlimit value of 0 causes
+ * this function to do nothing (leaving the limit unchanged) and still
+ * return LZMA_OK. Later versions treat 0 as if 1 had been specified (so
+ * lzma_memlimit_get() will return 1 even if you specify 0 here).
+ *
+ * liblzma 5.2.6 and earlier had a bug in single-threaded .xz decoder
+ * (lzma_stream_decoder()) which made it impossible to continue decoding
+ * after LZMA_MEMLIMIT_ERROR even if the limit was increased using
+ * lzma_memlimit_set(). Other decoders worked correctly.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: New memory usage limit successfully set.
+ *              - LZMA_MEMLIMIT_ERROR: The new limit is too small.
+ *                The limit was not changed.
+ *              - LZMA_PROG_ERROR: Invalid arguments, e.g. *strm doesn't
+ *                support memory usage limit.
+ */
+extern LZMA_API(lzma_ret) lzma_memlimit_set(
+		lzma_stream *strm, uint64_t memlimit) lzma_nothrow;
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/bcj.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/bcj.h
new file mode 100644
index 00000000000..7f6611feb32
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/bcj.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/**
+ * \file        lzma/bcj.h
+ * \brief       Branch/Call/Jump conversion filters
+ * \note        Never include this file directly. Use  instead.
+ */
+
+/*
+ * Author: Lasse Collin
+ */
+
+#ifndef LZMA_H_INTERNAL
+#	error Never include this file directly. Use  instead.
+#endif
+
+
+/* Filter IDs for lzma_filter.id */
+
+/**
+ * \brief       Filter for x86 binaries
+ */
+#define LZMA_FILTER_X86         LZMA_VLI_C(0x04)
+
+/**
+ * \brief       Filter for Big endian PowerPC binaries
+ */
+#define LZMA_FILTER_POWERPC     LZMA_VLI_C(0x05)
+
+/**
+ * \brief       Filter for IA-64 (Itanium) binaries
+ */
+#define LZMA_FILTER_IA64        LZMA_VLI_C(0x06)
+
+/**
+ * \brief       Filter for ARM binaries
+ */
+#define LZMA_FILTER_ARM         LZMA_VLI_C(0x07)
+
+/**
+ * \brief       Filter for ARM-Thumb binaries
+ */
+#define LZMA_FILTER_ARMTHUMB    LZMA_VLI_C(0x08)
+
+/**
+ * \brief       Filter for SPARC binaries
+ */
+#define LZMA_FILTER_SPARC       LZMA_VLI_C(0x09)
+
+/**
+ * \brief       Filter for ARM64 binaries
+ */
+#define LZMA_FILTER_ARM64       LZMA_VLI_C(0x0A)
+
+/**
+ * \brief       Filter for RISC-V binaries
+ */
+#define LZMA_FILTER_RISCV       LZMA_VLI_C(0x0B)
+
+
+/**
+ * \brief       Options for BCJ filters
+ *
+ * The BCJ filters never change the size of the data. Specifying options
+ * for them is optional: if pointer to options is NULL, default value is
+ * used. You probably never need to specify options to BCJ filters, so just
+ * set the options pointer to NULL and be happy.
+ *
+ * If options with non-default values have been specified when encoding,
+ * the same options must also be specified when decoding.
+ *
+ * \note        At the moment, none of the BCJ filters support
+ *              LZMA_SYNC_FLUSH. If LZMA_SYNC_FLUSH is specified,
+ *              LZMA_OPTIONS_ERROR will be returned. If there is need,
+ *              partial support for LZMA_SYNC_FLUSH can be added in future.
+ *              Partial means that flushing would be possible only at
+ *              offsets that are multiple of 2, 4, or 16 depending on
+ *              the filter, except x86 which cannot be made to support
+ *              LZMA_SYNC_FLUSH predictably.
+ */
+typedef struct {
+	/**
+	 * \brief       Start offset for conversions
+	 *
+	 * This setting is useful only when the same filter is used
+	 * _separately_ for multiple sections of the same executable file,
+	 * and the sections contain cross-section branch/call/jump
+	 * instructions. In that case it is beneficial to set the start
+	 * offset of the non-first sections so that the relative addresses
+	 * of the cross-section branch/call/jump instructions will use the
+	 * same absolute addresses as in the first section.
+	 *
+	 * When the pointer to options is NULL, the default value (zero)
+	 * is used.
+	 */
+	uint32_t start_offset;
+
+} lzma_options_bcj;
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/block.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/block.h
new file mode 100644
index 00000000000..05b77e59aab
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/block.h
@@ -0,0 +1,694 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/**
+ * \file        lzma/block.h
+ * \brief       .xz Block handling
+ * \note        Never include this file directly. Use  instead.
+ */
+
+/*
+ * Author: Lasse Collin
+ */
+
+#ifndef LZMA_H_INTERNAL
+#	error Never include this file directly. Use  instead.
+#endif
+
+
+/**
+ * \brief       Options for the Block and Block Header encoders and decoders
+ *
+ * Different Block handling functions use different parts of this structure.
+ * Some read some members, other functions write, and some do both. Only the
+ * members listed for reading need to be initialized when the specified
+ * functions are called. The members marked for writing will be assigned
+ * new values at some point either by calling the given function or by
+ * later calls to lzma_code().
+ */
+typedef struct {
+	/**
+	 * \brief       Block format version
+	 *
+	 * To prevent API and ABI breakages when new features are needed,
+	 * a version number is used to indicate which members in this
+	 * structure are in use:
+	 *   - liblzma >= 5.0.0: version = 0 is supported.
+	 *   - liblzma >= 5.1.4beta: Support for version = 1 was added,
+	 *     which adds the ignore_check member.
+	 *
+	 * If version is greater than one, most Block related functions
+	 * will return LZMA_OPTIONS_ERROR (lzma_block_header_decode() works
+	 * with any version value).
+	 *
+	 * Read by:
+	 *  - lzma_block_header_size()
+	 *  - lzma_block_header_encode()
+	 *  - lzma_block_header_decode()
+	 *  - lzma_block_compressed_size()
+	 *  - lzma_block_unpadded_size()
+	 *  - lzma_block_total_size()
+	 *  - lzma_block_encoder()
+	 *  - lzma_block_decoder()
+	 *  - lzma_block_buffer_encode()
+	 *  - lzma_block_uncomp_encode()
+	 *  - lzma_block_buffer_decode()
+	 *
+	 * Written by:
+	 *  - lzma_block_header_decode()
+	 */
+	uint32_t version;
+
+	/**
+	 * \brief       Size of the Block Header field in bytes
+	 *
+	 * This is always a multiple of four.
+	 *
+	 * Read by:
+	 *  - lzma_block_header_encode()
+	 *  - lzma_block_header_decode()
+	 *  - lzma_block_compressed_size()
+	 *  - lzma_block_unpadded_size()
+	 *  - lzma_block_total_size()
+	 *  - lzma_block_decoder()
+	 *  - lzma_block_buffer_decode()
+	 *
+	 * Written by:
+	 *  - lzma_block_header_size()
+	 *  - lzma_block_buffer_encode()
+	 *  - lzma_block_uncomp_encode()
+	 */
+	uint32_t header_size;
+#	define LZMA_BLOCK_HEADER_SIZE_MIN 8
+#	define LZMA_BLOCK_HEADER_SIZE_MAX 1024
+
+	/**
+	 * \brief       Type of integrity Check
+	 *
+	 * The Check ID is not stored into the Block Header, thus its value
+	 * must be provided also when decoding.
+	 *
+	 * Read by:
+	 *  - lzma_block_header_encode()
+	 *  - lzma_block_header_decode()
+	 *  - lzma_block_compressed_size()
+	 *  - lzma_block_unpadded_size()
+	 *  - lzma_block_total_size()
+	 *  - lzma_block_encoder()
+	 *  - lzma_block_decoder()
+	 *  - lzma_block_buffer_encode()
+	 *  - lzma_block_buffer_decode()
+	 */
+	lzma_check check;
+
+	/**
+	 * \brief       Size of the Compressed Data in bytes
+	 *
+	 * Encoding: If this is not LZMA_VLI_UNKNOWN, Block Header encoder
+	 * will store this value to the Block Header. Block encoder doesn't
+	 * care about this value, but will set it once the encoding has been
+	 * finished.
+	 *
+	 * Decoding: If this is not LZMA_VLI_UNKNOWN, Block decoder will
+	 * verify that the size of the Compressed Data field matches
+	 * compressed_size.
+	 *
+	 * Usually you don't know this value when encoding in streamed mode,
+	 * and thus cannot write this field into the Block Header.
+	 *
+	 * In non-streamed mode you can reserve space for this field before
+	 * encoding the actual Block. After encoding the data, finish the
+	 * Block by encoding the Block Header. Steps in detail:
+	 *
+	 *  - Set compressed_size to some big enough value. If you don't know
+	 *    better, use LZMA_VLI_MAX, but remember that bigger values take
+	 *    more space in Block Header.
+	 *
+	 *  - Call lzma_block_header_size() to see how much space you need to
+	 *    reserve for the Block Header.
+	 *
+	 *  - Encode the Block using lzma_block_encoder() and lzma_code().
+	 *    It sets compressed_size to the correct value.
+	 *
+	 *  - Use lzma_block_header_encode() to encode the Block Header.
+	 *    Because space was reserved in the first step, you don't need
+	 *    to call lzma_block_header_size() anymore, because due to
+	 *    reserving, header_size has to be big enough. If it is "too big",
+	 *    lzma_block_header_encode() will add enough Header Padding to
+	 *    make Block Header to match the size specified by header_size.
+	 *
+	 * Read by:
+	 *  - lzma_block_header_size()
+	 *  - lzma_block_header_encode()
+	 *  - lzma_block_compressed_size()
+	 *  - lzma_block_unpadded_size()
+	 *  - lzma_block_total_size()
+	 *  - lzma_block_decoder()
+	 *  - lzma_block_buffer_decode()
+	 *
+	 * Written by:
+	 *  - lzma_block_header_decode()
+	 *  - lzma_block_compressed_size()
+	 *  - lzma_block_encoder()
+	 *  - lzma_block_decoder()
+	 *  - lzma_block_buffer_encode()
+	 *  - lzma_block_uncomp_encode()
+	 *  - lzma_block_buffer_decode()
+	 */
+	lzma_vli compressed_size;
+
+	/**
+	 * \brief       Uncompressed Size in bytes
+	 *
+	 * This is handled very similarly to compressed_size above.
+	 *
+	 * uncompressed_size is needed by fewer functions than
+	 * compressed_size. This is because uncompressed_size isn't
+	 * needed to validate that Block stays within proper limits.
+	 *
+	 * Read by:
+	 *  - lzma_block_header_size()
+	 *  - lzma_block_header_encode()
+	 *  - lzma_block_decoder()
+	 *  - lzma_block_buffer_decode()
+	 *
+	 * Written by:
+	 *  - lzma_block_header_decode()
+	 *  - lzma_block_encoder()
+	 *  - lzma_block_decoder()
+	 *  - lzma_block_buffer_encode()
+	 *  - lzma_block_uncomp_encode()
+	 *  - lzma_block_buffer_decode()
+	 */
+	lzma_vli uncompressed_size;
+
+	/**
+	 * \brief       Array of filters
+	 *
+	 * There can be 1-4 filters. The end of the array is marked with
+	 * .id = LZMA_VLI_UNKNOWN.
+	 *
+	 * Read by:
+	 *  - lzma_block_header_size()
+	 *  - lzma_block_header_encode()
+	 *  - lzma_block_encoder()
+	 *  - lzma_block_decoder()
+	 *  - lzma_block_buffer_encode()
+	 *  - lzma_block_buffer_decode()
+	 *
+	 * Written by:
+	 *  - lzma_block_header_decode(): Note that this does NOT free()
+	 *    the old filter options structures. All unused filters[] will
+	 *    have .id == LZMA_VLI_UNKNOWN and .options == NULL. If
+	 *    decoding fails, all filters[] are guaranteed to be
+	 *    LZMA_VLI_UNKNOWN and NULL.
+	 *
+	 * \note        Because of the array is terminated with
+	 *              .id = LZMA_VLI_UNKNOWN, the actual array must
+	 *              have LZMA_FILTERS_MAX + 1 members or the Block
+	 *              Header decoder will overflow the buffer.
+	 */
+	lzma_filter *filters;
+
+	/**
+	 * \brief       Raw value stored in the Check field
+	 *
+	 * After successful coding, the first lzma_check_size(check) bytes
+	 * of this array contain the raw value stored in the Check field.
+	 *
+	 * Note that CRC32 and CRC64 are stored in little endian byte order.
+	 * Take it into account if you display the Check values to the user.
+	 *
+	 * Written by:
+	 *  - lzma_block_encoder()
+	 *  - lzma_block_decoder()
+	 *  - lzma_block_buffer_encode()
+	 *  - lzma_block_uncomp_encode()
+	 *  - lzma_block_buffer_decode()
+	 */
+	uint8_t raw_check[LZMA_CHECK_SIZE_MAX];
+
+	/*
+	 * Reserved space to allow possible future extensions without
+	 * breaking the ABI. You should not touch these, because the names
+	 * of these variables may change. These are and will never be used
+	 * with the currently supported options, so it is safe to leave these
+	 * uninitialized.
+	 */
+
+	/** \private     Reserved member. */
+	void *reserved_ptr1;
+
+	/** \private     Reserved member. */
+	void *reserved_ptr2;
+
+	/** \private     Reserved member. */
+	void *reserved_ptr3;
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int1;
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int2;
+
+	/** \private     Reserved member. */
+	lzma_vli reserved_int3;
+
+	/** \private     Reserved member. */
+	lzma_vli reserved_int4;
+
+	/** \private     Reserved member. */
+	lzma_vli reserved_int5;
+
+	/** \private     Reserved member. */
+	lzma_vli reserved_int6;
+
+	/** \private     Reserved member. */
+	lzma_vli reserved_int7;
+
+	/** \private     Reserved member. */
+	lzma_vli reserved_int8;
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum1;
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum2;
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum3;
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum4;
+
+	/**
+	 * \brief       A flag to Block decoder to not verify the Check field
+	 *
+	 * This member is supported by liblzma >= 5.1.4beta if .version >= 1.
+	 *
+	 * If this is set to true, the integrity check won't be calculated
+	 * and verified. Unless you know what you are doing, you should
+	 * leave this to false. (A reason to set this to true is when the
+	 * file integrity is verified externally anyway and you want to
+	 * speed up the decompression, which matters mostly when using
+	 * SHA-256 as the integrity check.)
+	 *
+	 * If .version >= 1, read by:
+	 *   - lzma_block_decoder()
+	 *   - lzma_block_buffer_decode()
+	 *
+	 * Written by (.version is ignored):
+	 *   - lzma_block_header_decode() always sets this to false
+	 */
+	lzma_bool ignore_check;
+
+	/** \private     Reserved member. */
+	lzma_bool reserved_bool2;
+
+	/** \private     Reserved member. */
+	lzma_bool reserved_bool3;
+
+	/** \private     Reserved member. */
+	lzma_bool reserved_bool4;
+
+	/** \private     Reserved member. */
+	lzma_bool reserved_bool5;
+
+	/** \private     Reserved member. */
+	lzma_bool reserved_bool6;
+
+	/** \private     Reserved member. */
+	lzma_bool reserved_bool7;
+
+	/** \private     Reserved member. */
+	lzma_bool reserved_bool8;
+
+} lzma_block;
+
+
+/**
+ * \brief       Decode the Block Header Size field
+ *
+ * To decode Block Header using lzma_block_header_decode(), the size of the
+ * Block Header has to be known and stored into lzma_block.header_size.
+ * The size can be calculated from the first byte of a Block using this macro.
+ * Note that if the first byte is 0x00, it indicates beginning of Index; use
+ * this macro only when the byte is not 0x00.
+ *
+ * There is no encoding macro because lzma_block_header_size() and
+ * lzma_block_header_encode() should be used.
+ */
+#define lzma_block_header_size_decode(b) (((uint32_t)(b) + 1) * 4)
+
+
+/**
+ * \brief       Calculate Block Header Size
+ *
+ * Calculate the minimum size needed for the Block Header field using the
+ * settings specified in the lzma_block structure. Note that it is OK to
+ * increase the calculated header_size value as long as it is a multiple of
+ * four and doesn't exceed LZMA_BLOCK_HEADER_SIZE_MAX. Increasing header_size
+ * just means that lzma_block_header_encode() will add Header Padding.
+ *
+ * \note        This doesn't check that all the options are valid i.e. this
+ *              may return LZMA_OK even if lzma_block_header_encode() or
+ *              lzma_block_encoder() would fail. If you want to validate the
+ *              filter chain, consider using lzma_memlimit_encoder() which as
+ *              a side-effect validates the filter chain.
+ *
+ * \param       block   Block options
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Size calculated successfully and stored to
+ *                block->header_size.
+ *              - LZMA_OPTIONS_ERROR: Unsupported version, filters or
+ *                filter options.
+ *              - LZMA_PROG_ERROR: Invalid values like compressed_size == 0.
+ */
+extern LZMA_API(lzma_ret) lzma_block_header_size(lzma_block *block)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Encode Block Header
+ *
+ * The caller must have calculated the size of the Block Header already with
+ * lzma_block_header_size(). If a value larger than the one calculated by
+ * lzma_block_header_size() is used, the Block Header will be padded to the
+ * specified size.
+ *
+ * \param       block       Block options to be encoded.
+ * \param[out]  out         Beginning of the output buffer. This must be
+ *                          at least block->header_size bytes.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Encoding was successful. block->header_size
+ *                bytes were written to output buffer.
+ *              - LZMA_OPTIONS_ERROR: Invalid or unsupported options.
+ *              - LZMA_PROG_ERROR: Invalid arguments, for example
+ *                block->header_size is invalid or block->filters is NULL.
+ */
+extern LZMA_API(lzma_ret) lzma_block_header_encode(
+		const lzma_block *block, uint8_t *out)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Decode Block Header
+ *
+ * block->version should (usually) be set to the highest value supported
+ * by the application. If the application sets block->version to a value
+ * higher than supported by the current liblzma version, this function will
+ * downgrade block->version to the highest value supported by it. Thus one
+ * should check the value of block->version after calling this function if
+ * block->version was set to a non-zero value and the application doesn't
+ * otherwise know that the liblzma version being used is new enough to
+ * support the specified block->version.
+ *
+ * The size of the Block Header must have already been decoded with
+ * lzma_block_header_size_decode() macro and stored to block->header_size.
+ *
+ * The integrity check type from Stream Header must have been stored
+ * to block->check.
+ *
+ * block->filters must have been allocated, but they don't need to be
+ * initialized (possible existing filter options are not freed).
+ *
+ * \param[out]  block       Destination for Block options
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() (and also free()
+ *                          if an error occurs).
+ * \param       in          Beginning of the input buffer. This must be
+ *                          at least block->header_size bytes.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Decoding was successful. block->header_size
+ *                bytes were read from the input buffer.
+ *              - LZMA_OPTIONS_ERROR: The Block Header specifies some
+ *                unsupported options such as unsupported filters. This can
+ *                happen also if block->version was set to a too low value
+ *                compared to what would be required to properly represent
+ *                the information stored in the Block Header.
+ *              - LZMA_DATA_ERROR: Block Header is corrupt, for example,
+ *                the CRC32 doesn't match.
+ *              - LZMA_PROG_ERROR: Invalid arguments, for example
+ *                block->header_size is invalid or block->filters is NULL.
+ */
+extern LZMA_API(lzma_ret) lzma_block_header_decode(lzma_block *block,
+		const lzma_allocator *allocator, const uint8_t *in)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Validate and set Compressed Size according to Unpadded Size
+ *
+ * Block Header stores Compressed Size, but Index has Unpadded Size. If the
+ * application has already parsed the Index and is now decoding Blocks,
+ * it can calculate Compressed Size from Unpadded Size. This function does
+ * exactly that with error checking:
+ *
+ *  - Compressed Size calculated from Unpadded Size must be positive integer,
+ *    that is, Unpadded Size must be big enough that after Block Header and
+ *    Check fields there's still at least one byte for Compressed Size.
+ *
+ *  - If Compressed Size was present in Block Header, the new value
+ *    calculated from Unpadded Size is compared against the value
+ *    from Block Header.
+ *
+ * \note        This function must be called _after_ decoding the Block Header
+ *              field so that it can properly validate Compressed Size if it
+ *              was present in Block Header.
+ *
+ * \param       block           Block options: block->header_size must
+ *                              already be set with lzma_block_header_size().
+ * \param       unpadded_size   Unpadded Size from the Index field in bytes
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: block->compressed_size was set successfully.
+ *              - LZMA_DATA_ERROR: unpadded_size is too small compared to
+ *                block->header_size and lzma_check_size(block->check).
+ *              - LZMA_PROG_ERROR: Some values are invalid. For example,
+ *                block->header_size must be a multiple of four and
+ *                between 8 and 1024 inclusive.
+ */
+extern LZMA_API(lzma_ret) lzma_block_compressed_size(
+		lzma_block *block, lzma_vli unpadded_size)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Calculate Unpadded Size
+ *
+ * The Index field stores Unpadded Size and Uncompressed Size. The latter
+ * can be taken directly from the lzma_block structure after coding a Block,
+ * but Unpadded Size needs to be calculated from Block Header Size,
+ * Compressed Size, and size of the Check field. This is where this function
+ * is needed.
+ *
+ * \param       block   Block options: block->header_size must already be
+ *                      set with lzma_block_header_size().
+ *
+ * \return      Unpadded Size on success, or zero on error.
+ */
+extern LZMA_API(lzma_vli) lzma_block_unpadded_size(const lzma_block *block)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Calculate the total encoded size of a Block
+ *
+ * This is equivalent to lzma_block_unpadded_size() except that the returned
+ * value includes the size of the Block Padding field.
+ *
+ * \param       block   Block options: block->header_size must already be
+ *                      set with lzma_block_header_size().
+ *
+ * \return      On success, total encoded size of the Block. On error,
+ *              zero is returned.
+ */
+extern LZMA_API(lzma_vli) lzma_block_total_size(const lzma_block *block)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Initialize .xz Block encoder
+ *
+ * Valid actions for lzma_code() are LZMA_RUN, LZMA_SYNC_FLUSH (only if the
+ * filter chain supports it), and LZMA_FINISH.
+ *
+ * The Block encoder encodes the Block Data, Block Padding, and Check value.
+ * It does NOT encode the Block Header which can be encoded with
+ * lzma_block_header_encode().
+ *
+ * \param       strm    Pointer to lzma_stream that is at least initialized
+ *                      with LZMA_STREAM_INIT.
+ * \param       block   Block options: block->version, block->check,
+ *                      and block->filters must have been initialized.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: All good, continue with lzma_code().
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_UNSUPPORTED_CHECK: block->check specifies a Check ID
+ *                that is not supported by this build of liblzma. Initializing
+ *                the encoder failed.
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_block_encoder(
+		lzma_stream *strm, lzma_block *block)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Initialize .xz Block decoder
+ *
+ * Valid actions for lzma_code() are LZMA_RUN and LZMA_FINISH. Using
+ * LZMA_FINISH is not required. It is supported only for convenience.
+ *
+ * The Block decoder decodes the Block Data, Block Padding, and Check value.
+ * It does NOT decode the Block Header which can be decoded with
+ * lzma_block_header_decode().
+ *
+ * \param       strm    Pointer to lzma_stream that is at least initialized
+ *                      with LZMA_STREAM_INIT.
+ * \param       block   Block options
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: All good, continue with lzma_code().
+ *              - LZMA_PROG_ERROR
+ *              - LZMA_MEM_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_block_decoder(
+		lzma_stream *strm, lzma_block *block)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Calculate maximum output size for single-call Block encoding
+ *
+ * This is equivalent to lzma_stream_buffer_bound() but for .xz Blocks.
+ * See the documentation of lzma_stream_buffer_bound().
+ *
+ * \param       uncompressed_size   Size of the data to be encoded with the
+ *                                  single-call Block encoder.
+ *
+ * \return      Maximum output size in bytes for single-call Block encoding.
+ */
+extern LZMA_API(size_t) lzma_block_buffer_bound(size_t uncompressed_size)
+		lzma_nothrow;
+
+
+/**
+ * \brief       Single-call .xz Block encoder
+ *
+ * In contrast to the multi-call encoder initialized with
+ * lzma_block_encoder(), this function encodes also the Block Header. This
+ * is required to make it possible to write appropriate Block Header also
+ * in case the data isn't compressible, and different filter chain has to be
+ * used to encode the data in uncompressed form using uncompressed chunks
+ * of the LZMA2 filter.
+ *
+ * When the data isn't compressible, header_size, compressed_size, and
+ * uncompressed_size are set just like when the data was compressible, but
+ * it is possible that header_size is too small to hold the filter chain
+ * specified in block->filters, because that isn't necessarily the filter
+ * chain that was actually used to encode the data. lzma_block_unpadded_size()
+ * still works normally, because it doesn't read the filters array.
+ *
+ * \param       block       Block options: block->version, block->check,
+ *                          and block->filters must have been initialized.
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ * \param       in          Beginning of the input buffer
+ * \param       in_size     Size of the input buffer
+ * \param[out]  out         Beginning of the output buffer
+ * \param[out]  out_pos     The next byte will be written to out[*out_pos].
+ *                          *out_pos is updated only if encoding succeeds.
+ * \param       out_size    Size of the out buffer; the first byte into
+ *                          which no data is written to is out[out_size].
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Encoding was successful.
+ *              - LZMA_BUF_ERROR: Not enough output buffer space.
+ *              - LZMA_UNSUPPORTED_CHECK
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_DATA_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_block_buffer_encode(
+		lzma_block *block, const lzma_allocator *allocator,
+		const uint8_t *in, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Single-call uncompressed .xz Block encoder
+ *
+ * This is like lzma_block_buffer_encode() except this doesn't try to
+ * compress the data and instead encodes the data using LZMA2 uncompressed
+ * chunks. The required output buffer size can be determined with
+ * lzma_block_buffer_bound().
+ *
+ * Since the data won't be compressed, this function ignores block->filters.
+ * This function doesn't take lzma_allocator because this function doesn't
+ * allocate any memory from the heap.
+ *
+ * \param       block       Block options: block->version, block->check,
+ *                          and block->filters must have been initialized.
+ * \param       in          Beginning of the input buffer
+ * \param       in_size     Size of the input buffer
+ * \param[out]  out         Beginning of the output buffer
+ * \param[out]  out_pos     The next byte will be written to out[*out_pos].
+ *                          *out_pos is updated only if encoding succeeds.
+ * \param       out_size    Size of the out buffer; the first byte into
+ *                          which no data is written to is out[out_size].
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Encoding was successful.
+ *              - LZMA_BUF_ERROR: Not enough output buffer space.
+ *              - LZMA_UNSUPPORTED_CHECK
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_DATA_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_block_uncomp_encode(lzma_block *block,
+		const uint8_t *in, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Single-call .xz Block decoder
+ *
+ * This is single-call equivalent of lzma_block_decoder(), and requires that
+ * the caller has already decoded Block Header and checked its memory usage.
+ *
+ * \param       block       Block options
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ * \param       in          Beginning of the input buffer
+ * \param       in_pos      The next byte will be read from in[*in_pos].
+ *                          *in_pos is updated only if decoding succeeds.
+ * \param       in_size     Size of the input buffer; the first byte that
+ *                          won't be read is in[in_size].
+ * \param[out]  out         Beginning of the output buffer
+ * \param[out]  out_pos     The next byte will be written to out[*out_pos].
+ *                          *out_pos is updated only if encoding succeeds.
+ * \param       out_size    Size of the out buffer; the first byte into
+ *                          which no data is written to is out[out_size].
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Decoding was successful.
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_DATA_ERROR
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_BUF_ERROR: Output buffer was too small.
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_block_buffer_decode(
+		lzma_block *block, const lzma_allocator *allocator,
+		const uint8_t *in, size_t *in_pos, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+		lzma_nothrow;
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/check.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/check.h
new file mode 100644
index 00000000000..e7a50ed3a3c
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/check.h
@@ -0,0 +1,163 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/**
+ * \file        lzma/check.h
+ * \brief       Integrity checks
+ * \note        Never include this file directly. Use  instead.
+ */
+
+/*
+ * Author: Lasse Collin
+ */
+
+#ifndef LZMA_H_INTERNAL
+#	error Never include this file directly. Use  instead.
+#endif
+
+
+/**
+ * \brief       Type of the integrity check (Check ID)
+ *
+ * The .xz format supports multiple types of checks that are calculated
+ * from the uncompressed data. They vary in both speed and ability to
+ * detect errors.
+ */
+typedef enum {
+	LZMA_CHECK_NONE     = 0,
+		/**<
+		 * No Check is calculated.
+		 *
+		 * Size of the Check field: 0 bytes
+		 */
+
+	LZMA_CHECK_CRC32    = 1,
+		/**<
+		 * CRC32 using the polynomial from the IEEE 802.3 standard
+		 *
+		 * Size of the Check field: 4 bytes
+		 */
+
+	LZMA_CHECK_CRC64    = 4,
+		/**<
+		 * CRC64 using the polynomial from the ECMA-182 standard
+		 *
+		 * Size of the Check field: 8 bytes
+		 */
+
+	LZMA_CHECK_SHA256   = 10
+		/**<
+		 * SHA-256
+		 *
+		 * Size of the Check field: 32 bytes
+		 */
+} lzma_check;
+
+
+/**
+ * \brief       Maximum valid Check ID
+ *
+ * The .xz file format specification specifies 16 Check IDs (0-15). Some
+ * of them are only reserved, that is, no actual Check algorithm has been
+ * assigned. When decoding, liblzma still accepts unknown Check IDs for
+ * future compatibility. If a valid but unsupported Check ID is detected,
+ * liblzma can indicate a warning; see the flags LZMA_TELL_NO_CHECK,
+ * LZMA_TELL_UNSUPPORTED_CHECK, and LZMA_TELL_ANY_CHECK in container.h.
+ */
+#define LZMA_CHECK_ID_MAX 15
+
+
+/**
+ * \brief       Test if the given Check ID is supported
+ *
+ * LZMA_CHECK_NONE and LZMA_CHECK_CRC32 are always supported (even if
+ * liblzma is built with limited features).
+ *
+ * \note        It is safe to call this with a value that is not in the
+ *              range [0, 15]; in that case the return value is always false.
+ *
+ * \param       check   Check ID
+ *
+ * \return      lzma_bool:
+ *              - true if Check ID is supported by this liblzma build.
+ *              - false otherwise.
+ */
+extern LZMA_API(lzma_bool) lzma_check_is_supported(lzma_check check)
+		lzma_nothrow lzma_attr_const;
+
+
+/**
+ * \brief       Get the size of the Check field with the given Check ID
+ *
+ * Although not all Check IDs have a check algorithm associated, the size of
+ * every Check is already frozen. This function returns the size (in bytes) of
+ * the Check field with the specified Check ID. The values are:
+ * { 0, 4, 4, 4, 8, 8, 8, 16, 16, 16, 32, 32, 32, 64, 64, 64 }
+ *
+ * \param       check   Check ID
+ *
+ * \return      Size of the Check field in bytes. If the argument is not in
+ *              the range [0, 15], UINT32_MAX is returned.
+ */
+extern LZMA_API(uint32_t) lzma_check_size(lzma_check check)
+		lzma_nothrow lzma_attr_const;
+
+
+/**
+ * \brief       Maximum size of a Check field
+ */
+#define LZMA_CHECK_SIZE_MAX 64
+
+
+/**
+ * \brief       Calculate CRC32
+ *
+ * Calculate CRC32 using the polynomial from the IEEE 802.3 standard.
+ *
+ * \param       buf     Pointer to the input buffer
+ * \param       size    Size of the input buffer
+ * \param       crc     Previously returned CRC value. This is used to
+ *                      calculate the CRC of a big buffer in smaller chunks.
+ *                      Set to zero when starting a new calculation.
+ *
+ * \return      Updated CRC value, which can be passed to this function
+ *              again to continue CRC calculation.
+ */
+extern LZMA_API(uint32_t) lzma_crc32(
+		const uint8_t *buf, size_t size, uint32_t crc)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Calculate CRC64
+ *
+ * Calculate CRC64 using the polynomial from the ECMA-182 standard.
+ *
+ * This function is used similarly to lzma_crc32().
+ *
+ * \param       buf     Pointer to the input buffer
+ * \param       size    Size of the input buffer
+ * \param       crc     Previously returned CRC value. This is used to
+ *                      calculate the CRC of a big buffer in smaller chunks.
+ *                      Set to zero when starting a new calculation.
+ *
+ * \return      Updated CRC value, which can be passed to this function
+ *              again to continue CRC calculation.
+ */
+extern LZMA_API(uint64_t) lzma_crc64(
+		const uint8_t *buf, size_t size, uint64_t crc)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Get the type of the integrity check
+ *
+ * This function can be called only immediately after lzma_code() has
+ * returned LZMA_NO_CHECK, LZMA_UNSUPPORTED_CHECK, or LZMA_GET_CHECK.
+ * Calling this function in any other situation has undefined behavior.
+ *
+ * \param       strm    Pointer to lzma_stream meeting the above conditions.
+ *
+ * \return      Check ID in the lzma_stream, or undefined if called improperly.
+ */
+extern LZMA_API(lzma_check) lzma_get_check(const lzma_stream *strm)
+		lzma_nothrow;
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/container.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/container.h
new file mode 100644
index 00000000000..ee5d77e4f1a
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/container.h
@@ -0,0 +1,995 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/**
+ * \file        lzma/container.h
+ * \brief       File formats
+ * \note        Never include this file directly. Use  instead.
+ */
+
+/*
+ * Author: Lasse Collin
+ */
+
+#ifndef LZMA_H_INTERNAL
+#	error Never include this file directly. Use  instead.
+#endif
+
+
+/************
+ * Encoding *
+ ************/
+
+/**
+ * \brief       Default compression preset
+ *
+ * It's not straightforward to recommend a default preset, because in some
+ * cases keeping the resource usage relatively low is more important that
+ * getting the maximum compression ratio.
+ */
+#define LZMA_PRESET_DEFAULT     UINT32_C(6)
+
+
+/**
+ * \brief       Mask for preset level
+ *
+ * This is useful only if you need to extract the level from the preset
+ * variable. That should be rare.
+ */
+#define LZMA_PRESET_LEVEL_MASK  UINT32_C(0x1F)
+
+
+/*
+ * Preset flags
+ *
+ * Currently only one flag is defined.
+ */
+
+/**
+ * \brief       Extreme compression preset
+ *
+ * This flag modifies the preset to make the encoding significantly slower
+ * while improving the compression ratio only marginally. This is useful
+ * when you don't mind spending time to get as small result as possible.
+ *
+ * This flag doesn't affect the memory usage requirements of the decoder (at
+ * least not significantly). The memory usage of the encoder may be increased
+ * a little but only at the lowest preset levels (0-3).
+ */
+#define LZMA_PRESET_EXTREME       (UINT32_C(1) << 31)
+
+
+/**
+ * \brief       Multithreading options
+ */
+typedef struct {
+	/**
+	 * \brief       Flags
+	 *
+	 * Set this to zero if no flags are wanted.
+	 *
+	 * Encoder: No flags are currently supported.
+	 *
+	 * Decoder: Bitwise-or of zero or more of the decoder flags:
+	 * - LZMA_TELL_NO_CHECK
+	 * - LZMA_TELL_UNSUPPORTED_CHECK
+	 * - LZMA_TELL_ANY_CHECK
+	 * - LZMA_IGNORE_CHECK
+	 * - LZMA_CONCATENATED
+	 * - LZMA_FAIL_FAST
+	 */
+	uint32_t flags;
+
+	/**
+	 * \brief       Number of worker threads to use
+	 */
+	uint32_t threads;
+
+	/**
+	 * \brief       Encoder only: Maximum uncompressed size of a Block
+	 *
+	 * The encoder will start a new .xz Block every block_size bytes.
+	 * Using LZMA_FULL_FLUSH or LZMA_FULL_BARRIER with lzma_code()
+	 * the caller may tell liblzma to start a new Block earlier.
+	 *
+	 * With LZMA2, a recommended block size is 2-4 times the LZMA2
+	 * dictionary size. With very small dictionaries, it is recommended
+	 * to use at least 1 MiB block size for good compression ratio, even
+	 * if this is more than four times the dictionary size. Note that
+	 * these are only recommendations for typical use cases; feel free
+	 * to use other values. Just keep in mind that using a block size
+	 * less than the LZMA2 dictionary size is waste of RAM.
+	 *
+	 * Set this to 0 to let liblzma choose the block size depending
+	 * on the compression options. For LZMA2 it will be 3*dict_size
+	 * or 1 MiB, whichever is more.
+	 *
+	 * For each thread, about 3 * block_size bytes of memory will be
+	 * allocated. This may change in later liblzma versions. If so,
+	 * the memory usage will probably be reduced, not increased.
+	 */
+	uint64_t block_size;
+
+	/**
+	 * \brief       Timeout to allow lzma_code() to return early
+	 *
+	 * Multithreading can make liblzma consume input and produce
+	 * output in a very bursty way: it may first read a lot of input
+	 * to fill internal buffers, then no input or output occurs for
+	 * a while.
+	 *
+	 * In single-threaded mode, lzma_code() won't return until it has
+	 * either consumed all the input or filled the output buffer. If
+	 * this is done in multithreaded mode, it may cause a call
+	 * lzma_code() to take even tens of seconds, which isn't acceptable
+	 * in all applications.
+	 *
+	 * To avoid very long blocking times in lzma_code(), a timeout
+	 * (in milliseconds) may be set here. If lzma_code() would block
+	 * longer than this number of milliseconds, it will return with
+	 * LZMA_OK. Reasonable values are 100 ms or more. The xz command
+	 * line tool uses 300 ms.
+	 *
+	 * If long blocking times are acceptable, set timeout to a special
+	 * value of 0. This will disable the timeout mechanism and will make
+	 * lzma_code() block until all the input is consumed or the output
+	 * buffer has been filled.
+	 *
+	 * \note        Even with a timeout, lzma_code() might sometimes take
+	 *              a long time to return. No timing guarantees are made.
+	 */
+	uint32_t timeout;
+
+	/**
+	 * \brief       Encoder only: Compression preset
+	 *
+	 * The preset is set just like with lzma_easy_encoder().
+	 * The preset is ignored if filters below is non-NULL.
+	 */
+	uint32_t preset;
+
+	/**
+	 * \brief       Encoder only: Filter chain (alternative to a preset)
+	 *
+	 * If this is NULL, the preset above is used. Otherwise the preset
+	 * is ignored and the filter chain specified here is used.
+	 */
+	const lzma_filter *filters;
+
+	/**
+	 * \brief       Encoder only: Integrity check type
+	 *
+	 * See check.h for available checks. The xz command line tool
+	 * defaults to LZMA_CHECK_CRC64, which is a good choice if you
+	 * are unsure.
+	 */
+	lzma_check check;
+
+	/*
+	 * Reserved space to allow possible future extensions without
+	 * breaking the ABI. You should not touch these, because the names
+	 * of these variables may change. These are and will never be used
+	 * with the currently supported options, so it is safe to leave these
+	 * uninitialized.
+	 */
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum1;
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum2;
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum3;
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int1;
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int2;
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int3;
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int4;
+
+	/**
+	 * \brief       Memory usage limit to reduce the number of threads
+	 *
+	 * Encoder: Ignored.
+	 *
+	 * Decoder:
+	 *
+	 * If the number of threads has been set so high that more than
+	 * memlimit_threading bytes of memory would be needed, the number
+	 * of threads will be reduced so that the memory usage will not exceed
+	 * memlimit_threading bytes. However, if memlimit_threading cannot
+	 * be met even in single-threaded mode, then decoding will continue
+	 * in single-threaded mode and memlimit_threading may be exceeded
+	 * even by a large amount. That is, memlimit_threading will never make
+	 * lzma_code() return LZMA_MEMLIMIT_ERROR. To truly cap the memory
+	 * usage, see memlimit_stop below.
+	 *
+	 * Setting memlimit_threading to UINT64_MAX or a similar huge value
+	 * means that liblzma is allowed to keep the whole compressed file
+	 * and the whole uncompressed file in memory in addition to the memory
+	 * needed by the decompressor data structures used by each thread!
+	 * In other words, a reasonable value limit must be set here or it
+	 * will cause problems sooner or later. If you have no idea what
+	 * a reasonable value could be, try lzma_physmem() / 4 as a starting
+	 * point. Setting this limit will never prevent decompression of
+	 * a file; this will only reduce the number of threads.
+	 *
+	 * If memlimit_threading is greater than memlimit_stop, then the value
+	 * of memlimit_stop will be used for both.
+	 */
+	uint64_t memlimit_threading;
+
+	/**
+	 * \brief       Memory usage limit that should never be exceeded
+	 *
+	 * Encoder: Ignored.
+	 *
+	 * Decoder: If decompressing will need more than this amount of
+	 * memory even in the single-threaded mode, then lzma_code() will
+	 * return LZMA_MEMLIMIT_ERROR.
+	 */
+	uint64_t memlimit_stop;
+
+	/** \private     Reserved member. */
+	uint64_t reserved_int7;
+
+	/** \private     Reserved member. */
+	uint64_t reserved_int8;
+
+	/** \private     Reserved member. */
+	void *reserved_ptr1;
+
+	/** \private     Reserved member. */
+	void *reserved_ptr2;
+
+	/** \private     Reserved member. */
+	void *reserved_ptr3;
+
+	/** \private     Reserved member. */
+	void *reserved_ptr4;
+
+} lzma_mt;
+
+
+/**
+ * \brief       Calculate approximate memory usage of easy encoder
+ *
+ * This function is a wrapper for lzma_raw_encoder_memusage().
+ *
+ * \param       preset  Compression preset (level and possible flags)
+ *
+ * \return      Number of bytes of memory required for the given
+ *              preset when encoding or UINT64_MAX on error.
+ */
+extern LZMA_API(uint64_t) lzma_easy_encoder_memusage(uint32_t preset)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Calculate approximate decoder memory usage of a preset
+ *
+ * This function is a wrapper for lzma_raw_decoder_memusage().
+ *
+ * \param       preset  Compression preset (level and possible flags)
+ *
+ * \return      Number of bytes of memory required to decompress a file
+ *              that was compressed using the given preset or UINT64_MAX
+ *              on error.
+ */
+extern LZMA_API(uint64_t) lzma_easy_decoder_memusage(uint32_t preset)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Initialize .xz Stream encoder using a preset number
+ *
+ * This function is intended for those who just want to use the basic features
+ * of liblzma (that is, most developers out there).
+ *
+ * If initialization fails (return value is not LZMA_OK), all the memory
+ * allocated for *strm by liblzma is always freed. Thus, there is no need
+ * to call lzma_end() after failed initialization.
+ *
+ * If initialization succeeds, use lzma_code() to do the actual encoding.
+ * Valid values for 'action' (the second argument of lzma_code()) are
+ * LZMA_RUN, LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, and LZMA_FINISH. In future,
+ * there may be compression levels or flags that don't support LZMA_SYNC_FLUSH.
+ *
+ * \param       strm    Pointer to lzma_stream that is at least initialized
+ *                      with LZMA_STREAM_INIT.
+ * \param       preset  Compression preset to use. A preset consist of level
+ *                      number and zero or more flags. Usually flags aren't
+ *                      used, so preset is simply a number [0, 9] which match
+ *                      the options -0 ... -9 of the xz command line tool.
+ *                      Additional flags can be set using bitwise-or with
+ *                      the preset level number, e.g. 6 | LZMA_PRESET_EXTREME.
+ * \param       check   Integrity check type to use. See check.h for available
+ *                      checks. The xz command line tool defaults to
+ *                      LZMA_CHECK_CRC64, which is a good choice if you are
+ *                      unsure. LZMA_CHECK_CRC32 is good too as long as the
+ *                      uncompressed file is not many gigabytes.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Initialization succeeded. Use lzma_code() to
+ *                encode your data.
+ *              - LZMA_MEM_ERROR: Memory allocation failed.
+ *              - LZMA_OPTIONS_ERROR: The given compression preset is not
+ *                supported by this build of liblzma.
+ *              - LZMA_UNSUPPORTED_CHECK: The given check type is not
+ *                supported by this liblzma build.
+ *              - LZMA_PROG_ERROR: One or more of the parameters have values
+ *                that will never be valid. For example, strm == NULL.
+ */
+extern LZMA_API(lzma_ret) lzma_easy_encoder(
+		lzma_stream *strm, uint32_t preset, lzma_check check)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Single-call .xz Stream encoding using a preset number
+ *
+ * The maximum required output buffer size can be calculated with
+ * lzma_stream_buffer_bound().
+ *
+ * \param       preset      Compression preset to use. See the description
+ *                          in lzma_easy_encoder().
+ * \param       check       Type of the integrity check to calculate from
+ *                          uncompressed data.
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ * \param       in          Beginning of the input buffer
+ * \param       in_size     Size of the input buffer
+ * \param[out]  out         Beginning of the output buffer
+ * \param[out]  out_pos     The next byte will be written to out[*out_pos].
+ *                          *out_pos is updated only if encoding succeeds.
+ * \param       out_size    Size of the out buffer; the first byte into
+ *                          which no data is written to is out[out_size].
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Encoding was successful.
+ *              - LZMA_BUF_ERROR: Not enough output buffer space.
+ *              - LZMA_UNSUPPORTED_CHECK
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_DATA_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_easy_buffer_encode(
+		uint32_t preset, lzma_check check,
+		const lzma_allocator *allocator,
+		const uint8_t *in, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
+
+
+/**
+ * \brief       Initialize .xz Stream encoder using a custom filter chain
+ *
+ * \param       strm    Pointer to lzma_stream that is at least initialized
+ *                      with LZMA_STREAM_INIT.
+ * \param       filters Array of filters terminated with
+ *                      .id == LZMA_VLI_UNKNOWN. See filters.h for more
+ *                      information.
+ * \param       check   Type of the integrity check to calculate from
+ *                      uncompressed data.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Initialization was successful.
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_UNSUPPORTED_CHECK
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_stream_encoder(lzma_stream *strm,
+		const lzma_filter *filters, lzma_check check)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Calculate approximate memory usage of multithreaded .xz encoder
+ *
+ * Since doing the encoding in threaded mode doesn't affect the memory
+ * requirements of single-threaded decompressor, you can use
+ * lzma_easy_decoder_memusage(options->preset) or
+ * lzma_raw_decoder_memusage(options->filters) to calculate
+ * the decompressor memory requirements.
+ *
+ * \param       options Compression options
+ *
+ * \return      Number of bytes of memory required for encoding with the
+ *              given options. If an error occurs, for example due to
+ *              unsupported preset or filter chain, UINT64_MAX is returned.
+ */
+extern LZMA_API(uint64_t) lzma_stream_encoder_mt_memusage(
+		const lzma_mt *options) lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Initialize multithreaded .xz Stream encoder
+ *
+ * This provides the functionality of lzma_easy_encoder() and
+ * lzma_stream_encoder() as a single function for multithreaded use.
+ *
+ * The supported actions for lzma_code() are LZMA_RUN, LZMA_FULL_FLUSH,
+ * LZMA_FULL_BARRIER, and LZMA_FINISH. Support for LZMA_SYNC_FLUSH might be
+ * added in the future.
+ *
+ * \param       strm    Pointer to lzma_stream that is at least initialized
+ *                      with LZMA_STREAM_INIT.
+ * \param       options Pointer to multithreaded compression options
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_UNSUPPORTED_CHECK
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_stream_encoder_mt(
+		lzma_stream *strm, const lzma_mt *options)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Calculate recommended Block size for multithreaded .xz encoder
+ *
+ * This calculates a recommended Block size for multithreaded encoding given
+ * a filter chain. This is used internally by lzma_stream_encoder_mt() to
+ * determine the Block size if the block_size member is not set to the
+ * special value of 0 in the lzma_mt options struct.
+ *
+ * If one wishes to change the filters between Blocks, this function is
+ * helpful to set the block_size member of the lzma_mt struct before calling
+ * lzma_stream_encoder_mt(). Since the block_size member represents the
+ * maximum possible Block size for the multithreaded .xz encoder, one can
+ * use this function to find the maximum recommended Block size based on
+ * all planned filter chains. Otherwise, the multithreaded encoder will
+ * base its maximum Block size on the first filter chain used (if the
+ * block_size member is not set), which may unnecessarily limit the Block
+ * size for a later filter chain.
+ *
+ * \param       filters   Array of filters terminated with
+ *                        .id == LZMA_VLI_UNKNOWN.
+ *
+ * \return      Recommended Block size in bytes, or UINT64_MAX if
+ *              an error occurred.
+ */
+extern LZMA_API(uint64_t) lzma_mt_block_size(const lzma_filter *filters)
+		lzma_nothrow;
+
+
+/**
+ * \brief       Initialize .lzma encoder (legacy file format)
+ *
+ * The .lzma format is sometimes called the LZMA_Alone format, which is the
+ * reason for the name of this function. The .lzma format supports only the
+ * LZMA1 filter. There is no support for integrity checks like CRC32.
+ *
+ * Use this function if and only if you need to create files readable by
+ * legacy LZMA tools such as LZMA Utils 4.32.x. Moving to the .xz format
+ * is strongly recommended.
+ *
+ * The valid action values for lzma_code() are LZMA_RUN and LZMA_FINISH.
+ * No kind of flushing is supported, because the file format doesn't make
+ * it possible.
+ *
+ * \param       strm    Pointer to lzma_stream that is at least initialized
+ *                      with LZMA_STREAM_INIT.
+ * \param       options Pointer to encoder options
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_alone_encoder(
+		lzma_stream *strm, const lzma_options_lzma *options)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Calculate output buffer size for single-call Stream encoder
+ *
+ * When trying to compress incompressible data, the encoded size will be
+ * slightly bigger than the input data. This function calculates how much
+ * output buffer space is required to be sure that lzma_stream_buffer_encode()
+ * doesn't return LZMA_BUF_ERROR.
+ *
+ * The calculated value is not exact, but it is guaranteed to be big enough.
+ * The actual maximum output space required may be slightly smaller (up to
+ * about 100 bytes). This should not be a problem in practice.
+ *
+ * If the calculated maximum size doesn't fit into size_t or would make the
+ * Stream grow past LZMA_VLI_MAX (which should never happen in practice),
+ * zero is returned to indicate the error.
+ *
+ * \note        The limit calculated by this function applies only to
+ *              single-call encoding. Multi-call encoding may (and probably
+ *              will) have larger maximum expansion when encoding
+ *              incompressible data. Currently there is no function to
+ *              calculate the maximum expansion of multi-call encoding.
+ *
+ * \param       uncompressed_size   Size in bytes of the uncompressed
+ *                                  input data
+ *
+ * \return      Maximum number of bytes needed to store the compressed data.
+ */
+extern LZMA_API(size_t) lzma_stream_buffer_bound(size_t uncompressed_size)
+		lzma_nothrow;
+
+
+/**
+ * \brief       Single-call .xz Stream encoder
+ *
+ * \param       filters     Array of filters terminated with
+ *                          .id == LZMA_VLI_UNKNOWN. See filters.h for more
+ *                          information.
+ * \param       check       Type of the integrity check to calculate from
+ *                          uncompressed data.
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ * \param       in          Beginning of the input buffer
+ * \param       in_size     Size of the input buffer
+ * \param[out]  out         Beginning of the output buffer
+ * \param[out]  out_pos     The next byte will be written to out[*out_pos].
+ *                          *out_pos is updated only if encoding succeeds.
+ * \param       out_size    Size of the out buffer; the first byte into
+ *                          which no data is written to is out[out_size].
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Encoding was successful.
+ *              - LZMA_BUF_ERROR: Not enough output buffer space.
+ *              - LZMA_UNSUPPORTED_CHECK
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_DATA_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_stream_buffer_encode(
+		lzma_filter *filters, lzma_check check,
+		const lzma_allocator *allocator,
+		const uint8_t *in, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       MicroLZMA encoder
+ *
+ * The MicroLZMA format is a raw LZMA stream whose first byte (always 0x00)
+ * has been replaced with bitwise-negation of the LZMA properties (lc/lp/pb).
+ * This encoding ensures that the first byte of MicroLZMA stream is never
+ * 0x00. There is no end of payload marker and thus the uncompressed size
+ * must be stored separately. For the best error detection the dictionary
+ * size should be stored separately as well but alternatively one may use
+ * the uncompressed size as the dictionary size when decoding.
+ *
+ * With the MicroLZMA encoder, lzma_code() behaves slightly unusually.
+ * The action argument must be LZMA_FINISH and the return value will never be
+ * LZMA_OK. Thus the encoding is always done with a single lzma_code() after
+ * the initialization. The benefit of the combination of initialization
+ * function and lzma_code() is that memory allocations can be re-used for
+ * better performance.
+ *
+ * lzma_code() will try to encode as much input as is possible to fit into
+ * the given output buffer. If not all input can be encoded, the stream will
+ * be finished without encoding all the input. The caller must check both
+ * input and output buffer usage after lzma_code() (total_in and total_out
+ * in lzma_stream can be convenient). Often lzma_code() can fill the output
+ * buffer completely if there is a lot of input, but sometimes a few bytes
+ * may remain unused because the next LZMA symbol would require more space.
+ *
+ * lzma_stream.avail_out must be at least 6. Otherwise LZMA_PROG_ERROR
+ * will be returned.
+ *
+ * The LZMA dictionary should be reasonably low to speed up the encoder
+ * re-initialization. A good value is bigger than the resulting
+ * uncompressed size of most of the output chunks. For example, if output
+ * size is 4 KiB, dictionary size of 32 KiB or 64 KiB is good. If the
+ * data compresses extremely well, even 128 KiB may be useful.
+ *
+ * The MicroLZMA format and this encoder variant were made with the EROFS
+ * file system in mind. This format may be convenient in other embedded
+ * uses too where many small streams are needed. XZ Embedded includes a
+ * decoder for this format.
+ *
+ * \param       strm    Pointer to lzma_stream that is at least initialized
+ *                      with LZMA_STREAM_INIT.
+ * \param       options Pointer to encoder options
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_STREAM_END: All good. Check the amounts of input used
+ *                and output produced. Store the amount of input used
+ *                (uncompressed size) as it needs to be known to decompress
+ *                the data.
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_PROG_ERROR: In addition to the generic reasons for this
+ *                error code, this may also be returned if there isn't enough
+ *                output space (6 bytes) to create a valid MicroLZMA stream.
+ */
+extern LZMA_API(lzma_ret) lzma_microlzma_encoder(
+		lzma_stream *strm, const lzma_options_lzma *options)
+		lzma_nothrow;
+
+
+/************
+ * Decoding *
+ ************/
+
+/**
+ * This flag makes lzma_code() return LZMA_NO_CHECK if the input stream
+ * being decoded has no integrity check. Note that when used with
+ * lzma_auto_decoder(), all .lzma files will trigger LZMA_NO_CHECK
+ * if LZMA_TELL_NO_CHECK is used.
+ */
+#define LZMA_TELL_NO_CHECK              UINT32_C(0x01)
+
+
+/**
+ * This flag makes lzma_code() return LZMA_UNSUPPORTED_CHECK if the input
+ * stream has an integrity check, but the type of the integrity check is not
+ * supported by this liblzma version or build. Such files can still be
+ * decoded, but the integrity check cannot be verified.
+ */
+#define LZMA_TELL_UNSUPPORTED_CHECK     UINT32_C(0x02)
+
+
+/**
+ * This flag makes lzma_code() return LZMA_GET_CHECK as soon as the type
+ * of the integrity check is known. The type can then be got with
+ * lzma_get_check().
+ */
+#define LZMA_TELL_ANY_CHECK             UINT32_C(0x04)
+
+
+/**
+ * This flag makes lzma_code() not calculate and verify the integrity check
+ * of the compressed data in .xz files. This means that invalid integrity
+ * check values won't be detected and LZMA_DATA_ERROR won't be returned in
+ * such cases.
+ *
+ * This flag only affects the checks of the compressed data itself; the CRC32
+ * values in the .xz headers will still be verified normally.
+ *
+ * Don't use this flag unless you know what you are doing. Possible reasons
+ * to use this flag:
+ *
+ *   - Trying to recover data from a corrupt .xz file.
+ *
+ *   - Speeding up decompression, which matters mostly with SHA-256
+ *     or with files that have compressed extremely well. It's recommended
+ *     to not use this flag for this purpose unless the file integrity is
+ *     verified externally in some other way.
+ *
+ * Support for this flag was added in liblzma 5.1.4beta.
+ */
+#define LZMA_IGNORE_CHECK               UINT32_C(0x10)
+
+
+/**
+ * This flag enables decoding of concatenated files with file formats that
+ * allow concatenating compressed files as is. From the formats currently
+ * supported by liblzma, only the .xz and .lz formats allow concatenated
+ * files. Concatenated files are not allowed with the legacy .lzma format.
+ *
+ * This flag also affects the usage of the 'action' argument for lzma_code().
+ * When LZMA_CONCATENATED is used, lzma_code() won't return LZMA_STREAM_END
+ * unless LZMA_FINISH is used as 'action'. Thus, the application has to set
+ * LZMA_FINISH in the same way as it does when encoding.
+ *
+ * If LZMA_CONCATENATED is not used, the decoders still accept LZMA_FINISH
+ * as 'action' for lzma_code(), but the usage of LZMA_FINISH isn't required.
+ */
+#define LZMA_CONCATENATED               UINT32_C(0x08)
+
+
+/**
+ * This flag makes the threaded decoder report errors (like LZMA_DATA_ERROR)
+ * as soon as they are detected. This saves time when the application has no
+ * interest in a partially decompressed truncated or corrupt file. Note that
+ * due to timing randomness, if the same truncated or corrupt input is
+ * decompressed multiple times with this flag, a different amount of output
+ * may be produced by different runs, and even the error code might vary.
+ *
+ * When using LZMA_FAIL_FAST, it is recommended to use LZMA_FINISH to tell
+ * the decoder when no more input will be coming because it can help fast
+ * detection and reporting of truncated files. Note that in this situation
+ * truncated files might be diagnosed with LZMA_DATA_ERROR instead of
+ * LZMA_OK or LZMA_BUF_ERROR!
+ *
+ * Without this flag the threaded decoder will provide as much output as
+ * possible at first and then report the pending error. This default behavior
+ * matches the single-threaded decoder and provides repeatable behavior
+ * with truncated or corrupt input. There are a few special cases where the
+ * behavior can still differ like memory allocation failures (LZMA_MEM_ERROR).
+ *
+ * Single-threaded decoders currently ignore this flag.
+ *
+ * Support for this flag was added in liblzma 5.3.3alpha. Note that in older
+ * versions this flag isn't supported (LZMA_OPTIONS_ERROR) even by functions
+ * that ignore this flag in newer liblzma versions.
+ */
+#define LZMA_FAIL_FAST                  UINT32_C(0x20)
+
+
+/**
+ * \brief       Initialize .xz Stream decoder
+ *
+ * \param       strm        Pointer to lzma_stream that is at least initialized
+ *                          with LZMA_STREAM_INIT.
+ * \param       memlimit    Memory usage limit as bytes. Use UINT64_MAX
+ *                          to effectively disable the limiter. liblzma
+ *                          5.2.3 and earlier don't allow 0 here and return
+ *                          LZMA_PROG_ERROR; later versions treat 0 as if 1
+ *                          had been specified.
+ * \param       flags       Bitwise-or of zero or more of the decoder flags:
+ *                          LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK,
+ *                          LZMA_TELL_ANY_CHECK, LZMA_IGNORE_CHECK,
+ *                          LZMA_CONCATENATED, LZMA_FAIL_FAST
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Initialization was successful.
+ *              - LZMA_MEM_ERROR: Cannot allocate memory.
+ *              - LZMA_OPTIONS_ERROR: Unsupported flags
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_stream_decoder(
+		lzma_stream *strm, uint64_t memlimit, uint32_t flags)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Initialize multithreaded .xz Stream decoder
+ *
+ * The decoder can decode multiple Blocks in parallel. This requires that each
+ * Block Header contains the Compressed Size and Uncompressed size fields
+ * which are added by the multi-threaded encoder, see lzma_stream_encoder_mt().
+ *
+ * A Stream with one Block will only utilize one thread. A Stream with multiple
+ * Blocks but without size information in Block Headers will be processed in
+ * single-threaded mode in the same way as done by lzma_stream_decoder().
+ * Concatenated Streams are processed one Stream at a time; no inter-Stream
+ * parallelization is done.
+ *
+ * This function behaves like lzma_stream_decoder() when options->threads == 1
+ * and options->memlimit_threading <= 1.
+ *
+ * \param       strm        Pointer to lzma_stream that is at least initialized
+ *                          with LZMA_STREAM_INIT.
+ * \param       options     Pointer to multithreaded compression options
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Initialization was successful.
+ *              - LZMA_MEM_ERROR: Cannot allocate memory.
+ *              - LZMA_MEMLIMIT_ERROR: Memory usage limit was reached.
+ *              - LZMA_OPTIONS_ERROR: Unsupported flags.
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_stream_decoder_mt(
+		lzma_stream *strm, const lzma_mt *options)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Decode .xz, .lzma, and .lz (lzip) files with autodetection
+ *
+ * This decoder autodetects between the .xz, .lzma, and .lz file formats,
+ * and calls lzma_stream_decoder(), lzma_alone_decoder(), or
+ * lzma_lzip_decoder() once the type of the input file has been detected.
+ *
+ * Support for .lz was added in 5.4.0.
+ *
+ * If the flag LZMA_CONCATENATED is used and the input is a .lzma file:
+ * For historical reasons concatenated .lzma files aren't supported.
+ * If there is trailing data after one .lzma stream, lzma_code() will
+ * return LZMA_DATA_ERROR. (lzma_alone_decoder() doesn't have such a check
+ * as it doesn't support any decoder flags. It will return LZMA_STREAM_END
+ * after one .lzma stream.)
+ *
+ * \param       strm        Pointer to lzma_stream that is at least initialized
+ *                          with LZMA_STREAM_INIT.
+ * \param       memlimit    Memory usage limit as bytes. Use UINT64_MAX
+ *                          to effectively disable the limiter. liblzma
+ *                          5.2.3 and earlier don't allow 0 here and return
+ *                          LZMA_PROG_ERROR; later versions treat 0 as if 1
+ *                          had been specified.
+ * \param       flags       Bitwise-or of zero or more of the decoder flags:
+ *                          LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK,
+ *                          LZMA_TELL_ANY_CHECK, LZMA_IGNORE_CHECK,
+ *                          LZMA_CONCATENATED, LZMA_FAIL_FAST
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Initialization was successful.
+ *              - LZMA_MEM_ERROR: Cannot allocate memory.
+ *              - LZMA_OPTIONS_ERROR: Unsupported flags
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_auto_decoder(
+		lzma_stream *strm, uint64_t memlimit, uint32_t flags)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Initialize .lzma decoder (legacy file format)
+ *
+ * Valid 'action' arguments to lzma_code() are LZMA_RUN and LZMA_FINISH.
+ * There is no need to use LZMA_FINISH, but it's allowed because it may
+ * simplify certain types of applications.
+ *
+ * \param       strm        Pointer to lzma_stream that is at least initialized
+ *                          with LZMA_STREAM_INIT.
+ * \param       memlimit    Memory usage limit as bytes. Use UINT64_MAX
+ *                          to effectively disable the limiter. liblzma
+ *                          5.2.3 and earlier don't allow 0 here and return
+ *                          LZMA_PROG_ERROR; later versions treat 0 as if 1
+ *                          had been specified.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_alone_decoder(
+		lzma_stream *strm, uint64_t memlimit)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Initialize .lz (lzip) decoder (a foreign file format)
+ *
+ * This decoder supports the .lz format version 0 and the unextended .lz
+ * format version 1:
+ *
+ *   - Files in the format version 0 were produced by lzip 1.3 and older.
+ *     Such files aren't common but may be found from file archives
+ *     as a few source packages were released in this format. People
+ *     might have old personal files in this format too. Decompression
+ *     support for the format version 0 was removed in lzip 1.18.
+ *
+ *   - lzip 1.3 added decompression support for .lz format version 1 files.
+ *     Compression support was added in lzip 1.4. In lzip 1.6 the .lz format
+ *     version 1 was extended to support the Sync Flush marker. This extension
+ *     is not supported by liblzma. lzma_code() will return LZMA_DATA_ERROR
+ *     at the location of the Sync Flush marker. In practice files with
+ *     the Sync Flush marker are very rare and thus liblzma can decompress
+ *     almost all .lz files.
+ *
+ * Just like with lzma_stream_decoder() for .xz files, LZMA_CONCATENATED
+ * should be used when decompressing normal standalone .lz files.
+ *
+ * The .lz format allows putting non-.lz data at the end of a file after at
+ * least one valid .lz member. That is, one can append custom data at the end
+ * of a .lz file and the decoder is required to ignore it. In liblzma this
+ * is relevant only when LZMA_CONCATENATED is used. In that case lzma_code()
+ * will return LZMA_STREAM_END and leave lzma_stream.next_in pointing to
+ * the first byte of the non-.lz data. An exception to this is if the first
+ * 1-3 bytes of the non-.lz data are identical to the .lz magic bytes
+ * (0x4C, 0x5A, 0x49, 0x50; "LZIP" in US-ASCII). In such a case the 1-3 bytes
+ * will have been ignored by lzma_code(). If one wishes to locate the non-.lz
+ * data reliably, one must ensure that the first byte isn't 0x4C. Actually
+ * one should ensure that none of the first four bytes of trailing data are
+ * equal to the magic bytes because lzip >= 1.20 requires it by default.
+ *
+ * \param       strm        Pointer to lzma_stream that is at least initialized
+ *                          with LZMA_STREAM_INIT.
+ * \param       memlimit    Memory usage limit as bytes. Use UINT64_MAX
+ *                          to effectively disable the limiter.
+ * \param       flags       Bitwise-or of flags, or zero for no flags.
+ *                          All decoder flags listed above are supported
+ *                          although only LZMA_CONCATENATED and (in very rare
+ *                          cases) LZMA_IGNORE_CHECK are actually useful.
+ *                          LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK,
+ *                          and LZMA_FAIL_FAST do nothing. LZMA_TELL_ANY_CHECK
+ *                          is supported for consistency only as CRC32 is
+ *                          always used in the .lz format.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Initialization was successful.
+ *              - LZMA_MEM_ERROR: Cannot allocate memory.
+ *              - LZMA_OPTIONS_ERROR: Unsupported flags
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_lzip_decoder(
+		lzma_stream *strm, uint64_t memlimit, uint32_t flags)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Single-call .xz Stream decoder
+ *
+ * \param       memlimit    Pointer to how much memory the decoder is allowed
+ *                          to allocate. The value pointed by this pointer is
+ *                          modified if and only if LZMA_MEMLIMIT_ERROR is
+ *                          returned.
+ * \param       flags       Bitwise-or of zero or more of the decoder flags:
+ *                          LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK,
+ *                          LZMA_IGNORE_CHECK, LZMA_CONCATENATED,
+ *                          LZMA_FAIL_FAST. Note that LZMA_TELL_ANY_CHECK
+ *                          is not allowed and will return LZMA_PROG_ERROR.
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ * \param       in          Beginning of the input buffer
+ * \param       in_pos      The next byte will be read from in[*in_pos].
+ *                          *in_pos is updated only if decoding succeeds.
+ * \param       in_size     Size of the input buffer; the first byte that
+ *                          won't be read is in[in_size].
+ * \param[out]  out         Beginning of the output buffer
+ * \param[out]  out_pos     The next byte will be written to out[*out_pos].
+ *                          *out_pos is updated only if decoding succeeds.
+ * \param       out_size    Size of the out buffer; the first byte into
+ *                          which no data is written to is out[out_size].
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Decoding was successful.
+ *              - LZMA_FORMAT_ERROR
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_DATA_ERROR
+ *              - LZMA_NO_CHECK: This can be returned only if using
+ *                the LZMA_TELL_NO_CHECK flag.
+ *              - LZMA_UNSUPPORTED_CHECK: This can be returned only if using
+ *                the LZMA_TELL_UNSUPPORTED_CHECK flag.
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_MEMLIMIT_ERROR: Memory usage limit was reached.
+ *                The minimum required memlimit value was stored to *memlimit.
+ *              - LZMA_BUF_ERROR: Output buffer was too small.
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_stream_buffer_decode(
+		uint64_t *memlimit, uint32_t flags,
+		const lzma_allocator *allocator,
+		const uint8_t *in, size_t *in_pos, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       MicroLZMA decoder
+ *
+ * See lzma_microlzma_encoder() for more information.
+ *
+ * The lzma_code() usage with this decoder is completely normal. The
+ * special behavior of lzma_code() applies to lzma_microlzma_encoder() only.
+ *
+ * \param       strm        Pointer to lzma_stream that is at least initialized
+ *                          with LZMA_STREAM_INIT.
+ * \param       comp_size   Compressed size of the MicroLZMA stream.
+ *                          The caller must somehow know this exactly.
+ * \param       uncomp_size Uncompressed size of the MicroLZMA stream.
+ *                          If the exact uncompressed size isn't known, this
+ *                          can be set to a value that is at most as big as
+ *                          the exact uncompressed size would be, but then the
+ *                          next argument uncomp_size_is_exact must be false.
+ * \param       uncomp_size_is_exact
+ *                          If true, uncomp_size must be exactly correct.
+ *                          This will improve error detection at the end of
+ *                          the stream. If the exact uncompressed size isn't
+ *                          known, this must be false. uncomp_size must still
+ *                          be at most as big as the exact uncompressed size
+ *                          is. Setting this to false when the exact size is
+ *                          known will work but error detection at the end of
+ *                          the stream will be weaker.
+ * \param       dict_size   LZMA dictionary size that was used when
+ *                          compressing the data. It is OK to use a bigger
+ *                          value too but liblzma will then allocate more
+ *                          memory than would actually be required and error
+ *                          detection will be slightly worse. (Note that with
+ *                          the implementation in XZ Embedded it doesn't
+ *                          affect the memory usage if one specifies bigger
+ *                          dictionary than actually required.)
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_microlzma_decoder(
+		lzma_stream *strm, uint64_t comp_size,
+		uint64_t uncomp_size, lzma_bool uncomp_size_is_exact,
+		uint32_t dict_size) lzma_nothrow;
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/delta.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/delta.h
new file mode 100644
index 00000000000..5ebacef8158
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/delta.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/**
+ * \file        lzma/delta.h
+ * \brief       Delta filter
+ * \note        Never include this file directly. Use  instead.
+ */
+
+/*
+ * Author: Lasse Collin
+ */
+
+#ifndef LZMA_H_INTERNAL
+#	error Never include this file directly. Use  instead.
+#endif
+
+
+/**
+ * \brief       Filter ID
+ *
+ * Filter ID of the Delta filter. This is used as lzma_filter.id.
+ */
+#define LZMA_FILTER_DELTA       LZMA_VLI_C(0x03)
+
+
+/**
+ * \brief       Type of the delta calculation
+ *
+ * Currently only byte-wise delta is supported. Other possible types could
+ * be, for example, delta of 16/32/64-bit little/big endian integers, but
+ * these are not currently planned since byte-wise delta is almost as good.
+ */
+typedef enum {
+	LZMA_DELTA_TYPE_BYTE
+} lzma_delta_type;
+
+
+/**
+ * \brief       Options for the Delta filter
+ *
+ * These options are needed by both encoder and decoder.
+ */
+typedef struct {
+	/** For now, this must always be LZMA_DELTA_TYPE_BYTE. */
+	lzma_delta_type type;
+
+	/**
+	 * \brief       Delta distance
+	 *
+	 * With the only currently supported type, LZMA_DELTA_TYPE_BYTE,
+	 * the distance is as bytes.
+	 *
+	 * Examples:
+	 *  - 16-bit stereo audio: distance = 4 bytes
+	 *  - 24-bit RGB image data: distance = 3 bytes
+	 */
+	uint32_t dist;
+
+	/**
+	 * \brief       Minimum value for lzma_options_delta.dist.
+	 */
+#	define LZMA_DELTA_DIST_MIN 1
+
+	/**
+	 * \brief       Maximum value for lzma_options_delta.dist.
+	 */
+#	define LZMA_DELTA_DIST_MAX 256
+
+	/*
+	 * Reserved space to allow possible future extensions without
+	 * breaking the ABI. You should not touch these, because the names
+	 * of these variables may change. These are and will never be used
+	 * when type is LZMA_DELTA_TYPE_BYTE, so it is safe to leave these
+	 * uninitialized.
+	 */
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int1;
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int2;
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int3;
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int4;
+
+	/** \private     Reserved member. */
+	void *reserved_ptr1;
+
+	/** \private     Reserved member. */
+	void *reserved_ptr2;
+
+} lzma_options_delta;
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/filter.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/filter.h
new file mode 100644
index 00000000000..e86809c4e39
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/filter.h
@@ -0,0 +1,769 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/**
+ * \file        lzma/filter.h
+ * \brief       Common filter related types and functions
+ * \note        Never include this file directly. Use  instead.
+ */
+
+/*
+ * Author: Lasse Collin
+ */
+
+#ifndef LZMA_H_INTERNAL
+#	error Never include this file directly. Use  instead.
+#endif
+
+
+/**
+ * \brief       Maximum number of filters in a chain
+ *
+ * A filter chain can have 1-4 filters, of which three are allowed to change
+ * the size of the data. Usually only one or two filters are needed.
+ */
+#define LZMA_FILTERS_MAX 4
+
+
+/**
+ * \brief       Filter options
+ *
+ * This structure is used to pass a Filter ID and a pointer to the filter's
+ * options to liblzma. A few functions work with a single lzma_filter
+ * structure, while most functions expect a filter chain.
+ *
+ * A filter chain is indicated with an array of lzma_filter structures.
+ * The array is terminated with .id = LZMA_VLI_UNKNOWN. Thus, the filter
+ * array must have LZMA_FILTERS_MAX + 1 elements (that is, five) to
+ * be able to hold any arbitrary filter chain. This is important when
+ * using lzma_block_header_decode() from block.h, because a filter array
+ * that is too small would make liblzma write past the end of the array.
+ */
+typedef struct {
+	/**
+	 * \brief       Filter ID
+	 *
+	 * Use constants whose name begin with 'LZMA_FILTER_' to specify
+	 * different filters. In an array of lzma_filter structures, use
+	 * LZMA_VLI_UNKNOWN to indicate end of filters.
+	 *
+	 * \note        This is not an enum, because on some systems enums
+	 *              cannot be 64-bit.
+	 */
+	lzma_vli id;
+
+	/**
+	 * \brief       Pointer to filter-specific options structure
+	 *
+	 * If the filter doesn't need options, set this to NULL. If id is
+	 * set to LZMA_VLI_UNKNOWN, options is ignored, and thus
+	 * doesn't need be initialized.
+	 */
+	void *options;
+
+} lzma_filter;
+
+
+/**
+ * \brief       Test if the given Filter ID is supported for encoding
+ *
+ * \param       id      Filter ID
+ *
+ * \return      lzma_bool:
+ *              - true if the Filter ID is supported for encoding by this
+ *                liblzma build.
+  *             - false otherwise.
+ */
+extern LZMA_API(lzma_bool) lzma_filter_encoder_is_supported(lzma_vli id)
+		lzma_nothrow lzma_attr_const;
+
+
+/**
+ * \brief       Test if the given Filter ID is supported for decoding
+ *
+ * \param       id      Filter ID
+ *
+ * \return      lzma_bool:
+ *              - true if the Filter ID is supported for decoding by this
+ *                liblzma build.
+ *              - false otherwise.
+ */
+extern LZMA_API(lzma_bool) lzma_filter_decoder_is_supported(lzma_vli id)
+		lzma_nothrow lzma_attr_const;
+
+
+/**
+ * \brief       Copy the filters array
+ *
+ * Copy the Filter IDs and filter-specific options from src to dest.
+ * Up to LZMA_FILTERS_MAX filters are copied, plus the terminating
+ * .id == LZMA_VLI_UNKNOWN. Thus, dest should have at least
+ * LZMA_FILTERS_MAX + 1 elements space unless the caller knows that
+ * src is smaller than that.
+ *
+ * Unless the filter-specific options is NULL, the Filter ID has to be
+ * supported by liblzma, because liblzma needs to know the size of every
+ * filter-specific options structure. The filter-specific options are not
+ * validated. If options is NULL, any unsupported Filter IDs are copied
+ * without returning an error.
+ *
+ * Old filter-specific options in dest are not freed, so dest doesn't
+ * need to be initialized by the caller in any way.
+ *
+ * If an error occurs, memory possibly already allocated by this function
+ * is always freed. liblzma versions older than 5.2.7 may modify the dest
+ * array and leave its contents in an undefined state if an error occurs.
+ * liblzma 5.2.7 and newer only modify the dest array when returning LZMA_OK.
+ *
+ * \param       src         Array of filters terminated with
+ *                          .id == LZMA_VLI_UNKNOWN.
+ * \param[out]  dest        Destination filter array
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_OPTIONS_ERROR: Unsupported Filter ID and its options
+ *                is not NULL.
+ *              - LZMA_PROG_ERROR: src or dest is NULL.
+ */
+extern LZMA_API(lzma_ret) lzma_filters_copy(
+		const lzma_filter *src, lzma_filter *dest,
+		const lzma_allocator *allocator)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Free the options in the array of lzma_filter structures
+ *
+ * This frees the filter chain options. The filters array itself is not freed.
+ *
+ * The filters array must have at most LZMA_FILTERS_MAX + 1 elements
+ * including the terminating element which must have .id = LZMA_VLI_UNKNOWN.
+ * For all elements before the terminating element:
+ *   - options will be freed using the given lzma_allocator or,
+ *     if allocator is NULL, using free().
+ *   - options will be set to NULL.
+ *   - id will be set to LZMA_VLI_UNKNOWN.
+ *
+ * If filters is NULL, this does nothing. Again, this never frees the
+ * filters array itself.
+ *
+ * \param       filters     Array of filters terminated with
+ *                          .id == LZMA_VLI_UNKNOWN.
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ */
+extern LZMA_API(void) lzma_filters_free(
+		lzma_filter *filters, const lzma_allocator *allocator)
+		lzma_nothrow;
+
+
+/**
+ * \brief       Calculate approximate memory requirements for raw encoder
+ *
+ * This function can be used to calculate the memory requirements for
+ * Block and Stream encoders too because Block and Stream encoders don't
+ * need significantly more memory than raw encoder.
+ *
+ * \param       filters     Array of filters terminated with
+ *                          .id == LZMA_VLI_UNKNOWN.
+ *
+ * \return      Number of bytes of memory required for the given
+ *              filter chain when encoding or UINT64_MAX on error.
+ */
+extern LZMA_API(uint64_t) lzma_raw_encoder_memusage(const lzma_filter *filters)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Calculate approximate memory requirements for raw decoder
+ *
+ * This function can be used to calculate the memory requirements for
+ * Block and Stream decoders too because Block and Stream decoders don't
+ * need significantly more memory than raw decoder.
+ *
+ * \param       filters     Array of filters terminated with
+ *                          .id == LZMA_VLI_UNKNOWN.
+ *
+ * \return      Number of bytes of memory required for the given
+ *              filter chain when decoding or UINT64_MAX on error.
+ */
+extern LZMA_API(uint64_t) lzma_raw_decoder_memusage(const lzma_filter *filters)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Initialize raw encoder
+ *
+ * This function may be useful when implementing custom file formats.
+ *
+ * The 'action' with lzma_code() can be LZMA_RUN, LZMA_SYNC_FLUSH (if the
+ * filter chain supports it), or LZMA_FINISH.
+ *
+ * \param       strm      Pointer to lzma_stream that is at least
+ *                        initialized with LZMA_STREAM_INIT.
+ * \param       filters   Array of filters terminated with
+ *                        .id == LZMA_VLI_UNKNOWN.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_raw_encoder(
+		lzma_stream *strm, const lzma_filter *filters)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Initialize raw decoder
+ *
+ * The initialization of raw decoder goes similarly to raw encoder.
+ *
+ * The 'action' with lzma_code() can be LZMA_RUN or LZMA_FINISH. Using
+ * LZMA_FINISH is not required, it is supported just for convenience.
+ *
+ * \param       strm      Pointer to lzma_stream that is at least
+ *                        initialized with LZMA_STREAM_INIT.
+ * \param       filters   Array of filters terminated with
+ *                        .id == LZMA_VLI_UNKNOWN.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_raw_decoder(
+		lzma_stream *strm, const lzma_filter *filters)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Update the filter chain in the encoder
+ *
+ * This function may be called after lzma_code() has returned LZMA_STREAM_END
+ * when LZMA_FULL_BARRIER, LZMA_FULL_FLUSH, or LZMA_SYNC_FLUSH was used:
+ *
+ *  - After LZMA_FULL_BARRIER or LZMA_FULL_FLUSH: Single-threaded .xz Stream
+ *    encoder (lzma_stream_encoder()) and (since liblzma 5.4.0) multi-threaded
+ *    Stream encoder (lzma_stream_encoder_mt()) allow setting a new filter
+ *    chain to be used for the next Block(s).
+ *
+ *  - After LZMA_SYNC_FLUSH: Raw encoder (lzma_raw_encoder()),
+ *    Block encoder (lzma_block_encoder()), and single-threaded .xz Stream
+ *    encoder (lzma_stream_encoder()) allow changing certain filter-specific
+ *    options in the middle of encoding. The actual filters in the chain
+ *    (Filter IDs) must not be changed! Currently only the lc, lp, and pb
+ *    options of LZMA2 (not LZMA1) can be changed this way.
+ *
+ *  - In the future some filters might allow changing some of their options
+ *    without any barrier or flushing but currently such filters don't exist.
+ *
+ * This function may also be called when no data has been compressed yet
+ * although this is rarely useful. In that case, this function will behave
+ * as if LZMA_FULL_FLUSH (Stream encoders) or LZMA_SYNC_FLUSH (Raw or Block
+ * encoder) had been used right before calling this function.
+ *
+ * \param       strm      Pointer to lzma_stream that is at least
+ *                        initialized with LZMA_STREAM_INIT.
+ * \param       filters   Array of filters terminated with
+ *                        .id == LZMA_VLI_UNKNOWN.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_MEMLIMIT_ERROR
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_filters_update(
+		lzma_stream *strm, const lzma_filter *filters) lzma_nothrow;
+
+
+/**
+ * \brief       Single-call raw encoder
+ *
+ * \note        There is no function to calculate how big output buffer
+ *              would surely be big enough. (lzma_stream_buffer_bound()
+ *              works only for lzma_stream_buffer_encode(); raw encoder
+ *              won't necessarily meet that bound.)
+ *
+ * \param       filters     Array of filters terminated with
+ *                          .id == LZMA_VLI_UNKNOWN.
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ * \param       in          Beginning of the input buffer
+ * \param       in_size     Size of the input buffer
+ * \param[out]  out         Beginning of the output buffer
+ * \param[out]  out_pos     The next byte will be written to out[*out_pos].
+ *                          *out_pos is updated only if encoding succeeds.
+ * \param       out_size    Size of the out buffer; the first byte into
+ *                          which no data is written to is out[out_size].
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Encoding was successful.
+ *              - LZMA_BUF_ERROR: Not enough output buffer space.
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_DATA_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_raw_buffer_encode(
+		const lzma_filter *filters, const lzma_allocator *allocator,
+		const uint8_t *in, size_t in_size, uint8_t *out,
+		size_t *out_pos, size_t out_size) lzma_nothrow;
+
+
+/**
+ * \brief       Single-call raw decoder
+ *
+ * \param       filters     Array of filters terminated with
+ *                          .id == LZMA_VLI_UNKNOWN.
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ * \param       in          Beginning of the input buffer
+ * \param       in_pos      The next byte will be read from in[*in_pos].
+ *                          *in_pos is updated only if decoding succeeds.
+ * \param       in_size     Size of the input buffer; the first byte that
+ *                          won't be read is in[in_size].
+ * \param[out]  out         Beginning of the output buffer
+ * \param[out]  out_pos     The next byte will be written to out[*out_pos].
+ *                          *out_pos is updated only if encoding succeeds.
+ * \param       out_size    Size of the out buffer; the first byte into
+ *                          which no data is written to is out[out_size].
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Decoding was successful.
+ *              - LZMA_BUF_ERROR: Not enough output buffer space.
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_DATA_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_raw_buffer_decode(
+		const lzma_filter *filters, const lzma_allocator *allocator,
+		const uint8_t *in, size_t *in_pos, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
+
+
+/**
+ * \brief       Get the size of the Filter Properties field
+ *
+ * This function may be useful when implementing custom file formats
+ * using the raw encoder and decoder.
+ *
+ * \note        This function validates the Filter ID, but does not
+ *              necessarily validate the options. Thus, it is possible
+ *              that this returns LZMA_OK while the following call to
+ *              lzma_properties_encode() returns LZMA_OPTIONS_ERROR.
+ *
+ * \param[out]  size    Pointer to uint32_t to hold the size of the properties
+ * \param       filter  Filter ID and options (the size of the properties may
+ *                      vary depending on the options)
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_properties_size(
+		uint32_t *size, const lzma_filter *filter) lzma_nothrow;
+
+
+/**
+ * \brief       Encode the Filter Properties field
+ *
+ * \note        Even this function won't validate more options than actually
+ *              necessary. Thus, it is possible that encoding the properties
+ *              succeeds but using the same options to initialize the encoder
+ *              will fail.
+ *
+ * \note        If lzma_properties_size() indicated that the size
+ *              of the Filter Properties field is zero, calling
+ *              lzma_properties_encode() is not required, but it
+ *              won't do any harm either.
+ *
+ * \param       filter  Filter ID and options
+ * \param[out]  props   Buffer to hold the encoded options. The size of
+ *                      the buffer must have been already determined with
+ *                      lzma_properties_size().
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_properties_encode(
+		const lzma_filter *filter, uint8_t *props) lzma_nothrow;
+
+
+/**
+ * \brief       Decode the Filter Properties field
+ *
+ * \param       filter      filter->id must have been set to the correct
+ *                          Filter ID. filter->options doesn't need to be
+ *                          initialized (it's not freed by this function). The
+ *                          decoded options will be stored in filter->options;
+ *                          it's application's responsibility to free it when
+ *                          appropriate. filter->options is set to NULL if
+ *                          there are no properties or if an error occurs.
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ *                          and in case of an error, also free().
+ * \param       props       Input buffer containing the properties.
+ * \param       props_size  Size of the properties. This must be the exact
+ *                          size; giving too much or too little input will
+ *                          return LZMA_OPTIONS_ERROR.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_MEM_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_properties_decode(
+		lzma_filter *filter, const lzma_allocator *allocator,
+		const uint8_t *props, size_t props_size) lzma_nothrow;
+
+
+/**
+ * \brief       Calculate encoded size of a Filter Flags field
+ *
+ * Knowing the size of Filter Flags is useful to know when allocating
+ * memory to hold the encoded Filter Flags.
+ *
+ * \note        If you need to calculate size of List of Filter Flags,
+ *              you need to loop over every lzma_filter entry.
+ *
+ * \param[out]  size    Pointer to integer to hold the calculated size
+ * \param       filter  Filter ID and associated options whose encoded
+ *                      size is to be calculated
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: *size set successfully. Note that this doesn't
+ *                guarantee that filter->options is valid, thus
+ *                lzma_filter_flags_encode() may still fail.
+ *              - LZMA_OPTIONS_ERROR: Unknown Filter ID or unsupported options.
+ *              - LZMA_PROG_ERROR: Invalid options
+ */
+extern LZMA_API(lzma_ret) lzma_filter_flags_size(
+		uint32_t *size, const lzma_filter *filter)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Encode Filter Flags into given buffer
+ *
+ * In contrast to some functions, this doesn't allocate the needed buffer.
+ * This is due to how this function is used internally by liblzma.
+ *
+ * \param       filter      Filter ID and options to be encoded
+ * \param[out]  out         Beginning of the output buffer
+ * \param[out]  out_pos     out[*out_pos] is the next write position. This
+ *                          is updated by the encoder.
+ * \param       out_size    out[out_size] is the first byte to not write.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Encoding was successful.
+ *              - LZMA_OPTIONS_ERROR: Invalid or unsupported options.
+ *              - LZMA_PROG_ERROR: Invalid options or not enough output
+ *                buffer space (you should have checked it with
+ *                lzma_filter_flags_size()).
+ */
+extern LZMA_API(lzma_ret) lzma_filter_flags_encode(const lzma_filter *filter,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Decode Filter Flags from given buffer
+ *
+ * The decoded result is stored into *filter. The old value of
+ * filter->options is not free()d. If anything other than LZMA_OK
+ * is returned, filter->options is set to NULL.
+ *
+ * \param[out]  filter      Destination filter. The decoded Filter ID will
+ *                          be stored in filter->id. If options are needed
+ *                          they will be allocated and the pointer will be
+ *                          stored in filter->options.
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ * \param       in          Beginning of the input buffer
+ * \param[out]  in_pos      The next byte will be read from in[*in_pos].
+ *                          *in_pos is updated only if decoding succeeds.
+ * \param       in_size     Size of the input buffer; the first byte that
+ *                          won't be read is in[in_size].
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_OPTIONS_ERROR
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_DATA_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_filter_flags_decode(
+		lzma_filter *filter, const lzma_allocator *allocator,
+		const uint8_t *in, size_t *in_pos, size_t in_size)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/***********
+ * Strings *
+ ***********/
+
+/**
+ * \brief       Allow or show all filters
+ *
+ * By default only the filters supported in the .xz format are accept by
+ * lzma_str_to_filters() or shown by lzma_str_list_filters().
+ */
+#define LZMA_STR_ALL_FILTERS    UINT32_C(0x01)
+
+
+/**
+ * \brief       Do not validate the filter chain in lzma_str_to_filters()
+ *
+ * By default lzma_str_to_filters() can return an error if the filter chain
+ * as a whole isn't usable in the .xz format or in the raw encoder or decoder.
+ * With this flag, this validation is skipped. This flag doesn't affect the
+ * handling of the individual filter options. To allow non-.xz filters also
+ * LZMA_STR_ALL_FILTERS is needed.
+ */
+#define LZMA_STR_NO_VALIDATION  UINT32_C(0x02)
+
+
+/**
+ * \brief       Stringify encoder options
+ *
+ * Show the filter-specific options that the encoder will use.
+ * This may be useful for verbose diagnostic messages.
+ *
+ * Note that if options were decoded from .xz headers then the encoder options
+ * may be undefined. This flag shouldn't be used in such a situation.
+ */
+#define LZMA_STR_ENCODER        UINT32_C(0x10)
+
+
+/**
+ * \brief       Stringify decoder options
+ *
+ * Show the filter-specific options that the decoder will use.
+ * This may be useful for showing what filter options were decoded
+ * from file headers.
+ */
+#define LZMA_STR_DECODER        UINT32_C(0x20)
+
+
+/**
+ * \brief       Produce xz-compatible getopt_long() syntax
+ *
+ * That is, "delta:dist=2 lzma2:dict=4MiB,pb=1,lp=1" becomes
+ * "--delta=dist=2 --lzma2=dict=4MiB,pb=1,lp=1".
+ *
+ * This syntax is compatible with xz 5.0.0 as long as the filters and
+ * their options are supported too.
+ */
+#define LZMA_STR_GETOPT_LONG    UINT32_C(0x40)
+
+
+/**
+ * \brief       Use two dashes "--" instead of a space to separate filters
+ *
+ * That is, "delta:dist=2 lzma2:pb=1,lp=1" becomes
+ * "delta:dist=2--lzma2:pb=1,lp=1". This looks slightly odd but this
+ * kind of strings should be usable on the command line without quoting.
+ * However, it is possible that future versions with new filter options
+ * might produce strings that require shell quoting anyway as the exact
+ * set of possible characters isn't frozen for now.
+ *
+ * It is guaranteed that the single quote (') will never be used in
+ * filter chain strings (even if LZMA_STR_NO_SPACES isn't used).
+ */
+#define LZMA_STR_NO_SPACES      UINT32_C(0x80)
+
+
+/**
+ * \brief       Convert a string to a filter chain
+ *
+ * This tries to make it easier to write applications that allow users
+ * to set custom compression options. This only handles the filter
+ * configuration (including presets) but not the number of threads,
+ * block size, check type, or memory limits.
+ *
+ * The input string can be either a preset or a filter chain. Presets
+ * begin with a digit 0-9 and may be followed by zero or more flags
+ * which are lower-case letters. Currently only "e" is supported, matching
+ * LZMA_PRESET_EXTREME. For partial xz command line syntax compatibility,
+ * a preset string may start with a single dash "-".
+ *
+ * A filter chain consists of one or more "filtername:opt1=value1,opt2=value2"
+ * strings separated by one or more spaces. Leading and trailing spaces are
+ * ignored. All names and values must be lower-case. Extra commas in the
+ * option list are ignored. The order of filters is significant: when
+ * encoding, the uncompressed input data goes to the leftmost filter first.
+ * Normally "lzma2" is the last filter in the chain.
+ *
+ * If one wishes to avoid spaces, for example, to avoid shell quoting,
+ * it is possible to use two dashes "--" instead of spaces to separate
+ * the filters.
+ *
+ * For xz command line compatibility, each filter may be prefixed with
+ * two dashes "--" and the colon ":" separating the filter name from
+ * the options may be replaced with an equals sign "=".
+ *
+ * By default, only filters that can be used in the .xz format are accepted.
+ * To allow all filters (LZMA1) use the flag LZMA_STR_ALL_FILTERS.
+ *
+ * By default, very basic validation is done for the filter chain as a whole,
+ * for example, that LZMA2 is only used as the last filter in the chain.
+ * The validation isn't perfect though and it's possible that this function
+ * succeeds but using the filter chain for encoding or decoding will still
+ * result in LZMA_OPTIONS_ERROR. To disable this validation, use the flag
+ * LZMA_STR_NO_VALIDATION.
+ *
+ * The available filter names and their options are available via
+ * lzma_str_list_filters(). See the xz man page for the description
+ * of filter names and options.
+ *
+ * For command line applications, below is an example how an error message
+ * can be displayed. Note the use of an empty string for the field width.
+ * If "^" was used there it would create an off-by-one error except at
+ * the very beginning of the line.
+ *
+ * \code{.c}
+ * const char *str = ...; // From user
+ * lzma_filter filters[LZMA_FILTERS_MAX + 1];
+ * int pos;
+ * const char *msg = lzma_str_to_filters(str, &pos, filters, 0, NULL);
+ * if (msg != NULL) {
+ *     printf("%s: Error in XZ compression options:\n", argv[0]);
+ *     printf("%s: %s\n", argv[0], str);
+ *     printf("%s: %*s^\n", argv[0], errpos, "");
+ *     printf("%s: %s\n", argv[0], msg);
+ * }
+ * \endcode
+ *
+ * \param       str         User-supplied string describing a preset or
+ *                          a filter chain. If a default value is needed and
+ *                          you don't know what would be good, use "6" since
+ *                          that is the default preset in xz too.
+ * \param[out]  error_pos   If this isn't NULL, this value will be set on
+ *                          both success and on all errors. This tells the
+ *                          location of the error in the string. This is
+ *                          an int to make it straightforward to use this
+ *                          as printf() field width. The value is guaranteed
+ *                          to be in the range [0, INT_MAX] even if strlen(str)
+ *                          somehow was greater than INT_MAX.
+ * \param[out]  filters     An array of lzma_filter structures. There must
+ *                          be LZMA_FILTERS_MAX + 1 (that is, five) elements
+ *                          in the array. The old contents are ignored so it
+ *                          doesn't need to be initialized. This array is
+ *                          modified only if this function returns NULL.
+ *                          Once the allocated filter options are no longer
+ *                          needed, lzma_filters_free() can be used to free the
+ *                          options (it doesn't free the filters array itself).
+ * \param       flags       Bitwise-or of zero or more of the flags
+ *                          LZMA_STR_ALL_FILTERS and LZMA_STR_NO_VALIDATION.
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ *
+ * \return      On success, NULL is returned. On error, a statically-allocated
+ *              error message is returned which together with the error_pos
+ *              should give some idea what is wrong.
+ */
+extern LZMA_API(const char *) lzma_str_to_filters(
+		const char *str, int *error_pos, lzma_filter *filters,
+		uint32_t flags, const lzma_allocator *allocator)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Convert a filter chain to a string
+ *
+ * Use cases:
+ *
+ *   - Verbose output showing the full encoder options to the user
+ *     (use LZMA_STR_ENCODER in flags)
+ *
+ *   - Showing the filters and options that are required to decode a file
+ *     (use LZMA_STR_DECODER in flags)
+ *
+ *   - Showing the filter names without any options in informational messages
+ *     where the technical details aren't important (no flags). In this case
+ *     the .options in the filters array are ignored and may be NULL even if
+ *     a filter has a mandatory options structure.
+ *
+ * Note that even if the filter chain was specified using a preset,
+ * the resulting filter chain isn't reversed to a preset. So if you
+ * specify "6" to lzma_str_to_filters() then lzma_str_from_filters()
+ * will produce a string containing "lzma2".
+ *
+ * \param[out]  str         On success *str will be set to point to an
+ *                          allocated string describing the given filter
+ *                          chain. Old value is ignored. On error *str is
+ *                          always set to NULL.
+ * \param       filters     Array of filters terminated with
+ *                          .id == LZMA_VLI_UNKNOWN.
+ * \param       flags       Bitwise-or of zero or more of the flags
+ *                          LZMA_STR_ENCODER, LZMA_STR_DECODER,
+ *                          LZMA_STR_GETOPT_LONG, and LZMA_STR_NO_SPACES.
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_OPTIONS_ERROR: Empty filter chain
+ *                (filters[0].id == LZMA_VLI_UNKNOWN) or the filter chain
+ *                includes a Filter ID that is not supported by this function.
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_str_from_filters(
+		char **str, const lzma_filter *filters, uint32_t flags,
+		const lzma_allocator *allocator)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       List available filters and/or their options (for help message)
+ *
+ * If a filter_id is given then only one line is created which contains the
+ * filter name. If LZMA_STR_ENCODER or LZMA_STR_DECODER is used then the
+ * options read by the encoder or decoder are printed on the same line.
+ *
+ * If filter_id is LZMA_VLI_UNKNOWN then all supported .xz-compatible filters
+ * are listed:
+ *
+ *   - If neither LZMA_STR_ENCODER nor LZMA_STR_DECODER is used then
+ *     the supported filter names are listed on a single line separated
+ *     by spaces.
+ *
+ *   - If LZMA_STR_ENCODER or LZMA_STR_DECODER is used then filters and
+ *     the supported options are listed one filter per line. There won't
+ *     be a newline after the last filter.
+ *
+ *   - If LZMA_STR_ALL_FILTERS is used then the list will include also
+ *     those filters that cannot be used in the .xz format (LZMA1).
+ *
+ * \param       str         On success *str will be set to point to an
+ *                          allocated string listing the filters and options.
+ *                          Old value is ignored. On error *str is always set
+ *                          to NULL.
+ * \param       filter_id   Filter ID or LZMA_VLI_UNKNOWN.
+ * \param       flags       Bitwise-or of zero or more of the flags
+ *                          LZMA_STR_ALL_FILTERS, LZMA_STR_ENCODER,
+ *                          LZMA_STR_DECODER, and LZMA_STR_GETOPT_LONG.
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_OPTIONS_ERROR: Unsupported filter_id or flags
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_str_list_filters(
+		char **str, lzma_vli filter_id, uint32_t flags,
+		const lzma_allocator *allocator)
+		lzma_nothrow lzma_attr_warn_unused_result;
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/hardware.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/hardware.h
new file mode 100644
index 00000000000..7a1a84fcccf
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/hardware.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/**
+ * \file        lzma/hardware.h
+ * \brief       Hardware information
+ * \note        Never include this file directly. Use  instead.
+ *
+ * Since liblzma can consume a lot of system resources, it also provides
+ * ways to limit the resource usage. Applications linking against liblzma
+ * need to do the actual decisions how much resources to let liblzma to use.
+ * To ease making these decisions, liblzma provides functions to find out
+ * the relevant capabilities of the underlying hardware. Currently there
+ * is only a function to find out the amount of RAM, but in the future there
+ * will be also a function to detect how many concurrent threads the system
+ * can run.
+ *
+ * \note        On some operating systems, these function may temporarily
+ *              load a shared library or open file descriptor(s) to find out
+ *              the requested hardware information. Unless the application
+ *              assumes that specific file descriptors are not touched by
+ *              other threads, this should have no effect on thread safety.
+ *              Possible operations involving file descriptors will restart
+ *              the syscalls if they return EINTR.
+ */
+
+/*
+ * Author: Lasse Collin
+ */
+
+#ifndef LZMA_H_INTERNAL
+#	error Never include this file directly. Use  instead.
+#endif
+
+
+/**
+ * \brief       Get the total amount of physical memory (RAM) in bytes
+ *
+ * This function may be useful when determining a reasonable memory
+ * usage limit for decompressing or how much memory it is OK to use
+ * for compressing.
+ *
+ * \return      On success, the total amount of physical memory in bytes
+ *              is returned. If the amount of RAM cannot be determined,
+ *              zero is returned. This can happen if an error occurs
+ *              or if there is no code in liblzma to detect the amount
+ *              of RAM on the specific operating system.
+ */
+extern LZMA_API(uint64_t) lzma_physmem(void) lzma_nothrow;
+
+
+/**
+ * \brief       Get the number of processor cores or threads
+ *
+ * This function may be useful when determining how many threads to use.
+ * If the hardware supports more than one thread per CPU core, the number
+ * of hardware threads is returned if that information is available.
+ *
+ * \return      On success, the number of available CPU threads or cores is
+ *              returned. If this information isn't available or an error
+ *              occurs, zero is returned.
+ */
+extern LZMA_API(uint32_t) lzma_cputhreads(void) lzma_nothrow;
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index.h
new file mode 100644
index 00000000000..b17025e3d90
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index.h
@@ -0,0 +1,882 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/**
+ * \file        lzma/index.h
+ * \brief       Handling of .xz Index and related information
+ * \note        Never include this file directly. Use  instead.
+ */
+
+/*
+ * Author: Lasse Collin
+ */
+
+#ifndef LZMA_H_INTERNAL
+#	error Never include this file directly. Use  instead.
+#endif
+
+
+/**
+ * \brief       Opaque data type to hold the Index(es) and other information
+ *
+ * lzma_index often holds just one .xz Index and possibly the Stream Flags
+ * of the same Stream and size of the Stream Padding field. However,
+ * multiple lzma_indexes can be concatenated with lzma_index_cat() and then
+ * there may be information about multiple Streams in the same lzma_index.
+ *
+ * Notes about thread safety: Only one thread may modify lzma_index at
+ * a time. All functions that take non-const pointer to lzma_index
+ * modify it. As long as no thread is modifying the lzma_index, getting
+ * information from the same lzma_index can be done from multiple threads
+ * at the same time with functions that take a const pointer to
+ * lzma_index or use lzma_index_iter. The same iterator must be used
+ * only by one thread at a time, of course, but there can be as many
+ * iterators for the same lzma_index as needed.
+ */
+typedef struct lzma_index_s lzma_index;
+
+
+/**
+ * \brief       Iterator to get information about Blocks and Streams
+ */
+typedef struct {
+	struct {
+		/**
+		 * \brief       Pointer to Stream Flags
+		 *
+		 * This is NULL if Stream Flags have not been set for
+		 * this Stream with lzma_index_stream_flags().
+		 */
+		const lzma_stream_flags *flags;
+
+		/** \private     Reserved member. */
+		const void *reserved_ptr1;
+
+		/** \private     Reserved member. */
+		const void *reserved_ptr2;
+
+		/** \private     Reserved member. */
+		const void *reserved_ptr3;
+
+		/**
+		 * \brief       Stream number in the lzma_index
+		 *
+		 * The first Stream is 1.
+		 */
+		lzma_vli number;
+
+		/**
+		 * \brief       Number of Blocks in the Stream
+		 *
+		 * If this is zero, the block structure below has
+		 * undefined values.
+		 */
+		lzma_vli block_count;
+
+		/**
+		 * \brief       Compressed start offset of this Stream
+		 *
+		 * The offset is relative to the beginning of the lzma_index
+		 * (i.e. usually the beginning of the .xz file).
+		 */
+		lzma_vli compressed_offset;
+
+		/**
+		 * \brief       Uncompressed start offset of this Stream
+		 *
+		 * The offset is relative to the beginning of the lzma_index
+		 * (i.e. usually the beginning of the .xz file).
+		 */
+		lzma_vli uncompressed_offset;
+
+		/**
+		 * \brief       Compressed size of this Stream
+		 *
+		 * This includes all headers except the possible
+		 * Stream Padding after this Stream.
+		 */
+		lzma_vli compressed_size;
+
+		/**
+		 * \brief       Uncompressed size of this Stream
+		 */
+		lzma_vli uncompressed_size;
+
+		/**
+		 * \brief       Size of Stream Padding after this Stream
+		 *
+		 * If it hasn't been set with lzma_index_stream_padding(),
+		 * this defaults to zero. Stream Padding is always
+		 * a multiple of four bytes.
+		 */
+		lzma_vli padding;
+
+
+		/** \private     Reserved member. */
+		lzma_vli reserved_vli1;
+
+		/** \private     Reserved member. */
+		lzma_vli reserved_vli2;
+
+		/** \private     Reserved member. */
+		lzma_vli reserved_vli3;
+
+		/** \private     Reserved member. */
+		lzma_vli reserved_vli4;
+	} stream;
+
+	struct {
+		/**
+		 * \brief       Block number in the file
+		 *
+		 * The first Block is 1.
+		 */
+		lzma_vli number_in_file;
+
+		/**
+		 * \brief       Compressed start offset of this Block
+		 *
+		 * This offset is relative to the beginning of the
+		 * lzma_index (i.e. usually the beginning of the .xz file).
+		 * Normally this is where you should seek in the .xz file
+		 * to start decompressing this Block.
+		 */
+		lzma_vli compressed_file_offset;
+
+		/**
+		 * \brief       Uncompressed start offset of this Block
+		 *
+		 * This offset is relative to the beginning of the lzma_index
+		 * (i.e. usually the beginning of the .xz file).
+		 *
+		 * When doing random-access reading, it is possible that
+		 * the target offset is not exactly at Block boundary. One
+		 * will need to compare the target offset against
+		 * uncompressed_file_offset or uncompressed_stream_offset,
+		 * and possibly decode and throw away some amount of data
+		 * before reaching the target offset.
+		 */
+		lzma_vli uncompressed_file_offset;
+
+		/**
+		 * \brief       Block number in this Stream
+		 *
+		 * The first Block is 1.
+		 */
+		lzma_vli number_in_stream;
+
+		/**
+		 * \brief       Compressed start offset of this Block
+		 *
+		 * This offset is relative to the beginning of the Stream
+		 * containing this Block.
+		 */
+		lzma_vli compressed_stream_offset;
+
+		/**
+		 * \brief       Uncompressed start offset of this Block
+		 *
+		 * This offset is relative to the beginning of the Stream
+		 * containing this Block.
+		 */
+		lzma_vli uncompressed_stream_offset;
+
+		/**
+		 * \brief       Uncompressed size of this Block
+		 *
+		 * You should pass this to the Block decoder if you will
+		 * decode this Block. It will allow the Block decoder to
+		 * validate the uncompressed size.
+		 */
+		lzma_vli uncompressed_size;
+
+		/**
+		 * \brief       Unpadded size of this Block
+		 *
+		 * You should pass this to the Block decoder if you will
+		 * decode this Block. It will allow the Block decoder to
+		 * validate the unpadded size.
+		 */
+		lzma_vli unpadded_size;
+
+		/**
+		 * \brief       Total compressed size
+		 *
+		 * This includes all headers and padding in this Block.
+		 * This is useful if you need to know how many bytes
+		 * the Block decoder will actually read.
+		 */
+		lzma_vli total_size;
+
+		/** \private     Reserved member. */
+		lzma_vli reserved_vli1;
+
+		/** \private     Reserved member. */
+		lzma_vli reserved_vli2;
+
+		/** \private     Reserved member. */
+		lzma_vli reserved_vli3;
+
+		/** \private     Reserved member. */
+		lzma_vli reserved_vli4;
+
+		/** \private     Reserved member. */
+		const void *reserved_ptr1;
+
+		/** \private     Reserved member. */
+		const void *reserved_ptr2;
+
+		/** \private     Reserved member. */
+		const void *reserved_ptr3;
+
+		/** \private     Reserved member. */
+		const void *reserved_ptr4;
+	} block;
+
+	/**
+	 * \private     Internal data
+	 *
+	 * Internal data which is used to store the state of the iterator.
+	 * The exact format may vary between liblzma versions, so don't
+	 * touch these in any way.
+	 */
+	union {
+		/** \private     Internal member. */
+		const void *p;
+
+		/** \private     Internal member. */
+		size_t s;
+
+		/** \private     Internal member. */
+		lzma_vli v;
+	} internal[6];
+} lzma_index_iter;
+
+
+/**
+ * \brief       Operation mode for lzma_index_iter_next()
+ */
+typedef enum {
+	LZMA_INDEX_ITER_ANY             = 0,
+		/**<
+		 * \brief       Get the next Block or Stream
+		 *
+		 * Go to the next Block if the current Stream has at least
+		 * one Block left. Otherwise go to the next Stream even if
+		 * it has no Blocks. If the Stream has no Blocks
+		 * (lzma_index_iter.stream.block_count == 0),
+		 * lzma_index_iter.block will have undefined values.
+		 */
+
+	LZMA_INDEX_ITER_STREAM          = 1,
+		/**<
+		 * \brief       Get the next Stream
+		 *
+		 * Go to the next Stream even if the current Stream has
+		 * unread Blocks left. If the next Stream has at least one
+		 * Block, the iterator will point to the first Block.
+		 * If there are no Blocks, lzma_index_iter.block will have
+		 * undefined values.
+		 */
+
+	LZMA_INDEX_ITER_BLOCK           = 2,
+		/**<
+		 * \brief       Get the next Block
+		 *
+		 * Go to the next Block if the current Stream has at least
+		 * one Block left. If the current Stream has no Blocks left,
+		 * the next Stream with at least one Block is located and
+		 * the iterator will be made to point to the first Block of
+		 * that Stream.
+		 */
+
+	LZMA_INDEX_ITER_NONEMPTY_BLOCK  = 3
+		/**<
+		 * \brief       Get the next non-empty Block
+		 *
+		 * This is like LZMA_INDEX_ITER_BLOCK except that it will
+		 * skip Blocks whose Uncompressed Size is zero.
+		 */
+
+} lzma_index_iter_mode;
+
+
+/**
+ * \brief       Mask for return value from lzma_index_checks() for check none
+ *
+ * \note        This and the other CHECK_MASK macros were added in 5.5.1alpha.
+ */
+#define LZMA_INDEX_CHECK_MASK_NONE (UINT32_C(1) << LZMA_CHECK_NONE)
+
+/**
+ * \brief       Mask for return value from lzma_index_checks() for check CRC32
+ */
+#define LZMA_INDEX_CHECK_MASK_CRC32 (UINT32_C(1) << LZMA_CHECK_CRC32)
+
+/**
+ * \brief       Mask for return value from lzma_index_checks() for check CRC64
+ */
+#define LZMA_INDEX_CHECK_MASK_CRC64 (UINT32_C(1) << LZMA_CHECK_CRC64)
+
+/**
+ * \brief       Mask for return value from lzma_index_checks() for check SHA256
+ */
+#define LZMA_INDEX_CHECK_MASK_SHA256 (UINT32_C(1) << LZMA_CHECK_SHA256)
+
+/**
+ * \brief       Calculate memory usage of lzma_index
+ *
+ * On disk, the size of the Index field depends on both the number of Records
+ * stored and the size of the Records (due to variable-length integer
+ * encoding). When the Index is kept in lzma_index structure, the memory usage
+ * depends only on the number of Records/Blocks stored in the Index(es), and
+ * in case of concatenated lzma_indexes, the number of Streams. The size in
+ * RAM is almost always significantly bigger than in the encoded form on disk.
+ *
+ * This function calculates an approximate amount of memory needed to hold
+ * the given number of Streams and Blocks in lzma_index structure. This
+ * value may vary between CPU architectures and also between liblzma versions
+ * if the internal implementation is modified.
+ *
+ * \param       streams Number of Streams
+ * \param       blocks  Number of Blocks
+ *
+ * \return      Approximate memory in bytes needed in a lzma_index structure.
+ */
+extern LZMA_API(uint64_t) lzma_index_memusage(
+		lzma_vli streams, lzma_vli blocks) lzma_nothrow;
+
+
+/**
+ * \brief       Calculate the memory usage of an existing lzma_index
+ *
+ * This is a shorthand for lzma_index_memusage(lzma_index_stream_count(i),
+ * lzma_index_block_count(i)).
+ *
+ * \param       i   Pointer to lzma_index structure
+ *
+ * \return      Approximate memory in bytes used by the lzma_index structure.
+ */
+extern LZMA_API(uint64_t) lzma_index_memused(const lzma_index *i)
+		lzma_nothrow;
+
+
+/**
+ * \brief       Allocate and initialize a new lzma_index structure
+ *
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ *
+ * \return      On success, a pointer to an empty initialized lzma_index is
+ *              returned. If allocation fails, NULL is returned.
+ */
+extern LZMA_API(lzma_index *) lzma_index_init(const lzma_allocator *allocator)
+		lzma_nothrow;
+
+
+/**
+ * \brief       Deallocate lzma_index
+ *
+ * If i is NULL, this does nothing.
+ *
+ * \param       i           Pointer to lzma_index structure to deallocate
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ */
+extern LZMA_API(void) lzma_index_end(
+		lzma_index *i, const lzma_allocator *allocator) lzma_nothrow;
+
+
+/**
+ * \brief       Add a new Block to lzma_index
+ *
+ * \param       i                 Pointer to a lzma_index structure
+ * \param       allocator         lzma_allocator for custom allocator
+ *                                functions. Set to NULL to use malloc()
+ *                                and free().
+ * \param       unpadded_size     Unpadded Size of a Block. This can be
+ *                                calculated with lzma_block_unpadded_size()
+ *                                after encoding or decoding the Block.
+ * \param       uncompressed_size Uncompressed Size of a Block. This can be
+ *                                taken directly from lzma_block structure
+ *                                after encoding or decoding the Block.
+ *
+ * Appending a new Block does not invalidate iterators. For example,
+ * if an iterator was pointing to the end of the lzma_index, after
+ * lzma_index_append() it is possible to read the next Block with
+ * an existing iterator.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_DATA_ERROR: Compressed or uncompressed size of the
+ *                Stream or size of the Index field would grow too big.
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_index_append(
+		lzma_index *i, const lzma_allocator *allocator,
+		lzma_vli unpadded_size, lzma_vli uncompressed_size)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Set the Stream Flags
+ *
+ * Set the Stream Flags of the last (and typically the only) Stream
+ * in lzma_index. This can be useful when reading information from the
+ * lzma_index, because to decode Blocks, knowing the integrity check type
+ * is needed.
+ *
+ * \param       i              Pointer to lzma_index structure
+ * \param       stream_flags   Pointer to lzma_stream_flags structure. This
+ *                             is copied into the internal preallocated
+ *                             structure, so the caller doesn't need to keep
+ *                             the flags' data available after calling this
+ *                             function.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_OPTIONS_ERROR: Unsupported stream_flags->version.
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_index_stream_flags(
+		lzma_index *i, const lzma_stream_flags *stream_flags)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Get the types of integrity Checks
+ *
+ * If lzma_index_stream_flags() is used to set the Stream Flags for
+ * every Stream, lzma_index_checks() can be used to get a bitmask to
+ * indicate which Check types have been used. It can be useful e.g. if
+ * showing the Check types to the user.
+ *
+ * The bitmask is 1 << check_id, e.g. CRC32 is 1 << 1 and SHA-256 is 1 << 10.
+ * These masks are defined for convenience as LZMA_INDEX_CHECK_MASK_XXX
+ *
+ * \param       i   Pointer to lzma_index structure
+ *
+ * \return      Bitmask indicating which Check types are used in the lzma_index
+ */
+extern LZMA_API(uint32_t) lzma_index_checks(const lzma_index *i)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Set the amount of Stream Padding
+ *
+ * Set the amount of Stream Padding of the last (and typically the only)
+ * Stream in the lzma_index. This is needed when planning to do random-access
+ * reading within multiple concatenated Streams.
+ *
+ * By default, the amount of Stream Padding is assumed to be zero bytes.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_DATA_ERROR: The file size would grow too big.
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_index_stream_padding(
+		lzma_index *i, lzma_vli stream_padding)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Get the number of Streams
+ *
+ * \param       i   Pointer to lzma_index structure
+ *
+ * \return      Number of Streams in the lzma_index
+ */
+extern LZMA_API(lzma_vli) lzma_index_stream_count(const lzma_index *i)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Get the number of Blocks
+ *
+ * This returns the total number of Blocks in lzma_index. To get number
+ * of Blocks in individual Streams, use lzma_index_iter.
+ *
+ * \param       i   Pointer to lzma_index structure
+ *
+ * \return      Number of blocks in the lzma_index
+ */
+extern LZMA_API(lzma_vli) lzma_index_block_count(const lzma_index *i)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Get the size of the Index field as bytes
+ *
+ * This is needed to verify the Backward Size field in the Stream Footer.
+ *
+ * \param       i   Pointer to lzma_index structure
+ *
+ * \return      Size in bytes of the Index
+ */
+extern LZMA_API(lzma_vli) lzma_index_size(const lzma_index *i)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Get the total size of the Stream
+ *
+ * If multiple lzma_indexes have been combined, this works as if the Blocks
+ * were in a single Stream. This is useful if you are going to combine
+ * Blocks from multiple Streams into a single new Stream.
+ *
+ * \param       i   Pointer to lzma_index structure
+ *
+ * \return      Size in bytes of the Stream (if all Blocks are combined
+ *              into one Stream).
+ */
+extern LZMA_API(lzma_vli) lzma_index_stream_size(const lzma_index *i)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Get the total size of the Blocks
+ *
+ * This doesn't include the Stream Header, Stream Footer, Stream Padding,
+ * or Index fields.
+ *
+ * \param       i   Pointer to lzma_index structure
+ *
+ * \return      Size in bytes of all Blocks in the Stream(s)
+ */
+extern LZMA_API(lzma_vli) lzma_index_total_size(const lzma_index *i)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Get the total size of the file
+ *
+ * When no lzma_indexes have been combined with lzma_index_cat() and there is
+ * no Stream Padding, this function is identical to lzma_index_stream_size().
+ * If multiple lzma_indexes have been combined, this includes also the headers
+ * of each separate Stream and the possible Stream Padding fields.
+ *
+ * \param       i   Pointer to lzma_index structure
+ *
+ * \return      Total size of the .xz file in bytes
+ */
+extern LZMA_API(lzma_vli) lzma_index_file_size(const lzma_index *i)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Get the uncompressed size of the file
+ *
+ * \param       i   Pointer to lzma_index structure
+ *
+ * \return      Size in bytes of the uncompressed data in the file
+ */
+extern LZMA_API(lzma_vli) lzma_index_uncompressed_size(const lzma_index *i)
+		lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief       Initialize an iterator
+ *
+ * This function associates the iterator with the given lzma_index, and calls
+ * lzma_index_iter_rewind() on the iterator.
+ *
+ * This function doesn't allocate any memory, thus there is no
+ * lzma_index_iter_end(). The iterator is valid as long as the
+ * associated lzma_index is valid, that is, until lzma_index_end() or
+ * using it as source in lzma_index_cat(). Specifically, lzma_index doesn't
+ * become invalid if new Blocks are added to it with lzma_index_append() or
+ * if it is used as the destination in lzma_index_cat().
+ *
+ * It is safe to make copies of an initialized lzma_index_iter, for example,
+ * to easily restart reading at some particular position.
+ *
+ * \param       iter    Pointer to a lzma_index_iter structure
+ * \param       i       lzma_index to which the iterator will be associated
+ */
+extern LZMA_API(void) lzma_index_iter_init(
+		lzma_index_iter *iter, const lzma_index *i) lzma_nothrow;
+
+
+/**
+ * \brief       Rewind the iterator
+ *
+ * Rewind the iterator so that next call to lzma_index_iter_next() will
+ * return the first Block or Stream.
+ *
+ * \param       iter    Pointer to a lzma_index_iter structure
+ */
+extern LZMA_API(void) lzma_index_iter_rewind(lzma_index_iter *iter)
+		lzma_nothrow;
+
+
+/**
+ * \brief       Get the next Block or Stream
+ *
+ * \param       iter    Iterator initialized with lzma_index_iter_init()
+ * \param       mode    Specify what kind of information the caller wants
+ *                      to get. See lzma_index_iter_mode for details.
+ *
+ * \return      lzma_bool:
+ *              - true if no Block or Stream matching the mode is found.
+ *                *iter is not updated (failure).
+ *              - false if the next Block or Stream matching the mode was
+ *                found. *iter is updated (success).
+ */
+extern LZMA_API(lzma_bool) lzma_index_iter_next(
+		lzma_index_iter *iter, lzma_index_iter_mode mode)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Locate a Block
+ *
+ * If it is possible to seek in the .xz file, it is possible to parse
+ * the Index field(s) and use lzma_index_iter_locate() to do random-access
+ * reading with granularity of Block size.
+ *
+ * If the target is smaller than the uncompressed size of the Stream (can be
+ * checked with lzma_index_uncompressed_size()):
+ *  - Information about the Stream and Block containing the requested
+ *    uncompressed offset is stored into *iter.
+ *  - Internal state of the iterator is adjusted so that
+ *    lzma_index_iter_next() can be used to read subsequent Blocks or Streams.
+ *
+ * If the target is greater than the uncompressed size of the Stream, *iter
+ * is not modified.
+ *
+ * \param       iter    Iterator that was earlier initialized with
+ *                      lzma_index_iter_init().
+ * \param       target  Uncompressed target offset which the caller would
+ *                      like to locate from the Stream
+ *
+ * \return      lzma_bool:
+ *              - true if the target is greater than or equal to the
+ *                uncompressed size of the Stream (failure)
+ *              - false if the target is smaller than the uncompressed size
+ *                of the Stream (success)
+ */
+extern LZMA_API(lzma_bool) lzma_index_iter_locate(
+		lzma_index_iter *iter, lzma_vli target) lzma_nothrow;
+
+
+/**
+ * \brief       Concatenate lzma_indexes
+ *
+ * Concatenating lzma_indexes is useful when doing random-access reading in
+ * multi-Stream .xz file, or when combining multiple Streams into single
+ * Stream.
+ *
+ * \param[out]  dest      lzma_index after which src is appended
+ * \param       src       lzma_index to be appended after dest. If this
+ *                        function succeeds, the memory allocated for src
+ *                        is freed or moved to be part of dest, and all
+ *                        iterators pointing to src will become invalid.
+ * \param       allocator lzma_allocator for custom allocator functions.
+ *                        Set to NULL to use malloc() and free().
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: lzma_indexes were concatenated successfully.
+ *                src is now a dangling pointer.
+ *              - LZMA_DATA_ERROR: *dest would grow too big.
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_index_cat(lzma_index *dest, lzma_index *src,
+		const lzma_allocator *allocator)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Duplicate lzma_index
+ *
+ * \param       i         Pointer to lzma_index structure to be duplicated
+ * \param       allocator lzma_allocator for custom allocator functions.
+ *                        Set to NULL to use malloc() and free().
+ *
+ * \return      A copy of the lzma_index, or NULL if memory allocation failed.
+ */
+extern LZMA_API(lzma_index *) lzma_index_dup(
+		const lzma_index *i, const lzma_allocator *allocator)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Initialize .xz Index encoder
+ *
+ * \param       strm        Pointer to properly prepared lzma_stream
+ * \param       i           Pointer to lzma_index which should be encoded.
+ *
+ * The valid 'action' values for lzma_code() are LZMA_RUN and LZMA_FINISH.
+ * It is enough to use only one of them (you can choose freely).
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Initialization succeeded, continue with lzma_code().
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_index_encoder(
+		lzma_stream *strm, const lzma_index *i)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Initialize .xz Index decoder
+ *
+ * \param       strm        Pointer to properly prepared lzma_stream
+ * \param[out]  i           The decoded Index will be made available via
+ *                          this pointer. Initially this function will
+ *                          set *i to NULL (the old value is ignored). If
+ *                          decoding succeeds (lzma_code() returns
+ *                          LZMA_STREAM_END), *i will be set to point
+ *                          to a new lzma_index, which the application
+ *                          has to later free with lzma_index_end().
+ * \param       memlimit    How much memory the resulting lzma_index is
+ *                          allowed to require. liblzma 5.2.3 and earlier
+ *                          don't allow 0 here and return LZMA_PROG_ERROR;
+ *                          later versions treat 0 as if 1 had been specified.
+ *
+ * Valid 'action' arguments to lzma_code() are LZMA_RUN and LZMA_FINISH.
+ * There is no need to use LZMA_FINISH, but it's allowed because it may
+ * simplify certain types of applications.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Initialization succeeded, continue with lzma_code().
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_PROG_ERROR
+ *
+ * \note        liblzma 5.2.3 and older list also LZMA_MEMLIMIT_ERROR here
+ *              but that error code has never been possible from this
+ *              initialization function.
+ */
+extern LZMA_API(lzma_ret) lzma_index_decoder(
+		lzma_stream *strm, lzma_index **i, uint64_t memlimit)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Single-call .xz Index encoder
+ *
+ * \note        This function doesn't take allocator argument since all
+ *              the internal data is allocated on stack.
+ *
+ * \param       i         lzma_index to be encoded
+ * \param[out]  out       Beginning of the output buffer
+ * \param[out]  out_pos   The next byte will be written to out[*out_pos].
+ *                        *out_pos is updated only if encoding succeeds.
+ * \param       out_size  Size of the out buffer; the first byte into
+ *                        which no data is written to is out[out_size].
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Encoding was successful.
+ *              - LZMA_BUF_ERROR: Output buffer is too small. Use
+ *                lzma_index_size() to find out how much output
+ *                space is needed.
+ *              - LZMA_PROG_ERROR
+ *
+ */
+extern LZMA_API(lzma_ret) lzma_index_buffer_encode(const lzma_index *i,
+		uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
+
+
+/**
+ * \brief       Single-call .xz Index decoder
+ *
+ * \param[out]  i           If decoding succeeds, *i will point to a new
+ *                          lzma_index, which the application has to
+ *                          later free with lzma_index_end(). If an error
+ *                          occurs, *i will be NULL. The old value of *i
+ *                          is always ignored and thus doesn't need to be
+ *                          initialized by the caller.
+ * \param[out]  memlimit    Pointer to how much memory the resulting
+ *                          lzma_index is allowed to require. The value
+ *                          pointed by this pointer is modified if and only
+ *                          if LZMA_MEMLIMIT_ERROR is returned.
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ * \param       in          Beginning of the input buffer
+ * \param       in_pos      The next byte will be read from in[*in_pos].
+ *                          *in_pos is updated only if decoding succeeds.
+ * \param       in_size     Size of the input buffer; the first byte that
+ *                          won't be read is in[in_size].
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Decoding was successful.
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_MEMLIMIT_ERROR: Memory usage limit was reached.
+ *                The minimum required memlimit value was stored to *memlimit.
+ *              - LZMA_DATA_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_index_buffer_decode(lzma_index **i,
+		uint64_t *memlimit, const lzma_allocator *allocator,
+		const uint8_t *in, size_t *in_pos, size_t in_size)
+		lzma_nothrow;
+
+
+/**
+ * \brief       Initialize a .xz file information decoder
+ *
+ * This decoder decodes the Stream Header, Stream Footer, Index, and
+ * Stream Padding field(s) from the input .xz file and stores the resulting
+ * combined index in *dest_index. This information can be used to get the
+ * uncompressed file size with lzma_index_uncompressed_size(*dest_index) or,
+ * for example, to implement random access reading by locating the Blocks
+ * in the Streams.
+ *
+ * To get the required information from the .xz file, lzma_code() may ask
+ * the application to seek in the input file by returning LZMA_SEEK_NEEDED
+ * and having the target file position specified in lzma_stream.seek_pos.
+ * The number of seeks required depends on the input file and how big buffers
+ * the application provides. When possible, the decoder will seek backward
+ * and forward in the given buffer to avoid useless seek requests. Thus, if
+ * the application provides the whole file at once, no external seeking will
+ * be required (that is, lzma_code() won't return LZMA_SEEK_NEEDED).
+ *
+ * The value in lzma_stream.total_in can be used to estimate how much data
+ * liblzma had to read to get the file information. However, due to seeking
+ * and the way total_in is updated, the value of total_in will be somewhat
+ * inaccurate (a little too big). Thus, total_in is a good estimate but don't
+ * expect to see the same exact value for the same file if you change the
+ * input buffer size or switch to a different liblzma version.
+ *
+ * Valid 'action' arguments to lzma_code() are LZMA_RUN and LZMA_FINISH.
+ * You only need to use LZMA_RUN; LZMA_FINISH is only supported because it
+ * might be convenient for some applications. If you use LZMA_FINISH and if
+ * lzma_code() asks the application to seek, remember to reset 'action' back
+ * to LZMA_RUN unless you hit the end of the file again.
+ *
+ * Possible return values from lzma_code():
+ *   - LZMA_OK: All OK so far, more input needed
+ *   - LZMA_SEEK_NEEDED: Provide more input starting from the absolute
+ *     file position strm->seek_pos
+ *   - LZMA_STREAM_END: Decoding was successful, *dest_index has been set
+ *   - LZMA_FORMAT_ERROR: The input file is not in the .xz format (the
+ *     expected magic bytes were not found from the beginning of the file)
+ *   - LZMA_OPTIONS_ERROR: File looks valid but contains headers that aren't
+ *     supported by this version of liblzma
+ *   - LZMA_DATA_ERROR: File is corrupt
+ *   - LZMA_BUF_ERROR
+ *   - LZMA_MEM_ERROR
+ *   - LZMA_MEMLIMIT_ERROR
+ *   - LZMA_PROG_ERROR
+ *
+ * \param       strm        Pointer to a properly prepared lzma_stream
+ * \param[out]  dest_index  Pointer to a pointer where the decoder will put
+ *                          the decoded lzma_index. The old value
+ *                          of *dest_index is ignored (not freed).
+ * \param       memlimit    How much memory the resulting lzma_index is
+ *                          allowed to require. Use UINT64_MAX to
+ *                          effectively disable the limiter.
+ * \param       file_size   Size of the input .xz file
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_MEM_ERROR
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_file_info_decoder(
+		lzma_stream *strm, lzma_index **dest_index,
+		uint64_t memlimit, uint64_t file_size)
+		lzma_nothrow;
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index_hash.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index_hash.h
new file mode 100644
index 00000000000..68f9024eb3b
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/index_hash.h
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/**
+ * \file        lzma/index_hash.h
+ * \brief       Validate Index by using a hash function
+ * \note        Never include this file directly. Use  instead.
+ *
+ * Hashing makes it possible to use constant amount of memory to validate
+ * Index of arbitrary size.
+ */
+
+/*
+ * Author: Lasse Collin
+ */
+
+#ifndef LZMA_H_INTERNAL
+#	error Never include this file directly. Use  instead.
+#endif
+
+/**
+ * \brief       Opaque data type to hold the Index hash
+ */
+typedef struct lzma_index_hash_s lzma_index_hash;
+
+
+/**
+ * \brief       Allocate and initialize a new lzma_index_hash structure
+ *
+ * If index_hash is NULL, this function allocates and initializes a new
+ * lzma_index_hash structure and returns a pointer to it. If allocation
+ * fails, NULL is returned.
+ *
+ * If index_hash is non-NULL, this function reinitializes the lzma_index_hash
+ * structure and returns the same pointer. In this case, return value cannot
+ * be NULL or a different pointer than the index_hash that was given as
+ * an argument.
+ *
+ * \param       index_hash  Pointer to a lzma_index_hash structure or NULL.
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ *
+ * \return      Initialized lzma_index_hash structure on success or
+ *              NULL on failure.
+ */
+extern LZMA_API(lzma_index_hash *) lzma_index_hash_init(
+		lzma_index_hash *index_hash, const lzma_allocator *allocator)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Deallocate lzma_index_hash structure
+ *
+ * \param       index_hash  Pointer to a lzma_index_hash structure to free.
+ * \param       allocator   lzma_allocator for custom allocator functions.
+ *                          Set to NULL to use malloc() and free().
+ */
+extern LZMA_API(void) lzma_index_hash_end(
+		lzma_index_hash *index_hash, const lzma_allocator *allocator)
+		lzma_nothrow;
+
+
+/**
+ * \brief       Add a new Record to an Index hash
+ *
+ * \param       index_hash        Pointer to a lzma_index_hash structure
+ * \param       unpadded_size     Unpadded Size of a Block
+ * \param       uncompressed_size Uncompressed Size of a Block
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK
+ *              - LZMA_DATA_ERROR: Compressed or uncompressed size of the
+ *                Stream or size of the Index field would grow too big.
+ *              - LZMA_PROG_ERROR: Invalid arguments or this function is being
+ *                used when lzma_index_hash_decode() has already been used.
+ */
+extern LZMA_API(lzma_ret) lzma_index_hash_append(lzma_index_hash *index_hash,
+		lzma_vli unpadded_size, lzma_vli uncompressed_size)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Decode and validate the Index field
+ *
+ * After telling the sizes of all Blocks with lzma_index_hash_append(),
+ * the actual Index field is decoded with this function. Specifically,
+ * once decoding of the Index field has been started, no more Records
+ * can be added using lzma_index_hash_append().
+ *
+ * This function doesn't use lzma_stream structure to pass the input data.
+ * Instead, the input buffer is specified using three arguments. This is
+ * because it matches better the internal APIs of liblzma.
+ *
+ * \param       index_hash      Pointer to a lzma_index_hash structure
+ * \param       in              Pointer to the beginning of the input buffer
+ * \param[out]  in_pos          in[*in_pos] is the next byte to process
+ * \param       in_size         in[in_size] is the first byte not to process
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: So far good, but more input is needed.
+ *              - LZMA_STREAM_END: Index decoded successfully and it matches
+ *                the Records given with lzma_index_hash_append().
+ *              - LZMA_DATA_ERROR: Index is corrupt or doesn't match the
+ *                information given with lzma_index_hash_append().
+ *              - LZMA_BUF_ERROR: Cannot progress because *in_pos >= in_size.
+ *              - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_index_hash_decode(lzma_index_hash *index_hash,
+		const uint8_t *in, size_t *in_pos, size_t in_size)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Get the size of the Index field as bytes
+ *
+ * This is needed to verify the Backward Size field in the Stream Footer.
+ *
+ * \param       index_hash      Pointer to a lzma_index_hash structure
+ *
+ * \return      Size of the Index field in bytes.
+ */
+extern LZMA_API(lzma_vli) lzma_index_hash_size(
+		const lzma_index_hash *index_hash)
+		lzma_nothrow lzma_attr_pure;
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/lzma12.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/lzma12.h
new file mode 100644
index 00000000000..05f5b66eb56
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/lzma12.h
@@ -0,0 +1,568 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/**
+ * \file        lzma/lzma12.h
+ * \brief       LZMA1 and LZMA2 filters
+ * \note        Never include this file directly. Use  instead.
+ */
+
+/*
+ * Author: Lasse Collin
+ */
+
+#ifndef LZMA_H_INTERNAL
+#	error Never include this file directly. Use  instead.
+#endif
+
+
+/**
+ * \brief       LZMA1 Filter ID (for raw encoder/decoder only, not in .xz)
+ *
+ * LZMA1 is the very same thing as what was called just LZMA in LZMA Utils,
+ * 7-Zip, and LZMA SDK. It's called LZMA1 here to prevent developers from
+ * accidentally using LZMA when they actually want LZMA2.
+ */
+#define LZMA_FILTER_LZMA1       LZMA_VLI_C(0x4000000000000001)
+
+/**
+ * \brief       LZMA1 Filter ID with extended options (for raw encoder/decoder)
+ *
+ * This is like LZMA_FILTER_LZMA1 but with this ID a few extra options
+ * are supported in the lzma_options_lzma structure:
+ *
+ *   - A flag to tell the encoder if the end of payload marker (EOPM) alias
+ *     end of stream (EOS) marker must be written at the end of the stream.
+ *     In contrast, LZMA_FILTER_LZMA1 always writes the end marker.
+ *
+ *   - Decoder needs to be told the uncompressed size of the stream
+ *     or that it is unknown (using the special value UINT64_MAX).
+ *     If the size is known, a flag can be set to allow the presence of
+ *     the end marker anyway. In contrast, LZMA_FILTER_LZMA1 always
+ *     behaves as if the uncompressed size was unknown.
+ *
+ * This allows handling file formats where LZMA1 streams are used but where
+ * the end marker isn't allowed or where it might not (always) be present.
+ * This extended LZMA1 functionality is provided as a Filter ID for raw
+ * encoder and decoder instead of adding new encoder and decoder initialization
+ * functions because this way it is possible to also use extra filters,
+ * for example, LZMA_FILTER_X86 in a filter chain with LZMA_FILTER_LZMA1EXT,
+ * which might be needed to handle some file formats.
+ */
+#define LZMA_FILTER_LZMA1EXT    LZMA_VLI_C(0x4000000000000002)
+
+/**
+ * \brief       LZMA2 Filter ID
+ *
+ * Usually you want this instead of LZMA1. Compared to LZMA1, LZMA2 adds
+ * support for LZMA_SYNC_FLUSH, uncompressed chunks (smaller expansion
+ * when trying to compress incompressible data), possibility to change
+ * lc/lp/pb in the middle of encoding, and some other internal improvements.
+ */
+#define LZMA_FILTER_LZMA2       LZMA_VLI_C(0x21)
+
+
+/**
+ * \brief       Match finders
+ *
+ * Match finder has major effect on both speed and compression ratio.
+ * Usually hash chains are faster than binary trees.
+ *
+ * If you will use LZMA_SYNC_FLUSH often, the hash chains may be a better
+ * choice, because binary trees get much higher compression ratio penalty
+ * with LZMA_SYNC_FLUSH.
+ *
+ * The memory usage formulas are only rough estimates, which are closest to
+ * reality when dict_size is a power of two. The formulas are  more complex
+ * in reality, and can also change a little between liblzma versions. Use
+ * lzma_raw_encoder_memusage() to get more accurate estimate of memory usage.
+ */
+typedef enum {
+	LZMA_MF_HC3     = 0x03,
+		/**<
+		 * \brief       Hash Chain with 2- and 3-byte hashing
+		 *
+		 * Minimum nice_len: 3
+		 *
+		 * Memory usage:
+		 *  - dict_size <= 16 MiB: dict_size * 7.5
+		 *  - dict_size > 16 MiB: dict_size * 5.5 + 64 MiB
+		 */
+
+	LZMA_MF_HC4     = 0x04,
+		/**<
+		 * \brief       Hash Chain with 2-, 3-, and 4-byte hashing
+		 *
+		 * Minimum nice_len: 4
+		 *
+		 * Memory usage:
+		 *  - dict_size <= 32 MiB: dict_size * 7.5
+		 *  - dict_size > 32 MiB: dict_size * 6.5
+		 */
+
+	LZMA_MF_BT2     = 0x12,
+		/**<
+		 * \brief       Binary Tree with 2-byte hashing
+		 *
+		 * Minimum nice_len: 2
+		 *
+		 * Memory usage: dict_size * 9.5
+		 */
+
+	LZMA_MF_BT3     = 0x13,
+		/**<
+		 * \brief       Binary Tree with 2- and 3-byte hashing
+		 *
+		 * Minimum nice_len: 3
+		 *
+		 * Memory usage:
+		 *  - dict_size <= 16 MiB: dict_size * 11.5
+		 *  - dict_size > 16 MiB: dict_size * 9.5 + 64 MiB
+		 */
+
+	LZMA_MF_BT4     = 0x14
+		/**<
+		 * \brief       Binary Tree with 2-, 3-, and 4-byte hashing
+		 *
+		 * Minimum nice_len: 4
+		 *
+		 * Memory usage:
+		 *  - dict_size <= 32 MiB: dict_size * 11.5
+		 *  - dict_size > 32 MiB: dict_size * 10.5
+		 */
+} lzma_match_finder;
+
+
+/**
+ * \brief       Test if given match finder is supported
+ *
+ * It is safe to call this with a value that isn't listed in
+ * lzma_match_finder enumeration; the return value will be false.
+ *
+ * There is no way to list which match finders are available in this
+ * particular liblzma version and build. It would be useless, because
+ * a new match finder, which the application developer wasn't aware,
+ * could require giving additional options to the encoder that the older
+ * match finders don't need.
+ *
+ * \param       match_finder    Match finder ID
+ *
+ * \return      lzma_bool:
+ *              - true if the match finder is supported by this liblzma build.
+ *              - false otherwise.
+ */
+extern LZMA_API(lzma_bool) lzma_mf_is_supported(lzma_match_finder match_finder)
+		lzma_nothrow lzma_attr_const;
+
+
+/**
+ * \brief       Compression modes
+ *
+ * This selects the function used to analyze the data produced by the match
+ * finder.
+ */
+typedef enum {
+	LZMA_MODE_FAST = 1,
+		/**<
+		 * \brief       Fast compression
+		 *
+		 * Fast mode is usually at its best when combined with
+		 * a hash chain match finder.
+		 */
+
+	LZMA_MODE_NORMAL = 2
+		/**<
+		 * \brief       Normal compression
+		 *
+		 * This is usually notably slower than fast mode. Use this
+		 * together with binary tree match finders to expose the
+		 * full potential of the LZMA1 or LZMA2 encoder.
+		 */
+} lzma_mode;
+
+
+/**
+ * \brief       Test if given compression mode is supported
+ *
+ * It is safe to call this with a value that isn't listed in lzma_mode
+ * enumeration; the return value will be false.
+ *
+ * There is no way to list which modes are available in this particular
+ * liblzma version and build. It would be useless, because a new compression
+ * mode, which the application developer wasn't aware, could require giving
+ * additional options to the encoder that the older modes don't need.
+ *
+ * \param       mode    Mode ID.
+ *
+ * \return      lzma_bool:
+ *              - true if the compression mode is supported by this liblzma
+ *                build.
+ *              - false otherwise.
+ */
+extern LZMA_API(lzma_bool) lzma_mode_is_supported(lzma_mode mode)
+		lzma_nothrow lzma_attr_const;
+
+
+/**
+ * \brief       Options specific to the LZMA1 and LZMA2 filters
+ *
+ * Since LZMA1 and LZMA2 share most of the code, it's simplest to share
+ * the options structure too. For encoding, all but the reserved variables
+ * need to be initialized unless specifically mentioned otherwise.
+ * lzma_lzma_preset() can be used to get a good starting point.
+ *
+ * For raw decoding, both LZMA1 and LZMA2 need dict_size, preset_dict, and
+ * preset_dict_size (if preset_dict != NULL). LZMA1 needs also lc, lp, and pb.
+ */
+typedef struct {
+	/**
+	 * \brief       Dictionary size in bytes
+	 *
+	 * Dictionary size indicates how many bytes of the recently processed
+	 * uncompressed data is kept in memory. One method to reduce size of
+	 * the uncompressed data is to store distance-length pairs, which
+	 * indicate what data to repeat from the dictionary buffer. Thus,
+	 * the bigger the dictionary, the better the compression ratio
+	 * usually is.
+	 *
+	 * Maximum size of the dictionary depends on multiple things:
+	 *  - Memory usage limit
+	 *  - Available address space (not a problem on 64-bit systems)
+	 *  - Selected match finder (encoder only)
+	 *
+	 * Currently the maximum dictionary size for encoding is 1.5 GiB
+	 * (i.e. (UINT32_C(1) << 30) + (UINT32_C(1) << 29)) even on 64-bit
+	 * systems for certain match finder implementation reasons. In the
+	 * future, there may be match finders that support bigger
+	 * dictionaries.
+	 *
+	 * Decoder already supports dictionaries up to 4 GiB - 1 B (i.e.
+	 * UINT32_MAX), so increasing the maximum dictionary size of the
+	 * encoder won't cause problems for old decoders.
+	 *
+	 * Because extremely small dictionaries sizes would have unneeded
+	 * overhead in the decoder, the minimum dictionary size is 4096 bytes.
+	 *
+	 * \note        When decoding, too big dictionary does no other harm
+	 *              than wasting memory.
+	 */
+	uint32_t dict_size;
+#	define LZMA_DICT_SIZE_MIN       UINT32_C(4096)
+#	define LZMA_DICT_SIZE_DEFAULT   (UINT32_C(1) << 23)
+
+	/**
+	 * \brief       Pointer to an initial dictionary
+	 *
+	 * It is possible to initialize the LZ77 history window using
+	 * a preset dictionary. It is useful when compressing many
+	 * similar, relatively small chunks of data independently from
+	 * each other. The preset dictionary should contain typical
+	 * strings that occur in the files being compressed. The most
+	 * probable strings should be near the end of the preset dictionary.
+	 *
+	 * This feature should be used only in special situations. For
+	 * now, it works correctly only with raw encoding and decoding.
+	 * Currently none of the container formats supported by
+	 * liblzma allow preset dictionary when decoding, thus if
+	 * you create a .xz or .lzma file with preset dictionary, it
+	 * cannot be decoded with the regular decoder functions. In the
+	 * future, the .xz format will likely get support for preset
+	 * dictionary though.
+	 */
+	const uint8_t *preset_dict;
+
+	/**
+	 * \brief       Size of the preset dictionary
+	 *
+	 * Specifies the size of the preset dictionary. If the size is
+	 * bigger than dict_size, only the last dict_size bytes are
+	 * processed.
+	 *
+	 * This variable is read only when preset_dict is not NULL.
+	 * If preset_dict is not NULL but preset_dict_size is zero,
+	 * no preset dictionary is used (identical to only setting
+	 * preset_dict to NULL).
+	 */
+	uint32_t preset_dict_size;
+
+	/**
+	 * \brief       Number of literal context bits
+	 *
+	 * How many of the highest bits of the previous uncompressed
+	 * eight-bit byte (also known as 'literal') are taken into
+	 * account when predicting the bits of the next literal.
+	 *
+	 * E.g. in typical English text, an upper-case letter is
+	 * often followed by a lower-case letter, and a lower-case
+	 * letter is usually followed by another lower-case letter.
+	 * In the US-ASCII character set, the highest three bits are 010
+	 * for upper-case letters and 011 for lower-case letters.
+	 * When lc is at least 3, the literal coding can take advantage of
+	 * this property in the uncompressed data.
+	 *
+	 * There is a limit that applies to literal context bits and literal
+	 * position bits together: lc + lp <= 4. Without this limit the
+	 * decoding could become very slow, which could have security related
+	 * results in some cases like email servers doing virus scanning.
+	 * This limit also simplifies the internal implementation in liblzma.
+	 *
+	 * There may be LZMA1 streams that have lc + lp > 4 (maximum possible
+	 * lc would be 8). It is not possible to decode such streams with
+	 * liblzma.
+	 */
+	uint32_t lc;
+#	define LZMA_LCLP_MIN    0
+#	define LZMA_LCLP_MAX    4
+#	define LZMA_LC_DEFAULT  3
+
+	/**
+	 * \brief       Number of literal position bits
+	 *
+	 * lp affects what kind of alignment in the uncompressed data is
+	 * assumed when encoding literals. A literal is a single 8-bit byte.
+	 * See pb below for more information about alignment.
+	 */
+	uint32_t lp;
+#	define LZMA_LP_DEFAULT  0
+
+	/**
+	 * \brief       Number of position bits
+	 *
+	 * pb affects what kind of alignment in the uncompressed data is
+	 * assumed in general. The default means four-byte alignment
+	 * (2^ pb =2^2=4), which is often a good choice when there's
+	 * no better guess.
+	 *
+	 * When the alignment is known, setting pb accordingly may reduce
+	 * the file size a little. E.g. with text files having one-byte
+	 * alignment (US-ASCII, ISO-8859-*, UTF-8), setting pb=0 can
+	 * improve compression slightly. For UTF-16 text, pb=1 is a good
+	 * choice. If the alignment is an odd number like 3 bytes, pb=0
+	 * might be the best choice.
+	 *
+	 * Even though the assumed alignment can be adjusted with pb and
+	 * lp, LZMA1 and LZMA2 still slightly favor 16-byte alignment.
+	 * It might be worth taking into account when designing file formats
+	 * that are likely to be often compressed with LZMA1 or LZMA2.
+	 */
+	uint32_t pb;
+#	define LZMA_PB_MIN      0
+#	define LZMA_PB_MAX      4
+#	define LZMA_PB_DEFAULT  2
+
+	/** Compression mode */
+	lzma_mode mode;
+
+	/**
+	 * \brief       Nice length of a match
+	 *
+	 * This determines how many bytes the encoder compares from the match
+	 * candidates when looking for the best match. Once a match of at
+	 * least nice_len bytes long is found, the encoder stops looking for
+	 * better candidates and encodes the match. (Naturally, if the found
+	 * match is actually longer than nice_len, the actual length is
+	 * encoded; it's not truncated to nice_len.)
+	 *
+	 * Bigger values usually increase the compression ratio and
+	 * compression time. For most files, 32 to 128 is a good value,
+	 * which gives very good compression ratio at good speed.
+	 *
+	 * The exact minimum value depends on the match finder. The maximum
+	 * is 273, which is the maximum length of a match that LZMA1 and
+	 * LZMA2 can encode.
+	 */
+	uint32_t nice_len;
+
+	/** Match finder ID */
+	lzma_match_finder mf;
+
+	/**
+	 * \brief       Maximum search depth in the match finder
+	 *
+	 * For every input byte, match finder searches through the hash chain
+	 * or binary tree in a loop, each iteration going one step deeper in
+	 * the chain or tree. The searching stops if
+	 *  - a match of at least nice_len bytes long is found;
+	 *  - all match candidates from the hash chain or binary tree have
+	 *    been checked; or
+	 *  - maximum search depth is reached.
+	 *
+	 * Maximum search depth is needed to prevent the match finder from
+	 * wasting too much time in case there are lots of short match
+	 * candidates. On the other hand, stopping the search before all
+	 * candidates have been checked can reduce compression ratio.
+	 *
+	 * Setting depth to zero tells liblzma to use an automatic default
+	 * value, that depends on the selected match finder and nice_len.
+	 * The default is in the range [4, 200] or so (it may vary between
+	 * liblzma versions).
+	 *
+	 * Using a bigger depth value than the default can increase
+	 * compression ratio in some cases. There is no strict maximum value,
+	 * but high values (thousands or millions) should be used with care:
+	 * the encoder could remain fast enough with typical input, but
+	 * malicious input could cause the match finder to slow down
+	 * dramatically, possibly creating a denial of service attack.
+	 */
+	uint32_t depth;
+
+	/**
+	 * \brief       For LZMA_FILTER_LZMA1EXT: Extended flags
+	 *
+	 * This is used only with LZMA_FILTER_LZMA1EXT.
+	 *
+	 * Currently only one flag is supported, LZMA_LZMA1EXT_ALLOW_EOPM:
+	 *
+	 *   - Encoder: If the flag is set, then end marker is written just
+	 *     like it is with LZMA_FILTER_LZMA1. Without this flag the
+	 *     end marker isn't written and the application has to store
+	 *     the uncompressed size somewhere outside the compressed stream.
+	 *     To decompress streams without the end marker, the application
+	 *     has to set the correct uncompressed size in ext_size_low and
+	 *     ext_size_high.
+	 *
+	 *   - Decoder: If the uncompressed size in ext_size_low and
+	 *     ext_size_high is set to the special value UINT64_MAX
+	 *     (indicating unknown uncompressed size) then this flag is
+	 *     ignored and the end marker must always be present, that is,
+	 *     the behavior is identical to LZMA_FILTER_LZMA1.
+	 *
+	 *     Otherwise, if this flag isn't set, then the input stream
+	 *     must not have the end marker; if the end marker is detected
+	 *     then it will result in LZMA_DATA_ERROR. This is useful when
+	 *     it is known that the stream must not have the end marker and
+	 *     strict validation is wanted.
+	 *
+	 *     If this flag is set, then it is autodetected if the end marker
+	 *     is present after the specified number of uncompressed bytes
+	 *     has been decompressed (ext_size_low and ext_size_high). The
+	 *     end marker isn't allowed in any other position. This behavior
+	 *     is useful when uncompressed size is known but the end marker
+	 *     may or may not be present. This is the case, for example,
+	 *     in .7z files (valid .7z files that have the end marker in
+	 *     LZMA1 streams are rare but they do exist).
+	 */
+	uint32_t ext_flags;
+#	define LZMA_LZMA1EXT_ALLOW_EOPM   UINT32_C(0x01)
+
+	/**
+	 * \brief       For LZMA_FILTER_LZMA1EXT: Uncompressed size (low bits)
+	 *
+	 * The 64-bit uncompressed size is needed for decompression with
+	 * LZMA_FILTER_LZMA1EXT. The size is ignored by the encoder.
+	 *
+	 * The special value UINT64_MAX indicates that the uncompressed size
+	 * is unknown and that the end of payload marker (also known as
+	 * end of stream marker) must be present to indicate the end of
+	 * the LZMA1 stream. Any other value indicates the expected
+	 * uncompressed size of the LZMA1 stream. (If LZMA1 was used together
+	 * with filters that change the size of the data then the uncompressed
+	 * size of the LZMA1 stream could be different than the final
+	 * uncompressed size of the filtered stream.)
+	 *
+	 * ext_size_low holds the least significant 32 bits of the
+	 * uncompressed size. The most significant 32 bits must be set
+	 * in ext_size_high. The macro lzma_ext_size_set(opt_lzma, u64size)
+	 * can be used to set these members.
+	 *
+	 * The 64-bit uncompressed size is split into two uint32_t variables
+	 * because there were no reserved uint64_t members and using the
+	 * same options structure for LZMA_FILTER_LZMA1, LZMA_FILTER_LZMA1EXT,
+	 * and LZMA_FILTER_LZMA2 was otherwise more convenient than having
+	 * a new options structure for LZMA_FILTER_LZMA1EXT. (Replacing two
+	 * uint32_t members with one uint64_t changes the ABI on some systems
+	 * as the alignment of this struct can increase from 4 bytes to 8.)
+	 */
+	uint32_t ext_size_low;
+
+	/**
+	 * \brief       For LZMA_FILTER_LZMA1EXT: Uncompressed size (high bits)
+	 *
+	 * This holds the most significant 32 bits of the uncompressed size.
+	 */
+	uint32_t ext_size_high;
+
+	/*
+	 * Reserved space to allow possible future extensions without
+	 * breaking the ABI. You should not touch these, because the names
+	 * of these variables may change. These are and will never be used
+	 * with the currently supported options, so it is safe to leave these
+	 * uninitialized.
+	 */
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int4;
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int5;
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int6;
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int7;
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int8;
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum1;
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum2;
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum3;
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum4;
+
+	/** \private     Reserved member. */
+	void *reserved_ptr1;
+
+	/** \private     Reserved member. */
+	void *reserved_ptr2;
+
+} lzma_options_lzma;
+
+
+/**
+ * \brief       Macro to set the 64-bit uncompressed size in ext_size_*
+ *
+ * This might be convenient when decoding using LZMA_FILTER_LZMA1EXT.
+ * This isn't used with LZMA_FILTER_LZMA1 or LZMA_FILTER_LZMA2.
+ */
+#define lzma_set_ext_size(opt_lzma2, u64size) \
+do { \
+	(opt_lzma2).ext_size_low = (uint32_t)(u64size); \
+	(opt_lzma2).ext_size_high = (uint32_t)((uint64_t)(u64size) >> 32); \
+} while (0)
+
+
+/**
+ * \brief       Set a compression preset to lzma_options_lzma structure
+ *
+ * 0 is the fastest and 9 is the slowest. These match the switches -0 .. -9
+ * of the xz command line tool. In addition, it is possible to bitwise-or
+ * flags to the preset. Currently only LZMA_PRESET_EXTREME is supported.
+ * The flags are defined in container.h, because the flags are used also
+ * with lzma_easy_encoder().
+ *
+ * The preset levels are subject to changes between liblzma versions.
+ *
+ * This function is available only if LZMA1 or LZMA2 encoder has been enabled
+ * when building liblzma.
+ *
+ * If features (like certain match finders) have been disabled at build time,
+ * then the function may return success (false) even though the resulting
+ * LZMA1/LZMA2 options may not be usable for encoder initialization
+ * (LZMA_OPTIONS_ERROR).
+ *
+ * \param[out]  options Pointer to LZMA1 or LZMA2 options to be filled
+ * \param       preset  Preset level bitwse-ORed with preset flags
+ *
+ * \return      lzma_bool:
+ *              - true if the preset is not supported (failure).
+ *              - false otherwise (success).
+ */
+extern LZMA_API(lzma_bool) lzma_lzma_preset(
+		lzma_options_lzma *options, uint32_t preset) lzma_nothrow;
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/stream_flags.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/stream_flags.h
new file mode 100644
index 00000000000..a33fe468376
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/stream_flags.h
@@ -0,0 +1,265 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/**
+ * \file        lzma/stream_flags.h
+ * \brief       .xz Stream Header and Stream Footer encoder and decoder
+ * \note        Never include this file directly. Use  instead.
+ */
+
+/*
+ * Author: Lasse Collin
+ */
+
+#ifndef LZMA_H_INTERNAL
+#	error Never include this file directly. Use  instead.
+#endif
+
+
+/**
+ * \brief       Size of Stream Header and Stream Footer
+ *
+ * Stream Header and Stream Footer have the same size and they are not
+ * going to change even if a newer version of the .xz file format is
+ * developed in future.
+ */
+#define LZMA_STREAM_HEADER_SIZE 12
+
+
+/**
+ * \brief       Options for encoding/decoding Stream Header and Stream Footer
+ */
+typedef struct {
+	/**
+	 * \brief       Stream Flags format version
+	 *
+	 * To prevent API and ABI breakages if new features are needed in
+	 * Stream Header or Stream Footer, a version number is used to
+	 * indicate which members in this structure are in use. For now,
+	 * version must always be zero. With non-zero version, the
+	 * lzma_stream_header_encode() and lzma_stream_footer_encode()
+	 * will return LZMA_OPTIONS_ERROR.
+	 *
+	 * lzma_stream_header_decode() and lzma_stream_footer_decode()
+	 * will always set this to the lowest value that supports all the
+	 * features indicated by the Stream Flags field. The application
+	 * must check that the version number set by the decoding functions
+	 * is supported by the application. Otherwise it is possible that
+	 * the application will decode the Stream incorrectly.
+	 */
+	uint32_t version;
+
+	/**
+	 * \brief       Backward Size
+	 *
+	 * Backward Size must be a multiple of four bytes. In this Stream
+	 * format version, Backward Size is the size of the Index field.
+	 *
+	 * Backward Size isn't actually part of the Stream Flags field, but
+	 * it is convenient to include in this structure anyway. Backward
+	 * Size is present only in the Stream Footer. There is no need to
+	 * initialize backward_size when encoding Stream Header.
+	 *
+	 * lzma_stream_header_decode() always sets backward_size to
+	 * LZMA_VLI_UNKNOWN so that it is convenient to use
+	 * lzma_stream_flags_compare() when both Stream Header and Stream
+	 * Footer have been decoded.
+	 */
+	lzma_vli backward_size;
+
+	/**
+	 * \brief       Minimum value for lzma_stream_flags.backward_size
+	 */
+#	define LZMA_BACKWARD_SIZE_MIN 4
+
+	/**
+	 * \brief       Maximum value for lzma_stream_flags.backward_size
+	 */
+#	define LZMA_BACKWARD_SIZE_MAX (LZMA_VLI_C(1) << 34)
+
+	/**
+	 * \brief       Check ID
+	 *
+	 * This indicates the type of the integrity check calculated from
+	 * uncompressed data.
+	 */
+	lzma_check check;
+
+	/*
+	 * Reserved space to allow possible future extensions without
+	 * breaking the ABI. You should not touch these, because the
+	 * names of these variables may change.
+	 *
+	 * (We will never be able to use all of these since Stream Flags
+	 * is just two bytes plus Backward Size of four bytes. But it's
+	 * nice to have the proper types when they are needed.)
+	 */
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum1;
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum2;
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum3;
+
+	/** \private     Reserved member. */
+	lzma_reserved_enum reserved_enum4;
+
+	/** \private     Reserved member. */
+	lzma_bool reserved_bool1;
+
+	/** \private     Reserved member. */
+	lzma_bool reserved_bool2;
+
+	/** \private     Reserved member. */
+	lzma_bool reserved_bool3;
+
+	/** \private     Reserved member. */
+	lzma_bool reserved_bool4;
+
+	/** \private     Reserved member. */
+	lzma_bool reserved_bool5;
+
+	/** \private     Reserved member. */
+	lzma_bool reserved_bool6;
+
+	/** \private     Reserved member. */
+	lzma_bool reserved_bool7;
+
+	/** \private     Reserved member. */
+	lzma_bool reserved_bool8;
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int1;
+
+	/** \private     Reserved member. */
+	uint32_t reserved_int2;
+
+} lzma_stream_flags;
+
+
+/**
+ * \brief       Encode Stream Header
+ *
+ * \param       options     Stream Header options to be encoded.
+ *                          options->backward_size is ignored and doesn't
+ *                          need to be initialized.
+ * \param[out]  out         Beginning of the output buffer of
+ *                          LZMA_STREAM_HEADER_SIZE bytes.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Encoding was successful.
+ *              - LZMA_OPTIONS_ERROR: options->version is not supported by
+ *                this liblzma version.
+ *              - LZMA_PROG_ERROR: Invalid options.
+ */
+extern LZMA_API(lzma_ret) lzma_stream_header_encode(
+		const lzma_stream_flags *options, uint8_t *out)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Encode Stream Footer
+ *
+ * \param       options     Stream Footer options to be encoded.
+ * \param[out]  out         Beginning of the output buffer of
+ *                          LZMA_STREAM_HEADER_SIZE bytes.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Encoding was successful.
+ *              - LZMA_OPTIONS_ERROR: options->version is not supported by
+ *                this liblzma version.
+ *              - LZMA_PROG_ERROR: Invalid options.
+ */
+extern LZMA_API(lzma_ret) lzma_stream_footer_encode(
+		const lzma_stream_flags *options, uint8_t *out)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Decode Stream Header
+ *
+ * options->backward_size is always set to LZMA_VLI_UNKNOWN. This is to
+ * help comparing Stream Flags from Stream Header and Stream Footer with
+ * lzma_stream_flags_compare().
+ *
+ * \note        When decoding .xz files that contain multiple Streams, it may
+ *              make sense to print "file format not recognized" only if
+ *              decoding of the Stream Header of the \a first Stream gives
+ *              LZMA_FORMAT_ERROR. If non-first Stream Header gives
+ *              LZMA_FORMAT_ERROR, the message used for LZMA_DATA_ERROR is
+ *              probably more appropriate.
+ *              For example, the Stream decoder in liblzma uses
+ *              LZMA_DATA_ERROR if LZMA_FORMAT_ERROR is returned by
+ *              lzma_stream_header_decode() when decoding non-first Stream.
+ *
+ * \param[out]  options     Target for the decoded Stream Header options.
+ * \param       in          Beginning of the input buffer of
+ *                          LZMA_STREAM_HEADER_SIZE bytes.
+ *
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Decoding was successful.
+ *              - LZMA_FORMAT_ERROR: Magic bytes don't match, thus the given
+ *                buffer cannot be Stream Header.
+ *              - LZMA_DATA_ERROR: CRC32 doesn't match, thus the header
+ *                is corrupt.
+ *              - LZMA_OPTIONS_ERROR: Unsupported options are present
+ *                in the header.
+ */
+extern LZMA_API(lzma_ret) lzma_stream_header_decode(
+		lzma_stream_flags *options, const uint8_t *in)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Decode Stream Footer
+ *
+ * \note        If Stream Header was already decoded successfully, but
+ *              decoding Stream Footer returns LZMA_FORMAT_ERROR, the
+ *              application should probably report some other error message
+ *              than "file format not recognized". The file likely
+ *              is corrupt (possibly truncated). The Stream decoder in liblzma
+ *              uses LZMA_DATA_ERROR in this situation.
+ *
+ * \param[out]  options     Target for the decoded Stream Footer options.
+ * \param       in          Beginning of the input buffer of
+ *                          LZMA_STREAM_HEADER_SIZE bytes.
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Decoding was successful.
+ *              - LZMA_FORMAT_ERROR: Magic bytes don't match, thus the given
+ *                buffer cannot be Stream Footer.
+ *              - LZMA_DATA_ERROR: CRC32 doesn't match, thus the Stream Footer
+ *                is corrupt.
+ *              - LZMA_OPTIONS_ERROR: Unsupported options are present
+ *                in Stream Footer.
+ */
+extern LZMA_API(lzma_ret) lzma_stream_footer_decode(
+		lzma_stream_flags *options, const uint8_t *in)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief       Compare two lzma_stream_flags structures
+ *
+ * backward_size values are compared only if both are not
+ * LZMA_VLI_UNKNOWN.
+ *
+ * \param       a       Pointer to lzma_stream_flags structure
+ * \param       b       Pointer to lzma_stream_flags structure
+ *
+ * \return      Possible lzma_ret values:
+ *              - LZMA_OK: Both are equal. If either had backward_size set
+ *                to LZMA_VLI_UNKNOWN, backward_size values were not
+ *                compared or validated.
+ *              - LZMA_DATA_ERROR: The structures differ.
+ *              - LZMA_OPTIONS_ERROR: version in either structure is greater
+ *                than the maximum supported version (currently zero).
+ *              - LZMA_PROG_ERROR: Invalid value, e.g. invalid check or
+ *                backward_size.
+ */
+extern LZMA_API(lzma_ret) lzma_stream_flags_compare(
+		const lzma_stream_flags *a, const lzma_stream_flags *b)
+		lzma_nothrow lzma_attr_pure;
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/version.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/version.h
new file mode 100644
index 00000000000..e86c0ea4c3d
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/version.h
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/**
+ * \file        lzma/version.h
+ * \brief       Version number
+ * \note        Never include this file directly. Use  instead.
+ */
+
+/*
+ * Author: Lasse Collin
+ */
+
+#ifndef LZMA_H_INTERNAL
+#	error Never include this file directly. Use  instead.
+#endif
+
+
+/** \brief Major version number of the liblzma release. */
+#define LZMA_VERSION_MAJOR 5
+
+/** \brief Minor version number of the liblzma release. */
+#define LZMA_VERSION_MINOR 6
+
+/** \brief Patch version number of the liblzma release. */
+#define LZMA_VERSION_PATCH 3
+
+/**
+ * \brief Version stability marker
+ *
+ * This will always be one of three values:
+ *   - LZMA_VERSION_STABILITY_ALPHA
+ *   - LZMA_VERSION_STABILITY_BETA
+ *   - LZMA_VERSION_STABILITY_STABLE
+ */
+#define LZMA_VERSION_STABILITY LZMA_VERSION_STABILITY_STABLE
+
+/** \brief Commit version number of the liblzma release */
+#ifndef LZMA_VERSION_COMMIT
+#	define LZMA_VERSION_COMMIT ""
+#endif
+
+
+/*
+ * Map symbolic stability levels to integers.
+ */
+#define LZMA_VERSION_STABILITY_ALPHA 0
+#define LZMA_VERSION_STABILITY_BETA 1
+#define LZMA_VERSION_STABILITY_STABLE 2
+
+
+/**
+ * \brief       Compile-time version number
+ *
+ * The version number is of format xyyyzzzs where
+ *  - x = major
+ *  - yyy = minor
+ *  - zzz = revision
+ *  - s indicates stability: 0 = alpha, 1 = beta, 2 = stable
+ *
+ * The same xyyyzzz triplet is never reused with different stability levels.
+ * For example, if 5.1.0alpha has been released, there will never be 5.1.0beta
+ * or 5.1.0 stable.
+ *
+ * \note        The version number of liblzma has nothing to with
+ *              the version number of Igor Pavlov's LZMA SDK.
+ */
+#define LZMA_VERSION (LZMA_VERSION_MAJOR * UINT32_C(10000000) \
+		+ LZMA_VERSION_MINOR * UINT32_C(10000) \
+		+ LZMA_VERSION_PATCH * UINT32_C(10) \
+		+ LZMA_VERSION_STABILITY)
+
+
+/*
+ * Macros to construct the compile-time version string
+ */
+#if LZMA_VERSION_STABILITY == LZMA_VERSION_STABILITY_ALPHA
+#	define LZMA_VERSION_STABILITY_STRING "alpha"
+#elif LZMA_VERSION_STABILITY == LZMA_VERSION_STABILITY_BETA
+#	define LZMA_VERSION_STABILITY_STRING "beta"
+#elif LZMA_VERSION_STABILITY == LZMA_VERSION_STABILITY_STABLE
+#	define LZMA_VERSION_STABILITY_STRING ""
+#else
+#	error Incorrect LZMA_VERSION_STABILITY
+#endif
+
+#define LZMA_VERSION_STRING_C_(major, minor, patch, stability, commit) \
+		#major "." #minor "." #patch stability commit
+
+#define LZMA_VERSION_STRING_C(major, minor, patch, stability, commit) \
+		LZMA_VERSION_STRING_C_(major, minor, patch, stability, commit)
+
+
+/**
+ * \brief       Compile-time version as a string
+ *
+ * This can be for example "4.999.5alpha", "4.999.8beta", or "5.0.0" (stable
+ * versions don't have any "stable" suffix). In future, a snapshot built
+ * from source code repository may include an additional suffix, for example
+ * "4.999.8beta-21-g1d92". The commit ID won't be available in numeric form
+ * in LZMA_VERSION macro.
+ */
+#define LZMA_VERSION_STRING LZMA_VERSION_STRING_C( \
+		LZMA_VERSION_MAJOR, LZMA_VERSION_MINOR, \
+		LZMA_VERSION_PATCH, LZMA_VERSION_STABILITY_STRING, \
+		LZMA_VERSION_COMMIT)
+
+
+/* #ifndef is needed for use with windres (MinGW-w64 or Cygwin). */
+#ifndef LZMA_H_INTERNAL_RC
+
+/**
+ * \brief       Run-time version number as an integer
+ *
+ * This allows an application to compare if it was built against the same,
+ * older, or newer version of liblzma that is currently running.
+ *
+ * \return The value of LZMA_VERSION macro at the compile time of liblzma
+ */
+extern LZMA_API(uint32_t) lzma_version_number(void)
+		lzma_nothrow lzma_attr_const;
+
+
+/**
+ * \brief       Run-time version as a string
+ *
+ * This function may be useful to display which version of liblzma an
+ * application is currently using.
+ *
+ * \return      Run-time version of liblzma
+ */
+extern LZMA_API(const char *) lzma_version_string(void)
+		lzma_nothrow lzma_attr_const;
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/vli.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/vli.h
new file mode 100644
index 00000000000..6b049021b90
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/api/lzma/vli.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/**
+ * \file        lzma/vli.h
+ * \brief       Variable-length integer handling
+ * \note        Never include this file directly. Use  instead.
+ *
+ * In the .xz format, most integers are encoded in a variable-length
+ * representation, which is sometimes called little endian base-128 encoding.
+ * This saves space when smaller values are more likely than bigger values.
+ *
+ * The encoding scheme encodes seven bits to every byte, using minimum
+ * number of bytes required to represent the given value. Encodings that use
+ * non-minimum number of bytes are invalid, thus every integer has exactly
+ * one encoded representation. The maximum number of bits in a VLI is 63,
+ * thus the vli argument must be less than or equal to UINT64_MAX / 2. You
+ * should use LZMA_VLI_MAX for clarity.
+ */
+
+/*
+ * Author: Lasse Collin
+ */
+
+#ifndef LZMA_H_INTERNAL
+#	error Never include this file directly. Use  instead.
+#endif
+
+
+/**
+ * \brief       Maximum supported value of a variable-length integer
+ */
+#define LZMA_VLI_MAX (UINT64_MAX / 2)
+
+/**
+ * \brief       VLI value to denote that the value is unknown
+ */
+#define LZMA_VLI_UNKNOWN UINT64_MAX
+
+/**
+ * \brief       Maximum supported encoded length of variable length integers
+ */
+#define LZMA_VLI_BYTES_MAX 9
+
+/**
+ * \brief       VLI constant suffix
+ */
+#define LZMA_VLI_C(n) UINT64_C(n)
+
+
+/**
+ * \brief       Variable-length integer type
+ *
+ * Valid VLI values are in the range [0, LZMA_VLI_MAX]. Unknown value is
+ * indicated with LZMA_VLI_UNKNOWN, which is the maximum value of the
+ * underlying integer type.
+ *
+ * lzma_vli will be uint64_t for the foreseeable future. If a bigger size
+ * is needed in the future, it is guaranteed that 2 * LZMA_VLI_MAX will
+ * not overflow lzma_vli. This simplifies integer overflow detection.
+ */
+typedef uint64_t lzma_vli;
+
+
+/**
+ * \brief       Validate a variable-length integer
+ *
+ * This is useful to test that application has given acceptable values
+ * for example in the uncompressed_size and compressed_size variables.
+ *
+ * \return      True if the integer is representable as a VLI or if it
+ *              indicates an unknown value. False otherwise.
+ */
+#define lzma_vli_is_valid(vli) \
+	((vli) <= LZMA_VLI_MAX || (vli) == LZMA_VLI_UNKNOWN)
+
+
+/**
+ * \brief       Encode a variable-length integer
+ *
+ * This function has two modes: single-call and multi-call. Single-call mode
+ * encodes the whole integer at once; it is an error if the output buffer is
+ * too small. Multi-call mode saves the position in *vli_pos, and thus it is
+ * possible to continue encoding if the buffer becomes full before the whole
+ * integer has been encoded.
+ *
+ * \param       vli       Integer to be encoded
+ * \param[out]  vli_pos   How many VLI-encoded bytes have already been written
+ *                        out. When starting to encode a new integer in
+ *                        multi-call mode, *vli_pos must be set to zero.
+ *                        To use single-call encoding, set vli_pos to NULL.
+ * \param[out]  out       Beginning of the output buffer
+ * \param[out]  out_pos   The next byte will be written to out[*out_pos].
+ * \param       out_size  Size of the out buffer; the first byte into
+ *                        which no data is written to is out[out_size].
+ *
+ * \return      Slightly different return values are used in multi-call and
+ *              single-call modes.
+ *
+ *              Single-call (vli_pos == NULL):
+ *              - LZMA_OK: Integer successfully encoded.
+ *              - LZMA_PROG_ERROR: Arguments are not sane. This can be due
+ *                to too little output space; single-call mode doesn't use
+ *                LZMA_BUF_ERROR, since the application should have checked
+ *                the encoded size with lzma_vli_size().
+ *
+ *              Multi-call (vli_pos != NULL):
+ *              - LZMA_OK: So far all OK, but the integer is not
+ *                completely written out yet.
+ *              - LZMA_STREAM_END: Integer successfully encoded.
+ *              - LZMA_BUF_ERROR: No output space was provided.
+ *              - LZMA_PROG_ERROR: Arguments are not sane.
+ */
+extern LZMA_API(lzma_ret) lzma_vli_encode(lzma_vli vli, size_t *vli_pos,
+		uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
+
+
+/**
+ * \brief       Decode a variable-length integer
+ *
+ * Like lzma_vli_encode(), this function has single-call and multi-call modes.
+ *
+ * \param[out]  vli       Pointer to decoded integer. The decoder will
+ *                        initialize it to zero when *vli_pos == 0, so
+ *                        application isn't required to initialize *vli.
+ * \param[out]  vli_pos   How many bytes have already been decoded. When
+ *                        starting to decode a new integer in multi-call
+ *                        mode, *vli_pos must be initialized to zero. To
+ *                        use single-call decoding, set vli_pos to NULL.
+ * \param       in        Beginning of the input buffer
+ * \param[out]  in_pos    The next byte will be read from in[*in_pos].
+ * \param       in_size   Size of the input buffer; the first byte that
+ *                        won't be read is in[in_size].
+ *
+ * \return      Slightly different return values are used in multi-call and
+ *              single-call modes.
+ *
+ *              Single-call (vli_pos == NULL):
+ *              - LZMA_OK: Integer successfully decoded.
+ *              - LZMA_DATA_ERROR: Integer is corrupt. This includes hitting
+ *                the end of the input buffer before the whole integer was
+ *                decoded; providing no input at all will use LZMA_DATA_ERROR.
+ *              - LZMA_PROG_ERROR: Arguments are not sane.
+ *
+ *              Multi-call (vli_pos != NULL):
+ *              - LZMA_OK: So far all OK, but the integer is not
+ *                completely decoded yet.
+ *              - LZMA_STREAM_END: Integer successfully decoded.
+ *              - LZMA_DATA_ERROR: Integer is corrupt.
+ *              - LZMA_BUF_ERROR: No input was provided.
+ *              - LZMA_PROG_ERROR: Arguments are not sane.
+ */
+extern LZMA_API(lzma_ret) lzma_vli_decode(lzma_vli *vli, size_t *vli_pos,
+		const uint8_t *in, size_t *in_pos, size_t in_size)
+		lzma_nothrow;
+
+
+/**
+ * \brief       Get the number of bytes required to encode a VLI
+ *
+ * \param       vli       Integer whose encoded size is to be determined
+ *
+ * \return      Number of bytes on success (1-9). If vli isn't valid,
+ *              zero is returned.
+ */
+extern LZMA_API(uint32_t) lzma_vli_size(lzma_vli vli)
+		lzma_nothrow lzma_attr_pure;
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.c
new file mode 100644
index 00000000000..7734ace1856
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       check.c
+/// \brief      Single API to access different integrity checks
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "check.h"
+
+
+extern LZMA_API(lzma_bool)
+lzma_check_is_supported(lzma_check type)
+{
+	if ((unsigned int)(type) > LZMA_CHECK_ID_MAX)
+		return false;
+
+	static const lzma_bool available_checks[LZMA_CHECK_ID_MAX + 1] = {
+		true,   // LZMA_CHECK_NONE
+
+#ifdef HAVE_CHECK_CRC32
+		true,
+#else
+		false,
+#endif
+
+		false,  // Reserved
+		false,  // Reserved
+
+#ifdef HAVE_CHECK_CRC64
+		true,
+#else
+		false,
+#endif
+
+		false,  // Reserved
+		false,  // Reserved
+		false,  // Reserved
+		false,  // Reserved
+		false,  // Reserved
+
+#ifdef HAVE_CHECK_SHA256
+		true,
+#else
+		false,
+#endif
+
+		false,  // Reserved
+		false,  // Reserved
+		false,  // Reserved
+		false,  // Reserved
+		false,  // Reserved
+	};
+
+	return available_checks[(unsigned int)(type)];
+}
+
+
+extern LZMA_API(uint32_t)
+lzma_check_size(lzma_check type)
+{
+	if ((unsigned int)(type) > LZMA_CHECK_ID_MAX)
+		return UINT32_MAX;
+
+	// See file-format.txt section 2.1.1.2.
+	static const uint8_t check_sizes[LZMA_CHECK_ID_MAX + 1] = {
+		0,
+		4, 4, 4,
+		8, 8, 8,
+		16, 16, 16,
+		32, 32, 32,
+		64, 64, 64
+	};
+
+	return check_sizes[(unsigned int)(type)];
+}
+
+
+extern void
+lzma_check_init(lzma_check_state *check, lzma_check type)
+{
+	switch (type) {
+	case LZMA_CHECK_NONE:
+		break;
+
+#ifdef HAVE_CHECK_CRC32
+	case LZMA_CHECK_CRC32:
+		check->state.crc32 = 0;
+		break;
+#endif
+
+#ifdef HAVE_CHECK_CRC64
+	case LZMA_CHECK_CRC64:
+		check->state.crc64 = 0;
+		break;
+#endif
+
+#ifdef HAVE_CHECK_SHA256
+	case LZMA_CHECK_SHA256:
+		lzma_sha256_init(check);
+		break;
+#endif
+
+	default:
+		break;
+	}
+
+	return;
+}
+
+
+extern void
+lzma_check_update(lzma_check_state *check, lzma_check type,
+		const uint8_t *buf, size_t size)
+{
+	switch (type) {
+#ifdef HAVE_CHECK_CRC32
+	case LZMA_CHECK_CRC32:
+		check->state.crc32 = lzma_crc32(buf, size, check->state.crc32);
+		break;
+#endif
+
+#ifdef HAVE_CHECK_CRC64
+	case LZMA_CHECK_CRC64:
+		check->state.crc64 = lzma_crc64(buf, size, check->state.crc64);
+		break;
+#endif
+
+#ifdef HAVE_CHECK_SHA256
+	case LZMA_CHECK_SHA256:
+		lzma_sha256_update(buf, size, check);
+		break;
+#endif
+
+	default:
+		break;
+	}
+
+	return;
+}
+
+
+extern void
+lzma_check_finish(lzma_check_state *check, lzma_check type)
+{
+	switch (type) {
+#ifdef HAVE_CHECK_CRC32
+	case LZMA_CHECK_CRC32:
+		check->buffer.u32[0] = conv32le(check->state.crc32);
+		break;
+#endif
+
+#ifdef HAVE_CHECK_CRC64
+	case LZMA_CHECK_CRC64:
+		check->buffer.u64[0] = conv64le(check->state.crc64);
+		break;
+#endif
+
+#ifdef HAVE_CHECK_SHA256
+	case LZMA_CHECK_SHA256:
+		lzma_sha256_finish(check);
+		break;
+#endif
+
+	default:
+		break;
+	}
+
+	return;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.h
new file mode 100644
index 00000000000..f0eb1172d90
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/check.h
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       check.h
+/// \brief      Internal API to different integrity check functions
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_CHECK_H
+#define LZMA_CHECK_H
+
+#include "common.h"
+
+// If the function for external SHA-256 is missing, use the internal SHA-256
+// code. Due to how configure works, these defines can only get defined when
+// both a usable header and a type have already been found.
+#if !(defined(HAVE_CC_SHA256_INIT) \
+		|| defined(HAVE_SHA256_INIT) \
+		|| defined(HAVE_SHA256INIT))
+#	define HAVE_INTERNAL_SHA256 1
+#endif
+
+#if defined(HAVE_INTERNAL_SHA256)
+// Nothing
+#elif defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
+#	include 
+#elif defined(HAVE_SHA256_H)
+#	include 
+#	include 
+#elif defined(HAVE_SHA2_H)
+#	include 
+#	include 
+#endif
+
+#if defined(HAVE_INTERNAL_SHA256)
+/// State for the internal SHA-256 implementation
+typedef struct {
+	/// Internal state
+	uint32_t state[8];
+
+	/// Size of the message excluding padding
+	uint64_t size;
+} lzma_sha256_state;
+#elif defined(HAVE_CC_SHA256_CTX)
+typedef CC_SHA256_CTX lzma_sha256_state;
+#elif defined(HAVE_SHA256_CTX)
+typedef SHA256_CTX lzma_sha256_state;
+#elif defined(HAVE_SHA2_CTX)
+typedef SHA2_CTX lzma_sha256_state;
+#endif
+
+#if defined(HAVE_INTERNAL_SHA256)
+// Nothing
+#elif defined(HAVE_CC_SHA256_INIT)
+#	define LZMA_SHA256FUNC(x) CC_SHA256_ ## x
+#elif defined(HAVE_SHA256_INIT)
+#	define LZMA_SHA256FUNC(x) SHA256_ ## x
+#elif defined(HAVE_SHA256INIT)
+#	define LZMA_SHA256FUNC(x) SHA256 ## x
+#endif
+
+// Index hashing needs the best possible hash function (preferably
+// a cryptographic hash) for maximum reliability.
+#if defined(HAVE_CHECK_SHA256)
+#	define LZMA_CHECK_BEST LZMA_CHECK_SHA256
+#elif defined(HAVE_CHECK_CRC64)
+#	define LZMA_CHECK_BEST LZMA_CHECK_CRC64
+#else
+#	define LZMA_CHECK_BEST LZMA_CHECK_CRC32
+#endif
+
+
+/// \brief      Structure to hold internal state of the check being calculated
+///
+/// \note       This is not in the public API because this structure may
+///             change in future if new integrity check algorithms are added.
+typedef struct {
+	/// Buffer to hold the final result and a temporary buffer for SHA256.
+	union {
+		uint8_t u8[64];
+		uint32_t u32[16];
+		uint64_t u64[8];
+	} buffer;
+
+	/// Check-specific data
+	union {
+		uint32_t crc32;
+		uint64_t crc64;
+		lzma_sha256_state sha256;
+	} state;
+
+} lzma_check_state;
+
+
+/// lzma_crc32_table[0] is needed by LZ encoder so we need to keep
+/// the array two-dimensional.
+#ifdef HAVE_SMALL
+lzma_attr_visibility_hidden
+extern uint32_t lzma_crc32_table[1][256];
+
+extern void lzma_crc32_init(void);
+
+#else
+
+lzma_attr_visibility_hidden
+extern const uint32_t lzma_crc32_table[8][256];
+
+lzma_attr_visibility_hidden
+extern const uint64_t lzma_crc64_table[4][256];
+#endif
+
+
+/// \brief      Initialize *check depending on type
+extern void lzma_check_init(lzma_check_state *check, lzma_check type);
+
+/// Update the check state
+extern void lzma_check_update(lzma_check_state *check, lzma_check type,
+		const uint8_t *buf, size_t size);
+
+/// Finish the check calculation and store the result to check->buffer.u8.
+extern void lzma_check_finish(lzma_check_state *check, lzma_check type);
+
+
+#ifndef LZMA_SHA256FUNC
+
+/// Prepare SHA-256 state for new input.
+extern void lzma_sha256_init(lzma_check_state *check);
+
+/// Update the SHA-256 hash state
+extern void lzma_sha256_update(
+		const uint8_t *buf, size_t size, lzma_check_state *check);
+
+/// Finish the SHA-256 calculation and store the result to check->buffer.u8.
+extern void lzma_sha256_finish(lzma_check_state *check);
+
+
+#else
+
+static inline void
+lzma_sha256_init(lzma_check_state *check)
+{
+	LZMA_SHA256FUNC(Init)(&check->state.sha256);
+}
+
+
+static inline void
+lzma_sha256_update(const uint8_t *buf, size_t size, lzma_check_state *check)
+{
+#if defined(HAVE_CC_SHA256_INIT) && SIZE_MAX > UINT32_MAX
+	// Darwin's CC_SHA256_Update takes uint32_t as the buffer size,
+	// so use a loop to support size_t.
+	while (size > UINT32_MAX) {
+		LZMA_SHA256FUNC(Update)(&check->state.sha256, buf, UINT32_MAX);
+		buf += UINT32_MAX;
+		size -= UINT32_MAX;
+	}
+#endif
+
+	LZMA_SHA256FUNC(Update)(&check->state.sha256, buf, size);
+}
+
+
+static inline void
+lzma_sha256_finish(lzma_check_state *check)
+{
+	LZMA_SHA256FUNC(Final)(check->buffer.u8, &check->state.sha256);
+}
+
+#endif
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_arm64.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_arm64.h
new file mode 100644
index 00000000000..39c1c63ec0e
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_arm64.h
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       crc32_arm64.h
+/// \brief      CRC32 calculation with ARM64 optimization
+//
+//  Authors:    Chenxi Mao
+//              Jia Tan
+//              Hans Jansen
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_CRC32_ARM64_H
+#define LZMA_CRC32_ARM64_H
+
+// MSVC always has the CRC intrinsics available when building for ARM64
+// there is no need to include any header files.
+#ifndef _MSC_VER
+#	include 
+#endif
+
+// If both versions are going to be built, we need runtime detection
+// to check if the instructions are supported.
+#if defined(CRC32_GENERIC) && defined(CRC32_ARCH_OPTIMIZED)
+#	if defined(HAVE_GETAUXVAL) || defined(HAVE_ELF_AUX_INFO)
+#		include 
+#	elif defined(_WIN32)
+#		include 
+#	elif defined(__APPLE__) && defined(HAVE_SYSCTLBYNAME)
+#		include 
+#	endif
+#endif
+
+// Some EDG-based compilers support ARM64 and define __GNUC__
+// (such as Nvidia's nvcc), but do not support function attributes.
+//
+// NOTE: Build systems check for this too, keep them in sync with this.
+#if (defined(__GNUC__) || defined(__clang__)) && !defined(__EDG__)
+#	define crc_attr_target __attribute__((__target__("+crc")))
+#else
+#	define crc_attr_target
+#endif
+
+
+crc_attr_target
+static uint32_t
+crc32_arch_optimized(const uint8_t *buf, size_t size, uint32_t crc)
+{
+	crc = ~crc;
+
+	// Align the input buffer because this was shown to be
+	// significantly faster than unaligned accesses.
+	const size_t align_amount = my_min(size, (0U - (uintptr_t)buf) & 7);
+
+	for (const uint8_t *limit = buf + align_amount; buf < limit; ++buf)
+		crc = __crc32b(crc, *buf);
+
+	size -= align_amount;
+
+	// Process 8 bytes at a time. The end point is determined by
+	// ignoring the least significant three bits of size to ensure
+	// we do not process past the bounds of the buffer. This guarantees
+	// that limit is a multiple of 8 and is strictly less than size.
+	for (const uint8_t *limit = buf + (size & ~(size_t)7);
+			buf < limit; buf += 8)
+		crc = __crc32d(crc, aligned_read64le(buf));
+
+	// Process the remaining bytes that are not 8 byte aligned.
+	for (const uint8_t *limit = buf + (size & 7); buf < limit; ++buf)
+		crc = __crc32b(crc, *buf);
+
+	return ~crc;
+}
+
+
+#if defined(CRC32_GENERIC) && defined(CRC32_ARCH_OPTIMIZED)
+static inline bool
+is_arch_extension_supported(void)
+{
+#if defined(HAVE_GETAUXVAL)
+	return (getauxval(AT_HWCAP) & HWCAP_CRC32) != 0;
+
+#elif defined(HAVE_ELF_AUX_INFO)
+	unsigned long feature_flags;
+
+	if (elf_aux_info(AT_HWCAP, &feature_flags, sizeof(feature_flags)) != 0)
+		return false;
+
+	return (feature_flags & HWCAP_CRC32) != 0;
+
+#elif defined(_WIN32)
+	return IsProcessorFeaturePresent(
+			PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
+
+#elif defined(__APPLE__) && defined(HAVE_SYSCTLBYNAME)
+	int has_crc32 = 0;
+	size_t size = sizeof(has_crc32);
+
+	// The sysctlbyname() function requires a string identifier for the
+	// CPU feature it tests. The Apple documentation lists the string
+	// "hw.optional.armv8_crc32", which can be found here:
+	// https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3915619
+	if (sysctlbyname("hw.optional.armv8_crc32", &has_crc32,
+			&size, NULL, 0) != 0)
+		return false;
+
+	return has_crc32;
+
+#else
+	// If a runtime detection method cannot be found, then this must
+	// be a compile time error. The checks in crc_common.h should ensure
+	// a runtime detection method is always found if this function is
+	// built. It would be possible to just return false here, but this
+	// is inefficient for binary size and runtime since only the generic
+	// method could ever be used.
+#	error Runtime detection method unavailable.
+#endif
+}
+#endif
+
+#endif // LZMA_CRC32_ARM64_H
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_fast.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_fast.c
new file mode 100644
index 00000000000..16dbb746751
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_fast.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       crc32.c
+/// \brief      CRC32 calculation
+//
+//  Authors:    Lasse Collin
+//              Ilya Kurdyukov
+//              Hans Jansen
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "check.h"
+#include "crc_common.h"
+
+#if defined(CRC_X86_CLMUL)
+#	define BUILDING_CRC32_CLMUL
+#	include "crc_x86_clmul.h"
+#elif defined(CRC32_ARM64)
+#	include "crc32_arm64.h"
+#endif
+
+
+#ifdef CRC32_GENERIC
+
+///////////////////
+// Generic CRC32 //
+///////////////////
+
+static uint32_t
+crc32_generic(const uint8_t *buf, size_t size, uint32_t crc)
+{
+	crc = ~crc;
+
+#ifdef WORDS_BIGENDIAN
+	crc = byteswap32(crc);
+#endif
+
+	if (size > 8) {
+		// Fix the alignment, if needed. The if statement above
+		// ensures that this won't read past the end of buf[].
+		while ((uintptr_t)(buf) & 7) {
+			crc = lzma_crc32_table[0][*buf++ ^ A(crc)] ^ S8(crc);
+			--size;
+		}
+
+		// Calculate the position where to stop.
+		const uint8_t *const limit = buf + (size & ~(size_t)(7));
+
+		// Calculate how many bytes must be calculated separately
+		// before returning the result.
+		size &= (size_t)(7);
+
+		// Calculate the CRC32 using the slice-by-eight algorithm.
+		while (buf < limit) {
+			crc ^= aligned_read32ne(buf);
+			buf += 4;
+
+			crc = lzma_crc32_table[7][A(crc)]
+			    ^ lzma_crc32_table[6][B(crc)]
+			    ^ lzma_crc32_table[5][C(crc)]
+			    ^ lzma_crc32_table[4][D(crc)];
+
+			const uint32_t tmp = aligned_read32ne(buf);
+			buf += 4;
+
+			// At least with some compilers, it is critical for
+			// performance, that the crc variable is XORed
+			// between the two table-lookup pairs.
+			crc = lzma_crc32_table[3][A(tmp)]
+			    ^ lzma_crc32_table[2][B(tmp)]
+			    ^ crc
+			    ^ lzma_crc32_table[1][C(tmp)]
+			    ^ lzma_crc32_table[0][D(tmp)];
+		}
+	}
+
+	while (size-- != 0)
+		crc = lzma_crc32_table[0][*buf++ ^ A(crc)] ^ S8(crc);
+
+#ifdef WORDS_BIGENDIAN
+	crc = byteswap32(crc);
+#endif
+
+	return ~crc;
+}
+#endif
+
+
+#if defined(CRC32_GENERIC) && defined(CRC32_ARCH_OPTIMIZED)
+
+//////////////////////////
+// Function dispatching //
+//////////////////////////
+
+// If both the generic and arch-optimized implementations are built, then
+// the function to use is selected at runtime because the system running
+// the binary might not have the arch-specific instruction set extension(s)
+// available. The dispatch methods in order of priority:
+//
+// 1. Constructor. This method uses __attribute__((__constructor__)) to
+//    set crc32_func at load time. This avoids extra computation (and any
+//    unlikely threading bugs) on the first call to lzma_crc32() to decide
+//    which implementation should be used.
+//
+// 2. First Call Resolution. On the very first call to lzma_crc32(), the
+//    call will be directed to crc32_dispatch() instead. This will set the
+//    appropriate implementation function and will not be called again.
+//    This method does not use any kind of locking but is safe because if
+//    multiple threads run the dispatcher simultaneously then they will all
+//    set crc32_func to the same value.
+
+typedef uint32_t (*crc32_func_type)(
+		const uint8_t *buf, size_t size, uint32_t crc);
+
+// This resolver is shared between all dispatch methods.
+static crc32_func_type
+crc32_resolve(void)
+{
+	return is_arch_extension_supported()
+			? &crc32_arch_optimized : &crc32_generic;
+}
+
+
+#ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
+// Constructor method.
+#	define CRC32_SET_FUNC_ATTR __attribute__((__constructor__))
+static crc32_func_type crc32_func;
+#else
+// First Call Resolution method.
+#	define CRC32_SET_FUNC_ATTR
+static uint32_t crc32_dispatch(const uint8_t *buf, size_t size, uint32_t crc);
+static crc32_func_type crc32_func = &crc32_dispatch;
+#endif
+
+CRC32_SET_FUNC_ATTR
+static void
+crc32_set_func(void)
+{
+	crc32_func = crc32_resolve();
+	return;
+}
+
+#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
+static uint32_t
+crc32_dispatch(const uint8_t *buf, size_t size, uint32_t crc)
+{
+	// When __attribute__((__constructor__)) isn't supported, set the
+	// function pointer without any locking. If multiple threads run
+	// the detection code in parallel, they will all end up setting
+	// the pointer to the same value. This avoids the use of
+	// mythread_once() on every call to lzma_crc32() but this likely
+	// isn't strictly standards compliant. Let's change it if it breaks.
+	crc32_set_func();
+	return crc32_func(buf, size, crc);
+}
+
+#endif
+#endif
+
+
+extern LZMA_API(uint32_t)
+lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc)
+{
+#if defined(CRC32_GENERIC) && defined(CRC32_ARCH_OPTIMIZED)
+	// On x86-64, if CLMUL is available, it is the best for non-tiny
+	// inputs, being over twice as fast as the generic slice-by-four
+	// version. However, for size <= 16 it's different. In the extreme
+	// case of size == 1 the generic version can be five times faster.
+	// At size >= 8 the CLMUL starts to become reasonable. It
+	// varies depending on the alignment of buf too.
+	//
+	// The above doesn't include the overhead of mythread_once().
+	// At least on x86-64 GNU/Linux, pthread_once() is very fast but
+	// it still makes lzma_crc32(buf, 1, crc) 50-100 % slower. When
+	// size reaches 12-16 bytes the overhead becomes negligible.
+	//
+	// So using the generic version for size <= 16 may give better
+	// performance with tiny inputs but if such inputs happen rarely
+	// it's not so obvious because then the lookup table of the
+	// generic version may not be in the processor cache.
+#ifdef CRC_USE_GENERIC_FOR_SMALL_INPUTS
+	if (size <= 16)
+		return crc32_generic(buf, size, crc);
+#endif
+
+/*
+#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
+	// See crc32_dispatch(). This would be the alternative which uses
+	// locking and doesn't use crc32_dispatch(). Note that on Windows
+	// this method needs Vista threads.
+	mythread_once(crc64_set_func);
+#endif
+*/
+	return crc32_func(buf, size, crc);
+
+#elif defined(CRC32_ARCH_OPTIMIZED)
+	return crc32_arch_optimized(buf, size, crc);
+
+#else
+	return crc32_generic(buf, size, crc);
+#endif
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_small.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_small.c
new file mode 100644
index 00000000000..6a1bd66185e
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_small.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       crc32_small.c
+/// \brief      CRC32 calculation (size-optimized)
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "check.h"
+
+
+uint32_t lzma_crc32_table[1][256];
+
+
+#ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
+__attribute__((__constructor__))
+#endif
+static void
+crc32_init(void)
+{
+	static const uint32_t poly32 = UINT32_C(0xEDB88320);
+
+	for (size_t b = 0; b < 256; ++b) {
+		uint32_t r = b;
+		for (size_t i = 0; i < 8; ++i) {
+			if (r & 1)
+				r = (r >> 1) ^ poly32;
+			else
+				r >>= 1;
+		}
+
+		lzma_crc32_table[0][b] = r;
+	}
+
+	return;
+}
+
+
+#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
+extern void
+lzma_crc32_init(void)
+{
+	mythread_once(crc32_init);
+	return;
+}
+#endif
+
+
+extern LZMA_API(uint32_t)
+lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc)
+{
+#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
+	lzma_crc32_init();
+#endif
+
+	crc = ~crc;
+
+	while (size != 0) {
+		crc = lzma_crc32_table[0][*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
+		--size;
+	}
+
+	return ~crc;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table.c
new file mode 100644
index 00000000000..56413eec336
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table.c
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       crc32_table.c
+/// \brief      Precalculated CRC32 table with correct endianness
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+
+// FIXME: Compared to crc_common.h this has to check for __x86_64__ too
+// so that in 32-bit builds crc32_x86.S won't break due to a missing table.
+#if defined(HAVE_USABLE_CLMUL) && ((defined(__x86_64__) && defined(__SSSE3__) \
+			&& defined(__SSE4_1__) && defined(__PCLMUL__)) \
+		|| (defined(__e2k__) && __iset__ >= 6))
+#	define NO_CRC32_TABLE
+
+#elif defined(HAVE_ARM64_CRC32) \
+		&& !defined(WORDS_BIGENDIAN) \
+		&& defined(__ARM_FEATURE_CRC32)
+#	define NO_CRC32_TABLE
+#endif
+
+
+#if !defined(HAVE_ENCODERS) && defined(NO_CRC32_TABLE)
+// No table needed. Use a typedef to avoid an empty translation unit.
+typedef void lzma_crc32_dummy;
+
+#else
+// Having the declaration here silences clang -Wmissing-variable-declarations.
+extern const uint32_t lzma_crc32_table[8][256];
+
+#	ifdef WORDS_BIGENDIAN
+#		include "crc32_table_be.h"
+#	else
+#		include "crc32_table_le.h"
+#	endif
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_be.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_be.h
new file mode 100644
index 00000000000..505c23074c1
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_be.h
@@ -0,0 +1,527 @@
+// SPDX-License-Identifier: 0BSD
+
+// This file has been generated by crc32_tablegen.c.
+
+const uint32_t lzma_crc32_table[8][256] = {
+	{
+		0x00000000, 0x96300777, 0x2C610EEE, 0xBA510999,
+		0x19C46D07, 0x8FF46A70, 0x35A563E9, 0xA395649E,
+		0x3288DB0E, 0xA4B8DC79, 0x1EE9D5E0, 0x88D9D297,
+		0x2B4CB609, 0xBD7CB17E, 0x072DB8E7, 0x911DBF90,
+		0x6410B71D, 0xF220B06A, 0x4871B9F3, 0xDE41BE84,
+		0x7DD4DA1A, 0xEBE4DD6D, 0x51B5D4F4, 0xC785D383,
+		0x56986C13, 0xC0A86B64, 0x7AF962FD, 0xECC9658A,
+		0x4F5C0114, 0xD96C0663, 0x633D0FFA, 0xF50D088D,
+		0xC8206E3B, 0x5E10694C, 0xE44160D5, 0x727167A2,
+		0xD1E4033C, 0x47D4044B, 0xFD850DD2, 0x6BB50AA5,
+		0xFAA8B535, 0x6C98B242, 0xD6C9BBDB, 0x40F9BCAC,
+		0xE36CD832, 0x755CDF45, 0xCF0DD6DC, 0x593DD1AB,
+		0xAC30D926, 0x3A00DE51, 0x8051D7C8, 0x1661D0BF,
+		0xB5F4B421, 0x23C4B356, 0x9995BACF, 0x0FA5BDB8,
+		0x9EB80228, 0x0888055F, 0xB2D90CC6, 0x24E90BB1,
+		0x877C6F2F, 0x114C6858, 0xAB1D61C1, 0x3D2D66B6,
+		0x9041DC76, 0x0671DB01, 0xBC20D298, 0x2A10D5EF,
+		0x8985B171, 0x1FB5B606, 0xA5E4BF9F, 0x33D4B8E8,
+		0xA2C90778, 0x34F9000F, 0x8EA80996, 0x18980EE1,
+		0xBB0D6A7F, 0x2D3D6D08, 0x976C6491, 0x015C63E6,
+		0xF4516B6B, 0x62616C1C, 0xD8306585, 0x4E0062F2,
+		0xED95066C, 0x7BA5011B, 0xC1F40882, 0x57C40FF5,
+		0xC6D9B065, 0x50E9B712, 0xEAB8BE8B, 0x7C88B9FC,
+		0xDF1DDD62, 0x492DDA15, 0xF37CD38C, 0x654CD4FB,
+		0x5861B24D, 0xCE51B53A, 0x7400BCA3, 0xE230BBD4,
+		0x41A5DF4A, 0xD795D83D, 0x6DC4D1A4, 0xFBF4D6D3,
+		0x6AE96943, 0xFCD96E34, 0x468867AD, 0xD0B860DA,
+		0x732D0444, 0xE51D0333, 0x5F4C0AAA, 0xC97C0DDD,
+		0x3C710550, 0xAA410227, 0x10100BBE, 0x86200CC9,
+		0x25B56857, 0xB3856F20, 0x09D466B9, 0x9FE461CE,
+		0x0EF9DE5E, 0x98C9D929, 0x2298D0B0, 0xB4A8D7C7,
+		0x173DB359, 0x810DB42E, 0x3B5CBDB7, 0xAD6CBAC0,
+		0x2083B8ED, 0xB6B3BF9A, 0x0CE2B603, 0x9AD2B174,
+		0x3947D5EA, 0xAF77D29D, 0x1526DB04, 0x8316DC73,
+		0x120B63E3, 0x843B6494, 0x3E6A6D0D, 0xA85A6A7A,
+		0x0BCF0EE4, 0x9DFF0993, 0x27AE000A, 0xB19E077D,
+		0x44930FF0, 0xD2A30887, 0x68F2011E, 0xFEC20669,
+		0x5D5762F7, 0xCB676580, 0x71366C19, 0xE7066B6E,
+		0x761BD4FE, 0xE02BD389, 0x5A7ADA10, 0xCC4ADD67,
+		0x6FDFB9F9, 0xF9EFBE8E, 0x43BEB717, 0xD58EB060,
+		0xE8A3D6D6, 0x7E93D1A1, 0xC4C2D838, 0x52F2DF4F,
+		0xF167BBD1, 0x6757BCA6, 0xDD06B53F, 0x4B36B248,
+		0xDA2B0DD8, 0x4C1B0AAF, 0xF64A0336, 0x607A0441,
+		0xC3EF60DF, 0x55DF67A8, 0xEF8E6E31, 0x79BE6946,
+		0x8CB361CB, 0x1A8366BC, 0xA0D26F25, 0x36E26852,
+		0x95770CCC, 0x03470BBB, 0xB9160222, 0x2F260555,
+		0xBE3BBAC5, 0x280BBDB2, 0x925AB42B, 0x046AB35C,
+		0xA7FFD7C2, 0x31CFD0B5, 0x8B9ED92C, 0x1DAEDE5B,
+		0xB0C2649B, 0x26F263EC, 0x9CA36A75, 0x0A936D02,
+		0xA906099C, 0x3F360EEB, 0x85670772, 0x13570005,
+		0x824ABF95, 0x147AB8E2, 0xAE2BB17B, 0x381BB60C,
+		0x9B8ED292, 0x0DBED5E5, 0xB7EFDC7C, 0x21DFDB0B,
+		0xD4D2D386, 0x42E2D4F1, 0xF8B3DD68, 0x6E83DA1F,
+		0xCD16BE81, 0x5B26B9F6, 0xE177B06F, 0x7747B718,
+		0xE65A0888, 0x706A0FFF, 0xCA3B0666, 0x5C0B0111,
+		0xFF9E658F, 0x69AE62F8, 0xD3FF6B61, 0x45CF6C16,
+		0x78E20AA0, 0xEED20DD7, 0x5483044E, 0xC2B30339,
+		0x612667A7, 0xF71660D0, 0x4D476949, 0xDB776E3E,
+		0x4A6AD1AE, 0xDC5AD6D9, 0x660BDF40, 0xF03BD837,
+		0x53AEBCA9, 0xC59EBBDE, 0x7FCFB247, 0xE9FFB530,
+		0x1CF2BDBD, 0x8AC2BACA, 0x3093B353, 0xA6A3B424,
+		0x0536D0BA, 0x9306D7CD, 0x2957DE54, 0xBF67D923,
+		0x2E7A66B3, 0xB84A61C4, 0x021B685D, 0x942B6F2A,
+		0x37BE0BB4, 0xA18E0CC3, 0x1BDF055A, 0x8DEF022D
+	}, {
+		0x00000000, 0x41311B19, 0x82623632, 0xC3532D2B,
+		0x04C56C64, 0x45F4777D, 0x86A75A56, 0xC796414F,
+		0x088AD9C8, 0x49BBC2D1, 0x8AE8EFFA, 0xCBD9F4E3,
+		0x0C4FB5AC, 0x4D7EAEB5, 0x8E2D839E, 0xCF1C9887,
+		0x5112C24A, 0x1023D953, 0xD370F478, 0x9241EF61,
+		0x55D7AE2E, 0x14E6B537, 0xD7B5981C, 0x96848305,
+		0x59981B82, 0x18A9009B, 0xDBFA2DB0, 0x9ACB36A9,
+		0x5D5D77E6, 0x1C6C6CFF, 0xDF3F41D4, 0x9E0E5ACD,
+		0xA2248495, 0xE3159F8C, 0x2046B2A7, 0x6177A9BE,
+		0xA6E1E8F1, 0xE7D0F3E8, 0x2483DEC3, 0x65B2C5DA,
+		0xAAAE5D5D, 0xEB9F4644, 0x28CC6B6F, 0x69FD7076,
+		0xAE6B3139, 0xEF5A2A20, 0x2C09070B, 0x6D381C12,
+		0xF33646DF, 0xB2075DC6, 0x715470ED, 0x30656BF4,
+		0xF7F32ABB, 0xB6C231A2, 0x75911C89, 0x34A00790,
+		0xFBBC9F17, 0xBA8D840E, 0x79DEA925, 0x38EFB23C,
+		0xFF79F373, 0xBE48E86A, 0x7D1BC541, 0x3C2ADE58,
+		0x054F79F0, 0x447E62E9, 0x872D4FC2, 0xC61C54DB,
+		0x018A1594, 0x40BB0E8D, 0x83E823A6, 0xC2D938BF,
+		0x0DC5A038, 0x4CF4BB21, 0x8FA7960A, 0xCE968D13,
+		0x0900CC5C, 0x4831D745, 0x8B62FA6E, 0xCA53E177,
+		0x545DBBBA, 0x156CA0A3, 0xD63F8D88, 0x970E9691,
+		0x5098D7DE, 0x11A9CCC7, 0xD2FAE1EC, 0x93CBFAF5,
+		0x5CD76272, 0x1DE6796B, 0xDEB55440, 0x9F844F59,
+		0x58120E16, 0x1923150F, 0xDA703824, 0x9B41233D,
+		0xA76BFD65, 0xE65AE67C, 0x2509CB57, 0x6438D04E,
+		0xA3AE9101, 0xE29F8A18, 0x21CCA733, 0x60FDBC2A,
+		0xAFE124AD, 0xEED03FB4, 0x2D83129F, 0x6CB20986,
+		0xAB2448C9, 0xEA1553D0, 0x29467EFB, 0x687765E2,
+		0xF6793F2F, 0xB7482436, 0x741B091D, 0x352A1204,
+		0xF2BC534B, 0xB38D4852, 0x70DE6579, 0x31EF7E60,
+		0xFEF3E6E7, 0xBFC2FDFE, 0x7C91D0D5, 0x3DA0CBCC,
+		0xFA368A83, 0xBB07919A, 0x7854BCB1, 0x3965A7A8,
+		0x4B98833B, 0x0AA99822, 0xC9FAB509, 0x88CBAE10,
+		0x4F5DEF5F, 0x0E6CF446, 0xCD3FD96D, 0x8C0EC274,
+		0x43125AF3, 0x022341EA, 0xC1706CC1, 0x804177D8,
+		0x47D73697, 0x06E62D8E, 0xC5B500A5, 0x84841BBC,
+		0x1A8A4171, 0x5BBB5A68, 0x98E87743, 0xD9D96C5A,
+		0x1E4F2D15, 0x5F7E360C, 0x9C2D1B27, 0xDD1C003E,
+		0x120098B9, 0x533183A0, 0x9062AE8B, 0xD153B592,
+		0x16C5F4DD, 0x57F4EFC4, 0x94A7C2EF, 0xD596D9F6,
+		0xE9BC07AE, 0xA88D1CB7, 0x6BDE319C, 0x2AEF2A85,
+		0xED796BCA, 0xAC4870D3, 0x6F1B5DF8, 0x2E2A46E1,
+		0xE136DE66, 0xA007C57F, 0x6354E854, 0x2265F34D,
+		0xE5F3B202, 0xA4C2A91B, 0x67918430, 0x26A09F29,
+		0xB8AEC5E4, 0xF99FDEFD, 0x3ACCF3D6, 0x7BFDE8CF,
+		0xBC6BA980, 0xFD5AB299, 0x3E099FB2, 0x7F3884AB,
+		0xB0241C2C, 0xF1150735, 0x32462A1E, 0x73773107,
+		0xB4E17048, 0xF5D06B51, 0x3683467A, 0x77B25D63,
+		0x4ED7FACB, 0x0FE6E1D2, 0xCCB5CCF9, 0x8D84D7E0,
+		0x4A1296AF, 0x0B238DB6, 0xC870A09D, 0x8941BB84,
+		0x465D2303, 0x076C381A, 0xC43F1531, 0x850E0E28,
+		0x42984F67, 0x03A9547E, 0xC0FA7955, 0x81CB624C,
+		0x1FC53881, 0x5EF42398, 0x9DA70EB3, 0xDC9615AA,
+		0x1B0054E5, 0x5A314FFC, 0x996262D7, 0xD85379CE,
+		0x174FE149, 0x567EFA50, 0x952DD77B, 0xD41CCC62,
+		0x138A8D2D, 0x52BB9634, 0x91E8BB1F, 0xD0D9A006,
+		0xECF37E5E, 0xADC26547, 0x6E91486C, 0x2FA05375,
+		0xE836123A, 0xA9070923, 0x6A542408, 0x2B653F11,
+		0xE479A796, 0xA548BC8F, 0x661B91A4, 0x272A8ABD,
+		0xE0BCCBF2, 0xA18DD0EB, 0x62DEFDC0, 0x23EFE6D9,
+		0xBDE1BC14, 0xFCD0A70D, 0x3F838A26, 0x7EB2913F,
+		0xB924D070, 0xF815CB69, 0x3B46E642, 0x7A77FD5B,
+		0xB56B65DC, 0xF45A7EC5, 0x370953EE, 0x763848F7,
+		0xB1AE09B8, 0xF09F12A1, 0x33CC3F8A, 0x72FD2493
+	}, {
+		0x00000000, 0x376AC201, 0x6ED48403, 0x59BE4602,
+		0xDCA80907, 0xEBC2CB06, 0xB27C8D04, 0x85164F05,
+		0xB851130E, 0x8F3BD10F, 0xD685970D, 0xE1EF550C,
+		0x64F91A09, 0x5393D808, 0x0A2D9E0A, 0x3D475C0B,
+		0x70A3261C, 0x47C9E41D, 0x1E77A21F, 0x291D601E,
+		0xAC0B2F1B, 0x9B61ED1A, 0xC2DFAB18, 0xF5B56919,
+		0xC8F23512, 0xFF98F713, 0xA626B111, 0x914C7310,
+		0x145A3C15, 0x2330FE14, 0x7A8EB816, 0x4DE47A17,
+		0xE0464D38, 0xD72C8F39, 0x8E92C93B, 0xB9F80B3A,
+		0x3CEE443F, 0x0B84863E, 0x523AC03C, 0x6550023D,
+		0x58175E36, 0x6F7D9C37, 0x36C3DA35, 0x01A91834,
+		0x84BF5731, 0xB3D59530, 0xEA6BD332, 0xDD011133,
+		0x90E56B24, 0xA78FA925, 0xFE31EF27, 0xC95B2D26,
+		0x4C4D6223, 0x7B27A022, 0x2299E620, 0x15F32421,
+		0x28B4782A, 0x1FDEBA2B, 0x4660FC29, 0x710A3E28,
+		0xF41C712D, 0xC376B32C, 0x9AC8F52E, 0xADA2372F,
+		0xC08D9A70, 0xF7E75871, 0xAE591E73, 0x9933DC72,
+		0x1C259377, 0x2B4F5176, 0x72F11774, 0x459BD575,
+		0x78DC897E, 0x4FB64B7F, 0x16080D7D, 0x2162CF7C,
+		0xA4748079, 0x931E4278, 0xCAA0047A, 0xFDCAC67B,
+		0xB02EBC6C, 0x87447E6D, 0xDEFA386F, 0xE990FA6E,
+		0x6C86B56B, 0x5BEC776A, 0x02523168, 0x3538F369,
+		0x087FAF62, 0x3F156D63, 0x66AB2B61, 0x51C1E960,
+		0xD4D7A665, 0xE3BD6464, 0xBA032266, 0x8D69E067,
+		0x20CBD748, 0x17A11549, 0x4E1F534B, 0x7975914A,
+		0xFC63DE4F, 0xCB091C4E, 0x92B75A4C, 0xA5DD984D,
+		0x989AC446, 0xAFF00647, 0xF64E4045, 0xC1248244,
+		0x4432CD41, 0x73580F40, 0x2AE64942, 0x1D8C8B43,
+		0x5068F154, 0x67023355, 0x3EBC7557, 0x09D6B756,
+		0x8CC0F853, 0xBBAA3A52, 0xE2147C50, 0xD57EBE51,
+		0xE839E25A, 0xDF53205B, 0x86ED6659, 0xB187A458,
+		0x3491EB5D, 0x03FB295C, 0x5A456F5E, 0x6D2FAD5F,
+		0x801B35E1, 0xB771F7E0, 0xEECFB1E2, 0xD9A573E3,
+		0x5CB33CE6, 0x6BD9FEE7, 0x3267B8E5, 0x050D7AE4,
+		0x384A26EF, 0x0F20E4EE, 0x569EA2EC, 0x61F460ED,
+		0xE4E22FE8, 0xD388EDE9, 0x8A36ABEB, 0xBD5C69EA,
+		0xF0B813FD, 0xC7D2D1FC, 0x9E6C97FE, 0xA90655FF,
+		0x2C101AFA, 0x1B7AD8FB, 0x42C49EF9, 0x75AE5CF8,
+		0x48E900F3, 0x7F83C2F2, 0x263D84F0, 0x115746F1,
+		0x944109F4, 0xA32BCBF5, 0xFA958DF7, 0xCDFF4FF6,
+		0x605D78D9, 0x5737BAD8, 0x0E89FCDA, 0x39E33EDB,
+		0xBCF571DE, 0x8B9FB3DF, 0xD221F5DD, 0xE54B37DC,
+		0xD80C6BD7, 0xEF66A9D6, 0xB6D8EFD4, 0x81B22DD5,
+		0x04A462D0, 0x33CEA0D1, 0x6A70E6D3, 0x5D1A24D2,
+		0x10FE5EC5, 0x27949CC4, 0x7E2ADAC6, 0x494018C7,
+		0xCC5657C2, 0xFB3C95C3, 0xA282D3C1, 0x95E811C0,
+		0xA8AF4DCB, 0x9FC58FCA, 0xC67BC9C8, 0xF1110BC9,
+		0x740744CC, 0x436D86CD, 0x1AD3C0CF, 0x2DB902CE,
+		0x4096AF91, 0x77FC6D90, 0x2E422B92, 0x1928E993,
+		0x9C3EA696, 0xAB546497, 0xF2EA2295, 0xC580E094,
+		0xF8C7BC9F, 0xCFAD7E9E, 0x9613389C, 0xA179FA9D,
+		0x246FB598, 0x13057799, 0x4ABB319B, 0x7DD1F39A,
+		0x3035898D, 0x075F4B8C, 0x5EE10D8E, 0x698BCF8F,
+		0xEC9D808A, 0xDBF7428B, 0x82490489, 0xB523C688,
+		0x88649A83, 0xBF0E5882, 0xE6B01E80, 0xD1DADC81,
+		0x54CC9384, 0x63A65185, 0x3A181787, 0x0D72D586,
+		0xA0D0E2A9, 0x97BA20A8, 0xCE0466AA, 0xF96EA4AB,
+		0x7C78EBAE, 0x4B1229AF, 0x12AC6FAD, 0x25C6ADAC,
+		0x1881F1A7, 0x2FEB33A6, 0x765575A4, 0x413FB7A5,
+		0xC429F8A0, 0xF3433AA1, 0xAAFD7CA3, 0x9D97BEA2,
+		0xD073C4B5, 0xE71906B4, 0xBEA740B6, 0x89CD82B7,
+		0x0CDBCDB2, 0x3BB10FB3, 0x620F49B1, 0x55658BB0,
+		0x6822D7BB, 0x5F4815BA, 0x06F653B8, 0x319C91B9,
+		0xB48ADEBC, 0x83E01CBD, 0xDA5E5ABF, 0xED3498BE
+	}, {
+		0x00000000, 0x6567BCB8, 0x8BC809AA, 0xEEAFB512,
+		0x5797628F, 0x32F0DE37, 0xDC5F6B25, 0xB938D79D,
+		0xEF28B4C5, 0x8A4F087D, 0x64E0BD6F, 0x018701D7,
+		0xB8BFD64A, 0xDDD86AF2, 0x3377DFE0, 0x56106358,
+		0x9F571950, 0xFA30A5E8, 0x149F10FA, 0x71F8AC42,
+		0xC8C07BDF, 0xADA7C767, 0x43087275, 0x266FCECD,
+		0x707FAD95, 0x1518112D, 0xFBB7A43F, 0x9ED01887,
+		0x27E8CF1A, 0x428F73A2, 0xAC20C6B0, 0xC9477A08,
+		0x3EAF32A0, 0x5BC88E18, 0xB5673B0A, 0xD00087B2,
+		0x6938502F, 0x0C5FEC97, 0xE2F05985, 0x8797E53D,
+		0xD1878665, 0xB4E03ADD, 0x5A4F8FCF, 0x3F283377,
+		0x8610E4EA, 0xE3775852, 0x0DD8ED40, 0x68BF51F8,
+		0xA1F82BF0, 0xC49F9748, 0x2A30225A, 0x4F579EE2,
+		0xF66F497F, 0x9308F5C7, 0x7DA740D5, 0x18C0FC6D,
+		0x4ED09F35, 0x2BB7238D, 0xC518969F, 0xA07F2A27,
+		0x1947FDBA, 0x7C204102, 0x928FF410, 0xF7E848A8,
+		0x3D58149B, 0x583FA823, 0xB6901D31, 0xD3F7A189,
+		0x6ACF7614, 0x0FA8CAAC, 0xE1077FBE, 0x8460C306,
+		0xD270A05E, 0xB7171CE6, 0x59B8A9F4, 0x3CDF154C,
+		0x85E7C2D1, 0xE0807E69, 0x0E2FCB7B, 0x6B4877C3,
+		0xA20F0DCB, 0xC768B173, 0x29C70461, 0x4CA0B8D9,
+		0xF5986F44, 0x90FFD3FC, 0x7E5066EE, 0x1B37DA56,
+		0x4D27B90E, 0x284005B6, 0xC6EFB0A4, 0xA3880C1C,
+		0x1AB0DB81, 0x7FD76739, 0x9178D22B, 0xF41F6E93,
+		0x03F7263B, 0x66909A83, 0x883F2F91, 0xED589329,
+		0x546044B4, 0x3107F80C, 0xDFA84D1E, 0xBACFF1A6,
+		0xECDF92FE, 0x89B82E46, 0x67179B54, 0x027027EC,
+		0xBB48F071, 0xDE2F4CC9, 0x3080F9DB, 0x55E74563,
+		0x9CA03F6B, 0xF9C783D3, 0x176836C1, 0x720F8A79,
+		0xCB375DE4, 0xAE50E15C, 0x40FF544E, 0x2598E8F6,
+		0x73888BAE, 0x16EF3716, 0xF8408204, 0x9D273EBC,
+		0x241FE921, 0x41785599, 0xAFD7E08B, 0xCAB05C33,
+		0x3BB659ED, 0x5ED1E555, 0xB07E5047, 0xD519ECFF,
+		0x6C213B62, 0x094687DA, 0xE7E932C8, 0x828E8E70,
+		0xD49EED28, 0xB1F95190, 0x5F56E482, 0x3A31583A,
+		0x83098FA7, 0xE66E331F, 0x08C1860D, 0x6DA63AB5,
+		0xA4E140BD, 0xC186FC05, 0x2F294917, 0x4A4EF5AF,
+		0xF3762232, 0x96119E8A, 0x78BE2B98, 0x1DD99720,
+		0x4BC9F478, 0x2EAE48C0, 0xC001FDD2, 0xA566416A,
+		0x1C5E96F7, 0x79392A4F, 0x97969F5D, 0xF2F123E5,
+		0x05196B4D, 0x607ED7F5, 0x8ED162E7, 0xEBB6DE5F,
+		0x528E09C2, 0x37E9B57A, 0xD9460068, 0xBC21BCD0,
+		0xEA31DF88, 0x8F566330, 0x61F9D622, 0x049E6A9A,
+		0xBDA6BD07, 0xD8C101BF, 0x366EB4AD, 0x53090815,
+		0x9A4E721D, 0xFF29CEA5, 0x11867BB7, 0x74E1C70F,
+		0xCDD91092, 0xA8BEAC2A, 0x46111938, 0x2376A580,
+		0x7566C6D8, 0x10017A60, 0xFEAECF72, 0x9BC973CA,
+		0x22F1A457, 0x479618EF, 0xA939ADFD, 0xCC5E1145,
+		0x06EE4D76, 0x6389F1CE, 0x8D2644DC, 0xE841F864,
+		0x51792FF9, 0x341E9341, 0xDAB12653, 0xBFD69AEB,
+		0xE9C6F9B3, 0x8CA1450B, 0x620EF019, 0x07694CA1,
+		0xBE519B3C, 0xDB362784, 0x35999296, 0x50FE2E2E,
+		0x99B95426, 0xFCDEE89E, 0x12715D8C, 0x7716E134,
+		0xCE2E36A9, 0xAB498A11, 0x45E63F03, 0x208183BB,
+		0x7691E0E3, 0x13F65C5B, 0xFD59E949, 0x983E55F1,
+		0x2106826C, 0x44613ED4, 0xAACE8BC6, 0xCFA9377E,
+		0x38417FD6, 0x5D26C36E, 0xB389767C, 0xD6EECAC4,
+		0x6FD61D59, 0x0AB1A1E1, 0xE41E14F3, 0x8179A84B,
+		0xD769CB13, 0xB20E77AB, 0x5CA1C2B9, 0x39C67E01,
+		0x80FEA99C, 0xE5991524, 0x0B36A036, 0x6E511C8E,
+		0xA7166686, 0xC271DA3E, 0x2CDE6F2C, 0x49B9D394,
+		0xF0810409, 0x95E6B8B1, 0x7B490DA3, 0x1E2EB11B,
+		0x483ED243, 0x2D596EFB, 0xC3F6DBE9, 0xA6916751,
+		0x1FA9B0CC, 0x7ACE0C74, 0x9461B966, 0xF10605DE
+	}, {
+		0x00000000, 0xB029603D, 0x6053C07A, 0xD07AA047,
+		0xC0A680F5, 0x708FE0C8, 0xA0F5408F, 0x10DC20B2,
+		0xC14B7030, 0x7162100D, 0xA118B04A, 0x1131D077,
+		0x01EDF0C5, 0xB1C490F8, 0x61BE30BF, 0xD1975082,
+		0x8297E060, 0x32BE805D, 0xE2C4201A, 0x52ED4027,
+		0x42316095, 0xF21800A8, 0x2262A0EF, 0x924BC0D2,
+		0x43DC9050, 0xF3F5F06D, 0x238F502A, 0x93A63017,
+		0x837A10A5, 0x33537098, 0xE329D0DF, 0x5300B0E2,
+		0x042FC1C1, 0xB406A1FC, 0x647C01BB, 0xD4556186,
+		0xC4894134, 0x74A02109, 0xA4DA814E, 0x14F3E173,
+		0xC564B1F1, 0x754DD1CC, 0xA537718B, 0x151E11B6,
+		0x05C23104, 0xB5EB5139, 0x6591F17E, 0xD5B89143,
+		0x86B821A1, 0x3691419C, 0xE6EBE1DB, 0x56C281E6,
+		0x461EA154, 0xF637C169, 0x264D612E, 0x96640113,
+		0x47F35191, 0xF7DA31AC, 0x27A091EB, 0x9789F1D6,
+		0x8755D164, 0x377CB159, 0xE706111E, 0x572F7123,
+		0x4958F358, 0xF9719365, 0x290B3322, 0x9922531F,
+		0x89FE73AD, 0x39D71390, 0xE9ADB3D7, 0x5984D3EA,
+		0x88138368, 0x383AE355, 0xE8404312, 0x5869232F,
+		0x48B5039D, 0xF89C63A0, 0x28E6C3E7, 0x98CFA3DA,
+		0xCBCF1338, 0x7BE67305, 0xAB9CD342, 0x1BB5B37F,
+		0x0B6993CD, 0xBB40F3F0, 0x6B3A53B7, 0xDB13338A,
+		0x0A846308, 0xBAAD0335, 0x6AD7A372, 0xDAFEC34F,
+		0xCA22E3FD, 0x7A0B83C0, 0xAA712387, 0x1A5843BA,
+		0x4D773299, 0xFD5E52A4, 0x2D24F2E3, 0x9D0D92DE,
+		0x8DD1B26C, 0x3DF8D251, 0xED827216, 0x5DAB122B,
+		0x8C3C42A9, 0x3C152294, 0xEC6F82D3, 0x5C46E2EE,
+		0x4C9AC25C, 0xFCB3A261, 0x2CC90226, 0x9CE0621B,
+		0xCFE0D2F9, 0x7FC9B2C4, 0xAFB31283, 0x1F9A72BE,
+		0x0F46520C, 0xBF6F3231, 0x6F159276, 0xDF3CF24B,
+		0x0EABA2C9, 0xBE82C2F4, 0x6EF862B3, 0xDED1028E,
+		0xCE0D223C, 0x7E244201, 0xAE5EE246, 0x1E77827B,
+		0x92B0E6B1, 0x2299868C, 0xF2E326CB, 0x42CA46F6,
+		0x52166644, 0xE23F0679, 0x3245A63E, 0x826CC603,
+		0x53FB9681, 0xE3D2F6BC, 0x33A856FB, 0x838136C6,
+		0x935D1674, 0x23747649, 0xF30ED60E, 0x4327B633,
+		0x102706D1, 0xA00E66EC, 0x7074C6AB, 0xC05DA696,
+		0xD0818624, 0x60A8E619, 0xB0D2465E, 0x00FB2663,
+		0xD16C76E1, 0x614516DC, 0xB13FB69B, 0x0116D6A6,
+		0x11CAF614, 0xA1E39629, 0x7199366E, 0xC1B05653,
+		0x969F2770, 0x26B6474D, 0xF6CCE70A, 0x46E58737,
+		0x5639A785, 0xE610C7B8, 0x366A67FF, 0x864307C2,
+		0x57D45740, 0xE7FD377D, 0x3787973A, 0x87AEF707,
+		0x9772D7B5, 0x275BB788, 0xF72117CF, 0x470877F2,
+		0x1408C710, 0xA421A72D, 0x745B076A, 0xC4726757,
+		0xD4AE47E5, 0x648727D8, 0xB4FD879F, 0x04D4E7A2,
+		0xD543B720, 0x656AD71D, 0xB510775A, 0x05391767,
+		0x15E537D5, 0xA5CC57E8, 0x75B6F7AF, 0xC59F9792,
+		0xDBE815E9, 0x6BC175D4, 0xBBBBD593, 0x0B92B5AE,
+		0x1B4E951C, 0xAB67F521, 0x7B1D5566, 0xCB34355B,
+		0x1AA365D9, 0xAA8A05E4, 0x7AF0A5A3, 0xCAD9C59E,
+		0xDA05E52C, 0x6A2C8511, 0xBA562556, 0x0A7F456B,
+		0x597FF589, 0xE95695B4, 0x392C35F3, 0x890555CE,
+		0x99D9757C, 0x29F01541, 0xF98AB506, 0x49A3D53B,
+		0x983485B9, 0x281DE584, 0xF86745C3, 0x484E25FE,
+		0x5892054C, 0xE8BB6571, 0x38C1C536, 0x88E8A50B,
+		0xDFC7D428, 0x6FEEB415, 0xBF941452, 0x0FBD746F,
+		0x1F6154DD, 0xAF4834E0, 0x7F3294A7, 0xCF1BF49A,
+		0x1E8CA418, 0xAEA5C425, 0x7EDF6462, 0xCEF6045F,
+		0xDE2A24ED, 0x6E0344D0, 0xBE79E497, 0x0E5084AA,
+		0x5D503448, 0xED795475, 0x3D03F432, 0x8D2A940F,
+		0x9DF6B4BD, 0x2DDFD480, 0xFDA574C7, 0x4D8C14FA,
+		0x9C1B4478, 0x2C322445, 0xFC488402, 0x4C61E43F,
+		0x5CBDC48D, 0xEC94A4B0, 0x3CEE04F7, 0x8CC764CA
+	}, {
+		0x00000000, 0xA5D35CCB, 0x0BA1C84D, 0xAE729486,
+		0x1642919B, 0xB391CD50, 0x1DE359D6, 0xB830051D,
+		0x6D8253EC, 0xC8510F27, 0x66239BA1, 0xC3F0C76A,
+		0x7BC0C277, 0xDE139EBC, 0x70610A3A, 0xD5B256F1,
+		0x9B02D603, 0x3ED18AC8, 0x90A31E4E, 0x35704285,
+		0x8D404798, 0x28931B53, 0x86E18FD5, 0x2332D31E,
+		0xF68085EF, 0x5353D924, 0xFD214DA2, 0x58F21169,
+		0xE0C21474, 0x451148BF, 0xEB63DC39, 0x4EB080F2,
+		0x3605AC07, 0x93D6F0CC, 0x3DA4644A, 0x98773881,
+		0x20473D9C, 0x85946157, 0x2BE6F5D1, 0x8E35A91A,
+		0x5B87FFEB, 0xFE54A320, 0x502637A6, 0xF5F56B6D,
+		0x4DC56E70, 0xE81632BB, 0x4664A63D, 0xE3B7FAF6,
+		0xAD077A04, 0x08D426CF, 0xA6A6B249, 0x0375EE82,
+		0xBB45EB9F, 0x1E96B754, 0xB0E423D2, 0x15377F19,
+		0xC08529E8, 0x65567523, 0xCB24E1A5, 0x6EF7BD6E,
+		0xD6C7B873, 0x7314E4B8, 0xDD66703E, 0x78B52CF5,
+		0x6C0A580F, 0xC9D904C4, 0x67AB9042, 0xC278CC89,
+		0x7A48C994, 0xDF9B955F, 0x71E901D9, 0xD43A5D12,
+		0x01880BE3, 0xA45B5728, 0x0A29C3AE, 0xAFFA9F65,
+		0x17CA9A78, 0xB219C6B3, 0x1C6B5235, 0xB9B80EFE,
+		0xF7088E0C, 0x52DBD2C7, 0xFCA94641, 0x597A1A8A,
+		0xE14A1F97, 0x4499435C, 0xEAEBD7DA, 0x4F388B11,
+		0x9A8ADDE0, 0x3F59812B, 0x912B15AD, 0x34F84966,
+		0x8CC84C7B, 0x291B10B0, 0x87698436, 0x22BAD8FD,
+		0x5A0FF408, 0xFFDCA8C3, 0x51AE3C45, 0xF47D608E,
+		0x4C4D6593, 0xE99E3958, 0x47ECADDE, 0xE23FF115,
+		0x378DA7E4, 0x925EFB2F, 0x3C2C6FA9, 0x99FF3362,
+		0x21CF367F, 0x841C6AB4, 0x2A6EFE32, 0x8FBDA2F9,
+		0xC10D220B, 0x64DE7EC0, 0xCAACEA46, 0x6F7FB68D,
+		0xD74FB390, 0x729CEF5B, 0xDCEE7BDD, 0x793D2716,
+		0xAC8F71E7, 0x095C2D2C, 0xA72EB9AA, 0x02FDE561,
+		0xBACDE07C, 0x1F1EBCB7, 0xB16C2831, 0x14BF74FA,
+		0xD814B01E, 0x7DC7ECD5, 0xD3B57853, 0x76662498,
+		0xCE562185, 0x6B857D4E, 0xC5F7E9C8, 0x6024B503,
+		0xB596E3F2, 0x1045BF39, 0xBE372BBF, 0x1BE47774,
+		0xA3D47269, 0x06072EA2, 0xA875BA24, 0x0DA6E6EF,
+		0x4316661D, 0xE6C53AD6, 0x48B7AE50, 0xED64F29B,
+		0x5554F786, 0xF087AB4D, 0x5EF53FCB, 0xFB266300,
+		0x2E9435F1, 0x8B47693A, 0x2535FDBC, 0x80E6A177,
+		0x38D6A46A, 0x9D05F8A1, 0x33776C27, 0x96A430EC,
+		0xEE111C19, 0x4BC240D2, 0xE5B0D454, 0x4063889F,
+		0xF8538D82, 0x5D80D149, 0xF3F245CF, 0x56211904,
+		0x83934FF5, 0x2640133E, 0x883287B8, 0x2DE1DB73,
+		0x95D1DE6E, 0x300282A5, 0x9E701623, 0x3BA34AE8,
+		0x7513CA1A, 0xD0C096D1, 0x7EB20257, 0xDB615E9C,
+		0x63515B81, 0xC682074A, 0x68F093CC, 0xCD23CF07,
+		0x189199F6, 0xBD42C53D, 0x133051BB, 0xB6E30D70,
+		0x0ED3086D, 0xAB0054A6, 0x0572C020, 0xA0A19CEB,
+		0xB41EE811, 0x11CDB4DA, 0xBFBF205C, 0x1A6C7C97,
+		0xA25C798A, 0x078F2541, 0xA9FDB1C7, 0x0C2EED0C,
+		0xD99CBBFD, 0x7C4FE736, 0xD23D73B0, 0x77EE2F7B,
+		0xCFDE2A66, 0x6A0D76AD, 0xC47FE22B, 0x61ACBEE0,
+		0x2F1C3E12, 0x8ACF62D9, 0x24BDF65F, 0x816EAA94,
+		0x395EAF89, 0x9C8DF342, 0x32FF67C4, 0x972C3B0F,
+		0x429E6DFE, 0xE74D3135, 0x493FA5B3, 0xECECF978,
+		0x54DCFC65, 0xF10FA0AE, 0x5F7D3428, 0xFAAE68E3,
+		0x821B4416, 0x27C818DD, 0x89BA8C5B, 0x2C69D090,
+		0x9459D58D, 0x318A8946, 0x9FF81DC0, 0x3A2B410B,
+		0xEF9917FA, 0x4A4A4B31, 0xE438DFB7, 0x41EB837C,
+		0xF9DB8661, 0x5C08DAAA, 0xF27A4E2C, 0x57A912E7,
+		0x19199215, 0xBCCACEDE, 0x12B85A58, 0xB76B0693,
+		0x0F5B038E, 0xAA885F45, 0x04FACBC3, 0xA1299708,
+		0x749BC1F9, 0xD1489D32, 0x7F3A09B4, 0xDAE9557F,
+		0x62D95062, 0xC70A0CA9, 0x6978982F, 0xCCABC4E4
+	}, {
+		0x00000000, 0xB40B77A6, 0x29119F97, 0x9D1AE831,
+		0x13244FF4, 0xA72F3852, 0x3A35D063, 0x8E3EA7C5,
+		0x674EEF33, 0xD3459895, 0x4E5F70A4, 0xFA540702,
+		0x746AA0C7, 0xC061D761, 0x5D7B3F50, 0xE97048F6,
+		0xCE9CDE67, 0x7A97A9C1, 0xE78D41F0, 0x53863656,
+		0xDDB89193, 0x69B3E635, 0xF4A90E04, 0x40A279A2,
+		0xA9D23154, 0x1DD946F2, 0x80C3AEC3, 0x34C8D965,
+		0xBAF67EA0, 0x0EFD0906, 0x93E7E137, 0x27EC9691,
+		0x9C39BDCF, 0x2832CA69, 0xB5282258, 0x012355FE,
+		0x8F1DF23B, 0x3B16859D, 0xA60C6DAC, 0x12071A0A,
+		0xFB7752FC, 0x4F7C255A, 0xD266CD6B, 0x666DBACD,
+		0xE8531D08, 0x5C586AAE, 0xC142829F, 0x7549F539,
+		0x52A563A8, 0xE6AE140E, 0x7BB4FC3F, 0xCFBF8B99,
+		0x41812C5C, 0xF58A5BFA, 0x6890B3CB, 0xDC9BC46D,
+		0x35EB8C9B, 0x81E0FB3D, 0x1CFA130C, 0xA8F164AA,
+		0x26CFC36F, 0x92C4B4C9, 0x0FDE5CF8, 0xBBD52B5E,
+		0x79750B44, 0xCD7E7CE2, 0x506494D3, 0xE46FE375,
+		0x6A5144B0, 0xDE5A3316, 0x4340DB27, 0xF74BAC81,
+		0x1E3BE477, 0xAA3093D1, 0x372A7BE0, 0x83210C46,
+		0x0D1FAB83, 0xB914DC25, 0x240E3414, 0x900543B2,
+		0xB7E9D523, 0x03E2A285, 0x9EF84AB4, 0x2AF33D12,
+		0xA4CD9AD7, 0x10C6ED71, 0x8DDC0540, 0x39D772E6,
+		0xD0A73A10, 0x64AC4DB6, 0xF9B6A587, 0x4DBDD221,
+		0xC38375E4, 0x77880242, 0xEA92EA73, 0x5E999DD5,
+		0xE54CB68B, 0x5147C12D, 0xCC5D291C, 0x78565EBA,
+		0xF668F97F, 0x42638ED9, 0xDF7966E8, 0x6B72114E,
+		0x820259B8, 0x36092E1E, 0xAB13C62F, 0x1F18B189,
+		0x9126164C, 0x252D61EA, 0xB83789DB, 0x0C3CFE7D,
+		0x2BD068EC, 0x9FDB1F4A, 0x02C1F77B, 0xB6CA80DD,
+		0x38F42718, 0x8CFF50BE, 0x11E5B88F, 0xA5EECF29,
+		0x4C9E87DF, 0xF895F079, 0x658F1848, 0xD1846FEE,
+		0x5FBAC82B, 0xEBB1BF8D, 0x76AB57BC, 0xC2A0201A,
+		0xF2EA1688, 0x46E1612E, 0xDBFB891F, 0x6FF0FEB9,
+		0xE1CE597C, 0x55C52EDA, 0xC8DFC6EB, 0x7CD4B14D,
+		0x95A4F9BB, 0x21AF8E1D, 0xBCB5662C, 0x08BE118A,
+		0x8680B64F, 0x328BC1E9, 0xAF9129D8, 0x1B9A5E7E,
+		0x3C76C8EF, 0x887DBF49, 0x15675778, 0xA16C20DE,
+		0x2F52871B, 0x9B59F0BD, 0x0643188C, 0xB2486F2A,
+		0x5B3827DC, 0xEF33507A, 0x7229B84B, 0xC622CFED,
+		0x481C6828, 0xFC171F8E, 0x610DF7BF, 0xD5068019,
+		0x6ED3AB47, 0xDAD8DCE1, 0x47C234D0, 0xF3C94376,
+		0x7DF7E4B3, 0xC9FC9315, 0x54E67B24, 0xE0ED0C82,
+		0x099D4474, 0xBD9633D2, 0x208CDBE3, 0x9487AC45,
+		0x1AB90B80, 0xAEB27C26, 0x33A89417, 0x87A3E3B1,
+		0xA04F7520, 0x14440286, 0x895EEAB7, 0x3D559D11,
+		0xB36B3AD4, 0x07604D72, 0x9A7AA543, 0x2E71D2E5,
+		0xC7019A13, 0x730AEDB5, 0xEE100584, 0x5A1B7222,
+		0xD425D5E7, 0x602EA241, 0xFD344A70, 0x493F3DD6,
+		0x8B9F1DCC, 0x3F946A6A, 0xA28E825B, 0x1685F5FD,
+		0x98BB5238, 0x2CB0259E, 0xB1AACDAF, 0x05A1BA09,
+		0xECD1F2FF, 0x58DA8559, 0xC5C06D68, 0x71CB1ACE,
+		0xFFF5BD0B, 0x4BFECAAD, 0xD6E4229C, 0x62EF553A,
+		0x4503C3AB, 0xF108B40D, 0x6C125C3C, 0xD8192B9A,
+		0x56278C5F, 0xE22CFBF9, 0x7F3613C8, 0xCB3D646E,
+		0x224D2C98, 0x96465B3E, 0x0B5CB30F, 0xBF57C4A9,
+		0x3169636C, 0x856214CA, 0x1878FCFB, 0xAC738B5D,
+		0x17A6A003, 0xA3ADD7A5, 0x3EB73F94, 0x8ABC4832,
+		0x0482EFF7, 0xB0899851, 0x2D937060, 0x999807C6,
+		0x70E84F30, 0xC4E33896, 0x59F9D0A7, 0xEDF2A701,
+		0x63CC00C4, 0xD7C77762, 0x4ADD9F53, 0xFED6E8F5,
+		0xD93A7E64, 0x6D3109C2, 0xF02BE1F3, 0x44209655,
+		0xCA1E3190, 0x7E154636, 0xE30FAE07, 0x5704D9A1,
+		0xBE749157, 0x0A7FE6F1, 0x97650EC0, 0x236E7966,
+		0xAD50DEA3, 0x195BA905, 0x84414134, 0x304A3692
+	}, {
+		0x00000000, 0x9E00AACC, 0x7D072542, 0xE3078F8E,
+		0xFA0E4A84, 0x640EE048, 0x87096FC6, 0x1909C50A,
+		0xB51BE5D3, 0x2B1B4F1F, 0xC81CC091, 0x561C6A5D,
+		0x4F15AF57, 0xD115059B, 0x32128A15, 0xAC1220D9,
+		0x2B31BB7C, 0xB53111B0, 0x56369E3E, 0xC83634F2,
+		0xD13FF1F8, 0x4F3F5B34, 0xAC38D4BA, 0x32387E76,
+		0x9E2A5EAF, 0x002AF463, 0xE32D7BED, 0x7D2DD121,
+		0x6424142B, 0xFA24BEE7, 0x19233169, 0x87239BA5,
+		0x566276F9, 0xC862DC35, 0x2B6553BB, 0xB565F977,
+		0xAC6C3C7D, 0x326C96B1, 0xD16B193F, 0x4F6BB3F3,
+		0xE379932A, 0x7D7939E6, 0x9E7EB668, 0x007E1CA4,
+		0x1977D9AE, 0x87777362, 0x6470FCEC, 0xFA705620,
+		0x7D53CD85, 0xE3536749, 0x0054E8C7, 0x9E54420B,
+		0x875D8701, 0x195D2DCD, 0xFA5AA243, 0x645A088F,
+		0xC8482856, 0x5648829A, 0xB54F0D14, 0x2B4FA7D8,
+		0x324662D2, 0xAC46C81E, 0x4F414790, 0xD141ED5C,
+		0xEDC29D29, 0x73C237E5, 0x90C5B86B, 0x0EC512A7,
+		0x17CCD7AD, 0x89CC7D61, 0x6ACBF2EF, 0xF4CB5823,
+		0x58D978FA, 0xC6D9D236, 0x25DE5DB8, 0xBBDEF774,
+		0xA2D7327E, 0x3CD798B2, 0xDFD0173C, 0x41D0BDF0,
+		0xC6F32655, 0x58F38C99, 0xBBF40317, 0x25F4A9DB,
+		0x3CFD6CD1, 0xA2FDC61D, 0x41FA4993, 0xDFFAE35F,
+		0x73E8C386, 0xEDE8694A, 0x0EEFE6C4, 0x90EF4C08,
+		0x89E68902, 0x17E623CE, 0xF4E1AC40, 0x6AE1068C,
+		0xBBA0EBD0, 0x25A0411C, 0xC6A7CE92, 0x58A7645E,
+		0x41AEA154, 0xDFAE0B98, 0x3CA98416, 0xA2A92EDA,
+		0x0EBB0E03, 0x90BBA4CF, 0x73BC2B41, 0xEDBC818D,
+		0xF4B54487, 0x6AB5EE4B, 0x89B261C5, 0x17B2CB09,
+		0x909150AC, 0x0E91FA60, 0xED9675EE, 0x7396DF22,
+		0x6A9F1A28, 0xF49FB0E4, 0x17983F6A, 0x899895A6,
+		0x258AB57F, 0xBB8A1FB3, 0x588D903D, 0xC68D3AF1,
+		0xDF84FFFB, 0x41845537, 0xA283DAB9, 0x3C837075,
+		0xDA853B53, 0x4485919F, 0xA7821E11, 0x3982B4DD,
+		0x208B71D7, 0xBE8BDB1B, 0x5D8C5495, 0xC38CFE59,
+		0x6F9EDE80, 0xF19E744C, 0x1299FBC2, 0x8C99510E,
+		0x95909404, 0x0B903EC8, 0xE897B146, 0x76971B8A,
+		0xF1B4802F, 0x6FB42AE3, 0x8CB3A56D, 0x12B30FA1,
+		0x0BBACAAB, 0x95BA6067, 0x76BDEFE9, 0xE8BD4525,
+		0x44AF65FC, 0xDAAFCF30, 0x39A840BE, 0xA7A8EA72,
+		0xBEA12F78, 0x20A185B4, 0xC3A60A3A, 0x5DA6A0F6,
+		0x8CE74DAA, 0x12E7E766, 0xF1E068E8, 0x6FE0C224,
+		0x76E9072E, 0xE8E9ADE2, 0x0BEE226C, 0x95EE88A0,
+		0x39FCA879, 0xA7FC02B5, 0x44FB8D3B, 0xDAFB27F7,
+		0xC3F2E2FD, 0x5DF24831, 0xBEF5C7BF, 0x20F56D73,
+		0xA7D6F6D6, 0x39D65C1A, 0xDAD1D394, 0x44D17958,
+		0x5DD8BC52, 0xC3D8169E, 0x20DF9910, 0xBEDF33DC,
+		0x12CD1305, 0x8CCDB9C9, 0x6FCA3647, 0xF1CA9C8B,
+		0xE8C35981, 0x76C3F34D, 0x95C47CC3, 0x0BC4D60F,
+		0x3747A67A, 0xA9470CB6, 0x4A408338, 0xD44029F4,
+		0xCD49ECFE, 0x53494632, 0xB04EC9BC, 0x2E4E6370,
+		0x825C43A9, 0x1C5CE965, 0xFF5B66EB, 0x615BCC27,
+		0x7852092D, 0xE652A3E1, 0x05552C6F, 0x9B5586A3,
+		0x1C761D06, 0x8276B7CA, 0x61713844, 0xFF719288,
+		0xE6785782, 0x7878FD4E, 0x9B7F72C0, 0x057FD80C,
+		0xA96DF8D5, 0x376D5219, 0xD46ADD97, 0x4A6A775B,
+		0x5363B251, 0xCD63189D, 0x2E649713, 0xB0643DDF,
+		0x6125D083, 0xFF257A4F, 0x1C22F5C1, 0x82225F0D,
+		0x9B2B9A07, 0x052B30CB, 0xE62CBF45, 0x782C1589,
+		0xD43E3550, 0x4A3E9F9C, 0xA9391012, 0x3739BADE,
+		0x2E307FD4, 0xB030D518, 0x53375A96, 0xCD37F05A,
+		0x4A146BFF, 0xD414C133, 0x37134EBD, 0xA913E471,
+		0xB01A217B, 0x2E1A8BB7, 0xCD1D0439, 0x531DAEF5,
+		0xFF0F8E2C, 0x610F24E0, 0x8208AB6E, 0x1C0801A2,
+		0x0501C4A8, 0x9B016E64, 0x7806E1EA, 0xE6064B26
+	}
+};
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_le.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_le.h
new file mode 100644
index 00000000000..e89c21a7b23
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_table_le.h
@@ -0,0 +1,527 @@
+// SPDX-License-Identifier: 0BSD
+
+// This file has been generated by crc32_tablegen.c.
+
+const uint32_t lzma_crc32_table[8][256] = {
+	{
+		0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
+		0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+		0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+		0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+		0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
+		0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+		0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
+		0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+		0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+		0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+		0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
+		0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+		0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
+		0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+		0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+		0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+		0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
+		0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+		0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
+		0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+		0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+		0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+		0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
+		0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+		0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
+		0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+		0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+		0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+		0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
+		0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+		0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
+		0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+		0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+		0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+		0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
+		0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+		0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
+		0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+		0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+		0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+		0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
+		0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+		0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
+		0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+		0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+		0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+		0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
+		0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+		0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
+		0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+		0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+		0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+		0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
+		0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+		0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
+		0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+		0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+		0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+		0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
+		0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+		0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
+		0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+		0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+		0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+	}, {
+		0x00000000, 0x191B3141, 0x32366282, 0x2B2D53C3,
+		0x646CC504, 0x7D77F445, 0x565AA786, 0x4F4196C7,
+		0xC8D98A08, 0xD1C2BB49, 0xFAEFE88A, 0xE3F4D9CB,
+		0xACB54F0C, 0xB5AE7E4D, 0x9E832D8E, 0x87981CCF,
+		0x4AC21251, 0x53D92310, 0x78F470D3, 0x61EF4192,
+		0x2EAED755, 0x37B5E614, 0x1C98B5D7, 0x05838496,
+		0x821B9859, 0x9B00A918, 0xB02DFADB, 0xA936CB9A,
+		0xE6775D5D, 0xFF6C6C1C, 0xD4413FDF, 0xCD5A0E9E,
+		0x958424A2, 0x8C9F15E3, 0xA7B24620, 0xBEA97761,
+		0xF1E8E1A6, 0xE8F3D0E7, 0xC3DE8324, 0xDAC5B265,
+		0x5D5DAEAA, 0x44469FEB, 0x6F6BCC28, 0x7670FD69,
+		0x39316BAE, 0x202A5AEF, 0x0B07092C, 0x121C386D,
+		0xDF4636F3, 0xC65D07B2, 0xED705471, 0xF46B6530,
+		0xBB2AF3F7, 0xA231C2B6, 0x891C9175, 0x9007A034,
+		0x179FBCFB, 0x0E848DBA, 0x25A9DE79, 0x3CB2EF38,
+		0x73F379FF, 0x6AE848BE, 0x41C51B7D, 0x58DE2A3C,
+		0xF0794F05, 0xE9627E44, 0xC24F2D87, 0xDB541CC6,
+		0x94158A01, 0x8D0EBB40, 0xA623E883, 0xBF38D9C2,
+		0x38A0C50D, 0x21BBF44C, 0x0A96A78F, 0x138D96CE,
+		0x5CCC0009, 0x45D73148, 0x6EFA628B, 0x77E153CA,
+		0xBABB5D54, 0xA3A06C15, 0x888D3FD6, 0x91960E97,
+		0xDED79850, 0xC7CCA911, 0xECE1FAD2, 0xF5FACB93,
+		0x7262D75C, 0x6B79E61D, 0x4054B5DE, 0x594F849F,
+		0x160E1258, 0x0F152319, 0x243870DA, 0x3D23419B,
+		0x65FD6BA7, 0x7CE65AE6, 0x57CB0925, 0x4ED03864,
+		0x0191AEA3, 0x188A9FE2, 0x33A7CC21, 0x2ABCFD60,
+		0xAD24E1AF, 0xB43FD0EE, 0x9F12832D, 0x8609B26C,
+		0xC94824AB, 0xD05315EA, 0xFB7E4629, 0xE2657768,
+		0x2F3F79F6, 0x362448B7, 0x1D091B74, 0x04122A35,
+		0x4B53BCF2, 0x52488DB3, 0x7965DE70, 0x607EEF31,
+		0xE7E6F3FE, 0xFEFDC2BF, 0xD5D0917C, 0xCCCBA03D,
+		0x838A36FA, 0x9A9107BB, 0xB1BC5478, 0xA8A76539,
+		0x3B83984B, 0x2298A90A, 0x09B5FAC9, 0x10AECB88,
+		0x5FEF5D4F, 0x46F46C0E, 0x6DD93FCD, 0x74C20E8C,
+		0xF35A1243, 0xEA412302, 0xC16C70C1, 0xD8774180,
+		0x9736D747, 0x8E2DE606, 0xA500B5C5, 0xBC1B8484,
+		0x71418A1A, 0x685ABB5B, 0x4377E898, 0x5A6CD9D9,
+		0x152D4F1E, 0x0C367E5F, 0x271B2D9C, 0x3E001CDD,
+		0xB9980012, 0xA0833153, 0x8BAE6290, 0x92B553D1,
+		0xDDF4C516, 0xC4EFF457, 0xEFC2A794, 0xF6D996D5,
+		0xAE07BCE9, 0xB71C8DA8, 0x9C31DE6B, 0x852AEF2A,
+		0xCA6B79ED, 0xD37048AC, 0xF85D1B6F, 0xE1462A2E,
+		0x66DE36E1, 0x7FC507A0, 0x54E85463, 0x4DF36522,
+		0x02B2F3E5, 0x1BA9C2A4, 0x30849167, 0x299FA026,
+		0xE4C5AEB8, 0xFDDE9FF9, 0xD6F3CC3A, 0xCFE8FD7B,
+		0x80A96BBC, 0x99B25AFD, 0xB29F093E, 0xAB84387F,
+		0x2C1C24B0, 0x350715F1, 0x1E2A4632, 0x07317773,
+		0x4870E1B4, 0x516BD0F5, 0x7A468336, 0x635DB277,
+		0xCBFAD74E, 0xD2E1E60F, 0xF9CCB5CC, 0xE0D7848D,
+		0xAF96124A, 0xB68D230B, 0x9DA070C8, 0x84BB4189,
+		0x03235D46, 0x1A386C07, 0x31153FC4, 0x280E0E85,
+		0x674F9842, 0x7E54A903, 0x5579FAC0, 0x4C62CB81,
+		0x8138C51F, 0x9823F45E, 0xB30EA79D, 0xAA1596DC,
+		0xE554001B, 0xFC4F315A, 0xD7626299, 0xCE7953D8,
+		0x49E14F17, 0x50FA7E56, 0x7BD72D95, 0x62CC1CD4,
+		0x2D8D8A13, 0x3496BB52, 0x1FBBE891, 0x06A0D9D0,
+		0x5E7EF3EC, 0x4765C2AD, 0x6C48916E, 0x7553A02F,
+		0x3A1236E8, 0x230907A9, 0x0824546A, 0x113F652B,
+		0x96A779E4, 0x8FBC48A5, 0xA4911B66, 0xBD8A2A27,
+		0xF2CBBCE0, 0xEBD08DA1, 0xC0FDDE62, 0xD9E6EF23,
+		0x14BCE1BD, 0x0DA7D0FC, 0x268A833F, 0x3F91B27E,
+		0x70D024B9, 0x69CB15F8, 0x42E6463B, 0x5BFD777A,
+		0xDC656BB5, 0xC57E5AF4, 0xEE530937, 0xF7483876,
+		0xB809AEB1, 0xA1129FF0, 0x8A3FCC33, 0x9324FD72
+	}, {
+		0x00000000, 0x01C26A37, 0x0384D46E, 0x0246BE59,
+		0x0709A8DC, 0x06CBC2EB, 0x048D7CB2, 0x054F1685,
+		0x0E1351B8, 0x0FD13B8F, 0x0D9785D6, 0x0C55EFE1,
+		0x091AF964, 0x08D89353, 0x0A9E2D0A, 0x0B5C473D,
+		0x1C26A370, 0x1DE4C947, 0x1FA2771E, 0x1E601D29,
+		0x1B2F0BAC, 0x1AED619B, 0x18ABDFC2, 0x1969B5F5,
+		0x1235F2C8, 0x13F798FF, 0x11B126A6, 0x10734C91,
+		0x153C5A14, 0x14FE3023, 0x16B88E7A, 0x177AE44D,
+		0x384D46E0, 0x398F2CD7, 0x3BC9928E, 0x3A0BF8B9,
+		0x3F44EE3C, 0x3E86840B, 0x3CC03A52, 0x3D025065,
+		0x365E1758, 0x379C7D6F, 0x35DAC336, 0x3418A901,
+		0x3157BF84, 0x3095D5B3, 0x32D36BEA, 0x331101DD,
+		0x246BE590, 0x25A98FA7, 0x27EF31FE, 0x262D5BC9,
+		0x23624D4C, 0x22A0277B, 0x20E69922, 0x2124F315,
+		0x2A78B428, 0x2BBADE1F, 0x29FC6046, 0x283E0A71,
+		0x2D711CF4, 0x2CB376C3, 0x2EF5C89A, 0x2F37A2AD,
+		0x709A8DC0, 0x7158E7F7, 0x731E59AE, 0x72DC3399,
+		0x7793251C, 0x76514F2B, 0x7417F172, 0x75D59B45,
+		0x7E89DC78, 0x7F4BB64F, 0x7D0D0816, 0x7CCF6221,
+		0x798074A4, 0x78421E93, 0x7A04A0CA, 0x7BC6CAFD,
+		0x6CBC2EB0, 0x6D7E4487, 0x6F38FADE, 0x6EFA90E9,
+		0x6BB5866C, 0x6A77EC5B, 0x68315202, 0x69F33835,
+		0x62AF7F08, 0x636D153F, 0x612BAB66, 0x60E9C151,
+		0x65A6D7D4, 0x6464BDE3, 0x662203BA, 0x67E0698D,
+		0x48D7CB20, 0x4915A117, 0x4B531F4E, 0x4A917579,
+		0x4FDE63FC, 0x4E1C09CB, 0x4C5AB792, 0x4D98DDA5,
+		0x46C49A98, 0x4706F0AF, 0x45404EF6, 0x448224C1,
+		0x41CD3244, 0x400F5873, 0x4249E62A, 0x438B8C1D,
+		0x54F16850, 0x55330267, 0x5775BC3E, 0x56B7D609,
+		0x53F8C08C, 0x523AAABB, 0x507C14E2, 0x51BE7ED5,
+		0x5AE239E8, 0x5B2053DF, 0x5966ED86, 0x58A487B1,
+		0x5DEB9134, 0x5C29FB03, 0x5E6F455A, 0x5FAD2F6D,
+		0xE1351B80, 0xE0F771B7, 0xE2B1CFEE, 0xE373A5D9,
+		0xE63CB35C, 0xE7FED96B, 0xE5B86732, 0xE47A0D05,
+		0xEF264A38, 0xEEE4200F, 0xECA29E56, 0xED60F461,
+		0xE82FE2E4, 0xE9ED88D3, 0xEBAB368A, 0xEA695CBD,
+		0xFD13B8F0, 0xFCD1D2C7, 0xFE976C9E, 0xFF5506A9,
+		0xFA1A102C, 0xFBD87A1B, 0xF99EC442, 0xF85CAE75,
+		0xF300E948, 0xF2C2837F, 0xF0843D26, 0xF1465711,
+		0xF4094194, 0xF5CB2BA3, 0xF78D95FA, 0xF64FFFCD,
+		0xD9785D60, 0xD8BA3757, 0xDAFC890E, 0xDB3EE339,
+		0xDE71F5BC, 0xDFB39F8B, 0xDDF521D2, 0xDC374BE5,
+		0xD76B0CD8, 0xD6A966EF, 0xD4EFD8B6, 0xD52DB281,
+		0xD062A404, 0xD1A0CE33, 0xD3E6706A, 0xD2241A5D,
+		0xC55EFE10, 0xC49C9427, 0xC6DA2A7E, 0xC7184049,
+		0xC25756CC, 0xC3953CFB, 0xC1D382A2, 0xC011E895,
+		0xCB4DAFA8, 0xCA8FC59F, 0xC8C97BC6, 0xC90B11F1,
+		0xCC440774, 0xCD866D43, 0xCFC0D31A, 0xCE02B92D,
+		0x91AF9640, 0x906DFC77, 0x922B422E, 0x93E92819,
+		0x96A63E9C, 0x976454AB, 0x9522EAF2, 0x94E080C5,
+		0x9FBCC7F8, 0x9E7EADCF, 0x9C381396, 0x9DFA79A1,
+		0x98B56F24, 0x99770513, 0x9B31BB4A, 0x9AF3D17D,
+		0x8D893530, 0x8C4B5F07, 0x8E0DE15E, 0x8FCF8B69,
+		0x8A809DEC, 0x8B42F7DB, 0x89044982, 0x88C623B5,
+		0x839A6488, 0x82580EBF, 0x801EB0E6, 0x81DCDAD1,
+		0x8493CC54, 0x8551A663, 0x8717183A, 0x86D5720D,
+		0xA9E2D0A0, 0xA820BA97, 0xAA6604CE, 0xABA46EF9,
+		0xAEEB787C, 0xAF29124B, 0xAD6FAC12, 0xACADC625,
+		0xA7F18118, 0xA633EB2F, 0xA4755576, 0xA5B73F41,
+		0xA0F829C4, 0xA13A43F3, 0xA37CFDAA, 0xA2BE979D,
+		0xB5C473D0, 0xB40619E7, 0xB640A7BE, 0xB782CD89,
+		0xB2CDDB0C, 0xB30FB13B, 0xB1490F62, 0xB08B6555,
+		0xBBD72268, 0xBA15485F, 0xB853F606, 0xB9919C31,
+		0xBCDE8AB4, 0xBD1CE083, 0xBF5A5EDA, 0xBE9834ED
+	}, {
+		0x00000000, 0xB8BC6765, 0xAA09C88B, 0x12B5AFEE,
+		0x8F629757, 0x37DEF032, 0x256B5FDC, 0x9DD738B9,
+		0xC5B428EF, 0x7D084F8A, 0x6FBDE064, 0xD7018701,
+		0x4AD6BFB8, 0xF26AD8DD, 0xE0DF7733, 0x58631056,
+		0x5019579F, 0xE8A530FA, 0xFA109F14, 0x42ACF871,
+		0xDF7BC0C8, 0x67C7A7AD, 0x75720843, 0xCDCE6F26,
+		0x95AD7F70, 0x2D111815, 0x3FA4B7FB, 0x8718D09E,
+		0x1ACFE827, 0xA2738F42, 0xB0C620AC, 0x087A47C9,
+		0xA032AF3E, 0x188EC85B, 0x0A3B67B5, 0xB28700D0,
+		0x2F503869, 0x97EC5F0C, 0x8559F0E2, 0x3DE59787,
+		0x658687D1, 0xDD3AE0B4, 0xCF8F4F5A, 0x7733283F,
+		0xEAE41086, 0x525877E3, 0x40EDD80D, 0xF851BF68,
+		0xF02BF8A1, 0x48979FC4, 0x5A22302A, 0xE29E574F,
+		0x7F496FF6, 0xC7F50893, 0xD540A77D, 0x6DFCC018,
+		0x359FD04E, 0x8D23B72B, 0x9F9618C5, 0x272A7FA0,
+		0xBAFD4719, 0x0241207C, 0x10F48F92, 0xA848E8F7,
+		0x9B14583D, 0x23A83F58, 0x311D90B6, 0x89A1F7D3,
+		0x1476CF6A, 0xACCAA80F, 0xBE7F07E1, 0x06C36084,
+		0x5EA070D2, 0xE61C17B7, 0xF4A9B859, 0x4C15DF3C,
+		0xD1C2E785, 0x697E80E0, 0x7BCB2F0E, 0xC377486B,
+		0xCB0D0FA2, 0x73B168C7, 0x6104C729, 0xD9B8A04C,
+		0x446F98F5, 0xFCD3FF90, 0xEE66507E, 0x56DA371B,
+		0x0EB9274D, 0xB6054028, 0xA4B0EFC6, 0x1C0C88A3,
+		0x81DBB01A, 0x3967D77F, 0x2BD27891, 0x936E1FF4,
+		0x3B26F703, 0x839A9066, 0x912F3F88, 0x299358ED,
+		0xB4446054, 0x0CF80731, 0x1E4DA8DF, 0xA6F1CFBA,
+		0xFE92DFEC, 0x462EB889, 0x549B1767, 0xEC277002,
+		0x71F048BB, 0xC94C2FDE, 0xDBF98030, 0x6345E755,
+		0x6B3FA09C, 0xD383C7F9, 0xC1366817, 0x798A0F72,
+		0xE45D37CB, 0x5CE150AE, 0x4E54FF40, 0xF6E89825,
+		0xAE8B8873, 0x1637EF16, 0x048240F8, 0xBC3E279D,
+		0x21E91F24, 0x99557841, 0x8BE0D7AF, 0x335CB0CA,
+		0xED59B63B, 0x55E5D15E, 0x47507EB0, 0xFFEC19D5,
+		0x623B216C, 0xDA874609, 0xC832E9E7, 0x708E8E82,
+		0x28ED9ED4, 0x9051F9B1, 0x82E4565F, 0x3A58313A,
+		0xA78F0983, 0x1F336EE6, 0x0D86C108, 0xB53AA66D,
+		0xBD40E1A4, 0x05FC86C1, 0x1749292F, 0xAFF54E4A,
+		0x322276F3, 0x8A9E1196, 0x982BBE78, 0x2097D91D,
+		0x78F4C94B, 0xC048AE2E, 0xD2FD01C0, 0x6A4166A5,
+		0xF7965E1C, 0x4F2A3979, 0x5D9F9697, 0xE523F1F2,
+		0x4D6B1905, 0xF5D77E60, 0xE762D18E, 0x5FDEB6EB,
+		0xC2098E52, 0x7AB5E937, 0x680046D9, 0xD0BC21BC,
+		0x88DF31EA, 0x3063568F, 0x22D6F961, 0x9A6A9E04,
+		0x07BDA6BD, 0xBF01C1D8, 0xADB46E36, 0x15080953,
+		0x1D724E9A, 0xA5CE29FF, 0xB77B8611, 0x0FC7E174,
+		0x9210D9CD, 0x2AACBEA8, 0x38191146, 0x80A57623,
+		0xD8C66675, 0x607A0110, 0x72CFAEFE, 0xCA73C99B,
+		0x57A4F122, 0xEF189647, 0xFDAD39A9, 0x45115ECC,
+		0x764DEE06, 0xCEF18963, 0xDC44268D, 0x64F841E8,
+		0xF92F7951, 0x41931E34, 0x5326B1DA, 0xEB9AD6BF,
+		0xB3F9C6E9, 0x0B45A18C, 0x19F00E62, 0xA14C6907,
+		0x3C9B51BE, 0x842736DB, 0x96929935, 0x2E2EFE50,
+		0x2654B999, 0x9EE8DEFC, 0x8C5D7112, 0x34E11677,
+		0xA9362ECE, 0x118A49AB, 0x033FE645, 0xBB838120,
+		0xE3E09176, 0x5B5CF613, 0x49E959FD, 0xF1553E98,
+		0x6C820621, 0xD43E6144, 0xC68BCEAA, 0x7E37A9CF,
+		0xD67F4138, 0x6EC3265D, 0x7C7689B3, 0xC4CAEED6,
+		0x591DD66F, 0xE1A1B10A, 0xF3141EE4, 0x4BA87981,
+		0x13CB69D7, 0xAB770EB2, 0xB9C2A15C, 0x017EC639,
+		0x9CA9FE80, 0x241599E5, 0x36A0360B, 0x8E1C516E,
+		0x866616A7, 0x3EDA71C2, 0x2C6FDE2C, 0x94D3B949,
+		0x090481F0, 0xB1B8E695, 0xA30D497B, 0x1BB12E1E,
+		0x43D23E48, 0xFB6E592D, 0xE9DBF6C3, 0x516791A6,
+		0xCCB0A91F, 0x740CCE7A, 0x66B96194, 0xDE0506F1
+	}, {
+		0x00000000, 0x3D6029B0, 0x7AC05360, 0x47A07AD0,
+		0xF580A6C0, 0xC8E08F70, 0x8F40F5A0, 0xB220DC10,
+		0x30704BC1, 0x0D106271, 0x4AB018A1, 0x77D03111,
+		0xC5F0ED01, 0xF890C4B1, 0xBF30BE61, 0x825097D1,
+		0x60E09782, 0x5D80BE32, 0x1A20C4E2, 0x2740ED52,
+		0x95603142, 0xA80018F2, 0xEFA06222, 0xD2C04B92,
+		0x5090DC43, 0x6DF0F5F3, 0x2A508F23, 0x1730A693,
+		0xA5107A83, 0x98705333, 0xDFD029E3, 0xE2B00053,
+		0xC1C12F04, 0xFCA106B4, 0xBB017C64, 0x866155D4,
+		0x344189C4, 0x0921A074, 0x4E81DAA4, 0x73E1F314,
+		0xF1B164C5, 0xCCD14D75, 0x8B7137A5, 0xB6111E15,
+		0x0431C205, 0x3951EBB5, 0x7EF19165, 0x4391B8D5,
+		0xA121B886, 0x9C419136, 0xDBE1EBE6, 0xE681C256,
+		0x54A11E46, 0x69C137F6, 0x2E614D26, 0x13016496,
+		0x9151F347, 0xAC31DAF7, 0xEB91A027, 0xD6F18997,
+		0x64D15587, 0x59B17C37, 0x1E1106E7, 0x23712F57,
+		0x58F35849, 0x659371F9, 0x22330B29, 0x1F532299,
+		0xAD73FE89, 0x9013D739, 0xD7B3ADE9, 0xEAD38459,
+		0x68831388, 0x55E33A38, 0x124340E8, 0x2F236958,
+		0x9D03B548, 0xA0639CF8, 0xE7C3E628, 0xDAA3CF98,
+		0x3813CFCB, 0x0573E67B, 0x42D39CAB, 0x7FB3B51B,
+		0xCD93690B, 0xF0F340BB, 0xB7533A6B, 0x8A3313DB,
+		0x0863840A, 0x3503ADBA, 0x72A3D76A, 0x4FC3FEDA,
+		0xFDE322CA, 0xC0830B7A, 0x872371AA, 0xBA43581A,
+		0x9932774D, 0xA4525EFD, 0xE3F2242D, 0xDE920D9D,
+		0x6CB2D18D, 0x51D2F83D, 0x167282ED, 0x2B12AB5D,
+		0xA9423C8C, 0x9422153C, 0xD3826FEC, 0xEEE2465C,
+		0x5CC29A4C, 0x61A2B3FC, 0x2602C92C, 0x1B62E09C,
+		0xF9D2E0CF, 0xC4B2C97F, 0x8312B3AF, 0xBE729A1F,
+		0x0C52460F, 0x31326FBF, 0x7692156F, 0x4BF23CDF,
+		0xC9A2AB0E, 0xF4C282BE, 0xB362F86E, 0x8E02D1DE,
+		0x3C220DCE, 0x0142247E, 0x46E25EAE, 0x7B82771E,
+		0xB1E6B092, 0x8C869922, 0xCB26E3F2, 0xF646CA42,
+		0x44661652, 0x79063FE2, 0x3EA64532, 0x03C66C82,
+		0x8196FB53, 0xBCF6D2E3, 0xFB56A833, 0xC6368183,
+		0x74165D93, 0x49767423, 0x0ED60EF3, 0x33B62743,
+		0xD1062710, 0xEC660EA0, 0xABC67470, 0x96A65DC0,
+		0x248681D0, 0x19E6A860, 0x5E46D2B0, 0x6326FB00,
+		0xE1766CD1, 0xDC164561, 0x9BB63FB1, 0xA6D61601,
+		0x14F6CA11, 0x2996E3A1, 0x6E369971, 0x5356B0C1,
+		0x70279F96, 0x4D47B626, 0x0AE7CCF6, 0x3787E546,
+		0x85A73956, 0xB8C710E6, 0xFF676A36, 0xC2074386,
+		0x4057D457, 0x7D37FDE7, 0x3A978737, 0x07F7AE87,
+		0xB5D77297, 0x88B75B27, 0xCF1721F7, 0xF2770847,
+		0x10C70814, 0x2DA721A4, 0x6A075B74, 0x576772C4,
+		0xE547AED4, 0xD8278764, 0x9F87FDB4, 0xA2E7D404,
+		0x20B743D5, 0x1DD76A65, 0x5A7710B5, 0x67173905,
+		0xD537E515, 0xE857CCA5, 0xAFF7B675, 0x92979FC5,
+		0xE915E8DB, 0xD475C16B, 0x93D5BBBB, 0xAEB5920B,
+		0x1C954E1B, 0x21F567AB, 0x66551D7B, 0x5B3534CB,
+		0xD965A31A, 0xE4058AAA, 0xA3A5F07A, 0x9EC5D9CA,
+		0x2CE505DA, 0x11852C6A, 0x562556BA, 0x6B457F0A,
+		0x89F57F59, 0xB49556E9, 0xF3352C39, 0xCE550589,
+		0x7C75D999, 0x4115F029, 0x06B58AF9, 0x3BD5A349,
+		0xB9853498, 0x84E51D28, 0xC34567F8, 0xFE254E48,
+		0x4C059258, 0x7165BBE8, 0x36C5C138, 0x0BA5E888,
+		0x28D4C7DF, 0x15B4EE6F, 0x521494BF, 0x6F74BD0F,
+		0xDD54611F, 0xE03448AF, 0xA794327F, 0x9AF41BCF,
+		0x18A48C1E, 0x25C4A5AE, 0x6264DF7E, 0x5F04F6CE,
+		0xED242ADE, 0xD044036E, 0x97E479BE, 0xAA84500E,
+		0x4834505D, 0x755479ED, 0x32F4033D, 0x0F942A8D,
+		0xBDB4F69D, 0x80D4DF2D, 0xC774A5FD, 0xFA148C4D,
+		0x78441B9C, 0x4524322C, 0x028448FC, 0x3FE4614C,
+		0x8DC4BD5C, 0xB0A494EC, 0xF704EE3C, 0xCA64C78C
+	}, {
+		0x00000000, 0xCB5CD3A5, 0x4DC8A10B, 0x869472AE,
+		0x9B914216, 0x50CD91B3, 0xD659E31D, 0x1D0530B8,
+		0xEC53826D, 0x270F51C8, 0xA19B2366, 0x6AC7F0C3,
+		0x77C2C07B, 0xBC9E13DE, 0x3A0A6170, 0xF156B2D5,
+		0x03D6029B, 0xC88AD13E, 0x4E1EA390, 0x85427035,
+		0x9847408D, 0x531B9328, 0xD58FE186, 0x1ED33223,
+		0xEF8580F6, 0x24D95353, 0xA24D21FD, 0x6911F258,
+		0x7414C2E0, 0xBF481145, 0x39DC63EB, 0xF280B04E,
+		0x07AC0536, 0xCCF0D693, 0x4A64A43D, 0x81387798,
+		0x9C3D4720, 0x57619485, 0xD1F5E62B, 0x1AA9358E,
+		0xEBFF875B, 0x20A354FE, 0xA6372650, 0x6D6BF5F5,
+		0x706EC54D, 0xBB3216E8, 0x3DA66446, 0xF6FAB7E3,
+		0x047A07AD, 0xCF26D408, 0x49B2A6A6, 0x82EE7503,
+		0x9FEB45BB, 0x54B7961E, 0xD223E4B0, 0x197F3715,
+		0xE82985C0, 0x23755665, 0xA5E124CB, 0x6EBDF76E,
+		0x73B8C7D6, 0xB8E41473, 0x3E7066DD, 0xF52CB578,
+		0x0F580A6C, 0xC404D9C9, 0x4290AB67, 0x89CC78C2,
+		0x94C9487A, 0x5F959BDF, 0xD901E971, 0x125D3AD4,
+		0xE30B8801, 0x28575BA4, 0xAEC3290A, 0x659FFAAF,
+		0x789ACA17, 0xB3C619B2, 0x35526B1C, 0xFE0EB8B9,
+		0x0C8E08F7, 0xC7D2DB52, 0x4146A9FC, 0x8A1A7A59,
+		0x971F4AE1, 0x5C439944, 0xDAD7EBEA, 0x118B384F,
+		0xE0DD8A9A, 0x2B81593F, 0xAD152B91, 0x6649F834,
+		0x7B4CC88C, 0xB0101B29, 0x36846987, 0xFDD8BA22,
+		0x08F40F5A, 0xC3A8DCFF, 0x453CAE51, 0x8E607DF4,
+		0x93654D4C, 0x58399EE9, 0xDEADEC47, 0x15F13FE2,
+		0xE4A78D37, 0x2FFB5E92, 0xA96F2C3C, 0x6233FF99,
+		0x7F36CF21, 0xB46A1C84, 0x32FE6E2A, 0xF9A2BD8F,
+		0x0B220DC1, 0xC07EDE64, 0x46EAACCA, 0x8DB67F6F,
+		0x90B34FD7, 0x5BEF9C72, 0xDD7BEEDC, 0x16273D79,
+		0xE7718FAC, 0x2C2D5C09, 0xAAB92EA7, 0x61E5FD02,
+		0x7CE0CDBA, 0xB7BC1E1F, 0x31286CB1, 0xFA74BF14,
+		0x1EB014D8, 0xD5ECC77D, 0x5378B5D3, 0x98246676,
+		0x852156CE, 0x4E7D856B, 0xC8E9F7C5, 0x03B52460,
+		0xF2E396B5, 0x39BF4510, 0xBF2B37BE, 0x7477E41B,
+		0x6972D4A3, 0xA22E0706, 0x24BA75A8, 0xEFE6A60D,
+		0x1D661643, 0xD63AC5E6, 0x50AEB748, 0x9BF264ED,
+		0x86F75455, 0x4DAB87F0, 0xCB3FF55E, 0x006326FB,
+		0xF135942E, 0x3A69478B, 0xBCFD3525, 0x77A1E680,
+		0x6AA4D638, 0xA1F8059D, 0x276C7733, 0xEC30A496,
+		0x191C11EE, 0xD240C24B, 0x54D4B0E5, 0x9F886340,
+		0x828D53F8, 0x49D1805D, 0xCF45F2F3, 0x04192156,
+		0xF54F9383, 0x3E134026, 0xB8873288, 0x73DBE12D,
+		0x6EDED195, 0xA5820230, 0x2316709E, 0xE84AA33B,
+		0x1ACA1375, 0xD196C0D0, 0x5702B27E, 0x9C5E61DB,
+		0x815B5163, 0x4A0782C6, 0xCC93F068, 0x07CF23CD,
+		0xF6999118, 0x3DC542BD, 0xBB513013, 0x700DE3B6,
+		0x6D08D30E, 0xA65400AB, 0x20C07205, 0xEB9CA1A0,
+		0x11E81EB4, 0xDAB4CD11, 0x5C20BFBF, 0x977C6C1A,
+		0x8A795CA2, 0x41258F07, 0xC7B1FDA9, 0x0CED2E0C,
+		0xFDBB9CD9, 0x36E74F7C, 0xB0733DD2, 0x7B2FEE77,
+		0x662ADECF, 0xAD760D6A, 0x2BE27FC4, 0xE0BEAC61,
+		0x123E1C2F, 0xD962CF8A, 0x5FF6BD24, 0x94AA6E81,
+		0x89AF5E39, 0x42F38D9C, 0xC467FF32, 0x0F3B2C97,
+		0xFE6D9E42, 0x35314DE7, 0xB3A53F49, 0x78F9ECEC,
+		0x65FCDC54, 0xAEA00FF1, 0x28347D5F, 0xE368AEFA,
+		0x16441B82, 0xDD18C827, 0x5B8CBA89, 0x90D0692C,
+		0x8DD55994, 0x46898A31, 0xC01DF89F, 0x0B412B3A,
+		0xFA1799EF, 0x314B4A4A, 0xB7DF38E4, 0x7C83EB41,
+		0x6186DBF9, 0xAADA085C, 0x2C4E7AF2, 0xE712A957,
+		0x15921919, 0xDECECABC, 0x585AB812, 0x93066BB7,
+		0x8E035B0F, 0x455F88AA, 0xC3CBFA04, 0x089729A1,
+		0xF9C19B74, 0x329D48D1, 0xB4093A7F, 0x7F55E9DA,
+		0x6250D962, 0xA90C0AC7, 0x2F987869, 0xE4C4ABCC
+	}, {
+		0x00000000, 0xA6770BB4, 0x979F1129, 0x31E81A9D,
+		0xF44F2413, 0x52382FA7, 0x63D0353A, 0xC5A73E8E,
+		0x33EF4E67, 0x959845D3, 0xA4705F4E, 0x020754FA,
+		0xC7A06A74, 0x61D761C0, 0x503F7B5D, 0xF64870E9,
+		0x67DE9CCE, 0xC1A9977A, 0xF0418DE7, 0x56368653,
+		0x9391B8DD, 0x35E6B369, 0x040EA9F4, 0xA279A240,
+		0x5431D2A9, 0xF246D91D, 0xC3AEC380, 0x65D9C834,
+		0xA07EF6BA, 0x0609FD0E, 0x37E1E793, 0x9196EC27,
+		0xCFBD399C, 0x69CA3228, 0x582228B5, 0xFE552301,
+		0x3BF21D8F, 0x9D85163B, 0xAC6D0CA6, 0x0A1A0712,
+		0xFC5277FB, 0x5A257C4F, 0x6BCD66D2, 0xCDBA6D66,
+		0x081D53E8, 0xAE6A585C, 0x9F8242C1, 0x39F54975,
+		0xA863A552, 0x0E14AEE6, 0x3FFCB47B, 0x998BBFCF,
+		0x5C2C8141, 0xFA5B8AF5, 0xCBB39068, 0x6DC49BDC,
+		0x9B8CEB35, 0x3DFBE081, 0x0C13FA1C, 0xAA64F1A8,
+		0x6FC3CF26, 0xC9B4C492, 0xF85CDE0F, 0x5E2BD5BB,
+		0x440B7579, 0xE27C7ECD, 0xD3946450, 0x75E36FE4,
+		0xB044516A, 0x16335ADE, 0x27DB4043, 0x81AC4BF7,
+		0x77E43B1E, 0xD19330AA, 0xE07B2A37, 0x460C2183,
+		0x83AB1F0D, 0x25DC14B9, 0x14340E24, 0xB2430590,
+		0x23D5E9B7, 0x85A2E203, 0xB44AF89E, 0x123DF32A,
+		0xD79ACDA4, 0x71EDC610, 0x4005DC8D, 0xE672D739,
+		0x103AA7D0, 0xB64DAC64, 0x87A5B6F9, 0x21D2BD4D,
+		0xE47583C3, 0x42028877, 0x73EA92EA, 0xD59D995E,
+		0x8BB64CE5, 0x2DC14751, 0x1C295DCC, 0xBA5E5678,
+		0x7FF968F6, 0xD98E6342, 0xE86679DF, 0x4E11726B,
+		0xB8590282, 0x1E2E0936, 0x2FC613AB, 0x89B1181F,
+		0x4C162691, 0xEA612D25, 0xDB8937B8, 0x7DFE3C0C,
+		0xEC68D02B, 0x4A1FDB9F, 0x7BF7C102, 0xDD80CAB6,
+		0x1827F438, 0xBE50FF8C, 0x8FB8E511, 0x29CFEEA5,
+		0xDF879E4C, 0x79F095F8, 0x48188F65, 0xEE6F84D1,
+		0x2BC8BA5F, 0x8DBFB1EB, 0xBC57AB76, 0x1A20A0C2,
+		0x8816EAF2, 0x2E61E146, 0x1F89FBDB, 0xB9FEF06F,
+		0x7C59CEE1, 0xDA2EC555, 0xEBC6DFC8, 0x4DB1D47C,
+		0xBBF9A495, 0x1D8EAF21, 0x2C66B5BC, 0x8A11BE08,
+		0x4FB68086, 0xE9C18B32, 0xD82991AF, 0x7E5E9A1B,
+		0xEFC8763C, 0x49BF7D88, 0x78576715, 0xDE206CA1,
+		0x1B87522F, 0xBDF0599B, 0x8C184306, 0x2A6F48B2,
+		0xDC27385B, 0x7A5033EF, 0x4BB82972, 0xEDCF22C6,
+		0x28681C48, 0x8E1F17FC, 0xBFF70D61, 0x198006D5,
+		0x47ABD36E, 0xE1DCD8DA, 0xD034C247, 0x7643C9F3,
+		0xB3E4F77D, 0x1593FCC9, 0x247BE654, 0x820CEDE0,
+		0x74449D09, 0xD23396BD, 0xE3DB8C20, 0x45AC8794,
+		0x800BB91A, 0x267CB2AE, 0x1794A833, 0xB1E3A387,
+		0x20754FA0, 0x86024414, 0xB7EA5E89, 0x119D553D,
+		0xD43A6BB3, 0x724D6007, 0x43A57A9A, 0xE5D2712E,
+		0x139A01C7, 0xB5ED0A73, 0x840510EE, 0x22721B5A,
+		0xE7D525D4, 0x41A22E60, 0x704A34FD, 0xD63D3F49,
+		0xCC1D9F8B, 0x6A6A943F, 0x5B828EA2, 0xFDF58516,
+		0x3852BB98, 0x9E25B02C, 0xAFCDAAB1, 0x09BAA105,
+		0xFFF2D1EC, 0x5985DA58, 0x686DC0C5, 0xCE1ACB71,
+		0x0BBDF5FF, 0xADCAFE4B, 0x9C22E4D6, 0x3A55EF62,
+		0xABC30345, 0x0DB408F1, 0x3C5C126C, 0x9A2B19D8,
+		0x5F8C2756, 0xF9FB2CE2, 0xC813367F, 0x6E643DCB,
+		0x982C4D22, 0x3E5B4696, 0x0FB35C0B, 0xA9C457BF,
+		0x6C636931, 0xCA146285, 0xFBFC7818, 0x5D8B73AC,
+		0x03A0A617, 0xA5D7ADA3, 0x943FB73E, 0x3248BC8A,
+		0xF7EF8204, 0x519889B0, 0x6070932D, 0xC6079899,
+		0x304FE870, 0x9638E3C4, 0xA7D0F959, 0x01A7F2ED,
+		0xC400CC63, 0x6277C7D7, 0x539FDD4A, 0xF5E8D6FE,
+		0x647E3AD9, 0xC209316D, 0xF3E12BF0, 0x55962044,
+		0x90311ECA, 0x3646157E, 0x07AE0FE3, 0xA1D90457,
+		0x579174BE, 0xF1E67F0A, 0xC00E6597, 0x66796E23,
+		0xA3DE50AD, 0x05A95B19, 0x34414184, 0x92364A30
+	}, {
+		0x00000000, 0xCCAA009E, 0x4225077D, 0x8E8F07E3,
+		0x844A0EFA, 0x48E00E64, 0xC66F0987, 0x0AC50919,
+		0xD3E51BB5, 0x1F4F1B2B, 0x91C01CC8, 0x5D6A1C56,
+		0x57AF154F, 0x9B0515D1, 0x158A1232, 0xD92012AC,
+		0x7CBB312B, 0xB01131B5, 0x3E9E3656, 0xF23436C8,
+		0xF8F13FD1, 0x345B3F4F, 0xBAD438AC, 0x767E3832,
+		0xAF5E2A9E, 0x63F42A00, 0xED7B2DE3, 0x21D12D7D,
+		0x2B142464, 0xE7BE24FA, 0x69312319, 0xA59B2387,
+		0xF9766256, 0x35DC62C8, 0xBB53652B, 0x77F965B5,
+		0x7D3C6CAC, 0xB1966C32, 0x3F196BD1, 0xF3B36B4F,
+		0x2A9379E3, 0xE639797D, 0x68B67E9E, 0xA41C7E00,
+		0xAED97719, 0x62737787, 0xECFC7064, 0x205670FA,
+		0x85CD537D, 0x496753E3, 0xC7E85400, 0x0B42549E,
+		0x01875D87, 0xCD2D5D19, 0x43A25AFA, 0x8F085A64,
+		0x562848C8, 0x9A824856, 0x140D4FB5, 0xD8A74F2B,
+		0xD2624632, 0x1EC846AC, 0x9047414F, 0x5CED41D1,
+		0x299DC2ED, 0xE537C273, 0x6BB8C590, 0xA712C50E,
+		0xADD7CC17, 0x617DCC89, 0xEFF2CB6A, 0x2358CBF4,
+		0xFA78D958, 0x36D2D9C6, 0xB85DDE25, 0x74F7DEBB,
+		0x7E32D7A2, 0xB298D73C, 0x3C17D0DF, 0xF0BDD041,
+		0x5526F3C6, 0x998CF358, 0x1703F4BB, 0xDBA9F425,
+		0xD16CFD3C, 0x1DC6FDA2, 0x9349FA41, 0x5FE3FADF,
+		0x86C3E873, 0x4A69E8ED, 0xC4E6EF0E, 0x084CEF90,
+		0x0289E689, 0xCE23E617, 0x40ACE1F4, 0x8C06E16A,
+		0xD0EBA0BB, 0x1C41A025, 0x92CEA7C6, 0x5E64A758,
+		0x54A1AE41, 0x980BAEDF, 0x1684A93C, 0xDA2EA9A2,
+		0x030EBB0E, 0xCFA4BB90, 0x412BBC73, 0x8D81BCED,
+		0x8744B5F4, 0x4BEEB56A, 0xC561B289, 0x09CBB217,
+		0xAC509190, 0x60FA910E, 0xEE7596ED, 0x22DF9673,
+		0x281A9F6A, 0xE4B09FF4, 0x6A3F9817, 0xA6959889,
+		0x7FB58A25, 0xB31F8ABB, 0x3D908D58, 0xF13A8DC6,
+		0xFBFF84DF, 0x37558441, 0xB9DA83A2, 0x7570833C,
+		0x533B85DA, 0x9F918544, 0x111E82A7, 0xDDB48239,
+		0xD7718B20, 0x1BDB8BBE, 0x95548C5D, 0x59FE8CC3,
+		0x80DE9E6F, 0x4C749EF1, 0xC2FB9912, 0x0E51998C,
+		0x04949095, 0xC83E900B, 0x46B197E8, 0x8A1B9776,
+		0x2F80B4F1, 0xE32AB46F, 0x6DA5B38C, 0xA10FB312,
+		0xABCABA0B, 0x6760BA95, 0xE9EFBD76, 0x2545BDE8,
+		0xFC65AF44, 0x30CFAFDA, 0xBE40A839, 0x72EAA8A7,
+		0x782FA1BE, 0xB485A120, 0x3A0AA6C3, 0xF6A0A65D,
+		0xAA4DE78C, 0x66E7E712, 0xE868E0F1, 0x24C2E06F,
+		0x2E07E976, 0xE2ADE9E8, 0x6C22EE0B, 0xA088EE95,
+		0x79A8FC39, 0xB502FCA7, 0x3B8DFB44, 0xF727FBDA,
+		0xFDE2F2C3, 0x3148F25D, 0xBFC7F5BE, 0x736DF520,
+		0xD6F6D6A7, 0x1A5CD639, 0x94D3D1DA, 0x5879D144,
+		0x52BCD85D, 0x9E16D8C3, 0x1099DF20, 0xDC33DFBE,
+		0x0513CD12, 0xC9B9CD8C, 0x4736CA6F, 0x8B9CCAF1,
+		0x8159C3E8, 0x4DF3C376, 0xC37CC495, 0x0FD6C40B,
+		0x7AA64737, 0xB60C47A9, 0x3883404A, 0xF42940D4,
+		0xFEEC49CD, 0x32464953, 0xBCC94EB0, 0x70634E2E,
+		0xA9435C82, 0x65E95C1C, 0xEB665BFF, 0x27CC5B61,
+		0x2D095278, 0xE1A352E6, 0x6F2C5505, 0xA386559B,
+		0x061D761C, 0xCAB77682, 0x44387161, 0x889271FF,
+		0x825778E6, 0x4EFD7878, 0xC0727F9B, 0x0CD87F05,
+		0xD5F86DA9, 0x19526D37, 0x97DD6AD4, 0x5B776A4A,
+		0x51B26353, 0x9D1863CD, 0x1397642E, 0xDF3D64B0,
+		0x83D02561, 0x4F7A25FF, 0xC1F5221C, 0x0D5F2282,
+		0x079A2B9B, 0xCB302B05, 0x45BF2CE6, 0x89152C78,
+		0x50353ED4, 0x9C9F3E4A, 0x121039A9, 0xDEBA3937,
+		0xD47F302E, 0x18D530B0, 0x965A3753, 0x5AF037CD,
+		0xFF6B144A, 0x33C114D4, 0xBD4E1337, 0x71E413A9,
+		0x7B211AB0, 0xB78B1A2E, 0x39041DCD, 0xF5AE1D53,
+		0x2C8E0FFF, 0xE0240F61, 0x6EAB0882, 0xA201081C,
+		0xA8C40105, 0x646E019B, 0xEAE10678, 0x264B06E6
+	}
+};
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_tablegen.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_tablegen.c
new file mode 100644
index 00000000000..b8cf459f8e7
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_tablegen.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       crc32_tablegen.c
+/// \brief      Generate crc32_table_le.h and crc32_table_be.h
+///
+/// Compiling: gcc -std=c99 -o crc32_tablegen crc32_tablegen.c
+/// Add -DWORDS_BIGENDIAN to generate big endian table.
+/// Add -DLZ_HASH_TABLE to generate lz_encoder_hash_table.h (little endian).
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include 
+#include "../../common/tuklib_integer.h"
+
+
+static uint32_t crc32_table[8][256];
+
+
+static void
+init_crc32_table(void)
+{
+	static const uint32_t poly32 = UINT32_C(0xEDB88320);
+
+	for (size_t s = 0; s < 8; ++s) {
+		for (size_t b = 0; b < 256; ++b) {
+			uint32_t r = s == 0 ? b : crc32_table[s - 1][b];
+
+			for (size_t i = 0; i < 8; ++i) {
+				if (r & 1)
+					r = (r >> 1) ^ poly32;
+				else
+					r >>= 1;
+			}
+
+			crc32_table[s][b] = r;
+		}
+	}
+
+#ifdef WORDS_BIGENDIAN
+	for (size_t s = 0; s < 8; ++s)
+		for (size_t b = 0; b < 256; ++b)
+			crc32_table[s][b] = byteswap32(crc32_table[s][b]);
+#endif
+
+	return;
+}
+
+
+static void
+print_crc32_table(void)
+{
+	// Split the SPDX string so that it won't accidentally match
+	// when tools search for the string.
+	printf("// SPDX" "-License-Identifier" ": 0BSD\n\n"
+		"// This file has been generated by crc32_tablegen.c.\n\n"
+		"const uint32_t lzma_crc32_table[8][256] = {\n\t{");
+
+	for (size_t s = 0; s < 8; ++s) {
+		for (size_t b = 0; b < 256; ++b) {
+			if ((b % 4) == 0)
+				printf("\n\t\t");
+
+			printf("0x%08" PRIX32, crc32_table[s][b]);
+
+			if (b != 255)
+				printf(",%s", (b+1) % 4 == 0 ? "" : " ");
+		}
+
+		if (s == 7)
+			printf("\n\t}\n};\n");
+		else
+			printf("\n\t}, {");
+	}
+
+	return;
+}
+
+
+static void
+print_lz_table(void)
+{
+	// Split the SPDX string so that it won't accidentally match
+	// when tools search for the string.
+	printf("// SPDX" "-License-Identifier" ": 0BSD\n\n"
+		"// This file has been generated by crc32_tablegen.c.\n\n"
+		"const uint32_t lzma_lz_hash_table[256] = {");
+
+	for (size_t b = 0; b < 256; ++b) {
+		if ((b % 4) == 0)
+			printf("\n\t");
+
+		printf("0x%08" PRIX32, crc32_table[0][b]);
+
+		if (b != 255)
+			printf(",%s", (b+1) % 4 == 0 ? "" : " ");
+	}
+
+	printf("\n};\n");
+
+	return;
+}
+
+
+int
+main(void)
+{
+	init_crc32_table();
+
+#ifdef LZ_HASH_TABLE
+	print_lz_table();
+#else
+	print_crc32_table();
+#endif
+
+	return 0;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_x86.S b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_x86.S
new file mode 100644
index 00000000000..ddc3cee6ea5
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc32_x86.S
@@ -0,0 +1,312 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/*
+ * Speed-optimized CRC32 using slicing-by-eight algorithm
+ *
+ * This uses only i386 instructions, but it is optimized for i686 and later
+ * (including e.g. Pentium II/III/IV, Athlon XP, and Core 2). For i586
+ * (e.g. Pentium), slicing-by-four would be better, and even the C version
+ * of slicing-by-eight built with gcc -march=i586 tends to be a little bit
+ * better than this. Very few probably run this code on i586 or older x86
+ * so this shouldn't be a problem in practice.
+ *
+ * Authors: Igor Pavlov (original version)
+ *          Lasse Collin (AT&T syntax, PIC support, better portability)
+ *
+ * This code needs lzma_crc32_table, which can be created using the
+ * following C code:
+
+uint32_t lzma_crc32_table[8][256];
+
+void
+init_table(void)
+{
+	// IEEE-802.3
+	static const uint32_t poly32 = UINT32_C(0xEDB88320);
+
+	// Castagnoli
+	// static const uint32_t poly32 = UINT32_C(0x82F63B78);
+
+	// Koopman
+	// static const uint32_t poly32 = UINT32_C(0xEB31D82E);
+
+	for (size_t s = 0; s < 8; ++s) {
+		for (size_t b = 0; b < 256; ++b) {
+			uint32_t r = s == 0 ? b : lzma_crc32_table[s - 1][b];
+
+			for (size_t i = 0; i < 8; ++i) {
+				if (r & 1)
+					r = (r >> 1) ^ poly32;
+				else
+					r >>= 1;
+			}
+
+			lzma_crc32_table[s][b] = r;
+		}
+	}
+}
+
+ * The prototype of the CRC32 function:
+ * extern uint32_t lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc);
+ */
+
+/* When Intel CET is enabled, include  in assembly code to mark
+   Intel CET support.  */
+#ifdef __CET__
+# include 
+#else
+# define _CET_ENDBR
+#endif
+
+/*
+ * On some systems, the functions need to be prefixed. The prefix is
+ * usually an underscore.
+ */
+#ifndef __USER_LABEL_PREFIX__
+#	define __USER_LABEL_PREFIX__
+#endif
+#define MAKE_SYM_CAT(prefix, sym) prefix ## sym
+#define MAKE_SYM(prefix, sym) MAKE_SYM_CAT(prefix, sym)
+#define LZMA_CRC32 MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc32)
+#define LZMA_CRC32_TABLE MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc32_table)
+
+/*
+ * Solaris assembler doesn't have .p2align, and Darwin uses .align
+ * differently than GNU/Linux and Solaris.
+ */
+#if defined(__APPLE__) || defined(__MSDOS__)
+#	define ALIGN(pow2, abs) .align pow2
+#else
+#	define ALIGN(pow2, abs) .align abs
+#endif
+
+	.text
+	.globl	LZMA_CRC32
+
+#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) \
+		&& !defined(__MSDOS__)
+	.type	LZMA_CRC32, @function
+#endif
+
+	ALIGN(4, 16)
+LZMA_CRC32:
+	_CET_ENDBR
+	/*
+	 * Register usage:
+	 * %eax crc
+	 * %esi buf
+	 * %edi size or buf + size
+	 * %ebx lzma_crc32_table
+	 * %ebp Table index
+	 * %ecx Temporary
+	 * %edx Temporary
+	 */
+	pushl	%ebx
+	pushl	%esi
+	pushl	%edi
+	pushl	%ebp
+	movl	0x14(%esp), %esi /* buf */
+	movl	0x18(%esp), %edi /* size */
+	movl	0x1C(%esp), %eax /* crc */
+
+	/*
+	 * Store the address of lzma_crc32_table to %ebx. This is needed to
+	 * get position-independent code (PIC).
+	 *
+	 * The PIC macro is defined by libtool, while __PIC__ is defined
+	 * by GCC but only on some systems. Testing for both makes it simpler
+	 * to test this code without libtool, and keeps the code working also
+	 * when built with libtool but using something else than GCC.
+	 *
+	 * I understood that libtool may define PIC on Windows even though
+	 * the code in Windows DLLs is not PIC in sense that it is in ELF
+	 * binaries, so we need a separate check to always use the non-PIC
+	 * code on Windows.
+	 */
+#if (!defined(PIC) && !defined(__PIC__)) \
+		|| (defined(_WIN32) || defined(__CYGWIN__))
+	/* Not PIC */
+	movl	$ LZMA_CRC32_TABLE, %ebx
+#elif defined(__APPLE__)
+	/* Mach-O */
+	call	.L_get_pc
+.L_pic:
+	leal	.L_lzma_crc32_table$non_lazy_ptr-.L_pic(%ebx), %ebx
+	movl	(%ebx), %ebx
+#else
+	/* ELF */
+	call	.L_get_pc
+	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
+	movl	LZMA_CRC32_TABLE@GOT(%ebx), %ebx
+#endif
+
+	/* Complement the initial value. */
+	notl	%eax
+
+	ALIGN(4, 16)
+.L_align:
+	/*
+	 * Check if there is enough input to use slicing-by-eight.
+	 * We need 16 bytes, because the loop pre-reads eight bytes.
+	 */
+	cmpl	$16, %edi
+	jb	.L_rest
+
+	/* Check if we have reached alignment of eight bytes. */
+	testl	$7, %esi
+	jz	.L_slice
+
+	/* Calculate CRC of the next input byte. */
+	movzbl	(%esi), %ebp
+	incl	%esi
+	movzbl	%al, %ecx
+	xorl	%ecx, %ebp
+	shrl	$8, %eax
+	xorl	(%ebx, %ebp, 4), %eax
+	decl	%edi
+	jmp	.L_align
+
+	ALIGN(2, 4)
+.L_slice:
+	/*
+	 * If we get here, there's at least 16 bytes of aligned input
+	 * available. Make %edi multiple of eight bytes. Store the possible
+	 * remainder over the "size" variable in the argument stack.
+	 */
+	movl	%edi, 0x18(%esp)
+	andl	$-8, %edi
+	subl	%edi, 0x18(%esp)
+
+	/*
+	 * Let %edi be buf + size - 8 while running the main loop. This way
+	 * we can compare for equality to determine when exit the loop.
+	 */
+	addl	%esi, %edi
+	subl	$8, %edi
+
+	/* Read in the first eight aligned bytes. */
+	xorl	(%esi), %eax
+	movl	4(%esi), %ecx
+	movzbl	%cl, %ebp
+
+.L_loop:
+	movl	0x0C00(%ebx, %ebp, 4), %edx
+	movzbl	%ch, %ebp
+	xorl	0x0800(%ebx, %ebp, 4), %edx
+	shrl	$16, %ecx
+	xorl	8(%esi), %edx
+	movzbl	%cl, %ebp
+	xorl	0x0400(%ebx, %ebp, 4), %edx
+	movzbl	%ch, %ebp
+	xorl	(%ebx, %ebp, 4), %edx
+	movzbl	%al, %ebp
+
+	/*
+	 * Read the next four bytes, for which the CRC is calculated
+	 * on the next iteration of the loop.
+	 */
+	movl	12(%esi), %ecx
+
+	xorl	0x1C00(%ebx, %ebp, 4), %edx
+	movzbl	%ah, %ebp
+	shrl	$16, %eax
+	xorl	0x1800(%ebx, %ebp, 4), %edx
+	movzbl	%ah, %ebp
+	movzbl	%al, %eax
+	movl	0x1400(%ebx, %eax, 4), %eax
+	addl	$8, %esi
+	xorl	%edx, %eax
+	xorl	0x1000(%ebx, %ebp, 4), %eax
+
+	/* Check for end of aligned input. */
+	cmpl	%edi, %esi
+	movzbl	%cl, %ebp
+	jne	.L_loop
+
+	/*
+	 * Process the remaining eight bytes, which we have already
+	 * copied to %ecx and %edx.
+	 */
+	movl	0x0C00(%ebx, %ebp, 4), %edx
+	movzbl	%ch, %ebp
+	xorl	0x0800(%ebx, %ebp, 4), %edx
+	shrl	$16, %ecx
+	movzbl	%cl, %ebp
+	xorl	0x0400(%ebx, %ebp, 4), %edx
+	movzbl	%ch, %ebp
+	xorl	(%ebx, %ebp, 4), %edx
+	movzbl	%al, %ebp
+
+	xorl	0x1C00(%ebx, %ebp, 4), %edx
+	movzbl	%ah, %ebp
+	shrl	$16, %eax
+	xorl	0x1800(%ebx, %ebp, 4), %edx
+	movzbl	%ah, %ebp
+	movzbl	%al, %eax
+	movl	0x1400(%ebx, %eax, 4), %eax
+	addl	$8, %esi
+	xorl	%edx, %eax
+	xorl	0x1000(%ebx, %ebp, 4), %eax
+
+	/* Copy the number of remaining bytes to %edi. */
+	movl	0x18(%esp), %edi
+
+.L_rest:
+	/* Check for end of input. */
+	testl	%edi, %edi
+	jz	.L_return
+
+	/* Calculate CRC of the next input byte. */
+	movzbl	(%esi), %ebp
+	incl	%esi
+	movzbl	%al, %ecx
+	xorl	%ecx, %ebp
+	shrl	$8, %eax
+	xorl	(%ebx, %ebp, 4), %eax
+	decl	%edi
+	jmp	.L_rest
+
+.L_return:
+	/* Complement the final value. */
+	notl	%eax
+
+	popl	%ebp
+	popl	%edi
+	popl	%esi
+	popl	%ebx
+	ret
+
+#if defined(PIC) || defined(__PIC__)
+	ALIGN(4, 16)
+.L_get_pc:
+	movl	(%esp), %ebx
+	ret
+#endif
+
+#if defined(__APPLE__) && (defined(PIC) || defined(__PIC__))
+	/* Mach-O PIC */
+	.section __IMPORT,__pointers,non_lazy_symbol_pointers
+.L_lzma_crc32_table$non_lazy_ptr:
+	.indirect_symbol LZMA_CRC32_TABLE
+	.long 0
+
+#elif defined(_WIN32) || defined(__CYGWIN__)
+#	ifdef DLL_EXPORT
+	/* This is equivalent of __declspec(dllexport). */
+	.section .drectve
+	.ascii " -export:lzma_crc32"
+#	endif
+
+#elif !defined(__MSDOS__)
+	/* ELF */
+	.size	LZMA_CRC32, .-LZMA_CRC32
+#endif
+
+/*
+ * This is needed to support non-executable stack. It's ugly to
+ * use __FreeBSD__ and __linux__ here, but I don't know a way to detect when
+ * we are using GNU assembler.
+ */
+#if defined(__ELF__) && (defined(__FreeBSD__) || defined(__linux__))
+	.section	.note.GNU-stack,"",@progbits
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_fast.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_fast.c
new file mode 100644
index 00000000000..0ce83fe4ad3
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_fast.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       crc64.c
+/// \brief      CRC64 calculation
+//
+//  Authors:    Lasse Collin
+//              Ilya Kurdyukov
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "check.h"
+#include "crc_common.h"
+
+#if defined(CRC_X86_CLMUL)
+#	define BUILDING_CRC64_CLMUL
+#	include "crc_x86_clmul.h"
+#endif
+
+
+#ifdef CRC64_GENERIC
+
+/////////////////////////////////
+// Generic slice-by-four CRC64 //
+/////////////////////////////////
+
+#ifdef WORDS_BIGENDIAN
+#	define A1(x) ((x) >> 56)
+#else
+#	define A1 A
+#endif
+
+
+// See the comments in crc32_fast.c. They aren't duplicated here.
+static uint64_t
+crc64_generic(const uint8_t *buf, size_t size, uint64_t crc)
+{
+	crc = ~crc;
+
+#ifdef WORDS_BIGENDIAN
+	crc = byteswap64(crc);
+#endif
+
+	if (size > 4) {
+		while ((uintptr_t)(buf) & 3) {
+			crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc);
+			--size;
+		}
+
+		const uint8_t *const limit = buf + (size & ~(size_t)(3));
+		size &= (size_t)(3);
+
+		while (buf < limit) {
+#ifdef WORDS_BIGENDIAN
+			const uint32_t tmp = (uint32_t)(crc >> 32)
+					^ aligned_read32ne(buf);
+#else
+			const uint32_t tmp = (uint32_t)crc
+					^ aligned_read32ne(buf);
+#endif
+			buf += 4;
+
+			crc = lzma_crc64_table[3][A(tmp)]
+			    ^ lzma_crc64_table[2][B(tmp)]
+			    ^ S32(crc)
+			    ^ lzma_crc64_table[1][C(tmp)]
+			    ^ lzma_crc64_table[0][D(tmp)];
+		}
+	}
+
+	while (size-- != 0)
+		crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc);
+
+#ifdef WORDS_BIGENDIAN
+	crc = byteswap64(crc);
+#endif
+
+	return ~crc;
+}
+#endif
+
+
+#if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED)
+
+//////////////////////////
+// Function dispatching //
+//////////////////////////
+
+// If both the generic and arch-optimized implementations are usable, then
+// the function that is used is selected at runtime. See crc32_fast.c.
+
+typedef uint64_t (*crc64_func_type)(
+		const uint8_t *buf, size_t size, uint64_t crc);
+
+static crc64_func_type
+crc64_resolve(void)
+{
+	return is_arch_extension_supported()
+			? &crc64_arch_optimized : &crc64_generic;
+}
+
+#ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
+#	define CRC64_SET_FUNC_ATTR __attribute__((__constructor__))
+static crc64_func_type crc64_func;
+#else
+#	define CRC64_SET_FUNC_ATTR
+static uint64_t crc64_dispatch(const uint8_t *buf, size_t size, uint64_t crc);
+static crc64_func_type crc64_func = &crc64_dispatch;
+#endif
+
+
+CRC64_SET_FUNC_ATTR
+static void
+crc64_set_func(void)
+{
+	crc64_func = crc64_resolve();
+	return;
+}
+
+
+#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
+static uint64_t
+crc64_dispatch(const uint8_t *buf, size_t size, uint64_t crc)
+{
+	crc64_set_func();
+	return crc64_func(buf, size, crc);
+}
+#endif
+#endif
+
+
+extern LZMA_API(uint64_t)
+lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc)
+{
+#if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED)
+
+#ifdef CRC_USE_GENERIC_FOR_SMALL_INPUTS
+	if (size <= 16)
+		return crc64_generic(buf, size, crc);
+#endif
+	return crc64_func(buf, size, crc);
+
+#elif defined(CRC64_ARCH_OPTIMIZED)
+	// If arch-optimized version is used unconditionally without runtime
+	// CPU detection then omitting the generic version and its 8 KiB
+	// lookup table makes the library smaller.
+	//
+	// FIXME: Lookup table isn't currently omitted on 32-bit x86,
+	// see crc64_table.c.
+	return crc64_arch_optimized(buf, size, crc);
+
+#else
+	return crc64_generic(buf, size, crc);
+#endif
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_small.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_small.c
new file mode 100644
index 00000000000..ee4ea26f67d
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_small.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       crc64_small.c
+/// \brief      CRC64 calculation (size-optimized)
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "check.h"
+
+
+static uint64_t crc64_table[256];
+
+
+#ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
+__attribute__((__constructor__))
+#endif
+static void
+crc64_init(void)
+{
+	static const uint64_t poly64 = UINT64_C(0xC96C5795D7870F42);
+
+	for (size_t b = 0; b < 256; ++b) {
+		uint64_t r = b;
+		for (size_t i = 0; i < 8; ++i) {
+			if (r & 1)
+				r = (r >> 1) ^ poly64;
+			else
+				r >>= 1;
+		}
+
+		crc64_table[b] = r;
+	}
+
+	return;
+}
+
+
+extern LZMA_API(uint64_t)
+lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc)
+{
+#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
+	mythread_once(crc64_init);
+#endif
+
+	crc = ~crc;
+
+	while (size != 0) {
+		crc = crc64_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
+		--size;
+	}
+
+	return ~crc;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table.c
new file mode 100644
index 00000000000..78e427597ce
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       crc64_table.c
+/// \brief      Precalculated CRC64 table with correct endianness
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+
+// FIXME: Compared to crc_common.h this has to check for __x86_64__ too
+// so that in 32-bit builds crc64_x86.S won't break due to a missing table.
+#if defined(HAVE_USABLE_CLMUL) && ((defined(__x86_64__) && defined(__SSSE3__) \
+			&& defined(__SSE4_1__) && defined(__PCLMUL__)) \
+		|| (defined(__e2k__) && __iset__ >= 6))
+#	define NO_CRC64_TABLE
+#endif
+
+
+#ifdef NO_CRC64_TABLE
+// No table needed. Use a typedef to avoid an empty translation unit.
+typedef void lzma_crc64_dummy;
+
+#else
+// Having the declaration here silences clang -Wmissing-variable-declarations.
+extern const uint64_t lzma_crc64_table[4][256];
+
+#	if defined(WORDS_BIGENDIAN)
+#		include "crc64_table_be.h"
+#	else
+#		include "crc64_table_le.h"
+#	endif
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_be.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_be.h
new file mode 100644
index 00000000000..db76cc70e07
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_be.h
@@ -0,0 +1,523 @@
+// SPDX-License-Identifier: 0BSD
+
+// This file has been generated by crc64_tablegen.c.
+
+const uint64_t lzma_crc64_table[4][256] = {
+	{
+		UINT64_C(0x0000000000000000), UINT64_C(0x6F5FA703BE4C2EB3),
+		UINT64_C(0x5BA040A8573684F4), UINT64_C(0x34FFE7ABE97AAA47),
+		UINT64_C(0x335E8FFF84C3D07B), UINT64_C(0x5C0128FC3A8FFEC8),
+		UINT64_C(0x68FECF57D3F5548F), UINT64_C(0x07A168546DB97A3C),
+		UINT64_C(0x66BC1EFF0987A1F7), UINT64_C(0x09E3B9FCB7CB8F44),
+		UINT64_C(0x3D1C5E575EB12503), UINT64_C(0x5243F954E0FD0BB0),
+		UINT64_C(0x55E291008D44718C), UINT64_C(0x3ABD360333085F3F),
+		UINT64_C(0x0E42D1A8DA72F578), UINT64_C(0x611D76AB643EDBCB),
+		UINT64_C(0x4966335138A19B7D), UINT64_C(0x2639945286EDB5CE),
+		UINT64_C(0x12C673F96F971F89), UINT64_C(0x7D99D4FAD1DB313A),
+		UINT64_C(0x7A38BCAEBC624B06), UINT64_C(0x15671BAD022E65B5),
+		UINT64_C(0x2198FC06EB54CFF2), UINT64_C(0x4EC75B055518E141),
+		UINT64_C(0x2FDA2DAE31263A8A), UINT64_C(0x40858AAD8F6A1439),
+		UINT64_C(0x747A6D066610BE7E), UINT64_C(0x1B25CA05D85C90CD),
+		UINT64_C(0x1C84A251B5E5EAF1), UINT64_C(0x73DB05520BA9C442),
+		UINT64_C(0x4724E2F9E2D36E05), UINT64_C(0x287B45FA5C9F40B6),
+		UINT64_C(0x92CC66A2704237FB), UINT64_C(0xFD93C1A1CE0E1948),
+		UINT64_C(0xC96C260A2774B30F), UINT64_C(0xA633810999389DBC),
+		UINT64_C(0xA192E95DF481E780), UINT64_C(0xCECD4E5E4ACDC933),
+		UINT64_C(0xFA32A9F5A3B76374), UINT64_C(0x956D0EF61DFB4DC7),
+		UINT64_C(0xF470785D79C5960C), UINT64_C(0x9B2FDF5EC789B8BF),
+		UINT64_C(0xAFD038F52EF312F8), UINT64_C(0xC08F9FF690BF3C4B),
+		UINT64_C(0xC72EF7A2FD064677), UINT64_C(0xA87150A1434A68C4),
+		UINT64_C(0x9C8EB70AAA30C283), UINT64_C(0xF3D11009147CEC30),
+		UINT64_C(0xDBAA55F348E3AC86), UINT64_C(0xB4F5F2F0F6AF8235),
+		UINT64_C(0x800A155B1FD52872), UINT64_C(0xEF55B258A19906C1),
+		UINT64_C(0xE8F4DA0CCC207CFD), UINT64_C(0x87AB7D0F726C524E),
+		UINT64_C(0xB3549AA49B16F809), UINT64_C(0xDC0B3DA7255AD6BA),
+		UINT64_C(0xBD164B0C41640D71), UINT64_C(0xD249EC0FFF2823C2),
+		UINT64_C(0xE6B60BA416528985), UINT64_C(0x89E9ACA7A81EA736),
+		UINT64_C(0x8E48C4F3C5A7DD0A), UINT64_C(0xE11763F07BEBF3B9),
+		UINT64_C(0xD5E8845B929159FE), UINT64_C(0xBAB723582CDD774D),
+		UINT64_C(0xA187C3EBCA2BB664), UINT64_C(0xCED864E8746798D7),
+		UINT64_C(0xFA2783439D1D3290), UINT64_C(0x9578244023511C23),
+		UINT64_C(0x92D94C144EE8661F), UINT64_C(0xFD86EB17F0A448AC),
+		UINT64_C(0xC9790CBC19DEE2EB), UINT64_C(0xA626ABBFA792CC58),
+		UINT64_C(0xC73BDD14C3AC1793), UINT64_C(0xA8647A177DE03920),
+		UINT64_C(0x9C9B9DBC949A9367), UINT64_C(0xF3C43ABF2AD6BDD4),
+		UINT64_C(0xF46552EB476FC7E8), UINT64_C(0x9B3AF5E8F923E95B),
+		UINT64_C(0xAFC512431059431C), UINT64_C(0xC09AB540AE156DAF),
+		UINT64_C(0xE8E1F0BAF28A2D19), UINT64_C(0x87BE57B94CC603AA),
+		UINT64_C(0xB341B012A5BCA9ED), UINT64_C(0xDC1E17111BF0875E),
+		UINT64_C(0xDBBF7F457649FD62), UINT64_C(0xB4E0D846C805D3D1),
+		UINT64_C(0x801F3FED217F7996), UINT64_C(0xEF4098EE9F335725),
+		UINT64_C(0x8E5DEE45FB0D8CEE), UINT64_C(0xE10249464541A25D),
+		UINT64_C(0xD5FDAEEDAC3B081A), UINT64_C(0xBAA209EE127726A9),
+		UINT64_C(0xBD0361BA7FCE5C95), UINT64_C(0xD25CC6B9C1827226),
+		UINT64_C(0xE6A3211228F8D861), UINT64_C(0x89FC861196B4F6D2),
+		UINT64_C(0x334BA549BA69819F), UINT64_C(0x5C14024A0425AF2C),
+		UINT64_C(0x68EBE5E1ED5F056B), UINT64_C(0x07B442E253132BD8),
+		UINT64_C(0x00152AB63EAA51E4), UINT64_C(0x6F4A8DB580E67F57),
+		UINT64_C(0x5BB56A1E699CD510), UINT64_C(0x34EACD1DD7D0FBA3),
+		UINT64_C(0x55F7BBB6B3EE2068), UINT64_C(0x3AA81CB50DA20EDB),
+		UINT64_C(0x0E57FB1EE4D8A49C), UINT64_C(0x61085C1D5A948A2F),
+		UINT64_C(0x66A93449372DF013), UINT64_C(0x09F6934A8961DEA0),
+		UINT64_C(0x3D0974E1601B74E7), UINT64_C(0x5256D3E2DE575A54),
+		UINT64_C(0x7A2D961882C81AE2), UINT64_C(0x1572311B3C843451),
+		UINT64_C(0x218DD6B0D5FE9E16), UINT64_C(0x4ED271B36BB2B0A5),
+		UINT64_C(0x497319E7060BCA99), UINT64_C(0x262CBEE4B847E42A),
+		UINT64_C(0x12D3594F513D4E6D), UINT64_C(0x7D8CFE4CEF7160DE),
+		UINT64_C(0x1C9188E78B4FBB15), UINT64_C(0x73CE2FE4350395A6),
+		UINT64_C(0x4731C84FDC793FE1), UINT64_C(0x286E6F4C62351152),
+		UINT64_C(0x2FCF07180F8C6B6E), UINT64_C(0x4090A01BB1C045DD),
+		UINT64_C(0x746F47B058BAEF9A), UINT64_C(0x1B30E0B3E6F6C129),
+		UINT64_C(0x420F87D795576CC9), UINT64_C(0x2D5020D42B1B427A),
+		UINT64_C(0x19AFC77FC261E83D), UINT64_C(0x76F0607C7C2DC68E),
+		UINT64_C(0x715108281194BCB2), UINT64_C(0x1E0EAF2BAFD89201),
+		UINT64_C(0x2AF1488046A23846), UINT64_C(0x45AEEF83F8EE16F5),
+		UINT64_C(0x24B399289CD0CD3E), UINT64_C(0x4BEC3E2B229CE38D),
+		UINT64_C(0x7F13D980CBE649CA), UINT64_C(0x104C7E8375AA6779),
+		UINT64_C(0x17ED16D718131D45), UINT64_C(0x78B2B1D4A65F33F6),
+		UINT64_C(0x4C4D567F4F2599B1), UINT64_C(0x2312F17CF169B702),
+		UINT64_C(0x0B69B486ADF6F7B4), UINT64_C(0x6436138513BAD907),
+		UINT64_C(0x50C9F42EFAC07340), UINT64_C(0x3F96532D448C5DF3),
+		UINT64_C(0x38373B79293527CF), UINT64_C(0x57689C7A9779097C),
+		UINT64_C(0x63977BD17E03A33B), UINT64_C(0x0CC8DCD2C04F8D88),
+		UINT64_C(0x6DD5AA79A4715643), UINT64_C(0x028A0D7A1A3D78F0),
+		UINT64_C(0x3675EAD1F347D2B7), UINT64_C(0x592A4DD24D0BFC04),
+		UINT64_C(0x5E8B258620B28638), UINT64_C(0x31D482859EFEA88B),
+		UINT64_C(0x052B652E778402CC), UINT64_C(0x6A74C22DC9C82C7F),
+		UINT64_C(0xD0C3E175E5155B32), UINT64_C(0xBF9C46765B597581),
+		UINT64_C(0x8B63A1DDB223DFC6), UINT64_C(0xE43C06DE0C6FF175),
+		UINT64_C(0xE39D6E8A61D68B49), UINT64_C(0x8CC2C989DF9AA5FA),
+		UINT64_C(0xB83D2E2236E00FBD), UINT64_C(0xD762892188AC210E),
+		UINT64_C(0xB67FFF8AEC92FAC5), UINT64_C(0xD920588952DED476),
+		UINT64_C(0xEDDFBF22BBA47E31), UINT64_C(0x8280182105E85082),
+		UINT64_C(0x8521707568512ABE), UINT64_C(0xEA7ED776D61D040D),
+		UINT64_C(0xDE8130DD3F67AE4A), UINT64_C(0xB1DE97DE812B80F9),
+		UINT64_C(0x99A5D224DDB4C04F), UINT64_C(0xF6FA752763F8EEFC),
+		UINT64_C(0xC205928C8A8244BB), UINT64_C(0xAD5A358F34CE6A08),
+		UINT64_C(0xAAFB5DDB59771034), UINT64_C(0xC5A4FAD8E73B3E87),
+		UINT64_C(0xF15B1D730E4194C0), UINT64_C(0x9E04BA70B00DBA73),
+		UINT64_C(0xFF19CCDBD43361B8), UINT64_C(0x90466BD86A7F4F0B),
+		UINT64_C(0xA4B98C738305E54C), UINT64_C(0xCBE62B703D49CBFF),
+		UINT64_C(0xCC47432450F0B1C3), UINT64_C(0xA318E427EEBC9F70),
+		UINT64_C(0x97E7038C07C63537), UINT64_C(0xF8B8A48FB98A1B84),
+		UINT64_C(0xE388443C5F7CDAAD), UINT64_C(0x8CD7E33FE130F41E),
+		UINT64_C(0xB8280494084A5E59), UINT64_C(0xD777A397B60670EA),
+		UINT64_C(0xD0D6CBC3DBBF0AD6), UINT64_C(0xBF896CC065F32465),
+		UINT64_C(0x8B768B6B8C898E22), UINT64_C(0xE4292C6832C5A091),
+		UINT64_C(0x85345AC356FB7B5A), UINT64_C(0xEA6BFDC0E8B755E9),
+		UINT64_C(0xDE941A6B01CDFFAE), UINT64_C(0xB1CBBD68BF81D11D),
+		UINT64_C(0xB66AD53CD238AB21), UINT64_C(0xD935723F6C748592),
+		UINT64_C(0xEDCA9594850E2FD5), UINT64_C(0x829532973B420166),
+		UINT64_C(0xAAEE776D67DD41D0), UINT64_C(0xC5B1D06ED9916F63),
+		UINT64_C(0xF14E37C530EBC524), UINT64_C(0x9E1190C68EA7EB97),
+		UINT64_C(0x99B0F892E31E91AB), UINT64_C(0xF6EF5F915D52BF18),
+		UINT64_C(0xC210B83AB428155F), UINT64_C(0xAD4F1F390A643BEC),
+		UINT64_C(0xCC5269926E5AE027), UINT64_C(0xA30DCE91D016CE94),
+		UINT64_C(0x97F2293A396C64D3), UINT64_C(0xF8AD8E3987204A60),
+		UINT64_C(0xFF0CE66DEA99305C), UINT64_C(0x9053416E54D51EEF),
+		UINT64_C(0xA4ACA6C5BDAFB4A8), UINT64_C(0xCBF301C603E39A1B),
+		UINT64_C(0x7144229E2F3EED56), UINT64_C(0x1E1B859D9172C3E5),
+		UINT64_C(0x2AE46236780869A2), UINT64_C(0x45BBC535C6444711),
+		UINT64_C(0x421AAD61ABFD3D2D), UINT64_C(0x2D450A6215B1139E),
+		UINT64_C(0x19BAEDC9FCCBB9D9), UINT64_C(0x76E54ACA4287976A),
+		UINT64_C(0x17F83C6126B94CA1), UINT64_C(0x78A79B6298F56212),
+		UINT64_C(0x4C587CC9718FC855), UINT64_C(0x2307DBCACFC3E6E6),
+		UINT64_C(0x24A6B39EA27A9CDA), UINT64_C(0x4BF9149D1C36B269),
+		UINT64_C(0x7F06F336F54C182E), UINT64_C(0x105954354B00369D),
+		UINT64_C(0x382211CF179F762B), UINT64_C(0x577DB6CCA9D35898),
+		UINT64_C(0x6382516740A9F2DF), UINT64_C(0x0CDDF664FEE5DC6C),
+		UINT64_C(0x0B7C9E30935CA650), UINT64_C(0x642339332D1088E3),
+		UINT64_C(0x50DCDE98C46A22A4), UINT64_C(0x3F83799B7A260C17),
+		UINT64_C(0x5E9E0F301E18D7DC), UINT64_C(0x31C1A833A054F96F),
+		UINT64_C(0x053E4F98492E5328), UINT64_C(0x6A61E89BF7627D9B),
+		UINT64_C(0x6DC080CF9ADB07A7), UINT64_C(0x029F27CC24972914),
+		UINT64_C(0x3660C067CDED8353), UINT64_C(0x593F676473A1ADE0)
+	}, {
+		UINT64_C(0x0000000000000000), UINT64_C(0x0DF1D05C9279E954),
+		UINT64_C(0x1AE2A1B924F3D2A9), UINT64_C(0x171371E5B68A3BFD),
+		UINT64_C(0xB1DA4DDC62497DC1), UINT64_C(0xBC2B9D80F0309495),
+		UINT64_C(0xAB38EC6546BAAF68), UINT64_C(0xA6C93C39D4C3463C),
+		UINT64_C(0xE7AB9517EE3D2210), UINT64_C(0xEA5A454B7C44CB44),
+		UINT64_C(0xFD4934AECACEF0B9), UINT64_C(0xF0B8E4F258B719ED),
+		UINT64_C(0x5671D8CB8C745FD1), UINT64_C(0x5B8008971E0DB685),
+		UINT64_C(0x4C937972A8878D78), UINT64_C(0x4162A92E3AFE642C),
+		UINT64_C(0xCE572B2FDC7B4420), UINT64_C(0xC3A6FB734E02AD74),
+		UINT64_C(0xD4B58A96F8889689), UINT64_C(0xD9445ACA6AF17FDD),
+		UINT64_C(0x7F8D66F3BE3239E1), UINT64_C(0x727CB6AF2C4BD0B5),
+		UINT64_C(0x656FC74A9AC1EB48), UINT64_C(0x689E171608B8021C),
+		UINT64_C(0x29FCBE3832466630), UINT64_C(0x240D6E64A03F8F64),
+		UINT64_C(0x331E1F8116B5B499), UINT64_C(0x3EEFCFDD84CC5DCD),
+		UINT64_C(0x9826F3E4500F1BF1), UINT64_C(0x95D723B8C276F2A5),
+		UINT64_C(0x82C4525D74FCC958), UINT64_C(0x8F358201E685200C),
+		UINT64_C(0x9CAF565EB8F78840), UINT64_C(0x915E86022A8E6114),
+		UINT64_C(0x864DF7E79C045AE9), UINT64_C(0x8BBC27BB0E7DB3BD),
+		UINT64_C(0x2D751B82DABEF581), UINT64_C(0x2084CBDE48C71CD5),
+		UINT64_C(0x3797BA3BFE4D2728), UINT64_C(0x3A666A676C34CE7C),
+		UINT64_C(0x7B04C34956CAAA50), UINT64_C(0x76F51315C4B34304),
+		UINT64_C(0x61E662F0723978F9), UINT64_C(0x6C17B2ACE04091AD),
+		UINT64_C(0xCADE8E953483D791), UINT64_C(0xC72F5EC9A6FA3EC5),
+		UINT64_C(0xD03C2F2C10700538), UINT64_C(0xDDCDFF708209EC6C),
+		UINT64_C(0x52F87D71648CCC60), UINT64_C(0x5F09AD2DF6F52534),
+		UINT64_C(0x481ADCC8407F1EC9), UINT64_C(0x45EB0C94D206F79D),
+		UINT64_C(0xE32230AD06C5B1A1), UINT64_C(0xEED3E0F194BC58F5),
+		UINT64_C(0xF9C0911422366308), UINT64_C(0xF4314148B04F8A5C),
+		UINT64_C(0xB553E8668AB1EE70), UINT64_C(0xB8A2383A18C80724),
+		UINT64_C(0xAFB149DFAE423CD9), UINT64_C(0xA24099833C3BD58D),
+		UINT64_C(0x0489A5BAE8F893B1), UINT64_C(0x097875E67A817AE5),
+		UINT64_C(0x1E6B0403CC0B4118), UINT64_C(0x139AD45F5E72A84C),
+		UINT64_C(0x385FADBC70EF1181), UINT64_C(0x35AE7DE0E296F8D5),
+		UINT64_C(0x22BD0C05541CC328), UINT64_C(0x2F4CDC59C6652A7C),
+		UINT64_C(0x8985E06012A66C40), UINT64_C(0x8474303C80DF8514),
+		UINT64_C(0x936741D93655BEE9), UINT64_C(0x9E969185A42C57BD),
+		UINT64_C(0xDFF438AB9ED23391), UINT64_C(0xD205E8F70CABDAC5),
+		UINT64_C(0xC5169912BA21E138), UINT64_C(0xC8E7494E2858086C),
+		UINT64_C(0x6E2E7577FC9B4E50), UINT64_C(0x63DFA52B6EE2A704),
+		UINT64_C(0x74CCD4CED8689CF9), UINT64_C(0x793D04924A1175AD),
+		UINT64_C(0xF6088693AC9455A1), UINT64_C(0xFBF956CF3EEDBCF5),
+		UINT64_C(0xECEA272A88678708), UINT64_C(0xE11BF7761A1E6E5C),
+		UINT64_C(0x47D2CB4FCEDD2860), UINT64_C(0x4A231B135CA4C134),
+		UINT64_C(0x5D306AF6EA2EFAC9), UINT64_C(0x50C1BAAA7857139D),
+		UINT64_C(0x11A3138442A977B1), UINT64_C(0x1C52C3D8D0D09EE5),
+		UINT64_C(0x0B41B23D665AA518), UINT64_C(0x06B06261F4234C4C),
+		UINT64_C(0xA0795E5820E00A70), UINT64_C(0xAD888E04B299E324),
+		UINT64_C(0xBA9BFFE10413D8D9), UINT64_C(0xB76A2FBD966A318D),
+		UINT64_C(0xA4F0FBE2C81899C1), UINT64_C(0xA9012BBE5A617095),
+		UINT64_C(0xBE125A5BECEB4B68), UINT64_C(0xB3E38A077E92A23C),
+		UINT64_C(0x152AB63EAA51E400), UINT64_C(0x18DB666238280D54),
+		UINT64_C(0x0FC817878EA236A9), UINT64_C(0x0239C7DB1CDBDFFD),
+		UINT64_C(0x435B6EF52625BBD1), UINT64_C(0x4EAABEA9B45C5285),
+		UINT64_C(0x59B9CF4C02D66978), UINT64_C(0x54481F1090AF802C),
+		UINT64_C(0xF2812329446CC610), UINT64_C(0xFF70F375D6152F44),
+		UINT64_C(0xE8638290609F14B9), UINT64_C(0xE59252CCF2E6FDED),
+		UINT64_C(0x6AA7D0CD1463DDE1), UINT64_C(0x67560091861A34B5),
+		UINT64_C(0x7045717430900F48), UINT64_C(0x7DB4A128A2E9E61C),
+		UINT64_C(0xDB7D9D11762AA020), UINT64_C(0xD68C4D4DE4534974),
+		UINT64_C(0xC19F3CA852D97289), UINT64_C(0xCC6EECF4C0A09BDD),
+		UINT64_C(0x8D0C45DAFA5EFFF1), UINT64_C(0x80FD9586682716A5),
+		UINT64_C(0x97EEE463DEAD2D58), UINT64_C(0x9A1F343F4CD4C40C),
+		UINT64_C(0x3CD6080698178230), UINT64_C(0x3127D85A0A6E6B64),
+		UINT64_C(0x2634A9BFBCE45099), UINT64_C(0x2BC579E32E9DB9CD),
+		UINT64_C(0xF5A054D6CA71FB90), UINT64_C(0xF851848A580812C4),
+		UINT64_C(0xEF42F56FEE822939), UINT64_C(0xE2B325337CFBC06D),
+		UINT64_C(0x447A190AA8388651), UINT64_C(0x498BC9563A416F05),
+		UINT64_C(0x5E98B8B38CCB54F8), UINT64_C(0x536968EF1EB2BDAC),
+		UINT64_C(0x120BC1C1244CD980), UINT64_C(0x1FFA119DB63530D4),
+		UINT64_C(0x08E9607800BF0B29), UINT64_C(0x0518B02492C6E27D),
+		UINT64_C(0xA3D18C1D4605A441), UINT64_C(0xAE205C41D47C4D15),
+		UINT64_C(0xB9332DA462F676E8), UINT64_C(0xB4C2FDF8F08F9FBC),
+		UINT64_C(0x3BF77FF9160ABFB0), UINT64_C(0x3606AFA5847356E4),
+		UINT64_C(0x2115DE4032F96D19), UINT64_C(0x2CE40E1CA080844D),
+		UINT64_C(0x8A2D32257443C271), UINT64_C(0x87DCE279E63A2B25),
+		UINT64_C(0x90CF939C50B010D8), UINT64_C(0x9D3E43C0C2C9F98C),
+		UINT64_C(0xDC5CEAEEF8379DA0), UINT64_C(0xD1AD3AB26A4E74F4),
+		UINT64_C(0xC6BE4B57DCC44F09), UINT64_C(0xCB4F9B0B4EBDA65D),
+		UINT64_C(0x6D86A7329A7EE061), UINT64_C(0x6077776E08070935),
+		UINT64_C(0x7764068BBE8D32C8), UINT64_C(0x7A95D6D72CF4DB9C),
+		UINT64_C(0x690F0288728673D0), UINT64_C(0x64FED2D4E0FF9A84),
+		UINT64_C(0x73EDA3315675A179), UINT64_C(0x7E1C736DC40C482D),
+		UINT64_C(0xD8D54F5410CF0E11), UINT64_C(0xD5249F0882B6E745),
+		UINT64_C(0xC237EEED343CDCB8), UINT64_C(0xCFC63EB1A64535EC),
+		UINT64_C(0x8EA4979F9CBB51C0), UINT64_C(0x835547C30EC2B894),
+		UINT64_C(0x94463626B8488369), UINT64_C(0x99B7E67A2A316A3D),
+		UINT64_C(0x3F7EDA43FEF22C01), UINT64_C(0x328F0A1F6C8BC555),
+		UINT64_C(0x259C7BFADA01FEA8), UINT64_C(0x286DABA6487817FC),
+		UINT64_C(0xA75829A7AEFD37F0), UINT64_C(0xAAA9F9FB3C84DEA4),
+		UINT64_C(0xBDBA881E8A0EE559), UINT64_C(0xB04B584218770C0D),
+		UINT64_C(0x1682647BCCB44A31), UINT64_C(0x1B73B4275ECDA365),
+		UINT64_C(0x0C60C5C2E8479898), UINT64_C(0x0191159E7A3E71CC),
+		UINT64_C(0x40F3BCB040C015E0), UINT64_C(0x4D026CECD2B9FCB4),
+		UINT64_C(0x5A111D096433C749), UINT64_C(0x57E0CD55F64A2E1D),
+		UINT64_C(0xF129F16C22896821), UINT64_C(0xFCD82130B0F08175),
+		UINT64_C(0xEBCB50D5067ABA88), UINT64_C(0xE63A8089940353DC),
+		UINT64_C(0xCDFFF96ABA9EEA11), UINT64_C(0xC00E293628E70345),
+		UINT64_C(0xD71D58D39E6D38B8), UINT64_C(0xDAEC888F0C14D1EC),
+		UINT64_C(0x7C25B4B6D8D797D0), UINT64_C(0x71D464EA4AAE7E84),
+		UINT64_C(0x66C7150FFC244579), UINT64_C(0x6B36C5536E5DAC2D),
+		UINT64_C(0x2A546C7D54A3C801), UINT64_C(0x27A5BC21C6DA2155),
+		UINT64_C(0x30B6CDC470501AA8), UINT64_C(0x3D471D98E229F3FC),
+		UINT64_C(0x9B8E21A136EAB5C0), UINT64_C(0x967FF1FDA4935C94),
+		UINT64_C(0x816C801812196769), UINT64_C(0x8C9D504480608E3D),
+		UINT64_C(0x03A8D24566E5AE31), UINT64_C(0x0E590219F49C4765),
+		UINT64_C(0x194A73FC42167C98), UINT64_C(0x14BBA3A0D06F95CC),
+		UINT64_C(0xB2729F9904ACD3F0), UINT64_C(0xBF834FC596D53AA4),
+		UINT64_C(0xA8903E20205F0159), UINT64_C(0xA561EE7CB226E80D),
+		UINT64_C(0xE403475288D88C21), UINT64_C(0xE9F2970E1AA16575),
+		UINT64_C(0xFEE1E6EBAC2B5E88), UINT64_C(0xF31036B73E52B7DC),
+		UINT64_C(0x55D90A8EEA91F1E0), UINT64_C(0x5828DAD278E818B4),
+		UINT64_C(0x4F3BAB37CE622349), UINT64_C(0x42CA7B6B5C1BCA1D),
+		UINT64_C(0x5150AF3402696251), UINT64_C(0x5CA17F6890108B05),
+		UINT64_C(0x4BB20E8D269AB0F8), UINT64_C(0x4643DED1B4E359AC),
+		UINT64_C(0xE08AE2E860201F90), UINT64_C(0xED7B32B4F259F6C4),
+		UINT64_C(0xFA68435144D3CD39), UINT64_C(0xF799930DD6AA246D),
+		UINT64_C(0xB6FB3A23EC544041), UINT64_C(0xBB0AEA7F7E2DA915),
+		UINT64_C(0xAC199B9AC8A792E8), UINT64_C(0xA1E84BC65ADE7BBC),
+		UINT64_C(0x072177FF8E1D3D80), UINT64_C(0x0AD0A7A31C64D4D4),
+		UINT64_C(0x1DC3D646AAEEEF29), UINT64_C(0x1032061A3897067D),
+		UINT64_C(0x9F07841BDE122671), UINT64_C(0x92F654474C6BCF25),
+		UINT64_C(0x85E525A2FAE1F4D8), UINT64_C(0x8814F5FE68981D8C),
+		UINT64_C(0x2EDDC9C7BC5B5BB0), UINT64_C(0x232C199B2E22B2E4),
+		UINT64_C(0x343F687E98A88919), UINT64_C(0x39CEB8220AD1604D),
+		UINT64_C(0x78AC110C302F0461), UINT64_C(0x755DC150A256ED35),
+		UINT64_C(0x624EB0B514DCD6C8), UINT64_C(0x6FBF60E986A53F9C),
+		UINT64_C(0xC9765CD0526679A0), UINT64_C(0xC4878C8CC01F90F4),
+		UINT64_C(0xD394FD697695AB09), UINT64_C(0xDE652D35E4EC425D)
+	}, {
+		UINT64_C(0x0000000000000000), UINT64_C(0xCB6D6A914AE10B3F),
+		UINT64_C(0x96DBD42295C2177E), UINT64_C(0x5DB6BEB3DF231C41),
+		UINT64_C(0x2CB7A9452A852FFC), UINT64_C(0xE7DAC3D4606424C3),
+		UINT64_C(0xBA6C7D67BF473882), UINT64_C(0x710117F6F5A633BD),
+		UINT64_C(0xDD705D247FA5876A), UINT64_C(0x161D37B535448C55),
+		UINT64_C(0x4BAB8906EA679014), UINT64_C(0x80C6E397A0869B2B),
+		UINT64_C(0xF1C7F4615520A896), UINT64_C(0x3AAA9EF01FC1A3A9),
+		UINT64_C(0x671C2043C0E2BFE8), UINT64_C(0xAC714AD28A03B4D7),
+		UINT64_C(0xBAE1BA48FE4A0FD5), UINT64_C(0x718CD0D9B4AB04EA),
+		UINT64_C(0x2C3A6E6A6B8818AB), UINT64_C(0xE75704FB21691394),
+		UINT64_C(0x9656130DD4CF2029), UINT64_C(0x5D3B799C9E2E2B16),
+		UINT64_C(0x008DC72F410D3757), UINT64_C(0xCBE0ADBE0BEC3C68),
+		UINT64_C(0x6791E76C81EF88BF), UINT64_C(0xACFC8DFDCB0E8380),
+		UINT64_C(0xF14A334E142D9FC1), UINT64_C(0x3A2759DF5ECC94FE),
+		UINT64_C(0x4B264E29AB6AA743), UINT64_C(0x804B24B8E18BAC7C),
+		UINT64_C(0xDDFD9A0B3EA8B03D), UINT64_C(0x1690F09A7449BB02),
+		UINT64_C(0xF1DD7B3ED73AC638), UINT64_C(0x3AB011AF9DDBCD07),
+		UINT64_C(0x6706AF1C42F8D146), UINT64_C(0xAC6BC58D0819DA79),
+		UINT64_C(0xDD6AD27BFDBFE9C4), UINT64_C(0x1607B8EAB75EE2FB),
+		UINT64_C(0x4BB10659687DFEBA), UINT64_C(0x80DC6CC8229CF585),
+		UINT64_C(0x2CAD261AA89F4152), UINT64_C(0xE7C04C8BE27E4A6D),
+		UINT64_C(0xBA76F2383D5D562C), UINT64_C(0x711B98A977BC5D13),
+		UINT64_C(0x001A8F5F821A6EAE), UINT64_C(0xCB77E5CEC8FB6591),
+		UINT64_C(0x96C15B7D17D879D0), UINT64_C(0x5DAC31EC5D3972EF),
+		UINT64_C(0x4B3CC1762970C9ED), UINT64_C(0x8051ABE76391C2D2),
+		UINT64_C(0xDDE71554BCB2DE93), UINT64_C(0x168A7FC5F653D5AC),
+		UINT64_C(0x678B683303F5E611), UINT64_C(0xACE602A24914ED2E),
+		UINT64_C(0xF150BC119637F16F), UINT64_C(0x3A3DD680DCD6FA50),
+		UINT64_C(0x964C9C5256D54E87), UINT64_C(0x5D21F6C31C3445B8),
+		UINT64_C(0x00974870C31759F9), UINT64_C(0xCBFA22E189F652C6),
+		UINT64_C(0xBAFB35177C50617B), UINT64_C(0x71965F8636B16A44),
+		UINT64_C(0x2C20E135E9927605), UINT64_C(0xE74D8BA4A3737D3A),
+		UINT64_C(0xE2BBF77CAE758C71), UINT64_C(0x29D69DEDE494874E),
+		UINT64_C(0x7460235E3BB79B0F), UINT64_C(0xBF0D49CF71569030),
+		UINT64_C(0xCE0C5E3984F0A38D), UINT64_C(0x056134A8CE11A8B2),
+		UINT64_C(0x58D78A1B1132B4F3), UINT64_C(0x93BAE08A5BD3BFCC),
+		UINT64_C(0x3FCBAA58D1D00B1B), UINT64_C(0xF4A6C0C99B310024),
+		UINT64_C(0xA9107E7A44121C65), UINT64_C(0x627D14EB0EF3175A),
+		UINT64_C(0x137C031DFB5524E7), UINT64_C(0xD811698CB1B42FD8),
+		UINT64_C(0x85A7D73F6E973399), UINT64_C(0x4ECABDAE247638A6),
+		UINT64_C(0x585A4D34503F83A4), UINT64_C(0x933727A51ADE889B),
+		UINT64_C(0xCE819916C5FD94DA), UINT64_C(0x05ECF3878F1C9FE5),
+		UINT64_C(0x74EDE4717ABAAC58), UINT64_C(0xBF808EE0305BA767),
+		UINT64_C(0xE2363053EF78BB26), UINT64_C(0x295B5AC2A599B019),
+		UINT64_C(0x852A10102F9A04CE), UINT64_C(0x4E477A81657B0FF1),
+		UINT64_C(0x13F1C432BA5813B0), UINT64_C(0xD89CAEA3F0B9188F),
+		UINT64_C(0xA99DB955051F2B32), UINT64_C(0x62F0D3C44FFE200D),
+		UINT64_C(0x3F466D7790DD3C4C), UINT64_C(0xF42B07E6DA3C3773),
+		UINT64_C(0x13668C42794F4A49), UINT64_C(0xD80BE6D333AE4176),
+		UINT64_C(0x85BD5860EC8D5D37), UINT64_C(0x4ED032F1A66C5608),
+		UINT64_C(0x3FD1250753CA65B5), UINT64_C(0xF4BC4F96192B6E8A),
+		UINT64_C(0xA90AF125C60872CB), UINT64_C(0x62679BB48CE979F4),
+		UINT64_C(0xCE16D16606EACD23), UINT64_C(0x057BBBF74C0BC61C),
+		UINT64_C(0x58CD05449328DA5D), UINT64_C(0x93A06FD5D9C9D162),
+		UINT64_C(0xE2A178232C6FE2DF), UINT64_C(0x29CC12B2668EE9E0),
+		UINT64_C(0x747AAC01B9ADF5A1), UINT64_C(0xBF17C690F34CFE9E),
+		UINT64_C(0xA987360A8705459C), UINT64_C(0x62EA5C9BCDE44EA3),
+		UINT64_C(0x3F5CE22812C752E2), UINT64_C(0xF43188B9582659DD),
+		UINT64_C(0x85309F4FAD806A60), UINT64_C(0x4E5DF5DEE761615F),
+		UINT64_C(0x13EB4B6D38427D1E), UINT64_C(0xD88621FC72A37621),
+		UINT64_C(0x74F76B2EF8A0C2F6), UINT64_C(0xBF9A01BFB241C9C9),
+		UINT64_C(0xE22CBF0C6D62D588), UINT64_C(0x2941D59D2783DEB7),
+		UINT64_C(0x5840C26BD225ED0A), UINT64_C(0x932DA8FA98C4E635),
+		UINT64_C(0xCE9B164947E7FA74), UINT64_C(0x05F67CD80D06F14B),
+		UINT64_C(0xC477EFF95CEB18E3), UINT64_C(0x0F1A8568160A13DC),
+		UINT64_C(0x52AC3BDBC9290F9D), UINT64_C(0x99C1514A83C804A2),
+		UINT64_C(0xE8C046BC766E371F), UINT64_C(0x23AD2C2D3C8F3C20),
+		UINT64_C(0x7E1B929EE3AC2061), UINT64_C(0xB576F80FA94D2B5E),
+		UINT64_C(0x1907B2DD234E9F89), UINT64_C(0xD26AD84C69AF94B6),
+		UINT64_C(0x8FDC66FFB68C88F7), UINT64_C(0x44B10C6EFC6D83C8),
+		UINT64_C(0x35B01B9809CBB075), UINT64_C(0xFEDD7109432ABB4A),
+		UINT64_C(0xA36BCFBA9C09A70B), UINT64_C(0x6806A52BD6E8AC34),
+		UINT64_C(0x7E9655B1A2A11736), UINT64_C(0xB5FB3F20E8401C09),
+		UINT64_C(0xE84D819337630048), UINT64_C(0x2320EB027D820B77),
+		UINT64_C(0x5221FCF4882438CA), UINT64_C(0x994C9665C2C533F5),
+		UINT64_C(0xC4FA28D61DE62FB4), UINT64_C(0x0F9742475707248B),
+		UINT64_C(0xA3E60895DD04905C), UINT64_C(0x688B620497E59B63),
+		UINT64_C(0x353DDCB748C68722), UINT64_C(0xFE50B62602278C1D),
+		UINT64_C(0x8F51A1D0F781BFA0), UINT64_C(0x443CCB41BD60B49F),
+		UINT64_C(0x198A75F26243A8DE), UINT64_C(0xD2E71F6328A2A3E1),
+		UINT64_C(0x35AA94C78BD1DEDB), UINT64_C(0xFEC7FE56C130D5E4),
+		UINT64_C(0xA37140E51E13C9A5), UINT64_C(0x681C2A7454F2C29A),
+		UINT64_C(0x191D3D82A154F127), UINT64_C(0xD2705713EBB5FA18),
+		UINT64_C(0x8FC6E9A03496E659), UINT64_C(0x44AB83317E77ED66),
+		UINT64_C(0xE8DAC9E3F47459B1), UINT64_C(0x23B7A372BE95528E),
+		UINT64_C(0x7E011DC161B64ECF), UINT64_C(0xB56C77502B5745F0),
+		UINT64_C(0xC46D60A6DEF1764D), UINT64_C(0x0F000A3794107D72),
+		UINT64_C(0x52B6B4844B336133), UINT64_C(0x99DBDE1501D26A0C),
+		UINT64_C(0x8F4B2E8F759BD10E), UINT64_C(0x4426441E3F7ADA31),
+		UINT64_C(0x1990FAADE059C670), UINT64_C(0xD2FD903CAAB8CD4F),
+		UINT64_C(0xA3FC87CA5F1EFEF2), UINT64_C(0x6891ED5B15FFF5CD),
+		UINT64_C(0x352753E8CADCE98C), UINT64_C(0xFE4A3979803DE2B3),
+		UINT64_C(0x523B73AB0A3E5664), UINT64_C(0x9956193A40DF5D5B),
+		UINT64_C(0xC4E0A7899FFC411A), UINT64_C(0x0F8DCD18D51D4A25),
+		UINT64_C(0x7E8CDAEE20BB7998), UINT64_C(0xB5E1B07F6A5A72A7),
+		UINT64_C(0xE8570ECCB5796EE6), UINT64_C(0x233A645DFF9865D9),
+		UINT64_C(0x26CC1885F29E9492), UINT64_C(0xEDA17214B87F9FAD),
+		UINT64_C(0xB017CCA7675C83EC), UINT64_C(0x7B7AA6362DBD88D3),
+		UINT64_C(0x0A7BB1C0D81BBB6E), UINT64_C(0xC116DB5192FAB051),
+		UINT64_C(0x9CA065E24DD9AC10), UINT64_C(0x57CD0F730738A72F),
+		UINT64_C(0xFBBC45A18D3B13F8), UINT64_C(0x30D12F30C7DA18C7),
+		UINT64_C(0x6D67918318F90486), UINT64_C(0xA60AFB1252180FB9),
+		UINT64_C(0xD70BECE4A7BE3C04), UINT64_C(0x1C668675ED5F373B),
+		UINT64_C(0x41D038C6327C2B7A), UINT64_C(0x8ABD5257789D2045),
+		UINT64_C(0x9C2DA2CD0CD49B47), UINT64_C(0x5740C85C46359078),
+		UINT64_C(0x0AF676EF99168C39), UINT64_C(0xC19B1C7ED3F78706),
+		UINT64_C(0xB09A0B882651B4BB), UINT64_C(0x7BF761196CB0BF84),
+		UINT64_C(0x2641DFAAB393A3C5), UINT64_C(0xED2CB53BF972A8FA),
+		UINT64_C(0x415DFFE973711C2D), UINT64_C(0x8A30957839901712),
+		UINT64_C(0xD7862BCBE6B30B53), UINT64_C(0x1CEB415AAC52006C),
+		UINT64_C(0x6DEA56AC59F433D1), UINT64_C(0xA6873C3D131538EE),
+		UINT64_C(0xFB31828ECC3624AF), UINT64_C(0x305CE81F86D72F90),
+		UINT64_C(0xD71163BB25A452AA), UINT64_C(0x1C7C092A6F455995),
+		UINT64_C(0x41CAB799B06645D4), UINT64_C(0x8AA7DD08FA874EEB),
+		UINT64_C(0xFBA6CAFE0F217D56), UINT64_C(0x30CBA06F45C07669),
+		UINT64_C(0x6D7D1EDC9AE36A28), UINT64_C(0xA610744DD0026117),
+		UINT64_C(0x0A613E9F5A01D5C0), UINT64_C(0xC10C540E10E0DEFF),
+		UINT64_C(0x9CBAEABDCFC3C2BE), UINT64_C(0x57D7802C8522C981),
+		UINT64_C(0x26D697DA7084FA3C), UINT64_C(0xEDBBFD4B3A65F103),
+		UINT64_C(0xB00D43F8E546ED42), UINT64_C(0x7B602969AFA7E67D),
+		UINT64_C(0x6DF0D9F3DBEE5D7F), UINT64_C(0xA69DB362910F5640),
+		UINT64_C(0xFB2B0DD14E2C4A01), UINT64_C(0x3046674004CD413E),
+		UINT64_C(0x414770B6F16B7283), UINT64_C(0x8A2A1A27BB8A79BC),
+		UINT64_C(0xD79CA49464A965FD), UINT64_C(0x1CF1CE052E486EC2),
+		UINT64_C(0xB08084D7A44BDA15), UINT64_C(0x7BEDEE46EEAAD12A),
+		UINT64_C(0x265B50F53189CD6B), UINT64_C(0xED363A647B68C654),
+		UINT64_C(0x9C372D928ECEF5E9), UINT64_C(0x575A4703C42FFED6),
+		UINT64_C(0x0AECF9B01B0CE297), UINT64_C(0xC181932151EDE9A8)
+	}, {
+		UINT64_C(0x0000000000000000), UINT64_C(0xDCA12C225E8AEE1D),
+		UINT64_C(0xB8435944BC14DD3B), UINT64_C(0x64E27566E29E3326),
+		UINT64_C(0x7087B2887829BA77), UINT64_C(0xAC269EAA26A3546A),
+		UINT64_C(0xC8C4EBCCC43D674C), UINT64_C(0x1465C7EE9AB78951),
+		UINT64_C(0xE00E6511F15274EF), UINT64_C(0x3CAF4933AFD89AF2),
+		UINT64_C(0x584D3C554D46A9D4), UINT64_C(0x84EC107713CC47C9),
+		UINT64_C(0x9089D799897BCE98), UINT64_C(0x4C28FBBBD7F12085),
+		UINT64_C(0x28CA8EDD356F13A3), UINT64_C(0xF46BA2FF6BE5FDBE),
+		UINT64_C(0x4503C48DC90A304C), UINT64_C(0x99A2E8AF9780DE51),
+		UINT64_C(0xFD409DC9751EED77), UINT64_C(0x21E1B1EB2B94036A),
+		UINT64_C(0x35847605B1238A3B), UINT64_C(0xE9255A27EFA96426),
+		UINT64_C(0x8DC72F410D375700), UINT64_C(0x5166036353BDB91D),
+		UINT64_C(0xA50DA19C385844A3), UINT64_C(0x79AC8DBE66D2AABE),
+		UINT64_C(0x1D4EF8D8844C9998), UINT64_C(0xC1EFD4FADAC67785),
+		UINT64_C(0xD58A13144071FED4), UINT64_C(0x092B3F361EFB10C9),
+		UINT64_C(0x6DC94A50FC6523EF), UINT64_C(0xB1686672A2EFCDF2),
+		UINT64_C(0x8A06881B93156098), UINT64_C(0x56A7A439CD9F8E85),
+		UINT64_C(0x3245D15F2F01BDA3), UINT64_C(0xEEE4FD7D718B53BE),
+		UINT64_C(0xFA813A93EB3CDAEF), UINT64_C(0x262016B1B5B634F2),
+		UINT64_C(0x42C263D7572807D4), UINT64_C(0x9E634FF509A2E9C9),
+		UINT64_C(0x6A08ED0A62471477), UINT64_C(0xB6A9C1283CCDFA6A),
+		UINT64_C(0xD24BB44EDE53C94C), UINT64_C(0x0EEA986C80D92751),
+		UINT64_C(0x1A8F5F821A6EAE00), UINT64_C(0xC62E73A044E4401D),
+		UINT64_C(0xA2CC06C6A67A733B), UINT64_C(0x7E6D2AE4F8F09D26),
+		UINT64_C(0xCF054C965A1F50D4), UINT64_C(0x13A460B40495BEC9),
+		UINT64_C(0x774615D2E60B8DEF), UINT64_C(0xABE739F0B88163F2),
+		UINT64_C(0xBF82FE1E2236EAA3), UINT64_C(0x6323D23C7CBC04BE),
+		UINT64_C(0x07C1A75A9E223798), UINT64_C(0xDB608B78C0A8D985),
+		UINT64_C(0x2F0B2987AB4D243B), UINT64_C(0xF3AA05A5F5C7CA26),
+		UINT64_C(0x974870C31759F900), UINT64_C(0x4BE95CE149D3171D),
+		UINT64_C(0x5F8C9B0FD3649E4C), UINT64_C(0x832DB72D8DEE7051),
+		UINT64_C(0xE7CFC24B6F704377), UINT64_C(0x3B6EEE6931FAAD6A),
+		UINT64_C(0x91131E980D8418A2), UINT64_C(0x4DB232BA530EF6BF),
+		UINT64_C(0x295047DCB190C599), UINT64_C(0xF5F16BFEEF1A2B84),
+		UINT64_C(0xE194AC1075ADA2D5), UINT64_C(0x3D3580322B274CC8),
+		UINT64_C(0x59D7F554C9B97FEE), UINT64_C(0x8576D976973391F3),
+		UINT64_C(0x711D7B89FCD66C4D), UINT64_C(0xADBC57ABA25C8250),
+		UINT64_C(0xC95E22CD40C2B176), UINT64_C(0x15FF0EEF1E485F6B),
+		UINT64_C(0x019AC90184FFD63A), UINT64_C(0xDD3BE523DA753827),
+		UINT64_C(0xB9D9904538EB0B01), UINT64_C(0x6578BC676661E51C),
+		UINT64_C(0xD410DA15C48E28EE), UINT64_C(0x08B1F6379A04C6F3),
+		UINT64_C(0x6C538351789AF5D5), UINT64_C(0xB0F2AF7326101BC8),
+		UINT64_C(0xA497689DBCA79299), UINT64_C(0x783644BFE22D7C84),
+		UINT64_C(0x1CD431D900B34FA2), UINT64_C(0xC0751DFB5E39A1BF),
+		UINT64_C(0x341EBF0435DC5C01), UINT64_C(0xE8BF93266B56B21C),
+		UINT64_C(0x8C5DE64089C8813A), UINT64_C(0x50FCCA62D7426F27),
+		UINT64_C(0x44990D8C4DF5E676), UINT64_C(0x983821AE137F086B),
+		UINT64_C(0xFCDA54C8F1E13B4D), UINT64_C(0x207B78EAAF6BD550),
+		UINT64_C(0x1B1596839E91783A), UINT64_C(0xC7B4BAA1C01B9627),
+		UINT64_C(0xA356CFC72285A501), UINT64_C(0x7FF7E3E57C0F4B1C),
+		UINT64_C(0x6B92240BE6B8C24D), UINT64_C(0xB7330829B8322C50),
+		UINT64_C(0xD3D17D4F5AAC1F76), UINT64_C(0x0F70516D0426F16B),
+		UINT64_C(0xFB1BF3926FC30CD5), UINT64_C(0x27BADFB03149E2C8),
+		UINT64_C(0x4358AAD6D3D7D1EE), UINT64_C(0x9FF986F48D5D3FF3),
+		UINT64_C(0x8B9C411A17EAB6A2), UINT64_C(0x573D6D38496058BF),
+		UINT64_C(0x33DF185EABFE6B99), UINT64_C(0xEF7E347CF5748584),
+		UINT64_C(0x5E16520E579B4876), UINT64_C(0x82B77E2C0911A66B),
+		UINT64_C(0xE6550B4AEB8F954D), UINT64_C(0x3AF42768B5057B50),
+		UINT64_C(0x2E91E0862FB2F201), UINT64_C(0xF230CCA471381C1C),
+		UINT64_C(0x96D2B9C293A62F3A), UINT64_C(0x4A7395E0CD2CC127),
+		UINT64_C(0xBE18371FA6C93C99), UINT64_C(0x62B91B3DF843D284),
+		UINT64_C(0x065B6E5B1ADDE1A2), UINT64_C(0xDAFA427944570FBF),
+		UINT64_C(0xCE9F8597DEE086EE), UINT64_C(0x123EA9B5806A68F3),
+		UINT64_C(0x76DCDCD362F45BD5), UINT64_C(0xAA7DF0F13C7EB5C8),
+		UINT64_C(0xA739329F30A7E9D6), UINT64_C(0x7B981EBD6E2D07CB),
+		UINT64_C(0x1F7A6BDB8CB334ED), UINT64_C(0xC3DB47F9D239DAF0),
+		UINT64_C(0xD7BE8017488E53A1), UINT64_C(0x0B1FAC351604BDBC),
+		UINT64_C(0x6FFDD953F49A8E9A), UINT64_C(0xB35CF571AA106087),
+		UINT64_C(0x4737578EC1F59D39), UINT64_C(0x9B967BAC9F7F7324),
+		UINT64_C(0xFF740ECA7DE14002), UINT64_C(0x23D522E8236BAE1F),
+		UINT64_C(0x37B0E506B9DC274E), UINT64_C(0xEB11C924E756C953),
+		UINT64_C(0x8FF3BC4205C8FA75), UINT64_C(0x535290605B421468),
+		UINT64_C(0xE23AF612F9ADD99A), UINT64_C(0x3E9BDA30A7273787),
+		UINT64_C(0x5A79AF5645B904A1), UINT64_C(0x86D883741B33EABC),
+		UINT64_C(0x92BD449A818463ED), UINT64_C(0x4E1C68B8DF0E8DF0),
+		UINT64_C(0x2AFE1DDE3D90BED6), UINT64_C(0xF65F31FC631A50CB),
+		UINT64_C(0x0234930308FFAD75), UINT64_C(0xDE95BF2156754368),
+		UINT64_C(0xBA77CA47B4EB704E), UINT64_C(0x66D6E665EA619E53),
+		UINT64_C(0x72B3218B70D61702), UINT64_C(0xAE120DA92E5CF91F),
+		UINT64_C(0xCAF078CFCCC2CA39), UINT64_C(0x165154ED92482424),
+		UINT64_C(0x2D3FBA84A3B2894E), UINT64_C(0xF19E96A6FD386753),
+		UINT64_C(0x957CE3C01FA65475), UINT64_C(0x49DDCFE2412CBA68),
+		UINT64_C(0x5DB8080CDB9B3339), UINT64_C(0x8119242E8511DD24),
+		UINT64_C(0xE5FB5148678FEE02), UINT64_C(0x395A7D6A3905001F),
+		UINT64_C(0xCD31DF9552E0FDA1), UINT64_C(0x1190F3B70C6A13BC),
+		UINT64_C(0x757286D1EEF4209A), UINT64_C(0xA9D3AAF3B07ECE87),
+		UINT64_C(0xBDB66D1D2AC947D6), UINT64_C(0x6117413F7443A9CB),
+		UINT64_C(0x05F5345996DD9AED), UINT64_C(0xD954187BC85774F0),
+		UINT64_C(0x683C7E096AB8B902), UINT64_C(0xB49D522B3432571F),
+		UINT64_C(0xD07F274DD6AC6439), UINT64_C(0x0CDE0B6F88268A24),
+		UINT64_C(0x18BBCC8112910375), UINT64_C(0xC41AE0A34C1BED68),
+		UINT64_C(0xA0F895C5AE85DE4E), UINT64_C(0x7C59B9E7F00F3053),
+		UINT64_C(0x88321B189BEACDED), UINT64_C(0x5493373AC56023F0),
+		UINT64_C(0x3071425C27FE10D6), UINT64_C(0xECD06E7E7974FECB),
+		UINT64_C(0xF8B5A990E3C3779A), UINT64_C(0x241485B2BD499987),
+		UINT64_C(0x40F6F0D45FD7AAA1), UINT64_C(0x9C57DCF6015D44BC),
+		UINT64_C(0x362A2C073D23F174), UINT64_C(0xEA8B002563A91F69),
+		UINT64_C(0x8E69754381372C4F), UINT64_C(0x52C85961DFBDC252),
+		UINT64_C(0x46AD9E8F450A4B03), UINT64_C(0x9A0CB2AD1B80A51E),
+		UINT64_C(0xFEEEC7CBF91E9638), UINT64_C(0x224FEBE9A7947825),
+		UINT64_C(0xD6244916CC71859B), UINT64_C(0x0A85653492FB6B86),
+		UINT64_C(0x6E671052706558A0), UINT64_C(0xB2C63C702EEFB6BD),
+		UINT64_C(0xA6A3FB9EB4583FEC), UINT64_C(0x7A02D7BCEAD2D1F1),
+		UINT64_C(0x1EE0A2DA084CE2D7), UINT64_C(0xC2418EF856C60CCA),
+		UINT64_C(0x7329E88AF429C138), UINT64_C(0xAF88C4A8AAA32F25),
+		UINT64_C(0xCB6AB1CE483D1C03), UINT64_C(0x17CB9DEC16B7F21E),
+		UINT64_C(0x03AE5A028C007B4F), UINT64_C(0xDF0F7620D28A9552),
+		UINT64_C(0xBBED03463014A674), UINT64_C(0x674C2F646E9E4869),
+		UINT64_C(0x93278D9B057BB5D7), UINT64_C(0x4F86A1B95BF15BCA),
+		UINT64_C(0x2B64D4DFB96F68EC), UINT64_C(0xF7C5F8FDE7E586F1),
+		UINT64_C(0xE3A03F137D520FA0), UINT64_C(0x3F01133123D8E1BD),
+		UINT64_C(0x5BE36657C146D29B), UINT64_C(0x87424A759FCC3C86),
+		UINT64_C(0xBC2CA41CAE3691EC), UINT64_C(0x608D883EF0BC7FF1),
+		UINT64_C(0x046FFD5812224CD7), UINT64_C(0xD8CED17A4CA8A2CA),
+		UINT64_C(0xCCAB1694D61F2B9B), UINT64_C(0x100A3AB68895C586),
+		UINT64_C(0x74E84FD06A0BF6A0), UINT64_C(0xA84963F2348118BD),
+		UINT64_C(0x5C22C10D5F64E503), UINT64_C(0x8083ED2F01EE0B1E),
+		UINT64_C(0xE4619849E3703838), UINT64_C(0x38C0B46BBDFAD625),
+		UINT64_C(0x2CA57385274D5F74), UINT64_C(0xF0045FA779C7B169),
+		UINT64_C(0x94E62AC19B59824F), UINT64_C(0x484706E3C5D36C52),
+		UINT64_C(0xF92F6091673CA1A0), UINT64_C(0x258E4CB339B64FBD),
+		UINT64_C(0x416C39D5DB287C9B), UINT64_C(0x9DCD15F785A29286),
+		UINT64_C(0x89A8D2191F151BD7), UINT64_C(0x5509FE3B419FF5CA),
+		UINT64_C(0x31EB8B5DA301C6EC), UINT64_C(0xED4AA77FFD8B28F1),
+		UINT64_C(0x19210580966ED54F), UINT64_C(0xC58029A2C8E43B52),
+		UINT64_C(0xA1625CC42A7A0874), UINT64_C(0x7DC370E674F0E669),
+		UINT64_C(0x69A6B708EE476F38), UINT64_C(0xB5079B2AB0CD8125),
+		UINT64_C(0xD1E5EE4C5253B203), UINT64_C(0x0D44C26E0CD95C1E)
+	}
+};
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_le.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_le.h
new file mode 100644
index 00000000000..e40a8c82105
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_table_le.h
@@ -0,0 +1,523 @@
+// SPDX-License-Identifier: 0BSD
+
+// This file has been generated by crc64_tablegen.c.
+
+const uint64_t lzma_crc64_table[4][256] = {
+	{
+		UINT64_C(0x0000000000000000), UINT64_C(0xB32E4CBE03A75F6F),
+		UINT64_C(0xF4843657A840A05B), UINT64_C(0x47AA7AE9ABE7FF34),
+		UINT64_C(0x7BD0C384FF8F5E33), UINT64_C(0xC8FE8F3AFC28015C),
+		UINT64_C(0x8F54F5D357CFFE68), UINT64_C(0x3C7AB96D5468A107),
+		UINT64_C(0xF7A18709FF1EBC66), UINT64_C(0x448FCBB7FCB9E309),
+		UINT64_C(0x0325B15E575E1C3D), UINT64_C(0xB00BFDE054F94352),
+		UINT64_C(0x8C71448D0091E255), UINT64_C(0x3F5F08330336BD3A),
+		UINT64_C(0x78F572DAA8D1420E), UINT64_C(0xCBDB3E64AB761D61),
+		UINT64_C(0x7D9BA13851336649), UINT64_C(0xCEB5ED8652943926),
+		UINT64_C(0x891F976FF973C612), UINT64_C(0x3A31DBD1FAD4997D),
+		UINT64_C(0x064B62BCAEBC387A), UINT64_C(0xB5652E02AD1B6715),
+		UINT64_C(0xF2CF54EB06FC9821), UINT64_C(0x41E11855055BC74E),
+		UINT64_C(0x8A3A2631AE2DDA2F), UINT64_C(0x39146A8FAD8A8540),
+		UINT64_C(0x7EBE1066066D7A74), UINT64_C(0xCD905CD805CA251B),
+		UINT64_C(0xF1EAE5B551A2841C), UINT64_C(0x42C4A90B5205DB73),
+		UINT64_C(0x056ED3E2F9E22447), UINT64_C(0xB6409F5CFA457B28),
+		UINT64_C(0xFB374270A266CC92), UINT64_C(0x48190ECEA1C193FD),
+		UINT64_C(0x0FB374270A266CC9), UINT64_C(0xBC9D3899098133A6),
+		UINT64_C(0x80E781F45DE992A1), UINT64_C(0x33C9CD4A5E4ECDCE),
+		UINT64_C(0x7463B7A3F5A932FA), UINT64_C(0xC74DFB1DF60E6D95),
+		UINT64_C(0x0C96C5795D7870F4), UINT64_C(0xBFB889C75EDF2F9B),
+		UINT64_C(0xF812F32EF538D0AF), UINT64_C(0x4B3CBF90F69F8FC0),
+		UINT64_C(0x774606FDA2F72EC7), UINT64_C(0xC4684A43A15071A8),
+		UINT64_C(0x83C230AA0AB78E9C), UINT64_C(0x30EC7C140910D1F3),
+		UINT64_C(0x86ACE348F355AADB), UINT64_C(0x3582AFF6F0F2F5B4),
+		UINT64_C(0x7228D51F5B150A80), UINT64_C(0xC10699A158B255EF),
+		UINT64_C(0xFD7C20CC0CDAF4E8), UINT64_C(0x4E526C720F7DAB87),
+		UINT64_C(0x09F8169BA49A54B3), UINT64_C(0xBAD65A25A73D0BDC),
+		UINT64_C(0x710D64410C4B16BD), UINT64_C(0xC22328FF0FEC49D2),
+		UINT64_C(0x85895216A40BB6E6), UINT64_C(0x36A71EA8A7ACE989),
+		UINT64_C(0x0ADDA7C5F3C4488E), UINT64_C(0xB9F3EB7BF06317E1),
+		UINT64_C(0xFE5991925B84E8D5), UINT64_C(0x4D77DD2C5823B7BA),
+		UINT64_C(0x64B62BCAEBC387A1), UINT64_C(0xD7986774E864D8CE),
+		UINT64_C(0x90321D9D438327FA), UINT64_C(0x231C512340247895),
+		UINT64_C(0x1F66E84E144CD992), UINT64_C(0xAC48A4F017EB86FD),
+		UINT64_C(0xEBE2DE19BC0C79C9), UINT64_C(0x58CC92A7BFAB26A6),
+		UINT64_C(0x9317ACC314DD3BC7), UINT64_C(0x2039E07D177A64A8),
+		UINT64_C(0x67939A94BC9D9B9C), UINT64_C(0xD4BDD62ABF3AC4F3),
+		UINT64_C(0xE8C76F47EB5265F4), UINT64_C(0x5BE923F9E8F53A9B),
+		UINT64_C(0x1C4359104312C5AF), UINT64_C(0xAF6D15AE40B59AC0),
+		UINT64_C(0x192D8AF2BAF0E1E8), UINT64_C(0xAA03C64CB957BE87),
+		UINT64_C(0xEDA9BCA512B041B3), UINT64_C(0x5E87F01B11171EDC),
+		UINT64_C(0x62FD4976457FBFDB), UINT64_C(0xD1D305C846D8E0B4),
+		UINT64_C(0x96797F21ED3F1F80), UINT64_C(0x2557339FEE9840EF),
+		UINT64_C(0xEE8C0DFB45EE5D8E), UINT64_C(0x5DA24145464902E1),
+		UINT64_C(0x1A083BACEDAEFDD5), UINT64_C(0xA9267712EE09A2BA),
+		UINT64_C(0x955CCE7FBA6103BD), UINT64_C(0x267282C1B9C65CD2),
+		UINT64_C(0x61D8F8281221A3E6), UINT64_C(0xD2F6B4961186FC89),
+		UINT64_C(0x9F8169BA49A54B33), UINT64_C(0x2CAF25044A02145C),
+		UINT64_C(0x6B055FEDE1E5EB68), UINT64_C(0xD82B1353E242B407),
+		UINT64_C(0xE451AA3EB62A1500), UINT64_C(0x577FE680B58D4A6F),
+		UINT64_C(0x10D59C691E6AB55B), UINT64_C(0xA3FBD0D71DCDEA34),
+		UINT64_C(0x6820EEB3B6BBF755), UINT64_C(0xDB0EA20DB51CA83A),
+		UINT64_C(0x9CA4D8E41EFB570E), UINT64_C(0x2F8A945A1D5C0861),
+		UINT64_C(0x13F02D374934A966), UINT64_C(0xA0DE61894A93F609),
+		UINT64_C(0xE7741B60E174093D), UINT64_C(0x545A57DEE2D35652),
+		UINT64_C(0xE21AC88218962D7A), UINT64_C(0x5134843C1B317215),
+		UINT64_C(0x169EFED5B0D68D21), UINT64_C(0xA5B0B26BB371D24E),
+		UINT64_C(0x99CA0B06E7197349), UINT64_C(0x2AE447B8E4BE2C26),
+		UINT64_C(0x6D4E3D514F59D312), UINT64_C(0xDE6071EF4CFE8C7D),
+		UINT64_C(0x15BB4F8BE788911C), UINT64_C(0xA6950335E42FCE73),
+		UINT64_C(0xE13F79DC4FC83147), UINT64_C(0x521135624C6F6E28),
+		UINT64_C(0x6E6B8C0F1807CF2F), UINT64_C(0xDD45C0B11BA09040),
+		UINT64_C(0x9AEFBA58B0476F74), UINT64_C(0x29C1F6E6B3E0301B),
+		UINT64_C(0xC96C5795D7870F42), UINT64_C(0x7A421B2BD420502D),
+		UINT64_C(0x3DE861C27FC7AF19), UINT64_C(0x8EC62D7C7C60F076),
+		UINT64_C(0xB2BC941128085171), UINT64_C(0x0192D8AF2BAF0E1E),
+		UINT64_C(0x4638A2468048F12A), UINT64_C(0xF516EEF883EFAE45),
+		UINT64_C(0x3ECDD09C2899B324), UINT64_C(0x8DE39C222B3EEC4B),
+		UINT64_C(0xCA49E6CB80D9137F), UINT64_C(0x7967AA75837E4C10),
+		UINT64_C(0x451D1318D716ED17), UINT64_C(0xF6335FA6D4B1B278),
+		UINT64_C(0xB199254F7F564D4C), UINT64_C(0x02B769F17CF11223),
+		UINT64_C(0xB4F7F6AD86B4690B), UINT64_C(0x07D9BA1385133664),
+		UINT64_C(0x4073C0FA2EF4C950), UINT64_C(0xF35D8C442D53963F),
+		UINT64_C(0xCF273529793B3738), UINT64_C(0x7C0979977A9C6857),
+		UINT64_C(0x3BA3037ED17B9763), UINT64_C(0x888D4FC0D2DCC80C),
+		UINT64_C(0x435671A479AAD56D), UINT64_C(0xF0783D1A7A0D8A02),
+		UINT64_C(0xB7D247F3D1EA7536), UINT64_C(0x04FC0B4DD24D2A59),
+		UINT64_C(0x3886B22086258B5E), UINT64_C(0x8BA8FE9E8582D431),
+		UINT64_C(0xCC0284772E652B05), UINT64_C(0x7F2CC8C92DC2746A),
+		UINT64_C(0x325B15E575E1C3D0), UINT64_C(0x8175595B76469CBF),
+		UINT64_C(0xC6DF23B2DDA1638B), UINT64_C(0x75F16F0CDE063CE4),
+		UINT64_C(0x498BD6618A6E9DE3), UINT64_C(0xFAA59ADF89C9C28C),
+		UINT64_C(0xBD0FE036222E3DB8), UINT64_C(0x0E21AC88218962D7),
+		UINT64_C(0xC5FA92EC8AFF7FB6), UINT64_C(0x76D4DE52895820D9),
+		UINT64_C(0x317EA4BB22BFDFED), UINT64_C(0x8250E80521188082),
+		UINT64_C(0xBE2A516875702185), UINT64_C(0x0D041DD676D77EEA),
+		UINT64_C(0x4AAE673FDD3081DE), UINT64_C(0xF9802B81DE97DEB1),
+		UINT64_C(0x4FC0B4DD24D2A599), UINT64_C(0xFCEEF8632775FAF6),
+		UINT64_C(0xBB44828A8C9205C2), UINT64_C(0x086ACE348F355AAD),
+		UINT64_C(0x34107759DB5DFBAA), UINT64_C(0x873E3BE7D8FAA4C5),
+		UINT64_C(0xC094410E731D5BF1), UINT64_C(0x73BA0DB070BA049E),
+		UINT64_C(0xB86133D4DBCC19FF), UINT64_C(0x0B4F7F6AD86B4690),
+		UINT64_C(0x4CE50583738CB9A4), UINT64_C(0xFFCB493D702BE6CB),
+		UINT64_C(0xC3B1F050244347CC), UINT64_C(0x709FBCEE27E418A3),
+		UINT64_C(0x3735C6078C03E797), UINT64_C(0x841B8AB98FA4B8F8),
+		UINT64_C(0xADDA7C5F3C4488E3), UINT64_C(0x1EF430E13FE3D78C),
+		UINT64_C(0x595E4A08940428B8), UINT64_C(0xEA7006B697A377D7),
+		UINT64_C(0xD60ABFDBC3CBD6D0), UINT64_C(0x6524F365C06C89BF),
+		UINT64_C(0x228E898C6B8B768B), UINT64_C(0x91A0C532682C29E4),
+		UINT64_C(0x5A7BFB56C35A3485), UINT64_C(0xE955B7E8C0FD6BEA),
+		UINT64_C(0xAEFFCD016B1A94DE), UINT64_C(0x1DD181BF68BDCBB1),
+		UINT64_C(0x21AB38D23CD56AB6), UINT64_C(0x9285746C3F7235D9),
+		UINT64_C(0xD52F0E859495CAED), UINT64_C(0x6601423B97329582),
+		UINT64_C(0xD041DD676D77EEAA), UINT64_C(0x636F91D96ED0B1C5),
+		UINT64_C(0x24C5EB30C5374EF1), UINT64_C(0x97EBA78EC690119E),
+		UINT64_C(0xAB911EE392F8B099), UINT64_C(0x18BF525D915FEFF6),
+		UINT64_C(0x5F1528B43AB810C2), UINT64_C(0xEC3B640A391F4FAD),
+		UINT64_C(0x27E05A6E926952CC), UINT64_C(0x94CE16D091CE0DA3),
+		UINT64_C(0xD3646C393A29F297), UINT64_C(0x604A2087398EADF8),
+		UINT64_C(0x5C3099EA6DE60CFF), UINT64_C(0xEF1ED5546E415390),
+		UINT64_C(0xA8B4AFBDC5A6ACA4), UINT64_C(0x1B9AE303C601F3CB),
+		UINT64_C(0x56ED3E2F9E224471), UINT64_C(0xE5C372919D851B1E),
+		UINT64_C(0xA26908783662E42A), UINT64_C(0x114744C635C5BB45),
+		UINT64_C(0x2D3DFDAB61AD1A42), UINT64_C(0x9E13B115620A452D),
+		UINT64_C(0xD9B9CBFCC9EDBA19), UINT64_C(0x6A978742CA4AE576),
+		UINT64_C(0xA14CB926613CF817), UINT64_C(0x1262F598629BA778),
+		UINT64_C(0x55C88F71C97C584C), UINT64_C(0xE6E6C3CFCADB0723),
+		UINT64_C(0xDA9C7AA29EB3A624), UINT64_C(0x69B2361C9D14F94B),
+		UINT64_C(0x2E184CF536F3067F), UINT64_C(0x9D36004B35545910),
+		UINT64_C(0x2B769F17CF112238), UINT64_C(0x9858D3A9CCB67D57),
+		UINT64_C(0xDFF2A94067518263), UINT64_C(0x6CDCE5FE64F6DD0C),
+		UINT64_C(0x50A65C93309E7C0B), UINT64_C(0xE388102D33392364),
+		UINT64_C(0xA4226AC498DEDC50), UINT64_C(0x170C267A9B79833F),
+		UINT64_C(0xDCD7181E300F9E5E), UINT64_C(0x6FF954A033A8C131),
+		UINT64_C(0x28532E49984F3E05), UINT64_C(0x9B7D62F79BE8616A),
+		UINT64_C(0xA707DB9ACF80C06D), UINT64_C(0x14299724CC279F02),
+		UINT64_C(0x5383EDCD67C06036), UINT64_C(0xE0ADA17364673F59)
+	}, {
+		UINT64_C(0x0000000000000000), UINT64_C(0x54E979925CD0F10D),
+		UINT64_C(0xA9D2F324B9A1E21A), UINT64_C(0xFD3B8AB6E5711317),
+		UINT64_C(0xC17D4962DC4DDAB1), UINT64_C(0x959430F0809D2BBC),
+		UINT64_C(0x68AFBA4665EC38AB), UINT64_C(0x3C46C3D4393CC9A6),
+		UINT64_C(0x10223DEE1795ABE7), UINT64_C(0x44CB447C4B455AEA),
+		UINT64_C(0xB9F0CECAAE3449FD), UINT64_C(0xED19B758F2E4B8F0),
+		UINT64_C(0xD15F748CCBD87156), UINT64_C(0x85B60D1E9708805B),
+		UINT64_C(0x788D87A87279934C), UINT64_C(0x2C64FE3A2EA96241),
+		UINT64_C(0x20447BDC2F2B57CE), UINT64_C(0x74AD024E73FBA6C3),
+		UINT64_C(0x899688F8968AB5D4), UINT64_C(0xDD7FF16ACA5A44D9),
+		UINT64_C(0xE13932BEF3668D7F), UINT64_C(0xB5D04B2CAFB67C72),
+		UINT64_C(0x48EBC19A4AC76F65), UINT64_C(0x1C02B80816179E68),
+		UINT64_C(0x3066463238BEFC29), UINT64_C(0x648F3FA0646E0D24),
+		UINT64_C(0x99B4B516811F1E33), UINT64_C(0xCD5DCC84DDCFEF3E),
+		UINT64_C(0xF11B0F50E4F32698), UINT64_C(0xA5F276C2B823D795),
+		UINT64_C(0x58C9FC745D52C482), UINT64_C(0x0C2085E60182358F),
+		UINT64_C(0x4088F7B85E56AF9C), UINT64_C(0x14618E2A02865E91),
+		UINT64_C(0xE95A049CE7F74D86), UINT64_C(0xBDB37D0EBB27BC8B),
+		UINT64_C(0x81F5BEDA821B752D), UINT64_C(0xD51CC748DECB8420),
+		UINT64_C(0x28274DFE3BBA9737), UINT64_C(0x7CCE346C676A663A),
+		UINT64_C(0x50AACA5649C3047B), UINT64_C(0x0443B3C41513F576),
+		UINT64_C(0xF9783972F062E661), UINT64_C(0xAD9140E0ACB2176C),
+		UINT64_C(0x91D78334958EDECA), UINT64_C(0xC53EFAA6C95E2FC7),
+		UINT64_C(0x380570102C2F3CD0), UINT64_C(0x6CEC098270FFCDDD),
+		UINT64_C(0x60CC8C64717DF852), UINT64_C(0x3425F5F62DAD095F),
+		UINT64_C(0xC91E7F40C8DC1A48), UINT64_C(0x9DF706D2940CEB45),
+		UINT64_C(0xA1B1C506AD3022E3), UINT64_C(0xF558BC94F1E0D3EE),
+		UINT64_C(0x086336221491C0F9), UINT64_C(0x5C8A4FB0484131F4),
+		UINT64_C(0x70EEB18A66E853B5), UINT64_C(0x2407C8183A38A2B8),
+		UINT64_C(0xD93C42AEDF49B1AF), UINT64_C(0x8DD53B3C839940A2),
+		UINT64_C(0xB193F8E8BAA58904), UINT64_C(0xE57A817AE6757809),
+		UINT64_C(0x18410BCC03046B1E), UINT64_C(0x4CA8725E5FD49A13),
+		UINT64_C(0x8111EF70BCAD5F38), UINT64_C(0xD5F896E2E07DAE35),
+		UINT64_C(0x28C31C54050CBD22), UINT64_C(0x7C2A65C659DC4C2F),
+		UINT64_C(0x406CA61260E08589), UINT64_C(0x1485DF803C307484),
+		UINT64_C(0xE9BE5536D9416793), UINT64_C(0xBD572CA48591969E),
+		UINT64_C(0x9133D29EAB38F4DF), UINT64_C(0xC5DAAB0CF7E805D2),
+		UINT64_C(0x38E121BA129916C5), UINT64_C(0x6C0858284E49E7C8),
+		UINT64_C(0x504E9BFC77752E6E), UINT64_C(0x04A7E26E2BA5DF63),
+		UINT64_C(0xF99C68D8CED4CC74), UINT64_C(0xAD75114A92043D79),
+		UINT64_C(0xA15594AC938608F6), UINT64_C(0xF5BCED3ECF56F9FB),
+		UINT64_C(0x088767882A27EAEC), UINT64_C(0x5C6E1E1A76F71BE1),
+		UINT64_C(0x6028DDCE4FCBD247), UINT64_C(0x34C1A45C131B234A),
+		UINT64_C(0xC9FA2EEAF66A305D), UINT64_C(0x9D135778AABAC150),
+		UINT64_C(0xB177A9428413A311), UINT64_C(0xE59ED0D0D8C3521C),
+		UINT64_C(0x18A55A663DB2410B), UINT64_C(0x4C4C23F46162B006),
+		UINT64_C(0x700AE020585E79A0), UINT64_C(0x24E399B2048E88AD),
+		UINT64_C(0xD9D81304E1FF9BBA), UINT64_C(0x8D316A96BD2F6AB7),
+		UINT64_C(0xC19918C8E2FBF0A4), UINT64_C(0x9570615ABE2B01A9),
+		UINT64_C(0x684BEBEC5B5A12BE), UINT64_C(0x3CA2927E078AE3B3),
+		UINT64_C(0x00E451AA3EB62A15), UINT64_C(0x540D28386266DB18),
+		UINT64_C(0xA936A28E8717C80F), UINT64_C(0xFDDFDB1CDBC73902),
+		UINT64_C(0xD1BB2526F56E5B43), UINT64_C(0x85525CB4A9BEAA4E),
+		UINT64_C(0x7869D6024CCFB959), UINT64_C(0x2C80AF90101F4854),
+		UINT64_C(0x10C66C44292381F2), UINT64_C(0x442F15D675F370FF),
+		UINT64_C(0xB9149F60908263E8), UINT64_C(0xEDFDE6F2CC5292E5),
+		UINT64_C(0xE1DD6314CDD0A76A), UINT64_C(0xB5341A8691005667),
+		UINT64_C(0x480F903074714570), UINT64_C(0x1CE6E9A228A1B47D),
+		UINT64_C(0x20A02A76119D7DDB), UINT64_C(0x744953E44D4D8CD6),
+		UINT64_C(0x8972D952A83C9FC1), UINT64_C(0xDD9BA0C0F4EC6ECC),
+		UINT64_C(0xF1FF5EFADA450C8D), UINT64_C(0xA51627688695FD80),
+		UINT64_C(0x582DADDE63E4EE97), UINT64_C(0x0CC4D44C3F341F9A),
+		UINT64_C(0x308217980608D63C), UINT64_C(0x646B6E0A5AD82731),
+		UINT64_C(0x9950E4BCBFA93426), UINT64_C(0xCDB99D2EE379C52B),
+		UINT64_C(0x90FB71CAD654A0F5), UINT64_C(0xC41208588A8451F8),
+		UINT64_C(0x392982EE6FF542EF), UINT64_C(0x6DC0FB7C3325B3E2),
+		UINT64_C(0x518638A80A197A44), UINT64_C(0x056F413A56C98B49),
+		UINT64_C(0xF854CB8CB3B8985E), UINT64_C(0xACBDB21EEF686953),
+		UINT64_C(0x80D94C24C1C10B12), UINT64_C(0xD43035B69D11FA1F),
+		UINT64_C(0x290BBF007860E908), UINT64_C(0x7DE2C69224B01805),
+		UINT64_C(0x41A405461D8CD1A3), UINT64_C(0x154D7CD4415C20AE),
+		UINT64_C(0xE876F662A42D33B9), UINT64_C(0xBC9F8FF0F8FDC2B4),
+		UINT64_C(0xB0BF0A16F97FF73B), UINT64_C(0xE4567384A5AF0636),
+		UINT64_C(0x196DF93240DE1521), UINT64_C(0x4D8480A01C0EE42C),
+		UINT64_C(0x71C2437425322D8A), UINT64_C(0x252B3AE679E2DC87),
+		UINT64_C(0xD810B0509C93CF90), UINT64_C(0x8CF9C9C2C0433E9D),
+		UINT64_C(0xA09D37F8EEEA5CDC), UINT64_C(0xF4744E6AB23AADD1),
+		UINT64_C(0x094FC4DC574BBEC6), UINT64_C(0x5DA6BD4E0B9B4FCB),
+		UINT64_C(0x61E07E9A32A7866D), UINT64_C(0x350907086E777760),
+		UINT64_C(0xC8328DBE8B066477), UINT64_C(0x9CDBF42CD7D6957A),
+		UINT64_C(0xD073867288020F69), UINT64_C(0x849AFFE0D4D2FE64),
+		UINT64_C(0x79A1755631A3ED73), UINT64_C(0x2D480CC46D731C7E),
+		UINT64_C(0x110ECF10544FD5D8), UINT64_C(0x45E7B682089F24D5),
+		UINT64_C(0xB8DC3C34EDEE37C2), UINT64_C(0xEC3545A6B13EC6CF),
+		UINT64_C(0xC051BB9C9F97A48E), UINT64_C(0x94B8C20EC3475583),
+		UINT64_C(0x698348B826364694), UINT64_C(0x3D6A312A7AE6B799),
+		UINT64_C(0x012CF2FE43DA7E3F), UINT64_C(0x55C58B6C1F0A8F32),
+		UINT64_C(0xA8FE01DAFA7B9C25), UINT64_C(0xFC177848A6AB6D28),
+		UINT64_C(0xF037FDAEA72958A7), UINT64_C(0xA4DE843CFBF9A9AA),
+		UINT64_C(0x59E50E8A1E88BABD), UINT64_C(0x0D0C771842584BB0),
+		UINT64_C(0x314AB4CC7B648216), UINT64_C(0x65A3CD5E27B4731B),
+		UINT64_C(0x989847E8C2C5600C), UINT64_C(0xCC713E7A9E159101),
+		UINT64_C(0xE015C040B0BCF340), UINT64_C(0xB4FCB9D2EC6C024D),
+		UINT64_C(0x49C73364091D115A), UINT64_C(0x1D2E4AF655CDE057),
+		UINT64_C(0x216889226CF129F1), UINT64_C(0x7581F0B03021D8FC),
+		UINT64_C(0x88BA7A06D550CBEB), UINT64_C(0xDC53039489803AE6),
+		UINT64_C(0x11EA9EBA6AF9FFCD), UINT64_C(0x4503E72836290EC0),
+		UINT64_C(0xB8386D9ED3581DD7), UINT64_C(0xECD1140C8F88ECDA),
+		UINT64_C(0xD097D7D8B6B4257C), UINT64_C(0x847EAE4AEA64D471),
+		UINT64_C(0x794524FC0F15C766), UINT64_C(0x2DAC5D6E53C5366B),
+		UINT64_C(0x01C8A3547D6C542A), UINT64_C(0x5521DAC621BCA527),
+		UINT64_C(0xA81A5070C4CDB630), UINT64_C(0xFCF329E2981D473D),
+		UINT64_C(0xC0B5EA36A1218E9B), UINT64_C(0x945C93A4FDF17F96),
+		UINT64_C(0x6967191218806C81), UINT64_C(0x3D8E608044509D8C),
+		UINT64_C(0x31AEE56645D2A803), UINT64_C(0x65479CF41902590E),
+		UINT64_C(0x987C1642FC734A19), UINT64_C(0xCC956FD0A0A3BB14),
+		UINT64_C(0xF0D3AC04999F72B2), UINT64_C(0xA43AD596C54F83BF),
+		UINT64_C(0x59015F20203E90A8), UINT64_C(0x0DE826B27CEE61A5),
+		UINT64_C(0x218CD888524703E4), UINT64_C(0x7565A11A0E97F2E9),
+		UINT64_C(0x885E2BACEBE6E1FE), UINT64_C(0xDCB7523EB73610F3),
+		UINT64_C(0xE0F191EA8E0AD955), UINT64_C(0xB418E878D2DA2858),
+		UINT64_C(0x492362CE37AB3B4F), UINT64_C(0x1DCA1B5C6B7BCA42),
+		UINT64_C(0x5162690234AF5051), UINT64_C(0x058B1090687FA15C),
+		UINT64_C(0xF8B09A268D0EB24B), UINT64_C(0xAC59E3B4D1DE4346),
+		UINT64_C(0x901F2060E8E28AE0), UINT64_C(0xC4F659F2B4327BED),
+		UINT64_C(0x39CDD344514368FA), UINT64_C(0x6D24AAD60D9399F7),
+		UINT64_C(0x414054EC233AFBB6), UINT64_C(0x15A92D7E7FEA0ABB),
+		UINT64_C(0xE892A7C89A9B19AC), UINT64_C(0xBC7BDE5AC64BE8A1),
+		UINT64_C(0x803D1D8EFF772107), UINT64_C(0xD4D4641CA3A7D00A),
+		UINT64_C(0x29EFEEAA46D6C31D), UINT64_C(0x7D0697381A063210),
+		UINT64_C(0x712612DE1B84079F), UINT64_C(0x25CF6B4C4754F692),
+		UINT64_C(0xD8F4E1FAA225E585), UINT64_C(0x8C1D9868FEF51488),
+		UINT64_C(0xB05B5BBCC7C9DD2E), UINT64_C(0xE4B2222E9B192C23),
+		UINT64_C(0x1989A8987E683F34), UINT64_C(0x4D60D10A22B8CE39),
+		UINT64_C(0x61042F300C11AC78), UINT64_C(0x35ED56A250C15D75),
+		UINT64_C(0xC8D6DC14B5B04E62), UINT64_C(0x9C3FA586E960BF6F),
+		UINT64_C(0xA0796652D05C76C9), UINT64_C(0xF4901FC08C8C87C4),
+		UINT64_C(0x09AB957669FD94D3), UINT64_C(0x5D42ECE4352D65DE)
+	}, {
+		UINT64_C(0x0000000000000000), UINT64_C(0x3F0BE14A916A6DCB),
+		UINT64_C(0x7E17C29522D4DB96), UINT64_C(0x411C23DFB3BEB65D),
+		UINT64_C(0xFC2F852A45A9B72C), UINT64_C(0xC3246460D4C3DAE7),
+		UINT64_C(0x823847BF677D6CBA), UINT64_C(0xBD33A6F5F6170171),
+		UINT64_C(0x6A87A57F245D70DD), UINT64_C(0x558C4435B5371D16),
+		UINT64_C(0x149067EA0689AB4B), UINT64_C(0x2B9B86A097E3C680),
+		UINT64_C(0x96A8205561F4C7F1), UINT64_C(0xA9A3C11FF09EAA3A),
+		UINT64_C(0xE8BFE2C043201C67), UINT64_C(0xD7B4038AD24A71AC),
+		UINT64_C(0xD50F4AFE48BAE1BA), UINT64_C(0xEA04ABB4D9D08C71),
+		UINT64_C(0xAB18886B6A6E3A2C), UINT64_C(0x94136921FB0457E7),
+		UINT64_C(0x2920CFD40D135696), UINT64_C(0x162B2E9E9C793B5D),
+		UINT64_C(0x57370D412FC78D00), UINT64_C(0x683CEC0BBEADE0CB),
+		UINT64_C(0xBF88EF816CE79167), UINT64_C(0x80830ECBFD8DFCAC),
+		UINT64_C(0xC19F2D144E334AF1), UINT64_C(0xFE94CC5EDF59273A),
+		UINT64_C(0x43A76AAB294E264B), UINT64_C(0x7CAC8BE1B8244B80),
+		UINT64_C(0x3DB0A83E0B9AFDDD), UINT64_C(0x02BB49749AF09016),
+		UINT64_C(0x38C63AD73E7BDDF1), UINT64_C(0x07CDDB9DAF11B03A),
+		UINT64_C(0x46D1F8421CAF0667), UINT64_C(0x79DA19088DC56BAC),
+		UINT64_C(0xC4E9BFFD7BD26ADD), UINT64_C(0xFBE25EB7EAB80716),
+		UINT64_C(0xBAFE7D685906B14B), UINT64_C(0x85F59C22C86CDC80),
+		UINT64_C(0x52419FA81A26AD2C), UINT64_C(0x6D4A7EE28B4CC0E7),
+		UINT64_C(0x2C565D3D38F276BA), UINT64_C(0x135DBC77A9981B71),
+		UINT64_C(0xAE6E1A825F8F1A00), UINT64_C(0x9165FBC8CEE577CB),
+		UINT64_C(0xD079D8177D5BC196), UINT64_C(0xEF72395DEC31AC5D),
+		UINT64_C(0xEDC9702976C13C4B), UINT64_C(0xD2C29163E7AB5180),
+		UINT64_C(0x93DEB2BC5415E7DD), UINT64_C(0xACD553F6C57F8A16),
+		UINT64_C(0x11E6F50333688B67), UINT64_C(0x2EED1449A202E6AC),
+		UINT64_C(0x6FF1379611BC50F1), UINT64_C(0x50FAD6DC80D63D3A),
+		UINT64_C(0x874ED556529C4C96), UINT64_C(0xB845341CC3F6215D),
+		UINT64_C(0xF95917C370489700), UINT64_C(0xC652F689E122FACB),
+		UINT64_C(0x7B61507C1735FBBA), UINT64_C(0x446AB136865F9671),
+		UINT64_C(0x057692E935E1202C), UINT64_C(0x3A7D73A3A48B4DE7),
+		UINT64_C(0x718C75AE7CF7BBE2), UINT64_C(0x4E8794E4ED9DD629),
+		UINT64_C(0x0F9BB73B5E236074), UINT64_C(0x30905671CF490DBF),
+		UINT64_C(0x8DA3F084395E0CCE), UINT64_C(0xB2A811CEA8346105),
+		UINT64_C(0xF3B432111B8AD758), UINT64_C(0xCCBFD35B8AE0BA93),
+		UINT64_C(0x1B0BD0D158AACB3F), UINT64_C(0x2400319BC9C0A6F4),
+		UINT64_C(0x651C12447A7E10A9), UINT64_C(0x5A17F30EEB147D62),
+		UINT64_C(0xE72455FB1D037C13), UINT64_C(0xD82FB4B18C6911D8),
+		UINT64_C(0x9933976E3FD7A785), UINT64_C(0xA6387624AEBDCA4E),
+		UINT64_C(0xA4833F50344D5A58), UINT64_C(0x9B88DE1AA5273793),
+		UINT64_C(0xDA94FDC5169981CE), UINT64_C(0xE59F1C8F87F3EC05),
+		UINT64_C(0x58ACBA7A71E4ED74), UINT64_C(0x67A75B30E08E80BF),
+		UINT64_C(0x26BB78EF533036E2), UINT64_C(0x19B099A5C25A5B29),
+		UINT64_C(0xCE049A2F10102A85), UINT64_C(0xF10F7B65817A474E),
+		UINT64_C(0xB01358BA32C4F113), UINT64_C(0x8F18B9F0A3AE9CD8),
+		UINT64_C(0x322B1F0555B99DA9), UINT64_C(0x0D20FE4FC4D3F062),
+		UINT64_C(0x4C3CDD90776D463F), UINT64_C(0x73373CDAE6072BF4),
+		UINT64_C(0x494A4F79428C6613), UINT64_C(0x7641AE33D3E60BD8),
+		UINT64_C(0x375D8DEC6058BD85), UINT64_C(0x08566CA6F132D04E),
+		UINT64_C(0xB565CA530725D13F), UINT64_C(0x8A6E2B19964FBCF4),
+		UINT64_C(0xCB7208C625F10AA9), UINT64_C(0xF479E98CB49B6762),
+		UINT64_C(0x23CDEA0666D116CE), UINT64_C(0x1CC60B4CF7BB7B05),
+		UINT64_C(0x5DDA28934405CD58), UINT64_C(0x62D1C9D9D56FA093),
+		UINT64_C(0xDFE26F2C2378A1E2), UINT64_C(0xE0E98E66B212CC29),
+		UINT64_C(0xA1F5ADB901AC7A74), UINT64_C(0x9EFE4CF390C617BF),
+		UINT64_C(0x9C4505870A3687A9), UINT64_C(0xA34EE4CD9B5CEA62),
+		UINT64_C(0xE252C71228E25C3F), UINT64_C(0xDD592658B98831F4),
+		UINT64_C(0x606A80AD4F9F3085), UINT64_C(0x5F6161E7DEF55D4E),
+		UINT64_C(0x1E7D42386D4BEB13), UINT64_C(0x2176A372FC2186D8),
+		UINT64_C(0xF6C2A0F82E6BF774), UINT64_C(0xC9C941B2BF019ABF),
+		UINT64_C(0x88D5626D0CBF2CE2), UINT64_C(0xB7DE83279DD54129),
+		UINT64_C(0x0AED25D26BC24058), UINT64_C(0x35E6C498FAA82D93),
+		UINT64_C(0x74FAE74749169BCE), UINT64_C(0x4BF1060DD87CF605),
+		UINT64_C(0xE318EB5CF9EF77C4), UINT64_C(0xDC130A1668851A0F),
+		UINT64_C(0x9D0F29C9DB3BAC52), UINT64_C(0xA204C8834A51C199),
+		UINT64_C(0x1F376E76BC46C0E8), UINT64_C(0x203C8F3C2D2CAD23),
+		UINT64_C(0x6120ACE39E921B7E), UINT64_C(0x5E2B4DA90FF876B5),
+		UINT64_C(0x899F4E23DDB20719), UINT64_C(0xB694AF694CD86AD2),
+		UINT64_C(0xF7888CB6FF66DC8F), UINT64_C(0xC8836DFC6E0CB144),
+		UINT64_C(0x75B0CB09981BB035), UINT64_C(0x4ABB2A430971DDFE),
+		UINT64_C(0x0BA7099CBACF6BA3), UINT64_C(0x34ACE8D62BA50668),
+		UINT64_C(0x3617A1A2B155967E), UINT64_C(0x091C40E8203FFBB5),
+		UINT64_C(0x4800633793814DE8), UINT64_C(0x770B827D02EB2023),
+		UINT64_C(0xCA382488F4FC2152), UINT64_C(0xF533C5C265964C99),
+		UINT64_C(0xB42FE61DD628FAC4), UINT64_C(0x8B2407574742970F),
+		UINT64_C(0x5C9004DD9508E6A3), UINT64_C(0x639BE59704628B68),
+		UINT64_C(0x2287C648B7DC3D35), UINT64_C(0x1D8C270226B650FE),
+		UINT64_C(0xA0BF81F7D0A1518F), UINT64_C(0x9FB460BD41CB3C44),
+		UINT64_C(0xDEA84362F2758A19), UINT64_C(0xE1A3A228631FE7D2),
+		UINT64_C(0xDBDED18BC794AA35), UINT64_C(0xE4D530C156FEC7FE),
+		UINT64_C(0xA5C9131EE54071A3), UINT64_C(0x9AC2F254742A1C68),
+		UINT64_C(0x27F154A1823D1D19), UINT64_C(0x18FAB5EB135770D2),
+		UINT64_C(0x59E69634A0E9C68F), UINT64_C(0x66ED777E3183AB44),
+		UINT64_C(0xB15974F4E3C9DAE8), UINT64_C(0x8E5295BE72A3B723),
+		UINT64_C(0xCF4EB661C11D017E), UINT64_C(0xF045572B50776CB5),
+		UINT64_C(0x4D76F1DEA6606DC4), UINT64_C(0x727D1094370A000F),
+		UINT64_C(0x3361334B84B4B652), UINT64_C(0x0C6AD20115DEDB99),
+		UINT64_C(0x0ED19B758F2E4B8F), UINT64_C(0x31DA7A3F1E442644),
+		UINT64_C(0x70C659E0ADFA9019), UINT64_C(0x4FCDB8AA3C90FDD2),
+		UINT64_C(0xF2FE1E5FCA87FCA3), UINT64_C(0xCDF5FF155BED9168),
+		UINT64_C(0x8CE9DCCAE8532735), UINT64_C(0xB3E23D8079394AFE),
+		UINT64_C(0x64563E0AAB733B52), UINT64_C(0x5B5DDF403A195699),
+		UINT64_C(0x1A41FC9F89A7E0C4), UINT64_C(0x254A1DD518CD8D0F),
+		UINT64_C(0x9879BB20EEDA8C7E), UINT64_C(0xA7725A6A7FB0E1B5),
+		UINT64_C(0xE66E79B5CC0E57E8), UINT64_C(0xD96598FF5D643A23),
+		UINT64_C(0x92949EF28518CC26), UINT64_C(0xAD9F7FB81472A1ED),
+		UINT64_C(0xEC835C67A7CC17B0), UINT64_C(0xD388BD2D36A67A7B),
+		UINT64_C(0x6EBB1BD8C0B17B0A), UINT64_C(0x51B0FA9251DB16C1),
+		UINT64_C(0x10ACD94DE265A09C), UINT64_C(0x2FA73807730FCD57),
+		UINT64_C(0xF8133B8DA145BCFB), UINT64_C(0xC718DAC7302FD130),
+		UINT64_C(0x8604F9188391676D), UINT64_C(0xB90F185212FB0AA6),
+		UINT64_C(0x043CBEA7E4EC0BD7), UINT64_C(0x3B375FED7586661C),
+		UINT64_C(0x7A2B7C32C638D041), UINT64_C(0x45209D785752BD8A),
+		UINT64_C(0x479BD40CCDA22D9C), UINT64_C(0x789035465CC84057),
+		UINT64_C(0x398C1699EF76F60A), UINT64_C(0x0687F7D37E1C9BC1),
+		UINT64_C(0xBBB45126880B9AB0), UINT64_C(0x84BFB06C1961F77B),
+		UINT64_C(0xC5A393B3AADF4126), UINT64_C(0xFAA872F93BB52CED),
+		UINT64_C(0x2D1C7173E9FF5D41), UINT64_C(0x121790397895308A),
+		UINT64_C(0x530BB3E6CB2B86D7), UINT64_C(0x6C0052AC5A41EB1C),
+		UINT64_C(0xD133F459AC56EA6D), UINT64_C(0xEE3815133D3C87A6),
+		UINT64_C(0xAF2436CC8E8231FB), UINT64_C(0x902FD7861FE85C30),
+		UINT64_C(0xAA52A425BB6311D7), UINT64_C(0x9559456F2A097C1C),
+		UINT64_C(0xD44566B099B7CA41), UINT64_C(0xEB4E87FA08DDA78A),
+		UINT64_C(0x567D210FFECAA6FB), UINT64_C(0x6976C0456FA0CB30),
+		UINT64_C(0x286AE39ADC1E7D6D), UINT64_C(0x176102D04D7410A6),
+		UINT64_C(0xC0D5015A9F3E610A), UINT64_C(0xFFDEE0100E540CC1),
+		UINT64_C(0xBEC2C3CFBDEABA9C), UINT64_C(0x81C922852C80D757),
+		UINT64_C(0x3CFA8470DA97D626), UINT64_C(0x03F1653A4BFDBBED),
+		UINT64_C(0x42ED46E5F8430DB0), UINT64_C(0x7DE6A7AF6929607B),
+		UINT64_C(0x7F5DEEDBF3D9F06D), UINT64_C(0x40560F9162B39DA6),
+		UINT64_C(0x014A2C4ED10D2BFB), UINT64_C(0x3E41CD0440674630),
+		UINT64_C(0x83726BF1B6704741), UINT64_C(0xBC798ABB271A2A8A),
+		UINT64_C(0xFD65A96494A49CD7), UINT64_C(0xC26E482E05CEF11C),
+		UINT64_C(0x15DA4BA4D78480B0), UINT64_C(0x2AD1AAEE46EEED7B),
+		UINT64_C(0x6BCD8931F5505B26), UINT64_C(0x54C6687B643A36ED),
+		UINT64_C(0xE9F5CE8E922D379C), UINT64_C(0xD6FE2FC403475A57),
+		UINT64_C(0x97E20C1BB0F9EC0A), UINT64_C(0xA8E9ED51219381C1)
+	}, {
+		UINT64_C(0x0000000000000000), UINT64_C(0x1DEE8A5E222CA1DC),
+		UINT64_C(0x3BDD14BC445943B8), UINT64_C(0x26339EE26675E264),
+		UINT64_C(0x77BA297888B28770), UINT64_C(0x6A54A326AA9E26AC),
+		UINT64_C(0x4C673DC4CCEBC4C8), UINT64_C(0x5189B79AEEC76514),
+		UINT64_C(0xEF7452F111650EE0), UINT64_C(0xF29AD8AF3349AF3C),
+		UINT64_C(0xD4A9464D553C4D58), UINT64_C(0xC947CC137710EC84),
+		UINT64_C(0x98CE7B8999D78990), UINT64_C(0x8520F1D7BBFB284C),
+		UINT64_C(0xA3136F35DD8ECA28), UINT64_C(0xBEFDE56BFFA26BF4),
+		UINT64_C(0x4C300AC98DC40345), UINT64_C(0x51DE8097AFE8A299),
+		UINT64_C(0x77ED1E75C99D40FD), UINT64_C(0x6A03942BEBB1E121),
+		UINT64_C(0x3B8A23B105768435), UINT64_C(0x2664A9EF275A25E9),
+		UINT64_C(0x0057370D412FC78D), UINT64_C(0x1DB9BD5363036651),
+		UINT64_C(0xA34458389CA10DA5), UINT64_C(0xBEAAD266BE8DAC79),
+		UINT64_C(0x98994C84D8F84E1D), UINT64_C(0x8577C6DAFAD4EFC1),
+		UINT64_C(0xD4FE714014138AD5), UINT64_C(0xC910FB1E363F2B09),
+		UINT64_C(0xEF2365FC504AC96D), UINT64_C(0xF2CDEFA2726668B1),
+		UINT64_C(0x986015931B88068A), UINT64_C(0x858E9FCD39A4A756),
+		UINT64_C(0xA3BD012F5FD14532), UINT64_C(0xBE538B717DFDE4EE),
+		UINT64_C(0xEFDA3CEB933A81FA), UINT64_C(0xF234B6B5B1162026),
+		UINT64_C(0xD4072857D763C242), UINT64_C(0xC9E9A209F54F639E),
+		UINT64_C(0x771447620AED086A), UINT64_C(0x6AFACD3C28C1A9B6),
+		UINT64_C(0x4CC953DE4EB44BD2), UINT64_C(0x5127D9806C98EA0E),
+		UINT64_C(0x00AE6E1A825F8F1A), UINT64_C(0x1D40E444A0732EC6),
+		UINT64_C(0x3B737AA6C606CCA2), UINT64_C(0x269DF0F8E42A6D7E),
+		UINT64_C(0xD4501F5A964C05CF), UINT64_C(0xC9BE9504B460A413),
+		UINT64_C(0xEF8D0BE6D2154677), UINT64_C(0xF26381B8F039E7AB),
+		UINT64_C(0xA3EA36221EFE82BF), UINT64_C(0xBE04BC7C3CD22363),
+		UINT64_C(0x9837229E5AA7C107), UINT64_C(0x85D9A8C0788B60DB),
+		UINT64_C(0x3B244DAB87290B2F), UINT64_C(0x26CAC7F5A505AAF3),
+		UINT64_C(0x00F95917C3704897), UINT64_C(0x1D17D349E15CE94B),
+		UINT64_C(0x4C9E64D30F9B8C5F), UINT64_C(0x5170EE8D2DB72D83),
+		UINT64_C(0x7743706F4BC2CFE7), UINT64_C(0x6AADFA3169EE6E3B),
+		UINT64_C(0xA218840D981E1391), UINT64_C(0xBFF60E53BA32B24D),
+		UINT64_C(0x99C590B1DC475029), UINT64_C(0x842B1AEFFE6BF1F5),
+		UINT64_C(0xD5A2AD7510AC94E1), UINT64_C(0xC84C272B3280353D),
+		UINT64_C(0xEE7FB9C954F5D759), UINT64_C(0xF391339776D97685),
+		UINT64_C(0x4D6CD6FC897B1D71), UINT64_C(0x50825CA2AB57BCAD),
+		UINT64_C(0x76B1C240CD225EC9), UINT64_C(0x6B5F481EEF0EFF15),
+		UINT64_C(0x3AD6FF8401C99A01), UINT64_C(0x273875DA23E53BDD),
+		UINT64_C(0x010BEB384590D9B9), UINT64_C(0x1CE5616667BC7865),
+		UINT64_C(0xEE288EC415DA10D4), UINT64_C(0xF3C6049A37F6B108),
+		UINT64_C(0xD5F59A785183536C), UINT64_C(0xC81B102673AFF2B0),
+		UINT64_C(0x9992A7BC9D6897A4), UINT64_C(0x847C2DE2BF443678),
+		UINT64_C(0xA24FB300D931D41C), UINT64_C(0xBFA1395EFB1D75C0),
+		UINT64_C(0x015CDC3504BF1E34), UINT64_C(0x1CB2566B2693BFE8),
+		UINT64_C(0x3A81C88940E65D8C), UINT64_C(0x276F42D762CAFC50),
+		UINT64_C(0x76E6F54D8C0D9944), UINT64_C(0x6B087F13AE213898),
+		UINT64_C(0x4D3BE1F1C854DAFC), UINT64_C(0x50D56BAFEA787B20),
+		UINT64_C(0x3A78919E8396151B), UINT64_C(0x27961BC0A1BAB4C7),
+		UINT64_C(0x01A58522C7CF56A3), UINT64_C(0x1C4B0F7CE5E3F77F),
+		UINT64_C(0x4DC2B8E60B24926B), UINT64_C(0x502C32B8290833B7),
+		UINT64_C(0x761FAC5A4F7DD1D3), UINT64_C(0x6BF126046D51700F),
+		UINT64_C(0xD50CC36F92F31BFB), UINT64_C(0xC8E24931B0DFBA27),
+		UINT64_C(0xEED1D7D3D6AA5843), UINT64_C(0xF33F5D8DF486F99F),
+		UINT64_C(0xA2B6EA171A419C8B), UINT64_C(0xBF586049386D3D57),
+		UINT64_C(0x996BFEAB5E18DF33), UINT64_C(0x848574F57C347EEF),
+		UINT64_C(0x76489B570E52165E), UINT64_C(0x6BA611092C7EB782),
+		UINT64_C(0x4D958FEB4A0B55E6), UINT64_C(0x507B05B56827F43A),
+		UINT64_C(0x01F2B22F86E0912E), UINT64_C(0x1C1C3871A4CC30F2),
+		UINT64_C(0x3A2FA693C2B9D296), UINT64_C(0x27C12CCDE095734A),
+		UINT64_C(0x993CC9A61F3718BE), UINT64_C(0x84D243F83D1BB962),
+		UINT64_C(0xA2E1DD1A5B6E5B06), UINT64_C(0xBF0F57447942FADA),
+		UINT64_C(0xEE86E0DE97859FCE), UINT64_C(0xF3686A80B5A93E12),
+		UINT64_C(0xD55BF462D3DCDC76), UINT64_C(0xC8B57E3CF1F07DAA),
+		UINT64_C(0xD6E9A7309F3239A7), UINT64_C(0xCB072D6EBD1E987B),
+		UINT64_C(0xED34B38CDB6B7A1F), UINT64_C(0xF0DA39D2F947DBC3),
+		UINT64_C(0xA1538E481780BED7), UINT64_C(0xBCBD041635AC1F0B),
+		UINT64_C(0x9A8E9AF453D9FD6F), UINT64_C(0x876010AA71F55CB3),
+		UINT64_C(0x399DF5C18E573747), UINT64_C(0x24737F9FAC7B969B),
+		UINT64_C(0x0240E17DCA0E74FF), UINT64_C(0x1FAE6B23E822D523),
+		UINT64_C(0x4E27DCB906E5B037), UINT64_C(0x53C956E724C911EB),
+		UINT64_C(0x75FAC80542BCF38F), UINT64_C(0x6814425B60905253),
+		UINT64_C(0x9AD9ADF912F63AE2), UINT64_C(0x873727A730DA9B3E),
+		UINT64_C(0xA104B94556AF795A), UINT64_C(0xBCEA331B7483D886),
+		UINT64_C(0xED6384819A44BD92), UINT64_C(0xF08D0EDFB8681C4E),
+		UINT64_C(0xD6BE903DDE1DFE2A), UINT64_C(0xCB501A63FC315FF6),
+		UINT64_C(0x75ADFF0803933402), UINT64_C(0x6843755621BF95DE),
+		UINT64_C(0x4E70EBB447CA77BA), UINT64_C(0x539E61EA65E6D666),
+		UINT64_C(0x0217D6708B21B372), UINT64_C(0x1FF95C2EA90D12AE),
+		UINT64_C(0x39CAC2CCCF78F0CA), UINT64_C(0x24244892ED545116),
+		UINT64_C(0x4E89B2A384BA3F2D), UINT64_C(0x536738FDA6969EF1),
+		UINT64_C(0x7554A61FC0E37C95), UINT64_C(0x68BA2C41E2CFDD49),
+		UINT64_C(0x39339BDB0C08B85D), UINT64_C(0x24DD11852E241981),
+		UINT64_C(0x02EE8F674851FBE5), UINT64_C(0x1F0005396A7D5A39),
+		UINT64_C(0xA1FDE05295DF31CD), UINT64_C(0xBC136A0CB7F39011),
+		UINT64_C(0x9A20F4EED1867275), UINT64_C(0x87CE7EB0F3AAD3A9),
+		UINT64_C(0xD647C92A1D6DB6BD), UINT64_C(0xCBA943743F411761),
+		UINT64_C(0xED9ADD965934F505), UINT64_C(0xF07457C87B1854D9),
+		UINT64_C(0x02B9B86A097E3C68), UINT64_C(0x1F5732342B529DB4),
+		UINT64_C(0x3964ACD64D277FD0), UINT64_C(0x248A26886F0BDE0C),
+		UINT64_C(0x7503911281CCBB18), UINT64_C(0x68ED1B4CA3E01AC4),
+		UINT64_C(0x4EDE85AEC595F8A0), UINT64_C(0x53300FF0E7B9597C),
+		UINT64_C(0xEDCDEA9B181B3288), UINT64_C(0xF02360C53A379354),
+		UINT64_C(0xD610FE275C427130), UINT64_C(0xCBFE74797E6ED0EC),
+		UINT64_C(0x9A77C3E390A9B5F8), UINT64_C(0x879949BDB2851424),
+		UINT64_C(0xA1AAD75FD4F0F640), UINT64_C(0xBC445D01F6DC579C),
+		UINT64_C(0x74F1233D072C2A36), UINT64_C(0x691FA96325008BEA),
+		UINT64_C(0x4F2C37814375698E), UINT64_C(0x52C2BDDF6159C852),
+		UINT64_C(0x034B0A458F9EAD46), UINT64_C(0x1EA5801BADB20C9A),
+		UINT64_C(0x38961EF9CBC7EEFE), UINT64_C(0x257894A7E9EB4F22),
+		UINT64_C(0x9B8571CC164924D6), UINT64_C(0x866BFB923465850A),
+		UINT64_C(0xA05865705210676E), UINT64_C(0xBDB6EF2E703CC6B2),
+		UINT64_C(0xEC3F58B49EFBA3A6), UINT64_C(0xF1D1D2EABCD7027A),
+		UINT64_C(0xD7E24C08DAA2E01E), UINT64_C(0xCA0CC656F88E41C2),
+		UINT64_C(0x38C129F48AE82973), UINT64_C(0x252FA3AAA8C488AF),
+		UINT64_C(0x031C3D48CEB16ACB), UINT64_C(0x1EF2B716EC9DCB17),
+		UINT64_C(0x4F7B008C025AAE03), UINT64_C(0x52958AD220760FDF),
+		UINT64_C(0x74A614304603EDBB), UINT64_C(0x69489E6E642F4C67),
+		UINT64_C(0xD7B57B059B8D2793), UINT64_C(0xCA5BF15BB9A1864F),
+		UINT64_C(0xEC686FB9DFD4642B), UINT64_C(0xF186E5E7FDF8C5F7),
+		UINT64_C(0xA00F527D133FA0E3), UINT64_C(0xBDE1D8233113013F),
+		UINT64_C(0x9BD246C15766E35B), UINT64_C(0x863CCC9F754A4287),
+		UINT64_C(0xEC9136AE1CA42CBC), UINT64_C(0xF17FBCF03E888D60),
+		UINT64_C(0xD74C221258FD6F04), UINT64_C(0xCAA2A84C7AD1CED8),
+		UINT64_C(0x9B2B1FD69416ABCC), UINT64_C(0x86C59588B63A0A10),
+		UINT64_C(0xA0F60B6AD04FE874), UINT64_C(0xBD188134F26349A8),
+		UINT64_C(0x03E5645F0DC1225C), UINT64_C(0x1E0BEE012FED8380),
+		UINT64_C(0x383870E3499861E4), UINT64_C(0x25D6FABD6BB4C038),
+		UINT64_C(0x745F4D278573A52C), UINT64_C(0x69B1C779A75F04F0),
+		UINT64_C(0x4F82599BC12AE694), UINT64_C(0x526CD3C5E3064748),
+		UINT64_C(0xA0A13C6791602FF9), UINT64_C(0xBD4FB639B34C8E25),
+		UINT64_C(0x9B7C28DBD5396C41), UINT64_C(0x8692A285F715CD9D),
+		UINT64_C(0xD71B151F19D2A889), UINT64_C(0xCAF59F413BFE0955),
+		UINT64_C(0xECC601A35D8BEB31), UINT64_C(0xF1288BFD7FA74AED),
+		UINT64_C(0x4FD56E9680052119), UINT64_C(0x523BE4C8A22980C5),
+		UINT64_C(0x74087A2AC45C62A1), UINT64_C(0x69E6F074E670C37D),
+		UINT64_C(0x386F47EE08B7A669), UINT64_C(0x2581CDB02A9B07B5),
+		UINT64_C(0x03B253524CEEE5D1), UINT64_C(0x1E5CD90C6EC2440D)
+	}
+};
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_tablegen.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_tablegen.c
new file mode 100644
index 00000000000..2035127a112
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_tablegen.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       crc64_tablegen.c
+/// \brief      Generate crc64_table_le.h and crc64_table_be.h
+///
+/// Compiling: gcc -std=c99 -o crc64_tablegen crc64_tablegen.c
+/// Add -DWORDS_BIGENDIAN to generate big endian table.
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include 
+#include "../../common/tuklib_integer.h"
+
+
+static uint64_t crc64_table[4][256];
+
+
+extern void
+init_crc64_table(void)
+{
+	static const uint64_t poly64 = UINT64_C(0xC96C5795D7870F42);
+
+	for (size_t s = 0; s < 4; ++s) {
+		for (size_t b = 0; b < 256; ++b) {
+			uint64_t r = s == 0 ? b : crc64_table[s - 1][b];
+
+			for (size_t i = 0; i < 8; ++i) {
+				if (r & 1)
+					r = (r >> 1) ^ poly64;
+				else
+					r >>= 1;
+			}
+
+			crc64_table[s][b] = r;
+		}
+	}
+
+#ifdef WORDS_BIGENDIAN
+	for (size_t s = 0; s < 4; ++s)
+		for (size_t b = 0; b < 256; ++b)
+			crc64_table[s][b] = byteswap64(crc64_table[s][b]);
+#endif
+
+	return;
+}
+
+
+static void
+print_crc64_table(void)
+{
+	// Split the SPDX string so that it won't accidentally match
+	// when tools search for the string.
+	printf("// SPDX" "-License-Identifier" ": 0BSD\n\n"
+		"// This file has been generated by crc64_tablegen.c.\n\n"
+		"const uint64_t lzma_crc64_table[4][256] = {\n\t{");
+
+	for (size_t s = 0; s < 4; ++s) {
+		for (size_t b = 0; b < 256; ++b) {
+			if ((b % 2) == 0)
+				printf("\n\t\t");
+
+			printf("UINT64_C(0x%016" PRIX64 ")",
+					crc64_table[s][b]);
+
+			if (b != 255)
+				printf(",%s", (b+1) % 2 == 0 ? "" : " ");
+		}
+
+		if (s == 3)
+			printf("\n\t}\n};\n");
+		else
+			printf("\n\t}, {");
+	}
+
+	return;
+}
+
+
+int
+main(void)
+{
+	init_crc64_table();
+	print_crc64_table();
+	return 0;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_x86.S b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_x86.S
new file mode 100644
index 00000000000..47f608181ea
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc64_x86.S
@@ -0,0 +1,295 @@
+/* SPDX-License-Identifier: 0BSD */
+
+/*
+ * Speed-optimized CRC64 using slicing-by-four algorithm
+ *
+ * This uses only i386 instructions, but it is optimized for i686 and later
+ * (including e.g. Pentium II/III/IV, Athlon XP, and Core 2).
+ *
+ * Authors: Igor Pavlov (original CRC32 assembly code)
+ *          Lasse Collin (CRC64 adaptation of the modified CRC32 code)
+ *
+ * This code needs lzma_crc64_table, which can be created using the
+ * following C code:
+
+uint64_t lzma_crc64_table[4][256];
+
+void
+init_table(void)
+{
+	// ECMA-182
+	static const uint64_t poly64 = UINT64_C(0xC96C5795D7870F42);
+
+	for (size_t s = 0; s < 4; ++s) {
+		for (size_t b = 0; b < 256; ++b) {
+			uint64_t r = s == 0 ? b : lzma_crc64_table[s - 1][b];
+
+			for (size_t i = 0; i < 8; ++i) {
+				if (r & 1)
+					r = (r >> 1) ^ poly64;
+				else
+					r >>= 1;
+			}
+
+			lzma_crc64_table[s][b] = r;
+		}
+	}
+}
+
+ * The prototype of the CRC64 function:
+ * extern uint64_t lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc);
+ */
+
+/* When Intel CET is enabled, include  in assembly code to mark
+   Intel CET support.  */
+#ifdef __CET__
+# include 
+#else
+# define _CET_ENDBR
+#endif
+
+/*
+ * On some systems, the functions need to be prefixed. The prefix is
+ * usually an underscore.
+ */
+#ifndef __USER_LABEL_PREFIX__
+#	define __USER_LABEL_PREFIX__
+#endif
+#define MAKE_SYM_CAT(prefix, sym) prefix ## sym
+#define MAKE_SYM(prefix, sym) MAKE_SYM_CAT(prefix, sym)
+#define LZMA_CRC64 MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc64)
+#define LZMA_CRC64_TABLE MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc64_table)
+
+/*
+ * Solaris assembler doesn't have .p2align, and Darwin uses .align
+ * differently than GNU/Linux and Solaris.
+ */
+#if defined(__APPLE__) || defined(__MSDOS__)
+#	define ALIGN(pow2, abs) .align pow2
+#else
+#	define ALIGN(pow2, abs) .align abs
+#endif
+
+	.text
+	.globl	LZMA_CRC64
+
+#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) \
+		&& !defined(__MSDOS__)
+	.type	LZMA_CRC64, @function
+#endif
+
+	ALIGN(4, 16)
+LZMA_CRC64:
+	_CET_ENDBR
+	/*
+	 * Register usage:
+	 * %eax crc LSB
+	 * %edx crc MSB
+	 * %esi buf
+	 * %edi size or buf + size
+	 * %ebx lzma_crc64_table
+	 * %ebp Table index
+	 * %ecx Temporary
+	 */
+	pushl	%ebx
+	pushl	%esi
+	pushl	%edi
+	pushl	%ebp
+	movl	0x14(%esp), %esi /* buf */
+	movl	0x18(%esp), %edi /* size */
+	movl	0x1C(%esp), %eax /* crc LSB */
+	movl	0x20(%esp), %edx /* crc MSB */
+
+	/*
+	 * Store the address of lzma_crc64_table to %ebx. This is needed to
+	 * get position-independent code (PIC).
+	 *
+	 * The PIC macro is defined by libtool, while __PIC__ is defined
+	 * by GCC but only on some systems. Testing for both makes it simpler
+	 * to test this code without libtool, and keeps the code working also
+	 * when built with libtool but using something else than GCC.
+	 *
+	 * I understood that libtool may define PIC on Windows even though
+	 * the code in Windows DLLs is not PIC in sense that it is in ELF
+	 * binaries, so we need a separate check to always use the non-PIC
+	 * code on Windows.
+	 */
+#if (!defined(PIC) && !defined(__PIC__)) \
+		|| (defined(_WIN32) || defined(__CYGWIN__))
+	/* Not PIC */
+	movl	$ LZMA_CRC64_TABLE, %ebx
+#elif defined(__APPLE__)
+	/* Mach-O */
+	call	.L_get_pc
+.L_pic:
+	leal	.L_lzma_crc64_table$non_lazy_ptr-.L_pic(%ebx), %ebx
+	movl	(%ebx), %ebx
+#else
+	/* ELF */
+	call	.L_get_pc
+	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
+	movl	LZMA_CRC64_TABLE@GOT(%ebx), %ebx
+#endif
+
+	/* Complement the initial value. */
+	notl	%eax
+	notl	%edx
+
+.L_align:
+	/*
+	 * Check if there is enough input to use slicing-by-four.
+	 * We need eight bytes, because the loop pre-reads four bytes.
+	 */
+	cmpl	$8, %edi
+	jb	.L_rest
+
+	/* Check if we have reached alignment of four bytes. */
+	testl	$3, %esi
+	jz	.L_slice
+
+	/* Calculate CRC of the next input byte. */
+	movzbl	(%esi), %ebp
+	incl	%esi
+	movzbl	%al, %ecx
+	xorl	%ecx, %ebp
+	shrdl	$8, %edx, %eax
+	xorl	(%ebx, %ebp, 8), %eax
+	shrl	$8, %edx
+	xorl	4(%ebx, %ebp, 8), %edx
+	decl	%edi
+	jmp	.L_align
+
+.L_slice:
+	/*
+	 * If we get here, there's at least eight bytes of aligned input
+	 * available. Make %edi multiple of four bytes. Store the possible
+	 * remainder over the "size" variable in the argument stack.
+	 */
+	movl	%edi, 0x18(%esp)
+	andl	$-4, %edi
+	subl	%edi, 0x18(%esp)
+
+	/*
+	 * Let %edi be buf + size - 4 while running the main loop. This way
+	 * we can compare for equality to determine when exit the loop.
+	 */
+	addl	%esi, %edi
+	subl	$4, %edi
+
+	/* Read in the first four aligned bytes. */
+	movl	(%esi), %ecx
+
+.L_loop:
+	xorl	%eax, %ecx
+	movzbl	%cl, %ebp
+	movl	0x1800(%ebx, %ebp, 8), %eax
+	xorl	%edx, %eax
+	movl	0x1804(%ebx, %ebp, 8), %edx
+	movzbl	%ch, %ebp
+	xorl	0x1000(%ebx, %ebp, 8), %eax
+	xorl	0x1004(%ebx, %ebp, 8), %edx
+	shrl	$16, %ecx
+	movzbl	%cl, %ebp
+	xorl	0x0800(%ebx, %ebp, 8), %eax
+	xorl	0x0804(%ebx, %ebp, 8), %edx
+	movzbl	%ch, %ebp
+	addl	$4, %esi
+	xorl	(%ebx, %ebp, 8), %eax
+	xorl	4(%ebx, %ebp, 8), %edx
+
+	/* Check for end of aligned input. */
+	cmpl	%edi, %esi
+
+	/*
+	 * Copy the next input byte to %ecx. It is slightly faster to
+	 * read it here than at the top of the loop.
+	 */
+	movl	(%esi), %ecx
+	jb	.L_loop
+
+	/*
+	 * Process the remaining four bytes, which we have already
+	 * copied to %ecx.
+	 */
+	xorl	%eax, %ecx
+	movzbl	%cl, %ebp
+	movl	0x1800(%ebx, %ebp, 8), %eax
+	xorl	%edx, %eax
+	movl	0x1804(%ebx, %ebp, 8), %edx
+	movzbl	%ch, %ebp
+	xorl	0x1000(%ebx, %ebp, 8), %eax
+	xorl	0x1004(%ebx, %ebp, 8), %edx
+	shrl	$16, %ecx
+	movzbl	%cl, %ebp
+	xorl	0x0800(%ebx, %ebp, 8), %eax
+	xorl	0x0804(%ebx, %ebp, 8), %edx
+	movzbl	%ch, %ebp
+	addl	$4, %esi
+	xorl	(%ebx, %ebp, 8), %eax
+	xorl	4(%ebx, %ebp, 8), %edx
+
+	/* Copy the number of remaining bytes to %edi. */
+	movl	0x18(%esp), %edi
+
+.L_rest:
+	/* Check for end of input. */
+	testl	%edi, %edi
+	jz	.L_return
+
+	/* Calculate CRC of the next input byte. */
+	movzbl	(%esi), %ebp
+	incl	%esi
+	movzbl	%al, %ecx
+	xorl	%ecx, %ebp
+	shrdl	$8, %edx, %eax
+	xorl	(%ebx, %ebp, 8), %eax
+	shrl	$8, %edx
+	xorl	4(%ebx, %ebp, 8), %edx
+	decl	%edi
+	jmp	.L_rest
+
+.L_return:
+	/* Complement the final value. */
+	notl	%eax
+	notl	%edx
+
+	popl	%ebp
+	popl	%edi
+	popl	%esi
+	popl	%ebx
+	ret
+
+#if defined(PIC) || defined(__PIC__)
+	ALIGN(4, 16)
+.L_get_pc:
+	movl	(%esp), %ebx
+	ret
+#endif
+
+#if defined(__APPLE__) && (defined(PIC) || defined(__PIC__))
+	/* Mach-O PIC */
+	.section __IMPORT,__pointers,non_lazy_symbol_pointers
+.L_lzma_crc64_table$non_lazy_ptr:
+	.indirect_symbol LZMA_CRC64_TABLE
+	.long 0
+
+#elif defined(_WIN32) || defined(__CYGWIN__)
+#	ifdef DLL_EXPORT
+	/* This is equivalent of __declspec(dllexport). */
+	.section .drectve
+	.ascii " -export:lzma_crc64"
+#	endif
+
+#elif !defined(__MSDOS__)
+	/* ELF */
+	.size	LZMA_CRC64, .-LZMA_CRC64
+#endif
+
+/*
+ * This is needed to support non-executable stack. It's ugly to
+ * use __FreeBSD__ and __linux__ here, but I don't know a way to detect when
+ * we are using GNU assembler.
+ */
+#if defined(__ELF__) && (defined(__FreeBSD__) || defined(__linux__))
+	.section	.note.GNU-stack,"",@progbits
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_common.h
new file mode 100644
index 00000000000..c15d4c675c8
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_common.h
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       crc_common.h
+/// \brief      Some functions and macros for CRC32 and CRC64
+//
+//  Authors:    Lasse Collin
+//              Ilya Kurdyukov
+//              Hans Jansen
+//              Jia Tan
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_CRC_COMMON_H
+#define LZMA_CRC_COMMON_H
+
+#include "common.h"
+
+
+#ifdef WORDS_BIGENDIAN
+#	define A(x) ((x) >> 24)
+#	define B(x) (((x) >> 16) & 0xFF)
+#	define C(x) (((x) >> 8) & 0xFF)
+#	define D(x) ((x) & 0xFF)
+
+#	define S8(x) ((x) << 8)
+#	define S32(x) ((x) << 32)
+
+#else
+#	define A(x) ((x) & 0xFF)
+#	define B(x) (((x) >> 8) & 0xFF)
+#	define C(x) (((x) >> 16) & 0xFF)
+#	define D(x) ((x) >> 24)
+
+#	define S8(x) ((x) >> 8)
+#	define S32(x) ((x) >> 32)
+#endif
+
+
+// CRC CLMUL code needs this because accessing input buffers that aren't
+// aligned to the vector size will inherently trip the address sanitizer.
+#if lzma_has_attribute(__no_sanitize_address__)
+#	define crc_attr_no_sanitize_address \
+			__attribute__((__no_sanitize_address__))
+#else
+#	define crc_attr_no_sanitize_address
+#endif
+
+// Keep this in sync with changes to crc32_arm64.h
+#if defined(_WIN32) || defined(HAVE_GETAUXVAL) \
+		|| defined(HAVE_ELF_AUX_INFO) \
+		|| (defined(__APPLE__) && defined(HAVE_SYSCTLBYNAME))
+#	define ARM64_RUNTIME_DETECTION 1
+#endif
+
+
+#undef CRC32_GENERIC
+#undef CRC64_GENERIC
+
+#undef CRC32_ARCH_OPTIMIZED
+#undef CRC64_ARCH_OPTIMIZED
+
+// The x86 CLMUL is used for both CRC32 and CRC64.
+#undef CRC_X86_CLMUL
+
+#undef CRC32_ARM64
+#undef CRC64_ARM64_CLMUL
+
+#undef CRC_USE_GENERIC_FOR_SMALL_INPUTS
+
+// ARM64 CRC32 instruction is only useful for CRC32. Currently, only
+// little endian is supported since we were unable to test on a big
+// endian machine.
+//
+// NOTE: Keep this and the next check in sync with the macro
+//       NO_CRC32_TABLE in crc32_table.c
+#if defined(HAVE_ARM64_CRC32) && !defined(WORDS_BIGENDIAN)
+	// Allow ARM64 CRC32 instruction without a runtime check if
+	// __ARM_FEATURE_CRC32 is defined. GCC and Clang only define
+	// this if the proper compiler options are used.
+#	if defined(__ARM_FEATURE_CRC32)
+#		define CRC32_ARCH_OPTIMIZED 1
+#		define CRC32_ARM64 1
+#	elif defined(ARM64_RUNTIME_DETECTION)
+#		define CRC32_ARCH_OPTIMIZED 1
+#		define CRC32_ARM64 1
+#		define CRC32_GENERIC 1
+#	endif
+#endif
+
+#if defined(HAVE_USABLE_CLMUL)
+// If CLMUL is allowed unconditionally in the compiler options then the
+// generic version can be omitted. Note that this doesn't work with MSVC
+// as I don't know how to detect the features here.
+//
+// NOTE: Keep this in sync with the NO_CRC32_TABLE macro in crc32_table.c
+// and NO_CRC64_TABLE in crc64_table.c.
+#	if (defined(__SSSE3__) && defined(__SSE4_1__) && defined(__PCLMUL__)) \
+		|| (defined(__e2k__) && __iset__ >= 6)
+#		define CRC32_ARCH_OPTIMIZED 1
+#		define CRC64_ARCH_OPTIMIZED 1
+#		define CRC_X86_CLMUL 1
+#	else
+#		define CRC32_GENERIC 1
+#		define CRC64_GENERIC 1
+#		define CRC32_ARCH_OPTIMIZED 1
+#		define CRC64_ARCH_OPTIMIZED 1
+#		define CRC_X86_CLMUL 1
+
+/*
+		// The generic code is much faster with 1-8-byte inputs and
+		// has similar performance up to 16 bytes  at least in
+		// microbenchmarks (it depends on input buffer alignment
+		// too). If both versions are built, this #define will use
+		// the generic version for inputs up to 16 bytes and CLMUL
+		// for bigger inputs. It saves a little in code size since
+		// the special cases for 0-16-byte inputs will be omitted
+		// from the CLMUL code.
+#		define CRC_USE_GENERIC_FOR_SMALL_INPUTS 1
+*/
+#	endif
+#endif
+
+// For CRC32 use the generic slice-by-eight implementation if no optimized
+// version is available.
+#if !defined(CRC32_ARCH_OPTIMIZED) && !defined(CRC32_GENERIC)
+#	define CRC32_GENERIC 1
+#endif
+
+// For CRC64 use the generic slice-by-four implementation if no optimized
+// version is available.
+#if !defined(CRC64_ARCH_OPTIMIZED) && !defined(CRC64_GENERIC)
+#	define CRC64_GENERIC 1
+#endif
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_x86_clmul.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_x86_clmul.h
new file mode 100644
index 00000000000..50306e49a72
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/crc_x86_clmul.h
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       crc_x86_clmul.h
+/// \brief      CRC32 and CRC64 implementations using CLMUL instructions.
+///
+/// The CRC32 and CRC64 implementations use 32/64-bit x86 SSSE3, SSE4.1, and
+/// CLMUL instructions. This is compatible with Elbrus 2000 (E2K) too.
+///
+/// They were derived from
+/// https://www.researchgate.net/publication/263424619_Fast_CRC_computation
+/// and the public domain code from https://github.com/rawrunprotected/crc
+/// (URLs were checked on 2023-10-14).
+///
+/// While this file has both CRC32 and CRC64 implementations, only one
+/// should be built at a time to ensure that crc_simd_body() is inlined
+/// even with compilers with which lzma_always_inline expands to plain inline.
+/// The version to build is selected by defining BUILDING_CRC32_CLMUL or
+/// BUILDING_CRC64_CLMUL before including this file.
+///
+/// FIXME: Builds for 32-bit x86 use the assembly .S files by default
+/// unless configured with --disable-assembler. Even then the lookup table
+/// isn't omitted in crc64_table.c since it doesn't know that assembly
+/// code has been disabled.
+//
+//  Authors:    Ilya Kurdyukov
+//              Hans Jansen
+//              Lasse Collin
+//              Jia Tan
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// This file must not be included more than once.
+#ifdef LZMA_CRC_X86_CLMUL_H
+#	error crc_x86_clmul.h was included twice.
+#endif
+#define LZMA_CRC_X86_CLMUL_H
+
+#include 
+
+#if defined(_MSC_VER)
+#	include 
+#elif defined(HAVE_CPUID_H)
+#	include 
+#endif
+
+
+// EDG-based compilers (Intel's classic compiler and compiler for E2K) can
+// define __GNUC__ but the attribute must not be used with them.
+// The new Clang-based ICX needs the attribute.
+//
+// NOTE: Build systems check for this too, keep them in sync with this.
+#if (defined(__GNUC__) || defined(__clang__)) && !defined(__EDG__)
+#	define crc_attr_target \
+		__attribute__((__target__("ssse3,sse4.1,pclmul")))
+#else
+#	define crc_attr_target
+#endif
+
+
+#define MASK_L(in, mask, r) r = _mm_shuffle_epi8(in, mask)
+
+#define MASK_H(in, mask, r) \
+	r = _mm_shuffle_epi8(in, _mm_xor_si128(mask, vsign))
+
+#define MASK_LH(in, mask, low, high) \
+	MASK_L(in, mask, low); \
+	MASK_H(in, mask, high)
+
+
+crc_attr_target
+crc_attr_no_sanitize_address
+static lzma_always_inline void
+crc_simd_body(const uint8_t *buf, const size_t size, __m128i *v0, __m128i *v1,
+		const __m128i vfold16, const __m128i initial_crc)
+{
+	// Create a vector with 8-bit values 0 to 15. This is used to
+	// construct control masks for _mm_blendv_epi8 and _mm_shuffle_epi8.
+	const __m128i vramp = _mm_setr_epi32(
+			0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c);
+
+	// This is used to inverse the control mask of _mm_shuffle_epi8
+	// so that bytes that wouldn't be picked with the original mask
+	// will be picked and vice versa.
+	const __m128i vsign = _mm_set1_epi8(-0x80);
+
+	// Memory addresses A to D and the distances between them:
+	//
+	//     A           B     C         D
+	//     [skip_start][size][skip_end]
+	//     [     size2      ]
+	//
+	// A and D are 16-byte aligned. B and C are 1-byte aligned.
+	// skip_start and skip_end are 0-15 bytes. size is at least 1 byte.
+	//
+	// A = aligned_buf will initially point to this address.
+	// B = The address pointed by the caller-supplied buf.
+	// C = buf + size == aligned_buf + size2
+	// D = buf + size + skip_end == aligned_buf + size2 + skip_end
+	const size_t skip_start = (size_t)((uintptr_t)buf & 15);
+	const size_t skip_end = (size_t)((0U - (uintptr_t)(buf + size)) & 15);
+	const __m128i *aligned_buf = (const __m128i *)(
+			(uintptr_t)buf & ~(uintptr_t)15);
+
+	// If size2 <= 16 then the whole input fits into a single 16-byte
+	// vector. If size2 > 16 then at least two 16-byte vectors must
+	// be processed. If size2 > 16 && size <= 16 then there is only
+	// one 16-byte vector's worth of input but it is unaligned in memory.
+	//
+	// NOTE: There is no integer overflow here if the arguments
+	// are valid. If this overflowed, buf + size would too.
+	const size_t size2 = skip_start + size;
+
+	// Masks to be used with _mm_blendv_epi8 and _mm_shuffle_epi8:
+	// The first skip_start or skip_end bytes in the vectors will have
+	// the high bit (0x80) set. _mm_blendv_epi8 and _mm_shuffle_epi8
+	// will produce zeros for these positions. (Bitwise-xor of these
+	// masks with vsign will produce the opposite behavior.)
+	const __m128i mask_start
+			= _mm_sub_epi8(vramp, _mm_set1_epi8((char)skip_start));
+	const __m128i mask_end
+			= _mm_sub_epi8(vramp, _mm_set1_epi8((char)skip_end));
+
+	// Get the first 1-16 bytes into data0. If loading less than 16
+	// bytes, the bytes are loaded to the high bits of the vector and
+	// the least significant positions are filled with zeros.
+	const __m128i data0 = _mm_blendv_epi8(_mm_load_si128(aligned_buf),
+			_mm_setzero_si128(), mask_start);
+	aligned_buf++;
+
+	__m128i v2, v3;
+
+#ifndef CRC_USE_GENERIC_FOR_SMALL_INPUTS
+	if (size <= 16) {
+		// Right-shift initial_crc by 1-16 bytes based on "size"
+		// and store the result in v1 (high bytes) and v0 (low bytes).
+		//
+		// NOTE: The highest 8 bytes of initial_crc are zeros so
+		// v1 will be filled with zeros if size >= 8. The highest
+		// 8 bytes of v1 will always become zeros.
+		//
+		// [      v1      ][      v0      ]
+		//  [ initial_crc  ]                  size == 1
+		//   [ initial_crc  ]                 size == 2
+		//                [ initial_crc  ]    size == 15
+		//                 [ initial_crc  ]   size == 16 (all in v0)
+		const __m128i mask_low = _mm_add_epi8(
+				vramp, _mm_set1_epi8((char)(size - 16)));
+		MASK_LH(initial_crc, mask_low, *v0, *v1);
+
+		if (size2 <= 16) {
+			// There are 1-16 bytes of input and it is all
+			// in data0. Copy the input bytes to v3. If there
+			// are fewer than 16 bytes, the low bytes in v3
+			// will be filled with zeros. That is, the input
+			// bytes are stored to the same position as
+			// (part of) initial_crc is in v0.
+			MASK_L(data0, mask_end, v3);
+		} else {
+			// There are 2-16 bytes of input but not all bytes
+			// are in data0.
+			const __m128i data1 = _mm_load_si128(aligned_buf);
+
+			// Collect the 2-16 input bytes from data0 and data1
+			// to v2 and v3, and bitwise-xor them with the
+			// low bits of initial_crc in v0. Note that the
+			// the second xor is below this else-block as it
+			// is shared with the other branch.
+			MASK_H(data0, mask_end, v2);
+			MASK_L(data1, mask_end, v3);
+			*v0 = _mm_xor_si128(*v0, v2);
+		}
+
+		*v0 = _mm_xor_si128(*v0, v3);
+		*v1 = _mm_alignr_epi8(*v1, *v0, 8);
+	} else
+#endif
+	{
+		// There is more than 16 bytes of input.
+		const __m128i data1 = _mm_load_si128(aligned_buf);
+		const __m128i *end = (const __m128i*)(
+				(const char *)aligned_buf - 16 + size2);
+		aligned_buf++;
+
+		MASK_LH(initial_crc, mask_start, *v0, *v1);
+		*v0 = _mm_xor_si128(*v0, data0);
+		*v1 = _mm_xor_si128(*v1, data1);
+
+		while (aligned_buf < end) {
+			*v1 = _mm_xor_si128(*v1, _mm_clmulepi64_si128(
+					*v0, vfold16, 0x00));
+			*v0 = _mm_xor_si128(*v1, _mm_clmulepi64_si128(
+					*v0, vfold16, 0x11));
+			*v1 = _mm_load_si128(aligned_buf++);
+		}
+
+		if (aligned_buf != end) {
+			MASK_H(*v0, mask_end, v2);
+			MASK_L(*v0, mask_end, *v0);
+			MASK_L(*v1, mask_end, v3);
+			*v1 = _mm_or_si128(v2, v3);
+		}
+
+		*v1 = _mm_xor_si128(*v1, _mm_clmulepi64_si128(
+				*v0, vfold16, 0x00));
+		*v0 = _mm_xor_si128(*v1, _mm_clmulepi64_si128(
+				*v0, vfold16, 0x11));
+		*v1 = _mm_srli_si128(*v0, 8);
+	}
+}
+
+
+/////////////////////
+// x86 CLMUL CRC32 //
+/////////////////////
+
+/*
+// These functions were used to generate the constants
+// at the top of crc32_arch_optimized().
+static uint64_t
+calc_lo(uint64_t p, uint64_t a, int n)
+{
+	uint64_t b = 0; int i;
+	for (i = 0; i < n; i++) {
+		b = b >> 1 | (a & 1) << (n - 1);
+		a = (a >> 1) ^ ((0 - (a & 1)) & p);
+	}
+	return b;
+}
+
+// same as ~crc(&a, sizeof(a), ~0)
+static uint64_t
+calc_hi(uint64_t p, uint64_t a, int n)
+{
+	int i;
+	for (i = 0; i < n; i++)
+		a = (a >> 1) ^ ((0 - (a & 1)) & p);
+	return a;
+}
+*/
+
+#ifdef BUILDING_CRC32_CLMUL
+
+crc_attr_target
+crc_attr_no_sanitize_address
+static uint32_t
+crc32_arch_optimized(const uint8_t *buf, size_t size, uint32_t crc)
+{
+#ifndef CRC_USE_GENERIC_FOR_SMALL_INPUTS
+	// The code assumes that there is at least one byte of input.
+	if (size == 0)
+		return crc;
+#endif
+
+	// uint32_t poly = 0xedb88320;
+	const int64_t p = 0x1db710640; // p << 1
+	const int64_t mu = 0x1f7011641; // calc_lo(p, p, 32) << 1 | 1
+	const int64_t k5 = 0x163cd6124; // calc_hi(p, p, 32) << 1
+	const int64_t k4 = 0x0ccaa009e; // calc_hi(p, p, 64) << 1
+	const int64_t k3 = 0x1751997d0; // calc_hi(p, p, 128) << 1
+
+	const __m128i vfold4 = _mm_set_epi64x(mu, p);
+	const __m128i vfold8 = _mm_set_epi64x(0, k5);
+	const __m128i vfold16 = _mm_set_epi64x(k4, k3);
+
+	__m128i v0, v1, v2;
+
+	crc_simd_body(buf, size, &v0, &v1, vfold16,
+			_mm_cvtsi32_si128((int32_t)~crc));
+
+	v1 = _mm_xor_si128(
+			_mm_clmulepi64_si128(v0, vfold16, 0x10), v1); // xxx0
+	v2 = _mm_shuffle_epi32(v1, 0xe7); // 0xx0
+	v0 = _mm_slli_epi64(v1, 32);  // [0]
+	v0 = _mm_clmulepi64_si128(v0, vfold8, 0x00);
+	v0 = _mm_xor_si128(v0, v2);   // [1] [2]
+	v2 = _mm_clmulepi64_si128(v0, vfold4, 0x10);
+	v2 = _mm_clmulepi64_si128(v2, vfold4, 0x00);
+	v0 = _mm_xor_si128(v0, v2);   // [2]
+	return ~(uint32_t)_mm_extract_epi32(v0, 2);
+}
+#endif // BUILDING_CRC32_CLMUL
+
+
+/////////////////////
+// x86 CLMUL CRC64 //
+/////////////////////
+
+/*
+// These functions were used to generate the constants
+// at the top of crc64_arch_optimized().
+static uint64_t
+calc_lo(uint64_t poly)
+{
+	uint64_t a = poly;
+	uint64_t b = 0;
+
+	for (unsigned i = 0; i < 64; ++i) {
+		b = (b >> 1) | (a << 63);
+		a = (a >> 1) ^ (a & 1 ? poly : 0);
+	}
+
+	return b;
+}
+
+static uint64_t
+calc_hi(uint64_t poly, uint64_t a)
+{
+	for (unsigned i = 0; i < 64; ++i)
+		a = (a >> 1) ^ (a & 1 ? poly : 0);
+
+	return a;
+}
+*/
+
+#ifdef BUILDING_CRC64_CLMUL
+
+// MSVC (VS2015 - VS2022) produces bad 32-bit x86 code from the CLMUL CRC
+// code when optimizations are enabled (release build). According to the bug
+// report, the ebx register is corrupted and the calculated result is wrong.
+// Trying to workaround the problem with "__asm mov ebx, ebx" didn't help.
+// The following pragma works and performance is still good. x86-64 builds
+// and CRC32 CLMUL aren't affected by this problem. The problem does not
+// happen in crc_simd_body() either (which is shared with CRC32 CLMUL anyway).
+//
+// NOTE: Another pragma after crc64_arch_optimized() restores
+// the optimizations. If the #if condition here is updated,
+// the other one must be updated too.
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) \
+		&& defined(_M_IX86)
+#	pragma optimize("g", off)
+#endif
+
+crc_attr_target
+crc_attr_no_sanitize_address
+static uint64_t
+crc64_arch_optimized(const uint8_t *buf, size_t size, uint64_t crc)
+{
+#ifndef CRC_USE_GENERIC_FOR_SMALL_INPUTS
+	// The code assumes that there is at least one byte of input.
+	if (size == 0)
+		return crc;
+#endif
+
+	// const uint64_t poly = 0xc96c5795d7870f42; // CRC polynomial
+	const uint64_t p  = 0x92d8af2baf0e1e85; // (poly << 1) | 1
+	const uint64_t mu = 0x9c3e466c172963d5; // (calc_lo(poly) << 1) | 1
+	const uint64_t k2 = 0xdabe95afc7875f40; // calc_hi(poly, 1)
+	const uint64_t k1 = 0xe05dd497ca393ae4; // calc_hi(poly, k2)
+
+	const __m128i vfold8 = _mm_set_epi64x((int64_t)p, (int64_t)mu);
+	const __m128i vfold16 = _mm_set_epi64x((int64_t)k2, (int64_t)k1);
+
+	__m128i v0, v1, v2;
+
+#if defined(__i386__) || defined(_M_IX86)
+	crc_simd_body(buf, size, &v0, &v1, vfold16,
+			_mm_set_epi64x(0, (int64_t)~crc));
+#else
+	// GCC and Clang would produce good code with _mm_set_epi64x
+	// but MSVC needs _mm_cvtsi64_si128 on x86-64.
+	crc_simd_body(buf, size, &v0, &v1, vfold16,
+			_mm_cvtsi64_si128((int64_t)~crc));
+#endif
+
+	v1 = _mm_xor_si128(_mm_clmulepi64_si128(v0, vfold16, 0x10), v1);
+	v0 = _mm_clmulepi64_si128(v1, vfold8, 0x00);
+	v2 = _mm_clmulepi64_si128(v0, vfold8, 0x10);
+	v0 = _mm_xor_si128(_mm_xor_si128(v1, _mm_slli_si128(v0, 8)), v2);
+
+#if defined(__i386__) || defined(_M_IX86)
+	return ~(((uint64_t)(uint32_t)_mm_extract_epi32(v0, 3) << 32) |
+			(uint64_t)(uint32_t)_mm_extract_epi32(v0, 2));
+#else
+	return ~(uint64_t)_mm_extract_epi64(v0, 1);
+#endif
+}
+
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) \
+		&& defined(_M_IX86)
+#	pragma optimize("", on)
+#endif
+
+#endif // BUILDING_CRC64_CLMUL
+
+
+// Even though this is an inline function, compile it only when needed.
+// This way it won't appear in E2K builds at all.
+#if defined(CRC32_GENERIC) || defined(CRC64_GENERIC)
+// Inlining this function duplicates the function body in crc32_resolve() and
+// crc64_resolve(), but this is acceptable because this is a tiny function.
+static inline bool
+is_arch_extension_supported(void)
+{
+	int success = 1;
+	uint32_t r[4]; // eax, ebx, ecx, edx
+
+#if defined(_MSC_VER)
+	// This needs  with MSVC. ICC has it as a built-in
+	// on all platforms.
+	__cpuid(r, 1);
+#elif defined(HAVE_CPUID_H)
+	// Compared to just using __asm__ to run CPUID, this also checks
+	// that CPUID is supported and saves and restores ebx as that is
+	// needed with GCC < 5 with position-independent code (PIC).
+	success = __get_cpuid(1, &r[0], &r[1], &r[2], &r[3]);
+#else
+	// Just a fallback that shouldn't be needed.
+	__asm__("cpuid\n\t"
+			: "=a"(r[0]), "=b"(r[1]), "=c"(r[2]), "=d"(r[3])
+			: "a"(1), "c"(0));
+#endif
+
+	// Returns true if these are supported:
+	// CLMUL (bit 1 in ecx)
+	// SSSE3 (bit 9 in ecx)
+	// SSE4.1 (bit 19 in ecx)
+	const uint32_t ecx_mask = (1 << 1) | (1 << 9) | (1 << 19);
+	return success && (r[2] & ecx_mask) == ecx_mask;
+
+	// Alternative methods that weren't used:
+	//   - ICC's _may_i_use_cpu_feature: the other methods should work too.
+	//   - GCC >= 6 / Clang / ICX __builtin_cpu_supports("pclmul")
+	//
+	// CPUID decoding is needed with MSVC anyway and older GCC. This keeps
+	// the feature checks in the build system simpler too. The nice thing
+	// about __builtin_cpu_supports would be that it generates very short
+	// code as is it only reads a variable set at startup but a few bytes
+	// doesn't matter here.
+}
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/sha256.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/sha256.c
new file mode 100644
index 00000000000..c067a3a693f
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/check/sha256.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       sha256.c
+/// \brief      SHA-256
+//
+//  The C code is based on the public domain SHA-256 code found from
+//  Crypto++ Library 5.5.1 released in 2007: https://www.cryptopp.com/
+//  A few minor tweaks have been made in liblzma.
+//
+//  Authors:    Wei Dai
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "check.h"
+
+// Rotate a uint32_t. GCC can optimize this to a rotate instruction
+// at least on x86.
+static inline uint32_t
+rotr_32(uint32_t num, unsigned amount)
+{
+	return (num >> amount) | (num << (32 - amount));
+}
+
+#define blk0(i) (W[i] = conv32be(data[i]))
+#define blk2(i) (W[i & 15] += s1(W[(i - 2) & 15]) + W[(i - 7) & 15] \
+		+ s0(W[(i - 15) & 15]))
+
+#define Ch(x, y, z) (z ^ (x & (y ^ z)))
+#define Maj(x, y, z) ((x & (y ^ z)) + (y & z))
+
+#define a(i) T[(0 - i) & 7]
+#define b(i) T[(1 - i) & 7]
+#define c(i) T[(2 - i) & 7]
+#define d(i) T[(3 - i) & 7]
+#define e(i) T[(4 - i) & 7]
+#define f(i) T[(5 - i) & 7]
+#define g(i) T[(6 - i) & 7]
+#define h(i) T[(7 - i) & 7]
+
+#define R(i, j, blk) \
+	h(i) += S1(e(i)) + Ch(e(i), f(i), g(i)) + SHA256_K[i + j] + blk; \
+	d(i) += h(i); \
+	h(i) += S0(a(i)) + Maj(a(i), b(i), c(i))
+#define R0(i) R(i, 0, blk0(i))
+#define R2(i) R(i, j, blk2(i))
+
+#define S0(x) rotr_32(x ^ rotr_32(x ^ rotr_32(x, 9), 11), 2)
+#define S1(x) rotr_32(x ^ rotr_32(x ^ rotr_32(x, 14), 5), 6)
+#define s0(x) (rotr_32(x ^ rotr_32(x, 11), 7) ^ (x >> 3))
+#define s1(x) (rotr_32(x ^ rotr_32(x, 2), 17) ^ (x >> 10))
+
+
+static const uint32_t SHA256_K[64] = {
+	0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
+	0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
+	0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
+	0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
+	0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
+	0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
+	0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
+	0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
+	0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
+	0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
+	0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
+	0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
+	0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
+	0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
+	0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
+	0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
+};
+
+
+static void
+transform(uint32_t state[8], const uint32_t data[16])
+{
+	uint32_t W[16];
+	uint32_t T[8];
+
+	// Copy state[] to working vars.
+	memcpy(T, state, sizeof(T));
+
+	// The first 16 operations unrolled
+	R0( 0); R0( 1); R0( 2); R0( 3);
+	R0( 4); R0( 5); R0( 6); R0( 7);
+	R0( 8); R0( 9); R0(10); R0(11);
+	R0(12); R0(13); R0(14); R0(15);
+
+	// The remaining 48 operations partially unrolled
+	for (unsigned int j = 16; j < 64; j += 16) {
+		R2( 0); R2( 1); R2( 2); R2( 3);
+		R2( 4); R2( 5); R2( 6); R2( 7);
+		R2( 8); R2( 9); R2(10); R2(11);
+		R2(12); R2(13); R2(14); R2(15);
+	}
+
+	// Add the working vars back into state[].
+	state[0] += a(0);
+	state[1] += b(0);
+	state[2] += c(0);
+	state[3] += d(0);
+	state[4] += e(0);
+	state[5] += f(0);
+	state[6] += g(0);
+	state[7] += h(0);
+}
+
+
+static void
+process(lzma_check_state *check)
+{
+	transform(check->state.sha256.state, check->buffer.u32);
+	return;
+}
+
+
+extern void
+lzma_sha256_init(lzma_check_state *check)
+{
+	static const uint32_t s[8] = {
+		0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
+		0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
+	};
+
+	memcpy(check->state.sha256.state, s, sizeof(s));
+	check->state.sha256.size = 0;
+
+	return;
+}
+
+
+extern void
+lzma_sha256_update(const uint8_t *buf, size_t size, lzma_check_state *check)
+{
+	// Copy the input data into a properly aligned temporary buffer.
+	// This way we can be called with arbitrarily sized buffers
+	// (no need to be multiple of 64 bytes), and the code works also
+	// on architectures that don't allow unaligned memory access.
+	while (size > 0) {
+		const size_t copy_start = check->state.sha256.size & 0x3F;
+		size_t copy_size = 64 - copy_start;
+		if (copy_size > size)
+			copy_size = size;
+
+		memcpy(check->buffer.u8 + copy_start, buf, copy_size);
+
+		buf += copy_size;
+		size -= copy_size;
+		check->state.sha256.size += copy_size;
+
+		if ((check->state.sha256.size & 0x3F) == 0)
+			process(check);
+	}
+
+	return;
+}
+
+
+extern void
+lzma_sha256_finish(lzma_check_state *check)
+{
+	// Add padding as described in RFC 3174 (it describes SHA-1 but
+	// the same padding style is used for SHA-256 too).
+	size_t pos = check->state.sha256.size & 0x3F;
+	check->buffer.u8[pos++] = 0x80;
+
+	while (pos != 64 - 8) {
+		if (pos == 64) {
+			process(check);
+			pos = 0;
+		}
+
+		check->buffer.u8[pos++] = 0x00;
+	}
+
+	// Convert the message size from bytes to bits.
+	check->state.sha256.size *= 8;
+
+	check->buffer.u64[(64 - 8) / 8] = conv64be(check->state.sha256.size);
+
+	process(check);
+
+	for (size_t i = 0; i < 8; ++i)
+		check->buffer.u32[i] = conv32be(check->state.sha256.state[i]);
+
+	return;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.c
new file mode 100644
index 00000000000..78af651578f
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       alone_decoder.c
+/// \brief      Decoder for LZMA_Alone files
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "alone_decoder.h"
+#include "lzma_decoder.h"
+#include "lz_decoder.h"
+
+
+typedef struct {
+	lzma_next_coder next;
+
+	enum {
+		SEQ_PROPERTIES,
+		SEQ_DICTIONARY_SIZE,
+		SEQ_UNCOMPRESSED_SIZE,
+		SEQ_CODER_INIT,
+		SEQ_CODE,
+	} sequence;
+
+	/// If true, reject files that are unlikely to be .lzma files.
+	/// If false, more non-.lzma files get accepted and will give
+	/// LZMA_DATA_ERROR either immediately or after a few output bytes.
+	bool picky;
+
+	/// Position in the header fields
+	size_t pos;
+
+	/// Uncompressed size decoded from the header
+	lzma_vli uncompressed_size;
+
+	/// Memory usage limit
+	uint64_t memlimit;
+
+	/// Amount of memory actually needed (only an estimate)
+	uint64_t memusage;
+
+	/// Options decoded from the header needed to initialize
+	/// the LZMA decoder
+	lzma_options_lzma options;
+} lzma_alone_coder;
+
+
+static lzma_ret
+alone_decode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size,
+		lzma_action action)
+{
+	lzma_alone_coder *coder = coder_ptr;
+
+	while (*out_pos < out_size
+			&& (coder->sequence == SEQ_CODE || *in_pos < in_size))
+	switch (coder->sequence) {
+	case SEQ_PROPERTIES:
+		if (lzma_lzma_lclppb_decode(&coder->options, in[*in_pos]))
+			return LZMA_FORMAT_ERROR;
+
+		coder->sequence = SEQ_DICTIONARY_SIZE;
+		++*in_pos;
+		break;
+
+	case SEQ_DICTIONARY_SIZE:
+		coder->options.dict_size
+				|= (size_t)(in[*in_pos]) << (coder->pos * 8);
+
+		if (++coder->pos == 4) {
+			if (coder->picky && coder->options.dict_size
+					!= UINT32_MAX) {
+				// A hack to ditch tons of false positives:
+				// We allow only dictionary sizes that are
+				// 2^n or 2^n + 2^(n-1). LZMA_Alone created
+				// only files with 2^n, but accepts any
+				// dictionary size.
+				uint32_t d = coder->options.dict_size - 1;
+				d |= d >> 2;
+				d |= d >> 3;
+				d |= d >> 4;
+				d |= d >> 8;
+				d |= d >> 16;
+				++d;
+
+				if (d != coder->options.dict_size)
+					return LZMA_FORMAT_ERROR;
+			}
+
+			coder->pos = 0;
+			coder->sequence = SEQ_UNCOMPRESSED_SIZE;
+		}
+
+		++*in_pos;
+		break;
+
+	case SEQ_UNCOMPRESSED_SIZE:
+		coder->uncompressed_size
+				|= (lzma_vli)(in[*in_pos]) << (coder->pos * 8);
+		++*in_pos;
+		if (++coder->pos < 8)
+			break;
+
+		// Another hack to ditch false positives: Assume that
+		// if the uncompressed size is known, it must be less
+		// than 256 GiB.
+		//
+		// FIXME? Without picky we allow > LZMA_VLI_MAX which doesn't
+		// really matter in this specific situation (> LZMA_VLI_MAX is
+		// safe in the LZMA decoder) but it's somewhat weird still.
+		if (coder->picky
+				&& coder->uncompressed_size != LZMA_VLI_UNKNOWN
+				&& coder->uncompressed_size
+					>= (LZMA_VLI_C(1) << 38))
+			return LZMA_FORMAT_ERROR;
+
+		// Use LZMA_FILTER_LZMA1EXT features to specify the
+		// uncompressed size and that the end marker is allowed
+		// even when the uncompressed size is known. Both .lzma
+		// header and LZMA1EXT use UINT64_MAX indicate that size
+		// is unknown.
+		coder->options.ext_flags = LZMA_LZMA1EXT_ALLOW_EOPM;
+		lzma_set_ext_size(coder->options, coder->uncompressed_size);
+
+		// Calculate the memory usage so that it is ready
+		// for SEQ_CODER_INIT.
+		coder->memusage = lzma_lzma_decoder_memusage(&coder->options)
+				+ LZMA_MEMUSAGE_BASE;
+
+		coder->pos = 0;
+		coder->sequence = SEQ_CODER_INIT;
+
+	// Fall through
+
+	case SEQ_CODER_INIT: {
+		if (coder->memusage > coder->memlimit)
+			return LZMA_MEMLIMIT_ERROR;
+
+		lzma_filter_info filters[2] = {
+			{
+				.id = LZMA_FILTER_LZMA1EXT,
+				.init = &lzma_lzma_decoder_init,
+				.options = &coder->options,
+			}, {
+				.init = NULL,
+			}
+		};
+
+		return_if_error(lzma_next_filter_init(&coder->next,
+				allocator, filters));
+
+		coder->sequence = SEQ_CODE;
+		break;
+	}
+
+	case SEQ_CODE: {
+		return coder->next.code(coder->next.coder,
+				allocator, in, in_pos, in_size,
+				out, out_pos, out_size, action);
+	}
+
+	default:
+		return LZMA_PROG_ERROR;
+	}
+
+	return LZMA_OK;
+}
+
+
+static void
+alone_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_alone_coder *coder = coder_ptr;
+	lzma_next_end(&coder->next, allocator);
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_ret
+alone_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
+		uint64_t *old_memlimit, uint64_t new_memlimit)
+{
+	lzma_alone_coder *coder = coder_ptr;
+
+	*memusage = coder->memusage;
+	*old_memlimit = coder->memlimit;
+
+	if (new_memlimit != 0) {
+		if (new_memlimit < coder->memusage)
+			return LZMA_MEMLIMIT_ERROR;
+
+		coder->memlimit = new_memlimit;
+	}
+
+	return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_alone_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		uint64_t memlimit, bool picky)
+{
+	lzma_next_coder_init(&lzma_alone_decoder_init, next, allocator);
+
+	lzma_alone_coder *coder = next->coder;
+
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_alone_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+		next->code = &alone_decode;
+		next->end = &alone_decoder_end;
+		next->memconfig = &alone_decoder_memconfig;
+		coder->next = LZMA_NEXT_CODER_INIT;
+	}
+
+	coder->sequence = SEQ_PROPERTIES;
+	coder->picky = picky;
+	coder->pos = 0;
+	coder->options.dict_size = 0;
+	coder->options.preset_dict = NULL;
+	coder->options.preset_dict_size = 0;
+	coder->uncompressed_size = 0;
+	coder->memlimit = my_max(1, memlimit);
+	coder->memusage = LZMA_MEMUSAGE_BASE;
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_alone_decoder(lzma_stream *strm, uint64_t memlimit)
+{
+	lzma_next_strm_init(lzma_alone_decoder_init, strm, memlimit, false);
+
+	strm->internal->supported_actions[LZMA_RUN] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.h
new file mode 100644
index 00000000000..61ee24d97fe
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_decoder.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       alone_decoder.h
+/// \brief      Decoder for LZMA_Alone files
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_ALONE_DECODER_H
+#define LZMA_ALONE_DECODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_alone_decoder_init(
+		lzma_next_coder *next, const lzma_allocator *allocator,
+		uint64_t memlimit, bool picky);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_encoder.c
new file mode 100644
index 00000000000..21b039509ae
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/alone_encoder.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       alone_encoder.c
+/// \brief      Encoder for LZMA_Alone files
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+#include "lzma_encoder.h"
+
+
+#define ALONE_HEADER_SIZE (1 + 4 + 8)
+
+
+typedef struct {
+	lzma_next_coder next;
+
+	enum {
+		SEQ_HEADER,
+		SEQ_CODE,
+	} sequence;
+
+	size_t header_pos;
+	uint8_t header[ALONE_HEADER_SIZE];
+} lzma_alone_coder;
+
+
+static lzma_ret
+alone_encode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size,
+		lzma_action action)
+{
+	lzma_alone_coder *coder = coder_ptr;
+
+	while (*out_pos < out_size)
+	switch (coder->sequence) {
+	case SEQ_HEADER:
+		lzma_bufcpy(coder->header, &coder->header_pos,
+				ALONE_HEADER_SIZE,
+				out, out_pos, out_size);
+		if (coder->header_pos < ALONE_HEADER_SIZE)
+			return LZMA_OK;
+
+		coder->sequence = SEQ_CODE;
+		break;
+
+	case SEQ_CODE:
+		return coder->next.code(coder->next.coder,
+				allocator, in, in_pos, in_size,
+				out, out_pos, out_size, action);
+
+	default:
+		assert(0);
+		return LZMA_PROG_ERROR;
+	}
+
+	return LZMA_OK;
+}
+
+
+static void
+alone_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_alone_coder *coder = coder_ptr;
+	lzma_next_end(&coder->next, allocator);
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_ret
+alone_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_options_lzma *options)
+{
+	lzma_next_coder_init(&alone_encoder_init, next, allocator);
+
+	lzma_alone_coder *coder = next->coder;
+
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_alone_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+		next->code = &alone_encode;
+		next->end = &alone_encoder_end;
+		coder->next = LZMA_NEXT_CODER_INIT;
+	}
+
+	// Basic initializations
+	coder->sequence = SEQ_HEADER;
+	coder->header_pos = 0;
+
+	// Encode the header:
+	// - Properties (1 byte)
+	if (lzma_lzma_lclppb_encode(options, coder->header))
+		return LZMA_OPTIONS_ERROR;
+
+	// - Dictionary size (4 bytes)
+	if (options->dict_size < LZMA_DICT_SIZE_MIN)
+		return LZMA_OPTIONS_ERROR;
+
+	// Round up to the next 2^n or 2^n + 2^(n - 1) depending on which
+	// one is the next unless it is UINT32_MAX. While the header would
+	// allow any 32-bit integer, we do this to keep the decoder of liblzma
+	// accepting the resulting files.
+	uint32_t d = options->dict_size - 1;
+	d |= d >> 2;
+	d |= d >> 3;
+	d |= d >> 4;
+	d |= d >> 8;
+	d |= d >> 16;
+	if (d != UINT32_MAX)
+		++d;
+
+	write32le(coder->header + 1, d);
+
+	// - Uncompressed size (always unknown and using EOPM)
+	memset(coder->header + 1 + 4, 0xFF, 8);
+
+	// Initialize the LZMA encoder.
+	const lzma_filter_info filters[2] = {
+		{
+			.id = LZMA_FILTER_LZMA1,
+			.init = &lzma_lzma_encoder_init,
+			.options = (void *)(options),
+		}, {
+			.init = NULL,
+		}
+	};
+
+	return lzma_next_filter_init(&coder->next, allocator, filters);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_alone_encoder(lzma_stream *strm, const lzma_options_lzma *options)
+{
+	lzma_next_strm_init(alone_encoder_init, strm, options);
+
+	strm->internal->supported_actions[LZMA_RUN] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/auto_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/auto_decoder.c
new file mode 100644
index 00000000000..fdd520f905c
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/auto_decoder.c
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       auto_decoder.c
+/// \brief      Autodetect between .xz, .lzma (LZMA_Alone), and .lz (lzip)
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "stream_decoder.h"
+#include "alone_decoder.h"
+#ifdef HAVE_LZIP_DECODER
+#	include "lzip_decoder.h"
+#endif
+
+
+typedef struct {
+	/// .xz Stream decoder, LZMA_Alone decoder, or lzip decoder
+	lzma_next_coder next;
+
+	uint64_t memlimit;
+	uint32_t flags;
+
+	enum {
+		SEQ_INIT,
+		SEQ_CODE,
+		SEQ_FINISH,
+	} sequence;
+} lzma_auto_coder;
+
+
+static lzma_ret
+auto_decode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size, lzma_action action)
+{
+	lzma_auto_coder *coder = coder_ptr;
+
+	switch (coder->sequence) {
+	case SEQ_INIT:
+		if (*in_pos >= in_size)
+			return LZMA_OK;
+
+		// Update the sequence now, because we want to continue from
+		// SEQ_CODE even if we return some LZMA_*_CHECK.
+		coder->sequence = SEQ_CODE;
+
+		// Detect the file format. .xz files start with 0xFD which
+		// cannot be the first byte of .lzma (LZMA_Alone) format.
+		// The .lz format starts with 0x4C which could be the
+		// first byte of a .lzma file but luckily it would mean
+		// lc/lp/pb being 4/3/1 which liblzma doesn't support because
+		// lc + lp > 4. So using just 0x4C to detect .lz is OK here.
+		if (in[*in_pos] == 0xFD) {
+			return_if_error(lzma_stream_decoder_init(
+					&coder->next, allocator,
+					coder->memlimit, coder->flags));
+#ifdef HAVE_LZIP_DECODER
+		} else if (in[*in_pos] == 0x4C) {
+			return_if_error(lzma_lzip_decoder_init(
+					&coder->next, allocator,
+					coder->memlimit, coder->flags));
+#endif
+		} else {
+			return_if_error(lzma_alone_decoder_init(&coder->next,
+					allocator, coder->memlimit, true));
+
+			// If the application wants to know about missing
+			// integrity check or about the check in general, we
+			// need to handle it here, because LZMA_Alone decoder
+			// doesn't accept any flags.
+			if (coder->flags & LZMA_TELL_NO_CHECK)
+				return LZMA_NO_CHECK;
+
+			if (coder->flags & LZMA_TELL_ANY_CHECK)
+				return LZMA_GET_CHECK;
+		}
+
+	// Fall through
+
+	case SEQ_CODE: {
+		const lzma_ret ret = coder->next.code(
+				coder->next.coder, allocator,
+				in, in_pos, in_size,
+				out, out_pos, out_size, action);
+		if (ret != LZMA_STREAM_END
+				|| (coder->flags & LZMA_CONCATENATED) == 0)
+			return ret;
+
+		coder->sequence = SEQ_FINISH;
+	}
+
+	// Fall through
+
+	case SEQ_FINISH:
+		// When LZMA_CONCATENATED was used and we were decoding
+		// a LZMA_Alone file, we need to check that there is no
+		// trailing garbage and wait for LZMA_FINISH.
+		if (*in_pos < in_size)
+			return LZMA_DATA_ERROR;
+
+		return action == LZMA_FINISH ? LZMA_STREAM_END : LZMA_OK;
+
+	default:
+		assert(0);
+		return LZMA_PROG_ERROR;
+	}
+}
+
+
+static void
+auto_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_auto_coder *coder = coder_ptr;
+	lzma_next_end(&coder->next, allocator);
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_check
+auto_decoder_get_check(const void *coder_ptr)
+{
+	const lzma_auto_coder *coder = coder_ptr;
+
+	// It is LZMA_Alone if get_check is NULL.
+	return coder->next.get_check == NULL ? LZMA_CHECK_NONE
+			: coder->next.get_check(coder->next.coder);
+}
+
+
+static lzma_ret
+auto_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
+		uint64_t *old_memlimit, uint64_t new_memlimit)
+{
+	lzma_auto_coder *coder = coder_ptr;
+
+	lzma_ret ret;
+
+	if (coder->next.memconfig != NULL) {
+		ret = coder->next.memconfig(coder->next.coder,
+				memusage, old_memlimit, new_memlimit);
+		assert(*old_memlimit == coder->memlimit);
+	} else {
+		// No coder is configured yet. Use the base value as
+		// the current memory usage.
+		*memusage = LZMA_MEMUSAGE_BASE;
+		*old_memlimit = coder->memlimit;
+
+		ret = LZMA_OK;
+		if (new_memlimit != 0 && new_memlimit < *memusage)
+			ret = LZMA_MEMLIMIT_ERROR;
+	}
+
+	if (ret == LZMA_OK && new_memlimit != 0)
+		coder->memlimit = new_memlimit;
+
+	return ret;
+}
+
+
+static lzma_ret
+auto_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		uint64_t memlimit, uint32_t flags)
+{
+	lzma_next_coder_init(&auto_decoder_init, next, allocator);
+
+	if (flags & ~LZMA_SUPPORTED_FLAGS)
+		return LZMA_OPTIONS_ERROR;
+
+	lzma_auto_coder *coder = next->coder;
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_auto_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+		next->code = &auto_decode;
+		next->end = &auto_decoder_end;
+		next->get_check = &auto_decoder_get_check;
+		next->memconfig = &auto_decoder_memconfig;
+		coder->next = LZMA_NEXT_CODER_INIT;
+	}
+
+	coder->memlimit = my_max(1, memlimit);
+	coder->flags = flags;
+	coder->sequence = SEQ_INIT;
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_auto_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)
+{
+	lzma_next_strm_init(auto_decoder_init, strm, memlimit, flags);
+
+	strm->internal->supported_actions[LZMA_RUN] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_decoder.c
new file mode 100644
index 00000000000..55566cd2f2b
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_decoder.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       block_buffer_decoder.c
+/// \brief      Single-call .xz Block decoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "block_decoder.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_buffer_decode(lzma_block *block, const lzma_allocator *allocator,
+		const uint8_t *in, size_t *in_pos, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+{
+	if (in_pos == NULL || (in == NULL && *in_pos != in_size)
+			|| *in_pos > in_size || out_pos == NULL
+			|| (out == NULL && *out_pos != out_size)
+			|| *out_pos > out_size)
+		return LZMA_PROG_ERROR;
+
+	// Initialize the Block decoder.
+	lzma_next_coder block_decoder = LZMA_NEXT_CODER_INIT;
+	lzma_ret ret = lzma_block_decoder_init(
+			&block_decoder, allocator, block);
+
+	if (ret == LZMA_OK) {
+		// Save the positions so that we can restore them in case
+		// an error occurs.
+		const size_t in_start = *in_pos;
+		const size_t out_start = *out_pos;
+
+		// Do the actual decoding.
+		ret = block_decoder.code(block_decoder.coder, allocator,
+				in, in_pos, in_size, out, out_pos, out_size,
+				LZMA_FINISH);
+
+		if (ret == LZMA_STREAM_END) {
+			ret = LZMA_OK;
+		} else {
+			if (ret == LZMA_OK) {
+				// Either the input was truncated or the
+				// output buffer was too small.
+				assert(*in_pos == in_size
+						|| *out_pos == out_size);
+
+				// If all the input was consumed, then the
+				// input is truncated, even if the output
+				// buffer is also full. This is because
+				// processing the last byte of the Block
+				// never produces output.
+				//
+				// NOTE: This assumption may break when new
+				// filters are added, if the end marker of
+				// the filter doesn't consume at least one
+				// complete byte.
+				if (*in_pos == in_size)
+					ret = LZMA_DATA_ERROR;
+				else
+					ret = LZMA_BUF_ERROR;
+			}
+
+			// Restore the positions.
+			*in_pos = in_start;
+			*out_pos = out_start;
+		}
+	}
+
+	// Free the decoder memory. This needs to be done even if
+	// initialization fails, because the internal API doesn't
+	// require the initialization function to free its memory on error.
+	lzma_next_end(&block_decoder, allocator);
+
+	return ret;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.c
new file mode 100644
index 00000000000..df3b90e8a18
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       block_buffer_encoder.c
+/// \brief      Single-call .xz Block encoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "block_buffer_encoder.h"
+#include "block_encoder.h"
+#include "filter_encoder.h"
+#include "lzma2_encoder.h"
+#include "check.h"
+
+
+/// Estimate the maximum size of the Block Header and Check fields for
+/// a Block that uses LZMA2 uncompressed chunks. We could use
+/// lzma_block_header_size() but this is simpler.
+///
+/// Block Header Size + Block Flags + Compressed Size
+/// + Uncompressed Size + Filter Flags for LZMA2 + CRC32 + Check
+/// and round up to the next multiple of four to take Header Padding
+/// into account.
+#define HEADERS_BOUND ((1 + 1 + 2 * LZMA_VLI_BYTES_MAX + 3 + 4 \
+		+ LZMA_CHECK_SIZE_MAX + 3) & ~3)
+
+
+static uint64_t
+lzma2_bound(uint64_t uncompressed_size)
+{
+	// Prevent integer overflow in overhead calculation.
+	if (uncompressed_size > COMPRESSED_SIZE_MAX)
+		return 0;
+
+	// Calculate the exact overhead of the LZMA2 headers: Round
+	// uncompressed_size up to the next multiple of LZMA2_CHUNK_MAX,
+	// multiply by the size of per-chunk header, and add one byte for
+	// the end marker.
+	const uint64_t overhead = ((uncompressed_size + LZMA2_CHUNK_MAX - 1)
+				/ LZMA2_CHUNK_MAX)
+			* LZMA2_HEADER_UNCOMPRESSED + 1;
+
+	// Catch the possible integer overflow.
+	if (COMPRESSED_SIZE_MAX - overhead < uncompressed_size)
+		return 0;
+
+	return uncompressed_size + overhead;
+}
+
+
+extern uint64_t
+lzma_block_buffer_bound64(uint64_t uncompressed_size)
+{
+	// If the data doesn't compress, we always use uncompressed
+	// LZMA2 chunks.
+	uint64_t lzma2_size = lzma2_bound(uncompressed_size);
+	if (lzma2_size == 0)
+		return 0;
+
+	// Take Block Padding into account.
+	lzma2_size = (lzma2_size + 3) & ~UINT64_C(3);
+
+	// No risk of integer overflow because lzma2_bound() already takes
+	// into account the size of the headers in the Block.
+	return HEADERS_BOUND + lzma2_size;
+}
+
+
+extern LZMA_API(size_t)
+lzma_block_buffer_bound(size_t uncompressed_size)
+{
+	uint64_t ret = lzma_block_buffer_bound64(uncompressed_size);
+
+#if SIZE_MAX < UINT64_MAX
+	// Catch the possible integer overflow on 32-bit systems.
+	if (ret > SIZE_MAX)
+		return 0;
+#endif
+
+	return ret;
+}
+
+
+static lzma_ret
+block_encode_uncompressed(lzma_block *block, const uint8_t *in, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+{
+	// Use LZMA2 uncompressed chunks. We wouldn't need a dictionary at
+	// all, but LZMA2 always requires a dictionary, so use the minimum
+	// value to minimize memory usage of the decoder.
+	lzma_options_lzma lzma2 = {
+		.dict_size = LZMA_DICT_SIZE_MIN,
+	};
+
+	lzma_filter filters[2];
+	filters[0].id = LZMA_FILTER_LZMA2;
+	filters[0].options = &lzma2;
+	filters[1].id = LZMA_VLI_UNKNOWN;
+
+	// Set the above filter options to *block temporarily so that we can
+	// encode the Block Header.
+	lzma_filter *filters_orig = block->filters;
+	block->filters = filters;
+
+	if (lzma_block_header_size(block) != LZMA_OK) {
+		block->filters = filters_orig;
+		return LZMA_PROG_ERROR;
+	}
+
+	// Check that there's enough output space. The caller has already
+	// set block->compressed_size to what lzma2_bound() has returned,
+	// so we can reuse that value. We know that compressed_size is a
+	// known valid VLI and header_size is a small value so their sum
+	// will never overflow.
+	assert(block->compressed_size == lzma2_bound(in_size));
+	if (out_size - *out_pos
+			< block->header_size + block->compressed_size) {
+		block->filters = filters_orig;
+		return LZMA_BUF_ERROR;
+	}
+
+	if (lzma_block_header_encode(block, out + *out_pos) != LZMA_OK) {
+		block->filters = filters_orig;
+		return LZMA_PROG_ERROR;
+	}
+
+	block->filters = filters_orig;
+	*out_pos += block->header_size;
+
+	// Encode the data using LZMA2 uncompressed chunks.
+	size_t in_pos = 0;
+	uint8_t control = 0x01; // Dictionary reset
+
+	while (in_pos < in_size) {
+		// Control byte: Indicate uncompressed chunk, of which
+		// the first resets the dictionary.
+		out[(*out_pos)++] = control;
+		control = 0x02; // No dictionary reset
+
+		// Size of the uncompressed chunk
+		const size_t copy_size
+				= my_min(in_size - in_pos, LZMA2_CHUNK_MAX);
+		out[(*out_pos)++] = (copy_size - 1) >> 8;
+		out[(*out_pos)++] = (copy_size - 1) & 0xFF;
+
+		// The actual data
+		assert(*out_pos + copy_size <= out_size);
+		memcpy(out + *out_pos, in + in_pos, copy_size);
+
+		in_pos += copy_size;
+		*out_pos += copy_size;
+	}
+
+	// End marker
+	out[(*out_pos)++] = 0x00;
+	assert(*out_pos <= out_size);
+
+	return LZMA_OK;
+}
+
+
+static lzma_ret
+block_encode_normal(lzma_block *block, const lzma_allocator *allocator,
+		const uint8_t *in, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+{
+	// Find out the size of the Block Header.
+	return_if_error(lzma_block_header_size(block));
+
+	// Reserve space for the Block Header and skip it for now.
+	if (out_size - *out_pos <= block->header_size)
+		return LZMA_BUF_ERROR;
+
+	const size_t out_start = *out_pos;
+	*out_pos += block->header_size;
+
+	// Limit out_size so that we stop encoding if the output would grow
+	// bigger than what uncompressed Block would be.
+	if (out_size - *out_pos > block->compressed_size)
+		out_size = *out_pos + block->compressed_size;
+
+	// TODO: In many common cases this could be optimized to use
+	// significantly less memory.
+	lzma_next_coder raw_encoder = LZMA_NEXT_CODER_INIT;
+	lzma_ret ret = lzma_raw_encoder_init(
+			&raw_encoder, allocator, block->filters);
+
+	if (ret == LZMA_OK) {
+		size_t in_pos = 0;
+		ret = raw_encoder.code(raw_encoder.coder, allocator,
+				in, &in_pos, in_size, out, out_pos, out_size,
+				LZMA_FINISH);
+	}
+
+	// NOTE: This needs to be run even if lzma_raw_encoder_init() failed.
+	lzma_next_end(&raw_encoder, allocator);
+
+	if (ret == LZMA_STREAM_END) {
+		// Compression was successful. Write the Block Header.
+		block->compressed_size
+				= *out_pos - (out_start + block->header_size);
+		ret = lzma_block_header_encode(block, out + out_start);
+		if (ret != LZMA_OK)
+			ret = LZMA_PROG_ERROR;
+
+	} else if (ret == LZMA_OK) {
+		// Output buffer became full.
+		ret = LZMA_BUF_ERROR;
+	}
+
+	// Reset *out_pos if something went wrong.
+	if (ret != LZMA_OK)
+		*out_pos = out_start;
+
+	return ret;
+}
+
+
+static lzma_ret
+block_buffer_encode(lzma_block *block, const lzma_allocator *allocator,
+		const uint8_t *in, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size,
+		bool try_to_compress)
+{
+	// Validate the arguments.
+	if (block == NULL || (in == NULL && in_size != 0) || out == NULL
+			|| out_pos == NULL || *out_pos > out_size)
+		return LZMA_PROG_ERROR;
+
+	// The contents of the structure may depend on the version so
+	// check the version before validating the contents of *block.
+	if (block->version > 1)
+		return LZMA_OPTIONS_ERROR;
+
+	if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX
+			|| (try_to_compress && block->filters == NULL))
+		return LZMA_PROG_ERROR;
+
+	if (!lzma_check_is_supported(block->check))
+		return LZMA_UNSUPPORTED_CHECK;
+
+	// Size of a Block has to be a multiple of four, so limit the size
+	// here already. This way we don't need to check it again when adding
+	// Block Padding.
+	out_size -= (out_size - *out_pos) & 3;
+
+	// Get the size of the Check field.
+	const size_t check_size = lzma_check_size(block->check);
+	assert(check_size != UINT32_MAX);
+
+	// Reserve space for the Check field.
+	if (out_size - *out_pos <= check_size)
+		return LZMA_BUF_ERROR;
+
+	out_size -= check_size;
+
+	// Initialize block->uncompressed_size and calculate the worst-case
+	// value for block->compressed_size.
+	block->uncompressed_size = in_size;
+	block->compressed_size = lzma2_bound(in_size);
+	if (block->compressed_size == 0)
+		return LZMA_DATA_ERROR;
+
+	// Do the actual compression.
+	lzma_ret ret = LZMA_BUF_ERROR;
+	if (try_to_compress)
+		ret = block_encode_normal(block, allocator,
+				in, in_size, out, out_pos, out_size);
+
+	if (ret != LZMA_OK) {
+		// If the error was something else than output buffer
+		// becoming full, return the error now.
+		if (ret != LZMA_BUF_ERROR)
+			return ret;
+
+		// The data was incompressible (at least with the options
+		// given to us) or the output buffer was too small. Use the
+		// uncompressed chunks of LZMA2 to wrap the data into a valid
+		// Block. If we haven't been given enough output space, even
+		// this may fail.
+		return_if_error(block_encode_uncompressed(block, in, in_size,
+				out, out_pos, out_size));
+	}
+
+	assert(*out_pos <= out_size);
+
+	// Block Padding. No buffer overflow here, because we already adjusted
+	// out_size so that (out_size - out_start) is a multiple of four.
+	// Thus, if the buffer is full, the loop body can never run.
+	for (size_t i = (size_t)(block->compressed_size); i & 3; ++i) {
+		assert(*out_pos < out_size);
+		out[(*out_pos)++] = 0x00;
+	}
+
+	// If there's no Check field, we are done now.
+	if (check_size > 0) {
+		// Calculate the integrity check. We reserved space for
+		// the Check field earlier so we don't need to check for
+		// available output space here.
+		lzma_check_state check;
+		lzma_check_init(&check, block->check);
+		lzma_check_update(&check, block->check, in, in_size);
+		lzma_check_finish(&check, block->check);
+
+		memcpy(block->raw_check, check.buffer.u8, check_size);
+		memcpy(out + *out_pos, check.buffer.u8, check_size);
+		*out_pos += check_size;
+	}
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_buffer_encode(lzma_block *block, const lzma_allocator *allocator,
+		const uint8_t *in, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+{
+	return block_buffer_encode(block, allocator,
+			in, in_size, out, out_pos, out_size, true);
+}
+
+
+#ifdef HAVE_SYMBOL_VERSIONS_LINUX
+// This is for compatibility with binaries linked against liblzma that
+// has been patched with xz-5.2.2-compat-libs.patch from RHEL/CentOS 7.
+LZMA_SYMVER_API("lzma_block_uncomp_encode@XZ_5.2.2",
+	lzma_ret, lzma_block_uncomp_encode_522)(lzma_block *block,
+		const uint8_t *in, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+		lzma_nothrow lzma_attr_warn_unused_result
+		__attribute__((__alias__("lzma_block_uncomp_encode_52")));
+
+LZMA_SYMVER_API("lzma_block_uncomp_encode@@XZ_5.2",
+	lzma_ret, lzma_block_uncomp_encode_52)(lzma_block *block,
+		const uint8_t *in, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+#define lzma_block_uncomp_encode lzma_block_uncomp_encode_52
+#endif
+extern LZMA_API(lzma_ret)
+lzma_block_uncomp_encode(lzma_block *block,
+		const uint8_t *in, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+{
+	// It won't allocate any memory from heap so no need
+	// for lzma_allocator.
+	return block_buffer_encode(block, NULL,
+			in, in_size, out, out_pos, out_size, false);
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.h
new file mode 100644
index 00000000000..5274ac40d3a
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_buffer_encoder.h
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       block_buffer_encoder.h
+/// \brief      Single-call .xz Block encoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_BLOCK_BUFFER_ENCODER_H
+#define LZMA_BLOCK_BUFFER_ENCODER_H
+
+#include "common.h"
+
+
+/// uint64_t version of lzma_block_buffer_bound(). It is used by
+/// stream_encoder_mt.c. Probably the original lzma_block_buffer_bound()
+/// should have been 64-bit, but fixing it would break the ABI.
+extern uint64_t lzma_block_buffer_bound64(uint64_t uncompressed_size);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.c
new file mode 100644
index 00000000000..2e369d316bd
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       block_decoder.c
+/// \brief      Decodes .xz Blocks
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "block_decoder.h"
+#include "filter_decoder.h"
+#include "check.h"
+
+
+typedef struct {
+	enum {
+		SEQ_CODE,
+		SEQ_PADDING,
+		SEQ_CHECK,
+	} sequence;
+
+	/// The filters in the chain; initialized with lzma_raw_decoder_init().
+	lzma_next_coder next;
+
+	/// Decoding options; we also write Compressed Size and Uncompressed
+	/// Size back to this structure when the decoding has been finished.
+	lzma_block *block;
+
+	/// Compressed Size calculated while decoding
+	lzma_vli compressed_size;
+
+	/// Uncompressed Size calculated while decoding
+	lzma_vli uncompressed_size;
+
+	/// Maximum allowed Compressed Size; this takes into account the
+	/// size of the Block Header and Check fields when Compressed Size
+	/// is unknown.
+	lzma_vli compressed_limit;
+
+	/// Maximum allowed Uncompressed Size.
+	lzma_vli uncompressed_limit;
+
+	/// Position when reading the Check field
+	size_t check_pos;
+
+	/// Check of the uncompressed data
+	lzma_check_state check;
+
+	/// True if the integrity check won't be calculated and verified.
+	bool ignore_check;
+} lzma_block_coder;
+
+
+static inline bool
+is_size_valid(lzma_vli size, lzma_vli reference)
+{
+	return reference == LZMA_VLI_UNKNOWN || reference == size;
+}
+
+
+static lzma_ret
+block_decode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size, lzma_action action)
+{
+	lzma_block_coder *coder = coder_ptr;
+
+	switch (coder->sequence) {
+	case SEQ_CODE: {
+		const size_t in_start = *in_pos;
+		const size_t out_start = *out_pos;
+
+		// Limit the amount of input and output space that we give
+		// to the raw decoder based on the information we have
+		// (or don't have) from Block Header.
+		const size_t in_stop = *in_pos + (size_t)my_min(
+			in_size - *in_pos,
+			coder->compressed_limit - coder->compressed_size);
+		const size_t out_stop = *out_pos + (size_t)my_min(
+			out_size - *out_pos,
+			coder->uncompressed_limit - coder->uncompressed_size);
+
+		const lzma_ret ret = coder->next.code(coder->next.coder,
+				allocator, in, in_pos, in_stop,
+				out, out_pos, out_stop, action);
+
+		const size_t in_used = *in_pos - in_start;
+		const size_t out_used = *out_pos - out_start;
+
+		// Because we have limited the input and output sizes,
+		// we know that these cannot grow too big or overflow.
+		coder->compressed_size += in_used;
+		coder->uncompressed_size += out_used;
+
+		if (ret == LZMA_OK) {
+			const bool comp_done = coder->compressed_size
+					== coder->block->compressed_size;
+			const bool uncomp_done = coder->uncompressed_size
+					== coder->block->uncompressed_size;
+
+			// If both input and output amounts match the sizes
+			// in Block Header but we still got LZMA_OK instead
+			// of LZMA_STREAM_END, the file is broken.
+			if (comp_done && uncomp_done)
+				return LZMA_DATA_ERROR;
+
+			// If the decoder has consumed all the input that it
+			// needs but it still couldn't fill the output buffer
+			// or return LZMA_STREAM_END, the file is broken.
+			if (comp_done && *out_pos < out_size)
+				return LZMA_DATA_ERROR;
+
+			// If the decoder has produced all the output but
+			// it still didn't return LZMA_STREAM_END or consume
+			// more input (for example, detecting an end of
+			// payload marker may need more input but produce
+			// no output) the file is broken.
+			if (uncomp_done && *in_pos < in_size)
+				return LZMA_DATA_ERROR;
+		}
+
+		// Don't waste time updating the integrity check if it will be
+		// ignored. Also skip it if no new output was produced. This
+		// avoids null pointer + 0 (undefined behavior) when out == 0.
+		if (!coder->ignore_check && out_used > 0)
+			lzma_check_update(&coder->check, coder->block->check,
+					out + out_start, out_used);
+
+		if (ret != LZMA_STREAM_END)
+			return ret;
+
+		// Compressed and Uncompressed Sizes are now at their final
+		// values. Verify that they match the values given to us.
+		if (!is_size_valid(coder->compressed_size,
+					coder->block->compressed_size)
+				|| !is_size_valid(coder->uncompressed_size,
+					coder->block->uncompressed_size))
+			return LZMA_DATA_ERROR;
+
+		// Copy the values into coder->block. The caller
+		// may use this information to construct Index.
+		coder->block->compressed_size = coder->compressed_size;
+		coder->block->uncompressed_size = coder->uncompressed_size;
+
+		coder->sequence = SEQ_PADDING;
+	}
+
+	// Fall through
+
+	case SEQ_PADDING:
+		// Compressed Data is padded to a multiple of four bytes.
+		while (coder->compressed_size & 3) {
+			if (*in_pos >= in_size)
+				return LZMA_OK;
+
+			// We use compressed_size here just get the Padding
+			// right. The actual Compressed Size was stored to
+			// coder->block already, and won't be modified by
+			// us anymore.
+			++coder->compressed_size;
+
+			if (in[(*in_pos)++] != 0x00)
+				return LZMA_DATA_ERROR;
+		}
+
+		if (coder->block->check == LZMA_CHECK_NONE)
+			return LZMA_STREAM_END;
+
+		if (!coder->ignore_check)
+			lzma_check_finish(&coder->check, coder->block->check);
+
+		coder->sequence = SEQ_CHECK;
+
+	// Fall through
+
+	case SEQ_CHECK: {
+		const size_t check_size = lzma_check_size(coder->block->check);
+		lzma_bufcpy(in, in_pos, in_size, coder->block->raw_check,
+				&coder->check_pos, check_size);
+		if (coder->check_pos < check_size)
+			return LZMA_OK;
+
+		// Validate the Check only if we support it.
+		// coder->check.buffer may be uninitialized
+		// when the Check ID is not supported.
+		if (!coder->ignore_check
+				&& lzma_check_is_supported(coder->block->check)
+				&& memcmp(coder->block->raw_check,
+					coder->check.buffer.u8,
+					check_size) != 0)
+			return LZMA_DATA_ERROR;
+
+		return LZMA_STREAM_END;
+	}
+	}
+
+	return LZMA_PROG_ERROR;
+}
+
+
+static void
+block_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_block_coder *coder = coder_ptr;
+	lzma_next_end(&coder->next, allocator);
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+extern lzma_ret
+lzma_block_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		lzma_block *block)
+{
+	lzma_next_coder_init(&lzma_block_decoder_init, next, allocator);
+
+	// Validate the options. lzma_block_unpadded_size() does that for us
+	// except for Uncompressed Size and filters. Filters are validated
+	// by the raw decoder.
+	if (lzma_block_unpadded_size(block) == 0
+			|| !lzma_vli_is_valid(block->uncompressed_size))
+		return LZMA_PROG_ERROR;
+
+	// Allocate *next->coder if needed.
+	lzma_block_coder *coder = next->coder;
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_block_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+		next->code = &block_decode;
+		next->end = &block_decoder_end;
+		coder->next = LZMA_NEXT_CODER_INIT;
+	}
+
+	// Basic initializations
+	coder->sequence = SEQ_CODE;
+	coder->block = block;
+	coder->compressed_size = 0;
+	coder->uncompressed_size = 0;
+
+	// If Compressed Size is not known, we calculate the maximum allowed
+	// value so that encoded size of the Block (including Block Padding)
+	// is still a valid VLI and a multiple of four.
+	coder->compressed_limit
+			= block->compressed_size == LZMA_VLI_UNKNOWN
+				? (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
+					- block->header_size
+					- lzma_check_size(block->check)
+				: block->compressed_size;
+
+	// With Uncompressed Size this is simpler. If Block Header lacks
+	// the size info, then LZMA_VLI_MAX is the maximum possible
+	// Uncompressed Size.
+	coder->uncompressed_limit
+			= block->uncompressed_size == LZMA_VLI_UNKNOWN
+				? LZMA_VLI_MAX
+				: block->uncompressed_size;
+
+	// Initialize the check. It's caller's problem if the Check ID is not
+	// supported, and the Block decoder cannot verify the Check field.
+	// Caller can test lzma_check_is_supported(block->check).
+	coder->check_pos = 0;
+	lzma_check_init(&coder->check, block->check);
+
+	coder->ignore_check = block->version >= 1
+			? block->ignore_check : false;
+
+	// Initialize the filter chain.
+	return lzma_raw_decoder_init(&coder->next, allocator,
+			block->filters);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_decoder(lzma_stream *strm, lzma_block *block)
+{
+	lzma_next_strm_init(lzma_block_decoder_init, strm, block);
+
+	strm->internal->supported_actions[LZMA_RUN] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.h
new file mode 100644
index 00000000000..2cbf9ba6db8
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_decoder.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       block_decoder.h
+/// \brief      Decodes .xz Blocks
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_BLOCK_DECODER_H
+#define LZMA_BLOCK_DECODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_block_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator, lzma_block *block);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.c
new file mode 100644
index 00000000000..ce8c1de6944
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       block_encoder.c
+/// \brief      Encodes .xz Blocks
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "block_encoder.h"
+#include "filter_encoder.h"
+#include "check.h"
+
+
+typedef struct {
+	/// The filters in the chain; initialized with lzma_raw_decoder_init().
+	lzma_next_coder next;
+
+	/// Encoding options; we also write Unpadded Size, Compressed Size,
+	/// and Uncompressed Size back to this structure when the encoding
+	/// has been finished.
+	lzma_block *block;
+
+	enum {
+		SEQ_CODE,
+		SEQ_PADDING,
+		SEQ_CHECK,
+	} sequence;
+
+	/// Compressed Size calculated while encoding
+	lzma_vli compressed_size;
+
+	/// Uncompressed Size calculated while encoding
+	lzma_vli uncompressed_size;
+
+	/// Position in the Check field
+	size_t pos;
+
+	/// Check of the uncompressed data
+	lzma_check_state check;
+} lzma_block_coder;
+
+
+static lzma_ret
+block_encode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size, lzma_action action)
+{
+	lzma_block_coder *coder = coder_ptr;
+
+	// Check that our amount of input stays in proper limits.
+	if (LZMA_VLI_MAX - coder->uncompressed_size < in_size - *in_pos)
+		return LZMA_DATA_ERROR;
+
+	switch (coder->sequence) {
+	case SEQ_CODE: {
+		const size_t in_start = *in_pos;
+		const size_t out_start = *out_pos;
+
+		const lzma_ret ret = coder->next.code(coder->next.coder,
+				allocator, in, in_pos, in_size,
+				out, out_pos, out_size, action);
+
+		const size_t in_used = *in_pos - in_start;
+		const size_t out_used = *out_pos - out_start;
+
+		if (COMPRESSED_SIZE_MAX - coder->compressed_size < out_used)
+			return LZMA_DATA_ERROR;
+
+		coder->compressed_size += out_used;
+
+		// No need to check for overflow because we have already
+		// checked it at the beginning of this function.
+		coder->uncompressed_size += in_used;
+
+		// Call lzma_check_update() only if input was consumed. This
+		// avoids null pointer + 0 (undefined behavior) when in == 0.
+		if (in_used > 0)
+			lzma_check_update(&coder->check, coder->block->check,
+					in + in_start, in_used);
+
+		if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
+			return ret;
+
+		assert(*in_pos == in_size);
+		assert(action == LZMA_FINISH);
+
+		// Copy the values into coder->block. The caller
+		// may use this information to construct Index.
+		coder->block->compressed_size = coder->compressed_size;
+		coder->block->uncompressed_size = coder->uncompressed_size;
+
+		coder->sequence = SEQ_PADDING;
+	}
+
+	// Fall through
+
+	case SEQ_PADDING:
+		// Pad Compressed Data to a multiple of four bytes. We can
+		// use coder->compressed_size for this since we don't need
+		// it for anything else anymore.
+		while (coder->compressed_size & 3) {
+			if (*out_pos >= out_size)
+				return LZMA_OK;
+
+			out[*out_pos] = 0x00;
+			++*out_pos;
+			++coder->compressed_size;
+		}
+
+		if (coder->block->check == LZMA_CHECK_NONE)
+			return LZMA_STREAM_END;
+
+		lzma_check_finish(&coder->check, coder->block->check);
+
+		coder->sequence = SEQ_CHECK;
+
+	// Fall through
+
+	case SEQ_CHECK: {
+		const size_t check_size = lzma_check_size(coder->block->check);
+		lzma_bufcpy(coder->check.buffer.u8, &coder->pos, check_size,
+				out, out_pos, out_size);
+		if (coder->pos < check_size)
+			return LZMA_OK;
+
+		memcpy(coder->block->raw_check, coder->check.buffer.u8,
+				check_size);
+		return LZMA_STREAM_END;
+	}
+	}
+
+	return LZMA_PROG_ERROR;
+}
+
+
+static void
+block_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_block_coder *coder = coder_ptr;
+	lzma_next_end(&coder->next, allocator);
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_ret
+block_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
+		const lzma_filter *filters lzma_attribute((__unused__)),
+		const lzma_filter *reversed_filters)
+{
+	lzma_block_coder *coder = coder_ptr;
+
+	if (coder->sequence != SEQ_CODE)
+		return LZMA_PROG_ERROR;
+
+	return lzma_next_filter_update(
+			&coder->next, allocator, reversed_filters);
+}
+
+
+extern lzma_ret
+lzma_block_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		lzma_block *block)
+{
+	lzma_next_coder_init(&lzma_block_encoder_init, next, allocator);
+
+	if (block == NULL)
+		return LZMA_PROG_ERROR;
+
+	// The contents of the structure may depend on the version so
+	// check the version first.
+	if (block->version > 1)
+		return LZMA_OPTIONS_ERROR;
+
+	// If the Check ID is not supported, we cannot calculate the check and
+	// thus not create a proper Block.
+	if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX)
+		return LZMA_PROG_ERROR;
+
+	if (!lzma_check_is_supported(block->check))
+		return LZMA_UNSUPPORTED_CHECK;
+
+	// Allocate and initialize *next->coder if needed.
+	lzma_block_coder *coder = next->coder;
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_block_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+		next->code = &block_encode;
+		next->end = &block_encoder_end;
+		next->update = &block_encoder_update;
+		coder->next = LZMA_NEXT_CODER_INIT;
+	}
+
+	// Basic initializations
+	coder->sequence = SEQ_CODE;
+	coder->block = block;
+	coder->compressed_size = 0;
+	coder->uncompressed_size = 0;
+	coder->pos = 0;
+
+	// Initialize the check
+	lzma_check_init(&coder->check, block->check);
+
+	// Initialize the requested filters.
+	return lzma_raw_encoder_init(&coder->next, allocator, block->filters);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_encoder(lzma_stream *strm, lzma_block *block)
+{
+	lzma_next_strm_init(lzma_block_encoder_init, strm, block);
+
+	strm->internal->supported_actions[LZMA_RUN] = true;
+	strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.h
new file mode 100644
index 00000000000..b7dfe9a0841
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_encoder.h
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       block_encoder.h
+/// \brief      Encodes .xz Blocks
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_BLOCK_ENCODER_H
+#define LZMA_BLOCK_ENCODER_H
+
+#include "common.h"
+
+
+/// \brief      Biggest Compressed Size value that the Block encoder supports
+///
+/// The maximum size of a single Block is limited by the maximum size of
+/// a Stream, which in theory is 2^63 - 3 bytes (i.e. LZMA_VLI_MAX - 3).
+/// While the size is really big and no one should hit it in practice, we
+/// take it into account in some places anyway to catch some errors e.g. if
+/// application passes insanely big value to some function.
+///
+/// We could take into account the headers etc. to determine the exact
+/// maximum size of the Compressed Data field, but the complexity would give
+/// us nothing useful. Instead, limit the size of Compressed Data so that
+/// even with biggest possible Block Header and Check fields the total
+/// encoded size of the Block stays as a valid VLI. This doesn't guarantee
+/// that the size of the Stream doesn't grow too big, but that problem is
+/// taken care outside the Block handling code.
+///
+/// ~LZMA_VLI_C(3) is to guarantee that if we need padding at the end of
+/// the Compressed Data field, it will still stay in the proper limit.
+///
+/// This constant is in this file because it is needed in both
+/// block_encoder.c and block_buffer_encoder.c.
+#define COMPRESSED_SIZE_MAX ((LZMA_VLI_MAX - LZMA_BLOCK_HEADER_SIZE_MAX \
+		- LZMA_CHECK_SIZE_MAX) & ~LZMA_VLI_C(3))
+
+
+extern lzma_ret lzma_block_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator, lzma_block *block);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_decoder.c
new file mode 100644
index 00000000000..f0b2fbe54d8
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_decoder.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       block_header_decoder.c
+/// \brief      Decodes Block Header from .xz files
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+#include "check.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_header_decode(lzma_block *block,
+		const lzma_allocator *allocator, const uint8_t *in)
+{
+	// NOTE: We consider the header to be corrupt not only when the
+	// CRC32 doesn't match, but also when variable-length integers
+	// are invalid or over 63 bits, or if the header is too small
+	// to contain the claimed information.
+
+	// Catch unexpected NULL pointers.
+	if (block == NULL || block->filters == NULL || in == NULL)
+		return LZMA_PROG_ERROR;
+
+	// Initialize the filter options array. This way the caller can
+	// safely free() the options even if an error occurs in this function.
+	for (size_t i = 0; i <= LZMA_FILTERS_MAX; ++i) {
+		block->filters[i].id = LZMA_VLI_UNKNOWN;
+		block->filters[i].options = NULL;
+	}
+
+	// Versions 0 and 1 are supported. If a newer version was specified,
+	// we need to downgrade it.
+	if (block->version > 1)
+		block->version = 1;
+
+	// This isn't a Block Header option, but since the decompressor will
+	// read it if version >= 1, it's better to initialize it here than
+	// to expect the caller to do it since in almost all cases this
+	// should be false.
+	block->ignore_check = false;
+
+	// Validate Block Header Size and Check type. The caller must have
+	// already set these, so it is a programming error if this test fails.
+	if (lzma_block_header_size_decode(in[0]) != block->header_size
+			|| (unsigned int)(block->check) > LZMA_CHECK_ID_MAX)
+		return LZMA_PROG_ERROR;
+
+	// Exclude the CRC32 field.
+	const size_t in_size = block->header_size - 4;
+
+	// Verify CRC32
+	if (lzma_crc32(in, in_size, 0) != read32le(in + in_size)) {
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+		return LZMA_DATA_ERROR;
+#endif
+	}
+
+	// Check for unsupported flags.
+	if (in[1] & 0x3C)
+		return LZMA_OPTIONS_ERROR;
+
+	// Start after the Block Header Size and Block Flags fields.
+	size_t in_pos = 2;
+
+	// Compressed Size
+	if (in[1] & 0x40) {
+		return_if_error(lzma_vli_decode(&block->compressed_size,
+				NULL, in, &in_pos, in_size));
+
+		// Validate Compressed Size. This checks that it isn't zero
+		// and that the total size of the Block is a valid VLI.
+		if (lzma_block_unpadded_size(block) == 0)
+			return LZMA_DATA_ERROR;
+	} else {
+		block->compressed_size = LZMA_VLI_UNKNOWN;
+	}
+
+	// Uncompressed Size
+	if (in[1] & 0x80)
+		return_if_error(lzma_vli_decode(&block->uncompressed_size,
+				NULL, in, &in_pos, in_size));
+	else
+		block->uncompressed_size = LZMA_VLI_UNKNOWN;
+
+	// Filter Flags
+	const size_t filter_count = (in[1] & 3U) + 1;
+	for (size_t i = 0; i < filter_count; ++i) {
+		const lzma_ret ret = lzma_filter_flags_decode(
+				&block->filters[i], allocator,
+				in, &in_pos, in_size);
+		if (ret != LZMA_OK) {
+			lzma_filters_free(block->filters, allocator);
+			return ret;
+		}
+	}
+
+	// Padding
+	while (in_pos < in_size) {
+		if (in[in_pos++] != 0x00) {
+			lzma_filters_free(block->filters, allocator);
+
+			// Possibly some new field present so use
+			// LZMA_OPTIONS_ERROR instead of LZMA_DATA_ERROR.
+			return LZMA_OPTIONS_ERROR;
+		}
+	}
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_encoder.c
new file mode 100644
index 00000000000..45e57a26aba
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_header_encoder.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       block_header_encoder.c
+/// \brief      Encodes Block Header for .xz files
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+#include "check.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_header_size(lzma_block *block)
+{
+	if (block->version > 1)
+		return LZMA_OPTIONS_ERROR;
+
+	// Block Header Size + Block Flags + CRC32.
+	uint32_t size = 1 + 1 + 4;
+
+	// Compressed Size
+	if (block->compressed_size != LZMA_VLI_UNKNOWN) {
+		const uint32_t add = lzma_vli_size(block->compressed_size);
+		if (add == 0 || block->compressed_size == 0)
+			return LZMA_PROG_ERROR;
+
+		size += add;
+	}
+
+	// Uncompressed Size
+	if (block->uncompressed_size != LZMA_VLI_UNKNOWN) {
+		const uint32_t add = lzma_vli_size(block->uncompressed_size);
+		if (add == 0)
+			return LZMA_PROG_ERROR;
+
+		size += add;
+	}
+
+	// List of Filter Flags
+	if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN)
+		return LZMA_PROG_ERROR;
+
+	for (size_t i = 0; block->filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
+		// Don't allow too many filters.
+		if (i == LZMA_FILTERS_MAX)
+			return LZMA_PROG_ERROR;
+
+		uint32_t add;
+		return_if_error(lzma_filter_flags_size(&add,
+				block->filters + i));
+
+		size += add;
+	}
+
+	// Pad to a multiple of four bytes.
+	block->header_size = (size + 3) & ~UINT32_C(3);
+
+	// NOTE: We don't verify that the encoded size of the Block stays
+	// within limits. This is because it is possible that we are called
+	// with exaggerated Compressed Size (e.g. LZMA_VLI_MAX) to reserve
+	// space for Block Header, and later called again with lower,
+	// real values.
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_header_encode(const lzma_block *block, uint8_t *out)
+{
+	// Validate everything but filters.
+	if (lzma_block_unpadded_size(block) == 0
+			|| !lzma_vli_is_valid(block->uncompressed_size))
+		return LZMA_PROG_ERROR;
+
+	// Indicate the size of the buffer _excluding_ the CRC32 field.
+	const size_t out_size = block->header_size - 4;
+
+	// Store the Block Header Size.
+	out[0] = out_size / 4;
+
+	// We write Block Flags in pieces.
+	out[1] = 0x00;
+	size_t out_pos = 2;
+
+	// Compressed Size
+	if (block->compressed_size != LZMA_VLI_UNKNOWN) {
+		return_if_error(lzma_vli_encode(block->compressed_size, NULL,
+				out, &out_pos, out_size));
+
+		out[1] |= 0x40;
+	}
+
+	// Uncompressed Size
+	if (block->uncompressed_size != LZMA_VLI_UNKNOWN) {
+		return_if_error(lzma_vli_encode(block->uncompressed_size, NULL,
+				out, &out_pos, out_size));
+
+		out[1] |= 0x80;
+	}
+
+	// Filter Flags
+	if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN)
+		return LZMA_PROG_ERROR;
+
+	size_t filter_count = 0;
+	do {
+		// There can be a maximum of four filters.
+		if (filter_count == LZMA_FILTERS_MAX)
+			return LZMA_PROG_ERROR;
+
+		return_if_error(lzma_filter_flags_encode(
+				block->filters + filter_count,
+				out, &out_pos, out_size));
+
+	} while (block->filters[++filter_count].id != LZMA_VLI_UNKNOWN);
+
+	out[1] |= filter_count - 1;
+
+	// Padding
+	memzero(out + out_pos, out_size - out_pos);
+
+	// CRC32
+	write32le(out + out_size, lzma_crc32(out, out_size, 0));
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_util.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_util.c
new file mode 100644
index 00000000000..191f6d444aa
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/block_util.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       block_util.c
+/// \brief      Utility functions to handle lzma_block
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+#include "index.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_compressed_size(lzma_block *block, lzma_vli unpadded_size)
+{
+	// Validate everything but Uncompressed Size and filters.
+	if (lzma_block_unpadded_size(block) == 0)
+		return LZMA_PROG_ERROR;
+
+	const uint32_t container_size = block->header_size
+			+ lzma_check_size(block->check);
+
+	// Validate that Compressed Size will be greater than zero.
+	if (unpadded_size <= container_size)
+		return LZMA_DATA_ERROR;
+
+	// Calculate what Compressed Size is supposed to be.
+	// If Compressed Size was present in Block Header,
+	// compare that the new value matches it.
+	const lzma_vli compressed_size = unpadded_size - container_size;
+	if (block->compressed_size != LZMA_VLI_UNKNOWN
+			&& block->compressed_size != compressed_size)
+		return LZMA_DATA_ERROR;
+
+	block->compressed_size = compressed_size;
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_block_unpadded_size(const lzma_block *block)
+{
+	// Validate the values that we are interested in i.e. all but
+	// Uncompressed Size and the filters.
+	//
+	// NOTE: This function is used for validation too, so it is
+	// essential that these checks are always done even if
+	// Compressed Size is unknown.
+	if (block == NULL || block->version > 1
+			|| block->header_size < LZMA_BLOCK_HEADER_SIZE_MIN
+			|| block->header_size > LZMA_BLOCK_HEADER_SIZE_MAX
+			|| (block->header_size & 3)
+			|| !lzma_vli_is_valid(block->compressed_size)
+			|| block->compressed_size == 0
+			|| (unsigned int)(block->check) > LZMA_CHECK_ID_MAX)
+		return 0;
+
+	// If Compressed Size is unknown, return that we cannot know
+	// size of the Block either.
+	if (block->compressed_size == LZMA_VLI_UNKNOWN)
+		return LZMA_VLI_UNKNOWN;
+
+	// Calculate Unpadded Size and validate it.
+	const lzma_vli unpadded_size = block->compressed_size
+				+ block->header_size
+				+ lzma_check_size(block->check);
+
+	assert(unpadded_size >= UNPADDED_SIZE_MIN);
+	if (unpadded_size > UNPADDED_SIZE_MAX)
+		return 0;
+
+	return unpadded_size;
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_block_total_size(const lzma_block *block)
+{
+	lzma_vli unpadded_size = lzma_block_unpadded_size(block);
+
+	if (unpadded_size != LZMA_VLI_UNKNOWN)
+		unpadded_size = vli_ceil4(unpadded_size);
+
+	return unpadded_size;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.c
new file mode 100644
index 00000000000..cc0e06a51be
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.c
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       common.c
+/// \brief      Common functions needed in many places in liblzma
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+
+/////////////
+// Version //
+/////////////
+
+extern LZMA_API(uint32_t)
+lzma_version_number(void)
+{
+	return LZMA_VERSION;
+}
+
+
+extern LZMA_API(const char *)
+lzma_version_string(void)
+{
+	return LZMA_VERSION_STRING;
+}
+
+
+///////////////////////
+// Memory allocation //
+///////////////////////
+
+lzma_attr_alloc_size(1)
+extern void *
+lzma_alloc(size_t size, const lzma_allocator *allocator)
+{
+	// Some malloc() variants return NULL if called with size == 0.
+	if (size == 0)
+		size = 1;
+
+	void *ptr;
+
+	if (allocator != NULL && allocator->alloc != NULL)
+		ptr = allocator->alloc(allocator->opaque, 1, size);
+	else
+		ptr = malloc(size);
+
+	return ptr;
+}
+
+
+lzma_attr_alloc_size(1)
+extern void *
+lzma_alloc_zero(size_t size, const lzma_allocator *allocator)
+{
+	// Some calloc() variants return NULL if called with size == 0.
+	if (size == 0)
+		size = 1;
+
+	void *ptr;
+
+	if (allocator != NULL && allocator->alloc != NULL) {
+		ptr = allocator->alloc(allocator->opaque, 1, size);
+		if (ptr != NULL)
+			memzero(ptr, size);
+	} else {
+		ptr = calloc(1, size);
+	}
+
+	return ptr;
+}
+
+
+extern void
+lzma_free(void *ptr, const lzma_allocator *allocator)
+{
+	if (allocator != NULL && allocator->free != NULL)
+		allocator->free(allocator->opaque, ptr);
+	else
+		free(ptr);
+
+	return;
+}
+
+
+//////////
+// Misc //
+//////////
+
+extern size_t
+lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size)
+{
+	const size_t in_avail = in_size - *in_pos;
+	const size_t out_avail = out_size - *out_pos;
+	const size_t copy_size = my_min(in_avail, out_avail);
+
+	// Call memcpy() only if there is something to copy. If there is
+	// nothing to copy, in or out might be NULL and then the memcpy()
+	// call would trigger undefined behavior.
+	if (copy_size > 0)
+		memcpy(out + *out_pos, in + *in_pos, copy_size);
+
+	*in_pos += copy_size;
+	*out_pos += copy_size;
+
+	return copy_size;
+}
+
+
+extern lzma_ret
+lzma_next_filter_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	lzma_next_coder_init(filters[0].init, next, allocator);
+	next->id = filters[0].id;
+	return filters[0].init == NULL
+			? LZMA_OK : filters[0].init(next, allocator, filters);
+}
+
+
+extern lzma_ret
+lzma_next_filter_update(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter *reversed_filters)
+{
+	// Check that the application isn't trying to change the Filter ID.
+	// End of filters is indicated with LZMA_VLI_UNKNOWN in both
+	// reversed_filters[0].id and next->id.
+	if (reversed_filters[0].id != next->id)
+		return LZMA_PROG_ERROR;
+
+	if (reversed_filters[0].id == LZMA_VLI_UNKNOWN)
+		return LZMA_OK;
+
+	assert(next->update != NULL);
+	return next->update(next->coder, allocator, NULL, reversed_filters);
+}
+
+
+extern void
+lzma_next_end(lzma_next_coder *next, const lzma_allocator *allocator)
+{
+	if (next->init != (uintptr_t)(NULL)) {
+		// To avoid tiny end functions that simply call
+		// lzma_free(coder, allocator), we allow leaving next->end
+		// NULL and call lzma_free() here.
+		if (next->end != NULL)
+			next->end(next->coder, allocator);
+		else
+			lzma_free(next->coder, allocator);
+
+		// Reset the variables so the we don't accidentally think
+		// that it is an already initialized coder.
+		*next = LZMA_NEXT_CODER_INIT;
+	}
+
+	return;
+}
+
+
+//////////////////////////////////////
+// External to internal API wrapper //
+//////////////////////////////////////
+
+extern lzma_ret
+lzma_strm_init(lzma_stream *strm)
+{
+	if (strm == NULL)
+		return LZMA_PROG_ERROR;
+
+	if (strm->internal == NULL) {
+		strm->internal = lzma_alloc(sizeof(lzma_internal),
+				strm->allocator);
+		if (strm->internal == NULL)
+			return LZMA_MEM_ERROR;
+
+		strm->internal->next = LZMA_NEXT_CODER_INIT;
+	}
+
+	memzero(strm->internal->supported_actions,
+			sizeof(strm->internal->supported_actions));
+	strm->internal->sequence = ISEQ_RUN;
+	strm->internal->allow_buf_error = false;
+
+	strm->total_in = 0;
+	strm->total_out = 0;
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_code(lzma_stream *strm, lzma_action action)
+{
+	// Sanity checks
+	if ((strm->next_in == NULL && strm->avail_in != 0)
+			|| (strm->next_out == NULL && strm->avail_out != 0)
+			|| strm->internal == NULL
+			|| strm->internal->next.code == NULL
+			|| (unsigned int)(action) > LZMA_ACTION_MAX
+			|| !strm->internal->supported_actions[action])
+		return LZMA_PROG_ERROR;
+
+	// Check if unsupported members have been set to non-zero or non-NULL,
+	// which would indicate that some new feature is wanted.
+	if (strm->reserved_ptr1 != NULL
+			|| strm->reserved_ptr2 != NULL
+			|| strm->reserved_ptr3 != NULL
+			|| strm->reserved_ptr4 != NULL
+			|| strm->reserved_int2 != 0
+			|| strm->reserved_int3 != 0
+			|| strm->reserved_int4 != 0
+			|| strm->reserved_enum1 != LZMA_RESERVED_ENUM
+			|| strm->reserved_enum2 != LZMA_RESERVED_ENUM)
+		return LZMA_OPTIONS_ERROR;
+
+	switch (strm->internal->sequence) {
+	case ISEQ_RUN:
+		switch (action) {
+		case LZMA_RUN:
+			break;
+
+		case LZMA_SYNC_FLUSH:
+			strm->internal->sequence = ISEQ_SYNC_FLUSH;
+			break;
+
+		case LZMA_FULL_FLUSH:
+			strm->internal->sequence = ISEQ_FULL_FLUSH;
+			break;
+
+		case LZMA_FINISH:
+			strm->internal->sequence = ISEQ_FINISH;
+			break;
+
+		case LZMA_FULL_BARRIER:
+			strm->internal->sequence = ISEQ_FULL_BARRIER;
+			break;
+		}
+
+		break;
+
+	case ISEQ_SYNC_FLUSH:
+		// The same action must be used until we return
+		// LZMA_STREAM_END, and the amount of input must not change.
+		if (action != LZMA_SYNC_FLUSH
+				|| strm->internal->avail_in != strm->avail_in)
+			return LZMA_PROG_ERROR;
+
+		break;
+
+	case ISEQ_FULL_FLUSH:
+		if (action != LZMA_FULL_FLUSH
+				|| strm->internal->avail_in != strm->avail_in)
+			return LZMA_PROG_ERROR;
+
+		break;
+
+	case ISEQ_FINISH:
+		if (action != LZMA_FINISH
+				|| strm->internal->avail_in != strm->avail_in)
+			return LZMA_PROG_ERROR;
+
+		break;
+
+	case ISEQ_FULL_BARRIER:
+		if (action != LZMA_FULL_BARRIER
+				|| strm->internal->avail_in != strm->avail_in)
+			return LZMA_PROG_ERROR;
+
+		break;
+
+	case ISEQ_END:
+		return LZMA_STREAM_END;
+
+	case ISEQ_ERROR:
+	default:
+		return LZMA_PROG_ERROR;
+	}
+
+	size_t in_pos = 0;
+	size_t out_pos = 0;
+	lzma_ret ret = strm->internal->next.code(
+			strm->internal->next.coder, strm->allocator,
+			strm->next_in, &in_pos, strm->avail_in,
+			strm->next_out, &out_pos, strm->avail_out, action);
+
+	// Updating next_in and next_out has to be skipped when they are NULL
+	// to avoid null pointer + 0 (undefined behavior). Do this by checking
+	// in_pos > 0 and out_pos > 0 because this way NULL + non-zero (a bug)
+	// will get caught one way or other.
+	if (in_pos > 0) {
+		strm->next_in += in_pos;
+		strm->avail_in -= in_pos;
+		strm->total_in += in_pos;
+	}
+
+	if (out_pos > 0) {
+		strm->next_out += out_pos;
+		strm->avail_out -= out_pos;
+		strm->total_out += out_pos;
+	}
+
+	strm->internal->avail_in = strm->avail_in;
+
+	switch (ret) {
+	case LZMA_OK:
+		// Don't return LZMA_BUF_ERROR when it happens the first time.
+		// This is to avoid returning LZMA_BUF_ERROR when avail_out
+		// was zero but still there was no more data left to written
+		// to next_out.
+		if (out_pos == 0 && in_pos == 0) {
+			if (strm->internal->allow_buf_error)
+				ret = LZMA_BUF_ERROR;
+			else
+				strm->internal->allow_buf_error = true;
+		} else {
+			strm->internal->allow_buf_error = false;
+		}
+		break;
+
+	case LZMA_TIMED_OUT:
+		strm->internal->allow_buf_error = false;
+		ret = LZMA_OK;
+		break;
+
+	case LZMA_SEEK_NEEDED:
+		strm->internal->allow_buf_error = false;
+
+		// If LZMA_FINISH was used, reset it back to the
+		// LZMA_RUN-based state so that new input can be supplied
+		// by the application.
+		if (strm->internal->sequence == ISEQ_FINISH)
+			strm->internal->sequence = ISEQ_RUN;
+
+		break;
+
+	case LZMA_STREAM_END:
+		if (strm->internal->sequence == ISEQ_SYNC_FLUSH
+				|| strm->internal->sequence == ISEQ_FULL_FLUSH
+				|| strm->internal->sequence
+					== ISEQ_FULL_BARRIER)
+			strm->internal->sequence = ISEQ_RUN;
+		else
+			strm->internal->sequence = ISEQ_END;
+
+	// Fall through
+
+	case LZMA_NO_CHECK:
+	case LZMA_UNSUPPORTED_CHECK:
+	case LZMA_GET_CHECK:
+	case LZMA_MEMLIMIT_ERROR:
+		// Something else than LZMA_OK, but not a fatal error,
+		// that is, coding may be continued (except if ISEQ_END).
+		strm->internal->allow_buf_error = false;
+		break;
+
+	default:
+		// All the other errors are fatal; coding cannot be continued.
+		assert(ret != LZMA_BUF_ERROR);
+		strm->internal->sequence = ISEQ_ERROR;
+		break;
+	}
+
+	return ret;
+}
+
+
+extern LZMA_API(void)
+lzma_end(lzma_stream *strm)
+{
+	if (strm != NULL && strm->internal != NULL) {
+		lzma_next_end(&strm->internal->next, strm->allocator);
+		lzma_free(strm->internal, strm->allocator);
+		strm->internal = NULL;
+	}
+
+	return;
+}
+
+
+#ifdef HAVE_SYMBOL_VERSIONS_LINUX
+// This is for compatibility with binaries linked against liblzma that
+// has been patched with xz-5.2.2-compat-libs.patch from RHEL/CentOS 7.
+LZMA_SYMVER_API("lzma_get_progress@XZ_5.2.2",
+	void, lzma_get_progress_522)(lzma_stream *strm,
+		uint64_t *progress_in, uint64_t *progress_out) lzma_nothrow
+		__attribute__((__alias__("lzma_get_progress_52")));
+
+LZMA_SYMVER_API("lzma_get_progress@@XZ_5.2",
+	void, lzma_get_progress_52)(lzma_stream *strm,
+		uint64_t *progress_in, uint64_t *progress_out) lzma_nothrow;
+
+#define lzma_get_progress lzma_get_progress_52
+#endif
+extern LZMA_API(void)
+lzma_get_progress(lzma_stream *strm,
+		uint64_t *progress_in, uint64_t *progress_out)
+{
+	if (strm->internal->next.get_progress != NULL) {
+		strm->internal->next.get_progress(strm->internal->next.coder,
+				progress_in, progress_out);
+	} else {
+		*progress_in = strm->total_in;
+		*progress_out = strm->total_out;
+	}
+
+	return;
+}
+
+
+extern LZMA_API(lzma_check)
+lzma_get_check(const lzma_stream *strm)
+{
+	// Return LZMA_CHECK_NONE if we cannot know the check type.
+	// It's a bug in the application if this happens.
+	if (strm->internal->next.get_check == NULL)
+		return LZMA_CHECK_NONE;
+
+	return strm->internal->next.get_check(strm->internal->next.coder);
+}
+
+
+extern LZMA_API(uint64_t)
+lzma_memusage(const lzma_stream *strm)
+{
+	uint64_t memusage;
+	uint64_t old_memlimit;
+
+	if (strm == NULL || strm->internal == NULL
+			|| strm->internal->next.memconfig == NULL
+			|| strm->internal->next.memconfig(
+				strm->internal->next.coder,
+				&memusage, &old_memlimit, 0) != LZMA_OK)
+		return 0;
+
+	return memusage;
+}
+
+
+extern LZMA_API(uint64_t)
+lzma_memlimit_get(const lzma_stream *strm)
+{
+	uint64_t old_memlimit;
+	uint64_t memusage;
+
+	if (strm == NULL || strm->internal == NULL
+			|| strm->internal->next.memconfig == NULL
+			|| strm->internal->next.memconfig(
+				strm->internal->next.coder,
+				&memusage, &old_memlimit, 0) != LZMA_OK)
+		return 0;
+
+	return old_memlimit;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_memlimit_set(lzma_stream *strm, uint64_t new_memlimit)
+{
+	// Dummy variables to simplify memconfig functions
+	uint64_t old_memlimit;
+	uint64_t memusage;
+
+	if (strm == NULL || strm->internal == NULL
+			|| strm->internal->next.memconfig == NULL)
+		return LZMA_PROG_ERROR;
+
+	// Zero is a special value that cannot be used as an actual limit.
+	// If 0 was specified, use 1 instead.
+	if (new_memlimit == 0)
+		new_memlimit = 1;
+
+	return strm->internal->next.memconfig(strm->internal->next.coder,
+			&memusage, &old_memlimit, new_memlimit);
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.h
new file mode 100644
index 00000000000..20af32f6d6c
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/common.h
@@ -0,0 +1,412 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       common.h
+/// \brief      Definitions common to the whole liblzma library
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_COMMON_H
+#define LZMA_COMMON_H
+
+#include "sysdefs.h"
+#include "mythread.h"
+#include "tuklib_integer.h"
+
+// LZMA_API_EXPORT is used to mark the exported API functions.
+// It's used to define the LZMA_API macro.
+//
+// lzma_attr_visibility_hidden is used for marking *declarations* of extern
+// variables that are internal to liblzma (-fvisibility=hidden alone is
+// enough to hide the *definitions*). Such markings allow slightly more
+// efficient code to accesses those variables in ELF shared libraries.
+#if defined(_WIN32) || defined(__CYGWIN__)
+#	ifdef DLL_EXPORT
+#		define LZMA_API_EXPORT __declspec(dllexport)
+#	else
+#		define LZMA_API_EXPORT
+#	endif
+#	define lzma_attr_visibility_hidden
+// Don't use ifdef or defined() below.
+#elif HAVE_VISIBILITY
+#	define LZMA_API_EXPORT __attribute__((__visibility__("default")))
+#	define lzma_attr_visibility_hidden \
+			__attribute__((__visibility__("hidden")))
+#else
+#	define LZMA_API_EXPORT
+#	define lzma_attr_visibility_hidden
+#endif
+
+#define LZMA_API(type) LZMA_API_EXPORT type LZMA_API_CALL
+
+#include "lzma.h"
+
+// This is for detecting modern GCC and Clang attributes
+// like __symver__ in GCC >= 10.
+#ifdef __has_attribute
+#	define lzma_has_attribute(attr) __has_attribute(attr)
+#else
+#	define lzma_has_attribute(attr) 0
+#endif
+
+// The extra symbol versioning in the C files may only be used when
+// building a shared library. If HAVE_SYMBOL_VERSIONS_LINUX is defined
+// to 2 then symbol versioning is done only if also PIC is defined.
+// By default Libtool defines PIC when building a shared library and
+// doesn't define it when building a static library but it can be
+// overridden with --with-pic and --without-pic. configure let's rely
+// on PIC if neither --with-pic or --without-pic was used.
+#if defined(HAVE_SYMBOL_VERSIONS_LINUX) \
+		&& (HAVE_SYMBOL_VERSIONS_LINUX == 2 && !defined(PIC))
+#	undef HAVE_SYMBOL_VERSIONS_LINUX
+#endif
+
+#ifdef HAVE_SYMBOL_VERSIONS_LINUX
+// To keep link-time optimization (LTO, -flto) working with GCC,
+// the __symver__ attribute must be used instead of __asm__(".symver ...").
+// Otherwise the symbol versions may be lost, resulting in broken liblzma
+// that has wrong default versions in the exported symbol list!
+// The attribute was added in GCC 10; LTO with older GCC is not supported.
+//
+// To keep -Wmissing-prototypes happy, use LZMA_SYMVER_API only with function
+// declarations (including those with __alias__ attribute) and LZMA_API with
+// the function definitions. This means a little bit of silly copy-and-paste
+// between declarations and definitions though.
+//
+// As of GCC 12.2, the __symver__ attribute supports only @ and @@ but the
+// very convenient @@@ isn't supported (it's supported by GNU assembler
+// since 2000). When using @@ instead of @@@, the internal name must not be
+// the same as the external name to avoid problems in some situations. This
+// is why "#define foo_52 foo" is needed for the default symbol versions.
+//
+// __has_attribute is supported before GCC 10 and it is supported in Clang 14
+// too (which doesn't support __symver__) so use it to detect if __symver__
+// is available. This should be far more reliable than looking at compiler
+// version macros as nowadays especially __GNUC__ is defined by many compilers.
+#	if lzma_has_attribute(__symver__)
+#		define LZMA_SYMVER_API(extnamever, type, intname) \
+			extern __attribute__((__symver__(extnamever))) \
+					LZMA_API(type) intname
+#	else
+#		define LZMA_SYMVER_API(extnamever, type, intname) \
+			__asm__(".symver " #intname "," extnamever); \
+			extern LZMA_API(type) intname
+#	endif
+#endif
+
+// MSVC has __forceinline which shouldn't be combined with the inline keyword
+// (results in a warning).
+//
+// GCC 3.1 added always_inline attribute so we don't need to check
+// for __GNUC__ version. Similarly, all relevant Clang versions
+// support it (at least Clang 3.0.0 does already).
+// Other compilers might support too which also support __has_attribute
+// (Solaris Studio) so do that check too.
+#if defined(_MSC_VER)
+#	define lzma_always_inline __forceinline
+#elif defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER) \
+		|| lzma_has_attribute(__always_inline__)
+#	define lzma_always_inline inline __attribute__((__always_inline__))
+#else
+#	define lzma_always_inline inline
+#endif
+
+// These allow helping the compiler in some often-executed branches, whose
+// result is almost always the same.
+#ifdef __GNUC__
+#	define likely(expr) __builtin_expect(expr, true)
+#	define unlikely(expr) __builtin_expect(expr, false)
+#else
+#	define likely(expr) (expr)
+#	define unlikely(expr) (expr)
+#endif
+
+
+/// Size of temporary buffers needed in some filters
+#define LZMA_BUFFER_SIZE 4096
+
+
+/// Maximum number of worker threads within one multithreaded component.
+/// The limit exists solely to make it simpler to prevent integer overflows
+/// when allocating structures etc. This should be big enough for now...
+/// the code won't scale anywhere close to this number anyway.
+#define LZMA_THREADS_MAX 16384
+
+
+/// Starting value for memory usage estimates. Instead of calculating size
+/// of _every_ structure and taking into account malloc() overhead etc., we
+/// add a base size to all memory usage estimates. It's not very accurate
+/// but should be easily good enough.
+#define LZMA_MEMUSAGE_BASE (UINT64_C(1) << 15)
+
+/// Start of internal Filter ID space. These IDs must never be used
+/// in Streams.
+#define LZMA_FILTER_RESERVED_START (LZMA_VLI_C(1) << 62)
+
+
+/// Supported flags that can be passed to lzma_stream_decoder(),
+/// lzma_auto_decoder(), or lzma_stream_decoder_mt().
+#define LZMA_SUPPORTED_FLAGS \
+	( LZMA_TELL_NO_CHECK \
+	| LZMA_TELL_UNSUPPORTED_CHECK \
+	| LZMA_TELL_ANY_CHECK \
+	| LZMA_IGNORE_CHECK \
+	| LZMA_CONCATENATED \
+	| LZMA_FAIL_FAST )
+
+
+/// Largest valid lzma_action value as unsigned integer.
+#define LZMA_ACTION_MAX ((unsigned int)(LZMA_FULL_BARRIER))
+
+
+/// Special return value (lzma_ret) to indicate that a timeout was reached
+/// and lzma_code() must not return LZMA_BUF_ERROR. This is converted to
+/// LZMA_OK in lzma_code().
+#define LZMA_TIMED_OUT LZMA_RET_INTERNAL1
+
+/// Special return value (lzma_ret) for use in stream_decoder_mt.c to
+/// indicate Index was detected instead of a Block Header.
+#define LZMA_INDEX_DETECTED LZMA_RET_INTERNAL2
+
+
+typedef struct lzma_next_coder_s lzma_next_coder;
+
+typedef struct lzma_filter_info_s lzma_filter_info;
+
+
+/// Type of a function used to initialize a filter encoder or decoder
+typedef lzma_ret (*lzma_init_function)(
+		lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+/// Type of a function to do some kind of coding work (filters, Stream,
+/// Block encoders/decoders etc.). Some special coders use don't use both
+/// input and output buffers, but for simplicity they still use this same
+/// function prototype.
+typedef lzma_ret (*lzma_code_function)(
+		void *coder, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size,
+		lzma_action action);
+
+/// Type of a function to free the memory allocated for the coder
+typedef void (*lzma_end_function)(
+		void *coder, const lzma_allocator *allocator);
+
+
+/// Raw coder validates and converts an array of lzma_filter structures to
+/// an array of lzma_filter_info structures. This array is used with
+/// lzma_next_filter_init to initialize the filter chain.
+struct lzma_filter_info_s {
+	/// Filter ID. This can be used to share the same initiazation
+	/// function *and* data structures with different Filter IDs
+	/// (LZMA_FILTER_LZMA1EXT does it), and also by the encoder
+	/// with lzma_filters_update() if filter chain is updated
+	/// in the middle of a raw stream or Block (LZMA_SYNC_FLUSH).
+	lzma_vli id;
+
+	/// Pointer to function used to initialize the filter.
+	/// This is NULL to indicate end of array.
+	lzma_init_function init;
+
+	/// Pointer to filter's options structure
+	void *options;
+};
+
+
+/// Hold data and function pointers of the next filter in the chain.
+struct lzma_next_coder_s {
+	/// Pointer to coder-specific data
+	void *coder;
+
+	/// Filter ID. This is LZMA_VLI_UNKNOWN when this structure doesn't
+	/// point to a filter coder.
+	lzma_vli id;
+
+	/// "Pointer" to init function. This is never called here.
+	/// We need only to detect if we are initializing a coder
+	/// that was allocated earlier. See lzma_next_coder_init and
+	/// lzma_next_strm_init macros in this file.
+	uintptr_t init;
+
+	/// Pointer to function to do the actual coding
+	lzma_code_function code;
+
+	/// Pointer to function to free lzma_next_coder.coder. This can
+	/// be NULL; in that case, lzma_free is called to free
+	/// lzma_next_coder.coder.
+	lzma_end_function end;
+
+	/// Pointer to a function to get progress information. If this is NULL,
+	/// lzma_stream.total_in and .total_out are used instead.
+	void (*get_progress)(void *coder,
+			uint64_t *progress_in, uint64_t *progress_out);
+
+	/// Pointer to function to return the type of the integrity check.
+	/// Most coders won't support this.
+	lzma_check (*get_check)(const void *coder);
+
+	/// Pointer to function to get and/or change the memory usage limit.
+	/// If new_memlimit == 0, the limit is not changed.
+	lzma_ret (*memconfig)(void *coder, uint64_t *memusage,
+			uint64_t *old_memlimit, uint64_t new_memlimit);
+
+	/// Update the filter-specific options or the whole filter chain
+	/// in the encoder.
+	lzma_ret (*update)(void *coder, const lzma_allocator *allocator,
+			const lzma_filter *filters,
+			const lzma_filter *reversed_filters);
+
+	/// Set how many bytes of output this coder may produce at maximum.
+	/// On success LZMA_OK must be returned.
+	/// If the filter chain as a whole cannot support this feature,
+	/// this must return LZMA_OPTIONS_ERROR.
+	/// If no input has been given to the coder and the requested limit
+	/// is too small, this must return LZMA_BUF_ERROR. If input has been
+	/// seen, LZMA_OK is allowed too.
+	lzma_ret (*set_out_limit)(void *coder, uint64_t *uncomp_size,
+			uint64_t out_limit);
+};
+
+
+/// Macro to initialize lzma_next_coder structure
+#define LZMA_NEXT_CODER_INIT \
+	(lzma_next_coder){ \
+		.coder = NULL, \
+		.init = (uintptr_t)(NULL), \
+		.id = LZMA_VLI_UNKNOWN, \
+		.code = NULL, \
+		.end = NULL, \
+		.get_progress = NULL, \
+		.get_check = NULL, \
+		.memconfig = NULL, \
+		.update = NULL, \
+		.set_out_limit = NULL, \
+	}
+
+
+/// Internal data for lzma_strm_init, lzma_code, and lzma_end. A pointer to
+/// this is stored in lzma_stream.
+struct lzma_internal_s {
+	/// The actual coder that should do something useful
+	lzma_next_coder next;
+
+	/// Track the state of the coder. This is used to validate arguments
+	/// so that the actual coders can rely on e.g. that LZMA_SYNC_FLUSH
+	/// is used on every call to lzma_code until next.code has returned
+	/// LZMA_STREAM_END.
+	enum {
+		ISEQ_RUN,
+		ISEQ_SYNC_FLUSH,
+		ISEQ_FULL_FLUSH,
+		ISEQ_FINISH,
+		ISEQ_FULL_BARRIER,
+		ISEQ_END,
+		ISEQ_ERROR,
+	} sequence;
+
+	/// A copy of lzma_stream avail_in. This is used to verify that the
+	/// amount of input doesn't change once e.g. LZMA_FINISH has been
+	/// used.
+	size_t avail_in;
+
+	/// Indicates which lzma_action values are allowed by next.code.
+	bool supported_actions[LZMA_ACTION_MAX + 1];
+
+	/// If true, lzma_code will return LZMA_BUF_ERROR if no progress was
+	/// made (no input consumed and no output produced by next.code).
+	bool allow_buf_error;
+};
+
+
+/// Allocates memory
+lzma_attr_alloc_size(1)
+extern void *lzma_alloc(size_t size, const lzma_allocator *allocator);
+
+/// Allocates memory and zeroes it (like calloc()). This can be faster
+/// than lzma_alloc() + memzero() while being backward compatible with
+/// custom allocators.
+lzma_attr_alloc_size(1)
+extern void *lzma_alloc_zero(size_t size, const lzma_allocator *allocator);
+
+/// Frees memory
+extern void lzma_free(void *ptr, const lzma_allocator *allocator);
+
+
+/// Allocates strm->internal if it is NULL, and initializes *strm and
+/// strm->internal. This function is only called via lzma_next_strm_init macro.
+extern lzma_ret lzma_strm_init(lzma_stream *strm);
+
+/// Initializes the next filter in the chain, if any. This takes care of
+/// freeing the memory of previously initialized filter if it is different
+/// than the filter being initialized now. This way the actual filter
+/// initialization functions don't need to use lzma_next_coder_init macro.
+extern lzma_ret lzma_next_filter_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+/// Update the next filter in the chain, if any. This checks that
+/// the application is not trying to change the Filter IDs.
+extern lzma_ret lzma_next_filter_update(
+		lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter *reversed_filters);
+
+/// Frees the memory allocated for next->coder either using next->end or,
+/// if next->end is NULL, using lzma_free.
+extern void lzma_next_end(lzma_next_coder *next,
+		const lzma_allocator *allocator);
+
+
+/// Copy as much data as possible from in[] to out[] and update *in_pos
+/// and *out_pos accordingly. Returns the number of bytes copied.
+extern size_t lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size);
+
+
+/// \brief      Return if expression doesn't evaluate to LZMA_OK
+///
+/// There are several situations where we want to return immediately
+/// with the value of expr if it isn't LZMA_OK. This macro shortens
+/// the code a little.
+#define return_if_error(expr) \
+do { \
+	const lzma_ret ret_ = (expr); \
+	if (ret_ != LZMA_OK) \
+		return ret_; \
+} while (0)
+
+
+/// If next isn't already initialized, free the previous coder. Then mark
+/// that next is _possibly_ initialized for the coder using this macro.
+/// "Possibly" means that if e.g. allocation of next->coder fails, the
+/// structure isn't actually initialized for this coder, but leaving
+/// next->init to func is still OK.
+#define lzma_next_coder_init(func, next, allocator) \
+do { \
+	if ((uintptr_t)(func) != (next)->init) \
+		lzma_next_end(next, allocator); \
+	(next)->init = (uintptr_t)(func); \
+} while (0)
+
+
+/// Initializes lzma_strm and calls func() to initialize strm->internal->next.
+/// (The function being called will use lzma_next_coder_init()). If
+/// initialization fails, memory that wasn't freed by func() is freed
+/// along strm->internal.
+#define lzma_next_strm_init(func, strm, ...) \
+do { \
+	return_if_error(lzma_strm_init(strm)); \
+	const lzma_ret ret_ = func(&(strm)->internal->next, \
+			(strm)->allocator, __VA_ARGS__); \
+	if (ret_ != LZMA_OK) { \
+		lzma_end(strm); \
+		return ret_; \
+	} \
+} while (0)
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_buffer_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_buffer_encoder.c
new file mode 100644
index 00000000000..da610cea6bf
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_buffer_encoder.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       easy_buffer_encoder.c
+/// \brief      Easy single-call .xz Stream encoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "easy_preset.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_easy_buffer_encode(uint32_t preset, lzma_check check,
+		const lzma_allocator *allocator, const uint8_t *in,
+		size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size)
+{
+	lzma_options_easy opt_easy;
+	if (lzma_easy_preset(&opt_easy, preset))
+		return LZMA_OPTIONS_ERROR;
+
+	return lzma_stream_buffer_encode(opt_easy.filters, check,
+			allocator, in, in_size, out, out_pos, out_size);
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_decoder_memusage.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_decoder_memusage.c
new file mode 100644
index 00000000000..0c76f10033b
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_decoder_memusage.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       easy_decoder_memusage.c
+/// \brief      Decoder memory usage calculation to match easy encoder presets
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "easy_preset.h"
+
+
+extern LZMA_API(uint64_t)
+lzma_easy_decoder_memusage(uint32_t preset)
+{
+	lzma_options_easy opt_easy;
+	if (lzma_easy_preset(&opt_easy, preset))
+		return UINT32_MAX;
+
+	return lzma_raw_decoder_memusage(opt_easy.filters);
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder.c
new file mode 100644
index 00000000000..8dfe29610f7
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       easy_encoder.c
+/// \brief      Easy .xz Stream encoder initialization
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "easy_preset.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_easy_encoder(lzma_stream *strm, uint32_t preset, lzma_check check)
+{
+	lzma_options_easy opt_easy;
+	if (lzma_easy_preset(&opt_easy, preset))
+		return LZMA_OPTIONS_ERROR;
+
+	return lzma_stream_encoder(strm, opt_easy.filters, check);
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder_memusage.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder_memusage.c
new file mode 100644
index 00000000000..1184ac66542
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_encoder_memusage.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       easy_encoder_memusage.c
+/// \brief      Easy .xz Stream encoder memory usage calculation
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "easy_preset.h"
+
+
+extern LZMA_API(uint64_t)
+lzma_easy_encoder_memusage(uint32_t preset)
+{
+	lzma_options_easy opt_easy;
+	if (lzma_easy_preset(&opt_easy, preset))
+		return UINT32_MAX;
+
+	return lzma_raw_encoder_memusage(opt_easy.filters);
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.c
new file mode 100644
index 00000000000..7908a2bb73c
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       easy_preset.c
+/// \brief      Preset handling for easy encoder and decoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "easy_preset.h"
+
+
+extern bool
+lzma_easy_preset(lzma_options_easy *opt_easy, uint32_t preset)
+{
+	if (lzma_lzma_preset(&opt_easy->opt_lzma, preset))
+		return true;
+
+	opt_easy->filters[0].id = LZMA_FILTER_LZMA2;
+	opt_easy->filters[0].options = &opt_easy->opt_lzma;
+	opt_easy->filters[1].id = LZMA_VLI_UNKNOWN;
+
+	return false;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.h
new file mode 100644
index 00000000000..4ef6d044ad5
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/easy_preset.h
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       easy_preset.h
+/// \brief      Preset handling for easy encoder and decoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_EASY_PRESET_H
+#define LZMA_EASY_PRESET_H
+
+#include "common.h"
+
+
+typedef struct {
+	/// We need to keep the filters array available in case
+	/// LZMA_FULL_FLUSH is used.
+	lzma_filter filters[LZMA_FILTERS_MAX + 1];
+
+	/// Options for LZMA2
+	lzma_options_lzma opt_lzma;
+
+	// Options for more filters can be added later, so this struct
+	// is not ready to be put into the public API.
+
+} lzma_options_easy;
+
+
+/// Set *easy to the settings given by the preset. Returns true on error,
+/// false on success.
+extern bool lzma_easy_preset(lzma_options_easy *easy, uint32_t preset);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/file_info.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/file_info.c
new file mode 100644
index 00000000000..7c85084a706
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/file_info.c
@@ -0,0 +1,854 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       file_info.c
+/// \brief      Decode .xz file information into a lzma_index structure
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "index_decoder.h"
+
+
+typedef struct {
+	enum {
+		SEQ_MAGIC_BYTES,
+		SEQ_PADDING_SEEK,
+		SEQ_PADDING_DECODE,
+		SEQ_FOOTER,
+		SEQ_INDEX_INIT,
+		SEQ_INDEX_DECODE,
+		SEQ_HEADER_DECODE,
+		SEQ_HEADER_COMPARE,
+	} sequence;
+
+	/// Absolute position of in[*in_pos] in the file. All code that
+	/// modifies *in_pos also updates this. seek_to_pos() needs this
+	/// to determine if we need to request the application to seek for
+	/// us or if we can do the seeking internally by adjusting *in_pos.
+	uint64_t file_cur_pos;
+
+	/// This refers to absolute positions of interesting parts of the
+	/// input file. Sometimes it points to the *beginning* of a specific
+	/// field and sometimes to the *end* of a field. The current target
+	/// position at each moment is explained in the comments.
+	uint64_t file_target_pos;
+
+	/// Size of the .xz file (from the application).
+	uint64_t file_size;
+
+	/// Index decoder
+	lzma_next_coder index_decoder;
+
+	/// Number of bytes remaining in the Index field that is currently
+	/// being decoded.
+	lzma_vli index_remaining;
+
+	/// The Index decoder will store the decoded Index in this pointer.
+	lzma_index *this_index;
+
+	/// Amount of Stream Padding in the current Stream.
+	lzma_vli stream_padding;
+
+	/// The final combined index is collected here.
+	lzma_index *combined_index;
+
+	/// Pointer from the application where to store the index information
+	/// after successful decoding.
+	lzma_index **dest_index;
+
+	/// Pointer to lzma_stream.seek_pos to be used when returning
+	/// LZMA_SEEK_NEEDED. This is set by seek_to_pos() when needed.
+	uint64_t *external_seek_pos;
+
+	/// Memory usage limit
+	uint64_t memlimit;
+
+	/// Stream Flags from the very beginning of the file.
+	lzma_stream_flags first_header_flags;
+
+	/// Stream Flags from Stream Header of the current Stream.
+	lzma_stream_flags header_flags;
+
+	/// Stream Flags from Stream Footer of the current Stream.
+	lzma_stream_flags footer_flags;
+
+	size_t temp_pos;
+	size_t temp_size;
+	uint8_t temp[8192];
+
+} lzma_file_info_coder;
+
+
+/// Copies data from in[*in_pos] into coder->temp until
+/// coder->temp_pos == coder->temp_size. This also keeps coder->file_cur_pos
+/// in sync with *in_pos. Returns true if more input is needed.
+static bool
+fill_temp(lzma_file_info_coder *coder, const uint8_t *restrict in,
+		size_t *restrict in_pos, size_t in_size)
+{
+	coder->file_cur_pos += lzma_bufcpy(in, in_pos, in_size,
+			coder->temp, &coder->temp_pos, coder->temp_size);
+	return coder->temp_pos < coder->temp_size;
+}
+
+
+/// Seeks to the absolute file position specified by target_pos.
+/// This tries to do the seeking by only modifying *in_pos, if possible.
+/// The main benefit of this is that if one passes the whole file at once
+/// to lzma_code(), the decoder will never need to return LZMA_SEEK_NEEDED
+/// as all the seeking can be done by adjusting *in_pos in this function.
+///
+/// Returns true if an external seek is needed and the caller must return
+/// LZMA_SEEK_NEEDED.
+static bool
+seek_to_pos(lzma_file_info_coder *coder, uint64_t target_pos,
+		size_t in_start, size_t *in_pos, size_t in_size)
+{
+	// The input buffer doesn't extend beyond the end of the file.
+	// This has been checked by file_info_decode() already.
+	assert(coder->file_size - coder->file_cur_pos >= in_size - *in_pos);
+
+	const uint64_t pos_min = coder->file_cur_pos - (*in_pos - in_start);
+	const uint64_t pos_max = coder->file_cur_pos + (in_size - *in_pos);
+
+	bool external_seek_needed;
+
+	if (target_pos >= pos_min && target_pos <= pos_max) {
+		// The requested position is available in the current input
+		// buffer or right after it. That is, in a corner case we
+		// end up setting *in_pos == in_size and thus will immediately
+		// need new input bytes from the application.
+		*in_pos += (size_t)(target_pos - coder->file_cur_pos);
+		external_seek_needed = false;
+	} else {
+		// Ask the application to seek the input file.
+		*coder->external_seek_pos = target_pos;
+		external_seek_needed = true;
+
+		// Mark the whole input buffer as used. This way
+		// lzma_stream.total_in will have a better estimate
+		// of the amount of data read. It still won't be perfect
+		// as the value will depend on the input buffer size that
+		// the application uses, but it should be good enough for
+		// those few who want an estimate.
+		*in_pos = in_size;
+	}
+
+	// After seeking (internal or external) the current position
+	// will match the requested target position.
+	coder->file_cur_pos = target_pos;
+
+	return external_seek_needed;
+}
+
+
+/// The caller sets coder->file_target_pos so that it points to the *end*
+/// of the desired file position. This function then determines how far
+/// backwards from that position we can seek. After seeking fill_temp()
+/// can be used to read data into coder->temp. When fill_temp() has finished,
+/// coder->temp[coder->temp_size] will match coder->file_target_pos.
+///
+/// This also validates that coder->target_file_pos is sane in sense that
+/// we aren't trying to seek too far backwards (too close or beyond the
+/// beginning of the file).
+static lzma_ret
+reverse_seek(lzma_file_info_coder *coder,
+		size_t in_start, size_t *in_pos, size_t in_size)
+{
+	// Check that there is enough data before the target position
+	// to contain at least Stream Header and Stream Footer. If there
+	// isn't, the file cannot be valid.
+	if (coder->file_target_pos < 2 * LZMA_STREAM_HEADER_SIZE)
+		return LZMA_DATA_ERROR;
+
+	coder->temp_pos = 0;
+
+	// The Stream Header at the very beginning of the file gets handled
+	// specially in SEQ_MAGIC_BYTES and thus we will never need to seek
+	// there. By not seeking to the first LZMA_STREAM_HEADER_SIZE bytes
+	// we avoid a useless external seek after SEQ_MAGIC_BYTES if the
+	// application uses an extremely small input buffer and the input
+	// file is very small.
+	if (coder->file_target_pos - LZMA_STREAM_HEADER_SIZE
+			< sizeof(coder->temp))
+		coder->temp_size = (size_t)(coder->file_target_pos
+				- LZMA_STREAM_HEADER_SIZE);
+	else
+		coder->temp_size = sizeof(coder->temp);
+
+	// The above if-statements guarantee this. This is important because
+	// the Stream Header/Footer decoders assume that there's at least
+	// LZMA_STREAM_HEADER_SIZE bytes in coder->temp.
+	assert(coder->temp_size >= LZMA_STREAM_HEADER_SIZE);
+
+	if (seek_to_pos(coder, coder->file_target_pos - coder->temp_size,
+			in_start, in_pos, in_size))
+		return LZMA_SEEK_NEEDED;
+
+	return LZMA_OK;
+}
+
+
+/// Gets the number of zero-bytes at the end of the buffer.
+static size_t
+get_padding_size(const uint8_t *buf, size_t buf_size)
+{
+	size_t padding = 0;
+	while (buf_size > 0 && buf[--buf_size] == 0x00)
+		++padding;
+
+	return padding;
+}
+
+
+/// With the Stream Header at the very beginning of the file, LZMA_FORMAT_ERROR
+/// is used to tell the application that Magic Bytes didn't match. In other
+/// Stream Header/Footer fields (in the middle/end of the file) it could be
+/// a bit confusing to return LZMA_FORMAT_ERROR as we already know that there
+/// is a valid Stream Header at the beginning of the file. For those cases
+/// this function is used to convert LZMA_FORMAT_ERROR to LZMA_DATA_ERROR.
+static lzma_ret
+hide_format_error(lzma_ret ret)
+{
+	if (ret == LZMA_FORMAT_ERROR)
+		ret = LZMA_DATA_ERROR;
+
+	return ret;
+}
+
+
+/// Calls the Index decoder and updates coder->index_remaining.
+/// This is a separate function because the input can be either directly
+/// from the application or from coder->temp.
+static lzma_ret
+decode_index(lzma_file_info_coder *coder, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, bool update_file_cur_pos)
+{
+	const size_t in_start = *in_pos;
+
+	const lzma_ret ret = coder->index_decoder.code(
+			coder->index_decoder.coder,
+			allocator, in, in_pos, in_size,
+			NULL, NULL, 0, LZMA_RUN);
+
+	coder->index_remaining -= *in_pos - in_start;
+
+	if (update_file_cur_pos)
+		coder->file_cur_pos += *in_pos - in_start;
+
+	return ret;
+}
+
+
+static lzma_ret
+file_info_decode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size,
+		uint8_t *restrict out lzma_attribute((__unused__)),
+		size_t *restrict out_pos lzma_attribute((__unused__)),
+		size_t out_size lzma_attribute((__unused__)),
+		lzma_action action lzma_attribute((__unused__)))
+{
+	lzma_file_info_coder *coder = coder_ptr;
+	const size_t in_start = *in_pos;
+
+	// If the caller provides input past the end of the file, trim
+	// the extra bytes from the buffer so that we won't read too far.
+	assert(coder->file_size >= coder->file_cur_pos);
+	if (coder->file_size - coder->file_cur_pos < in_size - in_start)
+		in_size = in_start
+			+ (size_t)(coder->file_size - coder->file_cur_pos);
+
+	while (true)
+	switch (coder->sequence) {
+	case SEQ_MAGIC_BYTES:
+		// Decode the Stream Header at the beginning of the file
+		// first to check if the Magic Bytes match. The flags
+		// are stored in coder->first_header_flags so that we
+		// don't need to seek to it again.
+		//
+		// Check that the file is big enough to contain at least
+		// Stream Header.
+		if (coder->file_size < LZMA_STREAM_HEADER_SIZE)
+			return LZMA_FORMAT_ERROR;
+
+		// Read the Stream Header field into coder->temp.
+		if (fill_temp(coder, in, in_pos, in_size))
+			return LZMA_OK;
+
+		// This is the only Stream Header/Footer decoding where we
+		// want to return LZMA_FORMAT_ERROR if the Magic Bytes don't
+		// match. Elsewhere it will be converted to LZMA_DATA_ERROR.
+		return_if_error(lzma_stream_header_decode(
+				&coder->first_header_flags, coder->temp));
+
+		// Now that we know that the Magic Bytes match, check the
+		// file size. It's better to do this here after checking the
+		// Magic Bytes since this way we can give LZMA_FORMAT_ERROR
+		// instead of LZMA_DATA_ERROR when the Magic Bytes don't
+		// match in a file that is too big or isn't a multiple of
+		// four bytes.
+		if (coder->file_size > LZMA_VLI_MAX || (coder->file_size & 3))
+			return LZMA_DATA_ERROR;
+
+		// Start looking for Stream Padding and Stream Footer
+		// at the end of the file.
+		coder->file_target_pos = coder->file_size;
+
+	// Fall through
+
+	case SEQ_PADDING_SEEK:
+		coder->sequence = SEQ_PADDING_DECODE;
+		return_if_error(reverse_seek(
+				coder, in_start, in_pos, in_size));
+
+	// Fall through
+
+	case SEQ_PADDING_DECODE: {
+		// Copy to coder->temp first. This keeps the code simpler if
+		// the application only provides input a few bytes at a time.
+		if (fill_temp(coder, in, in_pos, in_size))
+			return LZMA_OK;
+
+		// Scan the buffer backwards to get the size of the
+		// Stream Padding field (if any).
+		const size_t new_padding = get_padding_size(
+				coder->temp, coder->temp_size);
+		coder->stream_padding += new_padding;
+
+		// Set the target position to the beginning of Stream Padding
+		// that has been observed so far. If all Stream Padding has
+		// been seen, then the target position will be at the end
+		// of the Stream Footer field.
+		coder->file_target_pos -= new_padding;
+
+		if (new_padding == coder->temp_size) {
+			// The whole buffer was padding. Seek backwards in
+			// the file to get more input.
+			coder->sequence = SEQ_PADDING_SEEK;
+			break;
+		}
+
+		// Size of Stream Padding must be a multiple of 4 bytes.
+		if (coder->stream_padding & 3)
+			return LZMA_DATA_ERROR;
+
+		coder->sequence = SEQ_FOOTER;
+
+		// Calculate the amount of non-padding data in coder->temp.
+		coder->temp_size -= new_padding;
+		coder->temp_pos = coder->temp_size;
+
+		// We can avoid an external seek if the whole Stream Footer
+		// is already in coder->temp. In that case SEQ_FOOTER won't
+		// read more input and will find the Stream Footer from
+		// coder->temp[coder->temp_size - LZMA_STREAM_HEADER_SIZE].
+		//
+		// Otherwise we will need to seek. The seeking is done so
+		// that Stream Footer will be at the end of coder->temp.
+		// This way it's likely that we also get a complete Index
+		// field into coder->temp without needing a separate seek
+		// for that (unless the Index field is big).
+		if (coder->temp_size < LZMA_STREAM_HEADER_SIZE)
+			return_if_error(reverse_seek(
+					coder, in_start, in_pos, in_size));
+	}
+
+	// Fall through
+
+	case SEQ_FOOTER:
+		// Copy the Stream Footer field into coder->temp.
+		// If Stream Footer was already available in coder->temp
+		// in SEQ_PADDING_DECODE, then this does nothing.
+		if (fill_temp(coder, in, in_pos, in_size))
+			return LZMA_OK;
+
+		// Make coder->file_target_pos and coder->temp_size point
+		// to the beginning of Stream Footer and thus to the end
+		// of the Index field. coder->temp_pos will be updated
+		// a bit later.
+		coder->file_target_pos -= LZMA_STREAM_HEADER_SIZE;
+		coder->temp_size -= LZMA_STREAM_HEADER_SIZE;
+
+		// Decode Stream Footer.
+		return_if_error(hide_format_error(lzma_stream_footer_decode(
+				&coder->footer_flags,
+				coder->temp + coder->temp_size)));
+
+		// Check that we won't seek past the beginning of the file.
+		//
+		// LZMA_STREAM_HEADER_SIZE is added because there must be
+		// space for Stream Header too even though we won't seek
+		// there before decoding the Index field.
+		//
+		// There's no risk of integer overflow here because
+		// Backward Size cannot be greater than 2^34.
+		if (coder->file_target_pos < coder->footer_flags.backward_size
+				+ LZMA_STREAM_HEADER_SIZE)
+			return LZMA_DATA_ERROR;
+
+		// Set the target position to the beginning of the Index field.
+		coder->file_target_pos -= coder->footer_flags.backward_size;
+		coder->sequence = SEQ_INDEX_INIT;
+
+		// We can avoid an external seek if the whole Index field is
+		// already available in coder->temp.
+		if (coder->temp_size >= coder->footer_flags.backward_size) {
+			// Set coder->temp_pos to point to the beginning
+			// of the Index.
+			coder->temp_pos = coder->temp_size
+					- coder->footer_flags.backward_size;
+		} else {
+			// These are set to zero to indicate that there's no
+			// useful data (Index or anything else) in coder->temp.
+			coder->temp_pos = 0;
+			coder->temp_size = 0;
+
+			// Seek to the beginning of the Index field.
+			if (seek_to_pos(coder, coder->file_target_pos,
+					in_start, in_pos, in_size))
+				return LZMA_SEEK_NEEDED;
+		}
+
+	// Fall through
+
+	case SEQ_INDEX_INIT: {
+		// Calculate the amount of memory already used by the earlier
+		// Indexes so that we know how big memory limit to pass to
+		// the Index decoder.
+		//
+		// NOTE: When there are multiple Streams, the separate
+		// lzma_index structures can use more RAM (as measured by
+		// lzma_index_memused()) than the final combined lzma_index.
+		// Thus memlimit may need to be slightly higher than the final
+		// calculated memory usage will be. This is perhaps a bit
+		// confusing to the application, but I think it shouldn't
+		// cause problems in practice.
+		uint64_t memused = 0;
+		if (coder->combined_index != NULL) {
+			memused = lzma_index_memused(coder->combined_index);
+			assert(memused <= coder->memlimit);
+			if (memused > coder->memlimit) // Extra sanity check
+				return LZMA_PROG_ERROR;
+		}
+
+		// Initialize the Index decoder.
+		return_if_error(lzma_index_decoder_init(
+				&coder->index_decoder, allocator,
+				&coder->this_index,
+				coder->memlimit - memused));
+
+		coder->index_remaining = coder->footer_flags.backward_size;
+		coder->sequence = SEQ_INDEX_DECODE;
+	}
+
+	// Fall through
+
+	case SEQ_INDEX_DECODE: {
+		// Decode (a part of) the Index. If the whole Index is already
+		// in coder->temp, read it from there. Otherwise read from
+		// in[*in_pos] onwards. Note that index_decode() updates
+		// coder->index_remaining and optionally coder->file_cur_pos.
+		lzma_ret ret;
+		if (coder->temp_size != 0) {
+			assert(coder->temp_size - coder->temp_pos
+					== coder->index_remaining);
+			ret = decode_index(coder, allocator, coder->temp,
+					&coder->temp_pos, coder->temp_size,
+					false);
+		} else {
+			// Don't give the decoder more input than the known
+			// remaining size of the Index field.
+			size_t in_stop = in_size;
+			if (in_size - *in_pos > coder->index_remaining)
+				in_stop = *in_pos
+					+ (size_t)(coder->index_remaining);
+
+			ret = decode_index(coder, allocator,
+					in, in_pos, in_stop, true);
+		}
+
+		switch (ret) {
+		case LZMA_OK:
+			// If the Index docoder asks for more input when we
+			// have already given it as much input as Backward Size
+			// indicated, the file is invalid.
+			if (coder->index_remaining == 0)
+				return LZMA_DATA_ERROR;
+
+			// We cannot get here if we were reading Index from
+			// coder->temp because when reading from coder->temp
+			// we give the Index decoder exactly
+			// coder->index_remaining bytes of input.
+			assert(coder->temp_size == 0);
+
+			return LZMA_OK;
+
+		case LZMA_STREAM_END:
+			// If the decoding seems to be successful, check also
+			// that the Index decoder consumed as much input as
+			// indicated by the Backward Size field.
+			if (coder->index_remaining != 0)
+				return LZMA_DATA_ERROR;
+
+			break;
+
+		default:
+			return ret;
+		}
+
+		// Calculate how much the Index tells us to seek backwards
+		// (relative to the beginning of the Index): Total size of
+		// all Blocks plus the size of the Stream Header field.
+		// No integer overflow here because lzma_index_total_size()
+		// cannot return a value greater than LZMA_VLI_MAX.
+		const uint64_t seek_amount
+				= lzma_index_total_size(coder->this_index)
+					+ LZMA_STREAM_HEADER_SIZE;
+
+		// Check that Index is sane in sense that seek_amount won't
+		// make us seek past the beginning of the file when locating
+		// the Stream Header.
+		//
+		// coder->file_target_pos still points to the beginning of
+		// the Index field.
+		if (coder->file_target_pos < seek_amount)
+			return LZMA_DATA_ERROR;
+
+		// Set the target to the beginning of Stream Header.
+		coder->file_target_pos -= seek_amount;
+
+		if (coder->file_target_pos == 0) {
+			// We would seek to the beginning of the file, but
+			// since we already decoded that Stream Header in
+			// SEQ_MAGIC_BYTES, we can use the cached value from
+			// coder->first_header_flags to avoid the seek.
+			coder->header_flags = coder->first_header_flags;
+			coder->sequence = SEQ_HEADER_COMPARE;
+			break;
+		}
+
+		coder->sequence = SEQ_HEADER_DECODE;
+
+		// Make coder->file_target_pos point to the end of
+		// the Stream Header field.
+		coder->file_target_pos += LZMA_STREAM_HEADER_SIZE;
+
+		// If coder->temp_size is non-zero, it points to the end
+		// of the Index field. Then the beginning of the Index
+		// field is at coder->temp[coder->temp_size
+		// - coder->footer_flags.backward_size].
+		assert(coder->temp_size == 0 || coder->temp_size
+				>= coder->footer_flags.backward_size);
+
+		// If coder->temp contained the whole Index, see if it has
+		// enough data to contain also the Stream Header. If so,
+		// we avoid an external seek.
+		//
+		// NOTE: This can happen only with small .xz files and only
+		// for the non-first Stream as the Stream Flags of the first
+		// Stream are cached and already handled a few lines above.
+		// So this isn't as useful as the other seek-avoidance cases.
+		if (coder->temp_size != 0 && coder->temp_size
+				- coder->footer_flags.backward_size
+				>= seek_amount) {
+			// Make temp_pos and temp_size point to the *end* of
+			// Stream Header so that SEQ_HEADER_DECODE will find
+			// the start of Stream Header from coder->temp[
+			// coder->temp_size - LZMA_STREAM_HEADER_SIZE].
+			coder->temp_pos = coder->temp_size
+					- coder->footer_flags.backward_size
+					- seek_amount
+					+ LZMA_STREAM_HEADER_SIZE;
+			coder->temp_size = coder->temp_pos;
+		} else {
+			// Seek so that Stream Header will be at the end of
+			// coder->temp. With typical multi-Stream files we
+			// will usually also get the Stream Footer and Index
+			// of the *previous* Stream in coder->temp and thus
+			// won't need a separate seek for them.
+			return_if_error(reverse_seek(coder,
+					in_start, in_pos, in_size));
+		}
+	}
+
+	// Fall through
+
+	case SEQ_HEADER_DECODE:
+		// Copy the Stream Header field into coder->temp.
+		// If Stream Header was already available in coder->temp
+		// in SEQ_INDEX_DECODE, then this does nothing.
+		if (fill_temp(coder, in, in_pos, in_size))
+			return LZMA_OK;
+
+		// Make all these point to the beginning of Stream Header.
+		coder->file_target_pos -= LZMA_STREAM_HEADER_SIZE;
+		coder->temp_size -= LZMA_STREAM_HEADER_SIZE;
+		coder->temp_pos = coder->temp_size;
+
+		// Decode the Stream Header.
+		return_if_error(hide_format_error(lzma_stream_header_decode(
+				&coder->header_flags,
+				coder->temp + coder->temp_size)));
+
+		coder->sequence = SEQ_HEADER_COMPARE;
+
+	// Fall through
+
+	case SEQ_HEADER_COMPARE:
+		// Compare Stream Header against Stream Footer. They must
+		// match.
+		return_if_error(lzma_stream_flags_compare(
+				&coder->header_flags, &coder->footer_flags));
+
+		// Store the decoded Stream Flags into the Index. Use the
+		// Footer Flags because it contains Backward Size, although
+		// it shouldn't matter in practice.
+		if (lzma_index_stream_flags(coder->this_index,
+				&coder->footer_flags) != LZMA_OK)
+			return LZMA_PROG_ERROR;
+
+		// Store also the size of the Stream Padding field. It is
+		// needed to calculate the offsets of the Streams correctly.
+		if (lzma_index_stream_padding(coder->this_index,
+				coder->stream_padding) != LZMA_OK)
+			return LZMA_PROG_ERROR;
+
+		// Reset it so that it's ready for the next Stream.
+		coder->stream_padding = 0;
+
+		// Append the earlier decoded Indexes after this_index.
+		if (coder->combined_index != NULL)
+			return_if_error(lzma_index_cat(coder->this_index,
+					coder->combined_index, allocator));
+
+		coder->combined_index = coder->this_index;
+		coder->this_index = NULL;
+
+		// If the whole file was decoded, tell the caller that we
+		// are finished.
+		if (coder->file_target_pos == 0) {
+			// The combined index must indicate the same file
+			// size as was told to us at initialization.
+			assert(lzma_index_file_size(coder->combined_index)
+					== coder->file_size);
+
+			// Make the combined index available to
+			// the application.
+			*coder->dest_index = coder->combined_index;
+			coder->combined_index = NULL;
+
+			// Mark the input buffer as used since we may have
+			// done internal seeking and thus don't know how
+			// many input bytes were actually used. This way
+			// lzma_stream.total_in gets a slightly better
+			// estimate of the amount of input used.
+			*in_pos = in_size;
+			return LZMA_STREAM_END;
+		}
+
+		// We didn't hit the beginning of the file yet, so continue
+		// reading backwards in the file. If we have unprocessed
+		// data in coder->temp, use it before requesting more data
+		// from the application.
+		//
+		// coder->file_target_pos, coder->temp_size, and
+		// coder->temp_pos all point to the beginning of Stream Header
+		// and thus the end of the previous Stream in the file.
+		coder->sequence = coder->temp_size > 0
+				? SEQ_PADDING_DECODE : SEQ_PADDING_SEEK;
+		break;
+
+	default:
+		assert(0);
+		return LZMA_PROG_ERROR;
+	}
+}
+
+
+static lzma_ret
+file_info_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
+		uint64_t *old_memlimit, uint64_t new_memlimit)
+{
+	lzma_file_info_coder *coder = coder_ptr;
+
+	// The memory usage calculation comes from three things:
+	//
+	// (1) The Indexes that have already been decoded and processed into
+	//     coder->combined_index.
+	//
+	// (2) The latest Index in coder->this_index that has been decoded but
+	//     not yet put into coder->combined_index.
+	//
+	// (3) The latest Index that we have started decoding but haven't
+	//     finished and thus isn't available in coder->this_index yet.
+	//     Memory usage and limit information needs to be communicated
+	//     from/to coder->index_decoder.
+	//
+	// Care has to be taken to not do both (2) and (3) when calculating
+	// the memory usage.
+	uint64_t combined_index_memusage = 0;
+	uint64_t this_index_memusage = 0;
+
+	// (1) If we have already successfully decoded one or more Indexes,
+	// get their memory usage.
+	if (coder->combined_index != NULL)
+		combined_index_memusage = lzma_index_memused(
+				coder->combined_index);
+
+	// Choose between (2), (3), or neither.
+	if (coder->this_index != NULL) {
+		// (2) The latest Index is available. Use its memory usage.
+		this_index_memusage = lzma_index_memused(coder->this_index);
+
+	} else if (coder->sequence == SEQ_INDEX_DECODE) {
+		// (3) The Index decoder is activate and hasn't yet stored
+		// the new index in coder->this_index. Get the memory usage
+		// information from the Index decoder.
+		//
+		// NOTE: If the Index decoder doesn't yet know how much memory
+		// it will eventually need, it will return a tiny value here.
+		uint64_t dummy;
+		if (coder->index_decoder.memconfig(coder->index_decoder.coder,
+					&this_index_memusage, &dummy, 0)
+				!= LZMA_OK) {
+			assert(0);
+			return LZMA_PROG_ERROR;
+		}
+	}
+
+	// Now we know the total memory usage/requirement. If we had neither
+	// old Indexes nor a new Index, this will be zero which isn't
+	// acceptable as lzma_memusage() has to return non-zero on success
+	// and even with an empty .xz file we will end up with a lzma_index
+	// that takes some memory.
+	*memusage = combined_index_memusage + this_index_memusage;
+	if (*memusage == 0)
+		*memusage = lzma_index_memusage(1, 0);
+
+	*old_memlimit = coder->memlimit;
+
+	// If requested, set a new memory usage limit.
+	if (new_memlimit != 0) {
+		if (new_memlimit < *memusage)
+			return LZMA_MEMLIMIT_ERROR;
+
+		// In the condition (3) we need to tell the Index decoder
+		// its new memory usage limit.
+		if (coder->this_index == NULL
+				&& coder->sequence == SEQ_INDEX_DECODE) {
+			const uint64_t idec_new_memlimit = new_memlimit
+					- combined_index_memusage;
+
+			assert(this_index_memusage > 0);
+			assert(idec_new_memlimit > 0);
+
+			uint64_t dummy1;
+			uint64_t dummy2;
+
+			if (coder->index_decoder.memconfig(
+					coder->index_decoder.coder,
+					&dummy1, &dummy2, idec_new_memlimit)
+					!= LZMA_OK) {
+				assert(0);
+				return LZMA_PROG_ERROR;
+			}
+		}
+
+		coder->memlimit = new_memlimit;
+	}
+
+	return LZMA_OK;
+}
+
+
+static void
+file_info_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_file_info_coder *coder = coder_ptr;
+
+	lzma_next_end(&coder->index_decoder, allocator);
+	lzma_index_end(coder->this_index, allocator);
+	lzma_index_end(coder->combined_index, allocator);
+
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_ret
+lzma_file_info_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator, uint64_t *seek_pos,
+		lzma_index **dest_index,
+		uint64_t memlimit, uint64_t file_size)
+{
+	lzma_next_coder_init(&lzma_file_info_decoder_init, next, allocator);
+
+	if (dest_index == NULL)
+		return LZMA_PROG_ERROR;
+
+	lzma_file_info_coder *coder = next->coder;
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_file_info_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+		next->code = &file_info_decode;
+		next->end = &file_info_decoder_end;
+		next->memconfig = &file_info_decoder_memconfig;
+
+		coder->index_decoder = LZMA_NEXT_CODER_INIT;
+		coder->this_index = NULL;
+		coder->combined_index = NULL;
+	}
+
+	coder->sequence = SEQ_MAGIC_BYTES;
+	coder->file_cur_pos = 0;
+	coder->file_target_pos = 0;
+	coder->file_size = file_size;
+
+	lzma_index_end(coder->this_index, allocator);
+	coder->this_index = NULL;
+
+	lzma_index_end(coder->combined_index, allocator);
+	coder->combined_index = NULL;
+
+	coder->stream_padding = 0;
+
+	coder->dest_index = dest_index;
+	coder->external_seek_pos = seek_pos;
+
+	// If memlimit is 0, make it 1 to ensure that lzma_memlimit_get()
+	// won't return 0 (which would indicate an error).
+	coder->memlimit = my_max(1, memlimit);
+
+	// Prepare these for reading the first Stream Header into coder->temp.
+	coder->temp_pos = 0;
+	coder->temp_size = LZMA_STREAM_HEADER_SIZE;
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_file_info_decoder(lzma_stream *strm, lzma_index **dest_index,
+		uint64_t memlimit, uint64_t file_size)
+{
+	lzma_next_strm_init(lzma_file_info_decoder_init, strm, &strm->seek_pos,
+			dest_index, memlimit, file_size);
+
+	// We allow LZMA_FINISH in addition to LZMA_RUN for convenience.
+	// lzma_code() is able to handle the LZMA_FINISH + LZMA_SEEK_NEEDED
+	// combination in a sane way. Applications still need to be careful
+	// if they use LZMA_FINISH so that they remember to reset it back
+	// to LZMA_RUN after seeking if needed.
+	strm->internal->supported_actions[LZMA_RUN] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_decoder.c
new file mode 100644
index 00000000000..cc0d88cc71c
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_decoder.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       filter_buffer_decoder.c
+/// \brief      Single-call raw decoding
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_decoder.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_raw_buffer_decode(
+		const lzma_filter *filters, const lzma_allocator *allocator,
+		const uint8_t *in, size_t *in_pos, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+{
+	// Validate what isn't validated later in filter_common.c.
+	if (in == NULL || in_pos == NULL || *in_pos > in_size || out == NULL
+			|| out_pos == NULL || *out_pos > out_size)
+		return LZMA_PROG_ERROR;
+
+	// Initialize the decoder.
+	lzma_next_coder next = LZMA_NEXT_CODER_INIT;
+	return_if_error(lzma_raw_decoder_init(&next, allocator, filters));
+
+	// Store the positions so that we can restore them if something
+	// goes wrong.
+	const size_t in_start = *in_pos;
+	const size_t out_start = *out_pos;
+
+	// Do the actual decoding and free decoder's memory.
+	lzma_ret ret = next.code(next.coder, allocator, in, in_pos, in_size,
+			out, out_pos, out_size, LZMA_FINISH);
+
+	if (ret == LZMA_STREAM_END) {
+		ret = LZMA_OK;
+	} else {
+		if (ret == LZMA_OK) {
+			// Either the input was truncated or the
+			// output buffer was too small.
+			assert(*in_pos == in_size || *out_pos == out_size);
+
+			if (*in_pos != in_size) {
+				// Since input wasn't consumed completely,
+				// the output buffer became full and is
+				// too small.
+				ret = LZMA_BUF_ERROR;
+
+			} else if (*out_pos != out_size) {
+				// Since output didn't became full, the input
+				// has to be truncated.
+				ret = LZMA_DATA_ERROR;
+
+			} else {
+				// All the input was consumed and output
+				// buffer is full. Now we don't immediately
+				// know the reason for the error. Try
+				// decoding one more byte. If it succeeds,
+				// then the output buffer was too small. If
+				// we cannot get a new output byte, the input
+				// is truncated.
+				uint8_t tmp[1];
+				size_t tmp_pos = 0;
+				(void)next.code(next.coder, allocator,
+						in, in_pos, in_size,
+						tmp, &tmp_pos, 1, LZMA_FINISH);
+
+				if (tmp_pos == 1)
+					ret = LZMA_BUF_ERROR;
+				else
+					ret = LZMA_DATA_ERROR;
+			}
+		}
+
+		// Restore the positions.
+		*in_pos = in_start;
+		*out_pos = out_start;
+	}
+
+	lzma_next_end(&next, allocator);
+
+	return ret;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_encoder.c
new file mode 100644
index 00000000000..7fb8922ae90
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_buffer_encoder.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       filter_buffer_encoder.c
+/// \brief      Single-call raw encoding
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_encoder.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_raw_buffer_encode(
+		const lzma_filter *filters, const lzma_allocator *allocator,
+		const uint8_t *in, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+{
+	// Validate what isn't validated later in filter_common.c.
+	if ((in == NULL && in_size != 0) || out == NULL
+			|| out_pos == NULL || *out_pos > out_size)
+		return LZMA_PROG_ERROR;
+
+	// Initialize the encoder
+	lzma_next_coder next = LZMA_NEXT_CODER_INIT;
+	return_if_error(lzma_raw_encoder_init(&next, allocator, filters));
+
+	// Store the output position so that we can restore it if
+	// something goes wrong.
+	const size_t out_start = *out_pos;
+
+	// Do the actual encoding and free coder's memory.
+	size_t in_pos = 0;
+	lzma_ret ret = next.code(next.coder, allocator, in, &in_pos, in_size,
+			out, out_pos, out_size, LZMA_FINISH);
+	lzma_next_end(&next, allocator);
+
+	if (ret == LZMA_STREAM_END) {
+		ret = LZMA_OK;
+	} else {
+		if (ret == LZMA_OK) {
+			// Output buffer was too small.
+			assert(*out_pos == out_size);
+			ret = LZMA_BUF_ERROR;
+		}
+
+		// Restore the output position.
+		*out_pos = out_start;
+	}
+
+	return ret;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.c
new file mode 100644
index 00000000000..d15d9cc94f9
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.c
@@ -0,0 +1,393 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       filter_common.c
+/// \brief      Filter-specific stuff common for both encoder and decoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_common.h"
+
+
+static const struct {
+	/// Filter ID
+	lzma_vli id;
+
+	/// Size of the filter-specific options structure
+	size_t options_size;
+
+	/// True if it is OK to use this filter as non-last filter in
+	/// the chain.
+	bool non_last_ok;
+
+	/// True if it is OK to use this filter as the last filter in
+	/// the chain.
+	bool last_ok;
+
+	/// True if the filter may change the size of the data (that is, the
+	/// amount of encoded output can be different than the amount of
+	/// uncompressed input).
+	bool changes_size;
+
+} features[] = {
+#if defined (HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1)
+	{
+		.id = LZMA_FILTER_LZMA1,
+		.options_size = sizeof(lzma_options_lzma),
+		.non_last_ok = false,
+		.last_ok = true,
+		.changes_size = true,
+	},
+	{
+		.id = LZMA_FILTER_LZMA1EXT,
+		.options_size = sizeof(lzma_options_lzma),
+		.non_last_ok = false,
+		.last_ok = true,
+		.changes_size = true,
+	},
+#endif
+#if defined(HAVE_ENCODER_LZMA2) || defined(HAVE_DECODER_LZMA2)
+	{
+		.id = LZMA_FILTER_LZMA2,
+		.options_size = sizeof(lzma_options_lzma),
+		.non_last_ok = false,
+		.last_ok = true,
+		.changes_size = true,
+	},
+#endif
+#if defined(HAVE_ENCODER_X86) || defined(HAVE_DECODER_X86)
+	{
+		.id = LZMA_FILTER_X86,
+		.options_size = sizeof(lzma_options_bcj),
+		.non_last_ok = true,
+		.last_ok = false,
+		.changes_size = false,
+	},
+#endif
+#if defined(HAVE_ENCODER_POWERPC) || defined(HAVE_DECODER_POWERPC)
+	{
+		.id = LZMA_FILTER_POWERPC,
+		.options_size = sizeof(lzma_options_bcj),
+		.non_last_ok = true,
+		.last_ok = false,
+		.changes_size = false,
+	},
+#endif
+#if defined(HAVE_ENCODER_IA64) || defined(HAVE_DECODER_IA64)
+	{
+		.id = LZMA_FILTER_IA64,
+		.options_size = sizeof(lzma_options_bcj),
+		.non_last_ok = true,
+		.last_ok = false,
+		.changes_size = false,
+	},
+#endif
+#if defined(HAVE_ENCODER_ARM) || defined(HAVE_DECODER_ARM)
+	{
+		.id = LZMA_FILTER_ARM,
+		.options_size = sizeof(lzma_options_bcj),
+		.non_last_ok = true,
+		.last_ok = false,
+		.changes_size = false,
+	},
+#endif
+#if defined(HAVE_ENCODER_ARMTHUMB) || defined(HAVE_DECODER_ARMTHUMB)
+	{
+		.id = LZMA_FILTER_ARMTHUMB,
+		.options_size = sizeof(lzma_options_bcj),
+		.non_last_ok = true,
+		.last_ok = false,
+		.changes_size = false,
+	},
+#endif
+#if defined(HAVE_ENCODER_ARM64) || defined(HAVE_DECODER_ARM64)
+	{
+		.id = LZMA_FILTER_ARM64,
+		.options_size = sizeof(lzma_options_bcj),
+		.non_last_ok = true,
+		.last_ok = false,
+		.changes_size = false,
+	},
+#endif
+#if defined(HAVE_ENCODER_SPARC) || defined(HAVE_DECODER_SPARC)
+	{
+		.id = LZMA_FILTER_SPARC,
+		.options_size = sizeof(lzma_options_bcj),
+		.non_last_ok = true,
+		.last_ok = false,
+		.changes_size = false,
+	},
+#endif
+#if defined(HAVE_ENCODER_RISCV) || defined(HAVE_DECODER_RISCV)
+	{
+		.id = LZMA_FILTER_RISCV,
+		.options_size = sizeof(lzma_options_bcj),
+		.non_last_ok = true,
+		.last_ok = false,
+		.changes_size = false,
+	},
+#endif
+#if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
+	{
+		.id = LZMA_FILTER_DELTA,
+		.options_size = sizeof(lzma_options_delta),
+		.non_last_ok = true,
+		.last_ok = false,
+		.changes_size = false,
+	},
+#endif
+	{
+		.id = LZMA_VLI_UNKNOWN
+	}
+};
+
+
+extern LZMA_API(lzma_ret)
+lzma_filters_copy(const lzma_filter *src, lzma_filter *real_dest,
+		const lzma_allocator *allocator)
+{
+	if (src == NULL || real_dest == NULL)
+		return LZMA_PROG_ERROR;
+
+	// Use a temporary destination so that the real destination
+	// will never be modified if an error occurs.
+	lzma_filter dest[LZMA_FILTERS_MAX + 1];
+
+	lzma_ret ret;
+	size_t i;
+	for (i = 0; src[i].id != LZMA_VLI_UNKNOWN; ++i) {
+		// There must be a maximum of four filters plus
+		// the array terminator.
+		if (i == LZMA_FILTERS_MAX) {
+			ret = LZMA_OPTIONS_ERROR;
+			goto error;
+		}
+
+		dest[i].id = src[i].id;
+
+		if (src[i].options == NULL) {
+			dest[i].options = NULL;
+		} else {
+			// See if the filter is supported only when the
+			// options is not NULL. This might be convenient
+			// sometimes if the app is actually copying only
+			// a partial filter chain with a place holder ID.
+			//
+			// When options is not NULL, the Filter ID must be
+			// supported by us, because otherwise we don't know
+			// how big the options are.
+			size_t j;
+			for (j = 0; src[i].id != features[j].id; ++j) {
+				if (features[j].id == LZMA_VLI_UNKNOWN) {
+					ret = LZMA_OPTIONS_ERROR;
+					goto error;
+				}
+			}
+
+			// Allocate and copy the options.
+			dest[i].options = lzma_alloc(features[j].options_size,
+					allocator);
+			if (dest[i].options == NULL) {
+				ret = LZMA_MEM_ERROR;
+				goto error;
+			}
+
+			memcpy(dest[i].options, src[i].options,
+					features[j].options_size);
+		}
+	}
+
+	// Terminate the filter array.
+	assert(i < LZMA_FILTERS_MAX + 1);
+	dest[i].id = LZMA_VLI_UNKNOWN;
+	dest[i].options = NULL;
+
+	// Copy it to the caller-supplied array now that we know that
+	// no errors occurred.
+	memcpy(real_dest, dest, (i + 1) * sizeof(lzma_filter));
+
+	return LZMA_OK;
+
+error:
+	// Free the options which we have already allocated.
+	while (i-- > 0)
+		lzma_free(dest[i].options, allocator);
+
+	return ret;
+}
+
+
+extern LZMA_API(void)
+lzma_filters_free(lzma_filter *filters, const lzma_allocator *allocator)
+{
+	if (filters == NULL)
+		return;
+
+	for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
+		if (i == LZMA_FILTERS_MAX) {
+			// The API says that LZMA_FILTERS_MAX + 1 is the
+			// maximum allowed size including the terminating
+			// element. Thus, we should never get here but in
+			// case there is a bug and we do anyway, don't go
+			// past the (probable) end of the array.
+			assert(0);
+			break;
+		}
+
+		lzma_free(filters[i].options, allocator);
+		filters[i].options = NULL;
+		filters[i].id = LZMA_VLI_UNKNOWN;
+	}
+
+	return;
+}
+
+
+extern lzma_ret
+lzma_validate_chain(const lzma_filter *filters, size_t *count)
+{
+	// There must be at least one filter.
+	if (filters == NULL || filters[0].id == LZMA_VLI_UNKNOWN)
+		return LZMA_PROG_ERROR;
+
+	// Number of non-last filters that may change the size of the data
+	// significantly (that is, more than 1-2 % or so).
+	size_t changes_size_count = 0;
+
+	// True if it is OK to add a new filter after the current filter.
+	bool non_last_ok = true;
+
+	// True if the last filter in the given chain is actually usable as
+	// the last filter. Only filters that support embedding End of Payload
+	// Marker can be used as the last filter in the chain.
+	bool last_ok = false;
+
+	size_t i = 0;
+	do {
+		size_t j;
+		for (j = 0; filters[i].id != features[j].id; ++j)
+			if (features[j].id == LZMA_VLI_UNKNOWN)
+				return LZMA_OPTIONS_ERROR;
+
+		// If the previous filter in the chain cannot be a non-last
+		// filter, the chain is invalid.
+		if (!non_last_ok)
+			return LZMA_OPTIONS_ERROR;
+
+		non_last_ok = features[j].non_last_ok;
+		last_ok = features[j].last_ok;
+		changes_size_count += features[j].changes_size;
+
+	} while (filters[++i].id != LZMA_VLI_UNKNOWN);
+
+	// There must be 1-4 filters. The last filter must be usable as
+	// the last filter in the chain. A maximum of three filters are
+	// allowed to change the size of the data.
+	if (i > LZMA_FILTERS_MAX || !last_ok || changes_size_count > 3)
+		return LZMA_OPTIONS_ERROR;
+
+	*count = i;
+	return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_raw_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter *options,
+		lzma_filter_find coder_find, bool is_encoder)
+{
+	// Do some basic validation and get the number of filters.
+	size_t count;
+	return_if_error(lzma_validate_chain(options, &count));
+
+	// Set the filter functions and copy the options pointer.
+	lzma_filter_info filters[LZMA_FILTERS_MAX + 1];
+	if (is_encoder) {
+		for (size_t i = 0; i < count; ++i) {
+			// The order of the filters is reversed in the
+			// encoder. It allows more efficient handling
+			// of the uncompressed data.
+			const size_t j = count - i - 1;
+
+			const lzma_filter_coder *const fc
+					= coder_find(options[i].id);
+			if (fc == NULL || fc->init == NULL)
+				return LZMA_OPTIONS_ERROR;
+
+			filters[j].id = options[i].id;
+			filters[j].init = fc->init;
+			filters[j].options = options[i].options;
+		}
+	} else {
+		for (size_t i = 0; i < count; ++i) {
+			const lzma_filter_coder *const fc
+					= coder_find(options[i].id);
+			if (fc == NULL || fc->init == NULL)
+				return LZMA_OPTIONS_ERROR;
+
+			filters[i].id = options[i].id;
+			filters[i].init = fc->init;
+			filters[i].options = options[i].options;
+		}
+	}
+
+	// Terminate the array.
+	filters[count].id = LZMA_VLI_UNKNOWN;
+	filters[count].init = NULL;
+
+	// Initialize the filters.
+	const lzma_ret ret = lzma_next_filter_init(next, allocator, filters);
+	if (ret != LZMA_OK)
+		lzma_next_end(next, allocator);
+
+	return ret;
+}
+
+
+extern uint64_t
+lzma_raw_coder_memusage(lzma_filter_find coder_find,
+		const lzma_filter *filters)
+{
+	// The chain has to have at least one filter.
+	{
+		size_t tmp;
+		if (lzma_validate_chain(filters, &tmp) != LZMA_OK)
+			return UINT64_MAX;
+	}
+
+	uint64_t total = 0;
+	size_t i = 0;
+
+	do {
+		const lzma_filter_coder *const fc
+				 = coder_find(filters[i].id);
+		if (fc == NULL)
+			return UINT64_MAX; // Unsupported Filter ID
+
+		if (fc->memusage == NULL) {
+			// This filter doesn't have a function to calculate
+			// the memory usage and validate the options. Such
+			// filters need only little memory, so we use 1 KiB
+			// as a good estimate. They also accept all possible
+			// options, so there's no need to worry about lack
+			// of validation.
+			total += 1024;
+		} else {
+			// Call the filter-specific memory usage calculation
+			// function.
+			const uint64_t usage
+					= fc->memusage(filters[i].options);
+			if (usage == UINT64_MAX)
+				return UINT64_MAX; // Invalid options
+
+			total += usage;
+		}
+	} while (filters[++i].id != LZMA_VLI_UNKNOWN);
+
+	// Add some fixed amount of extra. It's to compensate memory usage
+	// of Stream, Block etc. coders, malloc() overhead, stack etc.
+	return total + LZMA_MEMUSAGE_BASE;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.h
new file mode 100644
index 00000000000..95f9fe27017
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_common.h
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       filter_common.h
+/// \brief      Filter-specific stuff common for both encoder and decoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_FILTER_COMMON_H
+#define LZMA_FILTER_COMMON_H
+
+#include "common.h"
+
+
+/// Both lzma_filter_encoder and lzma_filter_decoder begin with these members.
+typedef struct {
+	/// Filter ID
+	lzma_vli id;
+
+	/// Initializes the filter encoder and calls lzma_next_filter_init()
+	/// for filters + 1.
+	lzma_init_function init;
+
+	/// Calculates memory usage of the encoder. If the options are
+	/// invalid, UINT64_MAX is returned.
+	uint64_t (*memusage)(const void *options);
+
+} lzma_filter_coder;
+
+
+typedef const lzma_filter_coder *(*lzma_filter_find)(lzma_vli id);
+
+
+extern lzma_ret lzma_validate_chain(const lzma_filter *filters, size_t *count);
+
+
+extern lzma_ret lzma_raw_coder_init(
+		lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter *filters,
+		lzma_filter_find coder_find, bool is_encoder);
+
+
+extern uint64_t lzma_raw_coder_memusage(lzma_filter_find coder_find,
+		const lzma_filter *filters);
+
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.c
new file mode 100644
index 00000000000..cbdeb5858f6
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       filter_decoder.c
+/// \brief      Filter ID mapping to filter-specific functions
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_decoder.h"
+#include "filter_common.h"
+#include "lzma_decoder.h"
+#include "lzma2_decoder.h"
+#include "simple_decoder.h"
+#include "delta_decoder.h"
+
+
+typedef struct {
+	/// Filter ID
+	lzma_vli id;
+
+	/// Initializes the filter encoder and calls lzma_next_filter_init()
+	/// for filters + 1.
+	lzma_init_function init;
+
+	/// Calculates memory usage of the encoder. If the options are
+	/// invalid, UINT64_MAX is returned.
+	uint64_t (*memusage)(const void *options);
+
+	/// Decodes Filter Properties.
+	///
+	/// \return     - LZMA_OK: Properties decoded successfully.
+	///             - LZMA_OPTIONS_ERROR: Unsupported properties
+	///             - LZMA_MEM_ERROR: Memory allocation failed.
+	lzma_ret (*props_decode)(
+			void **options, const lzma_allocator *allocator,
+			const uint8_t *props, size_t props_size);
+
+} lzma_filter_decoder;
+
+
+static const lzma_filter_decoder decoders[] = {
+#ifdef HAVE_DECODER_LZMA1
+	{
+		.id = LZMA_FILTER_LZMA1,
+		.init = &lzma_lzma_decoder_init,
+		.memusage = &lzma_lzma_decoder_memusage,
+		.props_decode = &lzma_lzma_props_decode,
+	},
+	{
+		.id = LZMA_FILTER_LZMA1EXT,
+		.init = &lzma_lzma_decoder_init,
+		.memusage = &lzma_lzma_decoder_memusage,
+		.props_decode = &lzma_lzma_props_decode,
+	},
+#endif
+#ifdef HAVE_DECODER_LZMA2
+	{
+		.id = LZMA_FILTER_LZMA2,
+		.init = &lzma_lzma2_decoder_init,
+		.memusage = &lzma_lzma2_decoder_memusage,
+		.props_decode = &lzma_lzma2_props_decode,
+	},
+#endif
+#ifdef HAVE_DECODER_X86
+	{
+		.id = LZMA_FILTER_X86,
+		.init = &lzma_simple_x86_decoder_init,
+		.memusage = NULL,
+		.props_decode = &lzma_simple_props_decode,
+	},
+#endif
+#ifdef HAVE_DECODER_POWERPC
+	{
+		.id = LZMA_FILTER_POWERPC,
+		.init = &lzma_simple_powerpc_decoder_init,
+		.memusage = NULL,
+		.props_decode = &lzma_simple_props_decode,
+	},
+#endif
+#ifdef HAVE_DECODER_IA64
+	{
+		.id = LZMA_FILTER_IA64,
+		.init = &lzma_simple_ia64_decoder_init,
+		.memusage = NULL,
+		.props_decode = &lzma_simple_props_decode,
+	},
+#endif
+#ifdef HAVE_DECODER_ARM
+	{
+		.id = LZMA_FILTER_ARM,
+		.init = &lzma_simple_arm_decoder_init,
+		.memusage = NULL,
+		.props_decode = &lzma_simple_props_decode,
+	},
+#endif
+#ifdef HAVE_DECODER_ARMTHUMB
+	{
+		.id = LZMA_FILTER_ARMTHUMB,
+		.init = &lzma_simple_armthumb_decoder_init,
+		.memusage = NULL,
+		.props_decode = &lzma_simple_props_decode,
+	},
+#endif
+#ifdef HAVE_DECODER_ARM64
+	{
+		.id = LZMA_FILTER_ARM64,
+		.init = &lzma_simple_arm64_decoder_init,
+		.memusage = NULL,
+		.props_decode = &lzma_simple_props_decode,
+	},
+#endif
+#ifdef HAVE_DECODER_SPARC
+	{
+		.id = LZMA_FILTER_SPARC,
+		.init = &lzma_simple_sparc_decoder_init,
+		.memusage = NULL,
+		.props_decode = &lzma_simple_props_decode,
+	},
+#endif
+#ifdef HAVE_DECODER_RISCV
+	{
+		.id = LZMA_FILTER_RISCV,
+		.init = &lzma_simple_riscv_decoder_init,
+		.memusage = NULL,
+		.props_decode = &lzma_simple_props_decode,
+	},
+#endif
+#ifdef HAVE_DECODER_DELTA
+	{
+		.id = LZMA_FILTER_DELTA,
+		.init = &lzma_delta_decoder_init,
+		.memusage = &lzma_delta_coder_memusage,
+		.props_decode = &lzma_delta_props_decode,
+	},
+#endif
+};
+
+
+static const lzma_filter_decoder *
+decoder_find(lzma_vli id)
+{
+	for (size_t i = 0; i < ARRAY_SIZE(decoders); ++i)
+		if (decoders[i].id == id)
+			return decoders + i;
+
+	return NULL;
+}
+
+
+// lzma_filter_coder begins with the same members as lzma_filter_decoder.
+// This function is a wrapper with a type that is compatible with the
+// typedef of lzma_filter_find in filter_common.h.
+static const lzma_filter_coder *
+coder_find(lzma_vli id)
+{
+	return (const lzma_filter_coder *)decoder_find(id);
+}
+
+
+extern LZMA_API(lzma_bool)
+lzma_filter_decoder_is_supported(lzma_vli id)
+{
+	return decoder_find(id) != NULL;
+}
+
+
+extern lzma_ret
+lzma_raw_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter *options)
+{
+	return lzma_raw_coder_init(next, allocator,
+			options, &coder_find, false);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_raw_decoder(lzma_stream *strm, const lzma_filter *options)
+{
+	lzma_next_strm_init(lzma_raw_decoder_init, strm, options);
+
+	strm->internal->supported_actions[LZMA_RUN] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(uint64_t)
+lzma_raw_decoder_memusage(const lzma_filter *filters)
+{
+	return lzma_raw_coder_memusage(&coder_find, filters);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_properties_decode(lzma_filter *filter, const lzma_allocator *allocator,
+		const uint8_t *props, size_t props_size)
+{
+	// Make it always NULL so that the caller can always safely free() it.
+	filter->options = NULL;
+
+	const lzma_filter_decoder *const fd = decoder_find(filter->id);
+	if (fd == NULL)
+		return LZMA_OPTIONS_ERROR;
+
+	if (fd->props_decode == NULL)
+		return props_size == 0 ? LZMA_OK : LZMA_OPTIONS_ERROR;
+
+	return fd->props_decode(
+			&filter->options, allocator, props, props_size);
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.h
new file mode 100644
index 00000000000..e610bc1f44e
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_decoder.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       filter_decoder.h
+/// \brief      Filter ID mapping to filter-specific functions
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_FILTER_DECODER_H
+#define LZMA_FILTER_DECODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_raw_decoder_init(
+		lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter *options);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.c
new file mode 100644
index 00000000000..bc394448985
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.c
@@ -0,0 +1,330 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       filter_decoder.c
+/// \brief      Filter ID mapping to filter-specific functions
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_encoder.h"
+#include "filter_common.h"
+#include "lzma_encoder.h"
+#include "lzma2_encoder.h"
+#include "simple_encoder.h"
+#include "delta_encoder.h"
+
+
+typedef struct {
+	/// Filter ID
+	lzma_vli id;
+
+	/// Initializes the filter encoder and calls lzma_next_filter_init()
+	/// for filters + 1.
+	lzma_init_function init;
+
+	/// Calculates memory usage of the encoder. If the options are
+	/// invalid, UINT64_MAX is returned.
+	uint64_t (*memusage)(const void *options);
+
+	/// Calculates the recommended Uncompressed Size for .xz Blocks to
+	/// which the input data can be split to make multithreaded
+	/// encoding possible. If this is NULL, it is assumed that
+	/// the encoder is fast enough with single thread. If the options
+	/// are invalid, UINT64_MAX is returned.
+	uint64_t (*block_size)(const void *options);
+
+	/// Tells the size of the Filter Properties field. If options are
+	/// invalid, LZMA_OPTIONS_ERROR is returned and size is set to
+	/// UINT32_MAX.
+	lzma_ret (*props_size_get)(uint32_t *size, const void *options);
+
+	/// Some filters will always have the same size Filter Properties
+	/// field. If props_size_get is NULL, this value is used.
+	uint32_t props_size_fixed;
+
+	/// Encodes Filter Properties.
+	///
+	/// \return     - LZMA_OK: Properties encoded successfully.
+	///             - LZMA_OPTIONS_ERROR: Unsupported options
+	///             - LZMA_PROG_ERROR: Invalid options or not enough
+	///               output space
+	lzma_ret (*props_encode)(const void *options, uint8_t *out);
+
+} lzma_filter_encoder;
+
+
+static const lzma_filter_encoder encoders[] = {
+#ifdef HAVE_ENCODER_LZMA1
+	{
+		.id = LZMA_FILTER_LZMA1,
+		.init = &lzma_lzma_encoder_init,
+		.memusage = &lzma_lzma_encoder_memusage,
+		.block_size = NULL, // Not needed for LZMA1
+		.props_size_get = NULL,
+		.props_size_fixed = 5,
+		.props_encode = &lzma_lzma_props_encode,
+	},
+	{
+		.id = LZMA_FILTER_LZMA1EXT,
+		.init = &lzma_lzma_encoder_init,
+		.memusage = &lzma_lzma_encoder_memusage,
+		.block_size = NULL, // Not needed for LZMA1
+		.props_size_get = NULL,
+		.props_size_fixed = 5,
+		.props_encode = &lzma_lzma_props_encode,
+	},
+#endif
+#ifdef HAVE_ENCODER_LZMA2
+	{
+		.id = LZMA_FILTER_LZMA2,
+		.init = &lzma_lzma2_encoder_init,
+		.memusage = &lzma_lzma2_encoder_memusage,
+		.block_size = &lzma_lzma2_block_size,
+		.props_size_get = NULL,
+		.props_size_fixed = 1,
+		.props_encode = &lzma_lzma2_props_encode,
+	},
+#endif
+#ifdef HAVE_ENCODER_X86
+	{
+		.id = LZMA_FILTER_X86,
+		.init = &lzma_simple_x86_encoder_init,
+		.memusage = NULL,
+		.block_size = NULL,
+		.props_size_get = &lzma_simple_props_size,
+		.props_encode = &lzma_simple_props_encode,
+	},
+#endif
+#ifdef HAVE_ENCODER_POWERPC
+	{
+		.id = LZMA_FILTER_POWERPC,
+		.init = &lzma_simple_powerpc_encoder_init,
+		.memusage = NULL,
+		.block_size = NULL,
+		.props_size_get = &lzma_simple_props_size,
+		.props_encode = &lzma_simple_props_encode,
+	},
+#endif
+#ifdef HAVE_ENCODER_IA64
+	{
+		.id = LZMA_FILTER_IA64,
+		.init = &lzma_simple_ia64_encoder_init,
+		.memusage = NULL,
+		.block_size = NULL,
+		.props_size_get = &lzma_simple_props_size,
+		.props_encode = &lzma_simple_props_encode,
+	},
+#endif
+#ifdef HAVE_ENCODER_ARM
+	{
+		.id = LZMA_FILTER_ARM,
+		.init = &lzma_simple_arm_encoder_init,
+		.memusage = NULL,
+		.block_size = NULL,
+		.props_size_get = &lzma_simple_props_size,
+		.props_encode = &lzma_simple_props_encode,
+	},
+#endif
+#ifdef HAVE_ENCODER_ARMTHUMB
+	{
+		.id = LZMA_FILTER_ARMTHUMB,
+		.init = &lzma_simple_armthumb_encoder_init,
+		.memusage = NULL,
+		.block_size = NULL,
+		.props_size_get = &lzma_simple_props_size,
+		.props_encode = &lzma_simple_props_encode,
+	},
+#endif
+#ifdef HAVE_ENCODER_ARM64
+	{
+		.id = LZMA_FILTER_ARM64,
+		.init = &lzma_simple_arm64_encoder_init,
+		.memusage = NULL,
+		.block_size = NULL,
+		.props_size_get = &lzma_simple_props_size,
+		.props_encode = &lzma_simple_props_encode,
+	},
+#endif
+#ifdef HAVE_ENCODER_SPARC
+	{
+		.id = LZMA_FILTER_SPARC,
+		.init = &lzma_simple_sparc_encoder_init,
+		.memusage = NULL,
+		.block_size = NULL,
+		.props_size_get = &lzma_simple_props_size,
+		.props_encode = &lzma_simple_props_encode,
+	},
+#endif
+#ifdef HAVE_ENCODER_RISCV
+	{
+		.id = LZMA_FILTER_RISCV,
+		.init = &lzma_simple_riscv_encoder_init,
+		.memusage = NULL,
+		.block_size = NULL,
+		.props_size_get = &lzma_simple_props_size,
+		.props_encode = &lzma_simple_props_encode,
+	},
+#endif
+#ifdef HAVE_ENCODER_DELTA
+	{
+		.id = LZMA_FILTER_DELTA,
+		.init = &lzma_delta_encoder_init,
+		.memusage = &lzma_delta_coder_memusage,
+		.block_size = NULL,
+		.props_size_get = NULL,
+		.props_size_fixed = 1,
+		.props_encode = &lzma_delta_props_encode,
+	},
+#endif
+};
+
+
+static const lzma_filter_encoder *
+encoder_find(lzma_vli id)
+{
+	for (size_t i = 0; i < ARRAY_SIZE(encoders); ++i)
+		if (encoders[i].id == id)
+			return encoders + i;
+
+	return NULL;
+}
+
+
+// lzma_filter_coder begins with the same members as lzma_filter_encoder.
+// This function is a wrapper with a type that is compatible with the
+// typedef of lzma_filter_find in filter_common.h.
+static const lzma_filter_coder *
+coder_find(lzma_vli id)
+{
+	return (const lzma_filter_coder *)encoder_find(id);
+}
+
+
+extern LZMA_API(lzma_bool)
+lzma_filter_encoder_is_supported(lzma_vli id)
+{
+	return encoder_find(id) != NULL;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_filters_update(lzma_stream *strm, const lzma_filter *filters)
+{
+	if (strm->internal->next.update == NULL)
+		return LZMA_PROG_ERROR;
+
+	// Validate the filter chain.
+	if (lzma_raw_encoder_memusage(filters) == UINT64_MAX)
+		return LZMA_OPTIONS_ERROR;
+
+	// The actual filter chain in the encoder is reversed. Some things
+	// still want the normal order chain, so we provide both.
+	size_t count = 1;
+	while (filters[count].id != LZMA_VLI_UNKNOWN)
+		++count;
+
+	lzma_filter reversed_filters[LZMA_FILTERS_MAX + 1];
+	for (size_t i = 0; i < count; ++i)
+		reversed_filters[count - i - 1] = filters[i];
+
+	reversed_filters[count].id = LZMA_VLI_UNKNOWN;
+
+	return strm->internal->next.update(strm->internal->next.coder,
+			strm->allocator, filters, reversed_filters);
+}
+
+
+extern lzma_ret
+lzma_raw_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter *filters)
+{
+	return lzma_raw_coder_init(next, allocator,
+			filters, &coder_find, true);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_raw_encoder(lzma_stream *strm, const lzma_filter *filters)
+{
+	lzma_next_strm_init(lzma_raw_coder_init, strm, filters,
+			&coder_find, true);
+
+	strm->internal->supported_actions[LZMA_RUN] = true;
+	strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(uint64_t)
+lzma_raw_encoder_memusage(const lzma_filter *filters)
+{
+	return lzma_raw_coder_memusage(&coder_find, filters);
+}
+
+
+extern LZMA_API(uint64_t)
+lzma_mt_block_size(const lzma_filter *filters)
+{
+	if (filters == NULL)
+		return UINT64_MAX;
+
+	uint64_t max = 0;
+
+	for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
+		const lzma_filter_encoder *const fe
+				= encoder_find(filters[i].id);
+		if (fe == NULL)
+			return UINT64_MAX;
+
+		if (fe->block_size != NULL) {
+			const uint64_t size
+					= fe->block_size(filters[i].options);
+			if (size > max)
+				max = size;
+		}
+	}
+
+	return max == 0 ? UINT64_MAX : max;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_properties_size(uint32_t *size, const lzma_filter *filter)
+{
+	const lzma_filter_encoder *const fe = encoder_find(filter->id);
+	if (fe == NULL) {
+		// Unknown filter - if the Filter ID is a proper VLI,
+		// return LZMA_OPTIONS_ERROR instead of LZMA_PROG_ERROR,
+		// because it's possible that we just don't have support
+		// compiled in for the requested filter.
+		return filter->id <= LZMA_VLI_MAX
+				? LZMA_OPTIONS_ERROR : LZMA_PROG_ERROR;
+	}
+
+	if (fe->props_size_get == NULL) {
+		// No props_size_get() function, use props_size_fixed.
+		*size = fe->props_size_fixed;
+		return LZMA_OK;
+	}
+
+	return fe->props_size_get(size, filter->options);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_properties_encode(const lzma_filter *filter, uint8_t *props)
+{
+	const lzma_filter_encoder *const fe = encoder_find(filter->id);
+	if (fe == NULL)
+		return LZMA_PROG_ERROR;
+
+	if (fe->props_encode == NULL)
+		return LZMA_OK;
+
+	return fe->props_encode(filter->options, props);
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.h
new file mode 100644
index 00000000000..88f2dafa43b
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_encoder.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       filter_encoder.h
+/// \brief      Filter ID mapping to filter-specific functions
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_FILTER_ENCODER_H
+#define LZMA_FILTER_ENCODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_raw_encoder_init(
+		lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter *filters);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_decoder.c
new file mode 100644
index 00000000000..0f5d204d474
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_decoder.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       filter_flags_decoder.c
+/// \brief      Decodes a Filter Flags field
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_decoder.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_filter_flags_decode(
+		lzma_filter *filter, const lzma_allocator *allocator,
+		const uint8_t *in, size_t *in_pos, size_t in_size)
+{
+	// Set the pointer to NULL so the caller can always safely free it.
+	filter->options = NULL;
+
+	// Filter ID
+	return_if_error(lzma_vli_decode(&filter->id, NULL,
+			in, in_pos, in_size));
+
+	if (filter->id >= LZMA_FILTER_RESERVED_START)
+		return LZMA_DATA_ERROR;
+
+	// Size of Properties
+	lzma_vli props_size;
+	return_if_error(lzma_vli_decode(&props_size, NULL,
+			in, in_pos, in_size));
+
+	// Filter Properties
+	if (in_size - *in_pos < props_size)
+		return LZMA_DATA_ERROR;
+
+	const lzma_ret ret = lzma_properties_decode(
+			filter, allocator, in + *in_pos, props_size);
+
+	*in_pos += props_size;
+
+	return ret;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_encoder.c
new file mode 100644
index 00000000000..e1d65884fb0
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/filter_flags_encoder.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       filter_flags_encoder.c
+/// \brief      Encodes a Filter Flags field
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_encoder.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_filter_flags_size(uint32_t *size, const lzma_filter *filter)
+{
+	if (filter->id >= LZMA_FILTER_RESERVED_START)
+		return LZMA_PROG_ERROR;
+
+	return_if_error(lzma_properties_size(size, filter));
+
+	*size += lzma_vli_size(filter->id) + lzma_vli_size(*size);
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_filter_flags_encode(const lzma_filter *filter,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+{
+	// Filter ID
+	if (filter->id >= LZMA_FILTER_RESERVED_START)
+		return LZMA_PROG_ERROR;
+
+	return_if_error(lzma_vli_encode(filter->id, NULL,
+			out, out_pos, out_size));
+
+	// Size of Properties
+	uint32_t props_size;
+	return_if_error(lzma_properties_size(&props_size, filter));
+	return_if_error(lzma_vli_encode(props_size, NULL,
+			out, out_pos, out_size));
+
+	// Filter Properties
+	if (out_size - *out_pos < props_size)
+		return LZMA_PROG_ERROR;
+
+	return_if_error(lzma_properties_encode(filter, out + *out_pos));
+
+	*out_pos += props_size;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_cputhreads.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_cputhreads.c
new file mode 100644
index 00000000000..4ce852b42c3
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_cputhreads.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       hardware_cputhreads.c
+/// \brief      Get the number of CPU threads or cores
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+#include "tuklib_cpucores.h"
+
+
+#ifdef HAVE_SYMBOL_VERSIONS_LINUX
+// This is for compatibility with binaries linked against liblzma that
+// has been patched with xz-5.2.2-compat-libs.patch from RHEL/CentOS 7.
+LZMA_SYMVER_API("lzma_cputhreads@XZ_5.2.2",
+	uint32_t, lzma_cputhreads_522)(void) lzma_nothrow
+		__attribute__((__alias__("lzma_cputhreads_52")));
+
+LZMA_SYMVER_API("lzma_cputhreads@@XZ_5.2",
+	uint32_t, lzma_cputhreads_52)(void) lzma_nothrow;
+
+#define lzma_cputhreads lzma_cputhreads_52
+#endif
+extern LZMA_API(uint32_t)
+lzma_cputhreads(void)
+{
+	return tuklib_cpucores();
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_physmem.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_physmem.c
new file mode 100644
index 00000000000..1bc34864e84
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/hardware_physmem.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       hardware_physmem.c
+/// \brief      Get the total amount of physical memory (RAM)
+//
+//  Author:     Jonathan Nieder
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+#include "tuklib_physmem.h"
+
+
+extern LZMA_API(uint64_t)
+lzma_physmem(void)
+{
+	// It is simpler to make lzma_physmem() a wrapper for
+	// tuklib_physmem() than to hack appropriate symbol visibility
+	// support for the tuklib modules.
+	return tuklib_physmem();
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.c
new file mode 100644
index 00000000000..6add6a68350
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.c
@@ -0,0 +1,1268 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       index.c
+/// \brief      Handling of .xz Indexes and some other Stream information
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+#include "index.h"
+#include "stream_flags_common.h"
+
+
+/// \brief      How many Records to allocate at once
+///
+/// This should be big enough to avoid making lots of tiny allocations
+/// but small enough to avoid too much unused memory at once.
+#define INDEX_GROUP_SIZE 512
+
+
+/// \brief      How many Records can be allocated at once at maximum
+#define PREALLOC_MAX ((SIZE_MAX - sizeof(index_group)) / sizeof(index_record))
+
+
+/// \brief      Base structure for index_stream and index_group structures
+typedef struct index_tree_node_s index_tree_node;
+struct index_tree_node_s {
+	/// Uncompressed start offset of this Stream (relative to the
+	/// beginning of the file) or Block (relative to the beginning
+	/// of the Stream)
+	lzma_vli uncompressed_base;
+
+	/// Compressed start offset of this Stream or Block
+	lzma_vli compressed_base;
+
+	index_tree_node *parent;
+	index_tree_node *left;
+	index_tree_node *right;
+};
+
+
+/// \brief      AVL tree to hold index_stream or index_group structures
+typedef struct {
+	/// Root node
+	index_tree_node *root;
+
+	/// Leftmost node. Since the tree will be filled sequentially,
+	/// this won't change after the first node has been added to
+	/// the tree.
+	index_tree_node *leftmost;
+
+	/// The rightmost node in the tree. Since the tree is filled
+	/// sequentially, this is always the node where to add the new data.
+	index_tree_node *rightmost;
+
+	/// Number of nodes in the tree
+	uint32_t count;
+
+} index_tree;
+
+
+typedef struct {
+	lzma_vli uncompressed_sum;
+	lzma_vli unpadded_sum;
+} index_record;
+
+
+typedef struct {
+	/// Every Record group is part of index_stream.groups tree.
+	index_tree_node node;
+
+	/// Number of Blocks in this Stream before this group.
+	lzma_vli number_base;
+
+	/// Number of Records that can be put in records[].
+	size_t allocated;
+
+	/// Index of the last Record in use.
+	size_t last;
+
+	/// The sizes in this array are stored as cumulative sums relative
+	/// to the beginning of the Stream. This makes it possible to
+	/// use binary search in lzma_index_locate().
+	///
+	/// Note that the cumulative summing is done specially for
+	/// unpadded_sum: The previous value is rounded up to the next
+	/// multiple of four before adding the Unpadded Size of the new
+	/// Block. The total encoded size of the Blocks in the Stream
+	/// is records[last].unpadded_sum in the last Record group of
+	/// the Stream.
+	///
+	/// For example, if the Unpadded Sizes are 39, 57, and 81, the
+	/// stored values are 39, 97 (40 + 57), and 181 (100 + 181).
+	/// The total encoded size of these Blocks is 184.
+	///
+	/// This is a flexible array, because it makes easy to optimize
+	/// memory usage in case someone concatenates many Streams that
+	/// have only one or few Blocks.
+	index_record records[];
+
+} index_group;
+
+
+typedef struct {
+	/// Every index_stream is a node in the tree of Streams.
+	index_tree_node node;
+
+	/// Number of this Stream (first one is 1)
+	uint32_t number;
+
+	/// Total number of Blocks before this Stream
+	lzma_vli block_number_base;
+
+	/// Record groups of this Stream are stored in a tree.
+	/// It's a T-tree with AVL-tree balancing. There are
+	/// INDEX_GROUP_SIZE Records per node by default.
+	/// This keeps the number of memory allocations reasonable
+	/// and finding a Record is fast.
+	index_tree groups;
+
+	/// Number of Records in this Stream
+	lzma_vli record_count;
+
+	/// Size of the List of Records field in this Stream. This is used
+	/// together with record_count to calculate the size of the Index
+	/// field and thus the total size of the Stream.
+	lzma_vli index_list_size;
+
+	/// Stream Flags of this Stream. This is meaningful only if
+	/// the Stream Flags have been told us with lzma_index_stream_flags().
+	/// Initially stream_flags.version is set to UINT32_MAX to indicate
+	/// that the Stream Flags are unknown.
+	lzma_stream_flags stream_flags;
+
+	/// Amount of Stream Padding after this Stream. This defaults to
+	/// zero and can be set with lzma_index_stream_padding().
+	lzma_vli stream_padding;
+
+} index_stream;
+
+
+struct lzma_index_s {
+	/// AVL-tree containing the Stream(s). Often there is just one
+	/// Stream, but using a tree keeps lookups fast even when there
+	/// are many concatenated Streams.
+	index_tree streams;
+
+	/// Uncompressed size of all the Blocks in the Stream(s)
+	lzma_vli uncompressed_size;
+
+	/// Total size of all the Blocks in the Stream(s)
+	lzma_vli total_size;
+
+	/// Total number of Records in all Streams in this lzma_index
+	lzma_vli record_count;
+
+	/// Size of the List of Records field if all the Streams in this
+	/// lzma_index were packed into a single Stream (makes it simpler to
+	/// take many .xz files and combine them into a single Stream).
+	///
+	/// This value together with record_count is needed to calculate
+	/// Backward Size that is stored into Stream Footer.
+	lzma_vli index_list_size;
+
+	/// How many Records to allocate at once in lzma_index_append().
+	/// This defaults to INDEX_GROUP_SIZE but can be overridden with
+	/// lzma_index_prealloc().
+	size_t prealloc;
+
+	/// Bitmask indicating what integrity check types have been used
+	/// as set by lzma_index_stream_flags(). The bit of the last Stream
+	/// is not included here, since it is possible to change it by
+	/// calling lzma_index_stream_flags() again.
+	uint32_t checks;
+};
+
+
+static void
+index_tree_init(index_tree *tree)
+{
+	tree->root = NULL;
+	tree->leftmost = NULL;
+	tree->rightmost = NULL;
+	tree->count = 0;
+	return;
+}
+
+
+/// Helper for index_tree_end()
+static void
+index_tree_node_end(index_tree_node *node, const lzma_allocator *allocator,
+		void (*free_func)(void *node, const lzma_allocator *allocator))
+{
+	// The tree won't ever be very huge, so recursion should be fine.
+	// 20 levels in the tree is likely quite a lot already in practice.
+	if (node->left != NULL)
+		index_tree_node_end(node->left, allocator, free_func);
+
+	if (node->right != NULL)
+		index_tree_node_end(node->right, allocator, free_func);
+
+	free_func(node, allocator);
+	return;
+}
+
+
+/// Free the memory allocated for a tree. Each node is freed using the
+/// given free_func which is either &lzma_free or &index_stream_end.
+/// The latter is used to free the Record groups from each index_stream
+/// before freeing the index_stream itself.
+static void
+index_tree_end(index_tree *tree, const lzma_allocator *allocator,
+		void (*free_func)(void *node, const lzma_allocator *allocator))
+{
+	assert(free_func != NULL);
+
+	if (tree->root != NULL)
+		index_tree_node_end(tree->root, allocator, free_func);
+
+	return;
+}
+
+
+/// Add a new node to the tree. node->uncompressed_base and
+/// node->compressed_base must have been set by the caller already.
+static void
+index_tree_append(index_tree *tree, index_tree_node *node)
+{
+	node->parent = tree->rightmost;
+	node->left = NULL;
+	node->right = NULL;
+
+	++tree->count;
+
+	// Handle the special case of adding the first node.
+	if (tree->root == NULL) {
+		tree->root = node;
+		tree->leftmost = node;
+		tree->rightmost = node;
+		return;
+	}
+
+	// The tree is always filled sequentially.
+	assert(tree->rightmost->uncompressed_base <= node->uncompressed_base);
+	assert(tree->rightmost->compressed_base < node->compressed_base);
+
+	// Add the new node after the rightmost node. It's the correct
+	// place due to the reason above.
+	tree->rightmost->right = node;
+	tree->rightmost = node;
+
+	// Balance the AVL-tree if needed. We don't need to keep the balance
+	// factors in nodes, because we always fill the tree sequentially,
+	// and thus know the state of the tree just by looking at the node
+	// count. From the node count we can calculate how many steps to go
+	// up in the tree to find the rotation root.
+	uint32_t up = tree->count ^ (UINT32_C(1) << bsr32(tree->count));
+	if (up != 0) {
+		// Locate the root node for the rotation.
+		up = ctz32(tree->count) + 2;
+		do {
+			node = node->parent;
+		} while (--up > 0);
+
+		// Rotate left using node as the rotation root.
+		index_tree_node *pivot = node->right;
+
+		if (node->parent == NULL) {
+			tree->root = pivot;
+		} else {
+			assert(node->parent->right == node);
+			node->parent->right = pivot;
+		}
+
+		pivot->parent = node->parent;
+
+		node->right = pivot->left;
+		if (node->right != NULL)
+			node->right->parent = node;
+
+		pivot->left = node;
+		node->parent = pivot;
+	}
+
+	return;
+}
+
+
+/// Get the next node in the tree. Return NULL if there are no more nodes.
+static void *
+index_tree_next(const index_tree_node *node)
+{
+	if (node->right != NULL) {
+		node = node->right;
+		while (node->left != NULL)
+			node = node->left;
+
+		return (void *)(node);
+	}
+
+	while (node->parent != NULL && node->parent->right == node)
+		node = node->parent;
+
+	return (void *)(node->parent);
+}
+
+
+/// Locate a node that contains the given uncompressed offset. It is
+/// caller's job to check that target is not bigger than the uncompressed
+/// size of the tree (the last node would be returned in that case still).
+static void *
+index_tree_locate(const index_tree *tree, lzma_vli target)
+{
+	const index_tree_node *result = NULL;
+	const index_tree_node *node = tree->root;
+
+	assert(tree->leftmost == NULL
+			|| tree->leftmost->uncompressed_base == 0);
+
+	// Consecutive nodes may have the same uncompressed_base.
+	// We must pick the rightmost one.
+	while (node != NULL) {
+		if (node->uncompressed_base > target) {
+			node = node->left;
+		} else {
+			result = node;
+			node = node->right;
+		}
+	}
+
+	return (void *)(result);
+}
+
+
+/// Allocate and initialize a new Stream using the given base offsets.
+static index_stream *
+index_stream_init(lzma_vli compressed_base, lzma_vli uncompressed_base,
+		uint32_t stream_number, lzma_vli block_number_base,
+		const lzma_allocator *allocator)
+{
+	index_stream *s = lzma_alloc(sizeof(index_stream), allocator);
+	if (s == NULL)
+		return NULL;
+
+	s->node.uncompressed_base = uncompressed_base;
+	s->node.compressed_base = compressed_base;
+	s->node.parent = NULL;
+	s->node.left = NULL;
+	s->node.right = NULL;
+
+	s->number = stream_number;
+	s->block_number_base = block_number_base;
+
+	index_tree_init(&s->groups);
+
+	s->record_count = 0;
+	s->index_list_size = 0;
+	s->stream_flags.version = UINT32_MAX;
+	s->stream_padding = 0;
+
+	return s;
+}
+
+
+/// Free the memory allocated for a Stream and its Record groups.
+static void
+index_stream_end(void *node, const lzma_allocator *allocator)
+{
+	index_stream *s = node;
+	index_tree_end(&s->groups, allocator, &lzma_free);
+	lzma_free(s, allocator);
+	return;
+}
+
+
+static lzma_index *
+index_init_plain(const lzma_allocator *allocator)
+{
+	lzma_index *i = lzma_alloc(sizeof(lzma_index), allocator);
+	if (i != NULL) {
+		index_tree_init(&i->streams);
+		i->uncompressed_size = 0;
+		i->total_size = 0;
+		i->record_count = 0;
+		i->index_list_size = 0;
+		i->prealloc = INDEX_GROUP_SIZE;
+		i->checks = 0;
+	}
+
+	return i;
+}
+
+
+extern LZMA_API(lzma_index *)
+lzma_index_init(const lzma_allocator *allocator)
+{
+	lzma_index *i = index_init_plain(allocator);
+	if (i == NULL)
+		return NULL;
+
+	index_stream *s = index_stream_init(0, 0, 1, 0, allocator);
+	if (s == NULL) {
+		lzma_free(i, allocator);
+		return NULL;
+	}
+
+	index_tree_append(&i->streams, &s->node);
+
+	return i;
+}
+
+
+extern LZMA_API(void)
+lzma_index_end(lzma_index *i, const lzma_allocator *allocator)
+{
+	// NOTE: If you modify this function, check also the bottom
+	// of lzma_index_cat().
+	if (i != NULL) {
+		index_tree_end(&i->streams, allocator, &index_stream_end);
+		lzma_free(i, allocator);
+	}
+
+	return;
+}
+
+
+extern void
+lzma_index_prealloc(lzma_index *i, lzma_vli records)
+{
+	if (records > PREALLOC_MAX)
+		records = PREALLOC_MAX;
+
+	i->prealloc = (size_t)(records);
+	return;
+}
+
+
+extern LZMA_API(uint64_t)
+lzma_index_memusage(lzma_vli streams, lzma_vli blocks)
+{
+	// This calculates an upper bound that is only a little bit
+	// bigger than the exact maximum memory usage with the given
+	// parameters.
+
+	// Typical malloc() overhead is 2 * sizeof(void *) but we take
+	// a little bit extra just in case. Using LZMA_MEMUSAGE_BASE
+	// instead would give too inaccurate estimate.
+	const size_t alloc_overhead = 4 * sizeof(void *);
+
+	// Amount of memory needed for each Stream base structures.
+	// We assume that every Stream has at least one Block and
+	// thus at least one group.
+	const size_t stream_base = sizeof(index_stream)
+			+ sizeof(index_group) + 2 * alloc_overhead;
+
+	// Amount of memory needed per group.
+	const size_t group_base = sizeof(index_group)
+			+ INDEX_GROUP_SIZE * sizeof(index_record)
+			+ alloc_overhead;
+
+	// Number of groups. There may actually be more, but that overhead
+	// has been taken into account in stream_base already.
+	const lzma_vli groups
+			= (blocks + INDEX_GROUP_SIZE - 1) / INDEX_GROUP_SIZE;
+
+	// Memory used by index_stream and index_group structures.
+	const uint64_t streams_mem = streams * stream_base;
+	const uint64_t groups_mem = groups * group_base;
+
+	// Memory used by the base structure.
+	const uint64_t index_base = sizeof(lzma_index) + alloc_overhead;
+
+	// Validate the arguments and catch integer overflows.
+	// Maximum number of Streams is "only" UINT32_MAX, because
+	// that limit is used by the tree containing the Streams.
+	const uint64_t limit = UINT64_MAX - index_base;
+	if (streams == 0 || streams > UINT32_MAX || blocks > LZMA_VLI_MAX
+			|| streams > limit / stream_base
+			|| groups > limit / group_base
+			|| limit - streams_mem < groups_mem)
+		return UINT64_MAX;
+
+	return index_base + streams_mem + groups_mem;
+}
+
+
+extern LZMA_API(uint64_t)
+lzma_index_memused(const lzma_index *i)
+{
+	return lzma_index_memusage(i->streams.count, i->record_count);
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_block_count(const lzma_index *i)
+{
+	return i->record_count;
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_stream_count(const lzma_index *i)
+{
+	return i->streams.count;
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_size(const lzma_index *i)
+{
+	return index_size(i->record_count, i->index_list_size);
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_total_size(const lzma_index *i)
+{
+	return i->total_size;
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_stream_size(const lzma_index *i)
+{
+	// Stream Header + Blocks + Index + Stream Footer
+	return LZMA_STREAM_HEADER_SIZE + i->total_size
+			+ index_size(i->record_count, i->index_list_size)
+			+ LZMA_STREAM_HEADER_SIZE;
+}
+
+
+static lzma_vli
+index_file_size(lzma_vli compressed_base, lzma_vli unpadded_sum,
+		lzma_vli record_count, lzma_vli index_list_size,
+		lzma_vli stream_padding)
+{
+	// Earlier Streams and Stream Paddings + Stream Header
+	// + Blocks + Index + Stream Footer + Stream Padding
+	//
+	// This might go over LZMA_VLI_MAX due to too big unpadded_sum
+	// when this function is used in lzma_index_append().
+	lzma_vli file_size = compressed_base + 2 * LZMA_STREAM_HEADER_SIZE
+			+ stream_padding + vli_ceil4(unpadded_sum);
+	if (file_size > LZMA_VLI_MAX)
+		return LZMA_VLI_UNKNOWN;
+
+	// The same applies here.
+	file_size += index_size(record_count, index_list_size);
+	if (file_size > LZMA_VLI_MAX)
+		return LZMA_VLI_UNKNOWN;
+
+	return file_size;
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_file_size(const lzma_index *i)
+{
+	const index_stream *s = (const index_stream *)(i->streams.rightmost);
+	const index_group *g = (const index_group *)(s->groups.rightmost);
+	return index_file_size(s->node.compressed_base,
+			g == NULL ? 0 : g->records[g->last].unpadded_sum,
+			s->record_count, s->index_list_size,
+			s->stream_padding);
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_uncompressed_size(const lzma_index *i)
+{
+	return i->uncompressed_size;
+}
+
+
+extern LZMA_API(uint32_t)
+lzma_index_checks(const lzma_index *i)
+{
+	uint32_t checks = i->checks;
+
+	// Get the type of the Check of the last Stream too.
+	const index_stream *s = (const index_stream *)(i->streams.rightmost);
+	if (s->stream_flags.version != UINT32_MAX)
+		checks |= UINT32_C(1) << s->stream_flags.check;
+
+	return checks;
+}
+
+
+extern uint32_t
+lzma_index_padding_size(const lzma_index *i)
+{
+	return (LZMA_VLI_C(4) - index_size_unpadded(
+			i->record_count, i->index_list_size)) & 3;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_stream_flags(lzma_index *i, const lzma_stream_flags *stream_flags)
+{
+	if (i == NULL || stream_flags == NULL)
+		return LZMA_PROG_ERROR;
+
+	// Validate the Stream Flags.
+	return_if_error(lzma_stream_flags_compare(
+			stream_flags, stream_flags));
+
+	index_stream *s = (index_stream *)(i->streams.rightmost);
+	s->stream_flags = *stream_flags;
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_stream_padding(lzma_index *i, lzma_vli stream_padding)
+{
+	if (i == NULL || stream_padding > LZMA_VLI_MAX
+			|| (stream_padding & 3) != 0)
+		return LZMA_PROG_ERROR;
+
+	index_stream *s = (index_stream *)(i->streams.rightmost);
+
+	// Check that the new value won't make the file grow too big.
+	const lzma_vli old_stream_padding = s->stream_padding;
+	s->stream_padding = 0;
+	if (lzma_index_file_size(i) + stream_padding > LZMA_VLI_MAX) {
+		s->stream_padding = old_stream_padding;
+		return LZMA_DATA_ERROR;
+	}
+
+	s->stream_padding = stream_padding;
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_append(lzma_index *i, const lzma_allocator *allocator,
+		lzma_vli unpadded_size, lzma_vli uncompressed_size)
+{
+	// Validate.
+	if (i == NULL || unpadded_size < UNPADDED_SIZE_MIN
+			|| unpadded_size > UNPADDED_SIZE_MAX
+			|| uncompressed_size > LZMA_VLI_MAX)
+		return LZMA_PROG_ERROR;
+
+	index_stream *s = (index_stream *)(i->streams.rightmost);
+	index_group *g = (index_group *)(s->groups.rightmost);
+
+	const lzma_vli compressed_base = g == NULL ? 0
+			: vli_ceil4(g->records[g->last].unpadded_sum);
+	const lzma_vli uncompressed_base = g == NULL ? 0
+			: g->records[g->last].uncompressed_sum;
+	const uint32_t index_list_size_add = lzma_vli_size(unpadded_size)
+			+ lzma_vli_size(uncompressed_size);
+
+	// Check that uncompressed size will not overflow.
+	if (uncompressed_base + uncompressed_size > LZMA_VLI_MAX)
+		return LZMA_DATA_ERROR;
+
+	// Check that the new unpadded sum will not overflow. This is
+	// checked again in index_file_size(), but the unpadded sum is
+	// passed to vli_ceil4() which expects a valid lzma_vli value.
+	if (compressed_base + unpadded_size > UNPADDED_SIZE_MAX)
+		return LZMA_DATA_ERROR;
+
+	// Check that the file size will stay within limits.
+	if (index_file_size(s->node.compressed_base,
+			compressed_base + unpadded_size, s->record_count + 1,
+			s->index_list_size + index_list_size_add,
+			s->stream_padding) == LZMA_VLI_UNKNOWN)
+		return LZMA_DATA_ERROR;
+
+	// The size of the Index field must not exceed the maximum value
+	// that can be stored in the Backward Size field.
+	if (index_size(i->record_count + 1,
+			i->index_list_size + index_list_size_add)
+			> LZMA_BACKWARD_SIZE_MAX)
+		return LZMA_DATA_ERROR;
+
+	if (g != NULL && g->last + 1 < g->allocated) {
+		// There is space in the last group at least for one Record.
+		++g->last;
+	} else {
+		// We need to allocate a new group.
+		g = lzma_alloc(sizeof(index_group)
+				+ i->prealloc * sizeof(index_record),
+				allocator);
+		if (g == NULL)
+			return LZMA_MEM_ERROR;
+
+		g->last = 0;
+		g->allocated = i->prealloc;
+
+		// Reset prealloc so that if the application happens to
+		// add new Records, the allocation size will be sane.
+		i->prealloc = INDEX_GROUP_SIZE;
+
+		// Set the start offsets of this group.
+		g->node.uncompressed_base = uncompressed_base;
+		g->node.compressed_base = compressed_base;
+		g->number_base = s->record_count + 1;
+
+		// Add the new group to the Stream.
+		index_tree_append(&s->groups, &g->node);
+	}
+
+	// Add the new Record to the group.
+	g->records[g->last].uncompressed_sum
+			= uncompressed_base + uncompressed_size;
+	g->records[g->last].unpadded_sum
+			= compressed_base + unpadded_size;
+
+	// Update the totals.
+	++s->record_count;
+	s->index_list_size += index_list_size_add;
+
+	i->total_size += vli_ceil4(unpadded_size);
+	i->uncompressed_size += uncompressed_size;
+	++i->record_count;
+	i->index_list_size += index_list_size_add;
+
+	return LZMA_OK;
+}
+
+
+/// Structure to pass info to index_cat_helper()
+typedef struct {
+	/// Uncompressed size of the destination
+	lzma_vli uncompressed_size;
+
+	/// Compressed file size of the destination
+	lzma_vli file_size;
+
+	/// Same as above but for Block numbers
+	lzma_vli block_number_add;
+
+	/// Number of Streams that were in the destination index before we
+	/// started appending new Streams from the source index. This is
+	/// used to fix the Stream numbering.
+	uint32_t stream_number_add;
+
+	/// Destination index' Stream tree
+	index_tree *streams;
+
+} index_cat_info;
+
+
+/// Add the Stream nodes from the source index to dest using recursion.
+/// Simplest iterative traversal of the source tree wouldn't work, because
+/// we update the pointers in nodes when moving them to the destination tree.
+static void
+index_cat_helper(const index_cat_info *info, index_stream *this)
+{
+	index_stream *left = (index_stream *)(this->node.left);
+	index_stream *right = (index_stream *)(this->node.right);
+
+	if (left != NULL)
+		index_cat_helper(info, left);
+
+	this->node.uncompressed_base += info->uncompressed_size;
+	this->node.compressed_base += info->file_size;
+	this->number += info->stream_number_add;
+	this->block_number_base += info->block_number_add;
+	index_tree_append(info->streams, &this->node);
+
+	if (right != NULL)
+		index_cat_helper(info, right);
+
+	return;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_cat(lzma_index *restrict dest, lzma_index *restrict src,
+		const lzma_allocator *allocator)
+{
+	if (dest == NULL || src == NULL)
+		return LZMA_PROG_ERROR;
+
+	const lzma_vli dest_file_size = lzma_index_file_size(dest);
+
+	// Check that we don't exceed the file size limits.
+	if (dest_file_size + lzma_index_file_size(src) > LZMA_VLI_MAX
+			|| dest->uncompressed_size + src->uncompressed_size
+				> LZMA_VLI_MAX)
+		return LZMA_DATA_ERROR;
+
+	// Check that the encoded size of the combined lzma_indexes stays
+	// within limits. In theory, this should be done only if we know
+	// that the user plans to actually combine the Streams and thus
+	// construct a single Index (probably rare). However, exceeding
+	// this limit is quite theoretical, so we do this check always
+	// to simplify things elsewhere.
+	{
+		const lzma_vli dest_size = index_size_unpadded(
+				dest->record_count, dest->index_list_size);
+		const lzma_vli src_size = index_size_unpadded(
+				src->record_count, src->index_list_size);
+		if (vli_ceil4(dest_size + src_size) > LZMA_BACKWARD_SIZE_MAX)
+			return LZMA_DATA_ERROR;
+	}
+
+	// Optimize the last group to minimize memory usage. Allocation has
+	// to be done before modifying dest or src.
+	{
+		index_stream *s = (index_stream *)(dest->streams.rightmost);
+		index_group *g = (index_group *)(s->groups.rightmost);
+		if (g != NULL && g->last + 1 < g->allocated) {
+			assert(g->node.left == NULL);
+			assert(g->node.right == NULL);
+
+			index_group *newg = lzma_alloc(sizeof(index_group)
+					+ (g->last + 1)
+					* sizeof(index_record),
+					allocator);
+			if (newg == NULL)
+				return LZMA_MEM_ERROR;
+
+			newg->node = g->node;
+			newg->allocated = g->last + 1;
+			newg->last = g->last;
+			newg->number_base = g->number_base;
+
+			memcpy(newg->records, g->records, newg->allocated
+					* sizeof(index_record));
+
+			if (g->node.parent != NULL) {
+				assert(g->node.parent->right == &g->node);
+				g->node.parent->right = &newg->node;
+			}
+
+			if (s->groups.leftmost == &g->node) {
+				assert(s->groups.root == &g->node);
+				s->groups.leftmost = &newg->node;
+				s->groups.root = &newg->node;
+			}
+
+			assert(s->groups.rightmost == &g->node);
+			s->groups.rightmost = &newg->node;
+
+			lzma_free(g, allocator);
+
+			// NOTE: newg isn't leaked here because
+			// newg == (void *)&newg->node.
+		}
+	}
+
+	// dest->checks includes the check types of all except the last Stream
+	// in dest. Set the bit for the check type of the last Stream now so
+	// that it won't get lost when Stream(s) from src are appended to dest.
+	dest->checks = lzma_index_checks(dest);
+
+	// Add all the Streams from src to dest. Update the base offsets
+	// of each Stream from src.
+	const index_cat_info info = {
+		.uncompressed_size = dest->uncompressed_size,
+		.file_size = dest_file_size,
+		.stream_number_add = dest->streams.count,
+		.block_number_add = dest->record_count,
+		.streams = &dest->streams,
+	};
+	index_cat_helper(&info, (index_stream *)(src->streams.root));
+
+	// Update info about all the combined Streams.
+	dest->uncompressed_size += src->uncompressed_size;
+	dest->total_size += src->total_size;
+	dest->record_count += src->record_count;
+	dest->index_list_size += src->index_list_size;
+	dest->checks |= src->checks;
+
+	// There's nothing else left in src than the base structure.
+	lzma_free(src, allocator);
+
+	return LZMA_OK;
+}
+
+
+/// Duplicate an index_stream.
+static index_stream *
+index_dup_stream(const index_stream *src, const lzma_allocator *allocator)
+{
+	// Catch a somewhat theoretical integer overflow.
+	if (src->record_count > PREALLOC_MAX)
+		return NULL;
+
+	// Allocate and initialize a new Stream.
+	index_stream *dest = index_stream_init(src->node.compressed_base,
+			src->node.uncompressed_base, src->number,
+			src->block_number_base, allocator);
+	if (dest == NULL)
+		return NULL;
+
+	// Copy the overall information.
+	dest->record_count = src->record_count;
+	dest->index_list_size = src->index_list_size;
+	dest->stream_flags = src->stream_flags;
+	dest->stream_padding = src->stream_padding;
+
+	// Return if there are no groups to duplicate.
+	if (src->groups.leftmost == NULL)
+		return dest;
+
+	// Allocate memory for the Records. We put all the Records into
+	// a single group. It's simplest and also tends to make
+	// lzma_index_locate() a little bit faster with very big Indexes.
+	index_group *destg = lzma_alloc(sizeof(index_group)
+			+ src->record_count * sizeof(index_record),
+			allocator);
+	if (destg == NULL) {
+		index_stream_end(dest, allocator);
+		return NULL;
+	}
+
+	// Initialize destg.
+	destg->node.uncompressed_base = 0;
+	destg->node.compressed_base = 0;
+	destg->number_base = 1;
+	destg->allocated = src->record_count;
+	destg->last = src->record_count - 1;
+
+	// Go through all the groups in src and copy the Records into destg.
+	const index_group *srcg = (const index_group *)(src->groups.leftmost);
+	size_t i = 0;
+	do {
+		memcpy(destg->records + i, srcg->records,
+				(srcg->last + 1) * sizeof(index_record));
+		i += srcg->last + 1;
+		srcg = index_tree_next(&srcg->node);
+	} while (srcg != NULL);
+
+	assert(i == destg->allocated);
+
+	// Add the group to the new Stream.
+	index_tree_append(&dest->groups, &destg->node);
+
+	return dest;
+}
+
+
+extern LZMA_API(lzma_index *)
+lzma_index_dup(const lzma_index *src, const lzma_allocator *allocator)
+{
+	// Allocate the base structure (no initial Stream).
+	lzma_index *dest = index_init_plain(allocator);
+	if (dest == NULL)
+		return NULL;
+
+	// Copy the totals.
+	dest->uncompressed_size = src->uncompressed_size;
+	dest->total_size = src->total_size;
+	dest->record_count = src->record_count;
+	dest->index_list_size = src->index_list_size;
+
+	// Copy the Streams and the groups in them.
+	const index_stream *srcstream
+			= (const index_stream *)(src->streams.leftmost);
+	do {
+		index_stream *deststream = index_dup_stream(
+				srcstream, allocator);
+		if (deststream == NULL) {
+			lzma_index_end(dest, allocator);
+			return NULL;
+		}
+
+		index_tree_append(&dest->streams, &deststream->node);
+
+		srcstream = index_tree_next(&srcstream->node);
+	} while (srcstream != NULL);
+
+	return dest;
+}
+
+
+/// Indexing for lzma_index_iter.internal[]
+enum {
+	ITER_INDEX,
+	ITER_STREAM,
+	ITER_GROUP,
+	ITER_RECORD,
+	ITER_METHOD,
+};
+
+
+/// Values for lzma_index_iter.internal[ITER_METHOD].s
+enum {
+	ITER_METHOD_NORMAL,
+	ITER_METHOD_NEXT,
+	ITER_METHOD_LEFTMOST,
+};
+
+
+static void
+iter_set_info(lzma_index_iter *iter)
+{
+	const lzma_index *i = iter->internal[ITER_INDEX].p;
+	const index_stream *stream = iter->internal[ITER_STREAM].p;
+	const index_group *group = iter->internal[ITER_GROUP].p;
+	const size_t record = iter->internal[ITER_RECORD].s;
+
+	// lzma_index_iter.internal must not contain a pointer to the last
+	// group in the index, because that may be reallocated by
+	// lzma_index_cat().
+	if (group == NULL) {
+		// There are no groups.
+		assert(stream->groups.root == NULL);
+		iter->internal[ITER_METHOD].s = ITER_METHOD_LEFTMOST;
+
+	} else if (i->streams.rightmost != &stream->node
+			|| stream->groups.rightmost != &group->node) {
+		// The group is not not the last group in the index.
+		iter->internal[ITER_METHOD].s = ITER_METHOD_NORMAL;
+
+	} else if (stream->groups.leftmost != &group->node) {
+		// The group isn't the only group in the Stream, thus we
+		// know that it must have a parent group i.e. it's not
+		// the root node.
+		assert(stream->groups.root != &group->node);
+		assert(group->node.parent->right == &group->node);
+		iter->internal[ITER_METHOD].s = ITER_METHOD_NEXT;
+		iter->internal[ITER_GROUP].p = group->node.parent;
+
+	} else {
+		// The Stream has only one group.
+		assert(stream->groups.root == &group->node);
+		assert(group->node.parent == NULL);
+		iter->internal[ITER_METHOD].s = ITER_METHOD_LEFTMOST;
+		iter->internal[ITER_GROUP].p = NULL;
+	}
+
+	// NOTE: lzma_index_iter.stream.number is lzma_vli but we use uint32_t
+	// internally.
+	iter->stream.number = stream->number;
+	iter->stream.block_count = stream->record_count;
+	iter->stream.compressed_offset = stream->node.compressed_base;
+	iter->stream.uncompressed_offset = stream->node.uncompressed_base;
+
+	// iter->stream.flags will be NULL if the Stream Flags haven't been
+	// set with lzma_index_stream_flags().
+	iter->stream.flags = stream->stream_flags.version == UINT32_MAX
+			? NULL : &stream->stream_flags;
+	iter->stream.padding = stream->stream_padding;
+
+	if (stream->groups.rightmost == NULL) {
+		// Stream has no Blocks.
+		iter->stream.compressed_size = index_size(0, 0)
+				+ 2 * LZMA_STREAM_HEADER_SIZE;
+		iter->stream.uncompressed_size = 0;
+	} else {
+		const index_group *g = (const index_group *)(
+				stream->groups.rightmost);
+
+		// Stream Header + Stream Footer + Index + Blocks
+		iter->stream.compressed_size = 2 * LZMA_STREAM_HEADER_SIZE
+				+ index_size(stream->record_count,
+					stream->index_list_size)
+				+ vli_ceil4(g->records[g->last].unpadded_sum);
+		iter->stream.uncompressed_size
+				= g->records[g->last].uncompressed_sum;
+	}
+
+	if (group != NULL) {
+		iter->block.number_in_stream = group->number_base + record;
+		iter->block.number_in_file = iter->block.number_in_stream
+				+ stream->block_number_base;
+
+		iter->block.compressed_stream_offset
+				= record == 0 ? group->node.compressed_base
+				: vli_ceil4(group->records[
+					record - 1].unpadded_sum);
+		iter->block.uncompressed_stream_offset
+				= record == 0 ? group->node.uncompressed_base
+				: group->records[record - 1].uncompressed_sum;
+
+		iter->block.uncompressed_size
+				= group->records[record].uncompressed_sum
+				- iter->block.uncompressed_stream_offset;
+		iter->block.unpadded_size
+				= group->records[record].unpadded_sum
+				- iter->block.compressed_stream_offset;
+		iter->block.total_size = vli_ceil4(iter->block.unpadded_size);
+
+		iter->block.compressed_stream_offset
+				+= LZMA_STREAM_HEADER_SIZE;
+
+		iter->block.compressed_file_offset
+				= iter->block.compressed_stream_offset
+				+ iter->stream.compressed_offset;
+		iter->block.uncompressed_file_offset
+				= iter->block.uncompressed_stream_offset
+				+ iter->stream.uncompressed_offset;
+	}
+
+	return;
+}
+
+
+extern LZMA_API(void)
+lzma_index_iter_init(lzma_index_iter *iter, const lzma_index *i)
+{
+	iter->internal[ITER_INDEX].p = i;
+	lzma_index_iter_rewind(iter);
+	return;
+}
+
+
+extern LZMA_API(void)
+lzma_index_iter_rewind(lzma_index_iter *iter)
+{
+	iter->internal[ITER_STREAM].p = NULL;
+	iter->internal[ITER_GROUP].p = NULL;
+	iter->internal[ITER_RECORD].s = 0;
+	iter->internal[ITER_METHOD].s = ITER_METHOD_NORMAL;
+	return;
+}
+
+
+extern LZMA_API(lzma_bool)
+lzma_index_iter_next(lzma_index_iter *iter, lzma_index_iter_mode mode)
+{
+	// Catch unsupported mode values.
+	if ((unsigned int)(mode) > LZMA_INDEX_ITER_NONEMPTY_BLOCK)
+		return true;
+
+	const lzma_index *i = iter->internal[ITER_INDEX].p;
+	const index_stream *stream = iter->internal[ITER_STREAM].p;
+	const index_group *group = NULL;
+	size_t record = iter->internal[ITER_RECORD].s;
+
+	// If we are being asked for the next Stream, leave group to NULL
+	// so that the rest of the this function thinks that this Stream
+	// has no groups and will thus go to the next Stream.
+	if (mode != LZMA_INDEX_ITER_STREAM) {
+		// Get the pointer to the current group. See iter_set_inf()
+		// for explanation.
+		switch (iter->internal[ITER_METHOD].s) {
+		case ITER_METHOD_NORMAL:
+			group = iter->internal[ITER_GROUP].p;
+			break;
+
+		case ITER_METHOD_NEXT:
+			group = index_tree_next(iter->internal[ITER_GROUP].p);
+			break;
+
+		case ITER_METHOD_LEFTMOST:
+			group = (const index_group *)(
+					stream->groups.leftmost);
+			break;
+		}
+	}
+
+again:
+	if (stream == NULL) {
+		// We at the beginning of the lzma_index.
+		// Locate the first Stream.
+		stream = (const index_stream *)(i->streams.leftmost);
+		if (mode >= LZMA_INDEX_ITER_BLOCK) {
+			// Since we are being asked to return information
+			// about the first a Block, skip Streams that have
+			// no Blocks.
+			while (stream->groups.leftmost == NULL) {
+				stream = index_tree_next(&stream->node);
+				if (stream == NULL)
+					return true;
+			}
+		}
+
+		// Start from the first Record in the Stream.
+		group = (const index_group *)(stream->groups.leftmost);
+		record = 0;
+
+	} else if (group != NULL && record < group->last) {
+		// The next Record is in the same group.
+		++record;
+
+	} else {
+		// This group has no more Records or this Stream has
+		// no Blocks at all.
+		record = 0;
+
+		// If group is not NULL, this Stream has at least one Block
+		// and thus at least one group. Find the next group.
+		if (group != NULL)
+			group = index_tree_next(&group->node);
+
+		if (group == NULL) {
+			// This Stream has no more Records. Find the next
+			// Stream. If we are being asked to return information
+			// about a Block, we skip empty Streams.
+			do {
+				stream = index_tree_next(&stream->node);
+				if (stream == NULL)
+					return true;
+			} while (mode >= LZMA_INDEX_ITER_BLOCK
+					&& stream->groups.leftmost == NULL);
+
+			group = (const index_group *)(
+					stream->groups.leftmost);
+		}
+	}
+
+	if (mode == LZMA_INDEX_ITER_NONEMPTY_BLOCK) {
+		// We need to look for the next Block again if this Block
+		// is empty.
+		if (record == 0) {
+			if (group->node.uncompressed_base
+					== group->records[0].uncompressed_sum)
+				goto again;
+		} else if (group->records[record - 1].uncompressed_sum
+				== group->records[record].uncompressed_sum) {
+			goto again;
+		}
+	}
+
+	iter->internal[ITER_STREAM].p = stream;
+	iter->internal[ITER_GROUP].p = group;
+	iter->internal[ITER_RECORD].s = record;
+
+	iter_set_info(iter);
+
+	return false;
+}
+
+
+extern LZMA_API(lzma_bool)
+lzma_index_iter_locate(lzma_index_iter *iter, lzma_vli target)
+{
+	const lzma_index *i = iter->internal[ITER_INDEX].p;
+
+	// If the target is past the end of the file, return immediately.
+	if (i->uncompressed_size <= target)
+		return true;
+
+	// Locate the Stream containing the target offset.
+	const index_stream *stream = index_tree_locate(&i->streams, target);
+	assert(stream != NULL);
+	target -= stream->node.uncompressed_base;
+
+	// Locate the group containing the target offset.
+	const index_group *group = index_tree_locate(&stream->groups, target);
+	assert(group != NULL);
+
+	// Use binary search to locate the exact Record. It is the first
+	// Record whose uncompressed_sum is greater than target.
+	// This is because we want the rightmost Record that fulfills the
+	// search criterion. It is possible that there are empty Blocks;
+	// we don't want to return them.
+	size_t left = 0;
+	size_t right = group->last;
+
+	while (left < right) {
+		const size_t pos = left + (right - left) / 2;
+		if (group->records[pos].uncompressed_sum <= target)
+			left = pos + 1;
+		else
+			right = pos;
+	}
+
+	iter->internal[ITER_STREAM].p = stream;
+	iter->internal[ITER_GROUP].p = group;
+	iter->internal[ITER_RECORD].s = left;
+
+	iter_set_info(iter);
+
+	return false;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.h
new file mode 100644
index 00000000000..007e1188f25
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index.h
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       index.h
+/// \brief      Handling of Index
+/// \note       This header file does not include common.h or lzma.h because
+///             this file is needed by both liblzma internally and by the
+///             tests. Including common.h will include and define many things
+///             the tests do not need and prevents issues with header file
+///             include order. This way, if lzma.h or common.h are not
+///             included before this file it will break on every OS instead
+///             of causing more subtle errors.
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_INDEX_H
+#define LZMA_INDEX_H
+
+
+/// Minimum Unpadded Size
+#define UNPADDED_SIZE_MIN LZMA_VLI_C(5)
+
+/// Maximum Unpadded Size
+#define UNPADDED_SIZE_MAX (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
+
+/// Index Indicator based on xz specification
+#define INDEX_INDICATOR 0
+
+
+/// Get the size of the Index Padding field. This is needed by Index encoder
+/// and decoder, but applications should have no use for this.
+extern uint32_t lzma_index_padding_size(const lzma_index *i);
+
+
+/// Set for how many Records to allocate memory the next time
+/// lzma_index_append() needs to allocate space for a new Record.
+/// This is used only by the Index decoder.
+extern void lzma_index_prealloc(lzma_index *i, lzma_vli records);
+
+
+/// Round the variable-length integer to the next multiple of four.
+static inline lzma_vli
+vli_ceil4(lzma_vli vli)
+{
+	assert(vli <= UNPADDED_SIZE_MAX);
+	return (vli + 3) & ~LZMA_VLI_C(3);
+}
+
+
+/// Calculate the size of the Index field excluding Index Padding
+static inline lzma_vli
+index_size_unpadded(lzma_vli count, lzma_vli index_list_size)
+{
+	// Index Indicator + Number of Records + List of Records + CRC32
+	return 1 + lzma_vli_size(count) + index_list_size + 4;
+}
+
+
+/// Calculate the size of the Index field including Index Padding
+static inline lzma_vli
+index_size(lzma_vli count, lzma_vli index_list_size)
+{
+	return vli_ceil4(index_size_unpadded(count, index_list_size));
+}
+
+
+/// Calculate the total size of the Stream
+static inline lzma_vli
+index_stream_size(lzma_vli blocks_size,
+		lzma_vli count, lzma_vli index_list_size)
+{
+	return LZMA_STREAM_HEADER_SIZE + blocks_size
+			+ index_size(count, index_list_size)
+			+ LZMA_STREAM_HEADER_SIZE;
+}
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.c
new file mode 100644
index 00000000000..4bcb3069211
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.c
@@ -0,0 +1,372 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       index_decoder.c
+/// \brief      Decodes the Index field
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "index_decoder.h"
+#include "check.h"
+
+
+typedef struct {
+	enum {
+		SEQ_INDICATOR,
+		SEQ_COUNT,
+		SEQ_MEMUSAGE,
+		SEQ_UNPADDED,
+		SEQ_UNCOMPRESSED,
+		SEQ_PADDING_INIT,
+		SEQ_PADDING,
+		SEQ_CRC32,
+	} sequence;
+
+	/// Memory usage limit
+	uint64_t memlimit;
+
+	/// Target Index
+	lzma_index *index;
+
+	/// Pointer give by the application, which is set after
+	/// successful decoding.
+	lzma_index **index_ptr;
+
+	/// Number of Records left to decode.
+	lzma_vli count;
+
+	/// The most recent Unpadded Size field
+	lzma_vli unpadded_size;
+
+	/// The most recent Uncompressed Size field
+	lzma_vli uncompressed_size;
+
+	/// Position in integers
+	size_t pos;
+
+	/// CRC32 of the List of Records field
+	uint32_t crc32;
+} lzma_index_coder;
+
+
+static lzma_ret
+index_decode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size,
+		uint8_t *restrict out lzma_attribute((__unused__)),
+		size_t *restrict out_pos lzma_attribute((__unused__)),
+		size_t out_size lzma_attribute((__unused__)),
+		lzma_action action lzma_attribute((__unused__)))
+{
+	lzma_index_coder *coder = coder_ptr;
+
+	// Similar optimization as in index_encoder.c
+	const size_t in_start = *in_pos;
+	lzma_ret ret = LZMA_OK;
+
+	while (*in_pos < in_size)
+	switch (coder->sequence) {
+	case SEQ_INDICATOR:
+		// Return LZMA_DATA_ERROR instead of e.g. LZMA_PROG_ERROR or
+		// LZMA_FORMAT_ERROR, because a typical usage case for Index
+		// decoder is when parsing the Stream backwards. If seeking
+		// backward from the Stream Footer gives us something that
+		// doesn't begin with Index Indicator, the file is considered
+		// corrupt, not "programming error" or "unrecognized file
+		// format". One could argue that the application should
+		// verify the Index Indicator before trying to decode the
+		// Index, but well, I suppose it is simpler this way.
+		if (in[(*in_pos)++] != INDEX_INDICATOR)
+			return LZMA_DATA_ERROR;
+
+		coder->sequence = SEQ_COUNT;
+		break;
+
+	case SEQ_COUNT:
+		ret = lzma_vli_decode(&coder->count, &coder->pos,
+				in, in_pos, in_size);
+		if (ret != LZMA_STREAM_END)
+			goto out;
+
+		coder->pos = 0;
+		coder->sequence = SEQ_MEMUSAGE;
+
+	// Fall through
+
+	case SEQ_MEMUSAGE:
+		if (lzma_index_memusage(1, coder->count) > coder->memlimit) {
+			ret = LZMA_MEMLIMIT_ERROR;
+			goto out;
+		}
+
+		// Tell the Index handling code how many Records this
+		// Index has to allow it to allocate memory more efficiently.
+		lzma_index_prealloc(coder->index, coder->count);
+
+		ret = LZMA_OK;
+		coder->sequence = coder->count == 0
+				? SEQ_PADDING_INIT : SEQ_UNPADDED;
+		break;
+
+	case SEQ_UNPADDED:
+	case SEQ_UNCOMPRESSED: {
+		lzma_vli *size = coder->sequence == SEQ_UNPADDED
+				? &coder->unpadded_size
+				: &coder->uncompressed_size;
+
+		ret = lzma_vli_decode(size, &coder->pos,
+				in, in_pos, in_size);
+		if (ret != LZMA_STREAM_END)
+			goto out;
+
+		ret = LZMA_OK;
+		coder->pos = 0;
+
+		if (coder->sequence == SEQ_UNPADDED) {
+			// Validate that encoded Unpadded Size isn't too small
+			// or too big.
+			if (coder->unpadded_size < UNPADDED_SIZE_MIN
+					|| coder->unpadded_size
+						> UNPADDED_SIZE_MAX)
+				return LZMA_DATA_ERROR;
+
+			coder->sequence = SEQ_UNCOMPRESSED;
+		} else {
+			// Add the decoded Record to the Index.
+			return_if_error(lzma_index_append(
+					coder->index, allocator,
+					coder->unpadded_size,
+					coder->uncompressed_size));
+
+			// Check if this was the last Record.
+			coder->sequence = --coder->count == 0
+					? SEQ_PADDING_INIT
+					: SEQ_UNPADDED;
+		}
+
+		break;
+	}
+
+	case SEQ_PADDING_INIT:
+		coder->pos = lzma_index_padding_size(coder->index);
+		coder->sequence = SEQ_PADDING;
+
+	// Fall through
+
+	case SEQ_PADDING:
+		if (coder->pos > 0) {
+			--coder->pos;
+			if (in[(*in_pos)++] != 0x00)
+				return LZMA_DATA_ERROR;
+
+			break;
+		}
+
+		// Finish the CRC32 calculation.
+		coder->crc32 = lzma_crc32(in + in_start,
+				*in_pos - in_start, coder->crc32);
+
+		coder->sequence = SEQ_CRC32;
+
+	// Fall through
+
+	case SEQ_CRC32:
+		do {
+			if (*in_pos == in_size)
+				return LZMA_OK;
+
+			if (((coder->crc32 >> (coder->pos * 8)) & 0xFF)
+					!= in[(*in_pos)++]) {
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+				return LZMA_DATA_ERROR;
+#endif
+			}
+
+		} while (++coder->pos < 4);
+
+		// Decoding was successful, now we can let the application
+		// see the decoded Index.
+		*coder->index_ptr = coder->index;
+
+		// Make index NULL so we don't free it unintentionally.
+		coder->index = NULL;
+
+		return LZMA_STREAM_END;
+
+	default:
+		assert(0);
+		return LZMA_PROG_ERROR;
+	}
+
+out:
+	// Update the CRC32.
+	//
+	// Avoid null pointer + 0 (undefined behavior) in "in + in_start".
+	// In such a case we had no input and thus in_used == 0.
+	{
+		const size_t in_used = *in_pos - in_start;
+		if (in_used > 0)
+			coder->crc32 = lzma_crc32(in + in_start,
+					in_used, coder->crc32);
+	}
+
+	return ret;
+}
+
+
+static void
+index_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_index_coder *coder = coder_ptr;
+	lzma_index_end(coder->index, allocator);
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_ret
+index_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
+		uint64_t *old_memlimit, uint64_t new_memlimit)
+{
+	lzma_index_coder *coder = coder_ptr;
+
+	*memusage = lzma_index_memusage(1, coder->count);
+	*old_memlimit = coder->memlimit;
+
+	if (new_memlimit != 0) {
+		if (new_memlimit < *memusage)
+			return LZMA_MEMLIMIT_ERROR;
+
+		coder->memlimit = new_memlimit;
+	}
+
+	return LZMA_OK;
+}
+
+
+static lzma_ret
+index_decoder_reset(lzma_index_coder *coder, const lzma_allocator *allocator,
+		lzma_index **i, uint64_t memlimit)
+{
+	// Remember the pointer given by the application. We will set it
+	// to point to the decoded Index only if decoding is successful.
+	// Before that, keep it NULL so that applications can always safely
+	// pass it to lzma_index_end() no matter did decoding succeed or not.
+	coder->index_ptr = i;
+	*i = NULL;
+
+	// We always allocate a new lzma_index.
+	coder->index = lzma_index_init(allocator);
+	if (coder->index == NULL)
+		return LZMA_MEM_ERROR;
+
+	// Initialize the rest.
+	coder->sequence = SEQ_INDICATOR;
+	coder->memlimit = my_max(1, memlimit);
+	coder->count = 0; // Needs to be initialized due to _memconfig().
+	coder->pos = 0;
+	coder->crc32 = 0;
+
+	return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_index_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		lzma_index **i, uint64_t memlimit)
+{
+	lzma_next_coder_init(&lzma_index_decoder_init, next, allocator);
+
+	if (i == NULL)
+		return LZMA_PROG_ERROR;
+
+	lzma_index_coder *coder = next->coder;
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_index_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+		next->code = &index_decode;
+		next->end = &index_decoder_end;
+		next->memconfig = &index_decoder_memconfig;
+		coder->index = NULL;
+	} else {
+		lzma_index_end(coder->index, allocator);
+	}
+
+	return index_decoder_reset(coder, allocator, i, memlimit);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_decoder(lzma_stream *strm, lzma_index **i, uint64_t memlimit)
+{
+	// If i isn't NULL, *i must always be initialized due to
+	// the wording in the API docs. This way it is initialized
+	// if we return LZMA_PROG_ERROR due to strm == NULL.
+	if (i != NULL)
+		*i = NULL;
+
+	lzma_next_strm_init(lzma_index_decoder_init, strm, i, memlimit);
+
+	strm->internal->supported_actions[LZMA_RUN] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_buffer_decode(lzma_index **i, uint64_t *memlimit,
+		const lzma_allocator *allocator,
+		const uint8_t *in, size_t *in_pos, size_t in_size)
+{
+	// If i isn't NULL, *i must always be initialized due to
+	// the wording in the API docs.
+	if (i != NULL)
+		*i = NULL;
+
+	// Sanity checks
+	if (i == NULL || memlimit == NULL
+			|| in == NULL || in_pos == NULL || *in_pos > in_size)
+		return LZMA_PROG_ERROR;
+
+	// Initialize the decoder.
+	lzma_index_coder coder;
+	return_if_error(index_decoder_reset(&coder, allocator, i, *memlimit));
+
+	// Store the input start position so that we can restore it in case
+	// of an error.
+	const size_t in_start = *in_pos;
+
+	// Do the actual decoding.
+	lzma_ret ret = index_decode(&coder, allocator, in, in_pos, in_size,
+			NULL, NULL, 0, LZMA_RUN);
+
+	if (ret == LZMA_STREAM_END) {
+		ret = LZMA_OK;
+	} else {
+		// Something went wrong, free the Index structure and restore
+		// the input position.
+		lzma_index_end(coder.index, allocator);
+		*in_pos = in_start;
+
+		if (ret == LZMA_OK) {
+			// The input is truncated or otherwise corrupt.
+			// Use LZMA_DATA_ERROR instead of LZMA_BUF_ERROR
+			// like lzma_vli_decode() does in single-call mode.
+			ret = LZMA_DATA_ERROR;
+
+		} else if (ret == LZMA_MEMLIMIT_ERROR) {
+			// Tell the caller how much memory would have
+			// been needed.
+			*memlimit = lzma_index_memusage(1, coder.count);
+		}
+	}
+
+	return ret;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.h
new file mode 100644
index 00000000000..5351d2f0dfa
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_decoder.h
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       index_decoder.h
+/// \brief      Decodes the Index field
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_INDEX_DECODER_H
+#define LZMA_INDEX_DECODER_H
+
+#include "common.h"
+#include "index.h"
+
+
+extern lzma_ret lzma_index_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		lzma_index **i, uint64_t memlimit);
+
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.c
new file mode 100644
index 00000000000..ecc299c0159
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.c
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       index_encoder.c
+/// \brief      Encodes the Index field
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "index_encoder.h"
+#include "index.h"
+#include "check.h"
+
+
+typedef struct {
+	enum {
+		SEQ_INDICATOR,
+		SEQ_COUNT,
+		SEQ_UNPADDED,
+		SEQ_UNCOMPRESSED,
+		SEQ_NEXT,
+		SEQ_PADDING,
+		SEQ_CRC32,
+	} sequence;
+
+	/// Index being encoded
+	const lzma_index *index;
+
+	/// Iterator for the Index being encoded
+	lzma_index_iter iter;
+
+	/// Position in integers
+	size_t pos;
+
+	/// CRC32 of the List of Records field
+	uint32_t crc32;
+} lzma_index_coder;
+
+
+static lzma_ret
+index_encode(void *coder_ptr,
+		const lzma_allocator *allocator lzma_attribute((__unused__)),
+		const uint8_t *restrict in lzma_attribute((__unused__)),
+		size_t *restrict in_pos lzma_attribute((__unused__)),
+		size_t in_size lzma_attribute((__unused__)),
+		uint8_t *restrict out, size_t *restrict out_pos,
+		size_t out_size,
+		lzma_action action lzma_attribute((__unused__)))
+{
+	lzma_index_coder *coder = coder_ptr;
+
+	// Position where to start calculating CRC32. The idea is that we
+	// need to call lzma_crc32() only once per call to index_encode().
+	const size_t out_start = *out_pos;
+
+	// Return value to use if we return at the end of this function.
+	// We use "goto out" to jump out of the while-switch construct
+	// instead of returning directly, because that way we don't need
+	// to copypaste the lzma_crc32() call to many places.
+	lzma_ret ret = LZMA_OK;
+
+	while (*out_pos < out_size)
+	switch (coder->sequence) {
+	case SEQ_INDICATOR:
+		out[*out_pos] = INDEX_INDICATOR;
+		++*out_pos;
+		coder->sequence = SEQ_COUNT;
+		break;
+
+	case SEQ_COUNT: {
+		const lzma_vli count = lzma_index_block_count(coder->index);
+		ret = lzma_vli_encode(count, &coder->pos,
+				out, out_pos, out_size);
+		if (ret != LZMA_STREAM_END)
+			goto out;
+
+		ret = LZMA_OK;
+		coder->pos = 0;
+		coder->sequence = SEQ_NEXT;
+		break;
+	}
+
+	case SEQ_NEXT:
+		if (lzma_index_iter_next(
+				&coder->iter, LZMA_INDEX_ITER_BLOCK)) {
+			// Get the size of the Index Padding field.
+			coder->pos = lzma_index_padding_size(coder->index);
+			assert(coder->pos <= 3);
+			coder->sequence = SEQ_PADDING;
+			break;
+		}
+
+		coder->sequence = SEQ_UNPADDED;
+
+	// Fall through
+
+	case SEQ_UNPADDED:
+	case SEQ_UNCOMPRESSED: {
+		const lzma_vli size = coder->sequence == SEQ_UNPADDED
+				? coder->iter.block.unpadded_size
+				: coder->iter.block.uncompressed_size;
+
+		ret = lzma_vli_encode(size, &coder->pos,
+				out, out_pos, out_size);
+		if (ret != LZMA_STREAM_END)
+			goto out;
+
+		ret = LZMA_OK;
+		coder->pos = 0;
+
+		// Advance to SEQ_UNCOMPRESSED or SEQ_NEXT.
+		++coder->sequence;
+		break;
+	}
+
+	case SEQ_PADDING:
+		if (coder->pos > 0) {
+			--coder->pos;
+			out[(*out_pos)++] = 0x00;
+			break;
+		}
+
+		// Finish the CRC32 calculation.
+		coder->crc32 = lzma_crc32(out + out_start,
+				*out_pos - out_start, coder->crc32);
+
+		coder->sequence = SEQ_CRC32;
+
+	// Fall through
+
+	case SEQ_CRC32:
+		// We don't use the main loop, because we don't want
+		// coder->crc32 to be touched anymore.
+		do {
+			if (*out_pos == out_size)
+				return LZMA_OK;
+
+			out[*out_pos] = (coder->crc32 >> (coder->pos * 8))
+					& 0xFF;
+			++*out_pos;
+
+		} while (++coder->pos < 4);
+
+		return LZMA_STREAM_END;
+
+	default:
+		assert(0);
+		return LZMA_PROG_ERROR;
+	}
+
+out:
+	// Update the CRC32.
+	//
+	// Avoid null pointer + 0 (undefined behavior) in "out + out_start".
+	// In such a case we had no input and thus out_used == 0.
+	{
+		const size_t out_used = *out_pos - out_start;
+		if (out_used > 0)
+			coder->crc32 = lzma_crc32(out + out_start,
+					out_used, coder->crc32);
+	}
+
+	return ret;
+}
+
+
+static void
+index_encoder_end(void *coder, const lzma_allocator *allocator)
+{
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static void
+index_encoder_reset(lzma_index_coder *coder, const lzma_index *i)
+{
+	lzma_index_iter_init(&coder->iter, i);
+
+	coder->sequence = SEQ_INDICATOR;
+	coder->index = i;
+	coder->pos = 0;
+	coder->crc32 = 0;
+
+	return;
+}
+
+
+extern lzma_ret
+lzma_index_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_index *i)
+{
+	lzma_next_coder_init(&lzma_index_encoder_init, next, allocator);
+
+	if (i == NULL)
+		return LZMA_PROG_ERROR;
+
+	if (next->coder == NULL) {
+		next->coder = lzma_alloc(sizeof(lzma_index_coder), allocator);
+		if (next->coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->code = &index_encode;
+		next->end = &index_encoder_end;
+	}
+
+	index_encoder_reset(next->coder, i);
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_encoder(lzma_stream *strm, const lzma_index *i)
+{
+	lzma_next_strm_init(lzma_index_encoder_init, strm, i);
+
+	strm->internal->supported_actions[LZMA_RUN] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_buffer_encode(const lzma_index *i,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+{
+	// Validate the arguments.
+	if (i == NULL || out == NULL || out_pos == NULL || *out_pos > out_size)
+		return LZMA_PROG_ERROR;
+
+	// Don't try to encode if there's not enough output space.
+	if (out_size - *out_pos < lzma_index_size(i))
+		return LZMA_BUF_ERROR;
+
+	// The Index encoder needs just one small data structure so we can
+	// allocate it on stack.
+	lzma_index_coder coder;
+	index_encoder_reset(&coder, i);
+
+	// Do the actual encoding. This should never fail, but store
+	// the original *out_pos just in case.
+	const size_t out_start = *out_pos;
+	lzma_ret ret = index_encode(&coder, NULL, NULL, NULL, 0,
+			out, out_pos, out_size, LZMA_RUN);
+
+	if (ret == LZMA_STREAM_END) {
+		ret = LZMA_OK;
+	} else {
+		// We should never get here, but just in case, restore the
+		// output position and set the error accordingly if something
+		// goes wrong and debugging isn't enabled.
+		assert(0);
+		*out_pos = out_start;
+		ret = LZMA_PROG_ERROR;
+	}
+
+	return ret;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.h
new file mode 100644
index 00000000000..29ba1106696
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_encoder.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       index_encoder.h
+/// \brief      Encodes the Index field
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_INDEX_ENCODER_H
+#define LZMA_INDEX_ENCODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_index_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator, const lzma_index *i);
+
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_hash.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_hash.c
new file mode 100644
index 00000000000..caa5967ca49
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/index_hash.c
@@ -0,0 +1,342 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       index_hash.c
+/// \brief      Validates Index by using a hash function
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+#include "index.h"
+#include "check.h"
+
+
+typedef struct {
+	/// Sum of the Block sizes (including Block Padding)
+	lzma_vli blocks_size;
+
+	/// Sum of the Uncompressed Size fields
+	lzma_vli uncompressed_size;
+
+	/// Number of Records
+	lzma_vli count;
+
+	/// Size of the List of Index Records as bytes
+	lzma_vli index_list_size;
+
+	/// Check calculated from Unpadded Sizes and Uncompressed Sizes.
+	lzma_check_state check;
+
+} lzma_index_hash_info;
+
+
+struct lzma_index_hash_s {
+	enum {
+		SEQ_BLOCK,
+		SEQ_COUNT,
+		SEQ_UNPADDED,
+		SEQ_UNCOMPRESSED,
+		SEQ_PADDING_INIT,
+		SEQ_PADDING,
+		SEQ_CRC32,
+	} sequence;
+
+	/// Information collected while decoding the actual Blocks.
+	lzma_index_hash_info blocks;
+
+	/// Information collected from the Index field.
+	lzma_index_hash_info records;
+
+	/// Number of Records not fully decoded
+	lzma_vli remaining;
+
+	/// Unpadded Size currently being read from an Index Record.
+	lzma_vli unpadded_size;
+
+	/// Uncompressed Size currently being read from an Index Record.
+	lzma_vli uncompressed_size;
+
+	/// Position in variable-length integers when decoding them from
+	/// the List of Records.
+	size_t pos;
+
+	/// CRC32 of the Index
+	uint32_t crc32;
+};
+
+
+extern LZMA_API(lzma_index_hash *)
+lzma_index_hash_init(lzma_index_hash *index_hash,
+		const lzma_allocator *allocator)
+{
+	if (index_hash == NULL) {
+		index_hash = lzma_alloc(sizeof(lzma_index_hash), allocator);
+		if (index_hash == NULL)
+			return NULL;
+	}
+
+	index_hash->sequence = SEQ_BLOCK;
+	index_hash->blocks.blocks_size = 0;
+	index_hash->blocks.uncompressed_size = 0;
+	index_hash->blocks.count = 0;
+	index_hash->blocks.index_list_size = 0;
+	index_hash->records.blocks_size = 0;
+	index_hash->records.uncompressed_size = 0;
+	index_hash->records.count = 0;
+	index_hash->records.index_list_size = 0;
+	index_hash->unpadded_size = 0;
+	index_hash->uncompressed_size = 0;
+	index_hash->pos = 0;
+	index_hash->crc32 = 0;
+
+	// These cannot fail because LZMA_CHECK_BEST is known to be supported.
+	(void)lzma_check_init(&index_hash->blocks.check, LZMA_CHECK_BEST);
+	(void)lzma_check_init(&index_hash->records.check, LZMA_CHECK_BEST);
+
+	return index_hash;
+}
+
+
+extern LZMA_API(void)
+lzma_index_hash_end(lzma_index_hash *index_hash,
+		const lzma_allocator *allocator)
+{
+	lzma_free(index_hash, allocator);
+	return;
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_hash_size(const lzma_index_hash *index_hash)
+{
+	// Get the size of the Index from ->blocks instead of ->records for
+	// cases where application wants to know the Index Size before
+	// decoding the Index.
+	return index_size(index_hash->blocks.count,
+			index_hash->blocks.index_list_size);
+}
+
+
+/// Updates the sizes and the hash without any validation.
+static void
+hash_append(lzma_index_hash_info *info, lzma_vli unpadded_size,
+		lzma_vli uncompressed_size)
+{
+	info->blocks_size += vli_ceil4(unpadded_size);
+	info->uncompressed_size += uncompressed_size;
+	info->index_list_size += lzma_vli_size(unpadded_size)
+			+ lzma_vli_size(uncompressed_size);
+	++info->count;
+
+	const lzma_vli sizes[2] = { unpadded_size, uncompressed_size };
+	lzma_check_update(&info->check, LZMA_CHECK_BEST,
+			(const uint8_t *)(sizes), sizeof(sizes));
+
+	return;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_hash_append(lzma_index_hash *index_hash, lzma_vli unpadded_size,
+		lzma_vli uncompressed_size)
+{
+	// Validate the arguments.
+	if (index_hash == NULL || index_hash->sequence != SEQ_BLOCK
+			|| unpadded_size < UNPADDED_SIZE_MIN
+			|| unpadded_size > UNPADDED_SIZE_MAX
+			|| uncompressed_size > LZMA_VLI_MAX)
+		return LZMA_PROG_ERROR;
+
+	// Update the hash.
+	hash_append(&index_hash->blocks, unpadded_size, uncompressed_size);
+
+	// Validate the properties of *info are still in allowed limits.
+	if (index_hash->blocks.blocks_size > LZMA_VLI_MAX
+			|| index_hash->blocks.uncompressed_size > LZMA_VLI_MAX
+			|| index_size(index_hash->blocks.count,
+					index_hash->blocks.index_list_size)
+				> LZMA_BACKWARD_SIZE_MAX
+			|| index_stream_size(index_hash->blocks.blocks_size,
+					index_hash->blocks.count,
+					index_hash->blocks.index_list_size)
+				> LZMA_VLI_MAX)
+		return LZMA_DATA_ERROR;
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_hash_decode(lzma_index_hash *index_hash, const uint8_t *in,
+		size_t *in_pos, size_t in_size)
+{
+	// Catch zero input buffer here, because in contrast to Index encoder
+	// and decoder functions, applications call this function directly
+	// instead of via lzma_code(), which does the buffer checking.
+	if (*in_pos >= in_size)
+		return LZMA_BUF_ERROR;
+
+	// NOTE: This function has many similarities to index_encode() and
+	// index_decode() functions found from index_encoder.c and
+	// index_decoder.c. See the comments especially in index_encoder.c.
+	const size_t in_start = *in_pos;
+	lzma_ret ret = LZMA_OK;
+
+	while (*in_pos < in_size)
+	switch (index_hash->sequence) {
+	case SEQ_BLOCK:
+		// Check the Index Indicator is present.
+		if (in[(*in_pos)++] != INDEX_INDICATOR)
+			return LZMA_DATA_ERROR;
+
+		index_hash->sequence = SEQ_COUNT;
+		break;
+
+	case SEQ_COUNT: {
+		ret = lzma_vli_decode(&index_hash->remaining,
+				&index_hash->pos, in, in_pos, in_size);
+		if (ret != LZMA_STREAM_END)
+			goto out;
+
+		// The count must match the count of the Blocks decoded.
+		if (index_hash->remaining != index_hash->blocks.count)
+			return LZMA_DATA_ERROR;
+
+		ret = LZMA_OK;
+		index_hash->pos = 0;
+
+		// Handle the special case when there are no Blocks.
+		index_hash->sequence = index_hash->remaining == 0
+				? SEQ_PADDING_INIT : SEQ_UNPADDED;
+		break;
+	}
+
+	case SEQ_UNPADDED:
+	case SEQ_UNCOMPRESSED: {
+		lzma_vli *size = index_hash->sequence == SEQ_UNPADDED
+				? &index_hash->unpadded_size
+				: &index_hash->uncompressed_size;
+
+		ret = lzma_vli_decode(size, &index_hash->pos,
+				in, in_pos, in_size);
+		if (ret != LZMA_STREAM_END)
+			goto out;
+
+		ret = LZMA_OK;
+		index_hash->pos = 0;
+
+		if (index_hash->sequence == SEQ_UNPADDED) {
+			if (index_hash->unpadded_size < UNPADDED_SIZE_MIN
+					|| index_hash->unpadded_size
+						> UNPADDED_SIZE_MAX)
+				return LZMA_DATA_ERROR;
+
+			index_hash->sequence = SEQ_UNCOMPRESSED;
+		} else {
+			// Update the hash.
+			hash_append(&index_hash->records,
+					index_hash->unpadded_size,
+					index_hash->uncompressed_size);
+
+			// Verify that we don't go over the known sizes. Note
+			// that this validation is simpler than the one used
+			// in lzma_index_hash_append(), because here we know
+			// that values in index_hash->blocks are already
+			// validated and we are fine as long as we don't
+			// exceed them in index_hash->records.
+			if (index_hash->blocks.blocks_size
+					< index_hash->records.blocks_size
+					|| index_hash->blocks.uncompressed_size
+					< index_hash->records.uncompressed_size
+					|| index_hash->blocks.index_list_size
+					< index_hash->records.index_list_size)
+				return LZMA_DATA_ERROR;
+
+			// Check if this was the last Record.
+			index_hash->sequence = --index_hash->remaining == 0
+					? SEQ_PADDING_INIT : SEQ_UNPADDED;
+		}
+
+		break;
+	}
+
+	case SEQ_PADDING_INIT:
+		index_hash->pos = (LZMA_VLI_C(4) - index_size_unpadded(
+				index_hash->records.count,
+				index_hash->records.index_list_size)) & 3;
+		index_hash->sequence = SEQ_PADDING;
+
+	// Fall through
+
+	case SEQ_PADDING:
+		if (index_hash->pos > 0) {
+			--index_hash->pos;
+			if (in[(*in_pos)++] != 0x00)
+				return LZMA_DATA_ERROR;
+
+			break;
+		}
+
+		// Compare the sizes.
+		if (index_hash->blocks.blocks_size
+				!= index_hash->records.blocks_size
+				|| index_hash->blocks.uncompressed_size
+				!= index_hash->records.uncompressed_size
+				|| index_hash->blocks.index_list_size
+				!= index_hash->records.index_list_size)
+			return LZMA_DATA_ERROR;
+
+		// Finish the hashes and compare them.
+		lzma_check_finish(&index_hash->blocks.check, LZMA_CHECK_BEST);
+		lzma_check_finish(&index_hash->records.check, LZMA_CHECK_BEST);
+		if (memcmp(index_hash->blocks.check.buffer.u8,
+				index_hash->records.check.buffer.u8,
+				lzma_check_size(LZMA_CHECK_BEST)) != 0)
+			return LZMA_DATA_ERROR;
+
+		// Finish the CRC32 calculation.
+		index_hash->crc32 = lzma_crc32(in + in_start,
+				*in_pos - in_start, index_hash->crc32);
+
+		index_hash->sequence = SEQ_CRC32;
+
+	// Fall through
+
+	case SEQ_CRC32:
+		do {
+			if (*in_pos == in_size)
+				return LZMA_OK;
+
+			if (((index_hash->crc32 >> (index_hash->pos * 8))
+					& 0xFF) != in[(*in_pos)++]) {
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+				return LZMA_DATA_ERROR;
+#endif
+			}
+
+		} while (++index_hash->pos < 4);
+
+		return LZMA_STREAM_END;
+
+	default:
+		assert(0);
+		return LZMA_PROG_ERROR;
+	}
+
+out:
+	// Update the CRC32.
+	//
+	// Avoid null pointer + 0 (undefined behavior) in "in + in_start".
+	// In such a case we had no input and thus in_used == 0.
+	{
+		const size_t in_used = *in_pos - in_start;
+		if (in_used > 0)
+			index_hash->crc32 = lzma_crc32(in + in_start,
+					in_used, index_hash->crc32);
+	}
+
+	return ret;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.c
new file mode 100644
index 00000000000..651a0ae712c
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.c
@@ -0,0 +1,417 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lzip_decoder.c
+/// \brief      Decodes .lz (lzip) files
+//
+//  Author:     Michał Górny
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lzip_decoder.h"
+#include "lzma_decoder.h"
+#include "check.h"
+
+
+// .lz format version 0 lacks the 64-bit Member size field in the footer.
+#define LZIP_V0_FOOTER_SIZE 12
+#define LZIP_V1_FOOTER_SIZE 20
+#define LZIP_FOOTER_SIZE_MAX LZIP_V1_FOOTER_SIZE
+
+// lc/lp/pb are hardcoded in the .lz format.
+#define LZIP_LC 3
+#define LZIP_LP 0
+#define LZIP_PB 2
+
+
+typedef struct {
+	enum {
+		SEQ_ID_STRING,
+		SEQ_VERSION,
+		SEQ_DICT_SIZE,
+		SEQ_CODER_INIT,
+		SEQ_LZMA_STREAM,
+		SEQ_MEMBER_FOOTER,
+	} sequence;
+
+	/// .lz member format version
+	uint32_t version;
+
+	/// CRC32 of the uncompressed data in the .lz member
+	uint32_t crc32;
+
+	/// Uncompressed size of the .lz member
+	uint64_t uncompressed_size;
+
+	/// Compressed size of the .lz member
+	uint64_t member_size;
+
+	/// Memory usage limit
+	uint64_t memlimit;
+
+	/// Amount of memory actually needed
+	uint64_t memusage;
+
+	/// If true, LZMA_GET_CHECK is returned after decoding the header
+	/// fields. As all files use CRC32 this is redundant but it's
+	/// implemented anyway since the initialization functions supports
+	/// all other flags in addition to LZMA_TELL_ANY_CHECK.
+	bool tell_any_check;
+
+	/// If true, we won't calculate or verify the CRC32 of
+	/// the uncompressed data.
+	bool ignore_check;
+
+	/// If true, we will decode concatenated .lz members and stop if
+	/// non-.lz data is seen after at least one member has been
+	/// successfully decoded.
+	bool concatenated;
+
+	/// When decoding concatenated .lz members, this is true as long as
+	/// we are decoding the first .lz member. This is needed to avoid
+	/// incorrect LZMA_FORMAT_ERROR in case there is non-.lz data at
+	/// the end of the file.
+	bool first_member;
+
+	/// Reading position in the header and footer fields
+	size_t pos;
+
+	/// Buffer to hold the .lz footer fields
+	uint8_t buffer[LZIP_FOOTER_SIZE_MAX];
+
+	/// Options decoded from the .lz header that needed to initialize
+	/// the LZMA1 decoder.
+	lzma_options_lzma options;
+
+	/// LZMA1 decoder
+	lzma_next_coder lzma_decoder;
+
+} lzma_lzip_coder;
+
+
+static lzma_ret
+lzip_decode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size, lzma_action action)
+{
+	lzma_lzip_coder *coder = coder_ptr;
+
+	while (true)
+	switch (coder->sequence) {
+	case SEQ_ID_STRING: {
+		// The "ID string" or magic bytes are "LZIP" in US-ASCII.
+		const uint8_t lzip_id_string[4] = { 0x4C, 0x5A, 0x49, 0x50 };
+
+		while (coder->pos < sizeof(lzip_id_string)) {
+			if (*in_pos >= in_size) {
+				// If we are on the 2nd+ concatenated member
+				// and the input ends before we can read
+				// the magic bytes, we discard the bytes that
+				// were already read (up to 3) and finish.
+				// See the reasoning below.
+				return !coder->first_member
+						&& action == LZMA_FINISH
+					? LZMA_STREAM_END : LZMA_OK;
+			}
+
+			if (in[*in_pos] != lzip_id_string[coder->pos]) {
+				// The .lz format allows putting non-.lz data
+				// at the end of the file. If we have seen
+				// at least one valid .lz member already,
+				// then we won't consume the byte at *in_pos
+				// and will return LZMA_STREAM_END. This way
+				// apps can easily locate and read the non-.lz
+				// data after the .lz member(s).
+				//
+				// NOTE: If the first 1-3 bytes of the non-.lz
+				// data match the .lz ID string then the first
+				// 1-3 bytes of the junk will get ignored by
+				// us. If apps want to properly locate the
+				// trailing data they must ensure that the
+				// first byte of their custom data isn't the
+				// same as the first byte of .lz ID string.
+				// With the liblzma API we cannot rewind the
+				// input position across calls to lzma_code().
+				return !coder->first_member
+					? LZMA_STREAM_END : LZMA_FORMAT_ERROR;
+			}
+
+			++*in_pos;
+			++coder->pos;
+		}
+
+		coder->pos = 0;
+
+		coder->crc32 = 0;
+		coder->uncompressed_size = 0;
+		coder->member_size = sizeof(lzip_id_string);
+
+		coder->sequence = SEQ_VERSION;
+	}
+
+	// Fall through
+
+	case SEQ_VERSION:
+		if (*in_pos >= in_size)
+			return LZMA_OK;
+
+		coder->version = in[(*in_pos)++];
+
+		// We support version 0 and unextended version 1.
+		if (coder->version > 1)
+			return LZMA_OPTIONS_ERROR;
+
+		++coder->member_size;
+		coder->sequence = SEQ_DICT_SIZE;
+
+		// .lz versions 0 and 1 use CRC32 as the integrity check
+		// so if the application wanted to know that
+		// (LZMA_TELL_ANY_CHECK) we can tell it now.
+		if (coder->tell_any_check)
+			return LZMA_GET_CHECK;
+
+	// Fall through
+
+	case SEQ_DICT_SIZE: {
+		if (*in_pos >= in_size)
+			return LZMA_OK;
+
+		const uint32_t ds = in[(*in_pos)++];
+		++coder->member_size;
+
+		// The five lowest bits are for the base-2 logarithm of
+		// the dictionary size and the highest three bits are
+		// the fractional part (0/16 to 7/16) that will be
+		// subtracted to get the final value.
+		//
+		// For example, with 0xB5:
+		//     b2log = 21
+		//     fracnum = 5
+		//     dict_size = 2^21 - 2^21 * 5 / 16 = 1408 KiB
+		const uint32_t b2log = ds & 0x1F;
+		const uint32_t fracnum = ds >> 5;
+
+		// The format versions 0 and 1 allow dictionary size in the
+		// range [4 KiB, 512 MiB].
+		if (b2log < 12 || b2log > 29 || (b2log == 12 && fracnum > 0))
+			return LZMA_DATA_ERROR;
+
+		//   2^[b2log] - 2^[b2log] * [fracnum] / 16
+		// = 2^[b2log] - [fracnum] * 2^([b2log] - 4)
+		coder->options.dict_size = (UINT32_C(1) << b2log)
+				- (fracnum << (b2log - 4));
+
+		assert(coder->options.dict_size >= 4096);
+		assert(coder->options.dict_size <= (UINT32_C(512) << 20));
+
+		coder->options.preset_dict = NULL;
+		coder->options.lc = LZIP_LC;
+		coder->options.lp = LZIP_LP;
+		coder->options.pb = LZIP_PB;
+
+		// Calculate the memory usage.
+		coder->memusage = lzma_lzma_decoder_memusage(&coder->options)
+				+ LZMA_MEMUSAGE_BASE;
+
+		// Initialization is a separate step because if we return
+		// LZMA_MEMLIMIT_ERROR we need to be able to restart after
+		// the memlimit has been increased.
+		coder->sequence = SEQ_CODER_INIT;
+	}
+
+	// Fall through
+
+	case SEQ_CODER_INIT: {
+		if (coder->memusage > coder->memlimit)
+			return LZMA_MEMLIMIT_ERROR;
+
+		const lzma_filter_info filters[2] = {
+			{
+				.id = LZMA_FILTER_LZMA1,
+				.init = &lzma_lzma_decoder_init,
+				.options = &coder->options,
+			}, {
+				.init = NULL,
+			}
+		};
+
+		return_if_error(lzma_next_filter_init(&coder->lzma_decoder,
+				allocator, filters));
+
+		coder->crc32 = 0;
+		coder->sequence = SEQ_LZMA_STREAM;
+	}
+
+	// Fall through
+
+	case SEQ_LZMA_STREAM: {
+		const size_t in_start = *in_pos;
+		const size_t out_start = *out_pos;
+
+		const lzma_ret ret = coder->lzma_decoder.code(
+				coder->lzma_decoder.coder, allocator,
+				in, in_pos, in_size, out, out_pos, out_size,
+				action);
+
+		const size_t out_used = *out_pos - out_start;
+
+		coder->member_size += *in_pos - in_start;
+		coder->uncompressed_size += out_used;
+
+		// Don't update the CRC32 if the integrity check will be
+		// ignored or if there was no new output. The latter is
+		// important in case out == NULL to avoid null pointer + 0
+		// which is undefined behavior.
+		if (!coder->ignore_check && out_used > 0)
+			coder->crc32 = lzma_crc32(out + out_start, out_used,
+					coder->crc32);
+
+		if (ret != LZMA_STREAM_END)
+			return ret;
+
+		coder->sequence = SEQ_MEMBER_FOOTER;
+	}
+
+	// Fall through
+
+	case SEQ_MEMBER_FOOTER: {
+		// The footer of .lz version 0 lacks the Member size field.
+		// This is the only difference between version 0 and
+		// unextended version 1 formats.
+		const size_t footer_size = coder->version == 0
+				? LZIP_V0_FOOTER_SIZE
+				: LZIP_V1_FOOTER_SIZE;
+
+		// Copy the CRC32, Data size, and Member size fields to
+		// the internal buffer.
+		lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
+				footer_size);
+
+		// Return if we didn't get the whole footer yet.
+		if (coder->pos < footer_size)
+			return LZMA_OK;
+
+		coder->pos = 0;
+		coder->member_size += footer_size;
+
+		// Check that the footer fields match the observed data.
+		if (!coder->ignore_check
+				&& coder->crc32 != read32le(&coder->buffer[0]))
+			return LZMA_DATA_ERROR;
+
+		if (coder->uncompressed_size != read64le(&coder->buffer[4]))
+			return LZMA_DATA_ERROR;
+
+		if (coder->version > 0) {
+			// .lz version 0 has no Member size field.
+			if (coder->member_size != read64le(&coder->buffer[12]))
+				return LZMA_DATA_ERROR;
+		}
+
+		// Decoding is finished if we weren't requested to decode
+		// more than one .lz member.
+		if (!coder->concatenated)
+			return LZMA_STREAM_END;
+
+		coder->first_member = false;
+		coder->sequence = SEQ_ID_STRING;
+		break;
+	}
+
+	default:
+		assert(0);
+		return LZMA_PROG_ERROR;
+	}
+
+	// Never reached
+}
+
+
+static void
+lzip_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_lzip_coder *coder = coder_ptr;
+	lzma_next_end(&coder->lzma_decoder, allocator);
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_check
+lzip_decoder_get_check(const void *coder_ptr lzma_attribute((__unused__)))
+{
+	return LZMA_CHECK_CRC32;
+}
+
+
+static lzma_ret
+lzip_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
+		uint64_t *old_memlimit, uint64_t new_memlimit)
+{
+	lzma_lzip_coder *coder = coder_ptr;
+
+	*memusage = coder->memusage;
+	*old_memlimit = coder->memlimit;
+
+	if (new_memlimit != 0) {
+		if (new_memlimit < coder->memusage)
+			return LZMA_MEMLIMIT_ERROR;
+
+		coder->memlimit = new_memlimit;
+	}
+
+	return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_lzip_decoder_init(
+		lzma_next_coder *next, const lzma_allocator *allocator,
+		uint64_t memlimit, uint32_t flags)
+{
+	lzma_next_coder_init(&lzma_lzip_decoder_init, next, allocator);
+
+	if (flags & ~LZMA_SUPPORTED_FLAGS)
+		return LZMA_OPTIONS_ERROR;
+
+	lzma_lzip_coder *coder = next->coder;
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_lzip_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+		next->code = &lzip_decode;
+		next->end = &lzip_decoder_end;
+		next->get_check = &lzip_decoder_get_check;
+		next->memconfig = &lzip_decoder_memconfig;
+
+		coder->lzma_decoder = LZMA_NEXT_CODER_INIT;
+	}
+
+	coder->sequence = SEQ_ID_STRING;
+	coder->memlimit = my_max(1, memlimit);
+	coder->memusage = LZMA_MEMUSAGE_BASE;
+	coder->tell_any_check = (flags & LZMA_TELL_ANY_CHECK) != 0;
+	coder->ignore_check = (flags & LZMA_IGNORE_CHECK) != 0;
+	coder->concatenated = (flags & LZMA_CONCATENATED) != 0;
+	coder->first_member = true;
+	coder->pos = 0;
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_lzip_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)
+{
+	lzma_next_strm_init(lzma_lzip_decoder_init, strm, memlimit, flags);
+
+	strm->internal->supported_actions[LZMA_RUN] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.h
new file mode 100644
index 00000000000..0e1f7bebd45
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/lzip_decoder.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lzip_decoder.h
+/// \brief      Decodes .lz (lzip) files
+//
+//  Author:     Michał Górny
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZIP_DECODER_H
+#define LZMA_LZIP_DECODER_H
+
+#include "common.h"
+
+extern lzma_ret lzma_lzip_decoder_init(
+		lzma_next_coder *next, const lzma_allocator *allocator,
+		uint64_t memlimit, uint32_t flags);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/memcmplen.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/memcmplen.h
new file mode 100644
index 00000000000..394a4856dd6
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/memcmplen.h
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       memcmplen.h
+/// \brief      Optimized comparison of two buffers
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_MEMCMPLEN_H
+#define LZMA_MEMCMPLEN_H
+
+#include "common.h"
+
+#ifdef HAVE_IMMINTRIN_H
+#	include 
+#endif
+
+// Only include  if it is needed. The header is only needed
+// on Windows when using an MSVC compatible compiler. The Intel compiler
+// can use the intrinsics without the header file.
+#if defined(TUKLIB_FAST_UNALIGNED_ACCESS) \
+		&& defined(_MSC_VER) \
+		&& (defined(_M_X64) \
+			|| defined(_M_ARM64) || defined(_M_ARM64EC)) \
+		&& !defined(__INTEL_COMPILER)
+#	include 
+#endif
+
+
+/// Find out how many equal bytes the two buffers have.
+///
+/// \param      buf1    First buffer
+/// \param      buf2    Second buffer
+/// \param      len     How many bytes have already been compared and will
+///                     be assumed to match
+/// \param      limit   How many bytes to compare at most, including the
+///                     already-compared bytes. This must be significantly
+///                     smaller than UINT32_MAX to avoid integer overflows.
+///                     Up to LZMA_MEMCMPLEN_EXTRA bytes may be read past
+///                     the specified limit from both buf1 and buf2.
+///
+/// \return     Number of equal bytes in the buffers is returned.
+///             This is always at least len and at most limit.
+///
+/// \note       LZMA_MEMCMPLEN_EXTRA defines how many extra bytes may be read.
+///             It's rounded up to 2^n. This extra amount needs to be
+///             allocated in the buffers being used. It needs to be
+///             initialized too to keep Valgrind quiet.
+static lzma_always_inline uint32_t
+lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2,
+		uint32_t len, uint32_t limit)
+{
+	assert(len <= limit);
+	assert(limit <= UINT32_MAX / 2);
+
+#if defined(TUKLIB_FAST_UNALIGNED_ACCESS) \
+		&& (((TUKLIB_GNUC_REQ(3, 4) || defined(__clang__)) \
+				&& (defined(__x86_64__) \
+					|| defined(__aarch64__))) \
+			|| (defined(__INTEL_COMPILER) && defined(__x86_64__)) \
+			|| (defined(__INTEL_COMPILER) && defined(_M_X64)) \
+			|| (defined(_MSC_VER) && (defined(_M_X64) \
+				|| defined(_M_ARM64) || defined(_M_ARM64EC))))
+	// This is only for x86-64 and ARM64 for now. This might be fine on
+	// other 64-bit processors too. On big endian one should use xor
+	// instead of subtraction and switch to __builtin_clzll().
+	//
+	// Reasons to use subtraction instead of xor:
+	//
+	//   - On some x86-64 processors (Intel Sandy Bridge to Tiger Lake),
+	//     sub+jz and sub+jnz can be fused but xor+jz or xor+jnz cannot.
+	//     Thus using subtraction has potential to be a tiny amount faster
+	//     since the code checks if the quotient is non-zero.
+	//
+	//   - Some processors (Intel Pentium 4) used to have more ALU
+	//     resources for add/sub instructions than and/or/xor.
+	//
+	// The processor info is based on Agner Fog's microarchitecture.pdf
+	// version 2023-05-26. https://www.agner.org/optimize/
+#define LZMA_MEMCMPLEN_EXTRA 8
+	while (len < limit) {
+		const uint64_t x = read64ne(buf1 + len) - read64ne(buf2 + len);
+		if (x != 0) {
+	// MSVC or Intel C compiler on Windows
+#	if defined(_MSC_VER) || defined(__INTEL_COMPILER)
+			unsigned long tmp;
+			_BitScanForward64(&tmp, x);
+			len += (uint32_t)tmp >> 3;
+	// GCC, Clang, or Intel C compiler
+#	else
+			len += (uint32_t)__builtin_ctzll(x) >> 3;
+#	endif
+			return my_min(len, limit);
+		}
+
+		len += 8;
+	}
+
+	return limit;
+
+#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) \
+		&& defined(HAVE__MM_MOVEMASK_EPI8) \
+		&& (defined(__SSE2__) \
+			|| (defined(_MSC_VER) && defined(_M_IX86_FP) \
+				&& _M_IX86_FP >= 2))
+	// NOTE: This will use 128-bit unaligned access which
+	// TUKLIB_FAST_UNALIGNED_ACCESS wasn't meant to permit,
+	// but it's convenient here since this is x86-only.
+	//
+	// SSE2 version for 32-bit and 64-bit x86. On x86-64 the above
+	// version is sometimes significantly faster and sometimes
+	// slightly slower than this SSE2 version, so this SSE2
+	// version isn't used on x86-64.
+#	define LZMA_MEMCMPLEN_EXTRA 16
+	while (len < limit) {
+		const uint32_t x = 0xFFFF ^ (uint32_t)_mm_movemask_epi8(
+			_mm_cmpeq_epi8(
+			_mm_loadu_si128((const __m128i *)(buf1 + len)),
+			_mm_loadu_si128((const __m128i *)(buf2 + len))));
+
+		if (x != 0) {
+			len += ctz32(x);
+			return my_min(len, limit);
+		}
+
+		len += 16;
+	}
+
+	return limit;
+
+#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) && !defined(WORDS_BIGENDIAN)
+	// Generic 32-bit little endian method
+#	define LZMA_MEMCMPLEN_EXTRA 4
+	while (len < limit) {
+		uint32_t x = read32ne(buf1 + len) - read32ne(buf2 + len);
+		if (x != 0) {
+			if ((x & 0xFFFF) == 0) {
+				len += 2;
+				x >>= 16;
+			}
+
+			if ((x & 0xFF) == 0)
+				++len;
+
+			return my_min(len, limit);
+		}
+
+		len += 4;
+	}
+
+	return limit;
+
+#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) && defined(WORDS_BIGENDIAN)
+	// Generic 32-bit big endian method
+#	define LZMA_MEMCMPLEN_EXTRA 4
+	while (len < limit) {
+		uint32_t x = read32ne(buf1 + len) ^ read32ne(buf2 + len);
+		if (x != 0) {
+			if ((x & 0xFFFF0000) == 0) {
+				len += 2;
+				x <<= 16;
+			}
+
+			if ((x & 0xFF000000) == 0)
+				++len;
+
+			return my_min(len, limit);
+		}
+
+		len += 4;
+	}
+
+	return limit;
+
+#else
+	// Simple portable version that doesn't use unaligned access.
+#	define LZMA_MEMCMPLEN_EXTRA 0
+	while (len < limit && buf1[len] == buf2[len])
+		++len;
+
+	return len;
+#endif
+}
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_decoder.c
new file mode 100644
index 00000000000..882cb2c808d
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_decoder.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       microlzma_decoder.c
+/// \brief      Decode MicroLZMA format
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lzma_decoder.h"
+#include "lz_decoder.h"
+
+
+typedef struct {
+	/// LZMA1 decoder
+	lzma_next_coder lzma;
+
+	/// Compressed size of the stream as given by the application.
+	/// This must be exactly correct.
+	///
+	/// This will be decremented when input is read.
+	uint64_t comp_size;
+
+	/// Uncompressed size of the stream as given by the application.
+	/// This may be less than the actual uncompressed size if
+	/// uncomp_size_is_exact is false.
+	///
+	/// This will be decremented when output is produced.
+	lzma_vli uncomp_size;
+
+	/// LZMA dictionary size as given by the application
+	uint32_t dict_size;
+
+	/// If true, the exact uncompressed size is known. If false,
+	/// uncomp_size may be smaller than the real uncompressed size;
+	/// uncomp_size may never be bigger than the real uncompressed size.
+	bool uncomp_size_is_exact;
+
+	/// True once the first byte of the MicroLZMA stream
+	/// has been processed.
+	bool props_decoded;
+} lzma_microlzma_coder;
+
+
+static lzma_ret
+microlzma_decode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size, lzma_action action)
+{
+	lzma_microlzma_coder *coder = coder_ptr;
+
+	// Remember the in start position so that we can update comp_size.
+	const size_t in_start = *in_pos;
+
+	// Remember the out start position so that we can update uncomp_size.
+	const size_t out_start = *out_pos;
+
+	// Limit the amount of input so that the decoder won't read more than
+	// comp_size. This is required when uncomp_size isn't exact because
+	// in that case the LZMA decoder will try to decode more input even
+	// when it has no output space (it can be looking for EOPM).
+	if (in_size - *in_pos > coder->comp_size)
+		in_size = *in_pos + (size_t)(coder->comp_size);
+
+	// When the exact uncompressed size isn't known, we must limit
+	// the available output space to prevent the LZMA decoder from
+	// trying to decode too much.
+	if (!coder->uncomp_size_is_exact
+			&& out_size - *out_pos > coder->uncomp_size)
+		out_size = *out_pos + (size_t)(coder->uncomp_size);
+
+	if (!coder->props_decoded) {
+		// There must be at least one byte of input to decode
+		// the properties byte.
+		if (*in_pos >= in_size)
+			return LZMA_OK;
+
+		lzma_options_lzma options = {
+			.dict_size = coder->dict_size,
+			.preset_dict = NULL,
+			.preset_dict_size = 0,
+			.ext_flags = 0, // EOPM not allowed when size is known
+			.ext_size_low = UINT32_MAX, // Unknown size by default
+			.ext_size_high = UINT32_MAX,
+		};
+
+		if (coder->uncomp_size_is_exact)
+			lzma_set_ext_size(options, coder->uncomp_size);
+
+		// The properties are stored as bitwise-negation
+		// of the typical encoding.
+		if (lzma_lzma_lclppb_decode(&options, ~in[*in_pos]))
+			return LZMA_OPTIONS_ERROR;
+
+		++*in_pos;
+
+		// Initialize the decoder.
+		lzma_filter_info filters[2] = {
+			{
+				.id = LZMA_FILTER_LZMA1EXT,
+				.init = &lzma_lzma_decoder_init,
+				.options = &options,
+			}, {
+				.init = NULL,
+			}
+		};
+
+		return_if_error(lzma_next_filter_init(&coder->lzma,
+				allocator, filters));
+
+		// Pass one dummy 0x00 byte to the LZMA decoder since that
+		// is what it expects the first byte to be.
+		const uint8_t dummy_in = 0;
+		size_t dummy_in_pos = 0;
+		if (coder->lzma.code(coder->lzma.coder, allocator,
+				&dummy_in, &dummy_in_pos, 1,
+				out, out_pos, out_size, LZMA_RUN) != LZMA_OK)
+			return LZMA_PROG_ERROR;
+
+		assert(dummy_in_pos == 1);
+		coder->props_decoded = true;
+	}
+
+	// The rest is normal LZMA decoding.
+	lzma_ret ret = coder->lzma.code(coder->lzma.coder, allocator,
+				in, in_pos, in_size,
+				out, out_pos, out_size, action);
+
+	// Update the remaining compressed size.
+	assert(coder->comp_size >= *in_pos - in_start);
+	coder->comp_size -= *in_pos - in_start;
+
+	if (coder->uncomp_size_is_exact) {
+		// After successful decompression of the complete stream
+		// the compressed size must match.
+		if (ret == LZMA_STREAM_END && coder->comp_size != 0)
+			ret = LZMA_DATA_ERROR;
+	} else {
+		// Update the amount of output remaining.
+		assert(coder->uncomp_size >= *out_pos - out_start);
+		coder->uncomp_size -= *out_pos - out_start;
+
+		// - We must not get LZMA_STREAM_END because the stream
+		//   shouldn't have EOPM.
+		// - We must use uncomp_size to determine when to
+		//   return LZMA_STREAM_END.
+		if (ret == LZMA_STREAM_END)
+			ret = LZMA_DATA_ERROR;
+		else if (coder->uncomp_size == 0)
+			ret = LZMA_STREAM_END;
+	}
+
+	return ret;
+}
+
+
+static void
+microlzma_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_microlzma_coder *coder = coder_ptr;
+	lzma_next_end(&coder->lzma, allocator);
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_ret
+microlzma_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		uint64_t comp_size,
+		uint64_t uncomp_size, bool uncomp_size_is_exact,
+		uint32_t dict_size)
+{
+	lzma_next_coder_init(µlzma_decoder_init, next, allocator);
+
+	lzma_microlzma_coder *coder = next->coder;
+
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_microlzma_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+		next->code = µlzma_decode;
+		next->end = µlzma_decoder_end;
+
+		coder->lzma = LZMA_NEXT_CODER_INIT;
+	}
+
+	// The public API is uint64_t but the internal LZ decoder API uses
+	// lzma_vli.
+	if (uncomp_size > LZMA_VLI_MAX)
+		return LZMA_OPTIONS_ERROR;
+
+	coder->comp_size = comp_size;
+	coder->uncomp_size = uncomp_size;
+	coder->uncomp_size_is_exact = uncomp_size_is_exact;
+	coder->dict_size = dict_size;
+
+	coder->props_decoded = false;
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_microlzma_decoder(lzma_stream *strm, uint64_t comp_size,
+		uint64_t uncomp_size, lzma_bool uncomp_size_is_exact,
+		uint32_t dict_size)
+{
+	lzma_next_strm_init(microlzma_decoder_init, strm, comp_size,
+			uncomp_size, uncomp_size_is_exact, dict_size);
+
+	strm->internal->supported_actions[LZMA_RUN] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_encoder.c
new file mode 100644
index 00000000000..45ec0b12f45
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/microlzma_encoder.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       microlzma_encoder.c
+/// \brief      Encode into MicroLZMA format
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lzma_encoder.h"
+
+
+typedef struct {
+	/// LZMA1 encoder
+	lzma_next_coder lzma;
+
+	/// LZMA properties byte (lc/lp/pb)
+	uint8_t props;
+} lzma_microlzma_coder;
+
+
+static lzma_ret
+microlzma_encode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size, lzma_action action)
+{
+	lzma_microlzma_coder *coder = coder_ptr;
+
+	// Remember *out_pos so that we can overwrite the first byte with
+	// the LZMA properties byte.
+	const size_t out_start = *out_pos;
+
+	// Remember *in_pos so that we can set it based on how many
+	// uncompressed bytes were actually encoded.
+	const size_t in_start = *in_pos;
+
+	// Set the output size limit based on the available output space.
+	// We know that the encoder supports set_out_limit() so
+	// LZMA_OPTIONS_ERROR isn't possible. LZMA_BUF_ERROR is possible
+	// but lzma_code() has an assertion to not allow it to be returned
+	// from here and I don't want to change that for now, so
+	// LZMA_BUF_ERROR becomes LZMA_PROG_ERROR.
+	uint64_t uncomp_size;
+	if (coder->lzma.set_out_limit(coder->lzma.coder,
+			&uncomp_size, out_size - *out_pos) != LZMA_OK)
+		return LZMA_PROG_ERROR;
+
+	// set_out_limit fails if this isn't true.
+	assert(out_size - *out_pos >= 6);
+
+	// Encode as much as possible.
+	const lzma_ret ret = coder->lzma.code(coder->lzma.coder, allocator,
+			in, in_pos, in_size, out, out_pos, out_size, action);
+
+	if (ret != LZMA_STREAM_END) {
+		if (ret == LZMA_OK) {
+			assert(0);
+			return LZMA_PROG_ERROR;
+		}
+
+		return ret;
+	}
+
+	// The first output byte is bitwise-negation of the properties byte.
+	// We know that there is space for this byte because set_out_limit
+	// and the actual encoding succeeded.
+	out[out_start] = (uint8_t)(~coder->props);
+
+	// The LZMA encoder likely read more input than it was able to encode.
+	// Set *in_pos based on uncomp_size.
+	assert(uncomp_size <= in_size - in_start);
+	*in_pos = in_start + (size_t)(uncomp_size);
+
+	return ret;
+}
+
+
+static void
+microlzma_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_microlzma_coder *coder = coder_ptr;
+	lzma_next_end(&coder->lzma, allocator);
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_ret
+microlzma_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_options_lzma *options)
+{
+	lzma_next_coder_init(µlzma_encoder_init, next, allocator);
+
+	lzma_microlzma_coder *coder = next->coder;
+
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_microlzma_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+		next->code = µlzma_encode;
+		next->end = µlzma_encoder_end;
+
+		coder->lzma = LZMA_NEXT_CODER_INIT;
+	}
+
+	// Encode the properties byte. Bitwise-negation of it will be the
+	// first output byte.
+	if (lzma_lzma_lclppb_encode(options, &coder->props))
+		return LZMA_OPTIONS_ERROR;
+
+	// Initialize the LZMA encoder.
+	const lzma_filter_info filters[2] = {
+		{
+			.id = LZMA_FILTER_LZMA1,
+			.init = &lzma_lzma_encoder_init,
+			.options = (void *)(options),
+		}, {
+			.init = NULL,
+		}
+	};
+
+	return lzma_next_filter_init(&coder->lzma, allocator, filters);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_microlzma_encoder(lzma_stream *strm, const lzma_options_lzma *options)
+{
+	lzma_next_strm_init(microlzma_encoder_init, strm, options);
+
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.c
new file mode 100644
index 00000000000..eb018eb42b2
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.c
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       outqueue.c
+/// \brief      Output queue handling in multithreaded coding
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "outqueue.h"
+
+
+/// Get the maximum number of buffers that may be allocated based
+/// on the number of threads. For now this is twice the number of threads.
+/// It's a compromise between RAM usage and keeping the worker threads busy
+/// when buffers finish out of order.
+#define GET_BUFS_LIMIT(threads) (2 * (threads))
+
+
+extern uint64_t
+lzma_outq_memusage(uint64_t buf_size_max, uint32_t threads)
+{
+	// This is to ease integer overflow checking: We may allocate up to
+	// GET_BUFS_LIMIT(LZMA_THREADS_MAX) buffers and we need some extra
+	// memory for other data structures too (that's the /2).
+	//
+	// lzma_outq_prealloc_buf() will still accept bigger buffers than this.
+	const uint64_t limit
+			= UINT64_MAX / GET_BUFS_LIMIT(LZMA_THREADS_MAX) / 2;
+
+	if (threads > LZMA_THREADS_MAX || buf_size_max > limit)
+		return UINT64_MAX;
+
+	return GET_BUFS_LIMIT(threads)
+			* lzma_outq_outbuf_memusage(buf_size_max);
+}
+
+
+static void
+move_head_to_cache(lzma_outq *outq, const lzma_allocator *allocator)
+{
+	assert(outq->head != NULL);
+	assert(outq->tail != NULL);
+	assert(outq->bufs_in_use > 0);
+
+	lzma_outbuf *buf = outq->head;
+	outq->head = buf->next;
+	if (outq->head == NULL)
+		outq->tail = NULL;
+
+	if (outq->cache != NULL && outq->cache->allocated != buf->allocated)
+		lzma_outq_clear_cache(outq, allocator);
+
+	buf->next = outq->cache;
+	outq->cache = buf;
+
+	--outq->bufs_in_use;
+	outq->mem_in_use -= lzma_outq_outbuf_memusage(buf->allocated);
+
+	return;
+}
+
+
+static void
+free_one_cached_buffer(lzma_outq *outq, const lzma_allocator *allocator)
+{
+	assert(outq->cache != NULL);
+
+	lzma_outbuf *buf = outq->cache;
+	outq->cache = buf->next;
+
+	--outq->bufs_allocated;
+	outq->mem_allocated -= lzma_outq_outbuf_memusage(buf->allocated);
+
+	lzma_free(buf, allocator);
+	return;
+}
+
+
+extern void
+lzma_outq_clear_cache(lzma_outq *outq, const lzma_allocator *allocator)
+{
+	while (outq->cache != NULL)
+		free_one_cached_buffer(outq, allocator);
+
+	return;
+}
+
+
+extern void
+lzma_outq_clear_cache2(lzma_outq *outq, const lzma_allocator *allocator,
+		size_t keep_size)
+{
+	if (outq->cache == NULL)
+		return;
+
+	// Free all but one.
+	while (outq->cache->next != NULL)
+		free_one_cached_buffer(outq, allocator);
+
+	// Free the last one only if its size doesn't equal to keep_size.
+	if (outq->cache->allocated != keep_size)
+		free_one_cached_buffer(outq, allocator);
+
+	return;
+}
+
+
+extern lzma_ret
+lzma_outq_init(lzma_outq *outq, const lzma_allocator *allocator,
+		uint32_t threads)
+{
+	if (threads > LZMA_THREADS_MAX)
+		return LZMA_OPTIONS_ERROR;
+
+	const uint32_t bufs_limit = GET_BUFS_LIMIT(threads);
+
+	// Clear head/tail.
+	while (outq->head != NULL)
+		move_head_to_cache(outq, allocator);
+
+	// If new buf_limit is lower than the old one, we may need to free
+	// a few cached buffers.
+	while (bufs_limit < outq->bufs_allocated)
+		free_one_cached_buffer(outq, allocator);
+
+	outq->bufs_limit = bufs_limit;
+	outq->read_pos = 0;
+
+	return LZMA_OK;
+}
+
+
+extern void
+lzma_outq_end(lzma_outq *outq, const lzma_allocator *allocator)
+{
+	while (outq->head != NULL)
+		move_head_to_cache(outq, allocator);
+
+	lzma_outq_clear_cache(outq, allocator);
+	return;
+}
+
+
+extern lzma_ret
+lzma_outq_prealloc_buf(lzma_outq *outq, const lzma_allocator *allocator,
+		size_t size)
+{
+	// Caller must have checked it with lzma_outq_has_buf().
+	assert(outq->bufs_in_use < outq->bufs_limit);
+
+	// If there already is appropriately-sized buffer in the cache,
+	// we need to do nothing.
+	if (outq->cache != NULL && outq->cache->allocated == size)
+		return LZMA_OK;
+
+	if (size > SIZE_MAX - sizeof(lzma_outbuf))
+		return LZMA_MEM_ERROR;
+
+	const size_t alloc_size = lzma_outq_outbuf_memusage(size);
+
+	// The cache may have buffers but their size is wrong.
+	lzma_outq_clear_cache(outq, allocator);
+
+	outq->cache = lzma_alloc(alloc_size, allocator);
+	if (outq->cache == NULL)
+		return LZMA_MEM_ERROR;
+
+	outq->cache->next = NULL;
+	outq->cache->allocated = size;
+
+	++outq->bufs_allocated;
+	outq->mem_allocated += alloc_size;
+
+	return LZMA_OK;
+}
+
+
+extern lzma_outbuf *
+lzma_outq_get_buf(lzma_outq *outq, void *worker)
+{
+	// Caller must have used lzma_outq_prealloc_buf() to ensure these.
+	assert(outq->bufs_in_use < outq->bufs_limit);
+	assert(outq->bufs_in_use < outq->bufs_allocated);
+	assert(outq->cache != NULL);
+
+	lzma_outbuf *buf = outq->cache;
+	outq->cache = buf->next;
+	buf->next = NULL;
+
+	if (outq->tail != NULL) {
+		assert(outq->head != NULL);
+		outq->tail->next = buf;
+	} else {
+		assert(outq->head == NULL);
+		outq->head = buf;
+	}
+
+	outq->tail = buf;
+
+	buf->worker = worker;
+	buf->finished = false;
+	buf->finish_ret = LZMA_STREAM_END;
+	buf->pos = 0;
+	buf->decoder_in_pos = 0;
+
+	buf->unpadded_size = 0;
+	buf->uncompressed_size = 0;
+
+	++outq->bufs_in_use;
+	outq->mem_in_use += lzma_outq_outbuf_memusage(buf->allocated);
+
+	return buf;
+}
+
+
+extern bool
+lzma_outq_is_readable(const lzma_outq *outq)
+{
+	if (outq->head == NULL)
+		return false;
+
+	return outq->read_pos < outq->head->pos || outq->head->finished;
+}
+
+
+extern lzma_ret
+lzma_outq_read(lzma_outq *restrict outq,
+		const lzma_allocator *restrict allocator,
+		uint8_t *restrict out, size_t *restrict out_pos,
+		size_t out_size,
+		lzma_vli *restrict unpadded_size,
+		lzma_vli *restrict uncompressed_size)
+{
+	// There must be at least one buffer from which to read.
+	if (outq->bufs_in_use == 0)
+		return LZMA_OK;
+
+	// Get the buffer.
+	lzma_outbuf *buf = outq->head;
+
+	// Copy from the buffer to output.
+	//
+	// FIXME? In threaded decoder it may be bad to do this copy while
+	// the mutex is being held.
+	lzma_bufcpy(buf->buf, &outq->read_pos, buf->pos,
+			out, out_pos, out_size);
+
+	// Return if we didn't get all the data from the buffer.
+	if (!buf->finished || outq->read_pos < buf->pos)
+		return LZMA_OK;
+
+	// The buffer was finished. Tell the caller its size information.
+	if (unpadded_size != NULL)
+		*unpadded_size = buf->unpadded_size;
+
+	if (uncompressed_size != NULL)
+		*uncompressed_size = buf->uncompressed_size;
+
+	// Remember the return value.
+	const lzma_ret finish_ret = buf->finish_ret;
+
+	// Free this buffer for further use.
+	move_head_to_cache(outq, allocator);
+	outq->read_pos = 0;
+
+	return finish_ret;
+}
+
+
+extern void
+lzma_outq_enable_partial_output(lzma_outq *outq,
+		void (*enable_partial_output)(void *worker))
+{
+	if (outq->head != NULL && !outq->head->finished
+			&& outq->head->worker != NULL) {
+		enable_partial_output(outq->head->worker);
+
+		// Set it to NULL since calling it twice is pointless.
+		outq->head->worker = NULL;
+	}
+
+	return;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.h
new file mode 100644
index 00000000000..25f071977a8
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/outqueue.h
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       outqueue.h
+/// \brief      Output queue handling in multithreaded coding
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_OUTQUEUE_H
+#define LZMA_OUTQUEUE_H
+
+#include "common.h"
+
+
+/// Output buffer for a single thread
+typedef struct lzma_outbuf_s lzma_outbuf;
+struct lzma_outbuf_s {
+	/// Pointer to the next buffer. This is used for the cached buffers.
+	/// The worker thread must not modify this.
+	lzma_outbuf *next;
+
+	/// This initialized by lzma_outq_get_buf() and
+	/// is used by lzma_outq_enable_partial_output().
+	/// The worker thread must not modify this.
+	void *worker;
+
+	/// Amount of memory allocated for buf[].
+	/// The worker thread must not modify this.
+	size_t allocated;
+
+	/// Writing position in the worker thread or, in other words, the
+	/// amount of finished data written to buf[] which can be copied out
+	///
+	/// \note       This is read by another thread and thus access
+	///             to this variable needs a mutex.
+	size_t pos;
+
+	/// Decompression: Position in the input buffer in the worker thread
+	/// that matches the output "pos" above. This is used to detect if
+	/// more output might be possible from the worker thread: if it has
+	/// consumed all its input, then more output isn't possible.
+	///
+	/// \note       This is read by another thread and thus access
+	///             to this variable needs a mutex.
+	size_t decoder_in_pos;
+
+	/// True when no more data will be written into this buffer.
+	///
+	/// \note       This is read by another thread and thus access
+	///             to this variable needs a mutex.
+	bool finished;
+
+	/// Return value for lzma_outq_read() when the last byte from
+	/// a finished buffer has been read. Defaults to LZMA_STREAM_END.
+	/// This must *not* be LZMA_OK. The idea is to allow a decoder to
+	/// pass an error code to the main thread, setting the code here
+	/// together with finished = true.
+	lzma_ret finish_ret;
+
+	/// Additional size information. lzma_outq_read() may read these
+	/// when "finished" is true.
+	lzma_vli unpadded_size;
+	lzma_vli uncompressed_size;
+
+	/// Buffer of "allocated" bytes
+	uint8_t buf[];
+};
+
+
+typedef struct {
+	/// Linked list of buffers in use. The next output byte will be
+	/// read from the head and buffers for the next thread will be
+	/// appended to the tail. tail->next is always NULL.
+	lzma_outbuf *head;
+	lzma_outbuf *tail;
+
+	/// Number of bytes read from head->buf[] in lzma_outq_read()
+	size_t read_pos;
+
+	/// Linked list of allocated buffers that aren't currently used.
+	/// This way buffers of similar size can be reused and don't
+	/// need to be reallocated every time. For simplicity, all
+	/// cached buffers in the list have the same allocated size.
+	lzma_outbuf *cache;
+
+	/// Total amount of memory allocated for buffers
+	uint64_t mem_allocated;
+
+	/// Amount of memory used by the buffers that are in use in
+	/// the head...tail linked list.
+	uint64_t mem_in_use;
+
+	/// Number of buffers in use in the head...tail list. If and only if
+	/// this is zero, the pointers head and tail above are NULL.
+	uint32_t bufs_in_use;
+
+	/// Number of buffers allocated (in use + cached)
+	uint32_t bufs_allocated;
+
+	/// Maximum allowed number of allocated buffers
+	uint32_t bufs_limit;
+} lzma_outq;
+
+
+/**
+ * \brief       Calculate the memory usage of an output queue
+ *
+ * \return      Approximate memory usage in bytes or UINT64_MAX on error.
+ */
+extern uint64_t lzma_outq_memusage(uint64_t buf_size_max, uint32_t threads);
+
+
+/// \brief      Initialize an output queue
+///
+/// \param      outq            Pointer to an output queue. Before calling
+///                             this function the first time, *outq should
+///                             have been zeroed with memzero() so that this
+///                             function knows that there are no previous
+///                             allocations to free.
+/// \param      allocator       Pointer to allocator or NULL
+/// \param      threads         Number of buffers that may be in use
+///                             concurrently. Note that more than this number
+///                             of buffers may actually get allocated to
+///                             improve performance when buffers finish
+///                             out of order. The actual maximum number of
+///                             allocated buffers is derived from the number
+///                             of threads.
+///
+/// \return     - LZMA_OK
+///             - LZMA_MEM_ERROR
+///
+extern lzma_ret lzma_outq_init(lzma_outq *outq,
+		const lzma_allocator *allocator, uint32_t threads);
+
+
+/// \brief      Free the memory associated with the output queue
+extern void lzma_outq_end(lzma_outq *outq, const lzma_allocator *allocator);
+
+
+/// \brief      Free all cached buffers that consume memory but aren't in use
+extern void lzma_outq_clear_cache(
+		lzma_outq *outq, const lzma_allocator *allocator);
+
+
+/// \brief      Like lzma_outq_clear_cache() but might keep one buffer
+///
+/// One buffer is not freed if its size is equal to keep_size.
+/// This is useful if the caller knows that it will soon need a buffer of
+/// keep_size bytes. This way it won't be freed and immediately reallocated.
+extern void lzma_outq_clear_cache2(
+		lzma_outq *outq, const lzma_allocator *allocator,
+		size_t keep_size);
+
+
+/// \brief      Preallocate a new buffer into cache
+///
+/// Splitting the buffer allocation into a separate function makes it
+/// possible to ensure that way lzma_outq_get_buf() cannot fail.
+/// If the preallocated buffer isn't actually used (for example, some
+/// other error occurs), the caller has to do nothing as the buffer will
+/// be used later or cleared from the cache when not needed.
+///
+/// \return     LZMA_OK on success, LZMA_MEM_ERROR if allocation fails
+///
+extern lzma_ret lzma_outq_prealloc_buf(
+		lzma_outq *outq, const lzma_allocator *allocator, size_t size);
+
+
+/// \brief      Get a new buffer
+///
+/// lzma_outq_prealloc_buf() must be used to ensure that there is a buffer
+/// available before calling lzma_outq_get_buf().
+///
+extern lzma_outbuf *lzma_outq_get_buf(lzma_outq *outq, void *worker);
+
+
+/// \brief      Test if there is data ready to be read
+///
+/// Call to this function must be protected with the same mutex that
+/// is used to protect lzma_outbuf.finished.
+///
+extern bool lzma_outq_is_readable(const lzma_outq *outq);
+
+
+/// \brief      Read finished data
+///
+/// \param      outq            Pointer to an output queue
+/// \param      out             Beginning of the output buffer
+/// \param      out_pos         The next byte will be written to
+///                             out[*out_pos].
+/// \param      out_size        Size of the out buffer; the first byte into
+///                             which no data is written to is out[out_size].
+/// \param      unpadded_size   Unpadded Size from the Block encoder
+/// \param      uncompressed_size Uncompressed Size from the Block encoder
+///
+/// \return     - LZMA: All OK. Either no data was available or the buffer
+///               being read didn't become empty yet.
+///             - LZMA_STREAM_END: The buffer being read was finished.
+///               *unpadded_size and *uncompressed_size were set if they
+///               were not NULL.
+///
+/// \note       This reads lzma_outbuf.finished and .pos variables and thus
+///             calls to this function need to be protected with a mutex.
+///
+extern lzma_ret lzma_outq_read(lzma_outq *restrict outq,
+		const lzma_allocator *restrict allocator,
+		uint8_t *restrict out, size_t *restrict out_pos,
+		size_t out_size, lzma_vli *restrict unpadded_size,
+		lzma_vli *restrict uncompressed_size);
+
+
+/// \brief      Enable partial output from a worker thread
+///
+/// If the buffer at the head of the output queue isn't finished,
+/// this will call enable_partial_output on the worker associated with
+/// that output buffer.
+///
+/// \note       This reads a lzma_outbuf.finished variable and thus
+///             calls to this function need to be protected with a mutex.
+///
+extern void lzma_outq_enable_partial_output(lzma_outq *outq,
+		void (*enable_partial_output)(void *worker));
+
+
+/// \brief      Test if there is at least one buffer free
+///
+/// This must be used before getting a new buffer with lzma_outq_get_buf().
+///
+static inline bool
+lzma_outq_has_buf(const lzma_outq *outq)
+{
+	return outq->bufs_in_use < outq->bufs_limit;
+}
+
+
+/// \brief      Test if the queue is completely empty
+static inline bool
+lzma_outq_is_empty(const lzma_outq *outq)
+{
+	return outq->bufs_in_use == 0;
+}
+
+
+/// \brief      Get the amount of memory needed for a single lzma_outbuf
+///
+/// \note       Caller must check that the argument is significantly less
+///             than SIZE_MAX to avoid an integer overflow!
+static inline uint64_t
+lzma_outq_outbuf_memusage(size_t buf_size)
+{
+	assert(buf_size <= SIZE_MAX - sizeof(lzma_outbuf));
+	return sizeof(lzma_outbuf) + buf_size;
+}
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_decoder.c
new file mode 100644
index 00000000000..c4f91fb4983
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_decoder.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       stream_buffer_decoder.c
+/// \brief      Single-call .xz Stream decoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "stream_decoder.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_buffer_decode(uint64_t *memlimit, uint32_t flags,
+		const lzma_allocator *allocator,
+		const uint8_t *in, size_t *in_pos, size_t in_size,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+{
+	// Sanity checks
+	if (in_pos == NULL || (in == NULL && *in_pos != in_size)
+			|| *in_pos > in_size || out_pos == NULL
+			|| (out == NULL && *out_pos != out_size)
+			|| *out_pos > out_size)
+		return LZMA_PROG_ERROR;
+
+	// Catch flags that are not allowed in buffer-to-buffer decoding.
+	if (flags & LZMA_TELL_ANY_CHECK)
+		return LZMA_PROG_ERROR;
+
+	// Initialize the Stream decoder.
+	// TODO: We need something to tell the decoder that it can use the
+	// output buffer as workspace, and thus save significant amount of RAM.
+	lzma_next_coder stream_decoder = LZMA_NEXT_CODER_INIT;
+	lzma_ret ret = lzma_stream_decoder_init(
+			&stream_decoder, allocator, *memlimit, flags);
+
+	if (ret == LZMA_OK) {
+		// Save the positions so that we can restore them in case
+		// an error occurs.
+		const size_t in_start = *in_pos;
+		const size_t out_start = *out_pos;
+
+		// Do the actual decoding.
+		ret = stream_decoder.code(stream_decoder.coder, allocator,
+				in, in_pos, in_size, out, out_pos, out_size,
+				LZMA_FINISH);
+
+		if (ret == LZMA_STREAM_END) {
+			ret = LZMA_OK;
+		} else {
+			// Something went wrong, restore the positions.
+			*in_pos = in_start;
+			*out_pos = out_start;
+
+			if (ret == LZMA_OK) {
+				// Either the input was truncated or the
+				// output buffer was too small.
+				assert(*in_pos == in_size
+						|| *out_pos == out_size);
+
+				// If all the input was consumed, then the
+				// input is truncated, even if the output
+				// buffer is also full. This is because
+				// processing the last byte of the Stream
+				// never produces output.
+				if (*in_pos == in_size)
+					ret = LZMA_DATA_ERROR;
+				else
+					ret = LZMA_BUF_ERROR;
+
+			} else if (ret == LZMA_MEMLIMIT_ERROR) {
+				// Let the caller know how much memory would
+				// have been needed.
+				uint64_t memusage;
+				(void)stream_decoder.memconfig(
+						stream_decoder.coder,
+						memlimit, &memusage, 0);
+			}
+		}
+	}
+
+	// Free the decoder memory. This needs to be done even if
+	// initialization fails, because the internal API doesn't
+	// require the initialization function to free its memory on error.
+	lzma_next_end(&stream_decoder, allocator);
+
+	return ret;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_encoder.c
new file mode 100644
index 00000000000..04d58695946
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_buffer_encoder.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       stream_buffer_encoder.c
+/// \brief      Single-call .xz Stream encoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+#include "index.h"
+
+
+/// Maximum size of Index that has exactly one Record.
+/// Index Indicator + Number of Records + Record + CRC32 rounded up to
+/// the next multiple of four.
+#define INDEX_BOUND ((1 + 1 + 2 * LZMA_VLI_BYTES_MAX + 4 + 3) & ~3)
+
+/// Stream Header, Stream Footer, and Index
+#define HEADERS_BOUND (2 * LZMA_STREAM_HEADER_SIZE + INDEX_BOUND)
+
+
+extern LZMA_API(size_t)
+lzma_stream_buffer_bound(size_t uncompressed_size)
+{
+	// Get the maximum possible size of a Block.
+	const size_t block_bound = lzma_block_buffer_bound(uncompressed_size);
+	if (block_bound == 0)
+		return 0;
+
+	// Catch the possible integer overflow and also prevent the size of
+	// the Stream exceeding LZMA_VLI_MAX (theoretically possible on
+	// 64-bit systems).
+	if (my_min(SIZE_MAX, LZMA_VLI_MAX) - block_bound < HEADERS_BOUND)
+		return 0;
+
+	return block_bound + HEADERS_BOUND;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_buffer_encode(lzma_filter *filters, lzma_check check,
+		const lzma_allocator *allocator,
+		const uint8_t *in, size_t in_size,
+		uint8_t *out, size_t *out_pos_ptr, size_t out_size)
+{
+	// Sanity checks
+	if (filters == NULL || (unsigned int)(check) > LZMA_CHECK_ID_MAX
+			|| (in == NULL && in_size != 0) || out == NULL
+			|| out_pos_ptr == NULL || *out_pos_ptr > out_size)
+		return LZMA_PROG_ERROR;
+
+	if (!lzma_check_is_supported(check))
+		return LZMA_UNSUPPORTED_CHECK;
+
+	// Note for the paranoids: Index encoder prevents the Stream from
+	// getting too big and still being accepted with LZMA_OK, and Block
+	// encoder catches if the input is too big. So we don't need to
+	// separately check if the buffers are too big.
+
+	// Use a local copy. We update *out_pos_ptr only if everything
+	// succeeds.
+	size_t out_pos = *out_pos_ptr;
+
+	// Check that there's enough space for both Stream Header and
+	// Stream Footer.
+	if (out_size - out_pos <= 2 * LZMA_STREAM_HEADER_SIZE)
+		return LZMA_BUF_ERROR;
+
+	// Reserve space for Stream Footer so we don't need to check for
+	// available space again before encoding Stream Footer.
+	out_size -= LZMA_STREAM_HEADER_SIZE;
+
+	// Encode the Stream Header.
+	lzma_stream_flags stream_flags = {
+		.version = 0,
+		.check = check,
+	};
+
+	if (lzma_stream_header_encode(&stream_flags, out + out_pos)
+			!= LZMA_OK)
+		return LZMA_PROG_ERROR;
+
+	out_pos += LZMA_STREAM_HEADER_SIZE;
+
+	// Encode a Block but only if there is at least one byte of input.
+	lzma_block block = {
+		.version = 0,
+		.check = check,
+		.filters = filters,
+	};
+
+	if (in_size > 0)
+		return_if_error(lzma_block_buffer_encode(&block, allocator,
+				in, in_size, out, &out_pos, out_size));
+
+	// Index
+	{
+		// Create an Index. It will have one Record if there was
+		// at least one byte of input to encode. Otherwise the
+		// Index will be empty.
+		lzma_index *i = lzma_index_init(allocator);
+		if (i == NULL)
+			return LZMA_MEM_ERROR;
+
+		lzma_ret ret = LZMA_OK;
+
+		if (in_size > 0)
+			ret = lzma_index_append(i, allocator,
+					lzma_block_unpadded_size(&block),
+					block.uncompressed_size);
+
+		// If adding the Record was successful, encode the Index
+		// and get its size which will be stored into Stream Footer.
+		if (ret == LZMA_OK) {
+			ret = lzma_index_buffer_encode(
+					i, out, &out_pos, out_size);
+
+			stream_flags.backward_size = lzma_index_size(i);
+		}
+
+		lzma_index_end(i, allocator);
+
+		if (ret != LZMA_OK)
+			return ret;
+	}
+
+	// Stream Footer. We have already reserved space for this.
+	if (lzma_stream_footer_encode(&stream_flags, out + out_pos)
+			!= LZMA_OK)
+		return LZMA_PROG_ERROR;
+
+	out_pos += LZMA_STREAM_HEADER_SIZE;
+
+	// Everything went fine, make the new output position available
+	// to the application.
+	*out_pos_ptr = out_pos;
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.c
new file mode 100644
index 00000000000..7f426841366
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.c
@@ -0,0 +1,473 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       stream_decoder.c
+/// \brief      Decodes .xz Streams
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "stream_decoder.h"
+#include "block_decoder.h"
+#include "index.h"
+
+
+typedef struct {
+	enum {
+		SEQ_STREAM_HEADER,
+		SEQ_BLOCK_HEADER,
+		SEQ_BLOCK_INIT,
+		SEQ_BLOCK_RUN,
+		SEQ_INDEX,
+		SEQ_STREAM_FOOTER,
+		SEQ_STREAM_PADDING,
+	} sequence;
+
+	/// Block decoder
+	lzma_next_coder block_decoder;
+
+	/// Block options decoded by the Block Header decoder and used by
+	/// the Block decoder.
+	lzma_block block_options;
+
+	/// Stream Flags from Stream Header
+	lzma_stream_flags stream_flags;
+
+	/// Index is hashed so that it can be compared to the sizes of Blocks
+	/// with O(1) memory usage.
+	lzma_index_hash *index_hash;
+
+	/// Memory usage limit
+	uint64_t memlimit;
+
+	/// Amount of memory actually needed (only an estimate)
+	uint64_t memusage;
+
+	/// If true, LZMA_NO_CHECK is returned if the Stream has
+	/// no integrity check.
+	bool tell_no_check;
+
+	/// If true, LZMA_UNSUPPORTED_CHECK is returned if the Stream has
+	/// an integrity check that isn't supported by this liblzma build.
+	bool tell_unsupported_check;
+
+	/// If true, LZMA_GET_CHECK is returned after decoding Stream Header.
+	bool tell_any_check;
+
+	/// If true, we will tell the Block decoder to skip calculating
+	/// and verifying the integrity check.
+	bool ignore_check;
+
+	/// If true, we will decode concatenated Streams that possibly have
+	/// Stream Padding between or after them. LZMA_STREAM_END is returned
+	/// once the application isn't giving us any new input (LZMA_FINISH),
+	/// and we aren't in the middle of a Stream, and possible
+	/// Stream Padding is a multiple of four bytes.
+	bool concatenated;
+
+	/// When decoding concatenated Streams, this is true as long as we
+	/// are decoding the first Stream. This is needed to avoid misleading
+	/// LZMA_FORMAT_ERROR in case the later Streams don't have valid magic
+	/// bytes.
+	bool first_stream;
+
+	/// Write position in buffer[] and position in Stream Padding
+	size_t pos;
+
+	/// Buffer to hold Stream Header, Block Header, and Stream Footer.
+	/// Block Header has biggest maximum size.
+	uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX];
+} lzma_stream_coder;
+
+
+static lzma_ret
+stream_decoder_reset(lzma_stream_coder *coder, const lzma_allocator *allocator)
+{
+	// Initialize the Index hash used to verify the Index.
+	coder->index_hash = lzma_index_hash_init(coder->index_hash, allocator);
+	if (coder->index_hash == NULL)
+		return LZMA_MEM_ERROR;
+
+	// Reset the rest of the variables.
+	coder->sequence = SEQ_STREAM_HEADER;
+	coder->pos = 0;
+
+	return LZMA_OK;
+}
+
+
+static lzma_ret
+stream_decode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size, lzma_action action)
+{
+	lzma_stream_coder *coder = coder_ptr;
+
+	// When decoding the actual Block, it may be able to produce more
+	// output even if we don't give it any new input.
+	while (true)
+	switch (coder->sequence) {
+	case SEQ_STREAM_HEADER: {
+		// Copy the Stream Header to the internal buffer.
+		lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
+				LZMA_STREAM_HEADER_SIZE);
+
+		// Return if we didn't get the whole Stream Header yet.
+		if (coder->pos < LZMA_STREAM_HEADER_SIZE)
+			return LZMA_OK;
+
+		coder->pos = 0;
+
+		// Decode the Stream Header.
+		const lzma_ret ret = lzma_stream_header_decode(
+				&coder->stream_flags, coder->buffer);
+		if (ret != LZMA_OK)
+			return ret == LZMA_FORMAT_ERROR && !coder->first_stream
+					? LZMA_DATA_ERROR : ret;
+
+		// If we are decoding concatenated Streams, and the later
+		// Streams have invalid Header Magic Bytes, we give
+		// LZMA_DATA_ERROR instead of LZMA_FORMAT_ERROR.
+		coder->first_stream = false;
+
+		// Copy the type of the Check so that Block Header and Block
+		// decoders see it.
+		coder->block_options.check = coder->stream_flags.check;
+
+		// Even if we return LZMA_*_CHECK below, we want
+		// to continue from Block Header decoding.
+		coder->sequence = SEQ_BLOCK_HEADER;
+
+		// Detect if there's no integrity check or if it is
+		// unsupported if those were requested by the application.
+		if (coder->tell_no_check && coder->stream_flags.check
+				== LZMA_CHECK_NONE)
+			return LZMA_NO_CHECK;
+
+		if (coder->tell_unsupported_check
+				&& !lzma_check_is_supported(
+					coder->stream_flags.check))
+			return LZMA_UNSUPPORTED_CHECK;
+
+		if (coder->tell_any_check)
+			return LZMA_GET_CHECK;
+	}
+
+	// Fall through
+
+	case SEQ_BLOCK_HEADER: {
+		if (*in_pos >= in_size)
+			return LZMA_OK;
+
+		if (coder->pos == 0) {
+			// Detect if it's Index.
+			if (in[*in_pos] == INDEX_INDICATOR) {
+				coder->sequence = SEQ_INDEX;
+				break;
+			}
+
+			// Calculate the size of the Block Header. Note that
+			// Block Header decoder wants to see this byte too
+			// so don't advance *in_pos.
+			coder->block_options.header_size
+					= lzma_block_header_size_decode(
+						in[*in_pos]);
+		}
+
+		// Copy the Block Header to the internal buffer.
+		lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
+				coder->block_options.header_size);
+
+		// Return if we didn't get the whole Block Header yet.
+		if (coder->pos < coder->block_options.header_size)
+			return LZMA_OK;
+
+		coder->pos = 0;
+		coder->sequence = SEQ_BLOCK_INIT;
+	}
+
+	// Fall through
+
+	case SEQ_BLOCK_INIT: {
+		// Checking memusage and doing the initialization needs
+		// its own sequence point because we need to be able to
+		// retry if we return LZMA_MEMLIMIT_ERROR.
+
+		// Version 1 is needed to support the .ignore_check option.
+		coder->block_options.version = 1;
+
+		// Set up a buffer to hold the filter chain. Block Header
+		// decoder will initialize all members of this array so
+		// we don't need to do it here.
+		lzma_filter filters[LZMA_FILTERS_MAX + 1];
+		coder->block_options.filters = filters;
+
+		// Decode the Block Header.
+		return_if_error(lzma_block_header_decode(&coder->block_options,
+				allocator, coder->buffer));
+
+		// If LZMA_IGNORE_CHECK was used, this flag needs to be set.
+		// It has to be set after lzma_block_header_decode() because
+		// it always resets this to false.
+		coder->block_options.ignore_check = coder->ignore_check;
+
+		// Check the memory usage limit.
+		const uint64_t memusage = lzma_raw_decoder_memusage(filters);
+		lzma_ret ret;
+
+		if (memusage == UINT64_MAX) {
+			// One or more unknown Filter IDs.
+			ret = LZMA_OPTIONS_ERROR;
+		} else {
+			// Now we can set coder->memusage since we know that
+			// the filter chain is valid. We don't want
+			// lzma_memusage() to return UINT64_MAX in case of
+			// invalid filter chain.
+			coder->memusage = memusage;
+
+			if (memusage > coder->memlimit) {
+				// The chain would need too much memory.
+				ret = LZMA_MEMLIMIT_ERROR;
+			} else {
+				// Memory usage is OK.
+				// Initialize the Block decoder.
+				ret = lzma_block_decoder_init(
+						&coder->block_decoder,
+						allocator,
+						&coder->block_options);
+			}
+		}
+
+		// Free the allocated filter options since they are needed
+		// only to initialize the Block decoder.
+		lzma_filters_free(filters, allocator);
+		coder->block_options.filters = NULL;
+
+		// Check if memory usage calculation and Block decoder
+		// initialization succeeded.
+		if (ret != LZMA_OK)
+			return ret;
+
+		coder->sequence = SEQ_BLOCK_RUN;
+	}
+
+	// Fall through
+
+	case SEQ_BLOCK_RUN: {
+		const lzma_ret ret = coder->block_decoder.code(
+				coder->block_decoder.coder, allocator,
+				in, in_pos, in_size, out, out_pos, out_size,
+				action);
+
+		if (ret != LZMA_STREAM_END)
+			return ret;
+
+		// Block decoded successfully. Add the new size pair to
+		// the Index hash.
+		return_if_error(lzma_index_hash_append(coder->index_hash,
+				lzma_block_unpadded_size(
+					&coder->block_options),
+				coder->block_options.uncompressed_size));
+
+		coder->sequence = SEQ_BLOCK_HEADER;
+		break;
+	}
+
+	case SEQ_INDEX: {
+		// If we don't have any input, don't call
+		// lzma_index_hash_decode() since it would return
+		// LZMA_BUF_ERROR, which we must not do here.
+		if (*in_pos >= in_size)
+			return LZMA_OK;
+
+		// Decode the Index and compare it to the hash calculated
+		// from the sizes of the Blocks (if any).
+		const lzma_ret ret = lzma_index_hash_decode(coder->index_hash,
+				in, in_pos, in_size);
+		if (ret != LZMA_STREAM_END)
+			return ret;
+
+		coder->sequence = SEQ_STREAM_FOOTER;
+	}
+
+	// Fall through
+
+	case SEQ_STREAM_FOOTER: {
+		// Copy the Stream Footer to the internal buffer.
+		lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
+				LZMA_STREAM_HEADER_SIZE);
+
+		// Return if we didn't get the whole Stream Footer yet.
+		if (coder->pos < LZMA_STREAM_HEADER_SIZE)
+			return LZMA_OK;
+
+		coder->pos = 0;
+
+		// Decode the Stream Footer. The decoder gives
+		// LZMA_FORMAT_ERROR if the magic bytes don't match,
+		// so convert that return code to LZMA_DATA_ERROR.
+		lzma_stream_flags footer_flags;
+		const lzma_ret ret = lzma_stream_footer_decode(
+				&footer_flags, coder->buffer);
+		if (ret != LZMA_OK)
+			return ret == LZMA_FORMAT_ERROR
+					? LZMA_DATA_ERROR : ret;
+
+		// Check that Index Size stored in the Stream Footer matches
+		// the real size of the Index field.
+		if (lzma_index_hash_size(coder->index_hash)
+				!= footer_flags.backward_size)
+			return LZMA_DATA_ERROR;
+
+		// Compare that the Stream Flags fields are identical in
+		// both Stream Header and Stream Footer.
+		return_if_error(lzma_stream_flags_compare(
+				&coder->stream_flags, &footer_flags));
+
+		if (!coder->concatenated)
+			return LZMA_STREAM_END;
+
+		coder->sequence = SEQ_STREAM_PADDING;
+	}
+
+	// Fall through
+
+	case SEQ_STREAM_PADDING:
+		assert(coder->concatenated);
+
+		// Skip over possible Stream Padding.
+		while (true) {
+			if (*in_pos >= in_size) {
+				// Unless LZMA_FINISH was used, we cannot
+				// know if there's more input coming later.
+				if (action != LZMA_FINISH)
+					return LZMA_OK;
+
+				// Stream Padding must be a multiple of
+				// four bytes.
+				return coder->pos == 0
+						? LZMA_STREAM_END
+						: LZMA_DATA_ERROR;
+			}
+
+			// If the byte is not zero, it probably indicates
+			// beginning of a new Stream (or the file is corrupt).
+			if (in[*in_pos] != 0x00)
+				break;
+
+			++*in_pos;
+			coder->pos = (coder->pos + 1) & 3;
+		}
+
+		// Stream Padding must be a multiple of four bytes (empty
+		// Stream Padding is OK).
+		if (coder->pos != 0) {
+			++*in_pos;
+			return LZMA_DATA_ERROR;
+		}
+
+		// Prepare to decode the next Stream.
+		return_if_error(stream_decoder_reset(coder, allocator));
+		break;
+
+	default:
+		assert(0);
+		return LZMA_PROG_ERROR;
+	}
+
+	// Never reached
+}
+
+
+static void
+stream_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_stream_coder *coder = coder_ptr;
+	lzma_next_end(&coder->block_decoder, allocator);
+	lzma_index_hash_end(coder->index_hash, allocator);
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_check
+stream_decoder_get_check(const void *coder_ptr)
+{
+	const lzma_stream_coder *coder = coder_ptr;
+	return coder->stream_flags.check;
+}
+
+
+static lzma_ret
+stream_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
+		uint64_t *old_memlimit, uint64_t new_memlimit)
+{
+	lzma_stream_coder *coder = coder_ptr;
+
+	*memusage = coder->memusage;
+	*old_memlimit = coder->memlimit;
+
+	if (new_memlimit != 0) {
+		if (new_memlimit < coder->memusage)
+			return LZMA_MEMLIMIT_ERROR;
+
+		coder->memlimit = new_memlimit;
+	}
+
+	return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_stream_decoder_init(
+		lzma_next_coder *next, const lzma_allocator *allocator,
+		uint64_t memlimit, uint32_t flags)
+{
+	lzma_next_coder_init(&lzma_stream_decoder_init, next, allocator);
+
+	if (flags & ~LZMA_SUPPORTED_FLAGS)
+		return LZMA_OPTIONS_ERROR;
+
+	lzma_stream_coder *coder = next->coder;
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_stream_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+		next->code = &stream_decode;
+		next->end = &stream_decoder_end;
+		next->get_check = &stream_decoder_get_check;
+		next->memconfig = &stream_decoder_memconfig;
+
+		coder->block_decoder = LZMA_NEXT_CODER_INIT;
+		coder->index_hash = NULL;
+	}
+
+	coder->memlimit = my_max(1, memlimit);
+	coder->memusage = LZMA_MEMUSAGE_BASE;
+	coder->tell_no_check = (flags & LZMA_TELL_NO_CHECK) != 0;
+	coder->tell_unsupported_check
+			= (flags & LZMA_TELL_UNSUPPORTED_CHECK) != 0;
+	coder->tell_any_check = (flags & LZMA_TELL_ANY_CHECK) != 0;
+	coder->ignore_check = (flags & LZMA_IGNORE_CHECK) != 0;
+	coder->concatenated = (flags & LZMA_CONCATENATED) != 0;
+	coder->first_stream = true;
+
+	return stream_decoder_reset(coder, allocator);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)
+{
+	lzma_next_strm_init(lzma_stream_decoder_init, strm, memlimit, flags);
+
+	strm->internal->supported_actions[LZMA_RUN] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.h
new file mode 100644
index 00000000000..5803715374d
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       stream_decoder.h
+/// \brief      Decodes .xz Streams
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_STREAM_DECODER_H
+#define LZMA_STREAM_DECODER_H
+
+#include "common.h"
+
+extern lzma_ret lzma_stream_decoder_init(
+		lzma_next_coder *next, const lzma_allocator *allocator,
+		uint64_t memlimit, uint32_t flags);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder_mt.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder_mt.c
new file mode 100644
index 00000000000..244624a4790
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_decoder_mt.c
@@ -0,0 +1,2017 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       stream_decoder_mt.c
+/// \brief      Multithreaded .xz Stream decoder
+//
+//  Authors:    Sebastian Andrzej Siewior
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+#include "block_decoder.h"
+#include "stream_decoder.h"
+#include "index.h"
+#include "outqueue.h"
+
+
+typedef enum {
+	/// Waiting for work.
+	/// Main thread may change this to THR_RUN or THR_EXIT.
+	THR_IDLE,
+
+	/// Decoding is in progress.
+	/// Main thread may change this to THR_STOP or THR_EXIT.
+	/// The worker thread may change this to THR_IDLE.
+	THR_RUN,
+
+	/// The main thread wants the thread to stop whatever it was doing
+	/// but not exit. Main thread may change this to THR_EXIT.
+	/// The worker thread may change this to THR_IDLE.
+	THR_STOP,
+
+	/// The main thread wants the thread to exit.
+	THR_EXIT,
+
+} worker_state;
+
+
+typedef enum {
+	/// Partial updates (storing of worker thread progress
+	/// to lzma_outbuf) are disabled.
+	PARTIAL_DISABLED,
+
+	/// Main thread requests partial updates to be enabled but
+	/// no partial update has been done by the worker thread yet.
+	///
+	/// Changing from PARTIAL_DISABLED to PARTIAL_START requires
+	/// use of the worker-thread mutex. Other transitions don't
+	/// need a mutex.
+	PARTIAL_START,
+
+	/// Partial updates are enabled and the worker thread has done
+	/// at least one partial update.
+	PARTIAL_ENABLED,
+
+} partial_update_mode;
+
+
+struct worker_thread {
+	/// Worker state is protected with our mutex.
+	worker_state state;
+
+	/// Input buffer that will contain the whole Block except Block Header.
+	uint8_t *in;
+
+	/// Amount of memory allocated for "in"
+	size_t in_size;
+
+	/// Number of bytes written to "in" by the main thread
+	size_t in_filled;
+
+	/// Number of bytes consumed from "in" by the worker thread.
+	size_t in_pos;
+
+	/// Amount of uncompressed data that has been decoded. This local
+	/// copy is needed because updating outbuf->pos requires locking
+	/// the main mutex (coder->mutex).
+	size_t out_pos;
+
+	/// Pointer to the main structure is needed to (1) lock the main
+	/// mutex (coder->mutex) when updating outbuf->pos and (2) when
+	/// putting this thread back to the stack of free threads.
+	struct lzma_stream_coder *coder;
+
+	/// The allocator is set by the main thread. Since a copy of the
+	/// pointer is kept here, the application must not change the
+	/// allocator before calling lzma_end().
+	const lzma_allocator *allocator;
+
+	/// Output queue buffer to which the uncompressed data is written.
+	lzma_outbuf *outbuf;
+
+	/// Amount of compressed data that has already been decompressed.
+	/// This is updated from in_pos when our mutex is locked.
+	/// This is size_t, not uint64_t, because per-thread progress
+	/// is limited to sizes of allocated buffers.
+	size_t progress_in;
+
+	/// Like progress_in but for uncompressed data.
+	size_t progress_out;
+
+	/// Updating outbuf->pos requires locking the main mutex
+	/// (coder->mutex). Since the main thread will only read output
+	/// from the oldest outbuf in the queue, only the worker thread
+	/// that is associated with the oldest outbuf needs to update its
+	/// outbuf->pos. This avoids useless mutex contention that would
+	/// happen if all worker threads were frequently locking the main
+	/// mutex to update their outbuf->pos.
+	///
+	/// Only when partial_update is something else than PARTIAL_DISABLED,
+	/// this worker thread will update outbuf->pos after each call to
+	/// the Block decoder.
+	partial_update_mode partial_update;
+
+	/// Block decoder
+	lzma_next_coder block_decoder;
+
+	/// Thread-specific Block options are needed because the Block
+	/// decoder modifies the struct given to it at initialization.
+	lzma_block block_options;
+
+	/// Filter chain memory usage
+	uint64_t mem_filters;
+
+	/// Next structure in the stack of free worker threads.
+	struct worker_thread *next;
+
+	mythread_mutex mutex;
+	mythread_cond cond;
+
+	/// The ID of this thread is used to join the thread
+	/// when it's not needed anymore.
+	mythread thread_id;
+};
+
+
+struct lzma_stream_coder {
+	enum {
+		SEQ_STREAM_HEADER,
+		SEQ_BLOCK_HEADER,
+		SEQ_BLOCK_INIT,
+		SEQ_BLOCK_THR_INIT,
+		SEQ_BLOCK_THR_RUN,
+		SEQ_BLOCK_DIRECT_INIT,
+		SEQ_BLOCK_DIRECT_RUN,
+		SEQ_INDEX_WAIT_OUTPUT,
+		SEQ_INDEX_DECODE,
+		SEQ_STREAM_FOOTER,
+		SEQ_STREAM_PADDING,
+		SEQ_ERROR,
+	} sequence;
+
+	/// Block decoder
+	lzma_next_coder block_decoder;
+
+	/// Every Block Header will be decoded into this structure.
+	/// This is also used to initialize a Block decoder when in
+	/// direct mode. In threaded mode, a thread-specific copy will
+	/// be made for decoder initialization because the Block decoder
+	/// will modify the structure given to it.
+	lzma_block block_options;
+
+	/// Buffer to hold a filter chain for Block Header decoding and
+	/// initialization. These are freed after successful Block decoder
+	/// initialization or at stream_decoder_mt_end(). The thread-specific
+	/// copy of block_options won't hold a pointer to filters[] after
+	/// initialization.
+	lzma_filter filters[LZMA_FILTERS_MAX + 1];
+
+	/// Stream Flags from Stream Header
+	lzma_stream_flags stream_flags;
+
+	/// Index is hashed so that it can be compared to the sizes of Blocks
+	/// with O(1) memory usage.
+	lzma_index_hash *index_hash;
+
+
+	/// Maximum wait time if cannot use all the input and cannot
+	/// fill the output buffer. This is in milliseconds.
+	uint32_t timeout;
+
+
+	/// Error code from a worker thread.
+	///
+	/// \note       Use mutex.
+	lzma_ret thread_error;
+
+	/// Error code to return after pending output has been copied out. If
+	/// set in read_output_and_wait(), this is a mirror of thread_error.
+	/// If set in stream_decode_mt() then it's, for example, error that
+	/// occurred when decoding Block Header.
+	lzma_ret pending_error;
+
+	/// Number of threads that will be created at maximum.
+	uint32_t threads_max;
+
+	/// Number of thread structures that have been initialized from
+	/// "threads", and thus the number of worker threads actually
+	/// created so far.
+	uint32_t threads_initialized;
+
+	/// Array of allocated thread-specific structures. When no threads
+	/// are in use (direct mode) this is NULL. In threaded mode this
+	/// points to an array of threads_max number of worker_thread structs.
+	struct worker_thread *threads;
+
+	/// Stack of free threads. When a thread finishes, it puts itself
+	/// back into this stack. This starts as empty because threads
+	/// are created only when actually needed.
+	///
+	/// \note       Use mutex.
+	struct worker_thread *threads_free;
+
+	/// The most recent worker thread to which the main thread writes
+	/// the new input from the application.
+	struct worker_thread *thr;
+
+	/// Output buffer queue for decompressed data from the worker threads
+	///
+	/// \note       Use mutex with operations that need it.
+	lzma_outq outq;
+
+	mythread_mutex mutex;
+	mythread_cond cond;
+
+
+	/// Memory usage that will not be exceeded in multi-threaded mode.
+	/// Single-threaded mode can exceed this even by a large amount.
+	uint64_t memlimit_threading;
+
+	/// Memory usage limit that should never be exceeded.
+	/// LZMA_MEMLIMIT_ERROR will be returned if decoding isn't possible
+	/// even in single-threaded mode without exceeding this limit.
+	uint64_t memlimit_stop;
+
+	/// Amount of memory in use by the direct mode decoder
+	/// (coder->block_decoder). In threaded mode this is 0.
+	uint64_t mem_direct_mode;
+
+	/// Amount of memory needed by the running worker threads.
+	/// This doesn't include the memory needed by the output buffer.
+	///
+	/// \note       Use mutex.
+	uint64_t mem_in_use;
+
+	/// Amount of memory used by the idle (cached) threads.
+	///
+	/// \note       Use mutex.
+	uint64_t mem_cached;
+
+
+	/// Amount of memory needed for the filter chain of the next Block.
+	uint64_t mem_next_filters;
+
+	/// Amount of memory needed for the thread-specific input buffer
+	/// for the next Block.
+	uint64_t mem_next_in;
+
+	/// Amount of memory actually needed to decode the next Block
+	/// in threaded mode. This is
+	/// mem_next_filters + mem_next_in + memory needed for lzma_outbuf.
+	uint64_t mem_next_block;
+
+
+	/// Amount of compressed data in Stream Header + Blocks that have
+	/// already been finished.
+	///
+	/// \note       Use mutex.
+	uint64_t progress_in;
+
+	/// Amount of uncompressed data in Blocks that have already
+	/// been finished.
+	///
+	/// \note       Use mutex.
+	uint64_t progress_out;
+
+
+	/// If true, LZMA_NO_CHECK is returned if the Stream has
+	/// no integrity check.
+	bool tell_no_check;
+
+	/// If true, LZMA_UNSUPPORTED_CHECK is returned if the Stream has
+	/// an integrity check that isn't supported by this liblzma build.
+	bool tell_unsupported_check;
+
+	/// If true, LZMA_GET_CHECK is returned after decoding Stream Header.
+	bool tell_any_check;
+
+	/// If true, we will tell the Block decoder to skip calculating
+	/// and verifying the integrity check.
+	bool ignore_check;
+
+	/// If true, we will decode concatenated Streams that possibly have
+	/// Stream Padding between or after them. LZMA_STREAM_END is returned
+	/// once the application isn't giving us any new input (LZMA_FINISH),
+	/// and we aren't in the middle of a Stream, and possible
+	/// Stream Padding is a multiple of four bytes.
+	bool concatenated;
+
+	/// If true, we will return any errors immediately instead of first
+	/// producing all output before the location of the error.
+	bool fail_fast;
+
+
+	/// When decoding concatenated Streams, this is true as long as we
+	/// are decoding the first Stream. This is needed to avoid misleading
+	/// LZMA_FORMAT_ERROR in case the later Streams don't have valid magic
+	/// bytes.
+	bool first_stream;
+
+	/// This is used to track if the previous call to stream_decode_mt()
+	/// had output space (*out_pos < out_size) and managed to fill the
+	/// output buffer (*out_pos == out_size). This may be set to true
+	/// in read_output_and_wait(). This is read and then reset to false
+	/// at the beginning of stream_decode_mt().
+	///
+	/// This is needed to support applications that call lzma_code() in
+	/// such a way that more input is provided only when lzma_code()
+	/// didn't fill the output buffer completely. Basically, this makes
+	/// it easier to convert such applications from single-threaded
+	/// decoder to multi-threaded decoder.
+	bool out_was_filled;
+
+	/// Write position in buffer[] and position in Stream Padding
+	size_t pos;
+
+	/// Buffer to hold Stream Header, Block Header, and Stream Footer.
+	/// Block Header has biggest maximum size.
+	uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX];
+};
+
+
+/// Enables updating of outbuf->pos. This is a callback function that is
+/// used with lzma_outq_enable_partial_output().
+static void
+worker_enable_partial_update(void *thr_ptr)
+{
+	struct worker_thread *thr = thr_ptr;
+
+	mythread_sync(thr->mutex) {
+		thr->partial_update = PARTIAL_START;
+		mythread_cond_signal(&thr->cond);
+	}
+}
+
+
+/// Things do to at THR_STOP or when finishing a Block.
+/// This is called with thr->mutex locked.
+static void
+worker_stop(struct worker_thread *thr)
+{
+	// Update memory usage counters.
+	thr->coder->mem_in_use -= thr->in_size;
+	thr->in_size = 0; // thr->in was freed above.
+
+	thr->coder->mem_in_use -= thr->mem_filters;
+	thr->coder->mem_cached += thr->mem_filters;
+
+	// Put this thread to the stack of free threads.
+	thr->next = thr->coder->threads_free;
+	thr->coder->threads_free = thr;
+
+	mythread_cond_signal(&thr->coder->cond);
+	return;
+}
+
+
+static MYTHREAD_RET_TYPE
+worker_decoder(void *thr_ptr)
+{
+	struct worker_thread *thr = thr_ptr;
+	size_t in_filled;
+	partial_update_mode partial_update;
+	lzma_ret ret;
+
+next_loop_lock:
+
+	mythread_mutex_lock(&thr->mutex);
+next_loop_unlocked:
+
+	if (thr->state == THR_IDLE) {
+		mythread_cond_wait(&thr->cond, &thr->mutex);
+		goto next_loop_unlocked;
+	}
+
+	if (thr->state == THR_EXIT) {
+		mythread_mutex_unlock(&thr->mutex);
+
+		lzma_free(thr->in, thr->allocator);
+		lzma_next_end(&thr->block_decoder, thr->allocator);
+
+		mythread_mutex_destroy(&thr->mutex);
+		mythread_cond_destroy(&thr->cond);
+
+		return MYTHREAD_RET_VALUE;
+	}
+
+	if (thr->state == THR_STOP) {
+		thr->state = THR_IDLE;
+		mythread_mutex_unlock(&thr->mutex);
+
+		mythread_sync(thr->coder->mutex) {
+			worker_stop(thr);
+		}
+
+		goto next_loop_lock;
+	}
+
+	assert(thr->state == THR_RUN);
+
+	// Update progress info for get_progress().
+	thr->progress_in = thr->in_pos;
+	thr->progress_out = thr->out_pos;
+
+	// If we don't have any new input, wait for a signal from the main
+	// thread except if partial output has just been enabled. In that
+	// case we will do one normal run so that the partial output info
+	// gets passed to the main thread. The call to block_decoder.code()
+	// is useless but harmless as it can occur only once per Block.
+	in_filled = thr->in_filled;
+	partial_update = thr->partial_update;
+
+	if (in_filled == thr->in_pos && partial_update != PARTIAL_START) {
+		mythread_cond_wait(&thr->cond, &thr->mutex);
+		goto next_loop_unlocked;
+	}
+
+	mythread_mutex_unlock(&thr->mutex);
+
+	// Pass the input in small chunks to the Block decoder.
+	// This way we react reasonably fast if we are told to stop/exit,
+	// and (when partial update is enabled) we tell about our progress
+	// to the main thread frequently enough.
+	const size_t chunk_size = 16384;
+	if ((in_filled - thr->in_pos) > chunk_size)
+		in_filled = thr->in_pos + chunk_size;
+
+	ret = thr->block_decoder.code(
+			thr->block_decoder.coder, thr->allocator,
+			thr->in, &thr->in_pos, in_filled,
+			thr->outbuf->buf, &thr->out_pos,
+			thr->outbuf->allocated, LZMA_RUN);
+
+	if (ret == LZMA_OK) {
+		if (partial_update != PARTIAL_DISABLED) {
+			// The main thread uses thr->mutex to change from
+			// PARTIAL_DISABLED to PARTIAL_START. The main thread
+			// doesn't care about this variable after that so we
+			// can safely change it here to PARTIAL_ENABLED
+			// without a mutex.
+			thr->partial_update = PARTIAL_ENABLED;
+
+			// The main thread is reading decompressed data
+			// from thr->outbuf. Tell the main thread about
+			// our progress.
+			//
+			// NOTE: It's possible that we consumed input without
+			// producing any new output so it's possible that
+			// only in_pos has changed. In case of PARTIAL_START
+			// it is possible that neither in_pos nor out_pos has
+			// changed.
+			mythread_sync(thr->coder->mutex) {
+				thr->outbuf->pos = thr->out_pos;
+				thr->outbuf->decoder_in_pos = thr->in_pos;
+				mythread_cond_signal(&thr->coder->cond);
+			}
+		}
+
+		goto next_loop_lock;
+	}
+
+	// Either we finished successfully (LZMA_STREAM_END) or an error
+	// occurred. Both cases are handled almost identically. The error
+	// case requires updating thr->coder->thread_error.
+	//
+	// The sizes are in the Block Header and the Block decoder
+	// checks that they match, thus we know these:
+	assert(ret != LZMA_STREAM_END || thr->in_pos == thr->in_size);
+	assert(ret != LZMA_STREAM_END
+		|| thr->out_pos == thr->block_options.uncompressed_size);
+
+	// Free the input buffer. Don't update in_size as we need
+	// it later to update thr->coder->mem_in_use.
+	lzma_free(thr->in, thr->allocator);
+	thr->in = NULL;
+
+	mythread_sync(thr->mutex) {
+		if (thr->state != THR_EXIT)
+			thr->state = THR_IDLE;
+	}
+
+	mythread_sync(thr->coder->mutex) {
+		// Move our progress info to the main thread.
+		thr->coder->progress_in += thr->in_pos;
+		thr->coder->progress_out += thr->out_pos;
+		thr->progress_in = 0;
+		thr->progress_out = 0;
+
+		// Mark the outbuf as finished.
+		thr->outbuf->pos = thr->out_pos;
+		thr->outbuf->decoder_in_pos = thr->in_pos;
+		thr->outbuf->finished = true;
+		thr->outbuf->finish_ret = ret;
+		thr->outbuf = NULL;
+
+		// If an error occurred, tell it to the main thread.
+		if (ret != LZMA_STREAM_END
+				&& thr->coder->thread_error == LZMA_OK)
+			thr->coder->thread_error = ret;
+
+		worker_stop(thr);
+	}
+
+	goto next_loop_lock;
+}
+
+
+/// Tells the worker threads to exit and waits for them to terminate.
+static void
+threads_end(struct lzma_stream_coder *coder, const lzma_allocator *allocator)
+{
+	for (uint32_t i = 0; i < coder->threads_initialized; ++i) {
+		mythread_sync(coder->threads[i].mutex) {
+			coder->threads[i].state = THR_EXIT;
+			mythread_cond_signal(&coder->threads[i].cond);
+		}
+	}
+
+	for (uint32_t i = 0; i < coder->threads_initialized; ++i)
+		mythread_join(coder->threads[i].thread_id);
+
+	lzma_free(coder->threads, allocator);
+	coder->threads_initialized = 0;
+	coder->threads = NULL;
+	coder->threads_free = NULL;
+
+	// The threads don't update these when they exit. Do it here.
+	coder->mem_in_use = 0;
+	coder->mem_cached = 0;
+
+	return;
+}
+
+
+static void
+threads_stop(struct lzma_stream_coder *coder)
+{
+	for (uint32_t i = 0; i < coder->threads_initialized; ++i) {
+		mythread_sync(coder->threads[i].mutex) {
+			// The state must be changed conditionally because
+			// THR_IDLE -> THR_STOP is not a valid state change.
+			if (coder->threads[i].state != THR_IDLE) {
+				coder->threads[i].state = THR_STOP;
+				mythread_cond_signal(&coder->threads[i].cond);
+			}
+		}
+	}
+
+	return;
+}
+
+
+/// Initialize a new worker_thread structure and create a new thread.
+static lzma_ret
+initialize_new_thread(struct lzma_stream_coder *coder,
+		const lzma_allocator *allocator)
+{
+	// Allocate the coder->threads array if needed. It's done here instead
+	// of when initializing the decoder because we don't need this if we
+	// use the direct mode (we may even free coder->threads in the middle
+	// of the file if we switch from threaded to direct mode).
+	if (coder->threads == NULL) {
+		coder->threads = lzma_alloc(
+			coder->threads_max * sizeof(struct worker_thread),
+			allocator);
+
+		if (coder->threads == NULL)
+			return LZMA_MEM_ERROR;
+	}
+
+	// Pick a free structure.
+	assert(coder->threads_initialized < coder->threads_max);
+	struct worker_thread *thr
+			= &coder->threads[coder->threads_initialized];
+
+	if (mythread_mutex_init(&thr->mutex))
+		goto error_mutex;
+
+	if (mythread_cond_init(&thr->cond))
+		goto error_cond;
+
+	thr->state = THR_IDLE;
+	thr->in = NULL;
+	thr->in_size = 0;
+	thr->allocator = allocator;
+	thr->coder = coder;
+	thr->outbuf = NULL;
+	thr->block_decoder = LZMA_NEXT_CODER_INIT;
+	thr->mem_filters = 0;
+
+	if (mythread_create(&thr->thread_id, worker_decoder, thr))
+		goto error_thread;
+
+	++coder->threads_initialized;
+	coder->thr = thr;
+
+	return LZMA_OK;
+
+error_thread:
+	mythread_cond_destroy(&thr->cond);
+
+error_cond:
+	mythread_mutex_destroy(&thr->mutex);
+
+error_mutex:
+	return LZMA_MEM_ERROR;
+}
+
+
+static lzma_ret
+get_thread(struct lzma_stream_coder *coder, const lzma_allocator *allocator)
+{
+	// If there is a free structure on the stack, use it.
+	mythread_sync(coder->mutex) {
+		if (coder->threads_free != NULL) {
+			coder->thr = coder->threads_free;
+			coder->threads_free = coder->threads_free->next;
+
+			// The thread is no longer in the cache so subtract
+			// it from the cached memory usage. Don't add it
+			// to mem_in_use though; the caller will handle it
+			// since it knows how much memory it will actually
+			// use (the filter chain might change).
+			coder->mem_cached -= coder->thr->mem_filters;
+		}
+	}
+
+	if (coder->thr == NULL) {
+		assert(coder->threads_initialized < coder->threads_max);
+
+		// Initialize a new thread.
+		return_if_error(initialize_new_thread(coder, allocator));
+	}
+
+	coder->thr->in_filled = 0;
+	coder->thr->in_pos = 0;
+	coder->thr->out_pos = 0;
+
+	coder->thr->progress_in = 0;
+	coder->thr->progress_out = 0;
+
+	coder->thr->partial_update = PARTIAL_DISABLED;
+
+	return LZMA_OK;
+}
+
+
+static lzma_ret
+read_output_and_wait(struct lzma_stream_coder *coder,
+		const lzma_allocator *allocator,
+		uint8_t *restrict out, size_t *restrict out_pos,
+		size_t out_size,
+		bool *input_is_possible,
+		bool waiting_allowed,
+		mythread_condtime *wait_abs, bool *has_blocked)
+{
+	lzma_ret ret = LZMA_OK;
+
+	mythread_sync(coder->mutex) {
+		do {
+			// Get as much output from the queue as is possible
+			// without blocking.
+			const size_t out_start = *out_pos;
+			do {
+				ret = lzma_outq_read(&coder->outq, allocator,
+						out, out_pos, out_size,
+						NULL, NULL);
+
+				// If a Block was finished, tell the worker
+				// thread of the next Block (if it is still
+				// running) to start telling the main thread
+				// when new output is available.
+				if (ret == LZMA_STREAM_END)
+					lzma_outq_enable_partial_output(
+						&coder->outq,
+						&worker_enable_partial_update);
+
+				// Loop until a Block wasn't finished.
+				// It's important to loop around even if
+				// *out_pos == out_size because there could
+				// be an empty Block that will return
+				// LZMA_STREAM_END without needing any
+				// output space.
+			} while (ret == LZMA_STREAM_END);
+
+			// Check if lzma_outq_read reported an error from
+			// the Block decoder.
+			if (ret != LZMA_OK)
+				break;
+
+			// If the output buffer is now full but it wasn't full
+			// when this function was called, set out_was_filled.
+			// This way the next call to stream_decode_mt() knows
+			// that some output was produced and no output space
+			// remained in the previous call to stream_decode_mt().
+			if (*out_pos == out_size && *out_pos != out_start)
+				coder->out_was_filled = true;
+
+			// Check if any thread has indicated an error.
+			if (coder->thread_error != LZMA_OK) {
+				// If LZMA_FAIL_FAST was used, report errors
+				// from worker threads immediately.
+				if (coder->fail_fast) {
+					ret = coder->thread_error;
+					break;
+				}
+
+				// Otherwise set pending_error. The value we
+				// set here will not actually get used other
+				// than working as a flag that an error has
+				// occurred. This is because in SEQ_ERROR
+				// all output before the error will be read
+				// first by calling this function, and once we
+				// reach the location of the (first) error the
+				// error code from the above lzma_outq_read()
+				// will be returned to the application.
+				//
+				// Use LZMA_PROG_ERROR since the value should
+				// never leak to the application. It's
+				// possible that pending_error has already
+				// been set but that doesn't matter: if we get
+				// here, pending_error only works as a flag.
+				coder->pending_error = LZMA_PROG_ERROR;
+			}
+
+			// Check if decoding of the next Block can be started.
+			// The memusage of the active threads must be low
+			// enough, there must be a free buffer slot in the
+			// output queue, and there must be a free thread
+			// (that can be either created or an existing one
+			// reused).
+			//
+			// NOTE: This is checked after reading the output
+			// above because reading the output can free a slot in
+			// the output queue and also reduce active memusage.
+			//
+			// NOTE: If output queue is empty, then input will
+			// always be possible.
+			if (input_is_possible != NULL
+					&& coder->memlimit_threading
+						- coder->mem_in_use
+						- coder->outq.mem_in_use
+						>= coder->mem_next_block
+					&& lzma_outq_has_buf(&coder->outq)
+					&& (coder->threads_initialized
+							< coder->threads_max
+						|| coder->threads_free
+							!= NULL)) {
+				*input_is_possible = true;
+				break;
+			}
+
+			// If the caller doesn't want us to block, return now.
+			if (!waiting_allowed)
+				break;
+
+			// This check is needed only when input_is_possible
+			// is NULL. We must return if we aren't waiting for
+			// input to become possible and there is no more
+			// output coming from the queue.
+			if (lzma_outq_is_empty(&coder->outq)) {
+				assert(input_is_possible == NULL);
+				break;
+			}
+
+			// If there is more data available from the queue,
+			// our out buffer must be full and we need to return
+			// so that the application can provide more output
+			// space.
+			//
+			// NOTE: In general lzma_outq_is_readable() can return
+			// true also when there are no more bytes available.
+			// This can happen when a Block has finished without
+			// providing any new output. We know that this is not
+			// the case because in the beginning of this loop we
+			// tried to read as much as possible even when we had
+			// no output space left and the mutex has been locked
+			// all the time (so worker threads cannot have changed
+			// anything). Thus there must be actual pending output
+			// in the queue.
+			if (lzma_outq_is_readable(&coder->outq)) {
+				assert(*out_pos == out_size);
+				break;
+			}
+
+			// If the application stops providing more input
+			// in the middle of a Block, there will eventually
+			// be one worker thread left that is stuck waiting for
+			// more input (that might never arrive) and a matching
+			// outbuf which the worker thread cannot finish due
+			// to lack of input. We must detect this situation,
+			// otherwise we would end up waiting indefinitely
+			// (if no timeout is in use) or keep returning
+			// LZMA_TIMED_OUT while making no progress. Thus, the
+			// application would never get LZMA_BUF_ERROR from
+			// lzma_code() which would tell the application that
+			// no more progress is possible. No LZMA_BUF_ERROR
+			// means that, for example, truncated .xz files could
+			// cause an infinite loop.
+			//
+			// A worker thread doing partial updates will
+			// store not only the output position in outbuf->pos
+			// but also the matching input position in
+			// outbuf->decoder_in_pos. Here we check if that
+			// input position matches the amount of input that
+			// the worker thread has been given (in_filled).
+			// If so, we must return and not wait as no more
+			// output will be coming without first getting more
+			// input to the worker thread. If the application
+			// keeps calling lzma_code() without providing more
+			// input, it will eventually get LZMA_BUF_ERROR.
+			//
+			// NOTE: We can read partial_update and in_filled
+			// without thr->mutex as only the main thread
+			// modifies these variables. decoder_in_pos requires
+			// coder->mutex which we are already holding.
+			if (coder->thr != NULL && coder->thr->partial_update
+					!= PARTIAL_DISABLED) {
+				// There is exactly one outbuf in the queue.
+				assert(coder->thr->outbuf == coder->outq.head);
+				assert(coder->thr->outbuf == coder->outq.tail);
+
+				if (coder->thr->outbuf->decoder_in_pos
+						== coder->thr->in_filled)
+					break;
+			}
+
+			// Wait for input or output to become possible.
+			if (coder->timeout != 0) {
+				// See the comment in stream_encoder_mt.c
+				// about why mythread_condtime_set() is used
+				// like this.
+				//
+				// FIXME?
+				// In contrast to the encoder, this calls
+				// _condtime_set while the mutex is locked.
+				if (!*has_blocked) {
+					*has_blocked = true;
+					mythread_condtime_set(wait_abs,
+							&coder->cond,
+							coder->timeout);
+				}
+
+				if (mythread_cond_timedwait(&coder->cond,
+						&coder->mutex,
+						wait_abs) != 0) {
+					ret = LZMA_TIMED_OUT;
+					break;
+				}
+			} else {
+				mythread_cond_wait(&coder->cond,
+						&coder->mutex);
+			}
+		} while (ret == LZMA_OK);
+	}
+
+	// If we are returning an error, then the application cannot get
+	// more output from us and thus keeping the threads running is
+	// useless and waste of CPU time.
+	if (ret != LZMA_OK && ret != LZMA_TIMED_OUT)
+		threads_stop(coder);
+
+	return ret;
+}
+
+
+static lzma_ret
+decode_block_header(struct lzma_stream_coder *coder,
+		const lzma_allocator *allocator, const uint8_t *restrict in,
+		size_t *restrict in_pos, size_t in_size)
+{
+	if (*in_pos >= in_size)
+		return LZMA_OK;
+
+	if (coder->pos == 0) {
+		// Detect if it's Index.
+		if (in[*in_pos] == INDEX_INDICATOR)
+			return LZMA_INDEX_DETECTED;
+
+		// Calculate the size of the Block Header. Note that
+		// Block Header decoder wants to see this byte too
+		// so don't advance *in_pos.
+		coder->block_options.header_size
+				= lzma_block_header_size_decode(
+					in[*in_pos]);
+	}
+
+	// Copy the Block Header to the internal buffer.
+	lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
+			coder->block_options.header_size);
+
+	// Return if we didn't get the whole Block Header yet.
+	if (coder->pos < coder->block_options.header_size)
+		return LZMA_OK;
+
+	coder->pos = 0;
+
+	// Version 1 is needed to support the .ignore_check option.
+	coder->block_options.version = 1;
+
+	// Block Header decoder will initialize all members of this array
+	// so we don't need to do it here.
+	coder->block_options.filters = coder->filters;
+
+	// Decode the Block Header.
+	return_if_error(lzma_block_header_decode(&coder->block_options,
+			allocator, coder->buffer));
+
+	// If LZMA_IGNORE_CHECK was used, this flag needs to be set.
+	// It has to be set after lzma_block_header_decode() because
+	// it always resets this to false.
+	coder->block_options.ignore_check = coder->ignore_check;
+
+	// coder->block_options is ready now.
+	return LZMA_STREAM_END;
+}
+
+
+/// Get the size of the Compressed Data + Block Padding + Check.
+static size_t
+comp_blk_size(const struct lzma_stream_coder *coder)
+{
+	return vli_ceil4(coder->block_options.compressed_size)
+			+ lzma_check_size(coder->stream_flags.check);
+}
+
+
+/// Returns true if the size (compressed or uncompressed) is such that
+/// threaded decompression cannot be used. Sizes that are too big compared
+/// to SIZE_MAX must be rejected to avoid integer overflows and truncations
+/// when lzma_vli is assigned to a size_t.
+static bool
+is_direct_mode_needed(lzma_vli size)
+{
+	return size == LZMA_VLI_UNKNOWN || size > SIZE_MAX / 3;
+}
+
+
+static lzma_ret
+stream_decoder_reset(struct lzma_stream_coder *coder,
+		const lzma_allocator *allocator)
+{
+	// Initialize the Index hash used to verify the Index.
+	coder->index_hash = lzma_index_hash_init(coder->index_hash, allocator);
+	if (coder->index_hash == NULL)
+		return LZMA_MEM_ERROR;
+
+	// Reset the rest of the variables.
+	coder->sequence = SEQ_STREAM_HEADER;
+	coder->pos = 0;
+
+	return LZMA_OK;
+}
+
+
+static lzma_ret
+stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator,
+		 const uint8_t *restrict in, size_t *restrict in_pos,
+		 size_t in_size,
+		 uint8_t *restrict out, size_t *restrict out_pos,
+		 size_t out_size, lzma_action action)
+{
+	struct lzma_stream_coder *coder = coder_ptr;
+
+	mythread_condtime wait_abs;
+	bool has_blocked = false;
+
+	// Determine if in SEQ_BLOCK_HEADER and SEQ_BLOCK_THR_RUN we should
+	// tell read_output_and_wait() to wait until it can fill the output
+	// buffer (or a timeout occurs). Two conditions must be met:
+	//
+	// (1) If the caller provided no new input. The reason for this
+	//     can be, for example, the end of the file or that there is
+	//     a pause in the input stream and more input is available
+	//     a little later. In this situation we should wait for output
+	//     because otherwise we would end up in a busy-waiting loop where
+	//     we make no progress and the application just calls us again
+	//     without providing any new input. This would then result in
+	//     LZMA_BUF_ERROR even though more output would be available
+	//     once the worker threads decode more data.
+	//
+	// (2) Even if (1) is true, we will not wait if the previous call to
+	//     this function managed to produce some output and the output
+	//     buffer became full. This is for compatibility with applications
+	//     that call lzma_code() in such a way that new input is provided
+	//     only when the output buffer didn't become full. Without this
+	//     trick such applications would have bad performance (bad
+	//     parallelization due to decoder not getting input fast enough).
+	//
+	//     NOTE: Such loops might require that timeout is disabled (0)
+	//     if they assume that output-not-full implies that all input has
+	//     been consumed. If and only if timeout is enabled, we may return
+	//     when output isn't full *and* not all input has been consumed.
+	//
+	// However, if LZMA_FINISH is used, the above is ignored and we always
+	// wait (timeout can still cause us to return) because we know that
+	// we won't get any more input. This matters if the input file is
+	// truncated and we are doing single-shot decoding, that is,
+	// timeout = 0 and LZMA_FINISH is used on the first call to
+	// lzma_code() and the output buffer is known to be big enough
+	// to hold all uncompressed data:
+	//
+	//   - If LZMA_FINISH wasn't handled specially, we could return
+	//     LZMA_OK before providing all output that is possible with the
+	//     truncated input. The rest would be available if lzma_code() was
+	//     called again but then it's not single-shot decoding anymore.
+	//
+	//   - By handling LZMA_FINISH specially here, the first call will
+	//     produce all the output, matching the behavior of the
+	//     single-threaded decoder.
+	//
+	// So it's a very specific corner case but also easy to avoid. Note
+	// that this special handling of LZMA_FINISH has no effect for
+	// single-shot decoding when the input file is valid (not truncated);
+	// premature LZMA_OK wouldn't be possible as long as timeout = 0.
+	const bool waiting_allowed = action == LZMA_FINISH
+			|| (*in_pos == in_size && !coder->out_was_filled);
+	coder->out_was_filled = false;
+
+	while (true)
+	switch (coder->sequence) {
+	case SEQ_STREAM_HEADER: {
+		// Copy the Stream Header to the internal buffer.
+		const size_t in_old = *in_pos;
+		lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
+				LZMA_STREAM_HEADER_SIZE);
+		coder->progress_in += *in_pos - in_old;
+
+		// Return if we didn't get the whole Stream Header yet.
+		if (coder->pos < LZMA_STREAM_HEADER_SIZE)
+			return LZMA_OK;
+
+		coder->pos = 0;
+
+		// Decode the Stream Header.
+		const lzma_ret ret = lzma_stream_header_decode(
+				&coder->stream_flags, coder->buffer);
+		if (ret != LZMA_OK)
+			return ret == LZMA_FORMAT_ERROR && !coder->first_stream
+					? LZMA_DATA_ERROR : ret;
+
+		// If we are decoding concatenated Streams, and the later
+		// Streams have invalid Header Magic Bytes, we give
+		// LZMA_DATA_ERROR instead of LZMA_FORMAT_ERROR.
+		coder->first_stream = false;
+
+		// Copy the type of the Check so that Block Header and Block
+		// decoders see it.
+		coder->block_options.check = coder->stream_flags.check;
+
+		// Even if we return LZMA_*_CHECK below, we want
+		// to continue from Block Header decoding.
+		coder->sequence = SEQ_BLOCK_HEADER;
+
+		// Detect if there's no integrity check or if it is
+		// unsupported if those were requested by the application.
+		if (coder->tell_no_check && coder->stream_flags.check
+				== LZMA_CHECK_NONE)
+			return LZMA_NO_CHECK;
+
+		if (coder->tell_unsupported_check
+				&& !lzma_check_is_supported(
+					coder->stream_flags.check))
+			return LZMA_UNSUPPORTED_CHECK;
+
+		if (coder->tell_any_check)
+			return LZMA_GET_CHECK;
+	}
+
+	// Fall through
+
+	case SEQ_BLOCK_HEADER: {
+		const size_t in_old = *in_pos;
+		const lzma_ret ret = decode_block_header(coder, allocator,
+				in, in_pos, in_size);
+		coder->progress_in += *in_pos - in_old;
+
+		if (ret == LZMA_OK) {
+			// We didn't decode the whole Block Header yet.
+			//
+			// Read output from the queue before returning. This
+			// is important because it is possible that the
+			// application doesn't have any new input available
+			// immediately. If we didn't try to copy output from
+			// the output queue here, lzma_code() could end up
+			// returning LZMA_BUF_ERROR even though queued output
+			// is available.
+			//
+			// If the lzma_code() call provided at least one input
+			// byte, only copy as much data from the output queue
+			// as is available immediately. This way the
+			// application will be able to provide more input
+			// without a delay.
+			//
+			// On the other hand, if lzma_code() was called with
+			// an empty input buffer(*), treat it specially: try
+			// to fill the output buffer even if it requires
+			// waiting for the worker threads to provide output
+			// (timeout, if specified, can still cause us to
+			// return).
+			//
+			//   - This way the application will be able to get all
+			//     data that can be decoded from the input provided
+			//     so far.
+			//
+			//   - We avoid both premature LZMA_BUF_ERROR and
+			//     busy-waiting where the application repeatedly
+			//     calls lzma_code() which immediately returns
+			//     LZMA_OK without providing new data.
+			//
+			//   - If the queue becomes empty, we won't wait
+			//     anything and will return LZMA_OK immediately
+			//     (coder->timeout is completely ignored).
+			//
+			// (*) See the comment at the beginning of this
+			//     function how waiting_allowed is determined
+			//     and why there is an exception to the rule
+			//     of "called with an empty input buffer".
+			assert(*in_pos == in_size);
+
+			// If LZMA_FINISH was used we know that we won't get
+			// more input, so the file must be truncated if we
+			// get here. If worker threads don't detect any
+			// errors, eventually there will be no more output
+			// while we keep returning LZMA_OK which gets
+			// converted to LZMA_BUF_ERROR in lzma_code().
+			//
+			// If fail-fast is enabled then we will return
+			// immediately using LZMA_DATA_ERROR instead of
+			// LZMA_OK or LZMA_BUF_ERROR. Rationale for the
+			// error code:
+			//
+			//   - Worker threads may have a large amount of
+			//     not-yet-decoded input data and we don't
+			//     know for sure if all data is valid. Bad
+			//     data there would result in LZMA_DATA_ERROR
+			//     when fail-fast isn't used.
+			//
+			//   - Immediate LZMA_BUF_ERROR would be a bit weird
+			//     considering the older liblzma code. lzma_code()
+			//     even has an assertion to prevent coders from
+			//     returning LZMA_BUF_ERROR directly.
+			//
+			// The downside of this is that with fail-fast apps
+			// cannot always distinguish between corrupt and
+			// truncated files.
+			if (action == LZMA_FINISH && coder->fail_fast) {
+				// We won't produce any more output. Stop
+				// the unfinished worker threads so they
+				// won't waste CPU time.
+				threads_stop(coder);
+				return LZMA_DATA_ERROR;
+			}
+
+			// read_output_and_wait() will call threads_stop()
+			// if needed so with that we can use return_if_error.
+			return_if_error(read_output_and_wait(coder, allocator,
+				out, out_pos, out_size,
+				NULL, waiting_allowed,
+				&wait_abs, &has_blocked));
+
+			if (coder->pending_error != LZMA_OK) {
+				coder->sequence = SEQ_ERROR;
+				break;
+			}
+
+			return LZMA_OK;
+		}
+
+		if (ret == LZMA_INDEX_DETECTED) {
+			coder->sequence = SEQ_INDEX_WAIT_OUTPUT;
+			break;
+		}
+
+		// See if an error occurred.
+		if (ret != LZMA_STREAM_END) {
+			// NOTE: Here and in all other places where
+			// pending_error is set, it may overwrite the value
+			// (LZMA_PROG_ERROR) set by read_output_and_wait().
+			// That function might overwrite value set here too.
+			// These are fine because when read_output_and_wait()
+			// sets pending_error, it actually works as a flag
+			// variable only ("some error has occurred") and the
+			// actual value of pending_error is not used in
+			// SEQ_ERROR. In such cases SEQ_ERROR will eventually
+			// get the correct error code from the return value of
+			// a later read_output_and_wait() call.
+			coder->pending_error = ret;
+			coder->sequence = SEQ_ERROR;
+			break;
+		}
+
+		// Calculate the memory usage of the filters / Block decoder.
+		coder->mem_next_filters = lzma_raw_decoder_memusage(
+				coder->filters);
+
+		if (coder->mem_next_filters == UINT64_MAX) {
+			// One or more unknown Filter IDs.
+			coder->pending_error = LZMA_OPTIONS_ERROR;
+			coder->sequence = SEQ_ERROR;
+			break;
+		}
+
+		coder->sequence = SEQ_BLOCK_INIT;
+	}
+
+	// Fall through
+
+	case SEQ_BLOCK_INIT: {
+		// Check if decoding is possible at all with the current
+		// memlimit_stop which we must never exceed.
+		//
+		// This needs to be the first thing in SEQ_BLOCK_INIT
+		// to make it possible to restart decoding after increasing
+		// memlimit_stop with lzma_memlimit_set().
+		if (coder->mem_next_filters > coder->memlimit_stop) {
+			// Flush pending output before returning
+			// LZMA_MEMLIMIT_ERROR. If the application doesn't
+			// want to increase the limit, at least it will get
+			// all the output possible so far.
+			return_if_error(read_output_and_wait(coder, allocator,
+					out, out_pos, out_size,
+					NULL, true, &wait_abs, &has_blocked));
+
+			if (!lzma_outq_is_empty(&coder->outq))
+				return LZMA_OK;
+
+			return LZMA_MEMLIMIT_ERROR;
+		}
+
+		// Check if the size information is available in Block Header.
+		// If it is, check if the sizes are small enough that we don't
+		// need to worry *too* much about integer overflows later in
+		// the code. If these conditions are not met, we must use the
+		// single-threaded direct mode.
+		if (is_direct_mode_needed(coder->block_options.compressed_size)
+				|| is_direct_mode_needed(
+				coder->block_options.uncompressed_size)) {
+			coder->sequence = SEQ_BLOCK_DIRECT_INIT;
+			break;
+		}
+
+		// Calculate the amount of memory needed for the input and
+		// output buffers in threaded mode.
+		//
+		// These cannot overflow because we already checked that
+		// the sizes are small enough using is_direct_mode_needed().
+		coder->mem_next_in = comp_blk_size(coder);
+		const uint64_t mem_buffers = coder->mem_next_in
+				+ lzma_outq_outbuf_memusage(
+				coder->block_options.uncompressed_size);
+
+		// Add the amount needed by the filters.
+		// Avoid integer overflows.
+		if (UINT64_MAX - mem_buffers < coder->mem_next_filters) {
+			// Use direct mode if the memusage would overflow.
+			// This is a theoretical case that shouldn't happen
+			// in practice unless the input file is weird (broken
+			// or malicious).
+			coder->sequence = SEQ_BLOCK_DIRECT_INIT;
+			break;
+		}
+
+		// Amount of memory needed to decode this Block in
+		// threaded mode:
+		coder->mem_next_block = coder->mem_next_filters + mem_buffers;
+
+		// If this alone would exceed memlimit_threading, then we must
+		// use the single-threaded direct mode.
+		if (coder->mem_next_block > coder->memlimit_threading) {
+			coder->sequence = SEQ_BLOCK_DIRECT_INIT;
+			break;
+		}
+
+		// Use the threaded mode. Free the direct mode decoder in
+		// case it has been initialized.
+		lzma_next_end(&coder->block_decoder, allocator);
+		coder->mem_direct_mode = 0;
+
+		// Since we already know what the sizes are supposed to be,
+		// we can already add them to the Index hash. The Block
+		// decoder will verify the values while decoding.
+		const lzma_ret ret = lzma_index_hash_append(coder->index_hash,
+				lzma_block_unpadded_size(
+					&coder->block_options),
+				coder->block_options.uncompressed_size);
+		if (ret != LZMA_OK) {
+			coder->pending_error = ret;
+			coder->sequence = SEQ_ERROR;
+			break;
+		}
+
+		coder->sequence = SEQ_BLOCK_THR_INIT;
+	}
+
+	// Fall through
+
+	case SEQ_BLOCK_THR_INIT: {
+		// We need to wait for a multiple conditions to become true
+		// until we can initialize the Block decoder and let a worker
+		// thread decode it:
+		//
+		//   - Wait for the memory usage of the active threads to drop
+		//     so that starting the decoding of this Block won't make
+		//     us go over memlimit_threading.
+		//
+		//   - Wait for at least one free output queue slot.
+		//
+		//   - Wait for a free worker thread.
+		//
+		// While we wait, we must copy decompressed data to the out
+		// buffer and catch possible decoder errors.
+		//
+		// read_output_and_wait() does all the above.
+		bool block_can_start = false;
+
+		return_if_error(read_output_and_wait(coder, allocator,
+				out, out_pos, out_size,
+				&block_can_start, true,
+				&wait_abs, &has_blocked));
+
+		if (coder->pending_error != LZMA_OK) {
+			coder->sequence = SEQ_ERROR;
+			break;
+		}
+
+		if (!block_can_start) {
+			// It's not a timeout because return_if_error handles
+			// it already. Output queue cannot be empty either
+			// because in that case block_can_start would have
+			// been true. Thus the output buffer must be full and
+			// the queue isn't empty.
+			assert(*out_pos == out_size);
+			assert(!lzma_outq_is_empty(&coder->outq));
+			return LZMA_OK;
+		}
+
+		// We know that we can start decoding this Block without
+		// exceeding memlimit_threading. However, to stay below
+		// memlimit_threading may require freeing some of the
+		// cached memory.
+		//
+		// Get a local copy of variables that require locking the
+		// mutex. It is fine if the worker threads modify the real
+		// values after we read these as those changes can only be
+		// towards more favorable conditions (less memory in use,
+		// more in cache).
+		//
+		// These are initialized to silence warnings.
+		uint64_t mem_in_use = 0;
+		uint64_t mem_cached = 0;
+		struct worker_thread *thr = NULL;
+
+		mythread_sync(coder->mutex) {
+			mem_in_use = coder->mem_in_use;
+			mem_cached = coder->mem_cached;
+			thr = coder->threads_free;
+		}
+
+		// The maximum amount of memory that can be held by other
+		// threads and cached buffers while allowing us to start
+		// decoding the next Block.
+		const uint64_t mem_max = coder->memlimit_threading
+				- coder->mem_next_block;
+
+		// If the existing allocations are so large that starting
+		// to decode this Block might exceed memlimit_threads,
+		// try to free memory from the output queue cache first.
+		//
+		// NOTE: This math assumes the worst case. It's possible
+		// that the limit wouldn't be exceeded if the existing cached
+		// allocations are reused.
+		if (mem_in_use + mem_cached + coder->outq.mem_allocated
+				> mem_max) {
+			// Clear the outq cache except leave one buffer in
+			// the cache if its size is correct. That way we
+			// don't free and almost immediately reallocate
+			// an identical buffer.
+			lzma_outq_clear_cache2(&coder->outq, allocator,
+				coder->block_options.uncompressed_size);
+		}
+
+		// If there is at least one worker_thread in the cache and
+		// the existing allocations are so large that starting to
+		// decode this Block might exceed memlimit_threads, free
+		// memory by freeing cached Block decoders.
+		//
+		// NOTE: The comparison is different here than above.
+		// Here we don't care about cached buffers in outq anymore
+		// and only look at memory actually in use. This is because
+		// if there is something in outq cache, it's a single buffer
+		// that can be used as is. We ensured this in the above
+		// if-block.
+		uint64_t mem_freed = 0;
+		if (thr != NULL && mem_in_use + mem_cached
+				+ coder->outq.mem_in_use > mem_max) {
+			// Don't free the first Block decoder if its memory
+			// usage isn't greater than what this Block will need.
+			// Typically the same filter chain is used for all
+			// Blocks so this way the allocations can be reused
+			// when get_thread() picks the first worker_thread
+			// from the cache.
+			if (thr->mem_filters <= coder->mem_next_filters)
+				thr = thr->next;
+
+			while (thr != NULL) {
+				lzma_next_end(&thr->block_decoder, allocator);
+				mem_freed += thr->mem_filters;
+				thr->mem_filters = 0;
+				thr = thr->next;
+			}
+		}
+
+		// Update the memory usage counters. Note that coder->mem_*
+		// may have changed since we read them so we must subtract
+		// or add the changes.
+		mythread_sync(coder->mutex) {
+			coder->mem_cached -= mem_freed;
+
+			// Memory needed for the filters and the input buffer.
+			// The output queue takes care of its own counter so
+			// we don't touch it here.
+			//
+			// NOTE: After this, coder->mem_in_use +
+			// coder->mem_cached might count the same thing twice.
+			// If so, this will get corrected in get_thread() when
+			// a worker_thread is picked from coder->free_threads
+			// and its memory usage is subtracted from mem_cached.
+			coder->mem_in_use += coder->mem_next_in
+					+ coder->mem_next_filters;
+		}
+
+		// Allocate memory for the output buffer in the output queue.
+		lzma_ret ret = lzma_outq_prealloc_buf(
+				&coder->outq, allocator,
+				coder->block_options.uncompressed_size);
+		if (ret != LZMA_OK) {
+			threads_stop(coder);
+			return ret;
+		}
+
+		// Set up coder->thr.
+		ret = get_thread(coder, allocator);
+		if (ret != LZMA_OK) {
+			threads_stop(coder);
+			return ret;
+		}
+
+		// The new Block decoder memory usage is already counted in
+		// coder->mem_in_use. Store it in the thread too.
+		coder->thr->mem_filters = coder->mem_next_filters;
+
+		// Initialize the Block decoder.
+		coder->thr->block_options = coder->block_options;
+		ret = lzma_block_decoder_init(
+					&coder->thr->block_decoder, allocator,
+					&coder->thr->block_options);
+
+		// Free the allocated filter options since they are needed
+		// only to initialize the Block decoder.
+		lzma_filters_free(coder->filters, allocator);
+		coder->thr->block_options.filters = NULL;
+
+		// Check if memory usage calculation and Block encoder
+		// initialization succeeded.
+		if (ret != LZMA_OK) {
+			coder->pending_error = ret;
+			coder->sequence = SEQ_ERROR;
+			break;
+		}
+
+		// Allocate the input buffer.
+		coder->thr->in_size = coder->mem_next_in;
+		coder->thr->in = lzma_alloc(coder->thr->in_size, allocator);
+		if (coder->thr->in == NULL) {
+			threads_stop(coder);
+			return LZMA_MEM_ERROR;
+		}
+
+		// Get the preallocated output buffer.
+		coder->thr->outbuf = lzma_outq_get_buf(
+				&coder->outq, coder->thr);
+
+		// Start the decoder.
+		mythread_sync(coder->thr->mutex) {
+			assert(coder->thr->state == THR_IDLE);
+			coder->thr->state = THR_RUN;
+			mythread_cond_signal(&coder->thr->cond);
+		}
+
+		// Enable output from the thread that holds the oldest output
+		// buffer in the output queue (if such a thread exists).
+		mythread_sync(coder->mutex) {
+			lzma_outq_enable_partial_output(&coder->outq,
+					&worker_enable_partial_update);
+		}
+
+		coder->sequence = SEQ_BLOCK_THR_RUN;
+	}
+
+	// Fall through
+
+	case SEQ_BLOCK_THR_RUN: {
+		if (action == LZMA_FINISH && coder->fail_fast) {
+			// We know that we won't get more input and that
+			// the caller wants fail-fast behavior. If we see
+			// that we don't have enough input to finish this
+			// Block, return LZMA_DATA_ERROR immediately.
+			// See SEQ_BLOCK_HEADER for the error code rationale.
+			const size_t in_avail = in_size - *in_pos;
+			const size_t in_needed = coder->thr->in_size
+					- coder->thr->in_filled;
+			if (in_avail < in_needed) {
+				threads_stop(coder);
+				return LZMA_DATA_ERROR;
+			}
+		}
+
+		// Copy input to the worker thread.
+		size_t cur_in_filled = coder->thr->in_filled;
+		lzma_bufcpy(in, in_pos, in_size, coder->thr->in,
+				&cur_in_filled, coder->thr->in_size);
+
+		// Tell the thread how much we copied.
+		mythread_sync(coder->thr->mutex) {
+			coder->thr->in_filled = cur_in_filled;
+
+			// NOTE: Most of the time we are copying input faster
+			// than the thread can decode so most of the time
+			// calling mythread_cond_signal() is useless but
+			// we cannot make it conditional because thr->in_pos
+			// is updated without a mutex. And the overhead should
+			// be very much negligible anyway.
+			mythread_cond_signal(&coder->thr->cond);
+		}
+
+		// Read output from the output queue. Just like in
+		// SEQ_BLOCK_HEADER, we wait to fill the output buffer
+		// only if waiting_allowed was set to true in the beginning
+		// of this function (see the comment there).
+		return_if_error(read_output_and_wait(coder, allocator,
+				out, out_pos, out_size,
+				NULL, waiting_allowed,
+				&wait_abs, &has_blocked));
+
+		if (coder->pending_error != LZMA_OK) {
+			coder->sequence = SEQ_ERROR;
+			break;
+		}
+
+		// Return if the input didn't contain the whole Block.
+		if (coder->thr->in_filled < coder->thr->in_size) {
+			assert(*in_pos == in_size);
+			return LZMA_OK;
+		}
+
+		// The whole Block has been copied to the thread-specific
+		// buffer. Continue from the next Block Header or Index.
+		coder->thr = NULL;
+		coder->sequence = SEQ_BLOCK_HEADER;
+		break;
+	}
+
+	case SEQ_BLOCK_DIRECT_INIT: {
+		// Wait for the threads to finish and that all decoded data
+		// has been copied to the output. That is, wait until the
+		// output queue becomes empty.
+		//
+		// NOTE: No need to check for coder->pending_error as
+		// we aren't consuming any input until the queue is empty
+		// and if there is a pending error, read_output_and_wait()
+		// will eventually return it before the queue is empty.
+		return_if_error(read_output_and_wait(coder, allocator,
+				out, out_pos, out_size,
+				NULL, true, &wait_abs, &has_blocked));
+		if (!lzma_outq_is_empty(&coder->outq))
+			return LZMA_OK;
+
+		// Free the cached output buffers.
+		lzma_outq_clear_cache(&coder->outq, allocator);
+
+		// Get rid of the worker threads, including the coder->threads
+		// array.
+		threads_end(coder, allocator);
+
+		// Initialize the Block decoder.
+		const lzma_ret ret = lzma_block_decoder_init(
+				&coder->block_decoder, allocator,
+				&coder->block_options);
+
+		// Free the allocated filter options since they are needed
+		// only to initialize the Block decoder.
+		lzma_filters_free(coder->filters, allocator);
+		coder->block_options.filters = NULL;
+
+		// Check if Block decoder initialization succeeded.
+		if (ret != LZMA_OK)
+			return ret;
+
+		// Make the memory usage visible to _memconfig().
+		coder->mem_direct_mode = coder->mem_next_filters;
+
+		coder->sequence = SEQ_BLOCK_DIRECT_RUN;
+	}
+
+	// Fall through
+
+	case SEQ_BLOCK_DIRECT_RUN: {
+		const size_t in_old = *in_pos;
+		const size_t out_old = *out_pos;
+		const lzma_ret ret = coder->block_decoder.code(
+				coder->block_decoder.coder, allocator,
+				in, in_pos, in_size, out, out_pos, out_size,
+				action);
+		coder->progress_in += *in_pos - in_old;
+		coder->progress_out += *out_pos - out_old;
+
+		if (ret != LZMA_STREAM_END)
+			return ret;
+
+		// Block decoded successfully. Add the new size pair to
+		// the Index hash.
+		return_if_error(lzma_index_hash_append(coder->index_hash,
+				lzma_block_unpadded_size(
+					&coder->block_options),
+				coder->block_options.uncompressed_size));
+
+		coder->sequence = SEQ_BLOCK_HEADER;
+		break;
+	}
+
+	case SEQ_INDEX_WAIT_OUTPUT:
+		// Flush the output from all worker threads so that we can
+		// decode the Index without thinking about threading.
+		return_if_error(read_output_and_wait(coder, allocator,
+				out, out_pos, out_size,
+				NULL, true, &wait_abs, &has_blocked));
+
+		if (!lzma_outq_is_empty(&coder->outq))
+			return LZMA_OK;
+
+		coder->sequence = SEQ_INDEX_DECODE;
+
+	// Fall through
+
+	case SEQ_INDEX_DECODE: {
+		// If we don't have any input, don't call
+		// lzma_index_hash_decode() since it would return
+		// LZMA_BUF_ERROR, which we must not do here.
+		if (*in_pos >= in_size)
+			return LZMA_OK;
+
+		// Decode the Index and compare it to the hash calculated
+		// from the sizes of the Blocks (if any).
+		const size_t in_old = *in_pos;
+		const lzma_ret ret = lzma_index_hash_decode(coder->index_hash,
+				in, in_pos, in_size);
+		coder->progress_in += *in_pos - in_old;
+		if (ret != LZMA_STREAM_END)
+			return ret;
+
+		coder->sequence = SEQ_STREAM_FOOTER;
+	}
+
+	// Fall through
+
+	case SEQ_STREAM_FOOTER: {
+		// Copy the Stream Footer to the internal buffer.
+		const size_t in_old = *in_pos;
+		lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
+				LZMA_STREAM_HEADER_SIZE);
+		coder->progress_in += *in_pos - in_old;
+
+		// Return if we didn't get the whole Stream Footer yet.
+		if (coder->pos < LZMA_STREAM_HEADER_SIZE)
+			return LZMA_OK;
+
+		coder->pos = 0;
+
+		// Decode the Stream Footer. The decoder gives
+		// LZMA_FORMAT_ERROR if the magic bytes don't match,
+		// so convert that return code to LZMA_DATA_ERROR.
+		lzma_stream_flags footer_flags;
+		const lzma_ret ret = lzma_stream_footer_decode(
+				&footer_flags, coder->buffer);
+		if (ret != LZMA_OK)
+			return ret == LZMA_FORMAT_ERROR
+					? LZMA_DATA_ERROR : ret;
+
+		// Check that Index Size stored in the Stream Footer matches
+		// the real size of the Index field.
+		if (lzma_index_hash_size(coder->index_hash)
+				!= footer_flags.backward_size)
+			return LZMA_DATA_ERROR;
+
+		// Compare that the Stream Flags fields are identical in
+		// both Stream Header and Stream Footer.
+		return_if_error(lzma_stream_flags_compare(
+				&coder->stream_flags, &footer_flags));
+
+		if (!coder->concatenated)
+			return LZMA_STREAM_END;
+
+		coder->sequence = SEQ_STREAM_PADDING;
+	}
+
+	// Fall through
+
+	case SEQ_STREAM_PADDING:
+		assert(coder->concatenated);
+
+		// Skip over possible Stream Padding.
+		while (true) {
+			if (*in_pos >= in_size) {
+				// Unless LZMA_FINISH was used, we cannot
+				// know if there's more input coming later.
+				if (action != LZMA_FINISH)
+					return LZMA_OK;
+
+				// Stream Padding must be a multiple of
+				// four bytes.
+				return coder->pos == 0
+						? LZMA_STREAM_END
+						: LZMA_DATA_ERROR;
+			}
+
+			// If the byte is not zero, it probably indicates
+			// beginning of a new Stream (or the file is corrupt).
+			if (in[*in_pos] != 0x00)
+				break;
+
+			++*in_pos;
+			++coder->progress_in;
+			coder->pos = (coder->pos + 1) & 3;
+		}
+
+		// Stream Padding must be a multiple of four bytes (empty
+		// Stream Padding is OK).
+		if (coder->pos != 0) {
+			++*in_pos;
+			++coder->progress_in;
+			return LZMA_DATA_ERROR;
+		}
+
+		// Prepare to decode the next Stream.
+		return_if_error(stream_decoder_reset(coder, allocator));
+		break;
+
+	case SEQ_ERROR:
+		if (!coder->fail_fast) {
+			// Let the application get all data before the point
+			// where the error was detected. This matches the
+			// behavior of single-threaded use.
+			//
+			// FIXME? Some errors (LZMA_MEM_ERROR) don't get here,
+			// they are returned immediately. Thus in rare cases
+			// the output will be less than in the single-threaded
+			// mode. Maybe this doesn't matter much in practice.
+			return_if_error(read_output_and_wait(coder, allocator,
+					out, out_pos, out_size,
+					NULL, true, &wait_abs, &has_blocked));
+
+			// We get here only if the error happened in the main
+			// thread, for example, unsupported Block Header.
+			if (!lzma_outq_is_empty(&coder->outq))
+				return LZMA_OK;
+		}
+
+		// We only get here if no errors were detected by the worker
+		// threads. Errors from worker threads would have already been
+		// returned by the call to read_output_and_wait() above.
+		return coder->pending_error;
+
+	default:
+		assert(0);
+		return LZMA_PROG_ERROR;
+	}
+
+	// Never reached
+}
+
+
+static void
+stream_decoder_mt_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	struct lzma_stream_coder *coder = coder_ptr;
+
+	threads_end(coder, allocator);
+	lzma_outq_end(&coder->outq, allocator);
+
+	lzma_next_end(&coder->block_decoder, allocator);
+	lzma_filters_free(coder->filters, allocator);
+	lzma_index_hash_end(coder->index_hash, allocator);
+
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_check
+stream_decoder_mt_get_check(const void *coder_ptr)
+{
+	const struct lzma_stream_coder *coder = coder_ptr;
+	return coder->stream_flags.check;
+}
+
+
+static lzma_ret
+stream_decoder_mt_memconfig(void *coder_ptr, uint64_t *memusage,
+		uint64_t *old_memlimit, uint64_t new_memlimit)
+{
+	// NOTE: This function gets/sets memlimit_stop. For now,
+	// memlimit_threading cannot be modified after initialization.
+	//
+	// *memusage will include cached memory too. Excluding cached memory
+	// would be misleading and it wouldn't help the applications to
+	// know how much memory is actually needed to decompress the file
+	// because the higher the number of threads and the memlimits are
+	// the more memory the decoder may use.
+	//
+	// Setting a new limit includes the cached memory too and too low
+	// limits will be rejected. Alternative could be to free the cached
+	// memory immediately if that helps to bring the limit down but
+	// the current way is the simplest. It's unlikely that limit needs
+	// to be lowered in the middle of a file anyway; the typical reason
+	// to want a new limit is to increase after LZMA_MEMLIMIT_ERROR
+	// and even such use isn't common.
+	struct lzma_stream_coder *coder = coder_ptr;
+
+	mythread_sync(coder->mutex) {
+		*memusage = coder->mem_direct_mode
+				+ coder->mem_in_use
+				+ coder->mem_cached
+				+ coder->outq.mem_allocated;
+	}
+
+	// If no filter chains are allocated, *memusage may be zero.
+	// Always return at least LZMA_MEMUSAGE_BASE.
+	if (*memusage < LZMA_MEMUSAGE_BASE)
+		*memusage = LZMA_MEMUSAGE_BASE;
+
+	*old_memlimit = coder->memlimit_stop;
+
+	if (new_memlimit != 0) {
+		if (new_memlimit < *memusage)
+			return LZMA_MEMLIMIT_ERROR;
+
+		coder->memlimit_stop = new_memlimit;
+	}
+
+	return LZMA_OK;
+}
+
+
+static void
+stream_decoder_mt_get_progress(void *coder_ptr,
+		uint64_t *progress_in, uint64_t *progress_out)
+{
+	struct lzma_stream_coder *coder = coder_ptr;
+
+	// Lock coder->mutex to prevent finishing threads from moving their
+	// progress info from the worker_thread structure to lzma_stream_coder.
+	mythread_sync(coder->mutex) {
+		*progress_in = coder->progress_in;
+		*progress_out = coder->progress_out;
+
+		for (size_t i = 0; i < coder->threads_initialized; ++i) {
+			mythread_sync(coder->threads[i].mutex) {
+				*progress_in += coder->threads[i].progress_in;
+				*progress_out += coder->threads[i]
+						.progress_out;
+			}
+		}
+	}
+
+	return;
+}
+
+
+static lzma_ret
+stream_decoder_mt_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		       const lzma_mt *options)
+{
+	struct lzma_stream_coder *coder;
+
+	if (options->threads == 0 || options->threads > LZMA_THREADS_MAX)
+		return LZMA_OPTIONS_ERROR;
+
+	if (options->flags & ~LZMA_SUPPORTED_FLAGS)
+		return LZMA_OPTIONS_ERROR;
+
+	lzma_next_coder_init(&stream_decoder_mt_init, next, allocator);
+
+	coder = next->coder;
+	if (!coder) {
+		coder = lzma_alloc(sizeof(struct lzma_stream_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+
+		if (mythread_mutex_init(&coder->mutex)) {
+			lzma_free(coder, allocator);
+			return LZMA_MEM_ERROR;
+		}
+
+		if (mythread_cond_init(&coder->cond)) {
+			mythread_mutex_destroy(&coder->mutex);
+			lzma_free(coder, allocator);
+			return LZMA_MEM_ERROR;
+		}
+
+		next->code = &stream_decode_mt;
+		next->end = &stream_decoder_mt_end;
+		next->get_check = &stream_decoder_mt_get_check;
+		next->memconfig = &stream_decoder_mt_memconfig;
+		next->get_progress = &stream_decoder_mt_get_progress;
+
+		coder->filters[0].id = LZMA_VLI_UNKNOWN;
+		memzero(&coder->outq, sizeof(coder->outq));
+
+		coder->block_decoder = LZMA_NEXT_CODER_INIT;
+		coder->mem_direct_mode = 0;
+
+		coder->index_hash = NULL;
+		coder->threads = NULL;
+		coder->threads_free = NULL;
+		coder->threads_initialized = 0;
+	}
+
+	// Cleanup old filter chain if one remains after unfinished decoding
+	// of a previous Stream.
+	lzma_filters_free(coder->filters, allocator);
+
+	// By allocating threads from scratch we can start memory-usage
+	// accounting from scratch, too. Changes in filter and block sizes may
+	// affect number of threads.
+	//
+	// FIXME? Reusing should be easy but unlike the single-threaded
+	// decoder, with some types of input file combinations reusing
+	// could leave quite a lot of memory allocated but unused (first
+	// file could allocate a lot, the next files could use fewer
+	// threads and some of the allocations from the first file would not
+	// get freed unless memlimit_threading forces us to clear caches).
+	//
+	// NOTE: The direct mode decoder isn't freed here if one exists.
+	// It will be reused or freed as needed in the main loop.
+	threads_end(coder, allocator);
+
+	// All memusage counters start at 0 (including mem_direct_mode).
+	// The little extra that is needed for the structs in this file
+	// get accounted well enough by the filter chain memory usage
+	// which adds LZMA_MEMUSAGE_BASE for each chain. However,
+	// stream_decoder_mt_memconfig() has to handle this specially so that
+	// it will never return less than LZMA_MEMUSAGE_BASE as memory usage.
+	coder->mem_in_use = 0;
+	coder->mem_cached = 0;
+	coder->mem_next_block = 0;
+
+	coder->progress_in = 0;
+	coder->progress_out = 0;
+
+	coder->sequence = SEQ_STREAM_HEADER;
+	coder->thread_error = LZMA_OK;
+	coder->pending_error = LZMA_OK;
+	coder->thr = NULL;
+
+	coder->timeout = options->timeout;
+
+	coder->memlimit_threading = my_max(1, options->memlimit_threading);
+	coder->memlimit_stop = my_max(1, options->memlimit_stop);
+	if (coder->memlimit_threading > coder->memlimit_stop)
+		coder->memlimit_threading = coder->memlimit_stop;
+
+	coder->tell_no_check = (options->flags & LZMA_TELL_NO_CHECK) != 0;
+	coder->tell_unsupported_check
+			= (options->flags & LZMA_TELL_UNSUPPORTED_CHECK) != 0;
+	coder->tell_any_check = (options->flags & LZMA_TELL_ANY_CHECK) != 0;
+	coder->ignore_check = (options->flags & LZMA_IGNORE_CHECK) != 0;
+	coder->concatenated = (options->flags & LZMA_CONCATENATED) != 0;
+	coder->fail_fast = (options->flags & LZMA_FAIL_FAST) != 0;
+
+	coder->first_stream = true;
+	coder->out_was_filled = false;
+	coder->pos = 0;
+
+	coder->threads_max = options->threads;
+
+	return_if_error(lzma_outq_init(&coder->outq, allocator,
+				       coder->threads_max));
+
+	return stream_decoder_reset(coder, allocator);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_decoder_mt(lzma_stream *strm, const lzma_mt *options)
+{
+	lzma_next_strm_init(stream_decoder_mt_init, strm, options);
+
+	strm->internal->supported_actions[LZMA_RUN] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder.c
new file mode 100644
index 00000000000..e7e5b3fce7e
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       stream_encoder.c
+/// \brief      Encodes .xz Streams
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "block_encoder.h"
+#include "index_encoder.h"
+
+
+typedef struct {
+	enum {
+		SEQ_STREAM_HEADER,
+		SEQ_BLOCK_INIT,
+		SEQ_BLOCK_HEADER,
+		SEQ_BLOCK_ENCODE,
+		SEQ_INDEX_ENCODE,
+		SEQ_STREAM_FOOTER,
+	} sequence;
+
+	/// True if Block encoder has been initialized by
+	/// stream_encoder_init() or stream_encoder_update()
+	/// and thus doesn't need to be initialized in stream_encode().
+	bool block_encoder_is_initialized;
+
+	/// Block
+	lzma_next_coder block_encoder;
+
+	/// Options for the Block encoder
+	lzma_block block_options;
+
+	/// The filter chain currently in use
+	lzma_filter filters[LZMA_FILTERS_MAX + 1];
+
+	/// Index encoder. This is separate from Block encoder, because this
+	/// doesn't take much memory, and when encoding multiple Streams
+	/// with the same encoding options we avoid reallocating memory.
+	lzma_next_coder index_encoder;
+
+	/// Index to hold sizes of the Blocks
+	lzma_index *index;
+
+	/// Read position in buffer[]
+	size_t buffer_pos;
+
+	/// Total number of bytes in buffer[]
+	size_t buffer_size;
+
+	/// Buffer to hold Stream Header, Block Header, and Stream Footer.
+	/// Block Header has biggest maximum size.
+	uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX];
+} lzma_stream_coder;
+
+
+static lzma_ret
+block_encoder_init(lzma_stream_coder *coder, const lzma_allocator *allocator)
+{
+	// Prepare the Block options. Even though Block encoder doesn't need
+	// compressed_size, uncompressed_size, and header_size to be
+	// initialized, it is a good idea to do it here, because this way
+	// we catch if someone gave us Filter ID that cannot be used in
+	// Blocks/Streams.
+	coder->block_options.compressed_size = LZMA_VLI_UNKNOWN;
+	coder->block_options.uncompressed_size = LZMA_VLI_UNKNOWN;
+
+	return_if_error(lzma_block_header_size(&coder->block_options));
+
+	// Initialize the actual Block encoder.
+	return lzma_block_encoder_init(&coder->block_encoder, allocator,
+			&coder->block_options);
+}
+
+
+static lzma_ret
+stream_encode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size, lzma_action action)
+{
+	lzma_stream_coder *coder = coder_ptr;
+
+	// Main loop
+	while (*out_pos < out_size)
+	switch (coder->sequence) {
+	case SEQ_STREAM_HEADER:
+	case SEQ_BLOCK_HEADER:
+	case SEQ_STREAM_FOOTER:
+		lzma_bufcpy(coder->buffer, &coder->buffer_pos,
+				coder->buffer_size, out, out_pos, out_size);
+		if (coder->buffer_pos < coder->buffer_size)
+			return LZMA_OK;
+
+		if (coder->sequence == SEQ_STREAM_FOOTER)
+			return LZMA_STREAM_END;
+
+		coder->buffer_pos = 0;
+		++coder->sequence;
+		break;
+
+	case SEQ_BLOCK_INIT: {
+		if (*in_pos == in_size) {
+			// If we are requested to flush or finish the current
+			// Block, return LZMA_STREAM_END immediately since
+			// there's nothing to do.
+			if (action != LZMA_FINISH)
+				return action == LZMA_RUN
+						? LZMA_OK : LZMA_STREAM_END;
+
+			// The application had used LZMA_FULL_FLUSH to finish
+			// the previous Block, but now wants to finish without
+			// encoding new data, or it is simply creating an
+			// empty Stream with no Blocks.
+			//
+			// Initialize the Index encoder, and continue to
+			// actually encoding the Index.
+			return_if_error(lzma_index_encoder_init(
+					&coder->index_encoder, allocator,
+					coder->index));
+			coder->sequence = SEQ_INDEX_ENCODE;
+			break;
+		}
+
+		// Initialize the Block encoder unless it was already
+		// initialized by stream_encoder_init() or
+		// stream_encoder_update().
+		if (!coder->block_encoder_is_initialized)
+			return_if_error(block_encoder_init(coder, allocator));
+
+		// Make it false so that we don't skip the initialization
+		// with the next Block.
+		coder->block_encoder_is_initialized = false;
+
+		// Encode the Block Header. This shouldn't fail since we have
+		// already initialized the Block encoder.
+		if (lzma_block_header_encode(&coder->block_options,
+				coder->buffer) != LZMA_OK)
+			return LZMA_PROG_ERROR;
+
+		coder->buffer_size = coder->block_options.header_size;
+		coder->sequence = SEQ_BLOCK_HEADER;
+		break;
+	}
+
+	case SEQ_BLOCK_ENCODE: {
+		static const lzma_action convert[LZMA_ACTION_MAX + 1] = {
+			LZMA_RUN,
+			LZMA_SYNC_FLUSH,
+			LZMA_FINISH,
+			LZMA_FINISH,
+			LZMA_FINISH,
+		};
+
+		const lzma_ret ret = coder->block_encoder.code(
+				coder->block_encoder.coder, allocator,
+				in, in_pos, in_size,
+				out, out_pos, out_size, convert[action]);
+		if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
+			return ret;
+
+		// Add a new Index Record.
+		const lzma_vli unpadded_size = lzma_block_unpadded_size(
+				&coder->block_options);
+		assert(unpadded_size != 0);
+		return_if_error(lzma_index_append(coder->index, allocator,
+				unpadded_size,
+				coder->block_options.uncompressed_size));
+
+		coder->sequence = SEQ_BLOCK_INIT;
+		break;
+	}
+
+	case SEQ_INDEX_ENCODE: {
+		// Call the Index encoder. It doesn't take any input, so
+		// those pointers can be NULL.
+		const lzma_ret ret = coder->index_encoder.code(
+				coder->index_encoder.coder, allocator,
+				NULL, NULL, 0,
+				out, out_pos, out_size, LZMA_RUN);
+		if (ret != LZMA_STREAM_END)
+			return ret;
+
+		// Encode the Stream Footer into coder->buffer.
+		const lzma_stream_flags stream_flags = {
+			.version = 0,
+			.backward_size = lzma_index_size(coder->index),
+			.check = coder->block_options.check,
+		};
+
+		if (lzma_stream_footer_encode(&stream_flags, coder->buffer)
+				!= LZMA_OK)
+			return LZMA_PROG_ERROR;
+
+		coder->buffer_size = LZMA_STREAM_HEADER_SIZE;
+		coder->sequence = SEQ_STREAM_FOOTER;
+		break;
+	}
+
+	default:
+		assert(0);
+		return LZMA_PROG_ERROR;
+	}
+
+	return LZMA_OK;
+}
+
+
+static void
+stream_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_stream_coder *coder = coder_ptr;
+
+	lzma_next_end(&coder->block_encoder, allocator);
+	lzma_next_end(&coder->index_encoder, allocator);
+	lzma_index_end(coder->index, allocator);
+
+	lzma_filters_free(coder->filters, allocator);
+
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_ret
+stream_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
+		const lzma_filter *filters,
+		const lzma_filter *reversed_filters)
+{
+	lzma_stream_coder *coder = coder_ptr;
+	lzma_ret ret;
+
+	// Make a copy to a temporary buffer first. This way it is easier
+	// to keep the encoder state unchanged if an error occurs with
+	// lzma_filters_copy().
+	lzma_filter temp[LZMA_FILTERS_MAX + 1];
+	return_if_error(lzma_filters_copy(filters, temp, allocator));
+
+	if (coder->sequence <= SEQ_BLOCK_INIT) {
+		// There is no incomplete Block waiting to be finished,
+		// thus we can change the whole filter chain. Start by
+		// trying to initialize the Block encoder with the new
+		// chain. This way we detect if the chain is valid.
+		coder->block_encoder_is_initialized = false;
+		coder->block_options.filters = temp;
+		ret = block_encoder_init(coder, allocator);
+		coder->block_options.filters = coder->filters;
+		if (ret != LZMA_OK)
+			goto error;
+
+		coder->block_encoder_is_initialized = true;
+
+	} else if (coder->sequence <= SEQ_BLOCK_ENCODE) {
+		// We are in the middle of a Block. Try to update only
+		// the filter-specific options.
+		ret = coder->block_encoder.update(
+				coder->block_encoder.coder, allocator,
+				filters, reversed_filters);
+		if (ret != LZMA_OK)
+			goto error;
+	} else {
+		// Trying to update the filter chain when we are already
+		// encoding Index or Stream Footer.
+		ret = LZMA_PROG_ERROR;
+		goto error;
+	}
+
+	// Free the options of the old chain.
+	lzma_filters_free(coder->filters, allocator);
+
+	// Copy the new filter chain in place.
+	memcpy(coder->filters, temp, sizeof(temp));
+
+	return LZMA_OK;
+
+error:
+	lzma_filters_free(temp, allocator);
+	return ret;
+}
+
+
+static lzma_ret
+stream_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter *filters, lzma_check check)
+{
+	lzma_next_coder_init(&stream_encoder_init, next, allocator);
+
+	if (filters == NULL)
+		return LZMA_PROG_ERROR;
+
+	lzma_stream_coder *coder = next->coder;
+
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_stream_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+		next->code = &stream_encode;
+		next->end = &stream_encoder_end;
+		next->update = &stream_encoder_update;
+
+		coder->filters[0].id = LZMA_VLI_UNKNOWN;
+		coder->block_encoder = LZMA_NEXT_CODER_INIT;
+		coder->index_encoder = LZMA_NEXT_CODER_INIT;
+		coder->index = NULL;
+	}
+
+	// Basic initializations
+	coder->sequence = SEQ_STREAM_HEADER;
+	coder->block_options.version = 0;
+	coder->block_options.check = check;
+
+	// Initialize the Index
+	lzma_index_end(coder->index, allocator);
+	coder->index = lzma_index_init(allocator);
+	if (coder->index == NULL)
+		return LZMA_MEM_ERROR;
+
+	// Encode the Stream Header
+	lzma_stream_flags stream_flags = {
+		.version = 0,
+		.check = check,
+	};
+	return_if_error(lzma_stream_header_encode(
+			&stream_flags, coder->buffer));
+
+	coder->buffer_pos = 0;
+	coder->buffer_size = LZMA_STREAM_HEADER_SIZE;
+
+	// Initialize the Block encoder. This way we detect unsupported
+	// filter chains when initializing the Stream encoder instead of
+	// giving an error after Stream Header has already been written out.
+	return stream_encoder_update(coder, allocator, filters, NULL);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_encoder(lzma_stream *strm,
+		const lzma_filter *filters, lzma_check check)
+{
+	lzma_next_strm_init(stream_encoder_init, strm, filters, check);
+
+	strm->internal->supported_actions[LZMA_RUN] = true;
+	strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
+	strm->internal->supported_actions[LZMA_FULL_FLUSH] = true;
+	strm->internal->supported_actions[LZMA_FULL_BARRIER] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder_mt.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder_mt.c
new file mode 100644
index 00000000000..f0fef152331
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_encoder_mt.c
@@ -0,0 +1,1280 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       stream_encoder_mt.c
+/// \brief      Multithreaded .xz Stream encoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_encoder.h"
+#include "easy_preset.h"
+#include "block_encoder.h"
+#include "block_buffer_encoder.h"
+#include "index_encoder.h"
+#include "outqueue.h"
+
+
+/// Maximum supported block size. This makes it simpler to prevent integer
+/// overflows if we are given unusually large block size.
+#define BLOCK_SIZE_MAX (UINT64_MAX / LZMA_THREADS_MAX)
+
+
+typedef enum {
+	/// Waiting for work.
+	THR_IDLE,
+
+	/// Encoding is in progress.
+	THR_RUN,
+
+	/// Encoding is in progress but no more input data will
+	/// be read.
+	THR_FINISH,
+
+	/// The main thread wants the thread to stop whatever it was doing
+	/// but not exit.
+	THR_STOP,
+
+	/// The main thread wants the thread to exit. We could use
+	/// cancellation but since there's stopped anyway, this is lazier.
+	THR_EXIT,
+
+} worker_state;
+
+typedef struct lzma_stream_coder_s lzma_stream_coder;
+
+typedef struct worker_thread_s worker_thread;
+struct worker_thread_s {
+	worker_state state;
+
+	/// Input buffer of coder->block_size bytes. The main thread will
+	/// put new input into this and update in_size accordingly. Once
+	/// no more input is coming, state will be set to THR_FINISH.
+	uint8_t *in;
+
+	/// Amount of data available in the input buffer. This is modified
+	/// only by the main thread.
+	size_t in_size;
+
+	/// Output buffer for this thread. This is set by the main
+	/// thread every time a new Block is started with this thread
+	/// structure.
+	lzma_outbuf *outbuf;
+
+	/// Pointer to the main structure is needed when putting this
+	/// thread back to the stack of free threads.
+	lzma_stream_coder *coder;
+
+	/// The allocator is set by the main thread. Since a copy of the
+	/// pointer is kept here, the application must not change the
+	/// allocator before calling lzma_end().
+	const lzma_allocator *allocator;
+
+	/// Amount of uncompressed data that has already been compressed.
+	uint64_t progress_in;
+
+	/// Amount of compressed data that is ready.
+	uint64_t progress_out;
+
+	/// Block encoder
+	lzma_next_coder block_encoder;
+
+	/// Compression options for this Block
+	lzma_block block_options;
+
+	/// Filter chain for this thread. By copying the filters array
+	/// to each thread it is possible to change the filter chain
+	/// between Blocks using lzma_filters_update().
+	lzma_filter filters[LZMA_FILTERS_MAX + 1];
+
+	/// Next structure in the stack of free worker threads.
+	worker_thread *next;
+
+	mythread_mutex mutex;
+	mythread_cond cond;
+
+	/// The ID of this thread is used to join the thread
+	/// when it's not needed anymore.
+	mythread thread_id;
+};
+
+
+struct lzma_stream_coder_s {
+	enum {
+		SEQ_STREAM_HEADER,
+		SEQ_BLOCK,
+		SEQ_INDEX,
+		SEQ_STREAM_FOOTER,
+	} sequence;
+
+	/// Start a new Block every block_size bytes of input unless
+	/// LZMA_FULL_FLUSH or LZMA_FULL_BARRIER is used earlier.
+	size_t block_size;
+
+	/// The filter chain to use for the next Block.
+	/// This can be updated using lzma_filters_update()
+	/// after LZMA_FULL_BARRIER or LZMA_FULL_FLUSH.
+	lzma_filter filters[LZMA_FILTERS_MAX + 1];
+
+	/// A copy of filters[] will be put here when attempting to get
+	/// a new worker thread. This will be copied to a worker thread
+	/// when a thread becomes free and then this cache is marked as
+	/// empty by setting [0].id = LZMA_VLI_UNKNOWN. Without this cache
+	/// the filter options from filters[] would get uselessly copied
+	/// multiple times (allocated and freed) when waiting for a new free
+	/// worker thread.
+	///
+	/// This is freed if filters[] is updated via lzma_filters_update().
+	lzma_filter filters_cache[LZMA_FILTERS_MAX + 1];
+
+
+	/// Index to hold sizes of the Blocks
+	lzma_index *index;
+
+	/// Index encoder
+	lzma_next_coder index_encoder;
+
+
+	/// Stream Flags for encoding the Stream Header and Stream Footer.
+	lzma_stream_flags stream_flags;
+
+	/// Buffer to hold Stream Header and Stream Footer.
+	uint8_t header[LZMA_STREAM_HEADER_SIZE];
+
+	/// Read position in header[]
+	size_t header_pos;
+
+
+	/// Output buffer queue for compressed data
+	lzma_outq outq;
+
+	/// How much memory to allocate for each lzma_outbuf.buf
+	size_t outbuf_alloc_size;
+
+
+	/// Maximum wait time if cannot use all the input and cannot
+	/// fill the output buffer. This is in milliseconds.
+	uint32_t timeout;
+
+
+	/// Error code from a worker thread
+	lzma_ret thread_error;
+
+	/// Array of allocated thread-specific structures
+	worker_thread *threads;
+
+	/// Number of structures in "threads" above. This is also the
+	/// number of threads that will be created at maximum.
+	uint32_t threads_max;
+
+	/// Number of thread structures that have been initialized, and
+	/// thus the number of worker threads actually created so far.
+	uint32_t threads_initialized;
+
+	/// Stack of free threads. When a thread finishes, it puts itself
+	/// back into this stack. This starts as empty because threads
+	/// are created only when actually needed.
+	worker_thread *threads_free;
+
+	/// The most recent worker thread to which the main thread writes
+	/// the new input from the application.
+	worker_thread *thr;
+
+
+	/// Amount of uncompressed data in Blocks that have already
+	/// been finished.
+	uint64_t progress_in;
+
+	/// Amount of compressed data in Stream Header + Blocks that
+	/// have already been finished.
+	uint64_t progress_out;
+
+
+	mythread_mutex mutex;
+	mythread_cond cond;
+};
+
+
+/// Tell the main thread that something has gone wrong.
+static void
+worker_error(worker_thread *thr, lzma_ret ret)
+{
+	assert(ret != LZMA_OK);
+	assert(ret != LZMA_STREAM_END);
+
+	mythread_sync(thr->coder->mutex) {
+		if (thr->coder->thread_error == LZMA_OK)
+			thr->coder->thread_error = ret;
+
+		mythread_cond_signal(&thr->coder->cond);
+	}
+
+	return;
+}
+
+
+static worker_state
+worker_encode(worker_thread *thr, size_t *out_pos, worker_state state)
+{
+	assert(thr->progress_in == 0);
+	assert(thr->progress_out == 0);
+
+	// Set the Block options.
+	thr->block_options = (lzma_block){
+		.version = 0,
+		.check = thr->coder->stream_flags.check,
+		.compressed_size = thr->outbuf->allocated,
+		.uncompressed_size = thr->coder->block_size,
+		.filters = thr->filters,
+	};
+
+	// Calculate maximum size of the Block Header. This amount is
+	// reserved in the beginning of the buffer so that Block Header
+	// along with Compressed Size and Uncompressed Size can be
+	// written there.
+	lzma_ret ret = lzma_block_header_size(&thr->block_options);
+	if (ret != LZMA_OK) {
+		worker_error(thr, ret);
+		return THR_STOP;
+	}
+
+	// Initialize the Block encoder.
+	ret = lzma_block_encoder_init(&thr->block_encoder,
+			thr->allocator, &thr->block_options);
+	if (ret != LZMA_OK) {
+		worker_error(thr, ret);
+		return THR_STOP;
+	}
+
+	size_t in_pos = 0;
+	size_t in_size = 0;
+
+	*out_pos = thr->block_options.header_size;
+	const size_t out_size = thr->outbuf->allocated;
+
+	do {
+		mythread_sync(thr->mutex) {
+			// Store in_pos and *out_pos into *thr so that
+			// an application may read them via
+			// lzma_get_progress() to get progress information.
+			//
+			// NOTE: These aren't updated when the encoding
+			// finishes. Instead, the final values are taken
+			// later from thr->outbuf.
+			thr->progress_in = in_pos;
+			thr->progress_out = *out_pos;
+
+			while (in_size == thr->in_size
+					&& thr->state == THR_RUN)
+				mythread_cond_wait(&thr->cond, &thr->mutex);
+
+			state = thr->state;
+			in_size = thr->in_size;
+		}
+
+		// Return if we were asked to stop or exit.
+		if (state >= THR_STOP)
+			return state;
+
+		lzma_action action = state == THR_FINISH
+				? LZMA_FINISH : LZMA_RUN;
+
+		// Limit the amount of input given to the Block encoder
+		// at once. This way this thread can react fairly quickly
+		// if the main thread wants us to stop or exit.
+		static const size_t in_chunk_max = 16384;
+		size_t in_limit = in_size;
+		if (in_size - in_pos > in_chunk_max) {
+			in_limit = in_pos + in_chunk_max;
+			action = LZMA_RUN;
+		}
+
+		ret = thr->block_encoder.code(
+				thr->block_encoder.coder, thr->allocator,
+				thr->in, &in_pos, in_limit, thr->outbuf->buf,
+				out_pos, out_size, action);
+	} while (ret == LZMA_OK && *out_pos < out_size);
+
+	switch (ret) {
+	case LZMA_STREAM_END:
+		assert(state == THR_FINISH);
+
+		// Encode the Block Header. By doing it after
+		// the compression, we can store the Compressed Size
+		// and Uncompressed Size fields.
+		ret = lzma_block_header_encode(&thr->block_options,
+				thr->outbuf->buf);
+		if (ret != LZMA_OK) {
+			worker_error(thr, ret);
+			return THR_STOP;
+		}
+
+		break;
+
+	case LZMA_OK:
+		// The data was incompressible. Encode it using uncompressed
+		// LZMA2 chunks.
+		//
+		// First wait that we have gotten all the input.
+		mythread_sync(thr->mutex) {
+			while (thr->state == THR_RUN)
+				mythread_cond_wait(&thr->cond, &thr->mutex);
+
+			state = thr->state;
+			in_size = thr->in_size;
+		}
+
+		if (state >= THR_STOP)
+			return state;
+
+		// Do the encoding. This takes care of the Block Header too.
+		*out_pos = 0;
+		ret = lzma_block_uncomp_encode(&thr->block_options,
+				thr->in, in_size, thr->outbuf->buf,
+				out_pos, out_size);
+
+		// It shouldn't fail.
+		if (ret != LZMA_OK) {
+			worker_error(thr, LZMA_PROG_ERROR);
+			return THR_STOP;
+		}
+
+		break;
+
+	default:
+		worker_error(thr, ret);
+		return THR_STOP;
+	}
+
+	// Set the size information that will be read by the main thread
+	// to write the Index field.
+	thr->outbuf->unpadded_size
+			= lzma_block_unpadded_size(&thr->block_options);
+	assert(thr->outbuf->unpadded_size != 0);
+	thr->outbuf->uncompressed_size = thr->block_options.uncompressed_size;
+
+	return THR_FINISH;
+}
+
+
+static MYTHREAD_RET_TYPE
+worker_start(void *thr_ptr)
+{
+	worker_thread *thr = thr_ptr;
+	worker_state state = THR_IDLE; // Init to silence a warning
+
+	while (true) {
+		// Wait for work.
+		mythread_sync(thr->mutex) {
+			while (true) {
+				// The thread is already idle so if we are
+				// requested to stop, just set the state.
+				if (thr->state == THR_STOP) {
+					thr->state = THR_IDLE;
+					mythread_cond_signal(&thr->cond);
+				}
+
+				state = thr->state;
+				if (state != THR_IDLE)
+					break;
+
+				mythread_cond_wait(&thr->cond, &thr->mutex);
+			}
+		}
+
+		size_t out_pos = 0;
+
+		assert(state != THR_IDLE);
+		assert(state != THR_STOP);
+
+		if (state <= THR_FINISH)
+			state = worker_encode(thr, &out_pos, state);
+
+		if (state == THR_EXIT)
+			break;
+
+		// Mark the thread as idle unless the main thread has
+		// told us to exit. Signal is needed for the case
+		// where the main thread is waiting for the threads to stop.
+		mythread_sync(thr->mutex) {
+			if (thr->state != THR_EXIT) {
+				thr->state = THR_IDLE;
+				mythread_cond_signal(&thr->cond);
+			}
+		}
+
+		mythread_sync(thr->coder->mutex) {
+			// If no errors occurred, make the encoded data
+			// available to be copied out.
+			if (state == THR_FINISH) {
+				thr->outbuf->pos = out_pos;
+				thr->outbuf->finished = true;
+			}
+
+			// Update the main progress info.
+			thr->coder->progress_in
+					+= thr->outbuf->uncompressed_size;
+			thr->coder->progress_out += out_pos;
+			thr->progress_in = 0;
+			thr->progress_out = 0;
+
+			// Return this thread to the stack of free threads.
+			thr->next = thr->coder->threads_free;
+			thr->coder->threads_free = thr;
+
+			mythread_cond_signal(&thr->coder->cond);
+		}
+	}
+
+	// Exiting, free the resources.
+	lzma_filters_free(thr->filters, thr->allocator);
+
+	mythread_mutex_destroy(&thr->mutex);
+	mythread_cond_destroy(&thr->cond);
+
+	lzma_next_end(&thr->block_encoder, thr->allocator);
+	lzma_free(thr->in, thr->allocator);
+	return MYTHREAD_RET_VALUE;
+}
+
+
+/// Make the threads stop but not exit. Optionally wait for them to stop.
+static void
+threads_stop(lzma_stream_coder *coder, bool wait_for_threads)
+{
+	// Tell the threads to stop.
+	for (uint32_t i = 0; i < coder->threads_initialized; ++i) {
+		mythread_sync(coder->threads[i].mutex) {
+			coder->threads[i].state = THR_STOP;
+			mythread_cond_signal(&coder->threads[i].cond);
+		}
+	}
+
+	if (!wait_for_threads)
+		return;
+
+	// Wait for the threads to settle in the idle state.
+	for (uint32_t i = 0; i < coder->threads_initialized; ++i) {
+		mythread_sync(coder->threads[i].mutex) {
+			while (coder->threads[i].state != THR_IDLE)
+				mythread_cond_wait(&coder->threads[i].cond,
+						&coder->threads[i].mutex);
+		}
+	}
+
+	return;
+}
+
+
+/// Stop the threads and free the resources associated with them.
+/// Wait until the threads have exited.
+static void
+threads_end(lzma_stream_coder *coder, const lzma_allocator *allocator)
+{
+	for (uint32_t i = 0; i < coder->threads_initialized; ++i) {
+		mythread_sync(coder->threads[i].mutex) {
+			coder->threads[i].state = THR_EXIT;
+			mythread_cond_signal(&coder->threads[i].cond);
+		}
+	}
+
+	for (uint32_t i = 0; i < coder->threads_initialized; ++i) {
+		int ret = mythread_join(coder->threads[i].thread_id);
+		assert(ret == 0);
+		(void)ret;
+	}
+
+	lzma_free(coder->threads, allocator);
+	return;
+}
+
+
+/// Initialize a new worker_thread structure and create a new thread.
+static lzma_ret
+initialize_new_thread(lzma_stream_coder *coder,
+		const lzma_allocator *allocator)
+{
+	worker_thread *thr = &coder->threads[coder->threads_initialized];
+
+	thr->in = lzma_alloc(coder->block_size, allocator);
+	if (thr->in == NULL)
+		return LZMA_MEM_ERROR;
+
+	if (mythread_mutex_init(&thr->mutex))
+		goto error_mutex;
+
+	if (mythread_cond_init(&thr->cond))
+		goto error_cond;
+
+	thr->state = THR_IDLE;
+	thr->allocator = allocator;
+	thr->coder = coder;
+	thr->progress_in = 0;
+	thr->progress_out = 0;
+	thr->block_encoder = LZMA_NEXT_CODER_INIT;
+	thr->filters[0].id = LZMA_VLI_UNKNOWN;
+
+	if (mythread_create(&thr->thread_id, &worker_start, thr))
+		goto error_thread;
+
+	++coder->threads_initialized;
+	coder->thr = thr;
+
+	return LZMA_OK;
+
+error_thread:
+	mythread_cond_destroy(&thr->cond);
+
+error_cond:
+	mythread_mutex_destroy(&thr->mutex);
+
+error_mutex:
+	lzma_free(thr->in, allocator);
+	return LZMA_MEM_ERROR;
+}
+
+
+static lzma_ret
+get_thread(lzma_stream_coder *coder, const lzma_allocator *allocator)
+{
+	// If there are no free output subqueues, there is no
+	// point to try getting a thread.
+	if (!lzma_outq_has_buf(&coder->outq))
+		return LZMA_OK;
+
+	// That's also true if we cannot allocate memory for the output
+	// buffer in the output queue.
+	return_if_error(lzma_outq_prealloc_buf(&coder->outq, allocator,
+			coder->outbuf_alloc_size));
+
+	// Make a thread-specific copy of the filter chain. Put it in
+	// the cache array first so that if we cannot get a new thread yet,
+	// the allocation is ready when we try again.
+	if (coder->filters_cache[0].id == LZMA_VLI_UNKNOWN)
+		return_if_error(lzma_filters_copy(
+			coder->filters, coder->filters_cache, allocator));
+
+	// If there is a free structure on the stack, use it.
+	mythread_sync(coder->mutex) {
+		if (coder->threads_free != NULL) {
+			coder->thr = coder->threads_free;
+			coder->threads_free = coder->threads_free->next;
+		}
+	}
+
+	if (coder->thr == NULL) {
+		// If there are no uninitialized structures left, return.
+		if (coder->threads_initialized == coder->threads_max)
+			return LZMA_OK;
+
+		// Initialize a new thread.
+		return_if_error(initialize_new_thread(coder, allocator));
+	}
+
+	// Reset the parts of the thread state that have to be done
+	// in the main thread.
+	mythread_sync(coder->thr->mutex) {
+		coder->thr->state = THR_RUN;
+		coder->thr->in_size = 0;
+		coder->thr->outbuf = lzma_outq_get_buf(&coder->outq, NULL);
+
+		// Free the old thread-specific filter options and replace
+		// them with the already-allocated new options from
+		// coder->filters_cache[]. Then mark the cache as empty.
+		lzma_filters_free(coder->thr->filters, allocator);
+		memcpy(coder->thr->filters, coder->filters_cache,
+				sizeof(coder->filters_cache));
+		coder->filters_cache[0].id = LZMA_VLI_UNKNOWN;
+
+		mythread_cond_signal(&coder->thr->cond);
+	}
+
+	return LZMA_OK;
+}
+
+
+static lzma_ret
+stream_encode_in(lzma_stream_coder *coder, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, lzma_action action)
+{
+	while (*in_pos < in_size
+			|| (coder->thr != NULL && action != LZMA_RUN)) {
+		if (coder->thr == NULL) {
+			// Get a new thread.
+			const lzma_ret ret = get_thread(coder, allocator);
+			if (coder->thr == NULL)
+				return ret;
+		}
+
+		// Copy the input data to thread's buffer.
+		size_t thr_in_size = coder->thr->in_size;
+		lzma_bufcpy(in, in_pos, in_size, coder->thr->in,
+				&thr_in_size, coder->block_size);
+
+		// Tell the Block encoder to finish if
+		//  - it has got block_size bytes of input; or
+		//  - all input was used and LZMA_FINISH, LZMA_FULL_FLUSH,
+		//    or LZMA_FULL_BARRIER was used.
+		//
+		// TODO: LZMA_SYNC_FLUSH and LZMA_SYNC_BARRIER.
+		const bool finish = thr_in_size == coder->block_size
+				|| (*in_pos == in_size && action != LZMA_RUN);
+
+		bool block_error = false;
+
+		mythread_sync(coder->thr->mutex) {
+			if (coder->thr->state == THR_IDLE) {
+				// Something has gone wrong with the Block
+				// encoder. It has set coder->thread_error
+				// which we will read a few lines later.
+				block_error = true;
+			} else {
+				// Tell the Block encoder its new amount
+				// of input and update the state if needed.
+				coder->thr->in_size = thr_in_size;
+
+				if (finish)
+					coder->thr->state = THR_FINISH;
+
+				mythread_cond_signal(&coder->thr->cond);
+			}
+		}
+
+		if (block_error) {
+			lzma_ret ret = LZMA_OK; // Init to silence a warning.
+
+			mythread_sync(coder->mutex) {
+				ret = coder->thread_error;
+			}
+
+			return ret;
+		}
+
+		if (finish)
+			coder->thr = NULL;
+	}
+
+	return LZMA_OK;
+}
+
+
+/// Wait until more input can be consumed, more output can be read, or
+/// an optional timeout is reached.
+static bool
+wait_for_work(lzma_stream_coder *coder, mythread_condtime *wait_abs,
+		bool *has_blocked, bool has_input)
+{
+	if (coder->timeout != 0 && !*has_blocked) {
+		// Every time when stream_encode_mt() is called via
+		// lzma_code(), *has_blocked starts as false. We set it
+		// to true here and calculate the absolute time when
+		// we must return if there's nothing to do.
+		//
+		// This way if we block multiple times for short moments
+		// less than "timeout" milliseconds, we will return once
+		// "timeout" amount of time has passed since the *first*
+		// blocking occurred. If the absolute time was calculated
+		// again every time we block, "timeout" would effectively
+		// be meaningless if we never consecutively block longer
+		// than "timeout" ms.
+		*has_blocked = true;
+		mythread_condtime_set(wait_abs, &coder->cond, coder->timeout);
+	}
+
+	bool timed_out = false;
+
+	mythread_sync(coder->mutex) {
+		// There are four things that we wait. If one of them
+		// becomes possible, we return.
+		//  - If there is input left, we need to get a free
+		//    worker thread and an output buffer for it.
+		//  - Data ready to be read from the output queue.
+		//  - A worker thread indicates an error.
+		//  - Time out occurs.
+		while ((!has_input || coder->threads_free == NULL
+					|| !lzma_outq_has_buf(&coder->outq))
+				&& !lzma_outq_is_readable(&coder->outq)
+				&& coder->thread_error == LZMA_OK
+				&& !timed_out) {
+			if (coder->timeout != 0)
+				timed_out = mythread_cond_timedwait(
+						&coder->cond, &coder->mutex,
+						wait_abs) != 0;
+			else
+				mythread_cond_wait(&coder->cond,
+						&coder->mutex);
+		}
+	}
+
+	return timed_out;
+}
+
+
+static lzma_ret
+stream_encode_mt(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size, lzma_action action)
+{
+	lzma_stream_coder *coder = coder_ptr;
+
+	switch (coder->sequence) {
+	case SEQ_STREAM_HEADER:
+		lzma_bufcpy(coder->header, &coder->header_pos,
+				sizeof(coder->header),
+				out, out_pos, out_size);
+		if (coder->header_pos < sizeof(coder->header))
+			return LZMA_OK;
+
+		coder->header_pos = 0;
+		coder->sequence = SEQ_BLOCK;
+
+	// Fall through
+
+	case SEQ_BLOCK: {
+		// Initialized to silence warnings.
+		lzma_vli unpadded_size = 0;
+		lzma_vli uncompressed_size = 0;
+		lzma_ret ret = LZMA_OK;
+
+		// These are for wait_for_work().
+		bool has_blocked = false;
+		mythread_condtime wait_abs = { 0 };
+
+		while (true) {
+			mythread_sync(coder->mutex) {
+				// Check for Block encoder errors.
+				ret = coder->thread_error;
+				if (ret != LZMA_OK) {
+					assert(ret != LZMA_STREAM_END);
+					break; // Break out of mythread_sync.
+				}
+
+				// Try to read compressed data to out[].
+				ret = lzma_outq_read(&coder->outq, allocator,
+						out, out_pos, out_size,
+						&unpadded_size,
+						&uncompressed_size);
+			}
+
+			if (ret == LZMA_STREAM_END) {
+				// End of Block. Add it to the Index.
+				ret = lzma_index_append(coder->index,
+						allocator, unpadded_size,
+						uncompressed_size);
+				if (ret != LZMA_OK) {
+					threads_stop(coder, false);
+					return ret;
+				}
+
+				// If we didn't fill the output buffer yet,
+				// try to read more data. Maybe the next
+				// outbuf has been finished already too.
+				if (*out_pos < out_size)
+					continue;
+			}
+
+			if (ret != LZMA_OK) {
+				// coder->thread_error was set.
+				threads_stop(coder, false);
+				return ret;
+			}
+
+			// Try to give uncompressed data to a worker thread.
+			ret = stream_encode_in(coder, allocator,
+					in, in_pos, in_size, action);
+			if (ret != LZMA_OK) {
+				threads_stop(coder, false);
+				return ret;
+			}
+
+			// See if we should wait or return.
+			//
+			// TODO: LZMA_SYNC_FLUSH and LZMA_SYNC_BARRIER.
+			if (*in_pos == in_size) {
+				// LZMA_RUN: More data is probably coming
+				// so return to let the caller fill the
+				// input buffer.
+				if (action == LZMA_RUN)
+					return LZMA_OK;
+
+				// LZMA_FULL_BARRIER: The same as with
+				// LZMA_RUN but tell the caller that the
+				// barrier was completed.
+				if (action == LZMA_FULL_BARRIER)
+					return LZMA_STREAM_END;
+
+				// Finishing or flushing isn't completed until
+				// all input data has been encoded and copied
+				// to the output buffer.
+				if (lzma_outq_is_empty(&coder->outq)) {
+					// LZMA_FINISH: Continue to encode
+					// the Index field.
+					if (action == LZMA_FINISH)
+						break;
+
+					// LZMA_FULL_FLUSH: Return to tell
+					// the caller that flushing was
+					// completed.
+					if (action == LZMA_FULL_FLUSH)
+						return LZMA_STREAM_END;
+				}
+			}
+
+			// Return if there is no output space left.
+			// This check must be done after testing the input
+			// buffer, because we might want to use a different
+			// return code.
+			if (*out_pos == out_size)
+				return LZMA_OK;
+
+			// Neither in nor out has been used completely.
+			// Wait until there's something we can do.
+			if (wait_for_work(coder, &wait_abs, &has_blocked,
+					*in_pos < in_size))
+				return LZMA_TIMED_OUT;
+		}
+
+		// All Blocks have been encoded and the threads have stopped.
+		// Prepare to encode the Index field.
+		return_if_error(lzma_index_encoder_init(
+				&coder->index_encoder, allocator,
+				coder->index));
+		coder->sequence = SEQ_INDEX;
+
+		// Update the progress info to take the Index and
+		// Stream Footer into account. Those are very fast to encode
+		// so in terms of progress information they can be thought
+		// to be ready to be copied out.
+		coder->progress_out += lzma_index_size(coder->index)
+				+ LZMA_STREAM_HEADER_SIZE;
+	}
+
+	// Fall through
+
+	case SEQ_INDEX: {
+		// Call the Index encoder. It doesn't take any input, so
+		// those pointers can be NULL.
+		const lzma_ret ret = coder->index_encoder.code(
+				coder->index_encoder.coder, allocator,
+				NULL, NULL, 0,
+				out, out_pos, out_size, LZMA_RUN);
+		if (ret != LZMA_STREAM_END)
+			return ret;
+
+		// Encode the Stream Footer into coder->buffer.
+		coder->stream_flags.backward_size
+				= lzma_index_size(coder->index);
+		if (lzma_stream_footer_encode(&coder->stream_flags,
+				coder->header) != LZMA_OK)
+			return LZMA_PROG_ERROR;
+
+		coder->sequence = SEQ_STREAM_FOOTER;
+	}
+
+	// Fall through
+
+	case SEQ_STREAM_FOOTER:
+		lzma_bufcpy(coder->header, &coder->header_pos,
+				sizeof(coder->header),
+				out, out_pos, out_size);
+		return coder->header_pos < sizeof(coder->header)
+				? LZMA_OK : LZMA_STREAM_END;
+	}
+
+	assert(0);
+	return LZMA_PROG_ERROR;
+}
+
+
+static void
+stream_encoder_mt_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_stream_coder *coder = coder_ptr;
+
+	// Threads must be killed before the output queue can be freed.
+	threads_end(coder, allocator);
+	lzma_outq_end(&coder->outq, allocator);
+
+	lzma_filters_free(coder->filters, allocator);
+	lzma_filters_free(coder->filters_cache, allocator);
+
+	lzma_next_end(&coder->index_encoder, allocator);
+	lzma_index_end(coder->index, allocator);
+
+	mythread_cond_destroy(&coder->cond);
+	mythread_mutex_destroy(&coder->mutex);
+
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_ret
+stream_encoder_mt_update(void *coder_ptr, const lzma_allocator *allocator,
+		const lzma_filter *filters,
+		const lzma_filter *reversed_filters
+			lzma_attribute((__unused__)))
+{
+	lzma_stream_coder *coder = coder_ptr;
+
+	// Applications shouldn't attempt to change the options when
+	// we are already encoding the Index or Stream Footer.
+	if (coder->sequence > SEQ_BLOCK)
+		return LZMA_PROG_ERROR;
+
+	// For now the threaded encoder doesn't support changing
+	// the options in the middle of a Block.
+	if (coder->thr != NULL)
+		return LZMA_PROG_ERROR;
+
+	// Check if the filter chain seems mostly valid. See the comment
+	// in stream_encoder_mt_init().
+	if (lzma_raw_encoder_memusage(filters) == UINT64_MAX)
+		return LZMA_OPTIONS_ERROR;
+
+	// Make a copy to a temporary buffer first. This way the encoder
+	// state stays unchanged if an error occurs in lzma_filters_copy().
+	lzma_filter temp[LZMA_FILTERS_MAX + 1];
+	return_if_error(lzma_filters_copy(filters, temp, allocator));
+
+	// Free the options of the old chain as well as the cache.
+	lzma_filters_free(coder->filters, allocator);
+	lzma_filters_free(coder->filters_cache, allocator);
+
+	// Copy the new filter chain in place.
+	memcpy(coder->filters, temp, sizeof(temp));
+
+	return LZMA_OK;
+}
+
+
+/// Options handling for lzma_stream_encoder_mt_init() and
+/// lzma_stream_encoder_mt_memusage()
+static lzma_ret
+get_options(const lzma_mt *options, lzma_options_easy *opt_easy,
+		const lzma_filter **filters, uint64_t *block_size,
+		uint64_t *outbuf_size_max)
+{
+	// Validate some of the options.
+	if (options == NULL)
+		return LZMA_PROG_ERROR;
+
+	if (options->flags != 0 || options->threads == 0
+			|| options->threads > LZMA_THREADS_MAX)
+		return LZMA_OPTIONS_ERROR;
+
+	if (options->filters != NULL) {
+		// Filter chain was given, use it as is.
+		*filters = options->filters;
+	} else {
+		// Use a preset.
+		if (lzma_easy_preset(opt_easy, options->preset))
+			return LZMA_OPTIONS_ERROR;
+
+		*filters = opt_easy->filters;
+	}
+
+	// If the Block size is not set, determine it from the filter chain.
+	if (options->block_size > 0)
+		*block_size = options->block_size;
+	else
+		*block_size = lzma_mt_block_size(*filters);
+
+	// UINT64_MAX > BLOCK_SIZE_MAX, so the second condition
+	// should be optimized out by any reasonable compiler.
+	// The second condition should be there in the unlikely event that
+	// the macros change and UINT64_MAX < BLOCK_SIZE_MAX.
+	if (*block_size > BLOCK_SIZE_MAX || *block_size == UINT64_MAX)
+		return LZMA_OPTIONS_ERROR;
+
+	// Calculate the maximum amount output that a single output buffer
+	// may need to hold. This is the same as the maximum total size of
+	// a Block.
+	*outbuf_size_max = lzma_block_buffer_bound64(*block_size);
+	if (*outbuf_size_max == 0)
+		return LZMA_MEM_ERROR;
+
+	return LZMA_OK;
+}
+
+
+static void
+get_progress(void *coder_ptr, uint64_t *progress_in, uint64_t *progress_out)
+{
+	lzma_stream_coder *coder = coder_ptr;
+
+	// Lock coder->mutex to prevent finishing threads from moving their
+	// progress info from the worker_thread structure to lzma_stream_coder.
+	mythread_sync(coder->mutex) {
+		*progress_in = coder->progress_in;
+		*progress_out = coder->progress_out;
+
+		for (size_t i = 0; i < coder->threads_initialized; ++i) {
+			mythread_sync(coder->threads[i].mutex) {
+				*progress_in += coder->threads[i].progress_in;
+				*progress_out += coder->threads[i]
+						.progress_out;
+			}
+		}
+	}
+
+	return;
+}
+
+
+static lzma_ret
+stream_encoder_mt_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_mt *options)
+{
+	lzma_next_coder_init(&stream_encoder_mt_init, next, allocator);
+
+	// Get the filter chain.
+	lzma_options_easy easy;
+	const lzma_filter *filters;
+	uint64_t block_size;
+	uint64_t outbuf_size_max;
+	return_if_error(get_options(options, &easy, &filters,
+			&block_size, &outbuf_size_max));
+
+#if SIZE_MAX < UINT64_MAX
+	if (block_size > SIZE_MAX || outbuf_size_max > SIZE_MAX)
+		return LZMA_MEM_ERROR;
+#endif
+
+	// Validate the filter chain so that we can give an error in this
+	// function instead of delaying it to the first call to lzma_code().
+	// The memory usage calculation verifies the filter chain as
+	// a side effect so we take advantage of that. It's not a perfect
+	// check though as raw encoder allows LZMA1 too but such problems
+	// will be caught eventually with Block Header encoder.
+	if (lzma_raw_encoder_memusage(filters) == UINT64_MAX)
+		return LZMA_OPTIONS_ERROR;
+
+	// Validate the Check ID.
+	if ((unsigned int)(options->check) > LZMA_CHECK_ID_MAX)
+		return LZMA_PROG_ERROR;
+
+	if (!lzma_check_is_supported(options->check))
+		return LZMA_UNSUPPORTED_CHECK;
+
+	// Allocate and initialize the base structure if needed.
+	lzma_stream_coder *coder = next->coder;
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_stream_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+
+		// For the mutex and condition variable initializations
+		// the error handling has to be done here because
+		// stream_encoder_mt_end() doesn't know if they have
+		// already been initialized or not.
+		if (mythread_mutex_init(&coder->mutex)) {
+			lzma_free(coder, allocator);
+			next->coder = NULL;
+			return LZMA_MEM_ERROR;
+		}
+
+		if (mythread_cond_init(&coder->cond)) {
+			mythread_mutex_destroy(&coder->mutex);
+			lzma_free(coder, allocator);
+			next->coder = NULL;
+			return LZMA_MEM_ERROR;
+		}
+
+		next->code = &stream_encode_mt;
+		next->end = &stream_encoder_mt_end;
+		next->get_progress = &get_progress;
+		next->update = &stream_encoder_mt_update;
+
+		coder->filters[0].id = LZMA_VLI_UNKNOWN;
+		coder->filters_cache[0].id = LZMA_VLI_UNKNOWN;
+		coder->index_encoder = LZMA_NEXT_CODER_INIT;
+		coder->index = NULL;
+		memzero(&coder->outq, sizeof(coder->outq));
+		coder->threads = NULL;
+		coder->threads_max = 0;
+		coder->threads_initialized = 0;
+	}
+
+	// Basic initializations
+	coder->sequence = SEQ_STREAM_HEADER;
+	coder->block_size = (size_t)(block_size);
+	coder->outbuf_alloc_size = (size_t)(outbuf_size_max);
+	coder->thread_error = LZMA_OK;
+	coder->thr = NULL;
+
+	// Allocate the thread-specific base structures.
+	assert(options->threads > 0);
+	if (coder->threads_max != options->threads) {
+		threads_end(coder, allocator);
+
+		coder->threads = NULL;
+		coder->threads_max = 0;
+
+		coder->threads_initialized = 0;
+		coder->threads_free = NULL;
+
+		coder->threads = lzma_alloc(
+				options->threads * sizeof(worker_thread),
+				allocator);
+		if (coder->threads == NULL)
+			return LZMA_MEM_ERROR;
+
+		coder->threads_max = options->threads;
+	} else {
+		// Reuse the old structures and threads. Tell the running
+		// threads to stop and wait until they have stopped.
+		threads_stop(coder, true);
+	}
+
+	// Output queue
+	return_if_error(lzma_outq_init(&coder->outq, allocator,
+			options->threads));
+
+	// Timeout
+	coder->timeout = options->timeout;
+
+	// Free the old filter chain and the cache.
+	lzma_filters_free(coder->filters, allocator);
+	lzma_filters_free(coder->filters_cache, allocator);
+
+	// Copy the new filter chain.
+	return_if_error(lzma_filters_copy(
+			filters, coder->filters, allocator));
+
+	// Index
+	lzma_index_end(coder->index, allocator);
+	coder->index = lzma_index_init(allocator);
+	if (coder->index == NULL)
+		return LZMA_MEM_ERROR;
+
+	// Stream Header
+	coder->stream_flags.version = 0;
+	coder->stream_flags.check = options->check;
+	return_if_error(lzma_stream_header_encode(
+			&coder->stream_flags, coder->header));
+
+	coder->header_pos = 0;
+
+	// Progress info
+	coder->progress_in = 0;
+	coder->progress_out = LZMA_STREAM_HEADER_SIZE;
+
+	return LZMA_OK;
+}
+
+
+#ifdef HAVE_SYMBOL_VERSIONS_LINUX
+// These are for compatibility with binaries linked against liblzma that
+// has been patched with xz-5.2.2-compat-libs.patch from RHEL/CentOS 7.
+// Actually that patch didn't create lzma_stream_encoder_mt@XZ_5.2.2
+// but it has been added here anyway since someone might misread the
+// RHEL patch and think both @XZ_5.1.2alpha and @XZ_5.2.2 exist.
+LZMA_SYMVER_API("lzma_stream_encoder_mt@XZ_5.1.2alpha",
+	lzma_ret, lzma_stream_encoder_mt_512a)(
+		lzma_stream *strm, const lzma_mt *options)
+		lzma_nothrow lzma_attr_warn_unused_result
+		__attribute__((__alias__("lzma_stream_encoder_mt_52")));
+
+LZMA_SYMVER_API("lzma_stream_encoder_mt@XZ_5.2.2",
+	lzma_ret, lzma_stream_encoder_mt_522)(
+		lzma_stream *strm, const lzma_mt *options)
+		lzma_nothrow lzma_attr_warn_unused_result
+		__attribute__((__alias__("lzma_stream_encoder_mt_52")));
+
+LZMA_SYMVER_API("lzma_stream_encoder_mt@@XZ_5.2",
+	lzma_ret, lzma_stream_encoder_mt_52)(
+		lzma_stream *strm, const lzma_mt *options)
+		lzma_nothrow lzma_attr_warn_unused_result;
+
+#define lzma_stream_encoder_mt lzma_stream_encoder_mt_52
+#endif
+extern LZMA_API(lzma_ret)
+lzma_stream_encoder_mt(lzma_stream *strm, const lzma_mt *options)
+{
+	lzma_next_strm_init(stream_encoder_mt_init, strm, options);
+
+	strm->internal->supported_actions[LZMA_RUN] = true;
+// 	strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
+	strm->internal->supported_actions[LZMA_FULL_FLUSH] = true;
+	strm->internal->supported_actions[LZMA_FULL_BARRIER] = true;
+	strm->internal->supported_actions[LZMA_FINISH] = true;
+
+	return LZMA_OK;
+}
+
+
+#ifdef HAVE_SYMBOL_VERSIONS_LINUX
+LZMA_SYMVER_API("lzma_stream_encoder_mt_memusage@XZ_5.1.2alpha",
+	uint64_t, lzma_stream_encoder_mt_memusage_512a)(
+	const lzma_mt *options) lzma_nothrow lzma_attr_pure
+	__attribute__((__alias__("lzma_stream_encoder_mt_memusage_52")));
+
+LZMA_SYMVER_API("lzma_stream_encoder_mt_memusage@XZ_5.2.2",
+	uint64_t, lzma_stream_encoder_mt_memusage_522)(
+	const lzma_mt *options) lzma_nothrow lzma_attr_pure
+	__attribute__((__alias__("lzma_stream_encoder_mt_memusage_52")));
+
+LZMA_SYMVER_API("lzma_stream_encoder_mt_memusage@@XZ_5.2",
+	uint64_t, lzma_stream_encoder_mt_memusage_52)(
+	const lzma_mt *options) lzma_nothrow lzma_attr_pure;
+
+#define lzma_stream_encoder_mt_memusage lzma_stream_encoder_mt_memusage_52
+#endif
+// This function name is a monster but it's consistent with the older
+// monster names. :-( 31 chars is the max that C99 requires so in that
+// sense it's not too long. ;-)
+extern LZMA_API(uint64_t)
+lzma_stream_encoder_mt_memusage(const lzma_mt *options)
+{
+	lzma_options_easy easy;
+	const lzma_filter *filters;
+	uint64_t block_size;
+	uint64_t outbuf_size_max;
+
+	if (get_options(options, &easy, &filters, &block_size,
+			&outbuf_size_max) != LZMA_OK)
+		return UINT64_MAX;
+
+	// Memory usage of the input buffers
+	const uint64_t inbuf_memusage = options->threads * block_size;
+
+	// Memory usage of the filter encoders
+	uint64_t filters_memusage = lzma_raw_encoder_memusage(filters);
+	if (filters_memusage == UINT64_MAX)
+		return UINT64_MAX;
+
+	filters_memusage *= options->threads;
+
+	// Memory usage of the output queue
+	const uint64_t outq_memusage = lzma_outq_memusage(
+			outbuf_size_max, options->threads);
+	if (outq_memusage == UINT64_MAX)
+		return UINT64_MAX;
+
+	// Sum them with overflow checking.
+	uint64_t total_memusage = LZMA_MEMUSAGE_BASE
+			+ sizeof(lzma_stream_coder)
+			+ options->threads * sizeof(worker_thread);
+
+	if (UINT64_MAX - total_memusage < inbuf_memusage)
+		return UINT64_MAX;
+
+	total_memusage += inbuf_memusage;
+
+	if (UINT64_MAX - total_memusage < filters_memusage)
+		return UINT64_MAX;
+
+	total_memusage += filters_memusage;
+
+	if (UINT64_MAX - total_memusage < outq_memusage)
+		return UINT64_MAX;
+
+	return total_memusage + outq_memusage;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.c
new file mode 100644
index 00000000000..41b8dcb70d7
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       stream_flags_common.c
+/// \brief      Common stuff for Stream flags coders
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "stream_flags_common.h"
+
+
+const uint8_t lzma_header_magic[6] = { 0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00 };
+const uint8_t lzma_footer_magic[2] = { 0x59, 0x5A };
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_flags_compare(
+		const lzma_stream_flags *a, const lzma_stream_flags *b)
+{
+	// We can compare only version 0 structures.
+	if (a->version != 0 || b->version != 0)
+		return LZMA_OPTIONS_ERROR;
+
+	// Check type
+	if ((unsigned int)(a->check) > LZMA_CHECK_ID_MAX
+			|| (unsigned int)(b->check) > LZMA_CHECK_ID_MAX)
+		return LZMA_PROG_ERROR;
+
+	if (a->check != b->check)
+		return LZMA_DATA_ERROR;
+
+	// Backward Sizes are compared only if they are known in both.
+	if (a->backward_size != LZMA_VLI_UNKNOWN
+			&& b->backward_size != LZMA_VLI_UNKNOWN) {
+		if (!is_backward_size_valid(a) || !is_backward_size_valid(b))
+			return LZMA_PROG_ERROR;
+
+		if (a->backward_size != b->backward_size)
+			return LZMA_DATA_ERROR;
+	}
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.h
new file mode 100644
index 00000000000..28729dbcb6f
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_common.h
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       stream_flags_common.h
+/// \brief      Common stuff for Stream flags coders
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_STREAM_FLAGS_COMMON_H
+#define LZMA_STREAM_FLAGS_COMMON_H
+
+#include "common.h"
+
+/// Size of the Stream Flags field
+#define LZMA_STREAM_FLAGS_SIZE 2
+
+lzma_attr_visibility_hidden
+extern const uint8_t lzma_header_magic[6];
+
+lzma_attr_visibility_hidden
+extern const uint8_t lzma_footer_magic[2];
+
+
+static inline bool
+is_backward_size_valid(const lzma_stream_flags *options)
+{
+	return options->backward_size >= LZMA_BACKWARD_SIZE_MIN
+			&& options->backward_size <= LZMA_BACKWARD_SIZE_MAX
+			&& (options->backward_size & 3) == 0;
+}
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_decoder.c
new file mode 100644
index 00000000000..522c98b6fd5
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_decoder.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       stream_flags_decoder.c
+/// \brief      Decodes Stream Header and Stream Footer from .xz files
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "stream_flags_common.h"
+
+
+static bool
+stream_flags_decode(lzma_stream_flags *options, const uint8_t *in)
+{
+	// Reserved bits must be unset.
+	if (in[0] != 0x00 || (in[1] & 0xF0))
+		return true;
+
+	options->version = 0;
+	options->check = in[1] & 0x0F;
+
+	return false;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_header_decode(lzma_stream_flags *options, const uint8_t *in)
+{
+	// Magic
+	if (memcmp(in, lzma_header_magic, sizeof(lzma_header_magic)) != 0)
+		return LZMA_FORMAT_ERROR;
+
+	// Verify the CRC32 so we can distinguish between corrupt
+	// and unsupported files.
+	const uint32_t crc = lzma_crc32(in + sizeof(lzma_header_magic),
+			LZMA_STREAM_FLAGS_SIZE, 0);
+	if (crc != read32le(in + sizeof(lzma_header_magic)
+			+ LZMA_STREAM_FLAGS_SIZE)) {
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+		return LZMA_DATA_ERROR;
+#endif
+	}
+
+	// Stream Flags
+	if (stream_flags_decode(options, in + sizeof(lzma_header_magic)))
+		return LZMA_OPTIONS_ERROR;
+
+	// Set Backward Size to indicate unknown value. That way
+	// lzma_stream_flags_compare() can be used to compare Stream Header
+	// and Stream Footer while keeping it useful also for comparing
+	// two Stream Footers.
+	options->backward_size = LZMA_VLI_UNKNOWN;
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_footer_decode(lzma_stream_flags *options, const uint8_t *in)
+{
+	// Magic
+	if (memcmp(in + sizeof(uint32_t) * 2 + LZMA_STREAM_FLAGS_SIZE,
+			lzma_footer_magic, sizeof(lzma_footer_magic)) != 0)
+		return LZMA_FORMAT_ERROR;
+
+	// CRC32
+	const uint32_t crc = lzma_crc32(in + sizeof(uint32_t),
+			sizeof(uint32_t) + LZMA_STREAM_FLAGS_SIZE, 0);
+	if (crc != read32le(in)) {
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+		return LZMA_DATA_ERROR;
+#endif
+	}
+
+	// Stream Flags
+	if (stream_flags_decode(options, in + sizeof(uint32_t) * 2))
+		return LZMA_OPTIONS_ERROR;
+
+	// Backward Size
+	options->backward_size = read32le(in + sizeof(uint32_t));
+	options->backward_size = (options->backward_size + 1) * 4;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_encoder.c
new file mode 100644
index 00000000000..f94b5cd0a23
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/stream_flags_encoder.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       stream_flags_encoder.c
+/// \brief      Encodes Stream Header and Stream Footer for .xz files
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "stream_flags_common.h"
+
+
+static bool
+stream_flags_encode(const lzma_stream_flags *options, uint8_t *out)
+{
+	if ((unsigned int)(options->check) > LZMA_CHECK_ID_MAX)
+		return true;
+
+	out[0] = 0x00;
+	out[1] = options->check;
+
+	return false;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_header_encode(const lzma_stream_flags *options, uint8_t *out)
+{
+	assert(sizeof(lzma_header_magic) + LZMA_STREAM_FLAGS_SIZE
+			+ 4 == LZMA_STREAM_HEADER_SIZE);
+
+	if (options->version != 0)
+		return LZMA_OPTIONS_ERROR;
+
+	// Magic
+	memcpy(out, lzma_header_magic, sizeof(lzma_header_magic));
+
+	// Stream Flags
+	if (stream_flags_encode(options, out + sizeof(lzma_header_magic)))
+		return LZMA_PROG_ERROR;
+
+	// CRC32 of the Stream Header
+	const uint32_t crc = lzma_crc32(out + sizeof(lzma_header_magic),
+			LZMA_STREAM_FLAGS_SIZE, 0);
+
+	write32le(out + sizeof(lzma_header_magic) + LZMA_STREAM_FLAGS_SIZE,
+			crc);
+
+	return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_footer_encode(const lzma_stream_flags *options, uint8_t *out)
+{
+	assert(2 * 4 + LZMA_STREAM_FLAGS_SIZE + sizeof(lzma_footer_magic)
+			== LZMA_STREAM_HEADER_SIZE);
+
+	if (options->version != 0)
+		return LZMA_OPTIONS_ERROR;
+
+	// Backward Size
+	if (!is_backward_size_valid(options))
+		return LZMA_PROG_ERROR;
+
+	write32le(out + 4, options->backward_size / 4 - 1);
+
+	// Stream Flags
+	if (stream_flags_encode(options, out + 2 * 4))
+		return LZMA_PROG_ERROR;
+
+	// CRC32
+	const uint32_t crc = lzma_crc32(
+			out + 4, 4 + LZMA_STREAM_FLAGS_SIZE, 0);
+
+	write32le(out, crc);
+
+	// Magic
+	memcpy(out + 2 * 4 + LZMA_STREAM_FLAGS_SIZE,
+			lzma_footer_magic, sizeof(lzma_footer_magic));
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/string_conversion.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/string_conversion.c
new file mode 100644
index 00000000000..c899783c642
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/string_conversion.c
@@ -0,0 +1,1338 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       string_conversion.c
+/// \brief      Conversion of strings to filter chain and vice versa
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_common.h"
+
+
+/////////////////////
+// String building //
+/////////////////////
+
+/// How much memory to allocate for strings. For now, no realloc is used
+/// so this needs to be big enough even though there of course is
+/// an overflow check still.
+///
+/// FIXME? Using a fixed size is wasteful if the application doesn't free
+/// the string fairly quickly but this can be improved later if needed.
+#define STR_ALLOC_SIZE 800
+
+
+typedef struct {
+	char *buf;
+	size_t pos;
+} lzma_str;
+
+
+static lzma_ret
+str_init(lzma_str *str, const lzma_allocator *allocator)
+{
+	str->buf = lzma_alloc(STR_ALLOC_SIZE, allocator);
+	if (str->buf == NULL)
+		return LZMA_MEM_ERROR;
+
+	str->pos = 0;
+	return LZMA_OK;
+}
+
+
+static void
+str_free(lzma_str *str, const lzma_allocator *allocator)
+{
+	lzma_free(str->buf, allocator);
+	return;
+}
+
+
+static bool
+str_is_full(const lzma_str *str)
+{
+	return str->pos == STR_ALLOC_SIZE - 1;
+}
+
+
+static lzma_ret
+str_finish(char **dest, lzma_str *str, const lzma_allocator *allocator)
+{
+	if (str_is_full(str)) {
+		// The preallocated buffer was too small.
+		// This shouldn't happen as STR_ALLOC_SIZE should
+		// be adjusted if new filters are added.
+		lzma_free(str->buf, allocator);
+		*dest = NULL;
+		assert(0);
+		return LZMA_PROG_ERROR;
+	}
+
+	str->buf[str->pos] = '\0';
+	*dest = str->buf;
+	return LZMA_OK;
+}
+
+
+static void
+str_append_str(lzma_str *str, const char *s)
+{
+	const size_t len = strlen(s);
+	const size_t limit = STR_ALLOC_SIZE - 1 - str->pos;
+	const size_t copy_size = my_min(len, limit);
+
+	memcpy(str->buf + str->pos, s, copy_size);
+	str->pos += copy_size;
+	return;
+}
+
+
+static void
+str_append_u32(lzma_str *str, uint32_t v, bool use_byte_suffix)
+{
+	if (v == 0) {
+		str_append_str(str, "0");
+	} else {
+		// NOTE: Don't use plain "B" because xz and the parser in this
+		// file don't support it and at glance it may look like 8
+		// (there cannot be a space before the suffix).
+		static const char suffixes[4][4] = { "", "KiB", "MiB", "GiB" };
+
+		size_t suf = 0;
+		if (use_byte_suffix) {
+			while ((v & 1023) == 0
+					&& suf < ARRAY_SIZE(suffixes) - 1) {
+				v >>= 10;
+				++suf;
+			}
+		}
+
+		// UINT32_MAX in base 10 would need 10 + 1 bytes. Remember
+		// that initializing to "" initializes all elements to
+		// zero so '\0'-termination gets handled by this.
+		char buf[16] = "";
+		size_t pos = sizeof(buf) - 1;
+
+		do {
+			buf[--pos] = '0' + (v % 10);
+			v /= 10;
+		} while (v != 0);
+
+		str_append_str(str, buf + pos);
+		str_append_str(str, suffixes[suf]);
+	}
+
+	return;
+}
+
+
+//////////////////////////////////////////////
+// Parsing and stringification declarations //
+//////////////////////////////////////////////
+
+/// Maximum length for filter and option names.
+/// 11 chars + terminating '\0' + sizeof(uint32_t) = 16 bytes
+#define NAME_LEN_MAX 11
+
+
+/// For option_map.flags: Use .u.map to do convert the input value
+/// to an integer. Without this flag, .u.range.{min,max} are used
+/// as the allowed range for the integer.
+#define OPTMAP_USE_NAME_VALUE_MAP 0x01
+
+/// For option_map.flags: Allow KiB/MiB/GiB in input string and use them in
+/// the stringified output if the value is an exact multiple of these.
+/// This is used e.g. for LZMA1/2 dictionary size.
+#define OPTMAP_USE_BYTE_SUFFIX 0x02
+
+/// For option_map.flags: If the integer value is zero then this option
+/// won't be included in the stringified output. It's used e.g. for
+/// BCJ filter start offset which usually is zero.
+#define OPTMAP_NO_STRFY_ZERO 0x04
+
+/// Possible values for option_map.type. Since OPTMAP_TYPE_UINT32 is 0,
+/// it doesn't need to be specified in the initializers as it is
+/// the implicit value.
+enum {
+	OPTMAP_TYPE_UINT32,
+	OPTMAP_TYPE_LZMA_MODE,
+	OPTMAP_TYPE_LZMA_MATCH_FINDER,
+	OPTMAP_TYPE_LZMA_PRESET,
+};
+
+
+/// This is for mapping string values in options to integers.
+/// The last element of an array must have "" as the name.
+/// It's used e.g. for match finder names in LZMA1/2.
+typedef struct {
+	const char name[NAME_LEN_MAX + 1];
+	const uint32_t value;
+} name_value_map;
+
+
+/// Each filter that has options needs an array of option_map structures.
+/// The array doesn't need to be terminated as the functions take the
+/// length of the array as an argument.
+///
+/// When converting a string to filter options structure, option values
+/// will be handled in a few different ways:
+///
+/// (1) If .type equals OPTMAP_TYPE_LZMA_PRESET then LZMA1/2 preset string
+///     is handled specially.
+///
+/// (2) If .flags has OPTMAP_USE_NAME_VALUE_MAP set then the string is
+///     converted to an integer using the name_value_map pointed by .u.map.
+///     The last element in .u.map must have .name = "" as the terminator.
+///
+/// (3) Otherwise the string is treated as a non-negative unsigned decimal
+///     integer which must be in the range set in .u.range. If .flags has
+///     OPTMAP_USE_BYTE_SUFFIX then KiB, MiB, and GiB suffixes are allowed.
+///
+/// The integer value from (2) or (3) is then stored to filter_options
+/// at the offset specified in .offset using the type specified in .type
+/// (default is uint32_t).
+///
+/// Stringifying a filter is done by processing a given number of options
+/// in order from the beginning of an option_map array. The integer is
+/// read from filter_options at .offset using the type from .type.
+///
+/// If the integer is zero and .flags has OPTMAP_NO_STRFY_ZERO then the
+/// option is skipped.
+///
+/// If .flags has OPTMAP_USE_NAME_VALUE_MAP set then .u.map will be used
+/// to convert the option to a string. If the map doesn't contain a string
+/// for the integer value then "UNKNOWN" is used.
+///
+/// If .flags doesn't have OPTMAP_USE_NAME_VALUE_MAP set then the integer is
+/// converted to a decimal value. If OPTMAP_USE_BYTE_SUFFIX is used then KiB,
+/// MiB, or GiB suffix is used if the value is an exact multiple of these.
+/// Plain "B" suffix is never used.
+typedef struct {
+	char name[NAME_LEN_MAX + 1];
+	uint8_t type;
+	uint8_t flags;
+	uint16_t offset;
+
+	union {
+		// NVHPC has problems with unions that contain pointers that
+		// are not the first members, so keep "map" at the top.
+		const name_value_map *map;
+
+		struct {
+			uint32_t min;
+			uint32_t max;
+		} range;
+	} u;
+} option_map;
+
+
+static const char *parse_options(const char **const str, const char *str_end,
+		void *filter_options,
+		const option_map *const optmap, const size_t optmap_size);
+
+
+/////////
+// BCJ //
+/////////
+
+#if defined(HAVE_ENCODER_X86) \
+		|| defined(HAVE_DECODER_X86) \
+		|| defined(HAVE_ENCODER_ARM) \
+		|| defined(HAVE_DECODER_ARM) \
+		|| defined(HAVE_ENCODER_ARMTHUMB) \
+		|| defined(HAVE_DECODER_ARMTHUMB) \
+		|| defined(HAVE_ENCODER_ARM64) \
+		|| defined(HAVE_DECODER_ARM64) \
+		|| defined(HAVE_ENCODER_POWERPC) \
+		|| defined(HAVE_DECODER_POWERPC) \
+		|| defined(HAVE_ENCODER_IA64) \
+		|| defined(HAVE_DECODER_IA64) \
+		|| defined(HAVE_ENCODER_SPARC) \
+		|| defined(HAVE_DECODER_SPARC) \
+		|| defined(HAVE_ENCODER_RISCV) \
+		|| defined(HAVE_DECODER_RISCV)
+static const option_map bcj_optmap[] = {
+	{
+		.name = "start",
+		.flags = OPTMAP_NO_STRFY_ZERO | OPTMAP_USE_BYTE_SUFFIX,
+		.offset = offsetof(lzma_options_bcj, start_offset),
+		.u.range.min = 0,
+		.u.range.max = UINT32_MAX,
+	}
+};
+
+
+static const char *
+parse_bcj(const char **const str, const char *str_end, void *filter_options)
+{
+	// filter_options was zeroed on allocation and that is enough
+	// for the default value.
+	return parse_options(str, str_end, filter_options,
+			bcj_optmap, ARRAY_SIZE(bcj_optmap));
+}
+#endif
+
+
+///////////
+// Delta //
+///////////
+
+#if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
+static const option_map delta_optmap[] = {
+	{
+		.name = "dist",
+		.offset = offsetof(lzma_options_delta, dist),
+		.u.range.min = LZMA_DELTA_DIST_MIN,
+		.u.range.max = LZMA_DELTA_DIST_MAX,
+	}
+};
+
+
+static const char *
+parse_delta(const char **const str, const char *str_end, void *filter_options)
+{
+	lzma_options_delta *opts = filter_options;
+	opts->type = LZMA_DELTA_TYPE_BYTE;
+	opts->dist = LZMA_DELTA_DIST_MIN;
+
+	return parse_options(str, str_end, filter_options,
+			delta_optmap, ARRAY_SIZE(delta_optmap));
+}
+#endif
+
+
+///////////////////
+// LZMA1 & LZMA2 //
+///////////////////
+
+/// Help string for presets
+#define LZMA12_PRESET_STR "0-9[e]"
+
+
+static const char *
+parse_lzma12_preset(const char **const str, const char *str_end,
+		uint32_t *preset)
+{
+	assert(*str < str_end);
+	*preset = (uint32_t)(**str - '0');
+
+	// NOTE: Remember to update LZMA12_PRESET_STR if this is modified!
+	while (++*str < str_end) {
+		switch (**str) {
+		case 'e':
+			*preset |= LZMA_PRESET_EXTREME;
+			break;
+
+		default:
+			return "Unsupported preset flag";
+		}
+	}
+
+	return NULL;
+}
+
+
+static const char *
+set_lzma12_preset(const char **const str, const char *str_end,
+		void *filter_options)
+{
+	uint32_t preset;
+	const char *errmsg = parse_lzma12_preset(str, str_end, &preset);
+	if (errmsg != NULL)
+		return errmsg;
+
+	lzma_options_lzma *opts = filter_options;
+	if (lzma_lzma_preset(opts, preset))
+		return "Unsupported preset";
+
+	return NULL;
+}
+
+
+static const name_value_map lzma12_mode_map[] = {
+	{ "fast",   LZMA_MODE_FAST },
+	{ "normal", LZMA_MODE_NORMAL },
+	{ "",       0 }
+};
+
+
+static const name_value_map lzma12_mf_map[] = {
+	{ "hc3", LZMA_MF_HC3 },
+	{ "hc4", LZMA_MF_HC4 },
+	{ "bt2", LZMA_MF_BT2 },
+	{ "bt3", LZMA_MF_BT3 },
+	{ "bt4", LZMA_MF_BT4 },
+	{ "",    0 }
+};
+
+
+static const option_map lzma12_optmap[] = {
+	{
+		.name = "preset",
+		.type = OPTMAP_TYPE_LZMA_PRESET,
+	}, {
+		.name = "dict",
+		.flags = OPTMAP_USE_BYTE_SUFFIX,
+		.offset = offsetof(lzma_options_lzma, dict_size),
+		.u.range.min = LZMA_DICT_SIZE_MIN,
+		// FIXME? The max is really max for encoding but decoding
+		// would allow 4 GiB - 1 B.
+		.u.range.max = (UINT32_C(1) << 30) + (UINT32_C(1) << 29),
+	}, {
+		.name = "lc",
+		.offset = offsetof(lzma_options_lzma, lc),
+		.u.range.min = LZMA_LCLP_MIN,
+		.u.range.max = LZMA_LCLP_MAX,
+	}, {
+		.name = "lp",
+		.offset = offsetof(lzma_options_lzma, lp),
+		.u.range.min = LZMA_LCLP_MIN,
+		.u.range.max = LZMA_LCLP_MAX,
+	}, {
+		.name = "pb",
+		.offset = offsetof(lzma_options_lzma, pb),
+		.u.range.min = LZMA_PB_MIN,
+		.u.range.max = LZMA_PB_MAX,
+	}, {
+		.name = "mode",
+		.type = OPTMAP_TYPE_LZMA_MODE,
+		.flags = OPTMAP_USE_NAME_VALUE_MAP,
+		.offset = offsetof(lzma_options_lzma, mode),
+		.u.map = lzma12_mode_map,
+	}, {
+		.name = "nice",
+		.offset = offsetof(lzma_options_lzma, nice_len),
+		.u.range.min = 2,
+		.u.range.max = 273,
+	}, {
+		.name = "mf",
+		.type = OPTMAP_TYPE_LZMA_MATCH_FINDER,
+		.flags = OPTMAP_USE_NAME_VALUE_MAP,
+		.offset = offsetof(lzma_options_lzma, mf),
+		.u.map = lzma12_mf_map,
+	}, {
+		.name = "depth",
+		.offset = offsetof(lzma_options_lzma, depth),
+		.u.range.min = 0,
+		.u.range.max = UINT32_MAX,
+	}
+};
+
+
+static const char *
+parse_lzma12(const char **const str, const char *str_end, void *filter_options)
+{
+	lzma_options_lzma *opts = filter_options;
+
+	// It cannot fail.
+	const bool preset_ret = lzma_lzma_preset(opts, LZMA_PRESET_DEFAULT);
+	assert(!preset_ret);
+	(void)preset_ret;
+
+	const char *errmsg = parse_options(str, str_end, filter_options,
+			lzma12_optmap, ARRAY_SIZE(lzma12_optmap));
+	if (errmsg != NULL)
+		return errmsg;
+
+	if (opts->lc + opts->lp > LZMA_LCLP_MAX)
+		return "The sum of lc and lp must not exceed 4";
+
+	return NULL;
+}
+
+
+/////////////////////////////////////////
+// Generic parsing and stringification //
+/////////////////////////////////////////
+
+static const struct {
+	/// Name of the filter
+	char name[NAME_LEN_MAX + 1];
+
+	/// For lzma_str_to_filters:
+	/// Size of the filter-specific options structure.
+	uint32_t opts_size;
+
+	/// Filter ID
+	lzma_vli id;
+
+	/// For lzma_str_to_filters:
+	/// Function to parse the filter-specific options. The filter_options
+	/// will already have been allocated using lzma_alloc_zero().
+	const char *(*parse)(const char **str, const char *str_end,
+			void *filter_options);
+
+	/// For lzma_str_from_filters:
+	/// If the flag LZMA_STR_ENCODER is used then the first
+	/// strfy_encoder elements of optmap are stringified.
+	/// With LZMA_STR_DECODER strfy_decoder is used.
+	/// Currently encoders use all options that decoders do but if
+	/// that changes then this needs to be changed too, for example,
+	/// add a new OPTMAP flag to skip printing some decoder-only options.
+	const option_map *optmap;
+	uint8_t strfy_encoder;
+	uint8_t strfy_decoder;
+
+	/// For lzma_str_from_filters:
+	/// If true, lzma_filter.options is allowed to be NULL. In that case,
+	/// only the filter name is printed without any options.
+	bool allow_null;
+
+} filter_name_map[] = {
+#if defined (HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1)
+	{ "lzma1",        sizeof(lzma_options_lzma),  LZMA_FILTER_LZMA1,
+	  &parse_lzma12,  lzma12_optmap, 9, 5, false },
+#endif
+
+#if defined(HAVE_ENCODER_LZMA2) || defined(HAVE_DECODER_LZMA2)
+	{ "lzma2",        sizeof(lzma_options_lzma),  LZMA_FILTER_LZMA2,
+	  &parse_lzma12,  lzma12_optmap, 9, 2, false },
+#endif
+
+#if defined(HAVE_ENCODER_X86) || defined(HAVE_DECODER_X86)
+	{ "x86",          sizeof(lzma_options_bcj),   LZMA_FILTER_X86,
+	  &parse_bcj,     bcj_optmap, 1, 1, true },
+#endif
+
+#if defined(HAVE_ENCODER_ARM) || defined(HAVE_DECODER_ARM)
+	{ "arm",          sizeof(lzma_options_bcj),   LZMA_FILTER_ARM,
+	  &parse_bcj,     bcj_optmap, 1, 1, true },
+#endif
+
+#if defined(HAVE_ENCODER_ARMTHUMB) || defined(HAVE_DECODER_ARMTHUMB)
+	{ "armthumb",     sizeof(lzma_options_bcj),   LZMA_FILTER_ARMTHUMB,
+	  &parse_bcj,     bcj_optmap, 1, 1, true },
+#endif
+
+#if defined(HAVE_ENCODER_ARM64) || defined(HAVE_DECODER_ARM64)
+	{ "arm64",        sizeof(lzma_options_bcj),   LZMA_FILTER_ARM64,
+	  &parse_bcj,     bcj_optmap, 1, 1, true },
+#endif
+
+#if defined(HAVE_ENCODER_RISCV) || defined(HAVE_DECODER_RISCV)
+	{ "riscv",        sizeof(lzma_options_bcj),   LZMA_FILTER_RISCV,
+	  &parse_bcj,     bcj_optmap, 1, 1, true },
+#endif
+
+#if defined(HAVE_ENCODER_POWERPC) || defined(HAVE_DECODER_POWERPC)
+	{ "powerpc",      sizeof(lzma_options_bcj),   LZMA_FILTER_POWERPC,
+	  &parse_bcj,     bcj_optmap, 1, 1, true },
+#endif
+
+#if defined(HAVE_ENCODER_IA64) || defined(HAVE_DECODER_IA64)
+	{ "ia64",         sizeof(lzma_options_bcj),   LZMA_FILTER_IA64,
+	  &parse_bcj,     bcj_optmap, 1, 1, true },
+#endif
+
+#if defined(HAVE_ENCODER_SPARC) || defined(HAVE_DECODER_SPARC)
+	{ "sparc",        sizeof(lzma_options_bcj),   LZMA_FILTER_SPARC,
+	  &parse_bcj,     bcj_optmap, 1, 1, true },
+#endif
+
+#if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
+	{ "delta",        sizeof(lzma_options_delta), LZMA_FILTER_DELTA,
+	  &parse_delta,   delta_optmap, 1, 1, false },
+#endif
+};
+
+
+/// Decodes options from a string for one filter (name1=value1,name2=value2).
+/// Caller must have allocated memory for filter_options already and set
+/// the initial default values. This is called from the filter-specific
+/// parse_* functions.
+///
+/// The input string starts at *str and the address in str_end is the first
+/// char that is not part of the string anymore. So no '\0' terminator is
+/// used. *str is advanced every time something has been decoded successfully.
+static const char *
+parse_options(const char **const str, const char *str_end,
+		void *filter_options,
+		const option_map *const optmap, const size_t optmap_size)
+{
+	while (*str < str_end && **str != '\0') {
+		// Each option is of the form name=value.
+		// Commas (',') separate options. Extra commas are ignored.
+		// Ignoring extra commas makes it simpler if an optional
+		// option stored in a shell variable which can be empty.
+		if (**str == ',') {
+			++*str;
+			continue;
+		}
+
+		// Find where the next name=value ends.
+		const size_t str_len = (size_t)(str_end - *str);
+		const char *name_eq_value_end = memchr(*str, ',', str_len);
+		if (name_eq_value_end == NULL)
+			name_eq_value_end = str_end;
+
+		const char *equals_sign = memchr(*str, '=',
+				(size_t)(name_eq_value_end - *str));
+
+		// Fail if the '=' wasn't found or the option name is missing
+		// (the first char is '=').
+		if (equals_sign == NULL || **str == '=')
+			return "Options must be 'name=value' pairs separated "
+					"with commas";
+
+		// Reject a too long option name so that the memcmp()
+		// in the loop below won't read past the end of the
+		// string in optmap[i].name.
+		const size_t name_len = (size_t)(equals_sign - *str);
+		if (name_len > NAME_LEN_MAX)
+			return "Unknown option name";
+
+		// Find the option name from optmap[].
+		size_t i = 0;
+		while (true) {
+			if (i == optmap_size)
+				return "Unknown option name";
+
+			if (memcmp(*str, optmap[i].name, name_len) == 0
+					&& optmap[i].name[name_len] == '\0')
+				break;
+
+			++i;
+		}
+
+		// The input string is good at least until the start of
+		// the option value.
+		*str = equals_sign + 1;
+
+		// The code assumes that the option value isn't an empty
+		// string so check it here.
+		const size_t value_len = (size_t)(name_eq_value_end - *str);
+		if (value_len == 0)
+			return "Option value cannot be empty";
+
+		// LZMA1/2 preset has its own parsing function.
+		if (optmap[i].type == OPTMAP_TYPE_LZMA_PRESET) {
+			const char *errmsg = set_lzma12_preset(str,
+					name_eq_value_end, filter_options);
+			if (errmsg != NULL)
+				return errmsg;
+
+			continue;
+		}
+
+		// It's an integer value.
+		uint32_t v;
+		if (optmap[i].flags & OPTMAP_USE_NAME_VALUE_MAP) {
+			// The integer is picked from a string-to-integer map.
+			//
+			// Reject a too long value string so that the memcmp()
+			// in the loop below won't read past the end of the
+			// string in optmap[i].u.map[j].name.
+			if (value_len > NAME_LEN_MAX)
+				return "Invalid option value";
+
+			const name_value_map *map = optmap[i].u.map;
+			size_t j = 0;
+			while (true) {
+				// The array is terminated with an empty name.
+				if (map[j].name[0] == '\0')
+					return "Invalid option value";
+
+				if (memcmp(*str, map[j].name, value_len) == 0
+						&& map[j].name[value_len]
+							== '\0') {
+					v = map[j].value;
+					break;
+				}
+
+				++j;
+			}
+		} else if (**str < '0' || **str > '9') {
+			// Note that "max" isn't supported while it is
+			// supported in xz. It's not useful here.
+			return "Value is not a non-negative decimal integer";
+		} else {
+			// strtoul() has locale-specific behavior so it cannot
+			// be relied on to get reproducible results since we
+			// cannot change the locate in a thread-safe library.
+			// It also needs '\0'-termination.
+			//
+			// Use a temporary pointer so that *str will point
+			// to the beginning of the value string in case
+			// an error occurs.
+			const char *p = *str;
+			v = 0;
+			do {
+				if (v > UINT32_MAX / 10)
+					return "Value out of range";
+
+				v *= 10;
+
+				const uint32_t add = (uint32_t)(*p - '0');
+				if (UINT32_MAX - add < v)
+					return "Value out of range";
+
+				v += add;
+				++p;
+			} while (p < name_eq_value_end
+					&& *p >= '0' && *p <= '9');
+
+			if (p < name_eq_value_end) {
+				// Remember this position so that it can be
+				// used for error messages that are
+				// specifically about the suffix. (Out of
+				// range values are about the whole value
+				// and those error messages point to the
+				// beginning of the number part,
+				// not to the suffix.)
+				const char *multiplier_start = p;
+
+				// If multiplier suffix shouldn't be used
+				// then don't allow them even if the value
+				// would stay within limits. This is a somewhat
+				// unnecessary check but it rejects silly
+				// things like lzma2:pb=0MiB which xz allows.
+				if ((optmap[i].flags & OPTMAP_USE_BYTE_SUFFIX)
+						== 0) {
+					*str = multiplier_start;
+					return "This option does not support "
+						"any integer suffixes";
+				}
+
+				uint32_t shift;
+
+				switch (*p) {
+				case 'k':
+				case 'K':
+					shift = 10;
+					break;
+
+				case 'm':
+				case 'M':
+					shift = 20;
+					break;
+
+				case 'g':
+				case 'G':
+					shift = 30;
+					break;
+
+				default:
+					*str = multiplier_start;
+					return "Invalid multiplier suffix "
+							"(KiB, MiB, or GiB)";
+				}
+
+				++p;
+
+				// Allow "M", "Mi", "MB", "MiB" and the same
+				// for the other five characters from the
+				// switch-statement above. All are handled
+				// as base-2 (perhaps a mistake, perhaps not).
+				// Note that 'i' and 'B' are case sensitive.
+				if (p < name_eq_value_end && *p == 'i')
+					++p;
+
+				if (p < name_eq_value_end && *p == 'B')
+					++p;
+
+				// Now we must have no chars remaining.
+				if (p < name_eq_value_end) {
+					*str = multiplier_start;
+					return "Invalid multiplier suffix "
+							"(KiB, MiB, or GiB)";
+				}
+
+				if (v > (UINT32_MAX >> shift))
+					return "Value out of range";
+
+				v <<= shift;
+			}
+
+			if (v < optmap[i].u.range.min
+					|| v > optmap[i].u.range.max)
+				return "Value out of range";
+		}
+
+		// Set the value in filter_options. Enums are handled
+		// specially since the underlying type isn't the same
+		// as uint32_t on all systems.
+		void *ptr = (char *)filter_options + optmap[i].offset;
+		switch (optmap[i].type) {
+		case OPTMAP_TYPE_LZMA_MODE:
+			*(lzma_mode *)ptr = (lzma_mode)v;
+			break;
+
+		case OPTMAP_TYPE_LZMA_MATCH_FINDER:
+			*(lzma_match_finder *)ptr = (lzma_match_finder)v;
+			break;
+
+		default:
+			*(uint32_t *)ptr = v;
+			break;
+		}
+
+		// This option has been successfully handled.
+		*str = name_eq_value_end;
+	}
+
+	// No errors.
+	return NULL;
+}
+
+
+/// Finds the name of the filter at the beginning of the string and
+/// calls filter_name_map[i].parse() to decode the filter-specific options.
+/// The caller must have set str_end so that exactly one filter and its
+/// options are present without any trailing characters.
+static const char *
+parse_filter(const char **const str, const char *str_end, lzma_filter *filter,
+		const lzma_allocator *allocator, bool only_xz)
+{
+	// Search for a colon or equals sign that would separate the filter
+	// name from filter options. If neither is found, then the input
+	// string only contains a filter name and there are no options.
+	//
+	// First assume that a colon or equals sign won't be found:
+	const char *name_end = str_end;
+	const char *opts_start = str_end;
+
+	for (const char *p = *str; p < str_end; ++p) {
+		if (*p == ':' || *p == '=') {
+			name_end = p;
+
+			// Filter options (name1=value1,name2=value2,...)
+			// begin after the colon or equals sign.
+			opts_start = p + 1;
+			break;
+		}
+	}
+
+	// Reject a too long filter name so that the memcmp()
+	// in the loop below won't read past the end of the
+	// string in filter_name_map[i].name.
+	const size_t name_len = (size_t)(name_end - *str);
+	if (name_len > NAME_LEN_MAX)
+		return "Unknown filter name";
+
+	for (size_t i = 0; i < ARRAY_SIZE(filter_name_map); ++i) {
+		if (memcmp(*str, filter_name_map[i].name, name_len) == 0
+				&& filter_name_map[i].name[name_len] == '\0') {
+			if (only_xz && filter_name_map[i].id
+					>= LZMA_FILTER_RESERVED_START)
+				return "This filter cannot be used in "
+						"the .xz format";
+
+			// Allocate the filter-specific options and
+			// initialize the memory with zeros.
+			void *options = lzma_alloc_zero(
+					filter_name_map[i].opts_size,
+					allocator);
+			if (options == NULL)
+				return "Memory allocation failed";
+
+			// Filter name was found so the input string is good
+			// at least this far.
+			*str = opts_start;
+
+			const char *errmsg = filter_name_map[i].parse(
+					str, str_end, options);
+			if (errmsg != NULL) {
+				lzma_free(options, allocator);
+				return errmsg;
+			}
+
+			// *filter is modified only when parsing is successful.
+			filter->id = filter_name_map[i].id;
+			filter->options = options;
+			return NULL;
+		}
+	}
+
+	return "Unknown filter name";
+}
+
+
+/// Converts the string to a filter chain (array of lzma_filter structures).
+///
+/// *str is advanced every time something has been decoded successfully.
+/// This way the caller knows where in the string a possible error occurred.
+static const char *
+str_to_filters(const char **const str, lzma_filter *filters, uint32_t flags,
+		const lzma_allocator *allocator)
+{
+	const char *errmsg;
+
+	// Skip leading spaces.
+	while (**str == ' ')
+		++*str;
+
+	if (**str == '\0')
+		return "Empty string is not allowed, "
+				"try \"6\" if a default value is needed";
+
+	// Detect the type of the string.
+	//
+	// A string beginning with a digit or a string beginning with
+	// one dash and a digit are treated as presets. Trailing spaces
+	// will be ignored too (leading spaces were already ignored above).
+	//
+	// For example, "6", "7  ", "-9e", or "  -3  " are treated as presets.
+	// Strings like "-" or "- " aren't preset.
+#define MY_IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
+	if (MY_IS_DIGIT(**str) || (**str == '-' && MY_IS_DIGIT((*str)[1]))) {
+		if (**str == '-')
+			++*str;
+
+		// Ignore trailing spaces.
+		const size_t str_len = strlen(*str);
+		const char *str_end = memchr(*str, ' ', str_len);
+		if (str_end != NULL) {
+			// There is at least one trailing space. Check that
+			// there are no chars other than spaces.
+			for (size_t i = 1; str_end[i] != '\0'; ++i)
+				if (str_end[i] != ' ')
+					return "Unsupported preset";
+		} else {
+			// There are no trailing spaces. Use the whole string.
+			str_end = *str + str_len;
+		}
+
+		uint32_t preset;
+		errmsg = parse_lzma12_preset(str, str_end, &preset);
+		if (errmsg != NULL)
+			return errmsg;
+
+		lzma_options_lzma *opts = lzma_alloc(sizeof(*opts), allocator);
+		if (opts == NULL)
+			return "Memory allocation failed";
+
+		if (lzma_lzma_preset(opts, preset)) {
+			lzma_free(opts, allocator);
+			return "Unsupported preset";
+		}
+
+		filters[0].id = LZMA_FILTER_LZMA2;
+		filters[0].options = opts;
+		filters[1].id = LZMA_VLI_UNKNOWN;
+		filters[1].options = NULL;
+
+		return NULL;
+	}
+
+	// Not a preset so it must be a filter chain.
+	//
+	// If LZMA_STR_ALL_FILTERS isn't used we allow only filters that
+	// can be used in .xz.
+	const bool only_xz = (flags & LZMA_STR_ALL_FILTERS) == 0;
+
+	// Use a temporary array so that we don't modify the caller-supplied
+	// one until we know that no errors occurred.
+	lzma_filter temp_filters[LZMA_FILTERS_MAX + 1];
+
+	size_t i = 0;
+	do {
+		if (i == LZMA_FILTERS_MAX) {
+			errmsg = "The maximum number of filters is four";
+			goto error;
+		}
+
+		// Skip "--" if present.
+		if ((*str)[0] == '-' && (*str)[1] == '-')
+			*str += 2;
+
+		// Locate the end of "filter:name1=value1,name2=value2",
+		// stopping at the first "--" or a single space.
+		const char *filter_end = *str;
+		while (filter_end[0] != '\0') {
+			if ((filter_end[0] == '-' && filter_end[1] == '-')
+					|| filter_end[0] == ' ')
+				break;
+
+			++filter_end;
+		}
+
+		// Inputs that have "--" at the end or "-- " in the middle
+		// will result in an empty filter name.
+		if (filter_end == *str) {
+			errmsg = "Filter name is missing";
+			goto error;
+		}
+
+		errmsg = parse_filter(str, filter_end, &temp_filters[i],
+				allocator, only_xz);
+		if (errmsg != NULL)
+			goto error;
+
+		// Skip trailing spaces.
+		while (**str == ' ')
+			++*str;
+
+		++i;
+	} while (**str != '\0');
+
+	// Seems to be good, terminate the array so that
+	// basic validation can be done.
+	temp_filters[i].id = LZMA_VLI_UNKNOWN;
+	temp_filters[i].options = NULL;
+
+	// Do basic validation if the application didn't prohibit it.
+	if ((flags & LZMA_STR_NO_VALIDATION) == 0) {
+		size_t dummy;
+		const lzma_ret ret = lzma_validate_chain(temp_filters, &dummy);
+		assert(ret == LZMA_OK || ret == LZMA_OPTIONS_ERROR);
+		if (ret != LZMA_OK) {
+			errmsg = "Invalid filter chain "
+					"('lzma2' missing at the end?)";
+			goto error;
+		}
+	}
+
+	// All good. Copy the filters to the application supplied array.
+	memcpy(filters, temp_filters, (i + 1) * sizeof(lzma_filter));
+	return NULL;
+
+error:
+	// Free the filter options that were successfully decoded.
+	while (i-- > 0)
+		lzma_free(temp_filters[i].options, allocator);
+
+	return errmsg;
+}
+
+
+extern LZMA_API(const char *)
+lzma_str_to_filters(const char *str, int *error_pos, lzma_filter *filters,
+		uint32_t flags, const lzma_allocator *allocator)
+{
+	// If error_pos isn't NULL, *error_pos must always be set.
+	// liblzma <= 5.4.6 and <= 5.6.1 have a bug and don't do this
+	// when str == NULL or filters == NULL or flags are unsupported.
+	if (error_pos != NULL)
+		*error_pos = 0;
+
+	if (str == NULL || filters == NULL)
+		return "Unexpected NULL pointer argument(s) "
+				"to lzma_str_to_filters()";
+
+	// Validate the flags.
+	const uint32_t supported_flags
+			= LZMA_STR_ALL_FILTERS
+			| LZMA_STR_NO_VALIDATION;
+
+	if (flags & ~supported_flags)
+		return "Unsupported flags to lzma_str_to_filters()";
+
+	const char *used = str;
+	const char *errmsg = str_to_filters(&used, filters, flags, allocator);
+
+	if (error_pos != NULL) {
+		const size_t n = (size_t)(used - str);
+		*error_pos = n > INT_MAX ? INT_MAX : (int)n;
+	}
+
+	return errmsg;
+}
+
+
+/// Converts options of one filter to a string.
+///
+/// The caller must have already put the filter name in the destination
+/// string. Since it is possible that no options will be needed, the caller
+/// won't have put a delimiter character (':' or '=') in the string yet.
+/// We will add it if at least one option will be added to the string.
+static void
+strfy_filter(lzma_str *dest, const char *delimiter,
+		const option_map *optmap, size_t optmap_count,
+		const void *filter_options)
+{
+	for (size_t i = 0; i < optmap_count; ++i) {
+		// No attempt is made to reverse LZMA1/2 preset.
+		if (optmap[i].type == OPTMAP_TYPE_LZMA_PRESET)
+			continue;
+
+		// All options have integer values, some just are mapped
+		// to a string with a name_value_map. LZMA1/2 preset
+		// isn't reversed back to preset=PRESET form.
+		uint32_t v;
+		const void *ptr
+			= (const char *)filter_options + optmap[i].offset;
+		switch (optmap[i].type) {
+			case OPTMAP_TYPE_LZMA_MODE:
+				v = *(const lzma_mode *)ptr;
+				break;
+
+			case OPTMAP_TYPE_LZMA_MATCH_FINDER:
+				v = *(const lzma_match_finder *)ptr;
+				break;
+
+			default:
+				v = *(const uint32_t *)ptr;
+				break;
+		}
+
+		// Skip this if this option should be omitted from
+		// the string when the value is zero.
+		if (v == 0 && (optmap[i].flags & OPTMAP_NO_STRFY_ZERO))
+			continue;
+
+		// Before the first option we add whatever delimiter
+		// the caller gave us. For later options a comma is used.
+		str_append_str(dest, delimiter);
+		delimiter = ",";
+
+		// Add the option name and equals sign.
+		str_append_str(dest, optmap[i].name);
+		str_append_str(dest, "=");
+
+		if (optmap[i].flags & OPTMAP_USE_NAME_VALUE_MAP) {
+			const name_value_map *map = optmap[i].u.map;
+			size_t j = 0;
+			while (true) {
+				if (map[j].name[0] == '\0') {
+					str_append_str(dest, "UNKNOWN");
+					break;
+				}
+
+				if (map[j].value == v) {
+					str_append_str(dest, map[j].name);
+					break;
+				}
+
+				++j;
+			}
+		} else {
+			str_append_u32(dest, v,
+				optmap[i].flags & OPTMAP_USE_BYTE_SUFFIX);
+		}
+	}
+
+	return;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_str_from_filters(char **output_str, const lzma_filter *filters,
+		uint32_t flags, const lzma_allocator *allocator)
+{
+	// On error *output_str is always set to NULL.
+	// Do it as the very first step.
+	if (output_str == NULL)
+		return LZMA_PROG_ERROR;
+
+	*output_str = NULL;
+
+	if (filters == NULL)
+		return LZMA_PROG_ERROR;
+
+	// Validate the flags.
+	const uint32_t supported_flags
+			= LZMA_STR_ENCODER
+			| LZMA_STR_DECODER
+			| LZMA_STR_GETOPT_LONG
+			| LZMA_STR_NO_SPACES;
+
+	if (flags & ~supported_flags)
+		return LZMA_OPTIONS_ERROR;
+
+	// There must be at least one filter.
+	if (filters[0].id == LZMA_VLI_UNKNOWN)
+		return LZMA_OPTIONS_ERROR;
+
+	// Allocate memory for the output string.
+	lzma_str dest;
+	return_if_error(str_init(&dest, allocator));
+
+	const bool show_opts = (flags & (LZMA_STR_ENCODER | LZMA_STR_DECODER));
+
+	const char *opt_delim = (flags & LZMA_STR_GETOPT_LONG) ? "=" : ":";
+
+	for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
+		// If we reach LZMA_FILTERS_MAX, then the filters array
+		// is too large since the ID cannot be LZMA_VLI_UNKNOWN here.
+		if (i == LZMA_FILTERS_MAX) {
+			str_free(&dest, allocator);
+			return LZMA_OPTIONS_ERROR;
+		}
+
+		// Don't add a space between filters if the caller
+		// doesn't want them.
+		if (i > 0 && !(flags & LZMA_STR_NO_SPACES))
+			str_append_str(&dest, " ");
+
+		// Use dashes for xz getopt_long() compatible syntax but also
+		// use dashes to separate filters when spaces weren't wanted.
+		if ((flags & LZMA_STR_GETOPT_LONG)
+				|| (i > 0 && (flags & LZMA_STR_NO_SPACES)))
+			str_append_str(&dest, "--");
+
+		size_t j = 0;
+		while (true) {
+			if (j == ARRAY_SIZE(filter_name_map)) {
+				// Filter ID in filters[i].id isn't supported.
+				str_free(&dest, allocator);
+				return LZMA_OPTIONS_ERROR;
+			}
+
+			if (filter_name_map[j].id == filters[i].id) {
+				// Add the filter name.
+				str_append_str(&dest, filter_name_map[j].name);
+
+				// If only the filter names were wanted then
+				// skip to the next filter. In this case
+				// .options is ignored and may be NULL even
+				// when the filter doesn't allow NULL options.
+				if (!show_opts)
+					break;
+
+				if (filters[i].options == NULL) {
+					if (!filter_name_map[j].allow_null) {
+						// Filter-specific options
+						// are missing but with
+						// this filter the options
+						// structure is mandatory.
+						str_free(&dest, allocator);
+						return LZMA_OPTIONS_ERROR;
+					}
+
+					// .options is allowed to be NULL.
+					// There is no need to add any
+					// options to the string.
+					break;
+				}
+
+				// Options structure is available. Add
+				// the filter options to the string.
+				const size_t optmap_count
+					= (flags & LZMA_STR_ENCODER)
+					? filter_name_map[j].strfy_encoder
+					: filter_name_map[j].strfy_decoder;
+				strfy_filter(&dest, opt_delim,
+						filter_name_map[j].optmap,
+						optmap_count,
+						filters[i].options);
+				break;
+			}
+
+			++j;
+		}
+	}
+
+	return str_finish(output_str, &dest, allocator);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_str_list_filters(char **output_str, lzma_vli filter_id, uint32_t flags,
+		const lzma_allocator *allocator)
+{
+	// On error *output_str is always set to NULL.
+	// Do it as the very first step.
+	if (output_str == NULL)
+		return LZMA_PROG_ERROR;
+
+	*output_str = NULL;
+
+	// Validate the flags.
+	const uint32_t supported_flags
+			= LZMA_STR_ALL_FILTERS
+			| LZMA_STR_ENCODER
+			| LZMA_STR_DECODER
+			| LZMA_STR_GETOPT_LONG;
+
+	if (flags & ~supported_flags)
+		return LZMA_OPTIONS_ERROR;
+
+	// Allocate memory for the output string.
+	lzma_str dest;
+	return_if_error(str_init(&dest, allocator));
+
+	// If only listing the filter names then separate them with spaces.
+	// Otherwise use newlines.
+	const bool show_opts = (flags & (LZMA_STR_ENCODER | LZMA_STR_DECODER));
+	const char *filter_delim = show_opts ? "\n" : " ";
+
+	const char *opt_delim = (flags & LZMA_STR_GETOPT_LONG) ? "=" : ":";
+	bool first_filter_printed = false;
+
+	for (size_t i = 0; i < ARRAY_SIZE(filter_name_map); ++i) {
+		// If we are printing only one filter then skip others.
+		if (filter_id != LZMA_VLI_UNKNOWN
+				&& filter_id != filter_name_map[i].id)
+			continue;
+
+		// If we are printing only .xz filters then skip the others.
+		if (filter_name_map[i].id >= LZMA_FILTER_RESERVED_START
+				&& (flags & LZMA_STR_ALL_FILTERS) == 0
+				&& filter_id == LZMA_VLI_UNKNOWN)
+			continue;
+
+		// Add a new line if this isn't the first filter being
+		// written to the string.
+		if (first_filter_printed)
+			str_append_str(&dest, filter_delim);
+
+		first_filter_printed = true;
+
+		if (flags & LZMA_STR_GETOPT_LONG)
+			str_append_str(&dest, "--");
+
+		str_append_str(&dest, filter_name_map[i].name);
+
+		// If only the filter names were wanted then continue
+		// to the next filter.
+		if (!show_opts)
+			continue;
+
+		const option_map *optmap = filter_name_map[i].optmap;
+		const char *d = opt_delim;
+
+		const size_t end = (flags & LZMA_STR_ENCODER)
+				? filter_name_map[i].strfy_encoder
+				: filter_name_map[i].strfy_decoder;
+
+		for (size_t j = 0; j < end; ++j) {
+			// The first option is delimited from the filter
+			// name using "=" or ":" and the rest of the options
+			// are separated with ",".
+			str_append_str(&dest, d);
+			d = ",";
+
+			// optname=
+			str_append_str(&dest, optmap[j].name);
+			str_append_str(&dest, "=<");
+
+			if (optmap[j].type == OPTMAP_TYPE_LZMA_PRESET) {
+				// LZMA1/2 preset has its custom help string.
+				str_append_str(&dest, LZMA12_PRESET_STR);
+			} else if (optmap[j].flags
+					& OPTMAP_USE_NAME_VALUE_MAP) {
+				// Separate the possible option values by "|".
+				const name_value_map *m = optmap[j].u.map;
+				for (size_t k = 0; m[k].name[0] != '\0'; ++k) {
+					if (k > 0)
+						str_append_str(&dest, "|");
+
+					str_append_str(&dest, m[k].name);
+				}
+			} else {
+				// Integer range is shown as min-max.
+				const bool use_byte_suffix = optmap[j].flags
+						& OPTMAP_USE_BYTE_SUFFIX;
+				str_append_u32(&dest, optmap[j].u.range.min,
+						use_byte_suffix);
+				str_append_str(&dest, "-");
+				str_append_u32(&dest, optmap[j].u.range.max,
+						use_byte_suffix);
+			}
+
+			str_append_str(&dest, ">");
+		}
+	}
+
+	// If no filters were added to the string then it must be because
+	// the caller provided an unsupported Filter ID.
+	if (!first_filter_printed) {
+		str_free(&dest, allocator);
+		return LZMA_OPTIONS_ERROR;
+	}
+
+	return str_finish(output_str, &dest, allocator);
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_decoder.c
new file mode 100644
index 00000000000..3254ccc35bd
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_decoder.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       vli_decoder.c
+/// \brief      Decodes variable-length integers
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_vli_decode(lzma_vli *restrict vli, size_t *vli_pos,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size)
+{
+	// If we haven't been given vli_pos, work in single-call mode.
+	size_t vli_pos_internal = 0;
+	if (vli_pos == NULL) {
+		vli_pos = &vli_pos_internal;
+		*vli = 0;
+
+		// If there's no input, use LZMA_DATA_ERROR. This way it is
+		// easy to decode VLIs from buffers that have known size,
+		// and get the correct error code in case the buffer is
+		// too short.
+		if (*in_pos >= in_size)
+			return LZMA_DATA_ERROR;
+
+	} else {
+		// Initialize *vli when starting to decode a new integer.
+		if (*vli_pos == 0)
+			*vli = 0;
+
+		// Validate the arguments.
+		if (*vli_pos >= LZMA_VLI_BYTES_MAX
+				|| (*vli >> (*vli_pos * 7)) != 0)
+			return LZMA_PROG_ERROR;;
+
+		if (*in_pos >= in_size)
+			return LZMA_BUF_ERROR;
+	}
+
+	do {
+		// Read the next byte. Use a temporary variable so that we
+		// can update *in_pos immediately.
+		const uint8_t byte = in[*in_pos];
+		++*in_pos;
+
+		// Add the newly read byte to *vli.
+		*vli += (lzma_vli)(byte & 0x7F) << (*vli_pos * 7);
+		++*vli_pos;
+
+		// Check if this is the last byte of a multibyte integer.
+		if ((byte & 0x80) == 0) {
+			// We don't allow using variable-length integers as
+			// padding i.e. the encoding must use the most the
+			// compact form.
+			if (byte == 0x00 && *vli_pos > 1)
+				return LZMA_DATA_ERROR;
+
+			return vli_pos == &vli_pos_internal
+					? LZMA_OK : LZMA_STREAM_END;
+		}
+
+		// There is at least one more byte coming. If we have already
+		// read maximum number of bytes, the integer is considered
+		// corrupt.
+		//
+		// If we need bigger integers in future, old versions liblzma
+		// will confusingly indicate the file being corrupt instead of
+		// unsupported. I suppose it's still better this way, because
+		// in the foreseeable future (writing this in 2008) the only
+		// reason why files would appear having over 63-bit integers
+		// is that the files are simply corrupt.
+		if (*vli_pos == LZMA_VLI_BYTES_MAX)
+			return LZMA_DATA_ERROR;
+
+	} while (*in_pos < in_size);
+
+	return vli_pos == &vli_pos_internal ? LZMA_DATA_ERROR : LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_encoder.c
new file mode 100644
index 00000000000..3859006a94f
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_encoder.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       vli_encoder.c
+/// \brief      Encodes variable-length integers
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_vli_encode(lzma_vli vli, size_t *vli_pos,
+		uint8_t *restrict out, size_t *restrict out_pos,
+		size_t out_size)
+{
+	// If we haven't been given vli_pos, work in single-call mode.
+	size_t vli_pos_internal = 0;
+	if (vli_pos == NULL) {
+		vli_pos = &vli_pos_internal;
+
+		// In single-call mode, we expect that the caller has
+		// reserved enough output space.
+		if (*out_pos >= out_size)
+			return LZMA_PROG_ERROR;
+	} else {
+		// This never happens when we are called by liblzma, but
+		// may happen if called directly from an application.
+		if (*out_pos >= out_size)
+			return LZMA_BUF_ERROR;
+	}
+
+	// Validate the arguments.
+	if (*vli_pos >= LZMA_VLI_BYTES_MAX || vli > LZMA_VLI_MAX)
+		return LZMA_PROG_ERROR;
+
+	// Shift vli so that the next bits to encode are the lowest. In
+	// single-call mode this never changes vli since *vli_pos is zero.
+	vli >>= *vli_pos * 7;
+
+	// Write the non-last bytes in a loop.
+	while (vli >= 0x80) {
+		// We don't need *vli_pos during this function call anymore,
+		// but update it here so that it is ready if we need to
+		// return before the whole integer has been decoded.
+		++*vli_pos;
+		assert(*vli_pos < LZMA_VLI_BYTES_MAX);
+
+		// Write the next byte.
+		out[*out_pos] = (uint8_t)(vli) | 0x80;
+		vli >>= 7;
+
+		if (++*out_pos == out_size)
+			return vli_pos == &vli_pos_internal
+					? LZMA_PROG_ERROR : LZMA_OK;
+	}
+
+	// Write the last byte.
+	out[*out_pos] = (uint8_t)(vli);
+	++*out_pos;
+	++*vli_pos;
+
+	return vli_pos == &vli_pos_internal ? LZMA_OK : LZMA_STREAM_END;
+
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_size.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_size.c
new file mode 100644
index 00000000000..c8cb2ec10ad
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/common/vli_size.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       vli_size.c
+/// \brief      Calculates the encoded size of a variable-length integer
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+
+extern LZMA_API(uint32_t)
+lzma_vli_size(lzma_vli vli)
+{
+	if (vli > LZMA_VLI_MAX)
+		return 0;
+
+	uint32_t i = 0;
+	do {
+		vli >>= 7;
+		++i;
+	} while (vli != 0);
+
+	assert(i <= LZMA_VLI_BYTES_MAX);
+	return i;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.c
new file mode 100644
index 00000000000..5dbe253b4b3
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       delta_common.c
+/// \brief      Common stuff for Delta encoder and decoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "delta_common.h"
+#include "delta_private.h"
+
+
+static void
+delta_coder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_delta_coder *coder = coder_ptr;
+	lzma_next_end(&coder->next, allocator);
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+extern lzma_ret
+lzma_delta_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	// Allocate memory for the decoder if needed.
+	lzma_delta_coder *coder = next->coder;
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_delta_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+
+		// End function is the same for encoder and decoder.
+		next->end = &delta_coder_end;
+		coder->next = LZMA_NEXT_CODER_INIT;
+	}
+
+	// Validate the options.
+	if (lzma_delta_coder_memusage(filters[0].options) == UINT64_MAX)
+		return LZMA_OPTIONS_ERROR;
+
+	// Set the delta distance.
+	const lzma_options_delta *opt = filters[0].options;
+	coder->distance = opt->dist;
+
+	// Initialize the rest of the variables.
+	coder->pos = 0;
+	memzero(coder->history, LZMA_DELTA_DIST_MAX);
+
+	// Initialize the next decoder in the chain, if any.
+	return lzma_next_filter_init(&coder->next, allocator, filters + 1);
+}
+
+
+extern uint64_t
+lzma_delta_coder_memusage(const void *options)
+{
+	const lzma_options_delta *opt = options;
+
+	if (opt == NULL || opt->type != LZMA_DELTA_TYPE_BYTE
+			|| opt->dist < LZMA_DELTA_DIST_MIN
+			|| opt->dist > LZMA_DELTA_DIST_MAX)
+		return UINT64_MAX;
+
+	return sizeof(lzma_delta_coder);
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.h
new file mode 100644
index 00000000000..bd091276972
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_common.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       delta_common.h
+/// \brief      Common stuff for Delta encoder and decoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_DELTA_COMMON_H
+#define LZMA_DELTA_COMMON_H
+
+#include "common.h"
+
+extern uint64_t lzma_delta_coder_memusage(const void *options);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.c
new file mode 100644
index 00000000000..9f0d49ca415
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       delta_decoder.c
+/// \brief      Delta filter decoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "delta_decoder.h"
+#include "delta_private.h"
+
+
+static void
+decode_buffer(lzma_delta_coder *coder, uint8_t *buffer, size_t size)
+{
+	const size_t distance = coder->distance;
+
+	for (size_t i = 0; i < size; ++i) {
+		buffer[i] += coder->history[(distance + coder->pos) & 0xFF];
+		coder->history[coder->pos-- & 0xFF] = buffer[i];
+	}
+}
+
+
+// For an unknown reason NVIDIA HPC Compiler needs this pragma
+// to produce working code.
+#ifdef __NVCOMPILER
+#	pragma routine novector
+#endif
+static lzma_ret
+delta_decode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size, lzma_action action)
+{
+	lzma_delta_coder *coder = coder_ptr;
+
+	assert(coder->next.code != NULL);
+
+	const size_t out_start = *out_pos;
+
+	const lzma_ret ret = coder->next.code(coder->next.coder, allocator,
+			in, in_pos, in_size, out, out_pos, out_size,
+			action);
+
+	// out might be NULL. In that case size == 0. Null pointer + 0 is
+	// undefined behavior so skip the call in that case as it would
+	// do nothing anyway.
+	const size_t size = *out_pos - out_start;
+	if (size > 0)
+		decode_buffer(coder, out + out_start, size);
+
+	return ret;
+}
+
+
+extern lzma_ret
+lzma_delta_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	next->code = &delta_decode;
+	return lzma_delta_coder_init(next, allocator, filters);
+}
+
+
+extern lzma_ret
+lzma_delta_props_decode(void **options, const lzma_allocator *allocator,
+		const uint8_t *props, size_t props_size)
+{
+	if (props_size != 1)
+		return LZMA_OPTIONS_ERROR;
+
+	lzma_options_delta *opt
+			= lzma_alloc(sizeof(lzma_options_delta), allocator);
+	if (opt == NULL)
+		return LZMA_MEM_ERROR;
+
+	opt->type = LZMA_DELTA_TYPE_BYTE;
+	opt->dist = props[0] + 1U;
+
+	*options = opt;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.h
new file mode 100644
index 00000000000..e2268ed44e7
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_decoder.h
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       delta_decoder.h
+/// \brief      Delta filter decoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_DELTA_DECODER_H
+#define LZMA_DELTA_DECODER_H
+
+#include "delta_common.h"
+
+extern lzma_ret lzma_delta_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+extern lzma_ret lzma_delta_props_decode(
+		void **options, const lzma_allocator *allocator,
+		const uint8_t *props, size_t props_size);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.c
new file mode 100644
index 00000000000..ba4a50b1f42
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       delta_encoder.c
+/// \brief      Delta filter encoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "delta_encoder.h"
+#include "delta_private.h"
+
+
+/// Copies and encodes the data at the same time. This is used when Delta
+/// is the first filter in the chain (and thus the last filter in the
+/// encoder's filter stack).
+static void
+copy_and_encode(lzma_delta_coder *coder,
+		const uint8_t *restrict in, uint8_t *restrict out, size_t size)
+{
+	const size_t distance = coder->distance;
+
+	for (size_t i = 0; i < size; ++i) {
+		const uint8_t tmp = coder->history[
+				(distance + coder->pos) & 0xFF];
+		coder->history[coder->pos-- & 0xFF] = in[i];
+		out[i] = in[i] - tmp;
+	}
+}
+
+
+/// Encodes the data in place. This is used when we are the last filter
+/// in the chain (and thus non-last filter in the encoder's filter stack).
+static void
+encode_in_place(lzma_delta_coder *coder, uint8_t *buffer, size_t size)
+{
+	const size_t distance = coder->distance;
+
+	for (size_t i = 0; i < size; ++i) {
+		const uint8_t tmp = coder->history[
+				(distance + coder->pos) & 0xFF];
+		coder->history[coder->pos-- & 0xFF] = buffer[i];
+		buffer[i] -= tmp;
+	}
+}
+
+
+static lzma_ret
+delta_encode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size, lzma_action action)
+{
+	lzma_delta_coder *coder = coder_ptr;
+
+	lzma_ret ret;
+
+	if (coder->next.code == NULL) {
+		const size_t in_avail = in_size - *in_pos;
+		const size_t out_avail = out_size - *out_pos;
+		const size_t size = my_min(in_avail, out_avail);
+
+		// in and out might be NULL. In such cases size == 0.
+		// Null pointer + 0 is undefined behavior so skip
+		// the call in that case as it would do nothing anyway.
+		if (size > 0)
+			copy_and_encode(coder, in + *in_pos, out + *out_pos,
+					size);
+
+		*in_pos += size;
+		*out_pos += size;
+
+		ret = action != LZMA_RUN && *in_pos == in_size
+				? LZMA_STREAM_END : LZMA_OK;
+
+	} else {
+		const size_t out_start = *out_pos;
+
+		ret = coder->next.code(coder->next.coder, allocator,
+				in, in_pos, in_size, out, out_pos, out_size,
+				action);
+
+		// Like above, avoid null pointer + 0.
+		const size_t size = *out_pos - out_start;
+		if (size > 0)
+			encode_in_place(coder, out + out_start, size);
+	}
+
+	return ret;
+}
+
+
+static lzma_ret
+delta_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
+		const lzma_filter *filters_null lzma_attribute((__unused__)),
+		const lzma_filter *reversed_filters)
+{
+	lzma_delta_coder *coder = coder_ptr;
+
+	// Delta doesn't and will never support changing the options in
+	// the middle of encoding. If the app tries to change them, we
+	// simply ignore them.
+	return lzma_next_filter_update(
+			&coder->next, allocator, reversed_filters + 1);
+}
+
+
+extern lzma_ret
+lzma_delta_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	next->code = &delta_encode;
+	next->update = &delta_encoder_update;
+	return lzma_delta_coder_init(next, allocator, filters);
+}
+
+
+extern lzma_ret
+lzma_delta_props_encode(const void *options, uint8_t *out)
+{
+	// The caller must have already validated the options, so it's
+	// LZMA_PROG_ERROR if they are invalid.
+	if (lzma_delta_coder_memusage(options) == UINT64_MAX)
+		return LZMA_PROG_ERROR;
+
+	const lzma_options_delta *opt = options;
+	out[0] = opt->dist - LZMA_DELTA_DIST_MIN;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.h
new file mode 100644
index 00000000000..735f0ed0091
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_encoder.h
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       delta_encoder.h
+/// \brief      Delta filter encoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_DELTA_ENCODER_H
+#define LZMA_DELTA_ENCODER_H
+
+#include "delta_common.h"
+
+extern lzma_ret lzma_delta_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+extern lzma_ret lzma_delta_props_encode(const void *options, uint8_t *out);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_private.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_private.h
new file mode 100644
index 00000000000..e54721a8466
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/delta/delta_private.h
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       delta_private.h
+/// \brief      Private common stuff for Delta encoder and decoder
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_DELTA_PRIVATE_H
+#define LZMA_DELTA_PRIVATE_H
+
+#include "delta_common.h"
+
+typedef struct {
+	/// Next coder in the chain
+	lzma_next_coder next;
+
+	/// Delta distance
+	size_t distance;
+
+	/// Position in history[]
+	uint8_t pos;
+
+	/// Buffer to hold history of the original data
+	uint8_t history[LZMA_DELTA_DIST_MAX];
+} lzma_delta_coder;
+
+
+extern lzma_ret lzma_delta_coder_init(
+		lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma.pc.in b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma.pc.in
new file mode 100644
index 00000000000..a432992b707
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma.pc.in
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: 0BSD
+# Author: Lasse Collin
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: liblzma
+Description: General purpose data compression library
+URL: @PACKAGE_URL@
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}
+Cflags.private: -DLZMA_API_STATIC
+Libs: -L${libdir} -llzma
+Libs.private: @PTHREAD_CFLAGS@ @LIBS@
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_generic.map b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_generic.map
new file mode 100644
index 00000000000..f74c1548455
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_generic.map
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: 0BSD */
+
+XZ_5.0 {
+global:
+	lzma_alone_decoder;
+	lzma_alone_encoder;
+	lzma_auto_decoder;
+	lzma_block_buffer_bound;
+	lzma_block_buffer_decode;
+	lzma_block_buffer_encode;
+	lzma_block_compressed_size;
+	lzma_block_decoder;
+	lzma_block_encoder;
+	lzma_block_header_decode;
+	lzma_block_header_encode;
+	lzma_block_header_size;
+	lzma_block_total_size;
+	lzma_block_unpadded_size;
+	lzma_check_is_supported;
+	lzma_check_size;
+	lzma_code;
+	lzma_crc32;
+	lzma_crc64;
+	lzma_easy_buffer_encode;
+	lzma_easy_decoder_memusage;
+	lzma_easy_encoder;
+	lzma_easy_encoder_memusage;
+	lzma_end;
+	lzma_filter_decoder_is_supported;
+	lzma_filter_encoder_is_supported;
+	lzma_filter_flags_decode;
+	lzma_filter_flags_encode;
+	lzma_filter_flags_size;
+	lzma_filters_copy;
+	lzma_filters_update;
+	lzma_get_check;
+	lzma_index_append;
+	lzma_index_block_count;
+	lzma_index_buffer_decode;
+	lzma_index_buffer_encode;
+	lzma_index_cat;
+	lzma_index_checks;
+	lzma_index_decoder;
+	lzma_index_dup;
+	lzma_index_encoder;
+	lzma_index_end;
+	lzma_index_file_size;
+	lzma_index_hash_append;
+	lzma_index_hash_decode;
+	lzma_index_hash_end;
+	lzma_index_hash_init;
+	lzma_index_hash_size;
+	lzma_index_init;
+	lzma_index_iter_init;
+	lzma_index_iter_locate;
+	lzma_index_iter_next;
+	lzma_index_iter_rewind;
+	lzma_index_memusage;
+	lzma_index_memused;
+	lzma_index_size;
+	lzma_index_stream_count;
+	lzma_index_stream_flags;
+	lzma_index_stream_padding;
+	lzma_index_stream_size;
+	lzma_index_total_size;
+	lzma_index_uncompressed_size;
+	lzma_lzma_preset;
+	lzma_memlimit_get;
+	lzma_memlimit_set;
+	lzma_memusage;
+	lzma_mf_is_supported;
+	lzma_mode_is_supported;
+	lzma_physmem;
+	lzma_properties_decode;
+	lzma_properties_encode;
+	lzma_properties_size;
+	lzma_raw_buffer_decode;
+	lzma_raw_buffer_encode;
+	lzma_raw_decoder;
+	lzma_raw_decoder_memusage;
+	lzma_raw_encoder;
+	lzma_raw_encoder_memusage;
+	lzma_stream_buffer_bound;
+	lzma_stream_buffer_decode;
+	lzma_stream_buffer_encode;
+	lzma_stream_decoder;
+	lzma_stream_encoder;
+	lzma_stream_flags_compare;
+	lzma_stream_footer_decode;
+	lzma_stream_footer_encode;
+	lzma_stream_header_decode;
+	lzma_stream_header_encode;
+	lzma_version_number;
+	lzma_version_string;
+	lzma_vli_decode;
+	lzma_vli_encode;
+	lzma_vli_size;
+
+local:
+	*;
+};
+
+XZ_5.2 {
+global:
+	lzma_block_uncomp_encode;
+	lzma_cputhreads;
+	lzma_get_progress;
+	lzma_stream_encoder_mt;
+	lzma_stream_encoder_mt_memusage;
+} XZ_5.0;
+
+XZ_5.4 {
+global:
+	lzma_file_info_decoder;
+	lzma_filters_free;
+	lzma_lzip_decoder;
+	lzma_microlzma_decoder;
+	lzma_microlzma_encoder;
+	lzma_stream_decoder_mt;
+	lzma_str_from_filters;
+	lzma_str_list_filters;
+	lzma_str_to_filters;
+} XZ_5.2;
+
+XZ_5.6.0 {
+global:
+	lzma_mt_block_size;
+} XZ_5.4;
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_linux.map b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_linux.map
new file mode 100644
index 00000000000..7e4b25e1762
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/liblzma_linux.map
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: 0BSD */
+
+XZ_5.0 {
+global:
+	lzma_alone_decoder;
+	lzma_alone_encoder;
+	lzma_auto_decoder;
+	lzma_block_buffer_bound;
+	lzma_block_buffer_decode;
+	lzma_block_buffer_encode;
+	lzma_block_compressed_size;
+	lzma_block_decoder;
+	lzma_block_encoder;
+	lzma_block_header_decode;
+	lzma_block_header_encode;
+	lzma_block_header_size;
+	lzma_block_total_size;
+	lzma_block_unpadded_size;
+	lzma_check_is_supported;
+	lzma_check_size;
+	lzma_code;
+	lzma_crc32;
+	lzma_crc64;
+	lzma_easy_buffer_encode;
+	lzma_easy_decoder_memusage;
+	lzma_easy_encoder;
+	lzma_easy_encoder_memusage;
+	lzma_end;
+	lzma_filter_decoder_is_supported;
+	lzma_filter_encoder_is_supported;
+	lzma_filter_flags_decode;
+	lzma_filter_flags_encode;
+	lzma_filter_flags_size;
+	lzma_filters_copy;
+	lzma_filters_update;
+	lzma_get_check;
+	lzma_index_append;
+	lzma_index_block_count;
+	lzma_index_buffer_decode;
+	lzma_index_buffer_encode;
+	lzma_index_cat;
+	lzma_index_checks;
+	lzma_index_decoder;
+	lzma_index_dup;
+	lzma_index_encoder;
+	lzma_index_end;
+	lzma_index_file_size;
+	lzma_index_hash_append;
+	lzma_index_hash_decode;
+	lzma_index_hash_end;
+	lzma_index_hash_init;
+	lzma_index_hash_size;
+	lzma_index_init;
+	lzma_index_iter_init;
+	lzma_index_iter_locate;
+	lzma_index_iter_next;
+	lzma_index_iter_rewind;
+	lzma_index_memusage;
+	lzma_index_memused;
+	lzma_index_size;
+	lzma_index_stream_count;
+	lzma_index_stream_flags;
+	lzma_index_stream_padding;
+	lzma_index_stream_size;
+	lzma_index_total_size;
+	lzma_index_uncompressed_size;
+	lzma_lzma_preset;
+	lzma_memlimit_get;
+	lzma_memlimit_set;
+	lzma_memusage;
+	lzma_mf_is_supported;
+	lzma_mode_is_supported;
+	lzma_physmem;
+	lzma_properties_decode;
+	lzma_properties_encode;
+	lzma_properties_size;
+	lzma_raw_buffer_decode;
+	lzma_raw_buffer_encode;
+	lzma_raw_decoder;
+	lzma_raw_decoder_memusage;
+	lzma_raw_encoder;
+	lzma_raw_encoder_memusage;
+	lzma_stream_buffer_bound;
+	lzma_stream_buffer_decode;
+	lzma_stream_buffer_encode;
+	lzma_stream_decoder;
+	lzma_stream_encoder;
+	lzma_stream_flags_compare;
+	lzma_stream_footer_decode;
+	lzma_stream_footer_encode;
+	lzma_stream_header_decode;
+	lzma_stream_header_encode;
+	lzma_version_number;
+	lzma_version_string;
+	lzma_vli_decode;
+	lzma_vli_encode;
+	lzma_vli_size;
+
+local:
+	*;
+};
+
+XZ_5.2 {
+global:
+	lzma_block_uncomp_encode;
+	lzma_cputhreads;
+	lzma_get_progress;
+	lzma_stream_encoder_mt;
+	lzma_stream_encoder_mt_memusage;
+} XZ_5.0;
+
+XZ_5.1.2alpha {
+global:
+	lzma_stream_encoder_mt;
+	lzma_stream_encoder_mt_memusage;
+} XZ_5.0;
+
+XZ_5.2.2 {
+global:
+	lzma_block_uncomp_encode;
+	lzma_cputhreads;
+	lzma_get_progress;
+	lzma_stream_encoder_mt;
+	lzma_stream_encoder_mt_memusage;
+} XZ_5.1.2alpha;
+
+XZ_5.4 {
+global:
+	lzma_file_info_decoder;
+	lzma_filters_free;
+	lzma_lzip_decoder;
+	lzma_microlzma_decoder;
+	lzma_microlzma_encoder;
+	lzma_stream_decoder_mt;
+	lzma_str_from_filters;
+	lzma_str_list_filters;
+	lzma_str_to_filters;
+} XZ_5.2;
+
+XZ_5.6.0 {
+global:
+	lzma_mt_block_size;
+} XZ_5.4;
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.c
new file mode 100644
index 00000000000..92913f225a0
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.c
@@ -0,0 +1,324 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lz_decoder.c
+/// \brief      LZ out window
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// liblzma supports multiple LZ77-based filters. The LZ part is shared
+// between these filters. The LZ code takes care of dictionary handling
+// and passing the data between filters in the chain. The filter-specific
+// part decodes from the input buffer to the dictionary.
+
+
+#include "lz_decoder.h"
+
+
+typedef struct {
+	/// Dictionary (history buffer)
+	lzma_dict dict;
+
+	/// The actual LZ-based decoder e.g. LZMA
+	lzma_lz_decoder lz;
+
+	/// Next filter in the chain, if any. Note that LZMA and LZMA2 are
+	/// only allowed as the last filter, but the long-range filter in
+	/// future can be in the middle of the chain.
+	lzma_next_coder next;
+
+	/// True if the next filter in the chain has returned LZMA_STREAM_END.
+	bool next_finished;
+
+	/// True if the LZ decoder (e.g. LZMA) has detected end of payload
+	/// marker. This may become true before next_finished becomes true.
+	bool this_finished;
+
+	/// Temporary buffer needed when the LZ-based filter is not the last
+	/// filter in the chain. The output of the next filter is first
+	/// decoded into buffer[], which is then used as input for the actual
+	/// LZ-based decoder.
+	struct {
+		size_t pos;
+		size_t size;
+		uint8_t buffer[LZMA_BUFFER_SIZE];
+	} temp;
+} lzma_coder;
+
+
+static void
+lz_decoder_reset(lzma_coder *coder)
+{
+	coder->dict.pos = 2 * LZ_DICT_REPEAT_MAX;
+	coder->dict.full = 0;
+	coder->dict.buf[2 * LZ_DICT_REPEAT_MAX - 1] = '\0';
+	coder->dict.has_wrapped = false;
+	coder->dict.need_reset = false;
+	return;
+}
+
+
+static lzma_ret
+decode_buffer(lzma_coder *coder,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size)
+{
+	while (true) {
+		// Wrap the dictionary if needed.
+		if (coder->dict.pos == coder->dict.size) {
+			// See the comment of #define LZ_DICT_REPEAT_MAX.
+			coder->dict.pos = LZ_DICT_REPEAT_MAX;
+			coder->dict.has_wrapped = true;
+			memcpy(coder->dict.buf, coder->dict.buf
+						+ coder->dict.size
+						- LZ_DICT_REPEAT_MAX,
+					LZ_DICT_REPEAT_MAX);
+		}
+
+		// Store the current dictionary position. It is needed to know
+		// where to start copying to the out[] buffer.
+		const size_t dict_start = coder->dict.pos;
+
+		// Calculate how much we allow coder->lz.code() to decode.
+		// It must not decode past the end of the dictionary
+		// buffer, and we don't want it to decode more than is
+		// actually needed to fill the out[] buffer.
+		coder->dict.limit = coder->dict.pos
+				+ my_min(out_size - *out_pos,
+					coder->dict.size - coder->dict.pos);
+
+		// Call the coder->lz.code() to do the actual decoding.
+		const lzma_ret ret = coder->lz.code(
+				coder->lz.coder, &coder->dict,
+				in, in_pos, in_size);
+
+		// Copy the decoded data from the dictionary to the out[]
+		// buffer. Do it conditionally because out can be NULL
+		// (in which case copy_size is always 0). Calling memcpy()
+		// with a null-pointer is undefined even if the third
+		// argument is 0.
+		const size_t copy_size = coder->dict.pos - dict_start;
+		assert(copy_size <= out_size - *out_pos);
+
+		if (copy_size > 0)
+			memcpy(out + *out_pos, coder->dict.buf + dict_start,
+					copy_size);
+
+		*out_pos += copy_size;
+
+		// Reset the dictionary if so requested by coder->lz.code().
+		if (coder->dict.need_reset) {
+			lz_decoder_reset(coder);
+
+			// Since we reset dictionary, we don't check if
+			// dictionary became full.
+			if (ret != LZMA_OK || *out_pos == out_size)
+				return ret;
+		} else {
+			// Return if everything got decoded or an error
+			// occurred, or if there's no more data to decode.
+			//
+			// Note that detecting if there's something to decode
+			// is done by looking if dictionary become full
+			// instead of looking if *in_pos == in_size. This
+			// is because it is possible that all the input was
+			// consumed already but some data is pending to be
+			// written to the dictionary.
+			if (ret != LZMA_OK || *out_pos == out_size
+					|| coder->dict.pos < coder->dict.size)
+				return ret;
+		}
+	}
+}
+
+
+static lzma_ret
+lz_decode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size,
+		lzma_action action)
+{
+	lzma_coder *coder = coder_ptr;
+
+	if (coder->next.code == NULL)
+		return decode_buffer(coder, in, in_pos, in_size,
+				out, out_pos, out_size);
+
+	// We aren't the last coder in the chain, we need to decode
+	// our input to a temporary buffer.
+	while (*out_pos < out_size) {
+		// Fill the temporary buffer if it is empty.
+		if (!coder->next_finished
+				&& coder->temp.pos == coder->temp.size) {
+			coder->temp.pos = 0;
+			coder->temp.size = 0;
+
+			const lzma_ret ret = coder->next.code(
+					coder->next.coder,
+					allocator, in, in_pos, in_size,
+					coder->temp.buffer, &coder->temp.size,
+					LZMA_BUFFER_SIZE, action);
+
+			if (ret == LZMA_STREAM_END)
+				coder->next_finished = true;
+			else if (ret != LZMA_OK || coder->temp.size == 0)
+				return ret;
+		}
+
+		if (coder->this_finished) {
+			if (coder->temp.size != 0)
+				return LZMA_DATA_ERROR;
+
+			if (coder->next_finished)
+				return LZMA_STREAM_END;
+
+			return LZMA_OK;
+		}
+
+		const lzma_ret ret = decode_buffer(coder, coder->temp.buffer,
+				&coder->temp.pos, coder->temp.size,
+				out, out_pos, out_size);
+
+		if (ret == LZMA_STREAM_END)
+			coder->this_finished = true;
+		else if (ret != LZMA_OK)
+			return ret;
+		else if (coder->next_finished && *out_pos < out_size)
+			return LZMA_DATA_ERROR;
+	}
+
+	return LZMA_OK;
+}
+
+
+static void
+lz_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_coder *coder = coder_ptr;
+
+	lzma_next_end(&coder->next, allocator);
+	lzma_free(coder->dict.buf, allocator);
+
+	if (coder->lz.end != NULL)
+		coder->lz.end(coder->lz.coder, allocator);
+	else
+		lzma_free(coder->lz.coder, allocator);
+
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+extern lzma_ret
+lzma_lz_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters,
+		lzma_ret (*lz_init)(lzma_lz_decoder *lz,
+			const lzma_allocator *allocator,
+			lzma_vli id, const void *options,
+			lzma_lz_options *lz_options))
+{
+	// Allocate the base structure if it isn't already allocated.
+	lzma_coder *coder = next->coder;
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+		next->code = &lz_decode;
+		next->end = &lz_decoder_end;
+
+		coder->dict.buf = NULL;
+		coder->dict.size = 0;
+		coder->lz = LZMA_LZ_DECODER_INIT;
+		coder->next = LZMA_NEXT_CODER_INIT;
+	}
+
+	// Allocate and initialize the LZ-based decoder. It will also give
+	// us the dictionary size.
+	lzma_lz_options lz_options;
+	return_if_error(lz_init(&coder->lz, allocator,
+			filters[0].id, filters[0].options, &lz_options));
+
+	// If the dictionary size is very small, increase it to 4096 bytes.
+	// This is to prevent constant wrapping of the dictionary, which
+	// would slow things down. The downside is that since we don't check
+	// separately for the real dictionary size, we may happily accept
+	// corrupt files.
+	if (lz_options.dict_size < 4096)
+		lz_options.dict_size = 4096;
+
+	// Make dictionary size a multiple of 16. Some LZ-based decoders like
+	// LZMA use the lowest bits lzma_dict.pos to know the alignment of the
+	// data. Aligned buffer is also good when memcpying from the
+	// dictionary to the output buffer, since applications are
+	// recommended to give aligned buffers to liblzma.
+	//
+	// Reserve 2 * LZ_DICT_REPEAT_MAX bytes of extra space which is
+	// needed for alloc_size.
+	//
+	// Avoid integer overflow.
+	if (lz_options.dict_size > SIZE_MAX - 15 - 2 * LZ_DICT_REPEAT_MAX)
+		return LZMA_MEM_ERROR;
+
+	lz_options.dict_size = (lz_options.dict_size + 15) & ~((size_t)(15));
+
+	// Reserve extra space as explained in the comment
+	// of #define LZ_DICT_REPEAT_MAX.
+	const size_t alloc_size
+			= lz_options.dict_size + 2 * LZ_DICT_REPEAT_MAX;
+
+	// Allocate and initialize the dictionary.
+	if (coder->dict.size != alloc_size) {
+		lzma_free(coder->dict.buf, allocator);
+		coder->dict.buf = lzma_alloc(alloc_size, allocator);
+		if (coder->dict.buf == NULL)
+			return LZMA_MEM_ERROR;
+
+		// NOTE: Yes, alloc_size, not lz_options.dict_size. The way
+		// coder->dict.full is updated will take care that we will
+		// still reject distances larger than lz_options.dict_size.
+		coder->dict.size = alloc_size;
+	}
+
+	lz_decoder_reset(next->coder);
+
+	// Use the preset dictionary if it was given to us.
+	if (lz_options.preset_dict != NULL
+			&& lz_options.preset_dict_size > 0) {
+		// If the preset dictionary is bigger than the actual
+		// dictionary, copy only the tail.
+		const size_t copy_size = my_min(lz_options.preset_dict_size,
+				lz_options.dict_size);
+		const size_t offset = lz_options.preset_dict_size - copy_size;
+		memcpy(coder->dict.buf + coder->dict.pos,
+				lz_options.preset_dict + offset,
+				copy_size);
+
+		// dict.pos isn't zero after lz_decoder_reset().
+		coder->dict.pos += copy_size;
+		coder->dict.full = copy_size;
+	}
+
+	// Miscellaneous initializations
+	coder->next_finished = false;
+	coder->this_finished = false;
+	coder->temp.pos = 0;
+	coder->temp.size = 0;
+
+	// Initialize the next filter in the chain, if any.
+	return lzma_next_filter_init(&coder->next, allocator, filters + 1);
+}
+
+
+extern uint64_t
+lzma_lz_decoder_memusage(size_t dictionary_size)
+{
+	return sizeof(lzma_coder) + (uint64_t)(dictionary_size);
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.h
new file mode 100644
index 00000000000..cb61b6e24c7
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_decoder.h
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lz_decoder.h
+/// \brief      LZ out window
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZ_DECODER_H
+#define LZMA_LZ_DECODER_H
+
+#include "common.h"
+
+
+/// Maximum length of a match rounded up to a nice power of 2 which is
+/// a good size for aligned memcpy(). The allocated dictionary buffer will
+/// be 2 * LZ_DICT_REPEAT_MAX bytes larger than the actual dictionary size:
+///
+/// (1) Every time the decoder reaches the end of the dictionary buffer,
+///     the last LZ_DICT_REPEAT_MAX bytes will be copied to the beginning.
+///     This way dict_repeat() will only need to copy from one place,
+///     never from both the end and beginning of the buffer.
+///
+/// (2) The other LZ_DICT_REPEAT_MAX bytes is kept as a buffer between
+///     the oldest byte still in the dictionary and the current write
+///     position. This way dict_repeat(dict, dict->size - 1, &len)
+///     won't need memmove() as the copying cannot overlap.
+///
+/// Note that memcpy() still cannot be used if distance < len.
+///
+/// LZMA's longest match length is 273 so pick a multiple of 16 above that.
+#define LZ_DICT_REPEAT_MAX 288
+
+
+typedef struct {
+	/// Pointer to the dictionary buffer.
+	uint8_t *buf;
+
+	/// Write position in dictionary. The next byte will be written to
+	/// buf[pos].
+	size_t pos;
+
+	/// Indicates how full the dictionary is. This is used by
+	/// dict_is_distance_valid() to detect corrupt files that would
+	/// read beyond the beginning of the dictionary.
+	size_t full;
+
+	/// Write limit
+	size_t limit;
+
+	/// Allocated size of buf. This is 2 * LZ_DICT_REPEAT_MAX bytes
+	/// larger than the actual dictionary size. This is enforced by
+	/// how the value for "full" is set; it can be at most
+	/// "size - 2 * LZ_DICT_REPEAT_MAX".
+	size_t size;
+
+	/// True once the dictionary has become full and the writing position
+	/// has been wrapped in decode_buffer() in lz_decoder.c.
+	bool has_wrapped;
+
+	/// True when dictionary should be reset before decoding more data.
+	bool need_reset;
+
+} lzma_dict;
+
+
+typedef struct {
+	size_t dict_size;
+	const uint8_t *preset_dict;
+	size_t preset_dict_size;
+} lzma_lz_options;
+
+
+typedef struct {
+	/// Data specific to the LZ-based decoder
+	void *coder;
+
+	/// Function to decode from in[] to *dict
+	lzma_ret (*code)(void *coder,
+			lzma_dict *restrict dict, const uint8_t *restrict in,
+			size_t *restrict in_pos, size_t in_size);
+
+	void (*reset)(void *coder, const void *options);
+
+	/// Set the uncompressed size. If uncompressed_size == LZMA_VLI_UNKNOWN
+	/// then allow_eopm will always be true.
+	void (*set_uncompressed)(void *coder, lzma_vli uncompressed_size,
+			bool allow_eopm);
+
+	/// Free allocated resources
+	void (*end)(void *coder, const lzma_allocator *allocator);
+
+} lzma_lz_decoder;
+
+
+#define LZMA_LZ_DECODER_INIT \
+	(lzma_lz_decoder){ \
+		.coder = NULL, \
+		.code = NULL, \
+		.reset = NULL, \
+		.set_uncompressed = NULL, \
+		.end = NULL, \
+	}
+
+
+extern lzma_ret lzma_lz_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters,
+		lzma_ret (*lz_init)(lzma_lz_decoder *lz,
+			const lzma_allocator *allocator,
+			lzma_vli id, const void *options,
+			lzma_lz_options *lz_options));
+
+extern uint64_t lzma_lz_decoder_memusage(size_t dictionary_size);
+
+
+//////////////////////
+// Inline functions //
+//////////////////////
+
+/// Get a byte from the history buffer.
+static inline uint8_t
+dict_get(const lzma_dict *const dict, const uint32_t distance)
+{
+	return dict->buf[dict->pos - distance - 1
+			+ (distance < dict->pos
+				? 0 : dict->size - LZ_DICT_REPEAT_MAX)];
+}
+
+
+/// Optimized version of dict_get(dict, 0)
+static inline uint8_t
+dict_get0(const lzma_dict *const dict)
+{
+	return dict->buf[dict->pos - 1];
+}
+
+
+/// Test if dictionary is empty.
+static inline bool
+dict_is_empty(const lzma_dict *const dict)
+{
+	return dict->full == 0;
+}
+
+
+/// Validate the match distance
+static inline bool
+dict_is_distance_valid(const lzma_dict *const dict, const size_t distance)
+{
+	return dict->full > distance;
+}
+
+
+/// Repeat *len bytes at distance.
+static inline bool
+dict_repeat(lzma_dict *dict, uint32_t distance, uint32_t *len)
+{
+	// Don't write past the end of the dictionary.
+	const size_t dict_avail = dict->limit - dict->pos;
+	uint32_t left = my_min(dict_avail, *len);
+	*len -= left;
+
+	size_t back = dict->pos - distance - 1;
+	if (distance >= dict->pos)
+		back += dict->size - LZ_DICT_REPEAT_MAX;
+
+	// Repeat a block of data from the history. Because memcpy() is faster
+	// than copying byte by byte in a loop, the copying process gets split
+	// into two cases.
+	if (distance < left) {
+		// Source and target areas overlap, thus we can't use
+		// memcpy() nor even memmove() safely.
+		do {
+			dict->buf[dict->pos++] = dict->buf[back++];
+		} while (--left > 0);
+	} else {
+		memcpy(dict->buf + dict->pos, dict->buf + back, left);
+		dict->pos += left;
+	}
+
+	// Update how full the dictionary is.
+	if (!dict->has_wrapped)
+		dict->full = dict->pos - 2 * LZ_DICT_REPEAT_MAX;
+
+	return *len != 0;
+}
+
+
+static inline void
+dict_put(lzma_dict *dict, uint8_t byte)
+{
+	dict->buf[dict->pos++] = byte;
+
+	if (!dict->has_wrapped)
+		dict->full = dict->pos - 2 * LZ_DICT_REPEAT_MAX;
+}
+
+
+/// Puts one byte into the dictionary. Returns true if the dictionary was
+/// already full and the byte couldn't be added.
+static inline bool
+dict_put_safe(lzma_dict *dict, uint8_t byte)
+{
+	if (unlikely(dict->pos == dict->limit))
+		return true;
+
+	dict_put(dict, byte);
+	return false;
+}
+
+
+/// Copies arbitrary amount of data into the dictionary.
+static inline void
+dict_write(lzma_dict *restrict dict, const uint8_t *restrict in,
+		size_t *restrict in_pos, size_t in_size,
+		size_t *restrict left)
+{
+	// NOTE: If we are being given more data than the size of the
+	// dictionary, it could be possible to optimize the LZ decoder
+	// so that not everything needs to go through the dictionary.
+	// This shouldn't be very common thing in practice though, and
+	// the slowdown of one extra memcpy() isn't bad compared to how
+	// much time it would have taken if the data were compressed.
+
+	if (in_size - *in_pos > *left)
+		in_size = *in_pos + *left;
+
+	*left -= lzma_bufcpy(in, in_pos, in_size,
+			dict->buf, &dict->pos, dict->limit);
+
+	if (!dict->has_wrapped)
+		dict->full = dict->pos - 2 * LZ_DICT_REPEAT_MAX;
+
+	return;
+}
+
+
+static inline void
+dict_reset(lzma_dict *dict)
+{
+	dict->need_reset = true;
+	return;
+}
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.c
new file mode 100644
index 00000000000..4af23e14c42
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.c
@@ -0,0 +1,632 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lz_encoder.c
+/// \brief      LZ in window
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lz_encoder.h"
+#include "lz_encoder_hash.h"
+
+// See lz_encoder_hash.h. This is a bit hackish but avoids making
+// endianness a conditional in makefiles.
+#if defined(WORDS_BIGENDIAN) && !defined(HAVE_SMALL)
+#	include "lz_encoder_hash_table.h"
+#endif
+
+#include "memcmplen.h"
+
+
+typedef struct {
+	/// LZ-based encoder e.g. LZMA
+	lzma_lz_encoder lz;
+
+	/// History buffer and match finder
+	lzma_mf mf;
+
+	/// Next coder in the chain
+	lzma_next_coder next;
+} lzma_coder;
+
+
+/// \brief      Moves the data in the input window to free space for new data
+///
+/// mf->buffer is a sliding input window, which keeps mf->keep_size_before
+/// bytes of input history available all the time. Now and then we need to
+/// "slide" the buffer to make space for the new data to the end of the
+/// buffer. At the same time, data older than keep_size_before is dropped.
+///
+static void
+move_window(lzma_mf *mf)
+{
+	// Align the move to a multiple of 16 bytes. Some LZ-based encoders
+	// like LZMA use the lowest bits of mf->read_pos to know the
+	// alignment of the uncompressed data. We also get better speed
+	// for memmove() with aligned buffers.
+	assert(mf->read_pos > mf->keep_size_before);
+	const uint32_t move_offset
+		= (mf->read_pos - mf->keep_size_before) & ~UINT32_C(15);
+
+	assert(mf->write_pos > move_offset);
+	const size_t move_size = mf->write_pos - move_offset;
+
+	assert(move_offset + move_size <= mf->size);
+
+	memmove(mf->buffer, mf->buffer + move_offset, move_size);
+
+	mf->offset += move_offset;
+	mf->read_pos -= move_offset;
+	mf->read_limit -= move_offset;
+	mf->write_pos -= move_offset;
+
+	return;
+}
+
+
+/// \brief      Tries to fill the input window (mf->buffer)
+///
+/// If we are the last encoder in the chain, our input data is in in[].
+/// Otherwise we call the next filter in the chain to process in[] and
+/// write its output to mf->buffer.
+///
+/// This function must not be called once it has returned LZMA_STREAM_END.
+///
+static lzma_ret
+fill_window(lzma_coder *coder, const lzma_allocator *allocator,
+		const uint8_t *in, size_t *in_pos, size_t in_size,
+		lzma_action action)
+{
+	assert(coder->mf.read_pos <= coder->mf.write_pos);
+
+	// Move the sliding window if needed.
+	if (coder->mf.read_pos >= coder->mf.size - coder->mf.keep_size_after)
+		move_window(&coder->mf);
+
+	// Maybe this is ugly, but lzma_mf uses uint32_t for most things
+	// (which I find cleanest), but we need size_t here when filling
+	// the history window.
+	size_t write_pos = coder->mf.write_pos;
+	lzma_ret ret;
+	if (coder->next.code == NULL) {
+		// Not using a filter, simply memcpy() as much as possible.
+		lzma_bufcpy(in, in_pos, in_size, coder->mf.buffer,
+				&write_pos, coder->mf.size);
+
+		ret = action != LZMA_RUN && *in_pos == in_size
+				? LZMA_STREAM_END : LZMA_OK;
+
+	} else {
+		ret = coder->next.code(coder->next.coder, allocator,
+				in, in_pos, in_size,
+				coder->mf.buffer, &write_pos,
+				coder->mf.size, action);
+	}
+
+	coder->mf.write_pos = write_pos;
+
+	// Silence Valgrind. lzma_memcmplen() can read extra bytes
+	// and Valgrind will give warnings if those bytes are uninitialized
+	// because Valgrind cannot see that the values of the uninitialized
+	// bytes are eventually ignored.
+	memzero(coder->mf.buffer + write_pos, LZMA_MEMCMPLEN_EXTRA);
+
+	// If end of stream has been reached or flushing completed, we allow
+	// the encoder to process all the input (that is, read_pos is allowed
+	// to reach write_pos). Otherwise we keep keep_size_after bytes
+	// available as prebuffer.
+	if (ret == LZMA_STREAM_END) {
+		assert(*in_pos == in_size);
+		ret = LZMA_OK;
+		coder->mf.action = action;
+		coder->mf.read_limit = coder->mf.write_pos;
+
+	} else if (coder->mf.write_pos > coder->mf.keep_size_after) {
+		// This needs to be done conditionally, because if we got
+		// only little new input, there may be too little input
+		// to do any encoding yet.
+		coder->mf.read_limit = coder->mf.write_pos
+				- coder->mf.keep_size_after;
+	}
+
+	// Restart the match finder after finished LZMA_SYNC_FLUSH.
+	if (coder->mf.pending > 0
+			&& coder->mf.read_pos < coder->mf.read_limit) {
+		// Match finder may update coder->pending and expects it to
+		// start from zero, so use a temporary variable.
+		const uint32_t pending = coder->mf.pending;
+		coder->mf.pending = 0;
+
+		// Rewind read_pos so that the match finder can hash
+		// the pending bytes.
+		assert(coder->mf.read_pos >= pending);
+		coder->mf.read_pos -= pending;
+
+		// Call the skip function directly instead of using
+		// mf_skip(), since we don't want to touch mf->read_ahead.
+		coder->mf.skip(&coder->mf, pending);
+	}
+
+	return ret;
+}
+
+
+static lzma_ret
+lz_encode(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size,
+		uint8_t *restrict out, size_t *restrict out_pos,
+		size_t out_size, lzma_action action)
+{
+	lzma_coder *coder = coder_ptr;
+
+	while (*out_pos < out_size
+			&& (*in_pos < in_size || action != LZMA_RUN)) {
+		// Read more data to coder->mf.buffer if needed.
+		if (coder->mf.action == LZMA_RUN && coder->mf.read_pos
+				>= coder->mf.read_limit)
+			return_if_error(fill_window(coder, allocator,
+					in, in_pos, in_size, action));
+
+		// Encode
+		const lzma_ret ret = coder->lz.code(coder->lz.coder,
+				&coder->mf, out, out_pos, out_size);
+		if (ret != LZMA_OK) {
+			// Setting this to LZMA_RUN for cases when we are
+			// flushing. It doesn't matter when finishing or if
+			// an error occurred.
+			coder->mf.action = LZMA_RUN;
+			return ret;
+		}
+	}
+
+	return LZMA_OK;
+}
+
+
+static bool
+lz_encoder_prepare(lzma_mf *mf, const lzma_allocator *allocator,
+		const lzma_lz_options *lz_options)
+{
+	// For now, the dictionary size is limited to 1.5 GiB. This may grow
+	// in the future if needed, but it needs a little more work than just
+	// changing this check.
+	if (!IS_ENC_DICT_SIZE_VALID(lz_options->dict_size)
+			|| lz_options->nice_len > lz_options->match_len_max)
+		return true;
+
+	mf->keep_size_before = lz_options->before_size + lz_options->dict_size;
+
+	mf->keep_size_after = lz_options->after_size
+			+ lz_options->match_len_max;
+
+	// To avoid constant memmove()s, allocate some extra space. Since
+	// memmove()s become more expensive when the size of the buffer
+	// increases, we reserve more space when a large dictionary is
+	// used to make the memmove() calls rarer.
+	//
+	// This works with dictionaries up to about 3 GiB. If bigger
+	// dictionary is wanted, some extra work is needed:
+	//   - Several variables in lzma_mf have to be changed from uint32_t
+	//     to size_t.
+	//   - Memory usage calculation needs something too, e.g. use uint64_t
+	//     for mf->size.
+	uint32_t reserve = lz_options->dict_size / 2;
+	if (reserve > (UINT32_C(1) << 30))
+		reserve /= 2;
+
+	reserve += (lz_options->before_size + lz_options->match_len_max
+			+ lz_options->after_size) / 2 + (UINT32_C(1) << 19);
+
+	const uint32_t old_size = mf->size;
+	mf->size = mf->keep_size_before + reserve + mf->keep_size_after;
+
+	// Deallocate the old history buffer if it exists but has different
+	// size than what is needed now.
+	if (mf->buffer != NULL && old_size != mf->size) {
+		lzma_free(mf->buffer, allocator);
+		mf->buffer = NULL;
+	}
+
+	// Match finder options
+	mf->match_len_max = lz_options->match_len_max;
+	mf->nice_len = lz_options->nice_len;
+
+	// cyclic_size has to stay smaller than 2 Gi. Note that this doesn't
+	// mean limiting dictionary size to less than 2 GiB. With a match
+	// finder that uses multibyte resolution (hashes start at e.g. every
+	// fourth byte), cyclic_size would stay below 2 Gi even when
+	// dictionary size is greater than 2 GiB.
+	//
+	// It would be possible to allow cyclic_size >= 2 Gi, but then we
+	// would need to be careful to use 64-bit types in various places
+	// (size_t could do since we would need bigger than 32-bit address
+	// space anyway). It would also require either zeroing a multigigabyte
+	// buffer at initialization (waste of time and RAM) or allow
+	// normalization in lz_encoder_mf.c to access uninitialized
+	// memory to keep the code simpler. The current way is simple and
+	// still allows pretty big dictionaries, so I don't expect these
+	// limits to change.
+	mf->cyclic_size = lz_options->dict_size + 1;
+
+	// Validate the match finder ID and setup the function pointers.
+	switch (lz_options->match_finder) {
+#ifdef HAVE_MF_HC3
+	case LZMA_MF_HC3:
+		mf->find = &lzma_mf_hc3_find;
+		mf->skip = &lzma_mf_hc3_skip;
+		break;
+#endif
+#ifdef HAVE_MF_HC4
+	case LZMA_MF_HC4:
+		mf->find = &lzma_mf_hc4_find;
+		mf->skip = &lzma_mf_hc4_skip;
+		break;
+#endif
+#ifdef HAVE_MF_BT2
+	case LZMA_MF_BT2:
+		mf->find = &lzma_mf_bt2_find;
+		mf->skip = &lzma_mf_bt2_skip;
+		break;
+#endif
+#ifdef HAVE_MF_BT3
+	case LZMA_MF_BT3:
+		mf->find = &lzma_mf_bt3_find;
+		mf->skip = &lzma_mf_bt3_skip;
+		break;
+#endif
+#ifdef HAVE_MF_BT4
+	case LZMA_MF_BT4:
+		mf->find = &lzma_mf_bt4_find;
+		mf->skip = &lzma_mf_bt4_skip;
+		break;
+#endif
+
+	default:
+		return true;
+	}
+
+	// Calculate the sizes of mf->hash and mf->son.
+	//
+	// NOTE: Since 5.3.5beta the LZMA encoder ensures that nice_len
+	// is big enough for the selected match finder. This makes it
+	// easier for applications as nice_len = 2 will always be accepted
+	// even though the effective value can be slightly bigger.
+	const uint32_t hash_bytes
+			= mf_get_hash_bytes(lz_options->match_finder);
+	assert(hash_bytes <= mf->nice_len);
+
+	const bool is_bt = (lz_options->match_finder & 0x10) != 0;
+	uint32_t hs;
+
+	if (hash_bytes == 2) {
+		hs = 0xFFFF;
+	} else {
+		// Round dictionary size up to the next 2^n - 1 so it can
+		// be used as a hash mask.
+		hs = lz_options->dict_size - 1;
+		hs |= hs >> 1;
+		hs |= hs >> 2;
+		hs |= hs >> 4;
+		hs |= hs >> 8;
+		hs >>= 1;
+		hs |= 0xFFFF;
+
+		if (hs > (UINT32_C(1) << 24)) {
+			if (hash_bytes == 3)
+				hs = (UINT32_C(1) << 24) - 1;
+			else
+				hs >>= 1;
+		}
+	}
+
+	mf->hash_mask = hs;
+
+	++hs;
+	if (hash_bytes > 2)
+		hs += HASH_2_SIZE;
+	if (hash_bytes > 3)
+		hs += HASH_3_SIZE;
+/*
+	No match finder uses this at the moment.
+	if (mf->hash_bytes > 4)
+		hs += HASH_4_SIZE;
+*/
+
+	const uint32_t old_hash_count = mf->hash_count;
+	const uint32_t old_sons_count = mf->sons_count;
+	mf->hash_count = hs;
+	mf->sons_count = mf->cyclic_size;
+	if (is_bt)
+		mf->sons_count *= 2;
+
+	// Deallocate the old hash array if it exists and has different size
+	// than what is needed now.
+	if (old_hash_count != mf->hash_count
+			|| old_sons_count != mf->sons_count) {
+		lzma_free(mf->hash, allocator);
+		mf->hash = NULL;
+
+		lzma_free(mf->son, allocator);
+		mf->son = NULL;
+	}
+
+	// Maximum number of match finder cycles
+	mf->depth = lz_options->depth;
+	if (mf->depth == 0) {
+		if (is_bt)
+			mf->depth = 16 + mf->nice_len / 2;
+		else
+			mf->depth = 4 + mf->nice_len / 4;
+	}
+
+	return false;
+}
+
+
+static bool
+lz_encoder_init(lzma_mf *mf, const lzma_allocator *allocator,
+		const lzma_lz_options *lz_options)
+{
+	// Allocate the history buffer.
+	if (mf->buffer == NULL) {
+		// lzma_memcmplen() is used for the dictionary buffer
+		// so we need to allocate a few extra bytes to prevent
+		// it from reading past the end of the buffer.
+		mf->buffer = lzma_alloc(mf->size + LZMA_MEMCMPLEN_EXTRA,
+				allocator);
+		if (mf->buffer == NULL)
+			return true;
+
+		// Keep Valgrind happy with lzma_memcmplen() and initialize
+		// the extra bytes whose value may get read but which will
+		// effectively get ignored.
+		memzero(mf->buffer + mf->size, LZMA_MEMCMPLEN_EXTRA);
+	}
+
+	// Use cyclic_size as initial mf->offset. This allows
+	// avoiding a few branches in the match finders. The downside is
+	// that match finder needs to be normalized more often, which may
+	// hurt performance with huge dictionaries.
+	mf->offset = mf->cyclic_size;
+	mf->read_pos = 0;
+	mf->read_ahead = 0;
+	mf->read_limit = 0;
+	mf->write_pos = 0;
+	mf->pending = 0;
+
+#if UINT32_MAX >= SIZE_MAX / 4
+	// Check for integer overflow. (Huge dictionaries are not
+	// possible on 32-bit CPU.)
+	if (mf->hash_count > SIZE_MAX / sizeof(uint32_t)
+			|| mf->sons_count > SIZE_MAX / sizeof(uint32_t))
+		return true;
+#endif
+
+	// Allocate and initialize the hash table. Since EMPTY_HASH_VALUE
+	// is zero, we can use lzma_alloc_zero() or memzero() for mf->hash.
+	//
+	// We don't need to initialize mf->son, but not doing that may
+	// make Valgrind complain in normalization (see normalize() in
+	// lz_encoder_mf.c). Skipping the initialization is *very* good
+	// when big dictionary is used but only small amount of data gets
+	// actually compressed: most of the mf->son won't get actually
+	// allocated by the kernel, so we avoid wasting RAM and improve
+	// initialization speed a lot.
+	if (mf->hash == NULL) {
+		mf->hash = lzma_alloc_zero(mf->hash_count * sizeof(uint32_t),
+				allocator);
+		mf->son = lzma_alloc(mf->sons_count * sizeof(uint32_t),
+				allocator);
+
+		if (mf->hash == NULL || mf->son == NULL) {
+			lzma_free(mf->hash, allocator);
+			mf->hash = NULL;
+
+			lzma_free(mf->son, allocator);
+			mf->son = NULL;
+
+			return true;
+		}
+	} else {
+/*
+		for (uint32_t i = 0; i < mf->hash_count; ++i)
+			mf->hash[i] = EMPTY_HASH_VALUE;
+*/
+		memzero(mf->hash, mf->hash_count * sizeof(uint32_t));
+	}
+
+	mf->cyclic_pos = 0;
+
+	// Handle preset dictionary.
+	if (lz_options->preset_dict != NULL
+			&& lz_options->preset_dict_size > 0) {
+		// If the preset dictionary is bigger than the actual
+		// dictionary, use only the tail.
+		mf->write_pos = my_min(lz_options->preset_dict_size, mf->size);
+		memcpy(mf->buffer, lz_options->preset_dict
+				+ lz_options->preset_dict_size - mf->write_pos,
+				mf->write_pos);
+		mf->action = LZMA_SYNC_FLUSH;
+		mf->skip(mf, mf->write_pos);
+	}
+
+	mf->action = LZMA_RUN;
+
+	return false;
+}
+
+
+extern uint64_t
+lzma_lz_encoder_memusage(const lzma_lz_options *lz_options)
+{
+	// Old buffers must not exist when calling lz_encoder_prepare().
+	lzma_mf mf = {
+		.buffer = NULL,
+		.hash = NULL,
+		.son = NULL,
+		.hash_count = 0,
+		.sons_count = 0,
+	};
+
+	// Setup the size information into mf.
+	if (lz_encoder_prepare(&mf, NULL, lz_options))
+		return UINT64_MAX;
+
+	// Calculate the memory usage.
+	return ((uint64_t)(mf.hash_count) + mf.sons_count) * sizeof(uint32_t)
+			+ mf.size + sizeof(lzma_coder);
+}
+
+
+static void
+lz_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_coder *coder = coder_ptr;
+
+	lzma_next_end(&coder->next, allocator);
+
+	lzma_free(coder->mf.son, allocator);
+	lzma_free(coder->mf.hash, allocator);
+	lzma_free(coder->mf.buffer, allocator);
+
+	if (coder->lz.end != NULL)
+		coder->lz.end(coder->lz.coder, allocator);
+	else
+		lzma_free(coder->lz.coder, allocator);
+
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_ret
+lz_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
+		const lzma_filter *filters_null lzma_attribute((__unused__)),
+		const lzma_filter *reversed_filters)
+{
+	lzma_coder *coder = coder_ptr;
+
+	if (coder->lz.options_update == NULL)
+		return LZMA_PROG_ERROR;
+
+	return_if_error(coder->lz.options_update(
+			coder->lz.coder, reversed_filters));
+
+	return lzma_next_filter_update(
+			&coder->next, allocator, reversed_filters + 1);
+}
+
+
+static lzma_ret
+lz_encoder_set_out_limit(void *coder_ptr, uint64_t *uncomp_size,
+		uint64_t out_limit)
+{
+	lzma_coder *coder = coder_ptr;
+
+	// This is supported only if there are no other filters chained.
+	if (coder->next.code == NULL && coder->lz.set_out_limit != NULL)
+		return coder->lz.set_out_limit(
+				coder->lz.coder, uncomp_size, out_limit);
+
+	return LZMA_OPTIONS_ERROR;
+}
+
+
+extern lzma_ret
+lzma_lz_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters,
+		lzma_ret (*lz_init)(lzma_lz_encoder *lz,
+			const lzma_allocator *allocator,
+			lzma_vli id, const void *options,
+			lzma_lz_options *lz_options))
+{
+#if defined(HAVE_SMALL) && !defined(HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR)
+	// The CRC32 table must be initialized.
+	lzma_crc32_init();
+#endif
+
+	// Allocate and initialize the base data structure.
+	lzma_coder *coder = next->coder;
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+		next->code = &lz_encode;
+		next->end = &lz_encoder_end;
+		next->update = &lz_encoder_update;
+		next->set_out_limit = &lz_encoder_set_out_limit;
+
+		coder->lz.coder = NULL;
+		coder->lz.code = NULL;
+		coder->lz.end = NULL;
+		coder->lz.options_update = NULL;
+		coder->lz.set_out_limit = NULL;
+
+		// mf.size is initialized to silence Valgrind
+		// when used on optimized binaries (GCC may reorder
+		// code in a way that Valgrind gets unhappy).
+		coder->mf.buffer = NULL;
+		coder->mf.size = 0;
+		coder->mf.hash = NULL;
+		coder->mf.son = NULL;
+		coder->mf.hash_count = 0;
+		coder->mf.sons_count = 0;
+
+		coder->next = LZMA_NEXT_CODER_INIT;
+	}
+
+	// Initialize the LZ-based encoder.
+	lzma_lz_options lz_options;
+	return_if_error(lz_init(&coder->lz, allocator,
+			filters[0].id, filters[0].options, &lz_options));
+
+	// Setup the size information into coder->mf and deallocate
+	// old buffers if they have wrong size.
+	if (lz_encoder_prepare(&coder->mf, allocator, &lz_options))
+		return LZMA_OPTIONS_ERROR;
+
+	// Allocate new buffers if needed, and do the rest of
+	// the initialization.
+	if (lz_encoder_init(&coder->mf, allocator, &lz_options))
+		return LZMA_MEM_ERROR;
+
+	// Initialize the next filter in the chain, if any.
+	return lzma_next_filter_init(&coder->next, allocator, filters + 1);
+}
+
+
+extern LZMA_API(lzma_bool)
+lzma_mf_is_supported(lzma_match_finder mf)
+{
+	switch (mf) {
+#ifdef HAVE_MF_HC3
+	case LZMA_MF_HC3:
+		return true;
+#endif
+#ifdef HAVE_MF_HC4
+	case LZMA_MF_HC4:
+		return true;
+#endif
+#ifdef HAVE_MF_BT2
+	case LZMA_MF_BT2:
+		return true;
+#endif
+#ifdef HAVE_MF_BT3
+	case LZMA_MF_BT3:
+		return true;
+#endif
+#ifdef HAVE_MF_BT4
+	case LZMA_MF_BT4:
+		return true;
+#endif
+	default:
+		return false;
+	}
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.h
new file mode 100644
index 00000000000..eb197c6b6cd
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder.h
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lz_encoder.h
+/// \brief      LZ in window and match finder API
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZ_ENCODER_H
+#define LZMA_LZ_ENCODER_H
+
+#include "common.h"
+
+
+// For now, the dictionary size is limited to 1.5 GiB. This may grow
+// in the future if needed, but it needs a little more work than just
+// changing this check.
+#define IS_ENC_DICT_SIZE_VALID(size) \
+	((size) >= LZMA_DICT_SIZE_MIN \
+		&& (size) <= (UINT32_C(1) << 30) + (UINT32_C(1) << 29))
+
+
+/// A table of these is used by the LZ-based encoder to hold
+/// the length-distance pairs found by the match finder.
+typedef struct {
+	uint32_t len;
+	uint32_t dist;
+} lzma_match;
+
+
+typedef struct lzma_mf_s lzma_mf;
+struct lzma_mf_s {
+	///////////////
+	// In Window //
+	///////////////
+
+	/// Pointer to buffer with data to be compressed
+	uint8_t *buffer;
+
+	/// Total size of the allocated buffer (that is, including all
+	/// the extra space)
+	uint32_t size;
+
+	/// Number of bytes that must be kept available in our input history.
+	/// That is, once keep_size_before bytes have been processed,
+	/// buffer[read_pos - keep_size_before] is the oldest byte that
+	/// must be available for reading.
+	uint32_t keep_size_before;
+
+	/// Number of bytes that must be kept in buffer after read_pos.
+	/// That is, read_pos <= write_pos - keep_size_after as long as
+	/// action is LZMA_RUN; when action != LZMA_RUN, read_pos is allowed
+	/// to reach write_pos so that the last bytes get encoded too.
+	uint32_t keep_size_after;
+
+	/// Match finders store locations of matches using 32-bit integers.
+	/// To avoid adjusting several megabytes of integers every time the
+	/// input window is moved with move_window, we only adjust the
+	/// offset of the buffer. Thus, buffer[value_in_hash_table - offset]
+	/// is the byte pointed by value_in_hash_table.
+	uint32_t offset;
+
+	/// buffer[read_pos] is the next byte to run through the match
+	/// finder. This is incremented in the match finder once the byte
+	/// has been processed.
+	uint32_t read_pos;
+
+	/// Number of bytes that have been ran through the match finder, but
+	/// which haven't been encoded by the LZ-based encoder yet.
+	uint32_t read_ahead;
+
+	/// As long as read_pos is less than read_limit, there is enough
+	/// input available in buffer for at least one encoding loop.
+	///
+	/// Because of the stateful API, read_limit may and will get greater
+	/// than read_pos quite often. This is taken into account when
+	/// calculating the value for keep_size_after.
+	uint32_t read_limit;
+
+	/// buffer[write_pos] is the first byte that doesn't contain valid
+	/// uncompressed data; that is, the next input byte will be copied
+	/// to buffer[write_pos].
+	uint32_t write_pos;
+
+	/// Number of bytes not hashed before read_pos. This is needed to
+	/// restart the match finder after LZMA_SYNC_FLUSH.
+	uint32_t pending;
+
+	//////////////////
+	// Match Finder //
+	//////////////////
+
+	/// Find matches. Returns the number of distance-length pairs written
+	/// to the matches array. This is called only via lzma_mf_find().
+	uint32_t (*find)(lzma_mf *mf, lzma_match *matches);
+
+	/// Skips num bytes. This is like find() but doesn't make the
+	/// distance-length pairs available, thus being a little faster.
+	/// This is called only via mf_skip().
+	void (*skip)(lzma_mf *mf, uint32_t num);
+
+	uint32_t *hash;
+	uint32_t *son;
+	uint32_t cyclic_pos;
+	uint32_t cyclic_size; // Must be dictionary size + 1.
+	uint32_t hash_mask;
+
+	/// Maximum number of loops in the match finder
+	uint32_t depth;
+
+	/// Maximum length of a match that the match finder will try to find.
+	uint32_t nice_len;
+
+	/// Maximum length of a match supported by the LZ-based encoder.
+	/// If the longest match found by the match finder is nice_len,
+	/// mf_find() tries to expand it up to match_len_max bytes.
+	uint32_t match_len_max;
+
+	/// When running out of input, binary tree match finders need to know
+	/// if it is due to flushing or finishing. The action is used also
+	/// by the LZ-based encoders themselves.
+	lzma_action action;
+
+	/// Number of elements in hash[]
+	uint32_t hash_count;
+
+	/// Number of elements in son[]
+	uint32_t sons_count;
+};
+
+
+typedef struct {
+	/// Extra amount of data to keep available before the "actual"
+	/// dictionary.
+	size_t before_size;
+
+	/// Size of the history buffer
+	size_t dict_size;
+
+	/// Extra amount of data to keep available after the "actual"
+	/// dictionary.
+	size_t after_size;
+
+	/// Maximum length of a match that the LZ-based encoder can accept.
+	/// This is used to extend matches of length nice_len to the
+	/// maximum possible length.
+	size_t match_len_max;
+
+	/// Match finder will search matches up to this length.
+	/// This must be less than or equal to match_len_max.
+	size_t nice_len;
+
+	/// Type of the match finder to use
+	lzma_match_finder match_finder;
+
+	/// Maximum search depth
+	uint32_t depth;
+
+	/// Initial dictionary for the match finder to search.
+	const uint8_t *preset_dict;
+
+	/// If the preset dictionary is NULL, this value is ignored.
+	/// Otherwise this member must indicate the preset dictionary's
+	/// buffer size. If this size is larger than dict_size, then only
+	/// the dict_size sized tail of the preset_dict will be used.
+	uint32_t preset_dict_size;
+
+} lzma_lz_options;
+
+
+// The total usable buffer space at any moment outside the match finder:
+// before_size + dict_size + after_size + match_len_max
+//
+// In reality, there's some extra space allocated to prevent the number of
+// memmove() calls reasonable. The bigger the dict_size is, the bigger
+// this extra buffer will be since with bigger dictionaries memmove() would
+// also take longer.
+//
+// A single encoder loop in the LZ-based encoder may call the match finder
+// (mf_find() or mf_skip()) at most after_size times. In other words,
+// a single encoder loop may increment lzma_mf.read_pos at most after_size
+// times. Since matches are looked up to
+// lzma_mf.buffer[lzma_mf.read_pos + match_len_max - 1], the total
+// amount of extra buffer needed after dict_size becomes
+// after_size + match_len_max.
+//
+// before_size has two uses. The first one is to keep literals available
+// in cases when the LZ-based encoder has made some read ahead.
+// TODO: Maybe this could be changed by making the LZ-based encoders to
+// store the actual literals as they do with length-distance pairs.
+//
+// Algorithms such as LZMA2 first try to compress a chunk, and then check
+// if the encoded result is smaller than the uncompressed one. If the chunk
+// was incompressible, it is better to store it in uncompressed form in
+// the output stream. To do this, the whole uncompressed chunk has to be
+// still available in the history buffer. before_size achieves that.
+
+
+typedef struct {
+	/// Data specific to the LZ-based encoder
+	void *coder;
+
+	/// Function to encode from *dict to out[]
+	lzma_ret (*code)(void *coder,
+			lzma_mf *restrict mf, uint8_t *restrict out,
+			size_t *restrict out_pos, size_t out_size);
+
+	/// Free allocated resources
+	void (*end)(void *coder, const lzma_allocator *allocator);
+
+	/// Update the options in the middle of the encoding.
+	lzma_ret (*options_update)(void *coder, const lzma_filter *filter);
+
+	/// Set maximum allowed output size
+	lzma_ret (*set_out_limit)(void *coder, uint64_t *uncomp_size,
+			uint64_t out_limit);
+
+} lzma_lz_encoder;
+
+
+// Basic steps:
+//  1. Input gets copied into the dictionary.
+//  2. Data in dictionary gets run through the match finder byte by byte.
+//  3. The literals and matches are encoded using e.g. LZMA.
+//
+// The bytes that have been ran through the match finder, but not encoded yet,
+// are called 'read ahead'.
+
+
+/// Get how many bytes the match finder hashes in its initial step.
+/// This is also the minimum nice_len value with the match finder.
+static inline uint32_t
+mf_get_hash_bytes(lzma_match_finder match_finder)
+{
+	return (uint32_t)match_finder & 0x0F;
+}
+
+
+/// Get pointer to the first byte not ran through the match finder
+static inline const uint8_t *
+mf_ptr(const lzma_mf *mf)
+{
+	return mf->buffer + mf->read_pos;
+}
+
+
+/// Get the number of bytes that haven't been ran through the match finder yet.
+static inline uint32_t
+mf_avail(const lzma_mf *mf)
+{
+	return mf->write_pos - mf->read_pos;
+}
+
+
+/// Get the number of bytes that haven't been encoded yet (some of these
+/// bytes may have been ran through the match finder though).
+static inline uint32_t
+mf_unencoded(const lzma_mf *mf)
+{
+	return mf->write_pos - mf->read_pos + mf->read_ahead;
+}
+
+
+/// Calculate the absolute offset from the beginning of the most recent
+/// dictionary reset. Only the lowest four bits are important, so there's no
+/// problem that we don't know the 64-bit size of the data encoded so far.
+///
+/// NOTE: When moving the input window, we need to do it so that the lowest
+/// bits of dict->read_pos are not modified to keep this macro working
+/// as intended.
+static inline uint32_t
+mf_position(const lzma_mf *mf)
+{
+	return mf->read_pos - mf->read_ahead;
+}
+
+
+/// Since everything else begins with mf_, use it also for lzma_mf_find().
+#define mf_find lzma_mf_find
+
+
+/// Skip the given number of bytes. This is used when a good match was found.
+/// For example, if mf_find() finds a match of 200 bytes long, the first byte
+/// of that match was already consumed by mf_find(), and the rest 199 bytes
+/// have to be skipped with mf_skip(mf, 199).
+static inline void
+mf_skip(lzma_mf *mf, uint32_t amount)
+{
+	if (amount != 0) {
+		mf->skip(mf, amount);
+		mf->read_ahead += amount;
+	}
+}
+
+
+/// Copies at most *left number of bytes from the history buffer
+/// to out[]. This is needed by LZMA2 to encode uncompressed chunks.
+static inline void
+mf_read(lzma_mf *mf, uint8_t *out, size_t *out_pos, size_t out_size,
+		size_t *left)
+{
+	const size_t out_avail = out_size - *out_pos;
+	const size_t copy_size = my_min(out_avail, *left);
+
+	assert(mf->read_ahead == 0);
+	assert(mf->read_pos >= *left);
+
+	memcpy(out + *out_pos, mf->buffer + mf->read_pos - *left,
+			copy_size);
+
+	*out_pos += copy_size;
+	*left -= copy_size;
+	return;
+}
+
+
+extern lzma_ret lzma_lz_encoder_init(
+		lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters,
+		lzma_ret (*lz_init)(lzma_lz_encoder *lz,
+			const lzma_allocator *allocator,
+			lzma_vli id, const void *options,
+			lzma_lz_options *lz_options));
+
+
+extern uint64_t lzma_lz_encoder_memusage(const lzma_lz_options *lz_options);
+
+
+// These are only for LZ encoder's internal use.
+extern uint32_t lzma_mf_find(
+		lzma_mf *mf, uint32_t *count, lzma_match *matches);
+
+extern uint32_t lzma_mf_hc3_find(lzma_mf *dict, lzma_match *matches);
+extern void lzma_mf_hc3_skip(lzma_mf *dict, uint32_t amount);
+
+extern uint32_t lzma_mf_hc4_find(lzma_mf *dict, lzma_match *matches);
+extern void lzma_mf_hc4_skip(lzma_mf *dict, uint32_t amount);
+
+extern uint32_t lzma_mf_bt2_find(lzma_mf *dict, lzma_match *matches);
+extern void lzma_mf_bt2_skip(lzma_mf *dict, uint32_t amount);
+
+extern uint32_t lzma_mf_bt3_find(lzma_mf *dict, lzma_match *matches);
+extern void lzma_mf_bt3_skip(lzma_mf *dict, uint32_t amount);
+
+extern uint32_t lzma_mf_bt4_find(lzma_mf *dict, lzma_match *matches);
+extern void lzma_mf_bt4_skip(lzma_mf *dict, uint32_t amount);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash.h
new file mode 100644
index 00000000000..8ace82b04c5
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash.h
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lz_encoder_hash.h
+/// \brief      Hash macros for match finders
+//
+//  Author:     Igor Pavlov
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZ_ENCODER_HASH_H
+#define LZMA_LZ_ENCODER_HASH_H
+
+#if defined(WORDS_BIGENDIAN) && !defined(HAVE_SMALL)
+	// This is to make liblzma produce the same output on big endian
+	// systems that it does on little endian systems. lz_encoder.c
+	// takes care of including the actual table.
+	lzma_attr_visibility_hidden
+	extern const uint32_t lzma_lz_hash_table[256];
+#	define hash_table lzma_lz_hash_table
+#else
+#	include "check.h"
+#	define hash_table lzma_crc32_table[0]
+#endif
+
+#define HASH_2_SIZE (UINT32_C(1) << 10)
+#define HASH_3_SIZE (UINT32_C(1) << 16)
+#define HASH_4_SIZE (UINT32_C(1) << 20)
+
+#define HASH_2_MASK (HASH_2_SIZE - 1)
+#define HASH_3_MASK (HASH_3_SIZE - 1)
+#define HASH_4_MASK (HASH_4_SIZE - 1)
+
+#define FIX_3_HASH_SIZE (HASH_2_SIZE)
+#define FIX_4_HASH_SIZE (HASH_2_SIZE + HASH_3_SIZE)
+#define FIX_5_HASH_SIZE (HASH_2_SIZE + HASH_3_SIZE + HASH_4_SIZE)
+
+// Endianness doesn't matter in hash_2_calc() (no effect on the output).
+#ifdef TUKLIB_FAST_UNALIGNED_ACCESS
+#	define hash_2_calc() \
+		const uint32_t hash_value = read16ne(cur)
+#else
+#	define hash_2_calc() \
+		const uint32_t hash_value \
+			= (uint32_t)(cur[0]) | ((uint32_t)(cur[1]) << 8)
+#endif
+
+#define hash_3_calc() \
+	const uint32_t temp = hash_table[cur[0]] ^ cur[1]; \
+	const uint32_t hash_2_value = temp & HASH_2_MASK; \
+	const uint32_t hash_value \
+			= (temp ^ ((uint32_t)(cur[2]) << 8)) & mf->hash_mask
+
+#define hash_4_calc() \
+	const uint32_t temp = hash_table[cur[0]] ^ cur[1]; \
+	const uint32_t hash_2_value = temp & HASH_2_MASK; \
+	const uint32_t hash_3_value \
+			= (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK; \
+	const uint32_t hash_value = (temp ^ ((uint32_t)(cur[2]) << 8) \
+			^ (hash_table[cur[3]] << 5)) & mf->hash_mask
+
+
+// The following are not currently used.
+
+#define hash_5_calc() \
+	const uint32_t temp = hash_table[cur[0]] ^ cur[1]; \
+	const uint32_t hash_2_value = temp & HASH_2_MASK; \
+	const uint32_t hash_3_value \
+			= (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK; \
+	uint32_t hash_4_value = (temp ^ ((uint32_t)(cur[2]) << 8) ^ \
+			^ hash_table[cur[3]] << 5); \
+	const uint32_t hash_value \
+			= (hash_4_value ^ (hash_table[cur[4]] << 3)) \
+				& mf->hash_mask; \
+	hash_4_value &= HASH_4_MASK
+
+/*
+#define hash_zip_calc() \
+	const uint32_t hash_value \
+			= (((uint32_t)(cur[0]) | ((uint32_t)(cur[1]) << 8)) \
+				^ hash_table[cur[2]]) & 0xFFFF
+*/
+
+#define hash_zip_calc() \
+	const uint32_t hash_value \
+			= (((uint32_t)(cur[2]) | ((uint32_t)(cur[0]) << 8)) \
+				^ hash_table[cur[1]]) & 0xFFFF
+
+#define mt_hash_2_calc() \
+	const uint32_t hash_2_value \
+			= (hash_table[cur[0]] ^ cur[1]) & HASH_2_MASK
+
+#define mt_hash_3_calc() \
+	const uint32_t temp = hash_table[cur[0]] ^ cur[1]; \
+	const uint32_t hash_2_value = temp & HASH_2_MASK; \
+	const uint32_t hash_3_value \
+			= (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK
+
+#define mt_hash_4_calc() \
+	const uint32_t temp = hash_table[cur[0]] ^ cur[1]; \
+	const uint32_t hash_2_value = temp & HASH_2_MASK; \
+	const uint32_t hash_3_value \
+			= (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK; \
+	const uint32_t hash_4_value = (temp ^ ((uint32_t)(cur[2]) << 8) ^ \
+			(hash_table[cur[3]] << 5)) & HASH_4_MASK
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash_table.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash_table.h
new file mode 100644
index 00000000000..2b3a60e43e8
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_hash_table.h
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: 0BSD
+
+// This file has been generated by crc32_tablegen.c.
+
+const uint32_t lzma_lz_hash_table[256] = {
+	0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
+	0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+	0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+	0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+	0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
+	0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+	0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
+	0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+	0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+	0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+	0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
+	0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+	0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
+	0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+	0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+	0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+	0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
+	0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+	0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
+	0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+	0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+	0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+	0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
+	0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+	0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
+	0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+	0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+	0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+	0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
+	0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+	0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
+	0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+	0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+	0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+	0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
+	0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+	0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
+	0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+	0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+	0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+	0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
+	0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+	0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
+	0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+	0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+	0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+	0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
+	0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+	0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
+	0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+	0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+	0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+	0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
+	0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+	0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
+	0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+	0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+	0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+	0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
+	0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+	0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
+	0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+	0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+	0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_mf.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_mf.c
new file mode 100644
index 00000000000..557c2612f2a
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lz/lz_encoder_mf.c
@@ -0,0 +1,744 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lz_encoder_mf.c
+/// \brief      Match finders
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lz_encoder.h"
+#include "lz_encoder_hash.h"
+#include "memcmplen.h"
+
+
+/// \brief      Find matches starting from the current byte
+///
+/// \return     The length of the longest match found
+extern uint32_t
+lzma_mf_find(lzma_mf *mf, uint32_t *count_ptr, lzma_match *matches)
+{
+	// Call the match finder. It returns the number of length-distance
+	// pairs found.
+	// FIXME: Minimum count is zero, what _exactly_ is the maximum?
+	const uint32_t count = mf->find(mf, matches);
+
+	// Length of the longest match; assume that no matches were found
+	// and thus the maximum length is zero.
+	uint32_t len_best = 0;
+
+	if (count > 0) {
+#ifndef NDEBUG
+		// Validate the matches.
+		for (uint32_t i = 0; i < count; ++i) {
+			assert(matches[i].len <= mf->nice_len);
+			assert(matches[i].dist < mf->read_pos);
+			assert(memcmp(mf_ptr(mf) - 1,
+				mf_ptr(mf) - matches[i].dist - 2,
+				matches[i].len) == 0);
+		}
+#endif
+
+		// The last used element in the array contains
+		// the longest match.
+		len_best = matches[count - 1].len;
+
+		// If a match of maximum search length was found, try to
+		// extend the match to maximum possible length.
+		if (len_best == mf->nice_len) {
+			// The limit for the match length is either the
+			// maximum match length supported by the LZ-based
+			// encoder or the number of bytes left in the
+			// dictionary, whichever is smaller.
+			uint32_t limit = mf_avail(mf) + 1;
+			if (limit > mf->match_len_max)
+				limit = mf->match_len_max;
+
+			// Pointer to the byte we just ran through
+			// the match finder.
+			const uint8_t *p1 = mf_ptr(mf) - 1;
+
+			// Pointer to the beginning of the match. We need -1
+			// here because the match distances are zero based.
+			const uint8_t *p2 = p1 - matches[count - 1].dist - 1;
+
+			len_best = lzma_memcmplen(p1, p2, len_best, limit);
+		}
+	}
+
+	*count_ptr = count;
+
+	// Finally update the read position to indicate that match finder was
+	// run for this dictionary offset.
+	++mf->read_ahead;
+
+	return len_best;
+}
+
+
+/// Hash value to indicate unused element in the hash. Since we start the
+/// positions from dict_size + 1, zero is always too far to qualify
+/// as usable match position.
+#define EMPTY_HASH_VALUE 0
+
+
+/// Normalization must be done when lzma_mf.offset + lzma_mf.read_pos
+/// reaches MUST_NORMALIZE_POS.
+#define MUST_NORMALIZE_POS UINT32_MAX
+
+
+/// \brief      Normalizes hash values
+///
+/// The hash arrays store positions of match candidates. The positions are
+/// relative to an arbitrary offset that is not the same as the absolute
+/// offset in the input stream. The relative position of the current byte
+/// is lzma_mf.offset + lzma_mf.read_pos. The distances of the matches are
+/// the differences of the current read position and the position found from
+/// the hash.
+///
+/// To prevent integer overflows of the offsets stored in the hash arrays,
+/// we need to "normalize" the stored values now and then. During the
+/// normalization, we drop values that indicate distance greater than the
+/// dictionary size, thus making space for new values.
+static void
+normalize(lzma_mf *mf)
+{
+	assert(mf->read_pos + mf->offset == MUST_NORMALIZE_POS);
+
+	// In future we may not want to touch the lowest bits, because there
+	// may be match finders that use larger resolution than one byte.
+	const uint32_t subvalue
+			= (MUST_NORMALIZE_POS - mf->cyclic_size);
+				// & ~((UINT32_C(1) << 10) - 1);
+
+	for (uint32_t i = 0; i < mf->hash_count; ++i) {
+		// If the distance is greater than the dictionary size,
+		// we can simply mark the hash element as empty.
+		if (mf->hash[i] <= subvalue)
+			mf->hash[i] = EMPTY_HASH_VALUE;
+		else
+			mf->hash[i] -= subvalue;
+	}
+
+	for (uint32_t i = 0; i < mf->sons_count; ++i) {
+		// Do the same for mf->son.
+		//
+		// NOTE: There may be uninitialized elements in mf->son.
+		// Valgrind may complain that the "if" below depends on
+		// an uninitialized value. In this case it is safe to ignore
+		// the warning. See also the comments in lz_encoder_init()
+		// in lz_encoder.c.
+		if (mf->son[i] <= subvalue)
+			mf->son[i] = EMPTY_HASH_VALUE;
+		else
+			mf->son[i] -= subvalue;
+	}
+
+	// Update offset to match the new locations.
+	mf->offset -= subvalue;
+
+	return;
+}
+
+
+/// Mark the current byte as processed from point of view of the match finder.
+static void
+move_pos(lzma_mf *mf)
+{
+	if (++mf->cyclic_pos == mf->cyclic_size)
+		mf->cyclic_pos = 0;
+
+	++mf->read_pos;
+	assert(mf->read_pos <= mf->write_pos);
+
+	if (unlikely(mf->read_pos + mf->offset == UINT32_MAX))
+		normalize(mf);
+}
+
+
+/// When flushing, we cannot run the match finder unless there is nice_len
+/// bytes available in the dictionary. Instead, we skip running the match
+/// finder (indicating that no match was found), and count how many bytes we
+/// have ignored this way.
+///
+/// When new data is given after the flushing was completed, the match finder
+/// is restarted by rewinding mf->read_pos backwards by mf->pending. Then
+/// the missed bytes are added to the hash using the match finder's skip
+/// function (with small amount of input, it may start using mf->pending
+/// again if flushing).
+///
+/// Due to this rewinding, we don't touch cyclic_pos or test for
+/// normalization. It will be done when the match finder's skip function
+/// catches up after a flush.
+static void
+move_pending(lzma_mf *mf)
+{
+	++mf->read_pos;
+	assert(mf->read_pos <= mf->write_pos);
+	++mf->pending;
+}
+
+
+/// Calculate len_limit and determine if there is enough input to run
+/// the actual match finder code. Sets up "cur" and "pos". This macro
+/// is used by all find functions and binary tree skip functions. Hash
+/// chain skip function doesn't need len_limit so a simpler code is used
+/// in them.
+#define header(is_bt, len_min, ret_op) \
+	uint32_t len_limit = mf_avail(mf); \
+	if (mf->nice_len <= len_limit) { \
+		len_limit = mf->nice_len; \
+	} else if (len_limit < (len_min) \
+			|| (is_bt && mf->action == LZMA_SYNC_FLUSH)) { \
+		assert(mf->action != LZMA_RUN); \
+		move_pending(mf); \
+		ret_op; \
+	} \
+	const uint8_t *cur = mf_ptr(mf); \
+	const uint32_t pos = mf->read_pos + mf->offset
+
+
+/// Header for find functions. "return 0" indicates that zero matches
+/// were found.
+#define header_find(is_bt, len_min) \
+	header(is_bt, len_min, return 0); \
+	uint32_t matches_count = 0
+
+
+/// Header for a loop in a skip function. "continue" tells to skip the rest
+/// of the code in the loop.
+#define header_skip(is_bt, len_min) \
+	header(is_bt, len_min, continue)
+
+
+/// Calls hc_find_func() or bt_find_func() and calculates the total number
+/// of matches found. Updates the dictionary position and returns the number
+/// of matches found.
+#define call_find(func, len_best) \
+do { \
+	matches_count = (uint32_t)(func(len_limit, pos, cur, cur_match, \
+				mf->depth, mf->son, \
+				mf->cyclic_pos, mf->cyclic_size, \
+				matches + matches_count, len_best) \
+			- matches); \
+	move_pos(mf); \
+	return matches_count; \
+} while (0)
+
+
+////////////////
+// Hash Chain //
+////////////////
+
+#if defined(HAVE_MF_HC3) || defined(HAVE_MF_HC4)
+///
+///
+/// \param      len_limit       Don't look for matches longer than len_limit.
+/// \param      pos             lzma_mf.read_pos + lzma_mf.offset
+/// \param      cur             Pointer to current byte (mf_ptr(mf))
+/// \param      cur_match       Start position of the current match candidate
+/// \param      depth           Maximum length of the hash chain
+/// \param      son             lzma_mf.son (contains the hash chain)
+/// \param      cyclic_pos      lzma_mf.cyclic_pos
+/// \param      cyclic_size     lzma_mf_cyclic_size
+/// \param      matches         Array to hold the matches.
+/// \param      len_best        The length of the longest match found so far.
+static lzma_match *
+hc_find_func(
+		const uint32_t len_limit,
+		const uint32_t pos,
+		const uint8_t *const cur,
+		uint32_t cur_match,
+		uint32_t depth,
+		uint32_t *const son,
+		const uint32_t cyclic_pos,
+		const uint32_t cyclic_size,
+		lzma_match *matches,
+		uint32_t len_best)
+{
+	son[cyclic_pos] = cur_match;
+
+	while (true) {
+		const uint32_t delta = pos - cur_match;
+		if (depth-- == 0 || delta >= cyclic_size)
+			return matches;
+
+		const uint8_t *const pb = cur - delta;
+		cur_match = son[cyclic_pos - delta
+				+ (delta > cyclic_pos ? cyclic_size : 0)];
+
+		if (pb[len_best] == cur[len_best] && pb[0] == cur[0]) {
+			uint32_t len = lzma_memcmplen(pb, cur, 1, len_limit);
+
+			if (len_best < len) {
+				len_best = len;
+				matches->len = len;
+				matches->dist = delta - 1;
+				++matches;
+
+				if (len == len_limit)
+					return matches;
+			}
+		}
+	}
+}
+
+
+#define hc_find(len_best) \
+	call_find(hc_find_func, len_best)
+
+
+#define hc_skip() \
+do { \
+	mf->son[mf->cyclic_pos] = cur_match; \
+	move_pos(mf); \
+} while (0)
+
+#endif
+
+
+#ifdef HAVE_MF_HC3
+extern uint32_t
+lzma_mf_hc3_find(lzma_mf *mf, lzma_match *matches)
+{
+	header_find(false, 3);
+
+	hash_3_calc();
+
+	const uint32_t delta2 = pos - mf->hash[hash_2_value];
+	const uint32_t cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
+
+	mf->hash[hash_2_value] = pos;
+	mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
+
+	uint32_t len_best = 2;
+
+	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
+		len_best = lzma_memcmplen(cur - delta2, cur,
+				len_best, len_limit);
+
+		matches[0].len = len_best;
+		matches[0].dist = delta2 - 1;
+		matches_count = 1;
+
+		if (len_best == len_limit) {
+			hc_skip();
+			return 1; // matches_count
+		}
+	}
+
+	hc_find(len_best);
+}
+
+
+extern void
+lzma_mf_hc3_skip(lzma_mf *mf, uint32_t amount)
+{
+	do {
+		if (mf_avail(mf) < 3) {
+			move_pending(mf);
+			continue;
+		}
+
+		const uint8_t *cur = mf_ptr(mf);
+		const uint32_t pos = mf->read_pos + mf->offset;
+
+		hash_3_calc();
+
+		const uint32_t cur_match
+				= mf->hash[FIX_3_HASH_SIZE + hash_value];
+
+		mf->hash[hash_2_value] = pos;
+		mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
+
+		hc_skip();
+
+	} while (--amount != 0);
+}
+#endif
+
+
+#ifdef HAVE_MF_HC4
+extern uint32_t
+lzma_mf_hc4_find(lzma_mf *mf, lzma_match *matches)
+{
+	header_find(false, 4);
+
+	hash_4_calc();
+
+	uint32_t delta2 = pos - mf->hash[hash_2_value];
+	const uint32_t delta3
+			= pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
+	const uint32_t cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
+
+	mf->hash[hash_2_value ] = pos;
+	mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
+	mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
+
+	uint32_t len_best = 1;
+
+	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
+		len_best = 2;
+		matches[0].len = 2;
+		matches[0].dist = delta2 - 1;
+		matches_count = 1;
+	}
+
+	if (delta2 != delta3 && delta3 < mf->cyclic_size
+			&& *(cur - delta3) == *cur) {
+		len_best = 3;
+		matches[matches_count++].dist = delta3 - 1;
+		delta2 = delta3;
+	}
+
+	if (matches_count != 0) {
+		len_best = lzma_memcmplen(cur - delta2, cur,
+				len_best, len_limit);
+
+		matches[matches_count - 1].len = len_best;
+
+		if (len_best == len_limit) {
+			hc_skip();
+			return matches_count;
+		}
+	}
+
+	if (len_best < 3)
+		len_best = 3;
+
+	hc_find(len_best);
+}
+
+
+extern void
+lzma_mf_hc4_skip(lzma_mf *mf, uint32_t amount)
+{
+	do {
+		if (mf_avail(mf) < 4) {
+			move_pending(mf);
+			continue;
+		}
+
+		const uint8_t *cur = mf_ptr(mf);
+		const uint32_t pos = mf->read_pos + mf->offset;
+
+		hash_4_calc();
+
+		const uint32_t cur_match
+				= mf->hash[FIX_4_HASH_SIZE + hash_value];
+
+		mf->hash[hash_2_value] = pos;
+		mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
+		mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
+
+		hc_skip();
+
+	} while (--amount != 0);
+}
+#endif
+
+
+/////////////////
+// Binary Tree //
+/////////////////
+
+#if defined(HAVE_MF_BT2) || defined(HAVE_MF_BT3) || defined(HAVE_MF_BT4)
+static lzma_match *
+bt_find_func(
+		const uint32_t len_limit,
+		const uint32_t pos,
+		const uint8_t *const cur,
+		uint32_t cur_match,
+		uint32_t depth,
+		uint32_t *const son,
+		const uint32_t cyclic_pos,
+		const uint32_t cyclic_size,
+		lzma_match *matches,
+		uint32_t len_best)
+{
+	uint32_t *ptr0 = son + (cyclic_pos << 1) + 1;
+	uint32_t *ptr1 = son + (cyclic_pos << 1);
+
+	uint32_t len0 = 0;
+	uint32_t len1 = 0;
+
+	while (true) {
+		const uint32_t delta = pos - cur_match;
+		if (depth-- == 0 || delta >= cyclic_size) {
+			*ptr0 = EMPTY_HASH_VALUE;
+			*ptr1 = EMPTY_HASH_VALUE;
+			return matches;
+		}
+
+		uint32_t *const pair = son + ((cyclic_pos - delta
+				+ (delta > cyclic_pos ? cyclic_size : 0))
+				<< 1);
+
+		const uint8_t *const pb = cur - delta;
+		uint32_t len = my_min(len0, len1);
+
+		if (pb[len] == cur[len]) {
+			len = lzma_memcmplen(pb, cur, len + 1, len_limit);
+
+			if (len_best < len) {
+				len_best = len;
+				matches->len = len;
+				matches->dist = delta - 1;
+				++matches;
+
+				if (len == len_limit) {
+					*ptr1 = pair[0];
+					*ptr0 = pair[1];
+					return matches;
+				}
+			}
+		}
+
+		if (pb[len] < cur[len]) {
+			*ptr1 = cur_match;
+			ptr1 = pair + 1;
+			cur_match = *ptr1;
+			len1 = len;
+		} else {
+			*ptr0 = cur_match;
+			ptr0 = pair;
+			cur_match = *ptr0;
+			len0 = len;
+		}
+	}
+}
+
+
+static void
+bt_skip_func(
+		const uint32_t len_limit,
+		const uint32_t pos,
+		const uint8_t *const cur,
+		uint32_t cur_match,
+		uint32_t depth,
+		uint32_t *const son,
+		const uint32_t cyclic_pos,
+		const uint32_t cyclic_size)
+{
+	uint32_t *ptr0 = son + (cyclic_pos << 1) + 1;
+	uint32_t *ptr1 = son + (cyclic_pos << 1);
+
+	uint32_t len0 = 0;
+	uint32_t len1 = 0;
+
+	while (true) {
+		const uint32_t delta = pos - cur_match;
+		if (depth-- == 0 || delta >= cyclic_size) {
+			*ptr0 = EMPTY_HASH_VALUE;
+			*ptr1 = EMPTY_HASH_VALUE;
+			return;
+		}
+
+		uint32_t *pair = son + ((cyclic_pos - delta
+				+ (delta > cyclic_pos ? cyclic_size : 0))
+				<< 1);
+		const uint8_t *pb = cur - delta;
+		uint32_t len = my_min(len0, len1);
+
+		if (pb[len] == cur[len]) {
+			len = lzma_memcmplen(pb, cur, len + 1, len_limit);
+
+			if (len == len_limit) {
+				*ptr1 = pair[0];
+				*ptr0 = pair[1];
+				return;
+			}
+		}
+
+		if (pb[len] < cur[len]) {
+			*ptr1 = cur_match;
+			ptr1 = pair + 1;
+			cur_match = *ptr1;
+			len1 = len;
+		} else {
+			*ptr0 = cur_match;
+			ptr0 = pair;
+			cur_match = *ptr0;
+			len0 = len;
+		}
+	}
+}
+
+
+#define bt_find(len_best) \
+	call_find(bt_find_func, len_best)
+
+#define bt_skip() \
+do { \
+	bt_skip_func(len_limit, pos, cur, cur_match, mf->depth, \
+			mf->son, mf->cyclic_pos, \
+			mf->cyclic_size); \
+	move_pos(mf); \
+} while (0)
+
+#endif
+
+
+#ifdef HAVE_MF_BT2
+extern uint32_t
+lzma_mf_bt2_find(lzma_mf *mf, lzma_match *matches)
+{
+	header_find(true, 2);
+
+	hash_2_calc();
+
+	const uint32_t cur_match = mf->hash[hash_value];
+	mf->hash[hash_value] = pos;
+
+	bt_find(1);
+}
+
+
+extern void
+lzma_mf_bt2_skip(lzma_mf *mf, uint32_t amount)
+{
+	do {
+		header_skip(true, 2);
+
+		hash_2_calc();
+
+		const uint32_t cur_match = mf->hash[hash_value];
+		mf->hash[hash_value] = pos;
+
+		bt_skip();
+
+	} while (--amount != 0);
+}
+#endif
+
+
+#ifdef HAVE_MF_BT3
+extern uint32_t
+lzma_mf_bt3_find(lzma_mf *mf, lzma_match *matches)
+{
+	header_find(true, 3);
+
+	hash_3_calc();
+
+	const uint32_t delta2 = pos - mf->hash[hash_2_value];
+	const uint32_t cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
+
+	mf->hash[hash_2_value] = pos;
+	mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
+
+	uint32_t len_best = 2;
+
+	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
+		len_best = lzma_memcmplen(
+				cur, cur - delta2, len_best, len_limit);
+
+		matches[0].len = len_best;
+		matches[0].dist = delta2 - 1;
+		matches_count = 1;
+
+		if (len_best == len_limit) {
+			bt_skip();
+			return 1; // matches_count
+		}
+	}
+
+	bt_find(len_best);
+}
+
+
+extern void
+lzma_mf_bt3_skip(lzma_mf *mf, uint32_t amount)
+{
+	do {
+		header_skip(true, 3);
+
+		hash_3_calc();
+
+		const uint32_t cur_match
+				= mf->hash[FIX_3_HASH_SIZE + hash_value];
+
+		mf->hash[hash_2_value] = pos;
+		mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
+
+		bt_skip();
+
+	} while (--amount != 0);
+}
+#endif
+
+
+#ifdef HAVE_MF_BT4
+extern uint32_t
+lzma_mf_bt4_find(lzma_mf *mf, lzma_match *matches)
+{
+	header_find(true, 4);
+
+	hash_4_calc();
+
+	uint32_t delta2 = pos - mf->hash[hash_2_value];
+	const uint32_t delta3
+			= pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
+	const uint32_t cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
+
+	mf->hash[hash_2_value] = pos;
+	mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
+	mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
+
+	uint32_t len_best = 1;
+
+	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
+		len_best = 2;
+		matches[0].len = 2;
+		matches[0].dist = delta2 - 1;
+		matches_count = 1;
+	}
+
+	if (delta2 != delta3 && delta3 < mf->cyclic_size
+			&& *(cur - delta3) == *cur) {
+		len_best = 3;
+		matches[matches_count++].dist = delta3 - 1;
+		delta2 = delta3;
+	}
+
+	if (matches_count != 0) {
+		len_best = lzma_memcmplen(
+				cur, cur - delta2, len_best, len_limit);
+
+		matches[matches_count - 1].len = len_best;
+
+		if (len_best == len_limit) {
+			bt_skip();
+			return matches_count;
+		}
+	}
+
+	if (len_best < 3)
+		len_best = 3;
+
+	bt_find(len_best);
+}
+
+
+extern void
+lzma_mf_bt4_skip(lzma_mf *mf, uint32_t amount)
+{
+	do {
+		header_skip(true, 4);
+
+		hash_4_calc();
+
+		const uint32_t cur_match
+				= mf->hash[FIX_4_HASH_SIZE + hash_value];
+
+		mf->hash[hash_2_value] = pos;
+		mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
+		mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
+
+		bt_skip();
+
+	} while (--amount != 0);
+}
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos.h
new file mode 100644
index 00000000000..d3969a753fa
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos.h
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       fastpos.h
+/// \brief      Kind of two-bit version of bit scan reverse
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_FASTPOS_H
+#define LZMA_FASTPOS_H
+
+// LZMA encodes match distances by storing the highest two bits using
+// a six-bit value [0, 63], and then the missing lower bits.
+// Dictionary size is also stored using this encoding in the .xz
+// file format header.
+//
+// fastpos.h provides a way to quickly find out the correct six-bit
+// values. The following table gives some examples of this encoding:
+//
+//     dist   return
+//       0       0
+//       1       1
+//       2       2
+//       3       3
+//       4       4
+//       5       4
+//       6       5
+//       7       5
+//       8       6
+//      11       6
+//      12       7
+//     ...      ...
+//      15       7
+//      16       8
+//      17       8
+//     ...      ...
+//      23       8
+//      24       9
+//      25       9
+//     ...      ...
+//
+//
+// Provided functions or macros
+// ----------------------------
+//
+// get_dist_slot(dist) is the basic version. get_dist_slot_2(dist)
+// assumes that dist >= FULL_DISTANCES, thus the result is at least
+// FULL_DISTANCES_BITS * 2. Using get_dist_slot(dist) instead of
+// get_dist_slot_2(dist) would give the same result, but get_dist_slot_2(dist)
+// should be tiny bit faster due to the assumption being made.
+//
+//
+// Size vs. speed
+// --------------
+//
+// With some CPUs that have fast BSR (bit scan reverse) instruction, the
+// size optimized version is slightly faster than the bigger table based
+// approach. Such CPUs include Intel Pentium Pro, Pentium II, Pentium III
+// and Core 2 (possibly others). AMD K7 seems to have slower BSR, but that
+// would still have speed roughly comparable to the table version. Older
+// x86 CPUs like the original Pentium have very slow BSR; on those systems
+// the table version is a lot faster.
+//
+// On some CPUs, the table version is a lot faster when using position
+// dependent code, but with position independent code the size optimized
+// version is slightly faster. This occurs at least on 32-bit SPARC (no
+// ASM optimizations).
+//
+// I'm making the table version the default, because that has good speed
+// on all systems I have tried. The size optimized version is sometimes
+// slightly faster, but sometimes it is a lot slower.
+
+#ifdef HAVE_SMALL
+#	define get_dist_slot(dist) \
+		((dist) <= 4 ? (dist) : get_dist_slot_2(dist))
+
+static inline uint32_t
+get_dist_slot_2(uint32_t dist)
+{
+	const uint32_t i = bsr32(dist);
+	return (i + i) + ((dist >> (i - 1)) & 1);
+}
+
+
+#else
+
+#define FASTPOS_BITS 13
+
+lzma_attr_visibility_hidden
+extern const uint8_t lzma_fastpos[1 << FASTPOS_BITS];
+
+
+#define fastpos_shift(extra, n) \
+	((extra) + (n) * (FASTPOS_BITS - 1))
+
+#define fastpos_limit(extra, n) \
+	(UINT32_C(1) << (FASTPOS_BITS + fastpos_shift(extra, n)))
+
+#define fastpos_result(dist, extra, n) \
+	(uint32_t)(lzma_fastpos[(dist) >> fastpos_shift(extra, n)]) \
+			+ 2 * fastpos_shift(extra, n)
+
+
+static inline uint32_t
+get_dist_slot(uint32_t dist)
+{
+	// If it is small enough, we can pick the result directly from
+	// the precalculated table.
+	if (dist < fastpos_limit(0, 0))
+		return lzma_fastpos[dist];
+
+	if (dist < fastpos_limit(0, 1))
+		return fastpos_result(dist, 0, 1);
+
+	return fastpos_result(dist, 0, 2);
+}
+
+
+#ifdef FULL_DISTANCES_BITS
+static inline uint32_t
+get_dist_slot_2(uint32_t dist)
+{
+	assert(dist >= FULL_DISTANCES);
+
+	if (dist < fastpos_limit(FULL_DISTANCES_BITS - 1, 0))
+		return fastpos_result(dist, FULL_DISTANCES_BITS - 1, 0);
+
+	if (dist < fastpos_limit(FULL_DISTANCES_BITS - 1, 1))
+		return fastpos_result(dist, FULL_DISTANCES_BITS - 1, 1);
+
+	return fastpos_result(dist, FULL_DISTANCES_BITS - 1, 2);
+}
+#endif
+
+#endif
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_table.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_table.c
new file mode 100644
index 00000000000..4e10e3795e2
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_table.c
@@ -0,0 +1,521 @@
+// SPDX-License-Identifier: 0BSD
+
+// This file has been generated by fastpos_tablegen.c.
+
+#include "common.h"
+#include "fastpos.h"
+
+const uint8_t lzma_fastpos[1 << FASTPOS_BITS] = {
+	  0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,
+	  8,  8,  8,  8,  8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9,
+	 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+	 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+	 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+	 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+	 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+	 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+	 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+	 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+	 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+	 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+	 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+	 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+	 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+	 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+	 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+	 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25
+};
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_tablegen.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_tablegen.c
new file mode 100644
index 00000000000..957ccb7a643
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/fastpos_tablegen.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       fastpos_tablegen.c
+/// \brief      Generates the lzma_fastpos[] lookup table
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include 
+#include 
+
+#define lzma_attr_visibility_hidden
+#include "fastpos.h"
+
+
+int
+main(void)
+{
+	uint8_t fastpos[1 << FASTPOS_BITS];
+
+	const uint8_t fast_slots = 2 * FASTPOS_BITS;
+	uint32_t c = 2;
+
+	fastpos[0] = 0;
+	fastpos[1] = 1;
+
+	for (uint8_t slot_fast = 2; slot_fast < fast_slots; ++slot_fast) {
+		const uint32_t k = 1 << ((slot_fast >> 1) - 1);
+		for (uint32_t j = 0; j < k; ++j, ++c)
+			fastpos[c] = slot_fast;
+	}
+
+	// Split the SPDX string so that it won't accidentally match
+	// when tools search for the string.
+	printf("// SPDX" "-License-Identifier" ": 0BSD\n\n"
+		"// This file has been generated by fastpos_tablegen.c.\n\n"
+		"#include \"common.h\"\n"
+		"#include \"fastpos.h\"\n\n"
+		"const uint8_t lzma_fastpos[1 << FASTPOS_BITS] = {");
+
+	for (size_t i = 0; i < (1 << FASTPOS_BITS); ++i) {
+		if (i % 16 == 0)
+			printf("\n\t");
+
+		printf("%3u", (unsigned int)(fastpos[i]));
+
+		if (i != (1 << FASTPOS_BITS) - 1)
+			printf(",");
+	}
+
+	printf("\n};\n");
+
+	return 0;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.c
new file mode 100644
index 00000000000..37ab253f5b0
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lzma2_decoder.c
+/// \brief      LZMA2 decoder
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lzma2_decoder.h"
+#include "lz_decoder.h"
+#include "lzma_decoder.h"
+
+
+typedef struct {
+	enum sequence {
+		SEQ_CONTROL,
+		SEQ_UNCOMPRESSED_1,
+		SEQ_UNCOMPRESSED_2,
+		SEQ_COMPRESSED_0,
+		SEQ_COMPRESSED_1,
+		SEQ_PROPERTIES,
+		SEQ_LZMA,
+		SEQ_COPY,
+	} sequence;
+
+	/// Sequence after the size fields have been decoded.
+	enum sequence next_sequence;
+
+	/// LZMA decoder
+	lzma_lz_decoder lzma;
+
+	/// Uncompressed size of LZMA chunk
+	size_t uncompressed_size;
+
+	/// Compressed size of the chunk (naturally equals to uncompressed
+	/// size of uncompressed chunk)
+	size_t compressed_size;
+
+	/// True if properties are needed. This is false before the
+	/// first LZMA chunk.
+	bool need_properties;
+
+	/// True if dictionary reset is needed. This is false before the
+	/// first chunk (LZMA or uncompressed).
+	bool need_dictionary_reset;
+
+	lzma_options_lzma options;
+} lzma_lzma2_coder;
+
+
+static lzma_ret
+lzma2_decode(void *coder_ptr, lzma_dict *restrict dict,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size)
+{
+	lzma_lzma2_coder *restrict coder = coder_ptr;
+
+	// With SEQ_LZMA it is possible that no new input is needed to do
+	// some progress. The rest of the sequences assume that there is
+	// at least one byte of input.
+	while (*in_pos < in_size || coder->sequence == SEQ_LZMA)
+	switch (coder->sequence) {
+	case SEQ_CONTROL: {
+		const uint32_t control = in[*in_pos];
+		++*in_pos;
+
+		// End marker
+		if (control == 0x00)
+			return LZMA_STREAM_END;
+
+		if (control >= 0xE0 || control == 1) {
+			// Dictionary reset implies that next LZMA chunk has
+			// to set new properties.
+			coder->need_properties = true;
+			coder->need_dictionary_reset = true;
+		} else if (coder->need_dictionary_reset) {
+			return LZMA_DATA_ERROR;
+		}
+
+		if (control >= 0x80) {
+			// LZMA chunk. The highest five bits of the
+			// uncompressed size are taken from the control byte.
+			coder->uncompressed_size = (control & 0x1F) << 16;
+			coder->sequence = SEQ_UNCOMPRESSED_1;
+
+			// See if there are new properties or if we need to
+			// reset the state.
+			if (control >= 0xC0) {
+				// When there are new properties, state reset
+				// is done at SEQ_PROPERTIES.
+				coder->need_properties = false;
+				coder->next_sequence = SEQ_PROPERTIES;
+
+			} else if (coder->need_properties) {
+				return LZMA_DATA_ERROR;
+
+			} else {
+				coder->next_sequence = SEQ_LZMA;
+
+				// If only state reset is wanted with old
+				// properties, do the resetting here for
+				// simplicity.
+				if (control >= 0xA0)
+					coder->lzma.reset(coder->lzma.coder,
+							&coder->options);
+			}
+		} else {
+			// Invalid control values
+			if (control > 2)
+				return LZMA_DATA_ERROR;
+
+			// It's uncompressed chunk
+			coder->sequence = SEQ_COMPRESSED_0;
+			coder->next_sequence = SEQ_COPY;
+		}
+
+		if (coder->need_dictionary_reset) {
+			// Finish the dictionary reset and let the caller
+			// flush the dictionary to the actual output buffer.
+			coder->need_dictionary_reset = false;
+			dict_reset(dict);
+			return LZMA_OK;
+		}
+
+		break;
+	}
+
+	case SEQ_UNCOMPRESSED_1:
+		coder->uncompressed_size += (uint32_t)(in[(*in_pos)++]) << 8;
+		coder->sequence = SEQ_UNCOMPRESSED_2;
+		break;
+
+	case SEQ_UNCOMPRESSED_2:
+		coder->uncompressed_size += in[(*in_pos)++] + 1U;
+		coder->sequence = SEQ_COMPRESSED_0;
+		coder->lzma.set_uncompressed(coder->lzma.coder,
+				coder->uncompressed_size, false);
+		break;
+
+	case SEQ_COMPRESSED_0:
+		coder->compressed_size = (uint32_t)(in[(*in_pos)++]) << 8;
+		coder->sequence = SEQ_COMPRESSED_1;
+		break;
+
+	case SEQ_COMPRESSED_1:
+		coder->compressed_size += in[(*in_pos)++] + 1U;
+		coder->sequence = coder->next_sequence;
+		break;
+
+	case SEQ_PROPERTIES:
+		if (lzma_lzma_lclppb_decode(&coder->options, in[(*in_pos)++]))
+			return LZMA_DATA_ERROR;
+
+		coder->lzma.reset(coder->lzma.coder, &coder->options);
+
+		coder->sequence = SEQ_LZMA;
+		break;
+
+	case SEQ_LZMA: {
+		// Store the start offset so that we can update
+		// coder->compressed_size later.
+		const size_t in_start = *in_pos;
+
+		// Decode from in[] to *dict.
+		const lzma_ret ret = coder->lzma.code(coder->lzma.coder,
+				dict, in, in_pos, in_size);
+
+		// Validate and update coder->compressed_size.
+		const size_t in_used = *in_pos - in_start;
+		if (in_used > coder->compressed_size)
+			return LZMA_DATA_ERROR;
+
+		coder->compressed_size -= in_used;
+
+		// Return if we didn't finish the chunk, or an error occurred.
+		if (ret != LZMA_STREAM_END)
+			return ret;
+
+		// The LZMA decoder must have consumed the whole chunk now.
+		// We don't need to worry about uncompressed size since it
+		// is checked by the LZMA decoder.
+		if (coder->compressed_size != 0)
+			return LZMA_DATA_ERROR;
+
+		coder->sequence = SEQ_CONTROL;
+		break;
+	}
+
+	case SEQ_COPY: {
+		// Copy from input to the dictionary as is.
+		dict_write(dict, in, in_pos, in_size, &coder->compressed_size);
+		if (coder->compressed_size != 0)
+			return LZMA_OK;
+
+		coder->sequence = SEQ_CONTROL;
+		break;
+	}
+
+	default:
+		assert(0);
+		return LZMA_PROG_ERROR;
+	}
+
+	return LZMA_OK;
+}
+
+
+static void
+lzma2_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_lzma2_coder *coder = coder_ptr;
+
+	assert(coder->lzma.end == NULL);
+	lzma_free(coder->lzma.coder, allocator);
+
+	lzma_free(coder, allocator);
+
+	return;
+}
+
+
+static lzma_ret
+lzma2_decoder_init(lzma_lz_decoder *lz, const lzma_allocator *allocator,
+		lzma_vli id lzma_attribute((__unused__)), const void *opt,
+		lzma_lz_options *lz_options)
+{
+	lzma_lzma2_coder *coder = lz->coder;
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_lzma2_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		lz->coder = coder;
+		lz->code = &lzma2_decode;
+		lz->end = &lzma2_decoder_end;
+
+		coder->lzma = LZMA_LZ_DECODER_INIT;
+	}
+
+	const lzma_options_lzma *options = opt;
+
+	coder->sequence = SEQ_CONTROL;
+	coder->need_properties = true;
+	coder->need_dictionary_reset = options->preset_dict == NULL
+			|| options->preset_dict_size == 0;
+
+	return lzma_lzma_decoder_create(&coder->lzma,
+			allocator, options, lz_options);
+}
+
+
+extern lzma_ret
+lzma_lzma2_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	// LZMA2 can only be the last filter in the chain. This is enforced
+	// by the raw_decoder initialization.
+	assert(filters[1].init == NULL);
+
+	return lzma_lz_decoder_init(next, allocator, filters,
+			&lzma2_decoder_init);
+}
+
+
+extern uint64_t
+lzma_lzma2_decoder_memusage(const void *options)
+{
+	return sizeof(lzma_lzma2_coder)
+			+ lzma_lzma_decoder_memusage_nocheck(options);
+}
+
+
+extern lzma_ret
+lzma_lzma2_props_decode(void **options, const lzma_allocator *allocator,
+		const uint8_t *props, size_t props_size)
+{
+	if (props_size != 1)
+		return LZMA_OPTIONS_ERROR;
+
+	// Check that reserved bits are unset.
+	if (props[0] & 0xC0)
+		return LZMA_OPTIONS_ERROR;
+
+	// Decode the dictionary size.
+	if (props[0] > 40)
+		return LZMA_OPTIONS_ERROR;
+
+	lzma_options_lzma *opt = lzma_alloc(
+			sizeof(lzma_options_lzma), allocator);
+	if (opt == NULL)
+		return LZMA_MEM_ERROR;
+
+	if (props[0] == 40) {
+		opt->dict_size = UINT32_MAX;
+	} else {
+		opt->dict_size = 2 | (props[0] & 1U);
+		opt->dict_size <<= props[0] / 2U + 11;
+	}
+
+	opt->preset_dict = NULL;
+	opt->preset_dict_size = 0;
+
+	*options = opt;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.h
new file mode 100644
index 00000000000..cdd8b463abf
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_decoder.h
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lzma2_decoder.h
+/// \brief      LZMA2 decoder
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZMA2_DECODER_H
+#define LZMA_LZMA2_DECODER_H
+
+#include "common.h"
+
+extern lzma_ret lzma_lzma2_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+extern uint64_t lzma_lzma2_decoder_memusage(const void *options);
+
+extern lzma_ret lzma_lzma2_props_decode(
+		void **options, const lzma_allocator *allocator,
+		const uint8_t *props, size_t props_size);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.c
new file mode 100644
index 00000000000..e20b75b3003
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.c
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lzma2_encoder.c
+/// \brief      LZMA2 encoder
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lz_encoder.h"
+#include "lzma_encoder.h"
+#include "fastpos.h"
+#include "lzma2_encoder.h"
+
+
+typedef struct {
+	enum {
+		SEQ_INIT,
+		SEQ_LZMA_ENCODE,
+		SEQ_LZMA_COPY,
+		SEQ_UNCOMPRESSED_HEADER,
+		SEQ_UNCOMPRESSED_COPY,
+	} sequence;
+
+	/// LZMA encoder
+	void *lzma;
+
+	/// LZMA options currently in use.
+	lzma_options_lzma opt_cur;
+
+	bool need_properties;
+	bool need_state_reset;
+	bool need_dictionary_reset;
+
+	/// Uncompressed size of a chunk
+	size_t uncompressed_size;
+
+	/// Compressed size of a chunk (excluding headers); this is also used
+	/// to indicate the end of buf[] in SEQ_LZMA_COPY.
+	size_t compressed_size;
+
+	/// Read position in buf[]
+	size_t buf_pos;
+
+	/// Buffer to hold the chunk header and LZMA compressed data
+	uint8_t buf[LZMA2_HEADER_MAX + LZMA2_CHUNK_MAX];
+} lzma_lzma2_coder;
+
+
+static void
+lzma2_header_lzma(lzma_lzma2_coder *coder)
+{
+	assert(coder->uncompressed_size > 0);
+	assert(coder->uncompressed_size <= LZMA2_UNCOMPRESSED_MAX);
+	assert(coder->compressed_size > 0);
+	assert(coder->compressed_size <= LZMA2_CHUNK_MAX);
+
+	size_t pos;
+
+	if (coder->need_properties) {
+		pos = 0;
+
+		if (coder->need_dictionary_reset)
+			coder->buf[pos] = 0x80 + (3 << 5);
+		else
+			coder->buf[pos] = 0x80 + (2 << 5);
+	} else {
+		pos = 1;
+
+		if (coder->need_state_reset)
+			coder->buf[pos] = 0x80 + (1 << 5);
+		else
+			coder->buf[pos] = 0x80;
+	}
+
+	// Set the start position for copying.
+	coder->buf_pos = pos;
+
+	// Uncompressed size
+	size_t size = coder->uncompressed_size - 1;
+	coder->buf[pos++] += size >> 16;
+	coder->buf[pos++] = (size >> 8) & 0xFF;
+	coder->buf[pos++] = size & 0xFF;
+
+	// Compressed size
+	size = coder->compressed_size - 1;
+	coder->buf[pos++] = size >> 8;
+	coder->buf[pos++] = size & 0xFF;
+
+	// Properties, if needed
+	if (coder->need_properties)
+		lzma_lzma_lclppb_encode(&coder->opt_cur, coder->buf + pos);
+
+	coder->need_properties = false;
+	coder->need_state_reset = false;
+	coder->need_dictionary_reset = false;
+
+	// The copying code uses coder->compressed_size to indicate the end
+	// of coder->buf[], so we need add the maximum size of the header here.
+	coder->compressed_size += LZMA2_HEADER_MAX;
+
+	return;
+}
+
+
+static void
+lzma2_header_uncompressed(lzma_lzma2_coder *coder)
+{
+	assert(coder->uncompressed_size > 0);
+	assert(coder->uncompressed_size <= LZMA2_CHUNK_MAX);
+
+	// If this is the first chunk, we need to include dictionary
+	// reset indicator.
+	if (coder->need_dictionary_reset)
+		coder->buf[0] = 1;
+	else
+		coder->buf[0] = 2;
+
+	coder->need_dictionary_reset = false;
+
+	// "Compressed" size
+	coder->buf[1] = (coder->uncompressed_size - 1) >> 8;
+	coder->buf[2] = (coder->uncompressed_size - 1) & 0xFF;
+
+	// Set the start position for copying.
+	coder->buf_pos = 0;
+	return;
+}
+
+
+static lzma_ret
+lzma2_encode(void *coder_ptr, lzma_mf *restrict mf,
+		uint8_t *restrict out, size_t *restrict out_pos,
+		size_t out_size)
+{
+	lzma_lzma2_coder *restrict coder = coder_ptr;
+
+	while (*out_pos < out_size)
+	switch (coder->sequence) {
+	case SEQ_INIT:
+		// If there's no input left and we are flushing or finishing,
+		// don't start a new chunk.
+		if (mf_unencoded(mf) == 0) {
+			// Write end of payload marker if finishing.
+			if (mf->action == LZMA_FINISH)
+				out[(*out_pos)++] = 0;
+
+			return mf->action == LZMA_RUN
+					? LZMA_OK : LZMA_STREAM_END;
+		}
+
+		if (coder->need_state_reset)
+			return_if_error(lzma_lzma_encoder_reset(
+					coder->lzma, &coder->opt_cur));
+
+		coder->uncompressed_size = 0;
+		coder->compressed_size = 0;
+		coder->sequence = SEQ_LZMA_ENCODE;
+
+	// Fall through
+
+	case SEQ_LZMA_ENCODE: {
+		// Calculate how much more uncompressed data this chunk
+		// could accept.
+		const uint32_t left = LZMA2_UNCOMPRESSED_MAX
+				- coder->uncompressed_size;
+		uint32_t limit;
+
+		if (left < mf->match_len_max) {
+			// Must flush immediately since the next LZMA symbol
+			// could make the uncompressed size of the chunk too
+			// big.
+			limit = 0;
+		} else {
+			// Calculate maximum read_limit that is OK from point
+			// of view of LZMA2 chunk size.
+			limit = mf->read_pos - mf->read_ahead
+					+ left - mf->match_len_max;
+		}
+
+		// Save the start position so that we can update
+		// coder->uncompressed_size.
+		const uint32_t read_start = mf->read_pos - mf->read_ahead;
+
+		// Call the LZMA encoder until the chunk is finished.
+		const lzma_ret ret = lzma_lzma_encode(coder->lzma, mf,
+				coder->buf + LZMA2_HEADER_MAX,
+				&coder->compressed_size,
+				LZMA2_CHUNK_MAX, limit);
+
+		coder->uncompressed_size += mf->read_pos - mf->read_ahead
+				- read_start;
+
+		assert(coder->compressed_size <= LZMA2_CHUNK_MAX);
+		assert(coder->uncompressed_size <= LZMA2_UNCOMPRESSED_MAX);
+
+		if (ret != LZMA_STREAM_END)
+			return LZMA_OK;
+
+		// See if the chunk compressed. If it didn't, we encode it
+		// as uncompressed chunk. This saves a few bytes of space
+		// and makes decoding faster.
+		if (coder->compressed_size >= coder->uncompressed_size) {
+			coder->uncompressed_size += mf->read_ahead;
+			assert(coder->uncompressed_size
+					<= LZMA2_UNCOMPRESSED_MAX);
+			mf->read_ahead = 0;
+			lzma2_header_uncompressed(coder);
+			coder->need_state_reset = true;
+			coder->sequence = SEQ_UNCOMPRESSED_HEADER;
+			break;
+		}
+
+		// The chunk did compress at least by one byte, so we store
+		// the chunk as LZMA.
+		lzma2_header_lzma(coder);
+
+		coder->sequence = SEQ_LZMA_COPY;
+	}
+
+	// Fall through
+
+	case SEQ_LZMA_COPY:
+		// Copy the compressed chunk along its headers to the
+		// output buffer.
+		lzma_bufcpy(coder->buf, &coder->buf_pos,
+				coder->compressed_size,
+				out, out_pos, out_size);
+		if (coder->buf_pos != coder->compressed_size)
+			return LZMA_OK;
+
+		coder->sequence = SEQ_INIT;
+		break;
+
+	case SEQ_UNCOMPRESSED_HEADER:
+		// Copy the three-byte header to indicate uncompressed chunk.
+		lzma_bufcpy(coder->buf, &coder->buf_pos,
+				LZMA2_HEADER_UNCOMPRESSED,
+				out, out_pos, out_size);
+		if (coder->buf_pos != LZMA2_HEADER_UNCOMPRESSED)
+			return LZMA_OK;
+
+		coder->sequence = SEQ_UNCOMPRESSED_COPY;
+
+	// Fall through
+
+	case SEQ_UNCOMPRESSED_COPY:
+		// Copy the uncompressed data as is from the dictionary
+		// to the output buffer.
+		mf_read(mf, out, out_pos, out_size, &coder->uncompressed_size);
+		if (coder->uncompressed_size != 0)
+			return LZMA_OK;
+
+		coder->sequence = SEQ_INIT;
+		break;
+	}
+
+	return LZMA_OK;
+}
+
+
+static void
+lzma2_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_lzma2_coder *coder = coder_ptr;
+	lzma_free(coder->lzma, allocator);
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_ret
+lzma2_encoder_options_update(void *coder_ptr, const lzma_filter *filter)
+{
+	lzma_lzma2_coder *coder = coder_ptr;
+
+	// New options can be set only when there is no incomplete chunk.
+	// This is the case at the beginning of the raw stream and right
+	// after LZMA_SYNC_FLUSH.
+	if (filter->options == NULL || coder->sequence != SEQ_INIT)
+		return LZMA_PROG_ERROR;
+
+	// Look if there are new options. At least for now,
+	// only lc/lp/pb can be changed.
+	const lzma_options_lzma *opt = filter->options;
+	if (coder->opt_cur.lc != opt->lc || coder->opt_cur.lp != opt->lp
+			|| coder->opt_cur.pb != opt->pb) {
+		// Validate the options.
+		if (opt->lc > LZMA_LCLP_MAX || opt->lp > LZMA_LCLP_MAX
+				|| opt->lc + opt->lp > LZMA_LCLP_MAX
+				|| opt->pb > LZMA_PB_MAX)
+			return LZMA_OPTIONS_ERROR;
+
+		// The new options will be used when the encoder starts
+		// a new LZMA2 chunk.
+		coder->opt_cur.lc = opt->lc;
+		coder->opt_cur.lp = opt->lp;
+		coder->opt_cur.pb = opt->pb;
+		coder->need_properties = true;
+		coder->need_state_reset = true;
+	}
+
+	return LZMA_OK;
+}
+
+
+static lzma_ret
+lzma2_encoder_init(lzma_lz_encoder *lz, const lzma_allocator *allocator,
+		lzma_vli id lzma_attribute((__unused__)), const void *options,
+		lzma_lz_options *lz_options)
+{
+	if (options == NULL)
+		return LZMA_PROG_ERROR;
+
+	lzma_lzma2_coder *coder = lz->coder;
+	if (coder == NULL) {
+		coder = lzma_alloc(sizeof(lzma_lzma2_coder), allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		lz->coder = coder;
+		lz->code = &lzma2_encode;
+		lz->end = &lzma2_encoder_end;
+		lz->options_update = &lzma2_encoder_options_update;
+
+		coder->lzma = NULL;
+	}
+
+	coder->opt_cur = *(const lzma_options_lzma *)(options);
+
+	coder->sequence = SEQ_INIT;
+	coder->need_properties = true;
+	coder->need_state_reset = false;
+	coder->need_dictionary_reset
+			= coder->opt_cur.preset_dict == NULL
+			|| coder->opt_cur.preset_dict_size == 0;
+
+	// Initialize LZMA encoder
+	return_if_error(lzma_lzma_encoder_create(&coder->lzma, allocator,
+			LZMA_FILTER_LZMA2, &coder->opt_cur, lz_options));
+
+	// Make sure that we will always have enough history available in
+	// case we need to use uncompressed chunks. They are used when the
+	// compressed size of a chunk is not smaller than the uncompressed
+	// size, so we need to have at least LZMA2_COMPRESSED_MAX bytes
+	// history available.
+	if (lz_options->before_size + lz_options->dict_size < LZMA2_CHUNK_MAX)
+		lz_options->before_size
+				= LZMA2_CHUNK_MAX - lz_options->dict_size;
+
+	return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_lzma2_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return lzma_lz_encoder_init(
+			next, allocator, filters, &lzma2_encoder_init);
+}
+
+
+extern uint64_t
+lzma_lzma2_encoder_memusage(const void *options)
+{
+	const uint64_t lzma_mem = lzma_lzma_encoder_memusage(options);
+	if (lzma_mem == UINT64_MAX)
+		return UINT64_MAX;
+
+	return sizeof(lzma_lzma2_coder) + lzma_mem;
+}
+
+
+extern lzma_ret
+lzma_lzma2_props_encode(const void *options, uint8_t *out)
+{
+	if (options == NULL)
+		return LZMA_PROG_ERROR;
+
+	const lzma_options_lzma *const opt = options;
+	uint32_t d = my_max(opt->dict_size, LZMA_DICT_SIZE_MIN);
+
+	// Round up to the next 2^n - 1 or 2^n + 2^(n - 1) - 1 depending
+	// on which one is the next:
+	--d;
+	d |= d >> 2;
+	d |= d >> 3;
+	d |= d >> 4;
+	d |= d >> 8;
+	d |= d >> 16;
+
+	// Get the highest two bits using the proper encoding:
+	if (d == UINT32_MAX)
+		out[0] = 40;
+	else
+		out[0] = get_dist_slot(d + 1) - 24;
+
+	return LZMA_OK;
+}
+
+
+extern uint64_t
+lzma_lzma2_block_size(const void *options)
+{
+	const lzma_options_lzma *const opt = options;
+
+	if (!IS_ENC_DICT_SIZE_VALID(opt->dict_size))
+		return UINT64_MAX;
+
+	// Use at least 1 MiB to keep compression ratio better.
+	return my_max((uint64_t)(opt->dict_size) * 3, UINT64_C(1) << 20);
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.h
new file mode 100644
index 00000000000..29966a66d23
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma2_encoder.h
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lzma2_encoder.h
+/// \brief      LZMA2 encoder
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZMA2_ENCODER_H
+#define LZMA_LZMA2_ENCODER_H
+
+#include "common.h"
+
+
+/// Maximum number of bytes of actual data per chunk (no headers)
+#define LZMA2_CHUNK_MAX (UINT32_C(1) << 16)
+
+/// Maximum uncompressed size of LZMA chunk (no headers)
+#define LZMA2_UNCOMPRESSED_MAX (UINT32_C(1) << 21)
+
+/// Maximum size of LZMA2 headers
+#define LZMA2_HEADER_MAX 6
+
+/// Size of a header for uncompressed chunk
+#define LZMA2_HEADER_UNCOMPRESSED 3
+
+
+extern lzma_ret lzma_lzma2_encoder_init(
+		lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+extern uint64_t lzma_lzma2_encoder_memusage(const void *options);
+
+extern lzma_ret lzma_lzma2_props_encode(const void *options, uint8_t *out);
+
+extern uint64_t lzma_lzma2_block_size(const void *options);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_common.h
new file mode 100644
index 00000000000..c3c587f090e
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_common.h
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lzma_common.h
+/// \brief      Private definitions common to LZMA encoder and decoder
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZMA_COMMON_H
+#define LZMA_LZMA_COMMON_H
+
+#include "common.h"
+#include "range_common.h"
+
+
+///////////////////
+// Miscellaneous //
+///////////////////
+
+/// Maximum number of position states. A position state is the lowest pos bits
+/// number of bits of the current uncompressed offset. In some places there
+/// are different sets of probabilities for different pos states.
+#define POS_STATES_MAX (1 << LZMA_PB_MAX)
+
+
+/// Validates lc, lp, and pb.
+static inline bool
+is_lclppb_valid(const lzma_options_lzma *options)
+{
+	return options->lc <= LZMA_LCLP_MAX && options->lp <= LZMA_LCLP_MAX
+			&& options->lc + options->lp <= LZMA_LCLP_MAX
+			&& options->pb <= LZMA_PB_MAX;
+}
+
+
+///////////
+// State //
+///////////
+
+/// This enum is used to track which events have occurred most recently and
+/// in which order. This information is used to predict the next event.
+///
+/// Events:
+///  - Literal: One 8-bit byte
+///  - Match: Repeat a chunk of data at some distance
+///  - Long repeat: Multi-byte match at a recently seen distance
+///  - Short repeat: One-byte repeat at a recently seen distance
+///
+/// The event names are in from STATE_oldest_older_previous. REP means
+/// either short or long repeated match, and NONLIT means any non-literal.
+typedef enum {
+	STATE_LIT_LIT,
+	STATE_MATCH_LIT_LIT,
+	STATE_REP_LIT_LIT,
+	STATE_SHORTREP_LIT_LIT,
+	STATE_MATCH_LIT,
+	STATE_REP_LIT,
+	STATE_SHORTREP_LIT,
+	STATE_LIT_MATCH,
+	STATE_LIT_LONGREP,
+	STATE_LIT_SHORTREP,
+	STATE_NONLIT_MATCH,
+	STATE_NONLIT_REP,
+} lzma_lzma_state;
+
+
+/// Total number of states
+#define STATES 12
+
+/// The lowest 7 states indicate that the previous state was a literal.
+#define LIT_STATES 7
+
+
+/// Indicate that the latest state was a literal.
+#define update_literal(state) \
+	state = ((state) <= STATE_SHORTREP_LIT_LIT \
+			? STATE_LIT_LIT \
+			: ((state) <= STATE_LIT_SHORTREP \
+				? (state) - 3 \
+				: (state) - 6))
+
+/// Like update_literal(state) but when it is already known that
+/// is_literal_state(state) is true.
+#define update_literal_normal(state) \
+	state = ((state) <= STATE_SHORTREP_LIT_LIT \
+			? STATE_LIT_LIT \
+			: (state) - 3);
+
+/// Like update_literal(state) but when it is already known that
+/// is_literal_state(state) is false.
+#define update_literal_matched(state) \
+	state = ((state) <= STATE_LIT_SHORTREP \
+			? (state) - 3 \
+			: (state) - 6);
+
+/// Indicate that the latest state was a match.
+#define update_match(state) \
+	state = ((state) < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH)
+
+/// Indicate that the latest state was a long repeated match.
+#define update_long_rep(state) \
+	state = ((state) < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP)
+
+/// Indicate that the latest state was a short match.
+#define update_short_rep(state) \
+	state = ((state) < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP)
+
+/// Test if the previous state was a literal.
+#define is_literal_state(state) \
+	((state) < LIT_STATES)
+
+
+/////////////
+// Literal //
+/////////////
+
+/// Each literal coder is divided in three sections:
+///   - 0x001-0x0FF: Without match byte
+///   - 0x101-0x1FF: With match byte; match bit is 0
+///   - 0x201-0x2FF: With match byte; match bit is 1
+///
+/// Match byte is used when the previous LZMA symbol was something else than
+/// a literal (that is, it was some kind of match).
+#define LITERAL_CODER_SIZE UINT32_C(0x300)
+
+/// Maximum number of literal coders
+#define LITERAL_CODERS_MAX (1 << LZMA_LCLP_MAX)
+
+/// Calculates the literal_mask that literal_subcoder() needs.
+#define literal_mask_calc(lc, lp) \
+	((UINT32_C(0x100) << (lp)) - (UINT32_C(0x100) >> (lc)))
+
+/// Locate the literal coder for the next literal byte. The choice depends on
+///   - the lowest literal_pos_bits bits of the position of the current
+///     byte; and
+///   - the highest literal_context_bits bits of the previous byte.
+#define literal_subcoder(probs, lc, literal_mask, pos, prev_byte) \
+	((probs) + UINT32_C(3) * \
+		(((((pos) << 8) + (prev_byte)) & (literal_mask)) << (lc)))
+
+
+static inline void
+literal_init(probability *probs, uint32_t lc, uint32_t lp)
+{
+	assert(lc + lp <= LZMA_LCLP_MAX);
+
+	const size_t coders = LITERAL_CODER_SIZE << (lc + lp);
+
+	for (size_t i = 0; i < coders; ++i)
+		bit_reset(probs[i]);
+
+	return;
+}
+
+
+//////////////////
+// Match length //
+//////////////////
+
+// Minimum length of a match is two bytes.
+#define MATCH_LEN_MIN 2
+
+// Match length is encoded with 4, 5, or 10 bits.
+//
+// Length   Bits
+//  2-9      4 = Choice=0 + 3 bits
+// 10-17     5 = Choice=1 + Choice2=0 + 3 bits
+// 18-273   10 = Choice=1 + Choice2=1 + 8 bits
+#define LEN_LOW_BITS 3
+#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
+#define LEN_MID_BITS 3
+#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
+#define LEN_HIGH_BITS 8
+#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
+#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
+
+// Maximum length of a match is 273 which is a result of the encoding
+// described above.
+#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1)
+
+
+////////////////////
+// Match distance //
+////////////////////
+
+// Different sets of probabilities are used for match distances that have very
+// short match length: Lengths of 2, 3, and 4 bytes have a separate set of
+// probabilities for each length. The matches with longer length use a shared
+// set of probabilities.
+#define DIST_STATES 4
+
+// Macro to get the index of the appropriate probability array.
+#define get_dist_state(len) \
+	((len) < DIST_STATES + MATCH_LEN_MIN \
+		? (len) - MATCH_LEN_MIN \
+		: DIST_STATES - 1)
+
+// The highest two bits of a match distance (distance slot) are encoded
+// using six bits. See fastpos.h for more explanation.
+#define DIST_SLOT_BITS 6
+#define DIST_SLOTS (1 << DIST_SLOT_BITS)
+
+// Match distances up to 127 are fully encoded using probabilities. Since
+// the highest two bits (distance slot) are always encoded using six bits,
+// the distances 0-3 don't need any additional bits to encode, since the
+// distance slot itself is the same as the actual distance. DIST_MODEL_START
+// indicates the first distance slot where at least one additional bit is
+// needed.
+#define DIST_MODEL_START 4
+
+// Match distances greater than 127 are encoded in three pieces:
+//   - distance slot: the highest two bits
+//   - direct bits: 2-26 bits below the highest two bits
+//   - alignment bits: four lowest bits
+//
+// Direct bits don't use any probabilities.
+//
+// The distance slot value of 14 is for distances 128-191 (see the table in
+// fastpos.h to understand why).
+#define DIST_MODEL_END 14
+
+// Distance slots that indicate a distance <= 127.
+#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2)
+#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
+
+// For match distances greater than 127, only the highest two bits and the
+// lowest four bits (alignment) is encoded using probabilities.
+#define ALIGN_BITS 4
+#define ALIGN_SIZE (1 << ALIGN_BITS)
+#define ALIGN_MASK (ALIGN_SIZE - 1)
+
+// LZMA remembers the four most recent match distances. Reusing these distances
+// tends to take less space than re-encoding the actual distance value.
+#define REPS 4
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.c
new file mode 100644
index 00000000000..0abed02b815
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.c
@@ -0,0 +1,1263 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lzma_decoder.c
+/// \brief      LZMA decoder
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//              Jia Tan
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lz_decoder.h"
+#include "lzma_common.h"
+#include "lzma_decoder.h"
+#include "range_decoder.h"
+
+// The macros unroll loops with switch statements.
+// Silence warnings about missing fall-through comments.
+#if TUKLIB_GNUC_REQ(7, 0)
+#	pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+#endif
+
+// Minimum number of input bytes to safely decode one LZMA symbol.
+// The worst case is that we decode 22 bits using probabilities and 26
+// direct bits. This may decode at maximum 20 bytes of input.
+#define LZMA_IN_REQUIRED 20
+
+
+// Macros for (somewhat) size-optimized code.
+// This is used to decode the match length (how many bytes must be repeated
+// from the dictionary). This version is used in the Resumable mode and
+// does not unroll any loops.
+#define len_decode(target, ld, pos_state, seq) \
+do { \
+case seq ## _CHOICE: \
+	rc_if_0_safe(ld.choice, seq ## _CHOICE) { \
+		rc_update_0(ld.choice); \
+		probs = ld.low[pos_state];\
+		limit = LEN_LOW_SYMBOLS; \
+		target = MATCH_LEN_MIN; \
+	} else { \
+		rc_update_1(ld.choice); \
+case seq ## _CHOICE2: \
+		rc_if_0_safe(ld.choice2, seq ## _CHOICE2) { \
+			rc_update_0(ld.choice2); \
+			probs = ld.mid[pos_state]; \
+			limit = LEN_MID_SYMBOLS; \
+			target = MATCH_LEN_MIN + LEN_LOW_SYMBOLS; \
+		} else { \
+			rc_update_1(ld.choice2); \
+			probs = ld.high; \
+			limit = LEN_HIGH_SYMBOLS; \
+			target = MATCH_LEN_MIN + LEN_LOW_SYMBOLS \
+					+ LEN_MID_SYMBOLS; \
+		} \
+	} \
+	symbol = 1; \
+case seq ## _BITTREE: \
+	do { \
+		rc_bit_safe(probs[symbol], , , seq ## _BITTREE); \
+	} while (symbol < limit); \
+	target += symbol - limit; \
+} while (0)
+
+
+// This is the faster version of the match length decoder that does not
+// worry about being resumable. It unrolls the bittree decoding loop.
+#define len_decode_fast(target, ld, pos_state) \
+do { \
+	symbol = 1; \
+	rc_if_0(ld.choice) { \
+		rc_update_0(ld.choice); \
+		rc_bittree3(ld.low[pos_state], \
+				-LEN_LOW_SYMBOLS + MATCH_LEN_MIN); \
+		target = symbol; \
+	} else { \
+		rc_update_1(ld.choice); \
+		rc_if_0(ld.choice2) { \
+			rc_update_0(ld.choice2); \
+			rc_bittree3(ld.mid[pos_state], -LEN_MID_SYMBOLS \
+					+ MATCH_LEN_MIN + LEN_LOW_SYMBOLS); \
+			target = symbol; \
+		} else { \
+			rc_update_1(ld.choice2); \
+			rc_bittree8(ld.high, -LEN_HIGH_SYMBOLS \
+					+ MATCH_LEN_MIN \
+					+ LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS); \
+			target = symbol; \
+		} \
+	} \
+} while (0)
+
+
+/// Length decoder probabilities; see comments in lzma_common.h.
+typedef struct {
+	probability choice;
+	probability choice2;
+	probability low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
+	probability mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
+	probability high[LEN_HIGH_SYMBOLS];
+} lzma_length_decoder;
+
+
+typedef struct {
+	///////////////////
+	// Probabilities //
+	///////////////////
+
+	/// Literals; see comments in lzma_common.h.
+	probability literal[LITERAL_CODERS_MAX * LITERAL_CODER_SIZE];
+
+	/// If 1, it's a match. Otherwise it's a single 8-bit literal.
+	probability is_match[STATES][POS_STATES_MAX];
+
+	/// If 1, it's a repeated match. The distance is one of rep0 .. rep3.
+	probability is_rep[STATES];
+
+	/// If 0, distance of a repeated match is rep0.
+	/// Otherwise check is_rep1.
+	probability is_rep0[STATES];
+
+	/// If 0, distance of a repeated match is rep1.
+	/// Otherwise check is_rep2.
+	probability is_rep1[STATES];
+
+	/// If 0, distance of a repeated match is rep2. Otherwise it is rep3.
+	probability is_rep2[STATES];
+
+	/// If 1, the repeated match has length of one byte. Otherwise
+	/// the length is decoded from rep_len_decoder.
+	probability is_rep0_long[STATES][POS_STATES_MAX];
+
+	/// Probability tree for the highest two bits of the match distance.
+	/// There is a separate probability tree for match lengths of
+	/// 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273].
+	probability dist_slot[DIST_STATES][DIST_SLOTS];
+
+	/// Probability trees for additional bits for match distance when the
+	/// distance is in the range [4, 127].
+	probability pos_special[FULL_DISTANCES - DIST_MODEL_END];
+
+	/// Probability tree for the lowest four bits of a match distance
+	/// that is equal to or greater than 128.
+	probability pos_align[ALIGN_SIZE];
+
+	/// Length of a normal match
+	lzma_length_decoder match_len_decoder;
+
+	/// Length of a repeated match
+	lzma_length_decoder rep_len_decoder;
+
+	///////////////////
+	// Decoder state //
+	///////////////////
+
+	// Range coder
+	lzma_range_decoder rc;
+
+	// Types of the most recently seen LZMA symbols
+	lzma_lzma_state state;
+
+	uint32_t rep0;      ///< Distance of the latest match
+	uint32_t rep1;      ///< Distance of second latest match
+	uint32_t rep2;      ///< Distance of third latest match
+	uint32_t rep3;      ///< Distance of fourth latest match
+
+	uint32_t pos_mask; // (1U << pb) - 1
+	uint32_t literal_context_bits;
+	uint32_t literal_mask;
+
+	/// Uncompressed size as bytes, or LZMA_VLI_UNKNOWN if end of
+	/// payload marker is expected.
+	lzma_vli uncompressed_size;
+
+	/// True if end of payload marker (EOPM) is allowed even when
+	/// uncompressed_size is known; false if EOPM must not be present.
+	/// This is ignored if uncompressed_size == LZMA_VLI_UNKNOWN.
+	bool allow_eopm;
+
+	////////////////////////////////
+	// State of incomplete symbol //
+	////////////////////////////////
+
+	/// Position where to continue the decoder loop
+	enum {
+		SEQ_NORMALIZE,
+		SEQ_IS_MATCH,
+		SEQ_LITERAL,
+		SEQ_LITERAL_MATCHED,
+		SEQ_LITERAL_WRITE,
+		SEQ_IS_REP,
+		SEQ_MATCH_LEN_CHOICE,
+		SEQ_MATCH_LEN_CHOICE2,
+		SEQ_MATCH_LEN_BITTREE,
+		SEQ_DIST_SLOT,
+		SEQ_DIST_MODEL,
+		SEQ_DIRECT,
+		SEQ_ALIGN,
+		SEQ_EOPM,
+		SEQ_IS_REP0,
+		SEQ_SHORTREP,
+		SEQ_IS_REP0_LONG,
+		SEQ_IS_REP1,
+		SEQ_IS_REP2,
+		SEQ_REP_LEN_CHOICE,
+		SEQ_REP_LEN_CHOICE2,
+		SEQ_REP_LEN_BITTREE,
+		SEQ_COPY,
+	} sequence;
+
+	/// Base of the current probability tree
+	probability *probs;
+
+	/// Symbol being decoded. This is also used as an index variable in
+	/// bittree decoders: probs[symbol]
+	uint32_t symbol;
+
+	/// Used as a loop termination condition on bittree decoders and
+	/// direct bits decoder.
+	uint32_t limit;
+
+	/// Matched literal decoder: 0x100 or 0 to help avoiding branches.
+	/// Bittree reverse decoders: Offset of the next bit: 1 << offset
+	uint32_t offset;
+
+	/// If decoding a literal: match byte.
+	/// If decoding a match: length of the match.
+	uint32_t len;
+} lzma_lzma1_decoder;
+
+
+static lzma_ret
+lzma_decode(void *coder_ptr, lzma_dict *restrict dictptr,
+		const uint8_t *restrict in,
+		size_t *restrict in_pos, size_t in_size)
+{
+	lzma_lzma1_decoder *restrict coder = coder_ptr;
+
+	////////////////////
+	// Initialization //
+	////////////////////
+
+	{
+		const lzma_ret ret = rc_read_init(
+				&coder->rc, in, in_pos, in_size);
+		if (ret != LZMA_STREAM_END)
+			return ret;
+	}
+
+	///////////////
+	// Variables //
+	///////////////
+
+	// Making local copies of often-used variables improves both
+	// speed and readability.
+
+	lzma_dict dict = *dictptr;
+
+	const size_t dict_start = dict.pos;
+
+	// Range decoder
+	rc_to_local(coder->rc, *in_pos, LZMA_IN_REQUIRED);
+
+	// State
+	uint32_t state = coder->state;
+	uint32_t rep0 = coder->rep0;
+	uint32_t rep1 = coder->rep1;
+	uint32_t rep2 = coder->rep2;
+	uint32_t rep3 = coder->rep3;
+
+	const uint32_t pos_mask = coder->pos_mask;
+
+	// These variables are actually needed only if we last time ran
+	// out of input in the middle of the decoder loop.
+	probability *probs = coder->probs;
+	uint32_t symbol = coder->symbol;
+	uint32_t limit = coder->limit;
+	uint32_t offset = coder->offset;
+	uint32_t len = coder->len;
+
+	const uint32_t literal_mask = coder->literal_mask;
+	const uint32_t literal_context_bits = coder->literal_context_bits;
+
+	// Temporary variables
+	uint32_t pos_state = dict.pos & pos_mask;
+
+	lzma_ret ret = LZMA_OK;
+
+	// This is true when the next LZMA symbol is allowed to be EOPM.
+	// That is, if this is false, then EOPM is considered
+	// an invalid symbol and we will return LZMA_DATA_ERROR.
+	//
+	// EOPM is always required (not just allowed) when
+	// the uncompressed size isn't known. When uncompressed size
+	// is known, eopm_is_valid may be set to true later.
+	bool eopm_is_valid = coder->uncompressed_size == LZMA_VLI_UNKNOWN;
+
+	// If uncompressed size is known and there is enough output space
+	// to decode all the data, limit the available buffer space so that
+	// the main loop won't try to decode past the end of the stream.
+	bool might_finish_without_eopm = false;
+	if (coder->uncompressed_size != LZMA_VLI_UNKNOWN
+			&& coder->uncompressed_size <= dict.limit - dict.pos) {
+		dict.limit = dict.pos + (size_t)(coder->uncompressed_size);
+		might_finish_without_eopm = true;
+	}
+
+	// The main decoder loop. The "switch" is used to resume the decoder at
+	// correct location. Once resumed, the "switch" is no longer used.
+	// The decoder loops is split into two modes:
+	//
+	// 1 - Non-resumable mode (fast). This is used when it is guaranteed
+	//     there is enough input to decode the next symbol. If the output
+	//     limit is reached, then the decoder loop will save the place
+	//     for the resumable mode to continue. This mode is not used if
+	//     HAVE_SMALL is defined. This is faster than Resumable mode
+	//     because it reduces the number of branches needed and allows
+	//     for more compiler optimizations.
+	//
+	// 2 - Resumable mode (slow). This is used when a previous decoder
+	//     loop did not have enough space in the input or output buffers
+	//     to complete. It uses sequence enum values to set remind
+	//     coder->sequence where to resume in the decoder loop. This
+	//     is the only mode used when HAVE_SMALL is defined.
+
+	switch (coder->sequence)
+	while (true) {
+		// Calculate new pos_state. This is skipped on the first loop
+		// since we already calculated it when setting up the local
+		// variables.
+		pos_state = dict.pos & pos_mask;
+
+#ifndef HAVE_SMALL
+
+		///////////////////////////////
+		// Non-resumable Mode (fast) //
+		///////////////////////////////
+
+		// Go to Resumable mode (1) if there is not enough input to
+		// safely decode any possible LZMA symbol or (2) if the
+		// dictionary is full, which may need special checks that
+		// are only done in the Resumable mode.
+		if (unlikely(!rc_is_fast_allowed()
+				|| dict.pos == dict.limit))
+			goto slow;
+
+		// Decode the first bit from the next LZMA symbol.
+		// If the bit is a 0, then we handle it as a literal.
+		// If the bit is a 1, then it is a match of previously
+		// decoded data.
+		rc_if_0(coder->is_match[state][pos_state]) {
+			/////////////////////
+			// Decode literal. //
+			/////////////////////
+
+			// Update the RC that we have decoded a 0.
+			rc_update_0(coder->is_match[state][pos_state]);
+
+			// Get the correct probability array from lp and
+			// lc params.
+			probs = literal_subcoder(coder->literal,
+					literal_context_bits, literal_mask,
+					dict.pos, dict_get0(&dict));
+
+			if (is_literal_state(state)) {
+				update_literal_normal(state);
+
+				// Decode literal without match byte.
+				rc_bittree8(probs, 0);
+			} else {
+				update_literal_matched(state);
+
+				// Decode literal with match byte.
+				rc_matched_literal(probs,
+						dict_get(&dict, rep0));
+			}
+
+			// Write decoded literal to dictionary
+			dict_put(&dict, symbol);
+			continue;
+		}
+
+		///////////////////
+		// Decode match. //
+		///////////////////
+
+		// Instead of a new byte we are going to decode a
+		// distance-length pair. The distance represents how far
+		// back in the dictionary to begin copying. The length
+		// represents how many bytes to copy.
+
+		rc_update_1(coder->is_match[state][pos_state]);
+
+		rc_if_0(coder->is_rep[state]) {
+			///////////////////
+			// Simple match. //
+			///////////////////
+
+			// Not a repeated match. In this case,
+			// the length (how many bytes to copy) must be
+			// decoded first. Then, the distance (where to
+			// start copying) is decoded.
+			//
+			// This is also how we know when we are done
+			// decoding. If the distance decodes to UINT32_MAX,
+			// then we know to stop decoding (end of payload
+			// marker).
+
+			rc_update_0(coder->is_rep[state]);
+			update_match(state);
+
+			// The latest three match distances are kept in
+			// memory in case there are repeated matches.
+			rep3 = rep2;
+			rep2 = rep1;
+			rep1 = rep0;
+
+			// Decode the length of the match.
+			len_decode_fast(len, coder->match_len_decoder,
+					pos_state);
+
+			// Next, decode the distance into rep0.
+
+			// The next 6 bits determine how to decode the
+			// rest of the distance.
+			probs = coder->dist_slot[get_dist_state(len)];
+
+			rc_bittree6(probs, -DIST_SLOTS);
+			assert(symbol <= 63);
+
+			if (symbol < DIST_MODEL_START) {
+				// If the decoded symbol is < DIST_MODEL_START
+				// then we use its value directly as the
+				// match distance. No other bits are needed.
+				// The only possible distance values
+				// are [0, 3].
+				rep0 = symbol;
+			} else {
+				// Use the first two bits of symbol as the
+				// highest bits of the match distance.
+
+				// "limit" represents the number of low bits
+				// to decode.
+				limit = (symbol >> 1) - 1;
+				assert(limit >= 1 && limit <= 30);
+				rep0 = 2 + (symbol & 1);
+
+				if (symbol < DIST_MODEL_END) {
+					// When symbol is > DIST_MODEL_START,
+					// but symbol < DIST_MODEL_END, then
+					// it can decode distances between
+					// [4, 127].
+					assert(limit <= 5);
+					rep0 <<= limit;
+					assert(rep0 <= 96);
+
+					// -1 is fine, because we start
+					// decoding at probs[1], not probs[0].
+					// NOTE: This violates the C standard,
+					// since we are doing pointer
+					// arithmetic past the beginning of
+					// the array.
+					assert((int32_t)(rep0 - symbol - 1)
+							>= -1);
+					assert((int32_t)(rep0 - symbol - 1)
+							<= 82);
+					probs = coder->pos_special + rep0
+							- symbol - 1;
+					symbol = 1;
+					offset = 1;
+
+					// Variable number (1-5) of bits
+					// from a reverse bittree. This
+					// isn't worth manual unrolling.
+					//
+					// NOTE: Making one or many of the
+					// variables (probs, symbol, offset,
+					// or limit) local here (instead of
+					// using those declared outside the
+					// main loop) can affect code size
+					// and performance which isn't a
+					// surprise but it's not so clear
+					// what is the best.
+					do {
+						rc_bit_add_if_1(probs,
+								rep0, offset);
+						offset <<= 1;
+					} while (--limit > 0);
+				} else {
+					// The distance is >= 128. Decode the
+					// lower bits without probabilities
+					// except the lowest four bits.
+					assert(symbol >= 14);
+					assert(limit >= 6);
+
+					limit -= ALIGN_BITS;
+					assert(limit >= 2);
+
+					rc_direct(rep0, limit);
+
+					// Decode the lowest four bits using
+					// probabilities.
+					rep0 <<= ALIGN_BITS;
+					rc_bittree_rev4(coder->pos_align);
+					rep0 += symbol;
+
+					// If the end of payload marker (EOPM)
+					// is detected, jump to the safe code.
+					// The EOPM handling isn't speed
+					// critical at all.
+					//
+					// A final normalization is needed
+					// after the EOPM (there can be a
+					// dummy byte to read in some cases).
+					// If the normalization was done here
+					// in the fast code, it would need to
+					// be taken into account in the value
+					// of LZMA_IN_REQUIRED. Using the
+					// safe code allows keeping
+					// LZMA_IN_REQUIRED as 20 instead of
+					// 21.
+					if (rep0 == UINT32_MAX)
+						goto eopm;
+				}
+			}
+
+			// Validate the distance we just decoded.
+			if (unlikely(!dict_is_distance_valid(&dict, rep0))) {
+				ret = LZMA_DATA_ERROR;
+				goto out;
+			}
+
+		} else {
+			rc_update_1(coder->is_rep[state]);
+
+			/////////////////////
+			// Repeated match. //
+			/////////////////////
+
+			// The match distance is a value that we have decoded
+			// recently. The latest four match distances are
+			// available as rep0, rep1, rep2 and rep3. We will
+			// now decode which of them is the new distance.
+			//
+			// There cannot be a match if we haven't produced
+			// any output, so check that first.
+			if (unlikely(!dict_is_distance_valid(&dict, 0))) {
+				ret = LZMA_DATA_ERROR;
+				goto out;
+			}
+
+			rc_if_0(coder->is_rep0[state]) {
+				rc_update_0(coder->is_rep0[state]);
+				// The distance is rep0.
+
+				// Decode the next bit to determine if 1 byte
+				// should be copied from rep0 distance or
+				// if the number of bytes needs to be decoded.
+
+				// If the next bit is 0, then it is a
+				// "Short Rep Match" and only 1 bit is copied.
+				// Otherwise, the length of the match is
+				// decoded after the "else" statement.
+				rc_if_0(coder->is_rep0_long[state][pos_state]) {
+					rc_update_0(coder->is_rep0_long[
+							state][pos_state]);
+
+					update_short_rep(state);
+					dict_put(&dict, dict_get(&dict, rep0));
+					continue;
+				}
+
+				// Repeating more than one byte at
+				// distance of rep0.
+				rc_update_1(coder->is_rep0_long[
+						state][pos_state]);
+
+			} else {
+				rc_update_1(coder->is_rep0[state]);
+
+				// The distance is rep1, rep2 or rep3. Once
+				// we find out which one of these three, it
+				// is stored to rep0 and rep1, rep2 and rep3
+				// are updated accordingly. There is no
+				// "Short Rep Match" option, so the length
+				// of the match must always be decoded next.
+				rc_if_0(coder->is_rep1[state]) {
+					// The distance is rep1.
+					rc_update_0(coder->is_rep1[state]);
+
+					const uint32_t distance = rep1;
+					rep1 = rep0;
+					rep0 = distance;
+
+				} else {
+					rc_update_1(coder->is_rep1[state]);
+
+					rc_if_0(coder->is_rep2[state]) {
+						// The distance is rep2.
+						rc_update_0(coder->is_rep2[
+								state]);
+
+						const uint32_t distance = rep2;
+						rep2 = rep1;
+						rep1 = rep0;
+						rep0 = distance;
+
+					} else {
+						// The distance is rep3.
+						rc_update_1(coder->is_rep2[
+								state]);
+
+						const uint32_t distance = rep3;
+						rep3 = rep2;
+						rep2 = rep1;
+						rep1 = rep0;
+						rep0 = distance;
+					}
+				}
+			}
+
+			update_long_rep(state);
+
+			// Decode the length of the repeated match.
+			len_decode_fast(len, coder->rep_len_decoder,
+					pos_state);
+		}
+
+		/////////////////////////////////
+		// Repeat from history buffer. //
+		/////////////////////////////////
+
+		// The length is always between these limits. There is no way
+		// to trigger the algorithm to set len outside this range.
+		assert(len >= MATCH_LEN_MIN);
+		assert(len <= MATCH_LEN_MAX);
+
+		// Repeat len bytes from distance of rep0.
+		if (unlikely(dict_repeat(&dict, rep0, &len))) {
+			coder->sequence = SEQ_COPY;
+			goto out;
+		}
+
+		continue;
+
+slow:
+#endif
+	///////////////////////////
+	// Resumable Mode (slow) //
+	///////////////////////////
+
+	// This is very similar to Non-resumable Mode, so most of the
+	// comments are not repeated. The main differences are:
+	// - case labels are used to resume at the correct location.
+	// - Loops are not unrolled.
+	// - Range coder macros take an extra sequence argument
+	//   so they can save to coder->sequence the location to
+	//   resume in case there is not enough input.
+	case SEQ_NORMALIZE:
+	case SEQ_IS_MATCH:
+		if (unlikely(might_finish_without_eopm
+				&& dict.pos == dict.limit)) {
+			// In rare cases there is a useless byte that needs
+			// to be read anyway.
+			rc_normalize_safe(SEQ_NORMALIZE);
+
+			// If the range decoder state is such that we can
+			// be at the end of the LZMA stream, then the
+			// decoding is finished.
+			if (rc_is_finished(rc)) {
+				ret = LZMA_STREAM_END;
+				goto out;
+			}
+
+			// If the caller hasn't allowed EOPM to be present
+			// together with known uncompressed size, then the
+			// LZMA stream is corrupt.
+			if (!coder->allow_eopm) {
+				ret = LZMA_DATA_ERROR;
+				goto out;
+			}
+
+			// Otherwise continue decoding with the expectation
+			// that the next LZMA symbol is EOPM.
+			eopm_is_valid = true;
+		}
+
+		rc_if_0_safe(coder->is_match[state][pos_state], SEQ_IS_MATCH) {
+			/////////////////////
+			// Decode literal. //
+			/////////////////////
+
+			rc_update_0(coder->is_match[state][pos_state]);
+
+			probs = literal_subcoder(coder->literal,
+					literal_context_bits, literal_mask,
+					dict.pos, dict_get0(&dict));
+			symbol = 1;
+
+			if (is_literal_state(state)) {
+				update_literal_normal(state);
+
+				// Decode literal without match byte.
+				// The "slow" version does not unroll
+				// the loop.
+	case SEQ_LITERAL:
+				do {
+					rc_bit_safe(probs[symbol], , ,
+							SEQ_LITERAL);
+				} while (symbol < (1 << 8));
+			} else {
+				update_literal_matched(state);
+
+				// Decode literal with match byte.
+				len = (uint32_t)(dict_get(&dict, rep0)) << 1;
+
+				offset = 0x100;
+
+	case SEQ_LITERAL_MATCHED:
+				do {
+					const uint32_t match_bit
+							= len & offset;
+					const uint32_t subcoder_index
+							= offset + match_bit
+							+ symbol;
+
+					rc_bit_safe(probs[subcoder_index],
+							offset &= ~match_bit,
+							offset &= match_bit,
+							SEQ_LITERAL_MATCHED);
+
+					// It seems to be faster to do this
+					// here instead of putting it to the
+					// beginning of the loop and then
+					// putting the "case" in the middle
+					// of the loop.
+					len <<= 1;
+
+				} while (symbol < (1 << 8));
+			}
+
+	case SEQ_LITERAL_WRITE:
+			if (dict_put_safe(&dict, symbol)) {
+				coder->sequence = SEQ_LITERAL_WRITE;
+				goto out;
+			}
+
+			continue;
+		}
+
+		///////////////////
+		// Decode match. //
+		///////////////////
+
+		rc_update_1(coder->is_match[state][pos_state]);
+
+	case SEQ_IS_REP:
+		rc_if_0_safe(coder->is_rep[state], SEQ_IS_REP) {
+			///////////////////
+			// Simple match. //
+			///////////////////
+
+			rc_update_0(coder->is_rep[state]);
+			update_match(state);
+
+			rep3 = rep2;
+			rep2 = rep1;
+			rep1 = rep0;
+
+			len_decode(len, coder->match_len_decoder,
+					pos_state, SEQ_MATCH_LEN);
+
+			probs = coder->dist_slot[get_dist_state(len)];
+			symbol = 1;
+
+	case SEQ_DIST_SLOT:
+			do {
+				rc_bit_safe(probs[symbol], , , SEQ_DIST_SLOT);
+			} while (symbol < DIST_SLOTS);
+
+			symbol -= DIST_SLOTS;
+			assert(symbol <= 63);
+
+			if (symbol < DIST_MODEL_START) {
+				rep0 = symbol;
+			} else {
+				limit = (symbol >> 1) - 1;
+				assert(limit >= 1 && limit <= 30);
+				rep0 = 2 + (symbol & 1);
+
+				if (symbol < DIST_MODEL_END) {
+					assert(limit <= 5);
+					rep0 <<= limit;
+					assert(rep0 <= 96);
+					// -1 is fine, because we start
+					// decoding at probs[1], not probs[0].
+					// NOTE: This violates the C standard,
+					// since we are doing pointer
+					// arithmetic past the beginning of
+					// the array.
+					assert((int32_t)(rep0 - symbol - 1)
+							>= -1);
+					assert((int32_t)(rep0 - symbol - 1)
+							<= 82);
+					probs = coder->pos_special + rep0
+							- symbol - 1;
+					symbol = 1;
+					offset = 0;
+	case SEQ_DIST_MODEL:
+					do {
+						rc_bit_safe(probs[symbol], ,
+							rep0 += 1U << offset,
+							SEQ_DIST_MODEL);
+					} while (++offset < limit);
+				} else {
+					assert(symbol >= 14);
+					assert(limit >= 6);
+					limit -= ALIGN_BITS;
+					assert(limit >= 2);
+	case SEQ_DIRECT:
+					rc_direct_safe(rep0, limit,
+							SEQ_DIRECT);
+
+					rep0 <<= ALIGN_BITS;
+					symbol = 0;
+					offset = 1;
+	case SEQ_ALIGN:
+					do {
+						rc_bit_last_safe(
+							coder->pos_align[
+								offset
+								+ symbol],
+							,
+							symbol += offset,
+							SEQ_ALIGN);
+						offset <<= 1;
+					} while (offset < ALIGN_SIZE);
+
+					rep0 += symbol;
+
+					if (rep0 == UINT32_MAX) {
+						// End of payload marker was
+						// found. It may only be
+						// present if
+						//   - uncompressed size is
+						//     unknown or
+						//   - after known uncompressed
+						//     size amount of bytes has
+						//     been decompressed and
+						//     caller has indicated
+						//     that EOPM might be used
+						//     (it's not allowed in
+						//     LZMA2).
+#ifndef HAVE_SMALL
+eopm:
+#endif
+						if (!eopm_is_valid) {
+							ret = LZMA_DATA_ERROR;
+							goto out;
+						}
+
+	case SEQ_EOPM:
+						// LZMA1 stream with
+						// end-of-payload marker.
+						rc_normalize_safe(SEQ_EOPM);
+						ret = rc_is_finished(rc)
+							? LZMA_STREAM_END
+							: LZMA_DATA_ERROR;
+						goto out;
+					}
+				}
+			}
+
+			if (unlikely(!dict_is_distance_valid(&dict, rep0))) {
+				ret = LZMA_DATA_ERROR;
+				goto out;
+			}
+
+		} else {
+			/////////////////////
+			// Repeated match. //
+			/////////////////////
+
+			rc_update_1(coder->is_rep[state]);
+
+			if (unlikely(!dict_is_distance_valid(&dict, 0))) {
+				ret = LZMA_DATA_ERROR;
+				goto out;
+			}
+
+	case SEQ_IS_REP0:
+			rc_if_0_safe(coder->is_rep0[state], SEQ_IS_REP0) {
+				rc_update_0(coder->is_rep0[state]);
+
+	case SEQ_IS_REP0_LONG:
+				rc_if_0_safe(coder->is_rep0_long
+						[state][pos_state],
+						SEQ_IS_REP0_LONG) {
+					rc_update_0(coder->is_rep0_long[
+							state][pos_state]);
+
+					update_short_rep(state);
+
+	case SEQ_SHORTREP:
+					if (dict_put_safe(&dict,
+							dict_get(&dict,
+							rep0))) {
+						coder->sequence = SEQ_SHORTREP;
+						goto out;
+					}
+
+					continue;
+				}
+
+				rc_update_1(coder->is_rep0_long[
+						state][pos_state]);
+
+			} else {
+				rc_update_1(coder->is_rep0[state]);
+
+	case SEQ_IS_REP1:
+				rc_if_0_safe(coder->is_rep1[state], SEQ_IS_REP1) {
+					rc_update_0(coder->is_rep1[state]);
+
+					const uint32_t distance = rep1;
+					rep1 = rep0;
+					rep0 = distance;
+
+				} else {
+					rc_update_1(coder->is_rep1[state]);
+	case SEQ_IS_REP2:
+					rc_if_0_safe(coder->is_rep2[state],
+							SEQ_IS_REP2) {
+						rc_update_0(coder->is_rep2[
+								state]);
+
+						const uint32_t distance = rep2;
+						rep2 = rep1;
+						rep1 = rep0;
+						rep0 = distance;
+
+					} else {
+						rc_update_1(coder->is_rep2[
+								state]);
+
+						const uint32_t distance = rep3;
+						rep3 = rep2;
+						rep2 = rep1;
+						rep1 = rep0;
+						rep0 = distance;
+					}
+				}
+			}
+
+			update_long_rep(state);
+
+			len_decode(len, coder->rep_len_decoder,
+					pos_state, SEQ_REP_LEN);
+		}
+
+		/////////////////////////////////
+		// Repeat from history buffer. //
+		/////////////////////////////////
+
+		assert(len >= MATCH_LEN_MIN);
+		assert(len <= MATCH_LEN_MAX);
+
+	case SEQ_COPY:
+		if (unlikely(dict_repeat(&dict, rep0, &len))) {
+			coder->sequence = SEQ_COPY;
+			goto out;
+		}
+	}
+
+out:
+	// Save state
+
+	// NOTE: Must not copy dict.limit.
+	dictptr->pos = dict.pos;
+	dictptr->full = dict.full;
+
+	rc_from_local(coder->rc, *in_pos);
+
+	coder->state = state;
+	coder->rep0 = rep0;
+	coder->rep1 = rep1;
+	coder->rep2 = rep2;
+	coder->rep3 = rep3;
+
+	coder->probs = probs;
+	coder->symbol = symbol;
+	coder->limit = limit;
+	coder->offset = offset;
+	coder->len = len;
+
+	// Update the remaining amount of uncompressed data if uncompressed
+	// size was known.
+	if (coder->uncompressed_size != LZMA_VLI_UNKNOWN) {
+		coder->uncompressed_size -= dict.pos - dict_start;
+
+		// If we have gotten all the output but the decoder wants
+		// to write more output, the file is corrupt. There are
+		// three SEQ values where output is produced.
+		if (coder->uncompressed_size == 0 && ret == LZMA_OK
+				&& (coder->sequence == SEQ_LITERAL_WRITE
+					|| coder->sequence == SEQ_SHORTREP
+					|| coder->sequence == SEQ_COPY))
+			ret = LZMA_DATA_ERROR;
+	}
+
+	if (ret == LZMA_STREAM_END) {
+		// Reset the range decoder so that it is ready to reinitialize
+		// for a new LZMA2 chunk.
+		rc_reset(coder->rc);
+		coder->sequence = SEQ_IS_MATCH;
+	}
+
+	return ret;
+}
+
+
+static void
+lzma_decoder_uncompressed(void *coder_ptr, lzma_vli uncompressed_size,
+		bool allow_eopm)
+{
+	lzma_lzma1_decoder *coder = coder_ptr;
+	coder->uncompressed_size = uncompressed_size;
+	coder->allow_eopm = allow_eopm;
+}
+
+
+static void
+lzma_decoder_reset(void *coder_ptr, const void *opt)
+{
+	lzma_lzma1_decoder *coder = coder_ptr;
+	const lzma_options_lzma *options = opt;
+
+	// NOTE: We assume that lc/lp/pb are valid since they were
+	// successfully decoded with lzma_lzma_decode_properties().
+
+	// Calculate pos_mask. We don't need pos_bits as is for anything.
+	coder->pos_mask = (1U << options->pb) - 1;
+
+	// Initialize the literal decoder.
+	literal_init(coder->literal, options->lc, options->lp);
+
+	coder->literal_context_bits = options->lc;
+	coder->literal_mask = literal_mask_calc(options->lc, options->lp);
+
+	// State
+	coder->state = STATE_LIT_LIT;
+	coder->rep0 = 0;
+	coder->rep1 = 0;
+	coder->rep2 = 0;
+	coder->rep3 = 0;
+	coder->pos_mask = (1U << options->pb) - 1;
+
+	// Range decoder
+	rc_reset(coder->rc);
+
+	// Bit and bittree decoders
+	for (uint32_t i = 0; i < STATES; ++i) {
+		for (uint32_t j = 0; j <= coder->pos_mask; ++j) {
+			bit_reset(coder->is_match[i][j]);
+			bit_reset(coder->is_rep0_long[i][j]);
+		}
+
+		bit_reset(coder->is_rep[i]);
+		bit_reset(coder->is_rep0[i]);
+		bit_reset(coder->is_rep1[i]);
+		bit_reset(coder->is_rep2[i]);
+	}
+
+	for (uint32_t i = 0; i < DIST_STATES; ++i)
+		bittree_reset(coder->dist_slot[i], DIST_SLOT_BITS);
+
+	for (uint32_t i = 0; i < FULL_DISTANCES - DIST_MODEL_END; ++i)
+		bit_reset(coder->pos_special[i]);
+
+	bittree_reset(coder->pos_align, ALIGN_BITS);
+
+	// Len decoders (also bit/bittree)
+	const uint32_t num_pos_states = 1U << options->pb;
+	bit_reset(coder->match_len_decoder.choice);
+	bit_reset(coder->match_len_decoder.choice2);
+	bit_reset(coder->rep_len_decoder.choice);
+	bit_reset(coder->rep_len_decoder.choice2);
+
+	for (uint32_t pos_state = 0; pos_state < num_pos_states; ++pos_state) {
+		bittree_reset(coder->match_len_decoder.low[pos_state],
+				LEN_LOW_BITS);
+		bittree_reset(coder->match_len_decoder.mid[pos_state],
+				LEN_MID_BITS);
+
+		bittree_reset(coder->rep_len_decoder.low[pos_state],
+				LEN_LOW_BITS);
+		bittree_reset(coder->rep_len_decoder.mid[pos_state],
+				LEN_MID_BITS);
+	}
+
+	bittree_reset(coder->match_len_decoder.high, LEN_HIGH_BITS);
+	bittree_reset(coder->rep_len_decoder.high, LEN_HIGH_BITS);
+
+	coder->sequence = SEQ_IS_MATCH;
+	coder->probs = NULL;
+	coder->symbol = 0;
+	coder->limit = 0;
+	coder->offset = 0;
+	coder->len = 0;
+
+	return;
+}
+
+
+extern lzma_ret
+lzma_lzma_decoder_create(lzma_lz_decoder *lz, const lzma_allocator *allocator,
+		const lzma_options_lzma *options, lzma_lz_options *lz_options)
+{
+	if (lz->coder == NULL) {
+		lz->coder = lzma_alloc(sizeof(lzma_lzma1_decoder), allocator);
+		if (lz->coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		lz->code = &lzma_decode;
+		lz->reset = &lzma_decoder_reset;
+		lz->set_uncompressed = &lzma_decoder_uncompressed;
+	}
+
+	// All dictionary sizes are OK here. LZ decoder will take care of
+	// the special cases.
+	lz_options->dict_size = options->dict_size;
+	lz_options->preset_dict = options->preset_dict;
+	lz_options->preset_dict_size = options->preset_dict_size;
+
+	return LZMA_OK;
+}
+
+
+/// Allocate and initialize LZMA decoder. This is used only via LZ
+/// initialization (lzma_lzma_decoder_init() passes function pointer to
+/// the LZ initialization).
+static lzma_ret
+lzma_decoder_init(lzma_lz_decoder *lz, const lzma_allocator *allocator,
+		lzma_vli id, const void *options, lzma_lz_options *lz_options)
+{
+	if (!is_lclppb_valid(options))
+		return LZMA_PROG_ERROR;
+
+	lzma_vli uncomp_size = LZMA_VLI_UNKNOWN;
+	bool allow_eopm = true;
+
+	if (id == LZMA_FILTER_LZMA1EXT) {
+		const lzma_options_lzma *opt = options;
+
+		// Only one flag is supported.
+		if (opt->ext_flags & ~LZMA_LZMA1EXT_ALLOW_EOPM)
+			return LZMA_OPTIONS_ERROR;
+
+		// FIXME? Using lzma_vli instead of uint64_t is weird because
+		// this has nothing to do with .xz headers and variable-length
+		// integer encoding. On the other hand, using LZMA_VLI_UNKNOWN
+		// instead of UINT64_MAX is clearer when unknown size is
+		// meant. A problem with using lzma_vli is that now we
+		// allow > LZMA_VLI_MAX which is fine in this file but
+		// it's still confusing. Note that alone_decoder.c also
+		// allows > LZMA_VLI_MAX when setting uncompressed size.
+		uncomp_size = opt->ext_size_low
+				+ ((uint64_t)(opt->ext_size_high) << 32);
+		allow_eopm = (opt->ext_flags & LZMA_LZMA1EXT_ALLOW_EOPM) != 0
+				|| uncomp_size == LZMA_VLI_UNKNOWN;
+	}
+
+	return_if_error(lzma_lzma_decoder_create(
+			lz, allocator, options, lz_options));
+
+	lzma_decoder_reset(lz->coder, options);
+	lzma_decoder_uncompressed(lz->coder, uncomp_size, allow_eopm);
+
+	return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_lzma_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	// LZMA can only be the last filter in the chain. This is enforced
+	// by the raw_decoder initialization.
+	assert(filters[1].init == NULL);
+
+	return lzma_lz_decoder_init(next, allocator, filters,
+			&lzma_decoder_init);
+}
+
+
+extern bool
+lzma_lzma_lclppb_decode(lzma_options_lzma *options, uint8_t byte)
+{
+	if (byte > (4 * 5 + 4) * 9 + 8)
+		return true;
+
+	// See the file format specification to understand this.
+	options->pb = byte / (9 * 5);
+	byte -= options->pb * 9 * 5;
+	options->lp = byte / 9;
+	options->lc = byte - options->lp * 9;
+
+	return options->lc + options->lp > LZMA_LCLP_MAX;
+}
+
+
+extern uint64_t
+lzma_lzma_decoder_memusage_nocheck(const void *options)
+{
+	const lzma_options_lzma *const opt = options;
+	return sizeof(lzma_lzma1_decoder)
+			+ lzma_lz_decoder_memusage(opt->dict_size);
+}
+
+
+extern uint64_t
+lzma_lzma_decoder_memusage(const void *options)
+{
+	if (!is_lclppb_valid(options))
+		return UINT64_MAX;
+
+	return lzma_lzma_decoder_memusage_nocheck(options);
+}
+
+
+extern lzma_ret
+lzma_lzma_props_decode(void **options, const lzma_allocator *allocator,
+		const uint8_t *props, size_t props_size)
+{
+	if (props_size != 5)
+		return LZMA_OPTIONS_ERROR;
+
+	lzma_options_lzma *opt
+			= lzma_alloc(sizeof(lzma_options_lzma), allocator);
+	if (opt == NULL)
+		return LZMA_MEM_ERROR;
+
+	if (lzma_lzma_lclppb_decode(opt, props[0]))
+		goto error;
+
+	// All dictionary sizes are accepted, including zero. LZ decoder
+	// will automatically use a dictionary at least a few KiB even if
+	// a smaller dictionary is requested.
+	opt->dict_size = read32le(props + 1);
+
+	opt->preset_dict = NULL;
+	opt->preset_dict_size = 0;
+
+	*options = opt;
+
+	return LZMA_OK;
+
+error:
+	lzma_free(opt, allocator);
+	return LZMA_OPTIONS_ERROR;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.h
new file mode 100644
index 00000000000..9730f56fc26
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_decoder.h
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lzma_decoder.h
+/// \brief      LZMA decoder API
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZMA_DECODER_H
+#define LZMA_LZMA_DECODER_H
+
+#include "common.h"
+
+
+/// Allocates and initializes LZMA decoder
+extern lzma_ret lzma_lzma_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+extern uint64_t lzma_lzma_decoder_memusage(const void *options);
+
+extern lzma_ret lzma_lzma_props_decode(
+		void **options, const lzma_allocator *allocator,
+		const uint8_t *props, size_t props_size);
+
+
+/// \brief      Decodes the LZMA Properties byte (lc/lp/pb)
+///
+/// \return     true if error occurred, false on success
+///
+extern bool lzma_lzma_lclppb_decode(
+		lzma_options_lzma *options, uint8_t byte);
+
+
+#ifdef LZMA_LZ_DECODER_H
+/// Allocate and setup function pointers only. This is used by LZMA1 and
+/// LZMA2 decoders.
+extern lzma_ret lzma_lzma_decoder_create(
+		lzma_lz_decoder *lz, const lzma_allocator *allocator,
+		const lzma_options_lzma *opt, lzma_lz_options *lz_options);
+
+/// Gets memory usage without validating lc/lp/pb. This is used by LZMA2
+/// decoder, because raw LZMA2 decoding doesn't need lc/lp/pb.
+extern uint64_t lzma_lzma_decoder_memusage_nocheck(const void *options);
+
+#endif
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.c
new file mode 100644
index 00000000000..543ca321c3c
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.c
@@ -0,0 +1,786 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lzma_encoder.c
+/// \brief      LZMA encoder
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lzma2_encoder.h"
+#include "lzma_encoder_private.h"
+#include "fastpos.h"
+
+
+/////////////
+// Literal //
+/////////////
+
+static inline void
+literal_matched(lzma_range_encoder *rc, probability *subcoder,
+		uint32_t match_byte, uint32_t symbol)
+{
+	uint32_t offset = 0x100;
+	symbol += UINT32_C(1) << 8;
+
+	do {
+		match_byte <<= 1;
+		const uint32_t match_bit = match_byte & offset;
+		const uint32_t subcoder_index
+				= offset + match_bit + (symbol >> 8);
+		const uint32_t bit = (symbol >> 7) & 1;
+		rc_bit(rc, &subcoder[subcoder_index], bit);
+
+		symbol <<= 1;
+		offset &= ~(match_byte ^ symbol);
+
+	} while (symbol < (UINT32_C(1) << 16));
+}
+
+
+static inline void
+literal(lzma_lzma1_encoder *coder, lzma_mf *mf, uint32_t position)
+{
+	// Locate the literal byte to be encoded and the subcoder.
+	const uint8_t cur_byte = mf->buffer[
+			mf->read_pos - mf->read_ahead];
+	probability *subcoder = literal_subcoder(coder->literal,
+			coder->literal_context_bits, coder->literal_mask,
+			position, mf->buffer[mf->read_pos - mf->read_ahead - 1]);
+
+	if (is_literal_state(coder->state)) {
+		// Previous LZMA-symbol was a literal. Encode a normal
+		// literal without a match byte.
+		update_literal_normal(coder->state);
+		rc_bittree(&coder->rc, subcoder, 8, cur_byte);
+	} else {
+		// Previous LZMA-symbol was a match. Use the last byte of
+		// the match as a "match byte". That is, compare the bits
+		// of the current literal and the match byte.
+		update_literal_matched(coder->state);
+		const uint8_t match_byte = mf->buffer[
+				mf->read_pos - coder->reps[0] - 1
+				- mf->read_ahead];
+		literal_matched(&coder->rc, subcoder, match_byte, cur_byte);
+	}
+}
+
+
+//////////////////
+// Match length //
+//////////////////
+
+static void
+length_update_prices(lzma_length_encoder *lc, const uint32_t pos_state)
+{
+	const uint32_t table_size = lc->table_size;
+	lc->counters[pos_state] = table_size;
+
+	const uint32_t a0 = rc_bit_0_price(lc->choice);
+	const uint32_t a1 = rc_bit_1_price(lc->choice);
+	const uint32_t b0 = a1 + rc_bit_0_price(lc->choice2);
+	const uint32_t b1 = a1 + rc_bit_1_price(lc->choice2);
+	uint32_t *const prices = lc->prices[pos_state];
+
+	uint32_t i;
+	for (i = 0; i < table_size && i < LEN_LOW_SYMBOLS; ++i)
+		prices[i] = a0 + rc_bittree_price(lc->low[pos_state],
+				LEN_LOW_BITS, i);
+
+	for (; i < table_size && i < LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS; ++i)
+		prices[i] = b0 + rc_bittree_price(lc->mid[pos_state],
+				LEN_MID_BITS, i - LEN_LOW_SYMBOLS);
+
+	for (; i < table_size; ++i)
+		prices[i] = b1 + rc_bittree_price(lc->high, LEN_HIGH_BITS,
+				i - LEN_LOW_SYMBOLS - LEN_MID_SYMBOLS);
+
+	return;
+}
+
+
+static inline void
+length(lzma_range_encoder *rc, lzma_length_encoder *lc,
+		const uint32_t pos_state, uint32_t len, const bool fast_mode)
+{
+	assert(len <= MATCH_LEN_MAX);
+	len -= MATCH_LEN_MIN;
+
+	if (len < LEN_LOW_SYMBOLS) {
+		rc_bit(rc, &lc->choice, 0);
+		rc_bittree(rc, lc->low[pos_state], LEN_LOW_BITS, len);
+	} else {
+		rc_bit(rc, &lc->choice, 1);
+		len -= LEN_LOW_SYMBOLS;
+
+		if (len < LEN_MID_SYMBOLS) {
+			rc_bit(rc, &lc->choice2, 0);
+			rc_bittree(rc, lc->mid[pos_state], LEN_MID_BITS, len);
+		} else {
+			rc_bit(rc, &lc->choice2, 1);
+			len -= LEN_MID_SYMBOLS;
+			rc_bittree(rc, lc->high, LEN_HIGH_BITS, len);
+		}
+	}
+
+	// Only getoptimum uses the prices so don't update the table when
+	// in fast mode.
+	if (!fast_mode)
+		if (--lc->counters[pos_state] == 0)
+			length_update_prices(lc, pos_state);
+}
+
+
+///////////
+// Match //
+///////////
+
+static inline void
+match(lzma_lzma1_encoder *coder, const uint32_t pos_state,
+		const uint32_t distance, const uint32_t len)
+{
+	update_match(coder->state);
+
+	length(&coder->rc, &coder->match_len_encoder, pos_state, len,
+			coder->fast_mode);
+
+	const uint32_t dist_slot = get_dist_slot(distance);
+	const uint32_t dist_state = get_dist_state(len);
+	rc_bittree(&coder->rc, coder->dist_slot[dist_state],
+			DIST_SLOT_BITS, dist_slot);
+
+	if (dist_slot >= DIST_MODEL_START) {
+		const uint32_t footer_bits = (dist_slot >> 1) - 1;
+		const uint32_t base = (2 | (dist_slot & 1)) << footer_bits;
+		const uint32_t dist_reduced = distance - base;
+
+		if (dist_slot < DIST_MODEL_END) {
+			// Careful here: base - dist_slot - 1 can be -1, but
+			// rc_bittree_reverse starts at probs[1], not probs[0].
+			rc_bittree_reverse(&coder->rc,
+				coder->dist_special + base - dist_slot - 1,
+				footer_bits, dist_reduced);
+		} else {
+			rc_direct(&coder->rc, dist_reduced >> ALIGN_BITS,
+					footer_bits - ALIGN_BITS);
+			rc_bittree_reverse(
+					&coder->rc, coder->dist_align,
+					ALIGN_BITS, dist_reduced & ALIGN_MASK);
+			++coder->align_price_count;
+		}
+	}
+
+	coder->reps[3] = coder->reps[2];
+	coder->reps[2] = coder->reps[1];
+	coder->reps[1] = coder->reps[0];
+	coder->reps[0] = distance;
+	++coder->match_price_count;
+}
+
+
+////////////////////
+// Repeated match //
+////////////////////
+
+static inline void
+rep_match(lzma_lzma1_encoder *coder, const uint32_t pos_state,
+		const uint32_t rep, const uint32_t len)
+{
+	if (rep == 0) {
+		rc_bit(&coder->rc, &coder->is_rep0[coder->state], 0);
+		rc_bit(&coder->rc,
+				&coder->is_rep0_long[coder->state][pos_state],
+				len != 1);
+	} else {
+		const uint32_t distance = coder->reps[rep];
+		rc_bit(&coder->rc, &coder->is_rep0[coder->state], 1);
+
+		if (rep == 1) {
+			rc_bit(&coder->rc, &coder->is_rep1[coder->state], 0);
+		} else {
+			rc_bit(&coder->rc, &coder->is_rep1[coder->state], 1);
+			rc_bit(&coder->rc, &coder->is_rep2[coder->state],
+					rep - 2);
+
+			if (rep == 3)
+				coder->reps[3] = coder->reps[2];
+
+			coder->reps[2] = coder->reps[1];
+		}
+
+		coder->reps[1] = coder->reps[0];
+		coder->reps[0] = distance;
+	}
+
+	if (len == 1) {
+		update_short_rep(coder->state);
+	} else {
+		length(&coder->rc, &coder->rep_len_encoder, pos_state, len,
+				coder->fast_mode);
+		update_long_rep(coder->state);
+	}
+}
+
+
+//////////
+// Main //
+//////////
+
+static void
+encode_symbol(lzma_lzma1_encoder *coder, lzma_mf *mf,
+		uint32_t back, uint32_t len, uint32_t position)
+{
+	const uint32_t pos_state = position & coder->pos_mask;
+
+	if (back == UINT32_MAX) {
+		// Literal i.e. eight-bit byte
+		assert(len == 1);
+		rc_bit(&coder->rc,
+				&coder->is_match[coder->state][pos_state], 0);
+		literal(coder, mf, position);
+	} else {
+		// Some type of match
+		rc_bit(&coder->rc,
+			&coder->is_match[coder->state][pos_state], 1);
+
+		if (back < REPS) {
+			// It's a repeated match i.e. the same distance
+			// has been used earlier.
+			rc_bit(&coder->rc, &coder->is_rep[coder->state], 1);
+			rep_match(coder, pos_state, back, len);
+		} else {
+			// Normal match
+			rc_bit(&coder->rc, &coder->is_rep[coder->state], 0);
+			match(coder, pos_state, back - REPS, len);
+		}
+	}
+
+	assert(mf->read_ahead >= len);
+	mf->read_ahead -= len;
+}
+
+
+static bool
+encode_init(lzma_lzma1_encoder *coder, lzma_mf *mf)
+{
+	assert(mf_position(mf) == 0);
+	assert(coder->uncomp_size == 0);
+
+	if (mf->read_pos == mf->read_limit) {
+		if (mf->action == LZMA_RUN)
+			return false; // We cannot do anything.
+
+		// We are finishing (we cannot get here when flushing).
+		assert(mf->write_pos == mf->read_pos);
+		assert(mf->action == LZMA_FINISH);
+	} else {
+		// Do the actual initialization. The first LZMA symbol must
+		// always be a literal.
+		mf_skip(mf, 1);
+		mf->read_ahead = 0;
+		rc_bit(&coder->rc, &coder->is_match[0][0], 0);
+		rc_bittree(&coder->rc, coder->literal + 0, 8, mf->buffer[0]);
+		++coder->uncomp_size;
+	}
+
+	// Initialization is done (except if empty file).
+	coder->is_initialized = true;
+
+	return true;
+}
+
+
+static void
+encode_eopm(lzma_lzma1_encoder *coder, uint32_t position)
+{
+	const uint32_t pos_state = position & coder->pos_mask;
+	rc_bit(&coder->rc, &coder->is_match[coder->state][pos_state], 1);
+	rc_bit(&coder->rc, &coder->is_rep[coder->state], 0);
+	match(coder, pos_state, UINT32_MAX, MATCH_LEN_MIN);
+}
+
+
+/// Number of bytes that a single encoding loop in lzma_lzma_encode() can
+/// consume from the dictionary. This limit comes from lzma_lzma_optimum()
+/// and may need to be updated if that function is significantly modified.
+#define LOOP_INPUT_MAX (OPTS + 1)
+
+
+extern lzma_ret
+lzma_lzma_encode(lzma_lzma1_encoder *restrict coder, lzma_mf *restrict mf,
+		uint8_t *restrict out, size_t *restrict out_pos,
+		size_t out_size, uint32_t limit)
+{
+	// Initialize the stream if no data has been encoded yet.
+	if (!coder->is_initialized && !encode_init(coder, mf))
+		return LZMA_OK;
+
+	// Encode pending output bytes from the range encoder.
+	// At the start of the stream, encode_init() encodes one literal.
+	// Later there can be pending output only with LZMA1 because LZMA2
+	// ensures that there is always enough output space. Thus when using
+	// LZMA2, rc_encode() calls in this function will always return false.
+	if (rc_encode(&coder->rc, out, out_pos, out_size)) {
+		// We don't get here with LZMA2.
+		assert(limit == UINT32_MAX);
+		return LZMA_OK;
+	}
+
+	// If the range encoder was flushed in an earlier call to this
+	// function but there wasn't enough output buffer space, those
+	// bytes would have now been encoded by the above rc_encode() call
+	// and the stream has now been finished. This can only happen with
+	// LZMA1 as LZMA2 always provides enough output buffer space.
+	if (coder->is_flushed) {
+		assert(limit == UINT32_MAX);
+		return LZMA_STREAM_END;
+	}
+
+	while (true) {
+		// With LZMA2 we need to take care that compressed size of
+		// a chunk doesn't get too big.
+		// FIXME? Check if this could be improved.
+		if (limit != UINT32_MAX
+				&& (mf->read_pos - mf->read_ahead >= limit
+					|| *out_pos + rc_pending(&coder->rc)
+						>= LZMA2_CHUNK_MAX
+							- LOOP_INPUT_MAX))
+			break;
+
+		// Check that there is some input to process.
+		if (mf->read_pos >= mf->read_limit) {
+			if (mf->action == LZMA_RUN)
+				return LZMA_OK;
+
+			if (mf->read_ahead == 0)
+				break;
+		}
+
+		// Get optimal match (repeat position and length).
+		// Value ranges for pos:
+		//   - [0, REPS): repeated match
+		//   - [REPS, UINT32_MAX):
+		//     match at (pos - REPS)
+		//   - UINT32_MAX: not a match but a literal
+		// Value ranges for len:
+		//   - [MATCH_LEN_MIN, MATCH_LEN_MAX]
+		uint32_t len;
+		uint32_t back;
+
+		if (coder->fast_mode)
+			lzma_lzma_optimum_fast(coder, mf, &back, &len);
+		else
+			lzma_lzma_optimum_normal(coder, mf, &back, &len,
+					(uint32_t)(coder->uncomp_size));
+
+		encode_symbol(coder, mf, back, len,
+				(uint32_t)(coder->uncomp_size));
+
+		// If output size limiting is active (out_limit != 0), check
+		// if encoding this LZMA symbol would make the output size
+		// exceed the specified limit.
+		if (coder->out_limit != 0 && rc_encode_dummy(
+				&coder->rc, coder->out_limit)) {
+			// The most recent LZMA symbol would make the output
+			// too big. Throw it away.
+			rc_forget(&coder->rc);
+
+			// FIXME: Tell the LZ layer to not read more input as
+			// it would be waste of time. This doesn't matter if
+			// output-size-limited encoding is done with a single
+			// call though.
+
+			break;
+		}
+
+		// This symbol will be encoded so update the uncompressed size.
+		coder->uncomp_size += len;
+
+		// Encode the LZMA symbol.
+		if (rc_encode(&coder->rc, out, out_pos, out_size)) {
+			// Once again, this can only happen with LZMA1.
+			assert(limit == UINT32_MAX);
+			return LZMA_OK;
+		}
+	}
+
+	// Make the uncompressed size available to the application.
+	if (coder->uncomp_size_ptr != NULL)
+		*coder->uncomp_size_ptr = coder->uncomp_size;
+
+	// LZMA2 doesn't use EOPM at LZMA level.
+	//
+	// Plain LZMA streams without EOPM aren't supported except when
+	// output size limiting is enabled.
+	if (coder->use_eopm)
+		encode_eopm(coder, (uint32_t)(coder->uncomp_size));
+
+	// Flush the remaining bytes from the range encoder.
+	rc_flush(&coder->rc);
+
+	// Copy the remaining bytes to the output buffer. If there
+	// isn't enough output space, we will copy out the remaining
+	// bytes on the next call to this function.
+	if (rc_encode(&coder->rc, out, out_pos, out_size)) {
+		// This cannot happen with LZMA2.
+		assert(limit == UINT32_MAX);
+
+		coder->is_flushed = true;
+		return LZMA_OK;
+	}
+
+	return LZMA_STREAM_END;
+}
+
+
+static lzma_ret
+lzma_encode(void *coder, lzma_mf *restrict mf,
+		uint8_t *restrict out, size_t *restrict out_pos,
+		size_t out_size)
+{
+	// Plain LZMA has no support for sync-flushing.
+	if (unlikely(mf->action == LZMA_SYNC_FLUSH))
+		return LZMA_OPTIONS_ERROR;
+
+	return lzma_lzma_encode(coder, mf, out, out_pos, out_size, UINT32_MAX);
+}
+
+
+static lzma_ret
+lzma_lzma_set_out_limit(
+		void *coder_ptr, uint64_t *uncomp_size, uint64_t out_limit)
+{
+	// Minimum output size is 5 bytes but that cannot hold any output
+	// so we use 6 bytes.
+	if (out_limit < 6)
+		return LZMA_BUF_ERROR;
+
+	lzma_lzma1_encoder *coder = coder_ptr;
+	coder->out_limit = out_limit;
+	coder->uncomp_size_ptr = uncomp_size;
+	coder->use_eopm = false;
+	return LZMA_OK;
+}
+
+
+////////////////////
+// Initialization //
+////////////////////
+
+static bool
+is_options_valid(const lzma_options_lzma *options)
+{
+	// Validate some of the options. LZ encoder validates nice_len too
+	// but we need a valid value here earlier.
+	return is_lclppb_valid(options)
+			&& options->nice_len >= MATCH_LEN_MIN
+			&& options->nice_len <= MATCH_LEN_MAX
+			&& (options->mode == LZMA_MODE_FAST
+				|| options->mode == LZMA_MODE_NORMAL);
+}
+
+
+static void
+set_lz_options(lzma_lz_options *lz_options, const lzma_options_lzma *options)
+{
+	// LZ encoder initialization does the validation for these so we
+	// don't need to validate here.
+	lz_options->before_size = OPTS;
+	lz_options->dict_size = options->dict_size;
+	lz_options->after_size = LOOP_INPUT_MAX;
+	lz_options->match_len_max = MATCH_LEN_MAX;
+	lz_options->nice_len = my_max(mf_get_hash_bytes(options->mf),
+				options->nice_len);
+	lz_options->match_finder = options->mf;
+	lz_options->depth = options->depth;
+	lz_options->preset_dict = options->preset_dict;
+	lz_options->preset_dict_size = options->preset_dict_size;
+	return;
+}
+
+
+static void
+length_encoder_reset(lzma_length_encoder *lencoder,
+		const uint32_t num_pos_states, const bool fast_mode)
+{
+	bit_reset(lencoder->choice);
+	bit_reset(lencoder->choice2);
+
+	for (size_t pos_state = 0; pos_state < num_pos_states; ++pos_state) {
+		bittree_reset(lencoder->low[pos_state], LEN_LOW_BITS);
+		bittree_reset(lencoder->mid[pos_state], LEN_MID_BITS);
+	}
+
+	bittree_reset(lencoder->high, LEN_HIGH_BITS);
+
+	if (!fast_mode)
+		for (uint32_t pos_state = 0; pos_state < num_pos_states;
+				++pos_state)
+			length_update_prices(lencoder, pos_state);
+
+	return;
+}
+
+
+extern lzma_ret
+lzma_lzma_encoder_reset(lzma_lzma1_encoder *coder,
+		const lzma_options_lzma *options)
+{
+	if (!is_options_valid(options))
+		return LZMA_OPTIONS_ERROR;
+
+	coder->pos_mask = (1U << options->pb) - 1;
+	coder->literal_context_bits = options->lc;
+	coder->literal_mask = literal_mask_calc(options->lc, options->lp);
+
+	// Range coder
+	rc_reset(&coder->rc);
+
+	// State
+	coder->state = STATE_LIT_LIT;
+	for (size_t i = 0; i < REPS; ++i)
+		coder->reps[i] = 0;
+
+	literal_init(coder->literal, options->lc, options->lp);
+
+	// Bit encoders
+	for (size_t i = 0; i < STATES; ++i) {
+		for (size_t j = 0; j <= coder->pos_mask; ++j) {
+			bit_reset(coder->is_match[i][j]);
+			bit_reset(coder->is_rep0_long[i][j]);
+		}
+
+		bit_reset(coder->is_rep[i]);
+		bit_reset(coder->is_rep0[i]);
+		bit_reset(coder->is_rep1[i]);
+		bit_reset(coder->is_rep2[i]);
+	}
+
+	for (size_t i = 0; i < FULL_DISTANCES - DIST_MODEL_END; ++i)
+		bit_reset(coder->dist_special[i]);
+
+	// Bit tree encoders
+	for (size_t i = 0; i < DIST_STATES; ++i)
+		bittree_reset(coder->dist_slot[i], DIST_SLOT_BITS);
+
+	bittree_reset(coder->dist_align, ALIGN_BITS);
+
+	// Length encoders
+	length_encoder_reset(&coder->match_len_encoder,
+			1U << options->pb, coder->fast_mode);
+
+	length_encoder_reset(&coder->rep_len_encoder,
+			1U << options->pb, coder->fast_mode);
+
+	// Price counts are incremented every time appropriate probabilities
+	// are changed. price counts are set to zero when the price tables
+	// are updated, which is done when the appropriate price counts have
+	// big enough value, and lzma_mf.read_ahead == 0 which happens at
+	// least every OPTS (a few thousand) possible price count increments.
+	//
+	// By resetting price counts to UINT32_MAX / 2, we make sure that the
+	// price tables will be initialized before they will be used (since
+	// the value is definitely big enough), and that it is OK to increment
+	// price counts without risk of integer overflow (since UINT32_MAX / 2
+	// is small enough). The current code doesn't increment price counts
+	// before initializing price tables, but it maybe done in future if
+	// we add support for saving the state between LZMA2 chunks.
+	coder->match_price_count = UINT32_MAX / 2;
+	coder->align_price_count = UINT32_MAX / 2;
+
+	coder->opts_end_index = 0;
+	coder->opts_current_index = 0;
+
+	return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_lzma_encoder_create(void **coder_ptr, const lzma_allocator *allocator,
+		lzma_vli id, const lzma_options_lzma *options,
+		lzma_lz_options *lz_options)
+{
+	assert(id == LZMA_FILTER_LZMA1 || id == LZMA_FILTER_LZMA1EXT
+			|| id == LZMA_FILTER_LZMA2);
+
+	// Allocate lzma_lzma1_encoder if it wasn't already allocated.
+	if (*coder_ptr == NULL) {
+		*coder_ptr = lzma_alloc(sizeof(lzma_lzma1_encoder), allocator);
+		if (*coder_ptr == NULL)
+			return LZMA_MEM_ERROR;
+	}
+
+	lzma_lzma1_encoder *coder = *coder_ptr;
+
+	// Set compression mode. Note that we haven't validated the options
+	// yet. Invalid options will get rejected by lzma_lzma_encoder_reset()
+	// call at the end of this function.
+	switch (options->mode) {
+		case LZMA_MODE_FAST:
+			coder->fast_mode = true;
+			break;
+
+		case LZMA_MODE_NORMAL: {
+			coder->fast_mode = false;
+
+			// Set dist_table_size.
+			// Round the dictionary size up to next 2^n.
+			//
+			// Currently the maximum encoder dictionary size
+			// is 1.5 GiB due to lz_encoder.c and here we need
+			// to be below 2 GiB to make the rounded up value
+			// fit in an uint32_t and avoid an infinite while-loop
+			// (and undefined behavior due to a too large shift).
+			// So do the same check as in LZ encoder,
+			// limiting to 1.5 GiB.
+			if (options->dict_size > (UINT32_C(1) << 30)
+					+ (UINT32_C(1) << 29))
+				return LZMA_OPTIONS_ERROR;
+
+			uint32_t log_size = 0;
+			while ((UINT32_C(1) << log_size) < options->dict_size)
+				++log_size;
+
+			coder->dist_table_size = log_size * 2;
+
+			// Length encoders' price table size
+			const uint32_t nice_len = my_max(
+					mf_get_hash_bytes(options->mf),
+					options->nice_len);
+
+			coder->match_len_encoder.table_size
+					= nice_len + 1 - MATCH_LEN_MIN;
+			coder->rep_len_encoder.table_size
+					= nice_len + 1 - MATCH_LEN_MIN;
+			break;
+		}
+
+		default:
+			return LZMA_OPTIONS_ERROR;
+	}
+
+	// We don't need to write the first byte as literal if there is
+	// a non-empty preset dictionary. encode_init() wouldn't even work
+	// if there is a non-empty preset dictionary, because encode_init()
+	// assumes that position is zero and previous byte is also zero.
+	coder->is_initialized = options->preset_dict != NULL
+			&& options->preset_dict_size > 0;
+	coder->is_flushed = false;
+	coder->uncomp_size = 0;
+	coder->uncomp_size_ptr = NULL;
+
+	// Output size limiting is disabled by default.
+	coder->out_limit = 0;
+
+	// Determine if end marker is wanted:
+	//   - It is never used with LZMA2.
+	//   - It is always used with LZMA_FILTER_LZMA1 (unless
+	//     lzma_lzma_set_out_limit() is called later).
+	//   - LZMA_FILTER_LZMA1EXT has a flag for it in the options.
+	coder->use_eopm = (id == LZMA_FILTER_LZMA1);
+	if (id == LZMA_FILTER_LZMA1EXT) {
+		// Check if unsupported flags are present.
+		if (options->ext_flags & ~LZMA_LZMA1EXT_ALLOW_EOPM)
+			return LZMA_OPTIONS_ERROR;
+
+		coder->use_eopm = (options->ext_flags
+				& LZMA_LZMA1EXT_ALLOW_EOPM) != 0;
+
+		// TODO? As long as there are no filters that change the size
+		// of the data, it is enough to look at lzma_stream.total_in
+		// after encoding has been finished to know the uncompressed
+		// size of the LZMA1 stream. But in the future there could be
+		// filters that change the size of the data and then total_in
+		// doesn't work as the LZMA1 stream size might be different
+		// due to another filter in the chain. The problem is simple
+		// to solve: Add another flag to ext_flags and then set
+		// coder->uncomp_size_ptr to the address stored in
+		// lzma_options_lzma.reserved_ptr2 (or _ptr1).
+	}
+
+	set_lz_options(lz_options, options);
+
+	return lzma_lzma_encoder_reset(coder, options);
+}
+
+
+static lzma_ret
+lzma_encoder_init(lzma_lz_encoder *lz, const lzma_allocator *allocator,
+		lzma_vli id, const void *options, lzma_lz_options *lz_options)
+{
+        if (options == NULL)
+                return LZMA_PROG_ERROR;
+
+	lz->code = &lzma_encode;
+	lz->set_out_limit = &lzma_lzma_set_out_limit;
+	return lzma_lzma_encoder_create(
+			&lz->coder, allocator, id, options, lz_options);
+}
+
+
+extern lzma_ret
+lzma_lzma_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return lzma_lz_encoder_init(
+			next, allocator, filters, &lzma_encoder_init);
+}
+
+
+extern uint64_t
+lzma_lzma_encoder_memusage(const void *options)
+{
+	if (!is_options_valid(options))
+		return UINT64_MAX;
+
+	lzma_lz_options lz_options;
+	set_lz_options(&lz_options, options);
+
+	const uint64_t lz_memusage = lzma_lz_encoder_memusage(&lz_options);
+	if (lz_memusage == UINT64_MAX)
+		return UINT64_MAX;
+
+	return (uint64_t)(sizeof(lzma_lzma1_encoder)) + lz_memusage;
+}
+
+
+extern bool
+lzma_lzma_lclppb_encode(const lzma_options_lzma *options, uint8_t *byte)
+{
+	if (!is_lclppb_valid(options))
+		return true;
+
+	*byte = (options->pb * 5 + options->lp) * 9 + options->lc;
+	assert(*byte <= (4 * 5 + 4) * 9 + 8);
+
+	return false;
+}
+
+
+#ifdef HAVE_ENCODER_LZMA1
+extern lzma_ret
+lzma_lzma_props_encode(const void *options, uint8_t *out)
+{
+	if (options == NULL)
+		return LZMA_PROG_ERROR;
+
+	const lzma_options_lzma *const opt = options;
+
+	if (lzma_lzma_lclppb_encode(opt, out))
+		return LZMA_PROG_ERROR;
+
+	write32le(out + 1, opt->dict_size);
+
+	return LZMA_OK;
+}
+#endif
+
+
+extern LZMA_API(lzma_bool)
+lzma_mode_is_supported(lzma_mode mode)
+{
+	return mode == LZMA_MODE_FAST || mode == LZMA_MODE_NORMAL;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.h
new file mode 100644
index 00000000000..e8ae8079306
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder.h
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lzma_encoder.h
+/// \brief      LZMA encoder API
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZMA_ENCODER_H
+#define LZMA_LZMA_ENCODER_H
+
+#include "common.h"
+
+
+typedef struct lzma_lzma1_encoder_s lzma_lzma1_encoder;
+
+
+extern lzma_ret lzma_lzma_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+
+extern uint64_t lzma_lzma_encoder_memusage(const void *options);
+
+extern lzma_ret lzma_lzma_props_encode(const void *options, uint8_t *out);
+
+
+/// Encodes lc/lp/pb into one byte. Returns false on success and true on error.
+extern bool lzma_lzma_lclppb_encode(
+		const lzma_options_lzma *options, uint8_t *byte);
+
+
+#ifdef LZMA_LZ_ENCODER_H
+
+/// Initializes raw LZMA encoder; this is used by LZMA2.
+extern lzma_ret lzma_lzma_encoder_create(
+		void **coder_ptr, const lzma_allocator *allocator,
+		lzma_vli id, const lzma_options_lzma *options,
+		lzma_lz_options *lz_options);
+
+
+/// Resets an already initialized LZMA encoder; this is used by LZMA2.
+extern lzma_ret lzma_lzma_encoder_reset(
+		lzma_lzma1_encoder *coder, const lzma_options_lzma *options);
+
+
+extern lzma_ret lzma_lzma_encode(lzma_lzma1_encoder *restrict coder,
+		lzma_mf *restrict mf, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size,
+		uint32_t read_limit);
+
+#endif
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c
new file mode 100644
index 00000000000..0f063d5be7a
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lzma_encoder_optimum_fast.c
+//
+//  Author:     Igor Pavlov
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lzma_encoder_private.h"
+#include "memcmplen.h"
+
+
+#define change_pair(small_dist, big_dist) \
+	(((big_dist) >> 7) > (small_dist))
+
+
+extern void
+lzma_lzma_optimum_fast(lzma_lzma1_encoder *restrict coder,
+		lzma_mf *restrict mf,
+		uint32_t *restrict back_res, uint32_t *restrict len_res)
+{
+	const uint32_t nice_len = mf->nice_len;
+
+	uint32_t len_main;
+	uint32_t matches_count;
+	if (mf->read_ahead == 0) {
+		len_main = mf_find(mf, &matches_count, coder->matches);
+	} else {
+		assert(mf->read_ahead == 1);
+		len_main = coder->longest_match_length;
+		matches_count = coder->matches_count;
+	}
+
+	const uint8_t *buf = mf_ptr(mf) - 1;
+	const uint32_t buf_avail = my_min(mf_avail(mf) + 1, MATCH_LEN_MAX);
+
+	if (buf_avail < 2) {
+		// There's not enough input left to encode a match.
+		*back_res = UINT32_MAX;
+		*len_res = 1;
+		return;
+	}
+
+	// Look for repeated matches; scan the previous four match distances
+	uint32_t rep_len = 0;
+	uint32_t rep_index = 0;
+
+	for (uint32_t i = 0; i < REPS; ++i) {
+		// Pointer to the beginning of the match candidate
+		const uint8_t *const buf_back = buf - coder->reps[i] - 1;
+
+		// If the first two bytes (2 == MATCH_LEN_MIN) do not match,
+		// this rep is not useful.
+		if (not_equal_16(buf, buf_back))
+			continue;
+
+		// The first two bytes matched.
+		// Calculate the length of the match.
+		const uint32_t len = lzma_memcmplen(
+				buf, buf_back, 2, buf_avail);
+
+		// If we have found a repeated match that is at least
+		// nice_len long, return it immediately.
+		if (len >= nice_len) {
+			*back_res = i;
+			*len_res = len;
+			mf_skip(mf, len - 1);
+			return;
+		}
+
+		if (len > rep_len) {
+			rep_index = i;
+			rep_len = len;
+		}
+	}
+
+	// We didn't find a long enough repeated match. Encode it as a normal
+	// match if the match length is at least nice_len.
+	if (len_main >= nice_len) {
+		*back_res = coder->matches[matches_count - 1].dist + REPS;
+		*len_res = len_main;
+		mf_skip(mf, len_main - 1);
+		return;
+	}
+
+	uint32_t back_main = 0;
+	if (len_main >= 2) {
+		back_main = coder->matches[matches_count - 1].dist;
+
+		while (matches_count > 1 && len_main ==
+				coder->matches[matches_count - 2].len + 1) {
+			if (!change_pair(coder->matches[
+						matches_count - 2].dist,
+					back_main))
+				break;
+
+			--matches_count;
+			len_main = coder->matches[matches_count - 1].len;
+			back_main = coder->matches[matches_count - 1].dist;
+		}
+
+		if (len_main == 2 && back_main >= 0x80)
+			len_main = 1;
+	}
+
+	if (rep_len >= 2) {
+		if (rep_len + 1 >= len_main
+				|| (rep_len + 2 >= len_main
+					&& back_main > (UINT32_C(1) << 9))
+				|| (rep_len + 3 >= len_main
+					&& back_main > (UINT32_C(1) << 15))) {
+			*back_res = rep_index;
+			*len_res = rep_len;
+			mf_skip(mf, rep_len - 1);
+			return;
+		}
+	}
+
+	if (len_main < 2 || buf_avail <= 2) {
+		*back_res = UINT32_MAX;
+		*len_res = 1;
+		return;
+	}
+
+	// Get the matches for the next byte. If we find a better match,
+	// the current byte is encoded as a literal.
+	coder->longest_match_length = mf_find(mf,
+			&coder->matches_count, coder->matches);
+
+	if (coder->longest_match_length >= 2) {
+		const uint32_t new_dist = coder->matches[
+				coder->matches_count - 1].dist;
+
+		if ((coder->longest_match_length >= len_main
+					&& new_dist < back_main)
+				|| (coder->longest_match_length == len_main + 1
+					&& !change_pair(back_main, new_dist))
+				|| (coder->longest_match_length > len_main + 1)
+				|| (coder->longest_match_length + 1 >= len_main
+					&& len_main >= 3
+					&& change_pair(new_dist, back_main))) {
+			*back_res = UINT32_MAX;
+			*len_res = 1;
+			return;
+		}
+	}
+
+	// In contrast to LZMA SDK, dictionary could not have been moved
+	// between mf_find() calls, thus it is safe to just increment
+	// the old buf pointer instead of recalculating it with mf_ptr().
+	++buf;
+
+	const uint32_t limit = my_max(2, len_main - 1);
+
+	for (uint32_t i = 0; i < REPS; ++i) {
+		if (memcmp(buf, buf - coder->reps[i] - 1, limit) == 0) {
+			*back_res = UINT32_MAX;
+			*len_res = 1;
+			return;
+		}
+	}
+
+	*back_res = back_main + REPS;
+	*len_res = len_main;
+	mf_skip(mf, len_main - 2);
+	return;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_normal.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_normal.c
new file mode 100644
index 00000000000..a6c0398f3af
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_optimum_normal.c
@@ -0,0 +1,858 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lzma_encoder_optimum_normal.c
+//
+//  Author:     Igor Pavlov
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lzma_encoder_private.h"
+#include "fastpos.h"
+#include "memcmplen.h"
+
+
+////////////
+// Prices //
+////////////
+
+static uint32_t
+get_literal_price(const lzma_lzma1_encoder *const coder, const uint32_t pos,
+		const uint32_t prev_byte, const bool match_mode,
+		uint32_t match_byte, uint32_t symbol)
+{
+	const probability *const subcoder = literal_subcoder(coder->literal,
+			coder->literal_context_bits, coder->literal_mask,
+			pos, prev_byte);
+
+	uint32_t price = 0;
+
+	if (!match_mode) {
+		price = rc_bittree_price(subcoder, 8, symbol);
+	} else {
+		uint32_t offset = 0x100;
+		symbol += UINT32_C(1) << 8;
+
+		do {
+			match_byte <<= 1;
+
+			const uint32_t match_bit = match_byte & offset;
+			const uint32_t subcoder_index
+					= offset + match_bit + (symbol >> 8);
+			const uint32_t bit = (symbol >> 7) & 1;
+			price += rc_bit_price(subcoder[subcoder_index], bit);
+
+			symbol <<= 1;
+			offset &= ~(match_byte ^ symbol);
+
+		} while (symbol < (UINT32_C(1) << 16));
+	}
+
+	return price;
+}
+
+
+static inline uint32_t
+get_len_price(const lzma_length_encoder *const lencoder,
+		const uint32_t len, const uint32_t pos_state)
+{
+	// NOTE: Unlike the other price tables, length prices are updated
+	// in lzma_encoder.c
+	return lencoder->prices[pos_state][len - MATCH_LEN_MIN];
+}
+
+
+static inline uint32_t
+get_short_rep_price(const lzma_lzma1_encoder *const coder,
+		const lzma_lzma_state state, const uint32_t pos_state)
+{
+	return rc_bit_0_price(coder->is_rep0[state])
+		+ rc_bit_0_price(coder->is_rep0_long[state][pos_state]);
+}
+
+
+static inline uint32_t
+get_pure_rep_price(const lzma_lzma1_encoder *const coder, const uint32_t rep_index,
+		const lzma_lzma_state state, uint32_t pos_state)
+{
+	uint32_t price;
+
+	if (rep_index == 0) {
+		price = rc_bit_0_price(coder->is_rep0[state]);
+		price += rc_bit_1_price(coder->is_rep0_long[state][pos_state]);
+	} else {
+		price = rc_bit_1_price(coder->is_rep0[state]);
+
+		if (rep_index == 1) {
+			price += rc_bit_0_price(coder->is_rep1[state]);
+		} else {
+			price += rc_bit_1_price(coder->is_rep1[state]);
+			price += rc_bit_price(coder->is_rep2[state],
+					rep_index - 2);
+		}
+	}
+
+	return price;
+}
+
+
+static inline uint32_t
+get_rep_price(const lzma_lzma1_encoder *const coder, const uint32_t rep_index,
+		const uint32_t len, const lzma_lzma_state state,
+		const uint32_t pos_state)
+{
+	return get_len_price(&coder->rep_len_encoder, len, pos_state)
+		+ get_pure_rep_price(coder, rep_index, state, pos_state);
+}
+
+
+static inline uint32_t
+get_dist_len_price(const lzma_lzma1_encoder *const coder, const uint32_t dist,
+		const uint32_t len, const uint32_t pos_state)
+{
+	const uint32_t dist_state = get_dist_state(len);
+	uint32_t price;
+
+	if (dist < FULL_DISTANCES) {
+		price = coder->dist_prices[dist_state][dist];
+	} else {
+		const uint32_t dist_slot = get_dist_slot_2(dist);
+		price = coder->dist_slot_prices[dist_state][dist_slot]
+				+ coder->align_prices[dist & ALIGN_MASK];
+	}
+
+	price += get_len_price(&coder->match_len_encoder, len, pos_state);
+
+	return price;
+}
+
+
+static void
+fill_dist_prices(lzma_lzma1_encoder *coder)
+{
+	for (uint32_t dist_state = 0; dist_state < DIST_STATES; ++dist_state) {
+
+		uint32_t *const dist_slot_prices
+				= coder->dist_slot_prices[dist_state];
+
+		// Price to encode the dist_slot.
+		for (uint32_t dist_slot = 0;
+				dist_slot < coder->dist_table_size; ++dist_slot)
+			dist_slot_prices[dist_slot] = rc_bittree_price(
+					coder->dist_slot[dist_state],
+					DIST_SLOT_BITS, dist_slot);
+
+		// For matches with distance >= FULL_DISTANCES, add the price
+		// of the direct bits part of the match distance. (Align bits
+		// are handled by fill_align_prices()).
+		for (uint32_t dist_slot = DIST_MODEL_END;
+				dist_slot < coder->dist_table_size;
+				++dist_slot)
+			dist_slot_prices[dist_slot] += rc_direct_price(
+					((dist_slot >> 1) - 1) - ALIGN_BITS);
+
+		// Distances in the range [0, 3] are fully encoded with
+		// dist_slot, so they are used for coder->dist_prices
+		// as is.
+		for (uint32_t i = 0; i < DIST_MODEL_START; ++i)
+			coder->dist_prices[dist_state][i]
+					= dist_slot_prices[i];
+	}
+
+	// Distances in the range [4, 127] depend on dist_slot and
+	// dist_special. We do this in a loop separate from the above
+	// loop to avoid redundant calls to get_dist_slot().
+	for (uint32_t i = DIST_MODEL_START; i < FULL_DISTANCES; ++i) {
+		const uint32_t dist_slot = get_dist_slot(i);
+		const uint32_t footer_bits = ((dist_slot >> 1) - 1);
+		const uint32_t base = (2 | (dist_slot & 1)) << footer_bits;
+		const uint32_t price = rc_bittree_reverse_price(
+				coder->dist_special + base - dist_slot - 1,
+				footer_bits, i - base);
+
+		for (uint32_t dist_state = 0; dist_state < DIST_STATES;
+				++dist_state)
+			coder->dist_prices[dist_state][i]
+					= price + coder->dist_slot_prices[
+						dist_state][dist_slot];
+	}
+
+	coder->match_price_count = 0;
+	return;
+}
+
+
+static void
+fill_align_prices(lzma_lzma1_encoder *coder)
+{
+	for (uint32_t i = 0; i < ALIGN_SIZE; ++i)
+		coder->align_prices[i] = rc_bittree_reverse_price(
+				coder->dist_align, ALIGN_BITS, i);
+
+	coder->align_price_count = 0;
+	return;
+}
+
+
+/////////////
+// Optimal //
+/////////////
+
+static inline void
+make_literal(lzma_optimal *optimal)
+{
+	optimal->back_prev = UINT32_MAX;
+	optimal->prev_1_is_literal = false;
+}
+
+
+static inline void
+make_short_rep(lzma_optimal *optimal)
+{
+	optimal->back_prev = 0;
+	optimal->prev_1_is_literal = false;
+}
+
+
+#define is_short_rep(optimal) \
+	((optimal).back_prev == 0)
+
+
+static void
+backward(lzma_lzma1_encoder *restrict coder, uint32_t *restrict len_res,
+		uint32_t *restrict back_res, uint32_t cur)
+{
+	coder->opts_end_index = cur;
+
+	uint32_t pos_mem = coder->opts[cur].pos_prev;
+	uint32_t back_mem = coder->opts[cur].back_prev;
+
+	do {
+		if (coder->opts[cur].prev_1_is_literal) {
+			make_literal(&coder->opts[pos_mem]);
+			coder->opts[pos_mem].pos_prev = pos_mem - 1;
+
+			if (coder->opts[cur].prev_2) {
+				coder->opts[pos_mem - 1].prev_1_is_literal
+						= false;
+				coder->opts[pos_mem - 1].pos_prev
+						= coder->opts[cur].pos_prev_2;
+				coder->opts[pos_mem - 1].back_prev
+						= coder->opts[cur].back_prev_2;
+			}
+		}
+
+		const uint32_t pos_prev = pos_mem;
+		const uint32_t back_cur = back_mem;
+
+		back_mem = coder->opts[pos_prev].back_prev;
+		pos_mem = coder->opts[pos_prev].pos_prev;
+
+		coder->opts[pos_prev].back_prev = back_cur;
+		coder->opts[pos_prev].pos_prev = cur;
+		cur = pos_prev;
+
+	} while (cur != 0);
+
+	coder->opts_current_index = coder->opts[0].pos_prev;
+	*len_res = coder->opts[0].pos_prev;
+	*back_res = coder->opts[0].back_prev;
+
+	return;
+}
+
+
+//////////
+// Main //
+//////////
+
+static inline uint32_t
+helper1(lzma_lzma1_encoder *restrict coder, lzma_mf *restrict mf,
+		uint32_t *restrict back_res, uint32_t *restrict len_res,
+		uint32_t position)
+{
+	const uint32_t nice_len = mf->nice_len;
+
+	uint32_t len_main;
+	uint32_t matches_count;
+
+	if (mf->read_ahead == 0) {
+		len_main = mf_find(mf, &matches_count, coder->matches);
+	} else {
+		assert(mf->read_ahead == 1);
+		len_main = coder->longest_match_length;
+		matches_count = coder->matches_count;
+	}
+
+	const uint32_t buf_avail = my_min(mf_avail(mf) + 1, MATCH_LEN_MAX);
+	if (buf_avail < 2) {
+		*back_res = UINT32_MAX;
+		*len_res = 1;
+		return UINT32_MAX;
+	}
+
+	const uint8_t *const buf = mf_ptr(mf) - 1;
+
+	uint32_t rep_lens[REPS];
+	uint32_t rep_max_index = 0;
+
+	for (uint32_t i = 0; i < REPS; ++i) {
+		const uint8_t *const buf_back = buf - coder->reps[i] - 1;
+
+		if (not_equal_16(buf, buf_back)) {
+			rep_lens[i] = 0;
+			continue;
+		}
+
+		rep_lens[i] = lzma_memcmplen(buf, buf_back, 2, buf_avail);
+
+		if (rep_lens[i] > rep_lens[rep_max_index])
+			rep_max_index = i;
+	}
+
+	if (rep_lens[rep_max_index] >= nice_len) {
+		*back_res = rep_max_index;
+		*len_res = rep_lens[rep_max_index];
+		mf_skip(mf, *len_res - 1);
+		return UINT32_MAX;
+	}
+
+
+	if (len_main >= nice_len) {
+		*back_res = coder->matches[matches_count - 1].dist + REPS;
+		*len_res = len_main;
+		mf_skip(mf, len_main - 1);
+		return UINT32_MAX;
+	}
+
+	const uint8_t current_byte = *buf;
+	const uint8_t match_byte = *(buf - coder->reps[0] - 1);
+
+	if (len_main < 2 && current_byte != match_byte
+			&& rep_lens[rep_max_index] < 2) {
+		*back_res = UINT32_MAX;
+		*len_res = 1;
+		return UINT32_MAX;
+	}
+
+	coder->opts[0].state = coder->state;
+
+	const uint32_t pos_state = position & coder->pos_mask;
+
+	coder->opts[1].price = rc_bit_0_price(
+				coder->is_match[coder->state][pos_state])
+			+ get_literal_price(coder, position, buf[-1],
+				!is_literal_state(coder->state),
+				match_byte, current_byte);
+
+	make_literal(&coder->opts[1]);
+
+	const uint32_t match_price = rc_bit_1_price(
+			coder->is_match[coder->state][pos_state]);
+	const uint32_t rep_match_price = match_price
+			+ rc_bit_1_price(coder->is_rep[coder->state]);
+
+	if (match_byte == current_byte) {
+		const uint32_t short_rep_price = rep_match_price
+				+ get_short_rep_price(
+					coder, coder->state, pos_state);
+
+		if (short_rep_price < coder->opts[1].price) {
+			coder->opts[1].price = short_rep_price;
+			make_short_rep(&coder->opts[1]);
+		}
+	}
+
+	const uint32_t len_end = my_max(len_main, rep_lens[rep_max_index]);
+
+	if (len_end < 2) {
+		*back_res = coder->opts[1].back_prev;
+		*len_res = 1;
+		return UINT32_MAX;
+	}
+
+	coder->opts[1].pos_prev = 0;
+
+	for (uint32_t i = 0; i < REPS; ++i)
+		coder->opts[0].backs[i] = coder->reps[i];
+
+	uint32_t len = len_end;
+	do {
+		coder->opts[len].price = RC_INFINITY_PRICE;
+	} while (--len >= 2);
+
+
+	for (uint32_t i = 0; i < REPS; ++i) {
+		uint32_t rep_len = rep_lens[i];
+		if (rep_len < 2)
+			continue;
+
+		const uint32_t price = rep_match_price + get_pure_rep_price(
+				coder, i, coder->state, pos_state);
+
+		do {
+			const uint32_t cur_and_len_price = price
+					+ get_len_price(
+						&coder->rep_len_encoder,
+						rep_len, pos_state);
+
+			if (cur_and_len_price < coder->opts[rep_len].price) {
+				coder->opts[rep_len].price = cur_and_len_price;
+				coder->opts[rep_len].pos_prev = 0;
+				coder->opts[rep_len].back_prev = i;
+				coder->opts[rep_len].prev_1_is_literal = false;
+			}
+		} while (--rep_len >= 2);
+	}
+
+
+	const uint32_t normal_match_price = match_price
+			+ rc_bit_0_price(coder->is_rep[coder->state]);
+
+	len = rep_lens[0] >= 2 ? rep_lens[0] + 1 : 2;
+	if (len <= len_main) {
+		uint32_t i = 0;
+		while (len > coder->matches[i].len)
+			++i;
+
+		for(; ; ++len) {
+			const uint32_t dist = coder->matches[i].dist;
+			const uint32_t cur_and_len_price = normal_match_price
+					+ get_dist_len_price(coder,
+						dist, len, pos_state);
+
+			if (cur_and_len_price < coder->opts[len].price) {
+				coder->opts[len].price = cur_and_len_price;
+				coder->opts[len].pos_prev = 0;
+				coder->opts[len].back_prev = dist + REPS;
+				coder->opts[len].prev_1_is_literal = false;
+			}
+
+			if (len == coder->matches[i].len)
+				if (++i == matches_count)
+					break;
+		}
+	}
+
+	return len_end;
+}
+
+
+static inline uint32_t
+helper2(lzma_lzma1_encoder *coder, uint32_t *reps, const uint8_t *buf,
+		uint32_t len_end, uint32_t position, const uint32_t cur,
+		const uint32_t nice_len, const uint32_t buf_avail_full)
+{
+	uint32_t matches_count = coder->matches_count;
+	uint32_t new_len = coder->longest_match_length;
+	uint32_t pos_prev = coder->opts[cur].pos_prev;
+	lzma_lzma_state state;
+
+	if (coder->opts[cur].prev_1_is_literal) {
+		--pos_prev;
+
+		if (coder->opts[cur].prev_2) {
+			state = coder->opts[coder->opts[cur].pos_prev_2].state;
+
+			if (coder->opts[cur].back_prev_2 < REPS)
+				update_long_rep(state);
+			else
+				update_match(state);
+
+		} else {
+			state = coder->opts[pos_prev].state;
+		}
+
+		update_literal(state);
+
+	} else {
+		state = coder->opts[pos_prev].state;
+	}
+
+	if (pos_prev == cur - 1) {
+		if (is_short_rep(coder->opts[cur]))
+			update_short_rep(state);
+		else
+			update_literal(state);
+	} else {
+		uint32_t pos;
+		if (coder->opts[cur].prev_1_is_literal
+				&& coder->opts[cur].prev_2) {
+			pos_prev = coder->opts[cur].pos_prev_2;
+			pos = coder->opts[cur].back_prev_2;
+			update_long_rep(state);
+		} else {
+			pos = coder->opts[cur].back_prev;
+			if (pos < REPS)
+				update_long_rep(state);
+			else
+				update_match(state);
+		}
+
+		if (pos < REPS) {
+			reps[0] = coder->opts[pos_prev].backs[pos];
+
+			uint32_t i;
+			for (i = 1; i <= pos; ++i)
+				reps[i] = coder->opts[pos_prev].backs[i - 1];
+
+			for (; i < REPS; ++i)
+				reps[i] = coder->opts[pos_prev].backs[i];
+
+		} else {
+			reps[0] = pos - REPS;
+
+			for (uint32_t i = 1; i < REPS; ++i)
+				reps[i] = coder->opts[pos_prev].backs[i - 1];
+		}
+	}
+
+	coder->opts[cur].state = state;
+
+	for (uint32_t i = 0; i < REPS; ++i)
+		coder->opts[cur].backs[i] = reps[i];
+
+	const uint32_t cur_price = coder->opts[cur].price;
+
+	const uint8_t current_byte = *buf;
+	const uint8_t match_byte = *(buf - reps[0] - 1);
+
+	const uint32_t pos_state = position & coder->pos_mask;
+
+	const uint32_t cur_and_1_price = cur_price
+			+ rc_bit_0_price(coder->is_match[state][pos_state])
+			+ get_literal_price(coder, position, buf[-1],
+			!is_literal_state(state), match_byte, current_byte);
+
+	bool next_is_literal = false;
+
+	if (cur_and_1_price < coder->opts[cur + 1].price) {
+		coder->opts[cur + 1].price = cur_and_1_price;
+		coder->opts[cur + 1].pos_prev = cur;
+		make_literal(&coder->opts[cur + 1]);
+		next_is_literal = true;
+	}
+
+	const uint32_t match_price = cur_price
+			+ rc_bit_1_price(coder->is_match[state][pos_state]);
+	const uint32_t rep_match_price = match_price
+			+ rc_bit_1_price(coder->is_rep[state]);
+
+	if (match_byte == current_byte
+			&& !(coder->opts[cur + 1].pos_prev < cur
+				&& coder->opts[cur + 1].back_prev == 0)) {
+
+		const uint32_t short_rep_price = rep_match_price
+				+ get_short_rep_price(coder, state, pos_state);
+
+		if (short_rep_price <= coder->opts[cur + 1].price) {
+			coder->opts[cur + 1].price = short_rep_price;
+			coder->opts[cur + 1].pos_prev = cur;
+			make_short_rep(&coder->opts[cur + 1]);
+			next_is_literal = true;
+		}
+	}
+
+	if (buf_avail_full < 2)
+		return len_end;
+
+	const uint32_t buf_avail = my_min(buf_avail_full, nice_len);
+
+	if (!next_is_literal && match_byte != current_byte) { // speed optimization
+		// try literal + rep0
+		const uint8_t *const buf_back = buf - reps[0] - 1;
+		const uint32_t limit = my_min(buf_avail_full, nice_len + 1);
+
+		const uint32_t len_test = lzma_memcmplen(buf, buf_back, 1, limit) - 1;
+
+		if (len_test >= 2) {
+			lzma_lzma_state state_2 = state;
+			update_literal(state_2);
+
+			const uint32_t pos_state_next = (position + 1) & coder->pos_mask;
+			const uint32_t next_rep_match_price = cur_and_1_price
+					+ rc_bit_1_price(coder->is_match[state_2][pos_state_next])
+					+ rc_bit_1_price(coder->is_rep[state_2]);
+
+			//for (; len_test >= 2; --len_test) {
+			const uint32_t offset = cur + 1 + len_test;
+
+			while (len_end < offset)
+				coder->opts[++len_end].price = RC_INFINITY_PRICE;
+
+			const uint32_t cur_and_len_price = next_rep_match_price
+					+ get_rep_price(coder, 0, len_test,
+						state_2, pos_state_next);
+
+			if (cur_and_len_price < coder->opts[offset].price) {
+				coder->opts[offset].price = cur_and_len_price;
+				coder->opts[offset].pos_prev = cur + 1;
+				coder->opts[offset].back_prev = 0;
+				coder->opts[offset].prev_1_is_literal = true;
+				coder->opts[offset].prev_2 = false;
+			}
+			//}
+		}
+	}
+
+
+	uint32_t start_len = 2; // speed optimization
+
+	for (uint32_t rep_index = 0; rep_index < REPS; ++rep_index) {
+		const uint8_t *const buf_back = buf - reps[rep_index] - 1;
+		if (not_equal_16(buf, buf_back))
+			continue;
+
+		uint32_t len_test = lzma_memcmplen(buf, buf_back, 2, buf_avail);
+
+		while (len_end < cur + len_test)
+			coder->opts[++len_end].price = RC_INFINITY_PRICE;
+
+		const uint32_t len_test_temp = len_test;
+		const uint32_t price = rep_match_price + get_pure_rep_price(
+				coder, rep_index, state, pos_state);
+
+		do {
+			const uint32_t cur_and_len_price = price
+					+ get_len_price(&coder->rep_len_encoder,
+							len_test, pos_state);
+
+			if (cur_and_len_price < coder->opts[cur + len_test].price) {
+				coder->opts[cur + len_test].price = cur_and_len_price;
+				coder->opts[cur + len_test].pos_prev = cur;
+				coder->opts[cur + len_test].back_prev = rep_index;
+				coder->opts[cur + len_test].prev_1_is_literal = false;
+			}
+		} while (--len_test >= 2);
+
+		len_test = len_test_temp;
+
+		if (rep_index == 0)
+			start_len = len_test + 1;
+
+
+		uint32_t len_test_2 = len_test + 1;
+		const uint32_t limit = my_min(buf_avail_full,
+				len_test_2 + nice_len);
+		// NOTE: len_test_2 may be greater than limit so the call to
+		// lzma_memcmplen() must be done conditionally.
+		if (len_test_2 < limit)
+			len_test_2 = lzma_memcmplen(buf, buf_back, len_test_2, limit);
+
+		len_test_2 -= len_test + 1;
+
+		if (len_test_2 >= 2) {
+			lzma_lzma_state state_2 = state;
+			update_long_rep(state_2);
+
+			uint32_t pos_state_next = (position + len_test) & coder->pos_mask;
+
+			const uint32_t cur_and_len_literal_price = price
+					+ get_len_price(&coder->rep_len_encoder,
+						len_test, pos_state)
+					+ rc_bit_0_price(coder->is_match[state_2][pos_state_next])
+					+ get_literal_price(coder, position + len_test,
+						buf[len_test - 1], true,
+						buf_back[len_test], buf[len_test]);
+
+			update_literal(state_2);
+
+			pos_state_next = (position + len_test + 1) & coder->pos_mask;
+
+			const uint32_t next_rep_match_price = cur_and_len_literal_price
+					+ rc_bit_1_price(coder->is_match[state_2][pos_state_next])
+					+ rc_bit_1_price(coder->is_rep[state_2]);
+
+			//for(; len_test_2 >= 2; len_test_2--) {
+			const uint32_t offset = cur + len_test + 1 + len_test_2;
+
+			while (len_end < offset)
+				coder->opts[++len_end].price = RC_INFINITY_PRICE;
+
+			const uint32_t cur_and_len_price = next_rep_match_price
+					+ get_rep_price(coder, 0, len_test_2,
+						state_2, pos_state_next);
+
+			if (cur_and_len_price < coder->opts[offset].price) {
+				coder->opts[offset].price = cur_and_len_price;
+				coder->opts[offset].pos_prev = cur + len_test + 1;
+				coder->opts[offset].back_prev = 0;
+				coder->opts[offset].prev_1_is_literal = true;
+				coder->opts[offset].prev_2 = true;
+				coder->opts[offset].pos_prev_2 = cur;
+				coder->opts[offset].back_prev_2 = rep_index;
+			}
+			//}
+		}
+	}
+
+
+	//for (uint32_t len_test = 2; len_test <= new_len; ++len_test)
+	if (new_len > buf_avail) {
+		new_len = buf_avail;
+
+		matches_count = 0;
+		while (new_len > coder->matches[matches_count].len)
+			++matches_count;
+
+		coder->matches[matches_count++].len = new_len;
+	}
+
+
+	if (new_len >= start_len) {
+		const uint32_t normal_match_price = match_price
+				+ rc_bit_0_price(coder->is_rep[state]);
+
+		while (len_end < cur + new_len)
+			coder->opts[++len_end].price = RC_INFINITY_PRICE;
+
+		uint32_t i = 0;
+		while (start_len > coder->matches[i].len)
+			++i;
+
+		for (uint32_t len_test = start_len; ; ++len_test) {
+			const uint32_t cur_back = coder->matches[i].dist;
+			uint32_t cur_and_len_price = normal_match_price
+					+ get_dist_len_price(coder,
+						cur_back, len_test, pos_state);
+
+			if (cur_and_len_price < coder->opts[cur + len_test].price) {
+				coder->opts[cur + len_test].price = cur_and_len_price;
+				coder->opts[cur + len_test].pos_prev = cur;
+				coder->opts[cur + len_test].back_prev
+						= cur_back + REPS;
+				coder->opts[cur + len_test].prev_1_is_literal = false;
+			}
+
+			if (len_test == coder->matches[i].len) {
+				// Try Match + Literal + Rep0
+				const uint8_t *const buf_back = buf - cur_back - 1;
+				uint32_t len_test_2 = len_test + 1;
+				const uint32_t limit = my_min(buf_avail_full,
+						len_test_2 + nice_len);
+
+				// NOTE: len_test_2 may be greater than limit
+				// so the call to lzma_memcmplen() must be
+				// done conditionally.
+				if (len_test_2 < limit)
+					len_test_2 = lzma_memcmplen(buf, buf_back,
+							len_test_2, limit);
+
+				len_test_2 -= len_test + 1;
+
+				if (len_test_2 >= 2) {
+					lzma_lzma_state state_2 = state;
+					update_match(state_2);
+					uint32_t pos_state_next
+							= (position + len_test) & coder->pos_mask;
+
+					const uint32_t cur_and_len_literal_price = cur_and_len_price
+							+ rc_bit_0_price(
+								coder->is_match[state_2][pos_state_next])
+							+ get_literal_price(coder,
+								position + len_test,
+								buf[len_test - 1],
+								true,
+								buf_back[len_test],
+								buf[len_test]);
+
+					update_literal(state_2);
+					pos_state_next = (pos_state_next + 1) & coder->pos_mask;
+
+					const uint32_t next_rep_match_price
+							= cur_and_len_literal_price
+							+ rc_bit_1_price(
+								coder->is_match[state_2][pos_state_next])
+							+ rc_bit_1_price(coder->is_rep[state_2]);
+
+					// for(; len_test_2 >= 2; --len_test_2) {
+					const uint32_t offset = cur + len_test + 1 + len_test_2;
+
+					while (len_end < offset)
+						coder->opts[++len_end].price = RC_INFINITY_PRICE;
+
+					cur_and_len_price = next_rep_match_price
+							+ get_rep_price(coder, 0, len_test_2,
+								state_2, pos_state_next);
+
+					if (cur_and_len_price < coder->opts[offset].price) {
+						coder->opts[offset].price = cur_and_len_price;
+						coder->opts[offset].pos_prev = cur + len_test + 1;
+						coder->opts[offset].back_prev = 0;
+						coder->opts[offset].prev_1_is_literal = true;
+						coder->opts[offset].prev_2 = true;
+						coder->opts[offset].pos_prev_2 = cur;
+						coder->opts[offset].back_prev_2
+								= cur_back + REPS;
+					}
+					//}
+				}
+
+				if (++i == matches_count)
+					break;
+			}
+		}
+	}
+
+	return len_end;
+}
+
+
+extern void
+lzma_lzma_optimum_normal(lzma_lzma1_encoder *restrict coder,
+		lzma_mf *restrict mf,
+		uint32_t *restrict back_res, uint32_t *restrict len_res,
+		uint32_t position)
+{
+	// If we have symbols pending, return the next pending symbol.
+	if (coder->opts_end_index != coder->opts_current_index) {
+		assert(mf->read_ahead > 0);
+		*len_res = coder->opts[coder->opts_current_index].pos_prev
+				- coder->opts_current_index;
+		*back_res = coder->opts[coder->opts_current_index].back_prev;
+		coder->opts_current_index = coder->opts[
+				coder->opts_current_index].pos_prev;
+		return;
+	}
+
+	// Update the price tables. In LZMA SDK <= 4.60 (and possibly later)
+	// this was done in both initialization function and in the main loop.
+	// In liblzma they were moved into this single place.
+	if (mf->read_ahead == 0) {
+		if (coder->match_price_count >= (1 << 7))
+			fill_dist_prices(coder);
+
+		if (coder->align_price_count >= ALIGN_SIZE)
+			fill_align_prices(coder);
+	}
+
+	// TODO: This needs quite a bit of cleaning still. But splitting
+	// the original function into two pieces makes it at least a little
+	// more readable, since those two parts don't share many variables.
+
+	uint32_t len_end = helper1(coder, mf, back_res, len_res, position);
+	if (len_end == UINT32_MAX)
+		return;
+
+	uint32_t reps[REPS];
+	memcpy(reps, coder->reps, sizeof(reps));
+
+	uint32_t cur;
+	for (cur = 1; cur < len_end; ++cur) {
+		assert(cur < OPTS);
+
+		coder->longest_match_length = mf_find(
+				mf, &coder->matches_count, coder->matches);
+
+		if (coder->longest_match_length >= mf->nice_len)
+			break;
+
+		len_end = helper2(coder, reps, mf_ptr(mf) - 1, len_end,
+				position + cur, cur, mf->nice_len,
+				my_min(mf_avail(mf) + 1, OPTS - 1 - cur));
+	}
+
+	backward(coder, len_res, back_res, cur);
+	return;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_presets.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_presets.c
new file mode 100644
index 00000000000..e53483f9958
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_presets.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lzma_encoder_presets.c
+/// \brief      Encoder presets
+/// \note       xz needs this even when only decoding is enabled.
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+
+extern LZMA_API(lzma_bool)
+lzma_lzma_preset(lzma_options_lzma *options, uint32_t preset)
+{
+	const uint32_t level = preset & LZMA_PRESET_LEVEL_MASK;
+	const uint32_t flags = preset & ~LZMA_PRESET_LEVEL_MASK;
+	const uint32_t supported_flags = LZMA_PRESET_EXTREME;
+
+	if (level > 9 || (flags & ~supported_flags))
+		return true;
+
+	options->preset_dict = NULL;
+	options->preset_dict_size = 0;
+
+	options->lc = LZMA_LC_DEFAULT;
+	options->lp = LZMA_LP_DEFAULT;
+	options->pb = LZMA_PB_DEFAULT;
+
+	static const uint8_t dict_pow2[]
+			= { 18, 20, 21, 22, 22, 23, 23, 24, 25, 26 };
+	options->dict_size = UINT32_C(1) << dict_pow2[level];
+
+	if (level <= 3) {
+		options->mode = LZMA_MODE_FAST;
+		options->mf = level == 0 ? LZMA_MF_HC3 : LZMA_MF_HC4;
+		options->nice_len = level <= 1 ? 128 : 273;
+		static const uint8_t depths[] = { 4, 8, 24, 48 };
+		options->depth = depths[level];
+	} else {
+		options->mode = LZMA_MODE_NORMAL;
+		options->mf = LZMA_MF_BT4;
+		options->nice_len = level == 4 ? 16 : level == 5 ? 32 : 64;
+		options->depth = 0;
+	}
+
+	if (flags & LZMA_PRESET_EXTREME) {
+		options->mode = LZMA_MODE_NORMAL;
+		options->mf = LZMA_MF_BT4;
+		if (level == 3 || level == 5) {
+			options->nice_len = 192;
+			options->depth = 0;
+		} else {
+			options->nice_len = 273;
+			options->depth = 512;
+		}
+	}
+
+	return false;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_private.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_private.h
new file mode 100644
index 00000000000..eeea5e9c128
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/lzma/lzma_encoder_private.h
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       lzma_encoder_private.h
+/// \brief      Private definitions for LZMA encoder
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZMA_ENCODER_PRIVATE_H
+#define LZMA_LZMA_ENCODER_PRIVATE_H
+
+#include "lz_encoder.h"
+#include "range_encoder.h"
+#include "lzma_common.h"
+#include "lzma_encoder.h"
+
+
+// Macro to compare if the first two bytes in two buffers differ. This is
+// needed in lzma_lzma_optimum_*() to test if the match is at least
+// MATCH_LEN_MIN bytes. Unaligned access gives tiny gain so there's no
+// reason to not use it when it is supported.
+#ifdef TUKLIB_FAST_UNALIGNED_ACCESS
+#	define not_equal_16(a, b) (read16ne(a) != read16ne(b))
+#else
+#	define not_equal_16(a, b) \
+		((a)[0] != (b)[0] || (a)[1] != (b)[1])
+#endif
+
+
+// Optimal - Number of entries in the optimum array.
+#define OPTS (1 << 12)
+
+
+typedef struct {
+	probability choice;
+	probability choice2;
+	probability low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
+	probability mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
+	probability high[LEN_HIGH_SYMBOLS];
+
+	uint32_t prices[POS_STATES_MAX][LEN_SYMBOLS];
+	uint32_t table_size;
+	uint32_t counters[POS_STATES_MAX];
+
+} lzma_length_encoder;
+
+
+typedef struct {
+	lzma_lzma_state state;
+
+	bool prev_1_is_literal;
+	bool prev_2;
+
+	uint32_t pos_prev_2;
+	uint32_t back_prev_2;
+
+	uint32_t price;
+	uint32_t pos_prev;  // pos_next;
+	uint32_t back_prev;
+
+	uint32_t backs[REPS];
+
+} lzma_optimal;
+
+
+struct lzma_lzma1_encoder_s {
+	/// Range encoder
+	lzma_range_encoder rc;
+
+	/// Uncompressed size (doesn't include possible preset dictionary)
+	uint64_t uncomp_size;
+
+	/// If non-zero, produce at most this much output.
+	/// Some input may then be missing from the output.
+	uint64_t out_limit;
+
+	/// If the above out_limit is non-zero, *uncomp_size_ptr is set to
+	/// the amount of uncompressed data that we were able to fit
+	/// in the output buffer.
+	uint64_t *uncomp_size_ptr;
+
+	/// State
+	lzma_lzma_state state;
+
+	/// The four most recent match distances
+	uint32_t reps[REPS];
+
+	/// Array of match candidates
+	lzma_match matches[MATCH_LEN_MAX + 1];
+
+	/// Number of match candidates in matches[]
+	uint32_t matches_count;
+
+	/// Variable to hold the length of the longest match between calls
+	/// to lzma_lzma_optimum_*().
+	uint32_t longest_match_length;
+
+	/// True if using getoptimumfast
+	bool fast_mode;
+
+	/// True if the encoder has been initialized by encoding the first
+	/// byte as a literal.
+	bool is_initialized;
+
+	/// True if the range encoder has been flushed, but not all bytes
+	/// have been written to the output buffer yet.
+	bool is_flushed;
+
+	/// True if end of payload marker will be written.
+	bool use_eopm;
+
+	uint32_t pos_mask;         ///< (1 << pos_bits) - 1
+	uint32_t literal_context_bits;
+	uint32_t literal_mask;
+
+	// These are the same as in lzma_decoder.c. See comments there.
+	probability literal[LITERAL_CODERS_MAX * LITERAL_CODER_SIZE];
+	probability is_match[STATES][POS_STATES_MAX];
+	probability is_rep[STATES];
+	probability is_rep0[STATES];
+	probability is_rep1[STATES];
+	probability is_rep2[STATES];
+	probability is_rep0_long[STATES][POS_STATES_MAX];
+	probability dist_slot[DIST_STATES][DIST_SLOTS];
+	probability dist_special[FULL_DISTANCES - DIST_MODEL_END];
+	probability dist_align[ALIGN_SIZE];
+
+	// These are the same as in lzma_decoder.c except that the encoders
+	// include also price tables.
+	lzma_length_encoder match_len_encoder;
+	lzma_length_encoder rep_len_encoder;
+
+	// Price tables
+	uint32_t dist_slot_prices[DIST_STATES][DIST_SLOTS];
+	uint32_t dist_prices[DIST_STATES][FULL_DISTANCES];
+	uint32_t dist_table_size;
+	uint32_t match_price_count;
+
+	uint32_t align_prices[ALIGN_SIZE];
+	uint32_t align_price_count;
+
+	// Optimal
+	uint32_t opts_end_index;
+	uint32_t opts_current_index;
+	lzma_optimal opts[OPTS];
+};
+
+
+extern void lzma_lzma_optimum_fast(
+		lzma_lzma1_encoder *restrict coder, lzma_mf *restrict mf,
+		uint32_t *restrict back_res, uint32_t *restrict len_res);
+
+extern void lzma_lzma_optimum_normal(lzma_lzma1_encoder *restrict coder,
+		lzma_mf *restrict mf, uint32_t *restrict back_res,
+		uint32_t *restrict len_res, uint32_t position);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price.h
new file mode 100644
index 00000000000..cce6bdae5f9
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price.h
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       price.h
+/// \brief      Probability price calculation
+//
+//  Author:     Igor Pavlov
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_PRICE_H
+#define LZMA_PRICE_H
+
+
+#define RC_MOVE_REDUCING_BITS 4
+#define RC_BIT_PRICE_SHIFT_BITS 4
+#define RC_PRICE_TABLE_SIZE (RC_BIT_MODEL_TOTAL >> RC_MOVE_REDUCING_BITS)
+
+#define RC_INFINITY_PRICE (UINT32_C(1) << 30)
+
+
+/// Lookup table for the inline functions defined in this file.
+lzma_attr_visibility_hidden
+extern const uint8_t lzma_rc_prices[RC_PRICE_TABLE_SIZE];
+
+
+static inline uint32_t
+rc_bit_price(const probability prob, const uint32_t bit)
+{
+	return lzma_rc_prices[(prob ^ ((UINT32_C(0) - bit)
+			& (RC_BIT_MODEL_TOTAL - 1))) >> RC_MOVE_REDUCING_BITS];
+}
+
+
+static inline uint32_t
+rc_bit_0_price(const probability prob)
+{
+	return lzma_rc_prices[prob >> RC_MOVE_REDUCING_BITS];
+}
+
+
+static inline uint32_t
+rc_bit_1_price(const probability prob)
+{
+	return lzma_rc_prices[(prob ^ (RC_BIT_MODEL_TOTAL - 1))
+			>> RC_MOVE_REDUCING_BITS];
+}
+
+
+static inline uint32_t
+rc_bittree_price(const probability *const probs,
+		const uint32_t bit_levels, uint32_t symbol)
+{
+	uint32_t price = 0;
+	symbol += UINT32_C(1) << bit_levels;
+
+	do {
+		const uint32_t bit = symbol & 1;
+		symbol >>= 1;
+		price += rc_bit_price(probs[symbol], bit);
+	} while (symbol != 1);
+
+	return price;
+}
+
+
+static inline uint32_t
+rc_bittree_reverse_price(const probability *const probs,
+		uint32_t bit_levels, uint32_t symbol)
+{
+	uint32_t price = 0;
+	uint32_t model_index = 1;
+
+	do {
+		const uint32_t bit = symbol & 1;
+		symbol >>= 1;
+		price += rc_bit_price(probs[model_index], bit);
+		model_index = (model_index << 1) + bit;
+	} while (--bit_levels != 0);
+
+	return price;
+}
+
+
+static inline uint32_t
+rc_direct_price(const uint32_t bits)
+{
+	 return bits << RC_BIT_PRICE_SHIFT_BITS;
+}
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_table.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_table.c
new file mode 100644
index 00000000000..c33433f718c
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_table.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: 0BSD
+
+// This file has been generated by price_tablegen.c.
+
+#include "range_encoder.h"
+
+const uint8_t lzma_rc_prices[RC_PRICE_TABLE_SIZE] = {
+	 128, 103,  91,  84,  78,  73,  69,  66,
+	  63,  61,  58,  56,  54,  52,  51,  49,
+	  48,  46,  45,  44,  43,  42,  41,  40,
+	  39,  38,  37,  36,  35,  34,  34,  33,
+	  32,  31,  31,  30,  29,  29,  28,  28,
+	  27,  26,  26,  25,  25,  24,  24,  23,
+	  23,  22,  22,  22,  21,  21,  20,  20,
+	  19,  19,  19,  18,  18,  17,  17,  17,
+	  16,  16,  16,  15,  15,  15,  14,  14,
+	  14,  13,  13,  13,  12,  12,  12,  11,
+	  11,  11,  11,  10,  10,  10,  10,   9,
+	   9,   9,   9,   8,   8,   8,   8,   7,
+	   7,   7,   7,   6,   6,   6,   6,   5,
+	   5,   5,   5,   5,   4,   4,   4,   4,
+	   3,   3,   3,   3,   3,   2,   2,   2,
+	   2,   2,   2,   1,   1,   1,   1,   1
+};
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_tablegen.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_tablegen.c
new file mode 100644
index 00000000000..4b6ca37efad
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/price_tablegen.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       price_tablegen.c
+/// \brief      Probability price table generator
+///
+/// Compiling: gcc -std=c99 -o price_tablegen price_tablegen.c
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include 
+#include 
+
+// Make it compile without common.h.
+#define BUILDING_PRICE_TABLEGEN
+#define lzma_attr_visibility_hidden
+
+#include "range_common.h"
+#include "price.h"
+
+
+static uint32_t rc_prices[RC_PRICE_TABLE_SIZE];
+
+
+static void
+init_price_table(void)
+{
+	for (uint32_t i = (UINT32_C(1) << RC_MOVE_REDUCING_BITS) / 2;
+			i < RC_BIT_MODEL_TOTAL;
+			i += (UINT32_C(1) << RC_MOVE_REDUCING_BITS)) {
+		const uint32_t cycles_bits = RC_BIT_PRICE_SHIFT_BITS;
+		uint32_t w = i;
+		uint32_t bit_count = 0;
+
+		for (uint32_t j = 0; j < cycles_bits; ++j) {
+			w *= w;
+			bit_count <<= 1;
+
+			while (w >= (UINT32_C(1) << 16)) {
+				w >>= 1;
+				++bit_count;
+			}
+		}
+
+		rc_prices[i >> RC_MOVE_REDUCING_BITS]
+				= (RC_BIT_MODEL_TOTAL_BITS << cycles_bits)
+				- 15 - bit_count;
+	}
+
+	return;
+}
+
+
+static void
+print_price_table(void)
+{
+	// Split the SPDX string so that it won't accidentally match
+	// when tools search for the string.
+	printf("// SPDX" "-License-Identifier" ": 0BSD\n\n"
+		"// This file has been generated by price_tablegen.c.\n\n"
+		"#include \"range_encoder.h\"\n\n"
+		"const uint8_t lzma_rc_prices["
+		"RC_PRICE_TABLE_SIZE] = {");
+
+	const size_t array_size = sizeof(lzma_rc_prices)
+			/ sizeof(lzma_rc_prices[0]);
+	for (size_t i = 0; i < array_size; ++i) {
+		if (i % 8 == 0)
+			printf("\n\t");
+
+		printf("%4" PRIu32, rc_prices[i]);
+
+		if (i != array_size - 1)
+			printf(",");
+	}
+
+	printf("\n};\n");
+
+	return;
+}
+
+
+int
+main(void)
+{
+	init_price_table();
+	print_price_table();
+	return 0;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_common.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_common.h
new file mode 100644
index 00000000000..ac4dbe196f5
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_common.h
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       range_common.h
+/// \brief      Common things for range encoder and decoder
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_RANGE_COMMON_H
+#define LZMA_RANGE_COMMON_H
+
+// Skip common.h if building price_tablegen.c.
+#ifndef BUILDING_PRICE_TABLEGEN
+#	include "common.h"
+#endif
+
+
+///////////////
+// Constants //
+///////////////
+
+#define RC_SHIFT_BITS 8
+#define RC_TOP_BITS 24
+#define RC_TOP_VALUE (UINT32_C(1) << RC_TOP_BITS)
+#define RC_BIT_MODEL_TOTAL_BITS 11
+#define RC_BIT_MODEL_TOTAL (UINT32_C(1) << RC_BIT_MODEL_TOTAL_BITS)
+#define RC_MOVE_BITS 5
+
+
+////////////
+// Macros //
+////////////
+
+// Resets the probability so that both 0 and 1 have probability of 50 %
+#define bit_reset(prob) \
+	prob = RC_BIT_MODEL_TOTAL >> 1
+
+// This does the same for a complete bit tree.
+// (A tree represented as an array.)
+#define bittree_reset(probs, bit_levels) \
+	for (uint32_t bt_i = 0; bt_i < (1 << (bit_levels)); ++bt_i) \
+		bit_reset((probs)[bt_i])
+
+
+//////////////////////
+// Type definitions //
+//////////////////////
+
+/// \brief      Type of probabilities used with range coder
+///
+/// This needs to be at least 12-bit integer, so uint16_t is a logical choice.
+/// However, on some architecture and compiler combinations, a bigger type
+/// may give better speed, because the probability variables are accessed
+/// a lot. On the other hand, bigger probability type increases cache
+/// footprint, since there are 2 to 14 thousand probability variables in
+/// LZMA (assuming the limit of lc + lp <= 4; with lc + lp <= 12 there
+/// would be about 1.5 million variables).
+///
+/// With malicious files, the initialization speed of the LZMA decoder can
+/// become important. In that case, smaller probability variables mean that
+/// there is less bytes to write to RAM, which makes initialization faster.
+/// With big probability type, the initialization can become so slow that it
+/// can be a problem e.g. for email servers doing virus scanning.
+///
+/// I will be sticking to uint16_t unless some specific architectures
+/// are *much* faster (20-50 %) with uint32_t.
+///
+/// Update in 2024: The branchless C and x86-64 assembly was written so that
+/// probability is assumed to be uint16_t. (In contrast, LZMA SDK 23.01
+/// assembly supports both types.)
+typedef uint16_t probability;
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_decoder.h
new file mode 100644
index 00000000000..a8aca9077c1
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_decoder.h
@@ -0,0 +1,966 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       range_decoder.h
+/// \brief      Range Decoder
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_RANGE_DECODER_H
+#define LZMA_RANGE_DECODER_H
+
+#include "range_common.h"
+
+
+// Choose the range decoder variants to use using a bitmask.
+// If no bits are set, only the basic version is used.
+// If more than one version is selected for the same feature,
+// the last one on the list below is used.
+//
+// Bitwise-or of the following enable branchless C versions:
+//   0x01   normal bittrees
+//   0x02   fixed-sized reverse bittrees
+//   0x04   variable-sized reverse bittrees (not faster)
+//   0x08   matched literal (not faster)
+//
+// GCC & Clang compatible x86-64 inline assembly:
+//   0x010   normal bittrees
+//   0x020   fixed-sized reverse bittrees
+//   0x040   variable-sized reverse bittrees
+//   0x080   matched literal
+//   0x100   direct bits
+//
+// The default can be overridden at build time by defining
+// LZMA_RANGE_DECODER_CONFIG to the desired mask.
+//
+// 2024-02-22: Feedback from benchmarks:
+//   - Brancless C (0x003) can be better than basic on x86-64 but often it's
+//     slightly worse on other archs. Since asm is much better on x86-64,
+//     branchless C is not used at all.
+//   - With x86-64 asm, there are slight differences between GCC and Clang
+//     and different processors. Overall 0x1F0 seems to be the best choice.
+#ifndef LZMA_RANGE_DECODER_CONFIG
+#	if defined(__x86_64__) && !defined(__ILP32__) \
+			&& !defined(__NVCOMPILER) \
+			&& (defined(__GNUC__) || defined(__clang__))
+#		define LZMA_RANGE_DECODER_CONFIG 0x1F0
+#	else
+#		define LZMA_RANGE_DECODER_CONFIG 0
+#	endif
+#endif
+
+
+// Negative RC_BIT_MODEL_TOTAL but the lowest RC_MOVE_BITS are flipped.
+// This is useful for updating probability variables in branchless decoding:
+//
+//     uint32_t decoded_bit = ...;
+//     probability tmp = RC_BIT_MODEL_OFFSET;
+//     tmp &= decoded_bit - 1;
+//     prob -= (prob + tmp) >> RC_MOVE_BITS;
+#define RC_BIT_MODEL_OFFSET \
+	((UINT32_C(1) << RC_MOVE_BITS) - 1 - RC_BIT_MODEL_TOTAL)
+
+
+typedef struct {
+	uint32_t range;
+	uint32_t code;
+	uint32_t init_bytes_left;
+} lzma_range_decoder;
+
+
+/// Reads the first five bytes to initialize the range decoder.
+static inline lzma_ret
+rc_read_init(lzma_range_decoder *rc, const uint8_t *restrict in,
+		size_t *restrict in_pos, size_t in_size)
+{
+	while (rc->init_bytes_left > 0) {
+		if (*in_pos == in_size)
+			return LZMA_OK;
+
+		// The first byte is always 0x00. It could have been omitted
+		// in LZMA2 but it wasn't, so one byte is wasted in every
+		// LZMA2 chunk.
+		if (rc->init_bytes_left == 5 && in[*in_pos] != 0x00)
+			return LZMA_DATA_ERROR;
+
+		rc->code = (rc->code << 8) | in[*in_pos];
+		++*in_pos;
+		--rc->init_bytes_left;
+	}
+
+	return LZMA_STREAM_END;
+}
+
+
+/// Makes local copies of range decoder and *in_pos variables. Doing this
+/// improves speed significantly. The range decoder macros expect also
+/// variables 'in' and 'in_size' to be defined.
+#define rc_to_local(range_decoder, in_pos, fast_mode_in_required) \
+	lzma_range_decoder rc = range_decoder; \
+	const uint8_t *rc_in_ptr = in + (in_pos); \
+	const uint8_t *rc_in_end = in + in_size; \
+	const uint8_t *rc_in_fast_end \
+			= (rc_in_end - rc_in_ptr) <= (fast_mode_in_required) \
+			? rc_in_ptr \
+			: rc_in_end - (fast_mode_in_required); \
+	(void)rc_in_fast_end; /* Silence a warning with HAVE_SMALL. */ \
+	uint32_t rc_bound
+
+
+/// Evaluates to true if there is enough input remaining to use fast mode.
+#define rc_is_fast_allowed() (rc_in_ptr < rc_in_fast_end)
+
+
+/// Stores the local copes back to the range decoder structure.
+#define rc_from_local(range_decoder, in_pos) \
+do { \
+	range_decoder = rc; \
+	in_pos = (size_t)(rc_in_ptr - in); \
+} while (0)
+
+
+/// Resets the range decoder structure.
+#define rc_reset(range_decoder) \
+do { \
+	(range_decoder).range = UINT32_MAX; \
+	(range_decoder).code = 0; \
+	(range_decoder).init_bytes_left = 5; \
+} while (0)
+
+
+/// When decoding has been properly finished, rc.code is always zero unless
+/// the input stream is corrupt. So checking this can catch some corrupt
+/// files especially if they don't have any other integrity check.
+#define rc_is_finished(range_decoder) \
+	((range_decoder).code == 0)
+
+
+// Read the next input byte if needed.
+#define rc_normalize() \
+do { \
+	if (rc.range < RC_TOP_VALUE) { \
+		rc.range <<= RC_SHIFT_BITS; \
+		rc.code = (rc.code << RC_SHIFT_BITS) | *rc_in_ptr++; \
+	} \
+} while (0)
+
+
+/// If more input is needed but there is
+/// no more input available, "goto out" is used to jump out of the main
+/// decoder loop. The "_safe" macros are used in the Resumable decoder
+/// mode in order to save the sequence to continue decoding from that
+/// point later.
+#define rc_normalize_safe(seq) \
+do { \
+	if (rc.range < RC_TOP_VALUE) { \
+		if (rc_in_ptr == rc_in_end) { \
+			coder->sequence = seq; \
+			goto out; \
+		} \
+		rc.range <<= RC_SHIFT_BITS; \
+		rc.code = (rc.code << RC_SHIFT_BITS) | *rc_in_ptr++; \
+	} \
+} while (0)
+
+
+/// Start decoding a bit. This must be used together with rc_update_0()
+/// and rc_update_1():
+///
+///     rc_if_0(prob) {
+///         rc_update_0(prob);
+///         // Do something
+///     } else {
+///         rc_update_1(prob);
+///         // Do something else
+///     }
+///
+#define rc_if_0(prob) \
+	rc_normalize(); \
+	rc_bound = (rc.range >> RC_BIT_MODEL_TOTAL_BITS) * (prob); \
+	if (rc.code < rc_bound)
+
+
+#define rc_if_0_safe(prob, seq) \
+	rc_normalize_safe(seq); \
+	rc_bound = (rc.range >> RC_BIT_MODEL_TOTAL_BITS) * (prob); \
+	if (rc.code < rc_bound)
+
+
+/// Update the range decoder state and the used probability variable to
+/// match a decoded bit of 0.
+///
+/// The x86-64 assembly uses the commented method but it seems that,
+/// at least on x86-64, the first version is slightly faster as C code.
+#define rc_update_0(prob) \
+do { \
+	rc.range = rc_bound; \
+	prob += (RC_BIT_MODEL_TOTAL - (prob)) >> RC_MOVE_BITS; \
+	/* prob -= ((prob) + RC_BIT_MODEL_OFFSET) >> RC_MOVE_BITS; */ \
+} while (0)
+
+
+/// Update the range decoder state and the used probability variable to
+/// match a decoded bit of 1.
+#define rc_update_1(prob) \
+do { \
+	rc.range -= rc_bound; \
+	rc.code -= rc_bound; \
+	prob -= (prob) >> RC_MOVE_BITS; \
+} while (0)
+
+
+/// Decodes one bit and runs action0 or action1 depending on the decoded bit.
+/// This macro is used as the last step in bittree reverse decoders since
+/// those don't use "symbol" for anything else than indexing the probability
+/// arrays.
+#define rc_bit_last(prob, action0, action1) \
+do { \
+	rc_if_0(prob) { \
+		rc_update_0(prob); \
+		action0; \
+	} else { \
+		rc_update_1(prob); \
+		action1; \
+	} \
+} while (0)
+
+
+#define rc_bit_last_safe(prob, action0, action1, seq) \
+do { \
+	rc_if_0_safe(prob, seq) { \
+		rc_update_0(prob); \
+		action0; \
+	} else { \
+		rc_update_1(prob); \
+		action1; \
+	} \
+} while (0)
+
+
+/// Decodes one bit, updates "symbol", and runs action0 or action1 depending
+/// on the decoded bit.
+#define rc_bit(prob, action0, action1) \
+	rc_bit_last(prob, \
+		symbol <<= 1; action0, \
+		symbol = (symbol << 1) + 1; action1);
+
+
+#define rc_bit_safe(prob, action0, action1, seq) \
+	rc_bit_last_safe(prob, \
+		symbol <<= 1; action0, \
+		symbol = (symbol << 1) + 1; action1, \
+		seq);
+
+// Unroll fixed-sized bittree decoding.
+//
+// A compile-time constant in final_add can be used to get rid of the high bit
+// from symbol that is used for the array indexing (1U << bittree_bits).
+// final_add may also be used to add offset to the result (LZMA length
+// decoder does that).
+//
+// The reason to have final_add here is that in the asm code the addition
+// can be done for free: in x86-64 there is SBB instruction with -1 as
+// the immediate value, and final_add is combined with that value.
+#define rc_bittree_bit(prob) \
+	rc_bit(prob, , )
+
+#define rc_bittree3(probs, final_add) \
+do { \
+	symbol = 1; \
+	rc_bittree_bit(probs[symbol]); \
+	rc_bittree_bit(probs[symbol]); \
+	rc_bittree_bit(probs[symbol]); \
+	symbol += (uint32_t)(final_add); \
+} while (0)
+
+#define rc_bittree6(probs, final_add) \
+do { \
+	symbol = 1; \
+	rc_bittree_bit(probs[symbol]); \
+	rc_bittree_bit(probs[symbol]); \
+	rc_bittree_bit(probs[symbol]); \
+	rc_bittree_bit(probs[symbol]); \
+	rc_bittree_bit(probs[symbol]); \
+	rc_bittree_bit(probs[symbol]); \
+	symbol += (uint32_t)(final_add); \
+} while (0)
+
+#define rc_bittree8(probs, final_add) \
+do { \
+	symbol = 1; \
+	rc_bittree_bit(probs[symbol]); \
+	rc_bittree_bit(probs[symbol]); \
+	rc_bittree_bit(probs[symbol]); \
+	rc_bittree_bit(probs[symbol]); \
+	rc_bittree_bit(probs[symbol]); \
+	rc_bittree_bit(probs[symbol]); \
+	rc_bittree_bit(probs[symbol]); \
+	rc_bittree_bit(probs[symbol]); \
+	symbol += (uint32_t)(final_add); \
+} while (0)
+
+
+// Fixed-sized reverse bittree
+#define rc_bittree_rev4(probs) \
+do { \
+	symbol = 0; \
+	rc_bit_last(probs[symbol + 1], , symbol += 1); \
+	rc_bit_last(probs[symbol + 2], , symbol += 2); \
+	rc_bit_last(probs[symbol + 4], , symbol += 4); \
+	rc_bit_last(probs[symbol + 8], , symbol += 8); \
+} while (0)
+
+
+// Decode one bit from variable-sized reverse bittree. The loop is done
+// in the code that uses this macro. This could be changed if the assembly
+// version benefited from having the loop done in assembly but it didn't
+// seem so in early 2024.
+//
+// Also, if the loop was done here, the loop counter would likely be local
+// to the macro so that it wouldn't modify yet another input variable.
+// If a _safe version of a macro with a loop was done then a modifiable
+// input variable couldn't be avoided though.
+#define rc_bit_add_if_1(probs, dest, value_to_add_if_1) \
+	rc_bit(probs[symbol], \
+		, \
+		dest += value_to_add_if_1);
+
+
+// Matched literal
+#define decode_with_match_bit \
+		t_match_byte <<= 1; \
+		t_match_bit = t_match_byte & t_offset; \
+		t_subcoder_index = t_offset + t_match_bit + symbol; \
+		rc_bit(probs[t_subcoder_index], \
+				t_offset &= ~t_match_bit, \
+				t_offset &= t_match_bit)
+
+#define rc_matched_literal(probs_base_var, match_byte) \
+do { \
+	uint32_t t_match_byte = (match_byte); \
+	uint32_t t_match_bit; \
+	uint32_t t_subcoder_index; \
+	uint32_t t_offset = 0x100; \
+	symbol = 1; \
+	decode_with_match_bit; \
+	decode_with_match_bit; \
+	decode_with_match_bit; \
+	decode_with_match_bit; \
+	decode_with_match_bit; \
+	decode_with_match_bit; \
+	decode_with_match_bit; \
+	decode_with_match_bit; \
+} while (0)
+
+
+/// Decode a bit without using a probability.
+//
+// NOTE: GCC 13 and Clang/LLVM 16 can, at least on x86-64, optimize the bound
+// calculation to use an arithmetic right shift so there's no need to provide
+// the alternative code which, according to C99/C11/C23 6.3.1.3-p3 isn't
+// perfectly portable: rc_bound = (uint32_t)((int32_t)rc.code >> 31);
+#define rc_direct(dest, count_var) \
+do { \
+	dest = (dest << 1) + 1; \
+	rc_normalize(); \
+	rc.range >>= 1; \
+	rc.code -= rc.range; \
+	rc_bound = UINT32_C(0) - (rc.code >> 31); \
+	dest += rc_bound; \
+	rc.code += rc.range & rc_bound; \
+} while (--count_var > 0)
+
+
+
+#define rc_direct_safe(dest, count_var, seq) \
+do { \
+	rc_normalize_safe(seq); \
+	rc.range >>= 1; \
+	rc.code -= rc.range; \
+	rc_bound = UINT32_C(0) - (rc.code >> 31); \
+	rc.code += rc.range & rc_bound; \
+	dest = (dest << 1) + (rc_bound + 1); \
+} while (--count_var > 0)
+
+
+//////////////////
+// Branchless C //
+//////////////////
+
+/// Decode a bit using a branchless method. This reduces the number of
+/// mispredicted branches and thus can improve speed.
+#define rc_c_bit(prob, action_bit, action_neg) \
+do { \
+	probability *p = &(prob); \
+	rc_normalize(); \
+	rc_bound = (rc.range >> RC_BIT_MODEL_TOTAL_BITS) * *p; \
+	uint32_t rc_mask = rc.code >= rc_bound; /* rc_mask = decoded bit */ \
+	action_bit; /* action when rc_mask is 0 or 1 */ \
+	/* rc_mask becomes 0 if bit is 0 and 0xFFFFFFFF if bit is 1: */ \
+	rc_mask = 0U - rc_mask; \
+	rc.range &= rc_mask; /* If bit 0: set rc.range = 0 */ \
+	rc_bound ^= rc_mask; \
+	rc_bound -= rc_mask; /* If bit 1: rc_bound = 0U - rc_bound */ \
+	rc.range += rc_bound; \
+	rc_bound &= rc_mask; \
+	rc.code += rc_bound; \
+	action_neg; /* action when rc_mask is 0 or 0xFFFFFFFF */ \
+	rc_mask = ~rc_mask; /* If bit 0: all bits are set in rc_mask */ \
+	rc_mask &= RC_BIT_MODEL_OFFSET; \
+	*p -= (*p + rc_mask) >> RC_MOVE_BITS; \
+} while (0)
+
+
+// Testing on x86-64 give an impression that only the normal bittrees and
+// the fixed-sized reverse bittrees are worth the branchless C code.
+// It should be tested on other archs for which there isn't assembly code
+// in this file.
+
+// Using addition in "(symbol << 1) + rc_mask" allows use of x86 LEA
+// or RISC-V SH1ADD instructions. Compilers might infer it from
+// "(symbol << 1) | rc_mask" too if they see that mask is 0 or 1 but
+// the use of addition doesn't require such analysis from compilers.
+#if LZMA_RANGE_DECODER_CONFIG & 0x01
+#undef rc_bittree_bit
+#define rc_bittree_bit(prob) \
+	rc_c_bit(prob, \
+		symbol = (symbol << 1) + rc_mask, \
+		)
+#endif // LZMA_RANGE_DECODER_CONFIG & 0x01
+
+#if LZMA_RANGE_DECODER_CONFIG & 0x02
+#undef rc_bittree_rev4
+#define rc_bittree_rev4(probs) \
+do { \
+	symbol = 0; \
+	rc_c_bit(probs[symbol + 1], symbol += rc_mask, ); \
+	rc_c_bit(probs[symbol + 2], symbol += rc_mask << 1, ); \
+	rc_c_bit(probs[symbol + 4], symbol += rc_mask << 2, ); \
+	rc_c_bit(probs[symbol + 8], symbol += rc_mask << 3, ); \
+} while (0)
+#endif // LZMA_RANGE_DECODER_CONFIG & 0x02
+
+#if LZMA_RANGE_DECODER_CONFIG & 0x04
+#undef rc_bit_add_if_1
+#define rc_bit_add_if_1(probs, dest, value_to_add_if_1) \
+	rc_c_bit(probs[symbol], \
+		symbol = (symbol << 1) + rc_mask, \
+		dest += (value_to_add_if_1) & rc_mask)
+#endif // LZMA_RANGE_DECODER_CONFIG & 0x04
+
+
+#if LZMA_RANGE_DECODER_CONFIG & 0x08
+#undef decode_with_match_bit
+#define decode_with_match_bit \
+		t_match_byte <<= 1; \
+		t_match_bit = t_match_byte & t_offset; \
+		t_subcoder_index = t_offset + t_match_bit + symbol; \
+		rc_c_bit(probs[t_subcoder_index], \
+			symbol = (symbol << 1) + rc_mask, \
+			t_offset &= ~t_match_bit ^ rc_mask)
+#endif // LZMA_RANGE_DECODER_CONFIG & 0x08
+
+
+////////////
+// x86-64 //
+////////////
+
+#if LZMA_RANGE_DECODER_CONFIG & 0x1F0
+
+// rc_asm_y and rc_asm_n are used as arguments to macros to control which
+// strings to include or omit.
+#define rc_asm_y(str) str
+#define rc_asm_n(str)
+
+// There are a few possible variations for normalization.
+// This is the smallest variant which is also used by LZMA SDK.
+//
+//   - This has partial register write (the MOV from (%[in_ptr])).
+//
+//   - INC saves one byte in code size over ADD. False dependency on
+//     partial flags from INC shouldn't become a problem on any processor
+//     because the instructions after normalization don't read the flags
+//     until SUB which sets all flags.
+//
+#define rc_asm_normalize \
+	"cmp	%[top_value], %[range]\n\t" \
+	"jae	1f\n\t" \
+	"shl	%[shift_bits], %[code]\n\t" \
+	"mov	(%[in_ptr]), %b[code]\n\t" \
+	"shl	%[shift_bits], %[range]\n\t" \
+	"inc	%[in_ptr]\n" \
+	"1:\n"
+
+// rc_asm_calc(prob) is roughly equivalent to the C version of rc_if_0(prob)...
+//
+//     rc_bound = (rc.range >> RC_BIT_MODEL_TOTAL_BITS) * (prob);
+//     if (rc.code < rc_bound)
+//
+// ...but the bound is stored in "range":
+//
+//     t0 = range;
+//     range = (range >> RC_BIT_MODEL_TOTAL_BITS) * (prob);
+//     t0 -= range;
+//     t1 = code;
+//     code -= range;
+//
+// The carry flag (CF) from the last subtraction holds the negation of
+// the decoded bit (if CF==0 then the decoded bit is 1).
+// The values in t0 and t1 are needed for rc_update_0(prob) and
+// rc_update_1(prob). If the bit is 0, rc_update_0(prob)...
+//
+//     rc.range = rc_bound;
+//
+// ...has already been done but the "code -= range" has to be reverted using
+// the old value stored in t1. (Also, prob needs to be updated.)
+//
+// If the bit is 1, rc_update_1(prob)...
+//
+//     rc.range -= rc_bound;
+//     rc.code -= rc_bound;
+//
+// ...is already done for "code" but the value for "range" needs to be taken
+// from t0. (Also, prob needs to be updated here as well.)
+//
+// The assignments from t0 and t1 can be done in a branchless manner with CMOV
+// after the instructions from this macro. The CF from SUB tells which moves
+// are needed.
+#define rc_asm_calc(prob) \
+		"mov	%[range], %[t0]\n\t" \
+		"shr	%[bit_model_total_bits], %[range]\n\t" \
+		"imul	%[" prob "], %[range]\n\t" \
+		"sub	%[range], %[t0]\n\t" \
+		"mov	%[code], %[t1]\n\t" \
+		"sub	%[range], %[code]\n\t"
+
+// Also, prob needs to be updated: The update math depends on the decoded bit.
+// It can be expressed in a few slightly different ways but this is fairly
+// convenient here:
+//
+//     prob -= (prob + (bit ? 0 : RC_BIT_MODEL_OFFSET)) >> RC_MOVE_BITS;
+//
+// To do it in branchless way when the negation of the decoded bit is in CF,
+// both "prob" and "prob + RC_BIT_MODEL_OFFSET" are needed. Then the desired
+// value can be picked with CMOV. The addition can be done using LEA without
+// affecting CF.
+//
+// (This prob update method is a tiny bit different from LZMA SDK 23.01.
+// In the LZMA SDK a single register is reserved solely for a constant to
+// be used with CMOV when updating prob. That is fine since there are enough
+// free registers to do so. The method used here uses one fewer register,
+// which is valuable with inline assembly.)
+//
+// * * *
+//
+// In bittree decoding, each (unrolled) loop iteration decodes one bit
+// and needs one prob variable. To make it faster, the prob variable of
+// the iteration N+1 is loaded during iteration N. There are two possible
+// prob variables to choose from for N+1. Both are loaded from memory and
+// the correct one is chosen with CMOV using the same CF as is used for
+// other things described above.
+//
+// This preloading/prefetching requires an extra register. To avoid
+// useless moves from "preloaded prob register" to "current prob register",
+// the macros swap between the two registers for odd and even iterations.
+//
+// * * *
+//
+// Finally, the decoded bit has to be stored in "symbol". Since the negation
+// of the bit is in CF, this can be done with SBB: symbol -= CF - 1. That is,
+// if the decoded bit is 0 (CF==1) the operation is a no-op "symbol -= 0"
+// and when bit is 1 (CF==0) the operation is "symbol -= 0 - 1" which is
+// the same as "symbol += 1".
+//
+// The instructions for all things are intertwined for a few reasons:
+//   - freeing temporary registers for new use
+//   - not modifying CF too early
+//   - instruction scheduling
+//
+// The first and last iterations can cheat a little. For example,
+// on the first iteration "symbol" is known to start from 1 so it
+// doesn't need to be read; it can even be immediately initialized
+// to 2 to prepare for the second iteration of the loop.
+//
+// * * *
+//
+// a = number of the current prob variable (0 or 1)
+// b = number of the next prob variable (1 or 0)
+// *_only = rc_asm_y or _n to include or exclude code marked with them
+#define rc_asm_bittree(a, b, first_only, middle_only, last_only) \
+	first_only( \
+		"movzwl	2(%[probs_base]), %[prob" #a "]\n\t" \
+		"mov	$2, %[symbol]\n\t" \
+		"movzwl	4(%[probs_base]), %[prob" #b "]\n\t" \
+	) \
+	middle_only( \
+		/* Note the scaling of 4 instead of 2: */ \
+		"movzwl	(%[probs_base], %q[symbol], 4), %[prob" #b "]\n\t" \
+	) \
+	last_only( \
+		"add	%[symbol], %[symbol]\n\t" \
+	) \
+		\
+		rc_asm_normalize \
+		rc_asm_calc("prob" #a) \
+		\
+		"cmovae	%[t0], %[range]\n\t" \
+		\
+	first_only( \
+		"movzwl	6(%[probs_base]), %[t0]\n\t" \
+		"cmovae	%[t0], %[prob" #b "]\n\t" \
+	) \
+	middle_only( \
+		"movzwl	2(%[probs_base], %q[symbol], 4), %[t0]\n\t" \
+		"lea	(%q[symbol], %q[symbol]), %[symbol]\n\t" \
+		"cmovae	%[t0], %[prob" #b "]\n\t" \
+	) \
+		\
+		"lea	%c[bit_model_offset](%q[prob" #a "]), %[t0]\n\t" \
+		"cmovb	%[t1], %[code]\n\t" \
+		"mov	%[symbol], %[t1]\n\t" \
+		"cmovae	%[prob" #a "], %[t0]\n\t" \
+		\
+	first_only( \
+		"sbb	$-1, %[symbol]\n\t" \
+	) \
+	middle_only( \
+		"sbb	$-1, %[symbol]\n\t" \
+	) \
+	last_only( \
+		"sbb	%[last_sbb], %[symbol]\n\t" \
+	) \
+		\
+		"shr	%[move_bits], %[t0]\n\t" \
+		"sub	%[t0], %[prob" #a "]\n\t" \
+		/* Scaling of 1 instead of 2 because symbol <<= 1. */ \
+		"mov	%w[prob" #a "], (%[probs_base], %q[t1], 1)\n\t"
+
+// NOTE: The order of variables in __asm__ can affect speed and code size.
+#define rc_asm_bittree_n(probs_base_var, final_add, asm_str) \
+do { \
+	uint32_t t0; \
+	uint32_t t1; \
+	uint32_t t_prob0; \
+	uint32_t t_prob1; \
+	\
+	__asm__( \
+		asm_str \
+		: \
+		[range]     "+&r"(rc.range), \
+		[code]      "+&r"(rc.code), \
+		[t0]        "=&r"(t0), \
+		[t1]        "=&r"(t1), \
+		[prob0]     "=&r"(t_prob0), \
+		[prob1]     "=&r"(t_prob1), \
+		[symbol]    "=&r"(symbol), \
+		[in_ptr]    "+&r"(rc_in_ptr) \
+		: \
+		[probs_base]           "r"(probs_base_var), \
+		[last_sbb]             "n"(-1 - (final_add)), \
+		[top_value]            "n"(RC_TOP_VALUE), \
+		[shift_bits]           "n"(RC_SHIFT_BITS), \
+		[bit_model_total_bits] "n"(RC_BIT_MODEL_TOTAL_BITS), \
+		[bit_model_offset]     "n"(RC_BIT_MODEL_OFFSET), \
+		[move_bits]            "n"(RC_MOVE_BITS) \
+		: \
+		"cc", "memory"); \
+} while (0)
+
+
+#if LZMA_RANGE_DECODER_CONFIG & 0x010
+#undef rc_bittree3
+#define rc_bittree3(probs_base_var, final_add) \
+	rc_asm_bittree_n(probs_base_var, final_add, \
+		rc_asm_bittree(0, 1, rc_asm_y, rc_asm_n, rc_asm_n) \
+		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_y, rc_asm_n) \
+		rc_asm_bittree(0, 1, rc_asm_n, rc_asm_n, rc_asm_y) \
+	)
+
+#undef rc_bittree6
+#define rc_bittree6(probs_base_var, final_add) \
+	rc_asm_bittree_n(probs_base_var, final_add, \
+		rc_asm_bittree(0, 1, rc_asm_y, rc_asm_n, rc_asm_n) \
+		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_y, rc_asm_n) \
+		rc_asm_bittree(0, 1, rc_asm_n, rc_asm_y, rc_asm_n) \
+		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_y, rc_asm_n) \
+		rc_asm_bittree(0, 1, rc_asm_n, rc_asm_y, rc_asm_n) \
+		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_n, rc_asm_y) \
+	)
+
+#undef rc_bittree8
+#define rc_bittree8(probs_base_var, final_add) \
+	rc_asm_bittree_n(probs_base_var, final_add, \
+		rc_asm_bittree(0, 1, rc_asm_y, rc_asm_n, rc_asm_n) \
+		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_y, rc_asm_n) \
+		rc_asm_bittree(0, 1, rc_asm_n, rc_asm_y, rc_asm_n) \
+		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_y, rc_asm_n) \
+		rc_asm_bittree(0, 1, rc_asm_n, rc_asm_y, rc_asm_n) \
+		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_y, rc_asm_n) \
+		rc_asm_bittree(0, 1, rc_asm_n, rc_asm_y, rc_asm_n) \
+		rc_asm_bittree(1, 0, rc_asm_n, rc_asm_n, rc_asm_y) \
+	)
+#endif // LZMA_RANGE_DECODER_CONFIG & 0x010
+
+
+// Fixed-sized reverse bittree
+//
+// This uses the indexing that constructs the final value in symbol directly.
+// add    = 1,  2,   4,  8
+// dcur   = -,  4,   8, 16
+// dnext0 = 4,   8, 16,  -
+// dnext0 = 6,  12, 24,  -
+#define rc_asm_bittree_rev(a, b, add, dcur, dnext0, dnext1, \
+		first_only, middle_only, last_only) \
+	first_only( \
+		"movzwl	2(%[probs_base]), %[prob" #a "]\n\t" \
+		"xor	%[symbol], %[symbol]\n\t" \
+		"movzwl	4(%[probs_base]), %[prob" #b "]\n\t" \
+	) \
+	middle_only( \
+		"movzwl	" #dnext0 "(%[probs_base], %q[symbol], 2), " \
+			"%[prob" #b "]\n\t" \
+	) \
+		\
+		rc_asm_normalize \
+		rc_asm_calc("prob" #a) \
+		\
+		"cmovae	%[t0], %[range]\n\t" \
+		\
+	first_only( \
+		"movzwl	6(%[probs_base]), %[t0]\n\t" \
+		"cmovae	%[t0], %[prob" #b "]\n\t" \
+	) \
+	middle_only( \
+		"movzwl	" #dnext1 "(%[probs_base], %q[symbol], 2), %[t0]\n\t" \
+		"cmovae	%[t0], %[prob" #b "]\n\t" \
+	) \
+		\
+		"lea	" #add "(%q[symbol]), %[t0]\n\t" \
+		"cmovb	%[t1], %[code]\n\t" \
+	middle_only( \
+		"mov	%[symbol], %[t1]\n\t" \
+	) \
+	last_only( \
+		"mov	%[symbol], %[t1]\n\t" \
+	) \
+		"cmovae	%[t0], %[symbol]\n\t" \
+		"lea	%c[bit_model_offset](%q[prob" #a "]), %[t0]\n\t" \
+		"cmovae	%[prob" #a "], %[t0]\n\t" \
+		\
+		"shr	%[move_bits], %[t0]\n\t" \
+		"sub	%[t0], %[prob" #a "]\n\t" \
+	first_only( \
+		"mov	%w[prob" #a "], 2(%[probs_base])\n\t" \
+	) \
+	middle_only( \
+		"mov	%w[prob" #a "], " \
+			#dcur "(%[probs_base], %q[t1], 2)\n\t" \
+	) \
+	last_only( \
+		"mov	%w[prob" #a "], " \
+			#dcur "(%[probs_base], %q[t1], 2)\n\t" \
+	)
+
+#if LZMA_RANGE_DECODER_CONFIG & 0x020
+#undef rc_bittree_rev4
+#define rc_bittree_rev4(probs_base_var) \
+rc_asm_bittree_n(probs_base_var, 4, \
+	rc_asm_bittree_rev(0, 1, 1,  -,  4,  6, rc_asm_y, rc_asm_n, rc_asm_n) \
+	rc_asm_bittree_rev(1, 0, 2,  4,  8, 12, rc_asm_n, rc_asm_y, rc_asm_n) \
+	rc_asm_bittree_rev(0, 1, 4,  8, 16, 24, rc_asm_n, rc_asm_y, rc_asm_n) \
+	rc_asm_bittree_rev(1, 0, 8, 16,  -,  -, rc_asm_n, rc_asm_n, rc_asm_y) \
+)
+#endif // LZMA_RANGE_DECODER_CONFIG & 0x020
+
+
+#if LZMA_RANGE_DECODER_CONFIG & 0x040
+#undef rc_bit_add_if_1
+#define rc_bit_add_if_1(probs_base_var, dest_var, value_to_add_if_1) \
+do { \
+	uint32_t t0; \
+	uint32_t t1; \
+	uint32_t t2 = (value_to_add_if_1); \
+	uint32_t t_prob; \
+	uint32_t t_index; \
+	\
+	__asm__( \
+		"movzwl	(%[probs_base], %q[symbol], 2), %[prob]\n\t" \
+		"mov	%[symbol], %[index]\n\t" \
+		\
+		"add	%[dest], %[t2]\n\t" \
+		"add	%[symbol], %[symbol]\n\t" \
+		\
+		rc_asm_normalize \
+		rc_asm_calc("prob") \
+		\
+		"cmovae	%[t0], %[range]\n\t" \
+		"lea	%c[bit_model_offset](%q[prob]), %[t0]\n\t" \
+		"cmovb	%[t1], %[code]\n\t" \
+		"cmovae	%[prob], %[t0]\n\t" \
+		\
+		"cmovae	%[t2], %[dest]\n\t" \
+		"sbb	$-1, %[symbol]\n\t" \
+		\
+		"sar	%[move_bits], %[t0]\n\t" \
+		"sub	%[t0], %[prob]\n\t" \
+		"mov	%w[prob], (%[probs_base], %q[index], 2)" \
+		: \
+		[range]     "+&r"(rc.range), \
+		[code]      "+&r"(rc.code), \
+		[t0]        "=&r"(t0), \
+		[t1]        "=&r"(t1), \
+		[prob]      "=&r"(t_prob), \
+		[index]     "=&r"(t_index), \
+		[symbol]    "+&r"(symbol), \
+		[t2]        "+&r"(t2), \
+		[dest]      "+&r"(dest_var), \
+		[in_ptr]    "+&r"(rc_in_ptr) \
+		: \
+		[probs_base]           "r"(probs_base_var), \
+		[top_value]            "n"(RC_TOP_VALUE), \
+		[shift_bits]           "n"(RC_SHIFT_BITS), \
+		[bit_model_total_bits] "n"(RC_BIT_MODEL_TOTAL_BITS), \
+		[bit_model_offset]     "n"(RC_BIT_MODEL_OFFSET), \
+		[move_bits]            "n"(RC_MOVE_BITS) \
+		: \
+		"cc", "memory"); \
+} while (0)
+#endif // LZMA_RANGE_DECODER_CONFIG & 0x040
+
+
+// Literal decoding uses a normal 8-bit bittree but literal with match byte
+// is more complex in picking the probability variable from the correct
+// subtree. This doesn't use preloading/prefetching of the next prob because
+// there are four choices instead of two.
+//
+// FIXME? The first iteration starts with symbol = 1 so it could be optimized
+// by a tiny amount.
+#define rc_asm_matched_literal(nonlast_only) \
+		"add	%[offset], %[symbol]\n\t" \
+		"and	%[offset], %[match_bit]\n\t" \
+		"add	%[match_bit], %[symbol]\n\t" \
+		\
+		"movzwl	(%[probs_base], %q[symbol], 2), %[prob]\n\t" \
+		\
+		"add	%[symbol], %[symbol]\n\t" \
+		\
+	nonlast_only( \
+		"xor	%[match_bit], %[offset]\n\t" \
+		"add	%[match_byte], %[match_byte]\n\t" \
+	) \
+		\
+		rc_asm_normalize \
+		rc_asm_calc("prob") \
+		\
+		"cmovae	%[t0], %[range]\n\t" \
+		"lea	%c[bit_model_offset](%q[prob]), %[t0]\n\t" \
+		"cmovb	%[t1], %[code]\n\t" \
+		"mov	%[symbol], %[t1]\n\t" \
+		"cmovae	%[prob], %[t0]\n\t" \
+		\
+	nonlast_only( \
+		"cmovae	%[match_bit], %[offset]\n\t" \
+		"mov	%[match_byte], %[match_bit]\n\t" \
+	) \
+		\
+		"sbb	$-1, %[symbol]\n\t" \
+		\
+		"shr	%[move_bits], %[t0]\n\t" \
+		/* Undo symbol += match_bit + offset: */ \
+		"and	$0x1FF, %[symbol]\n\t" \
+		"sub	%[t0], %[prob]\n\t" \
+		\
+		/* Scaling of 1 instead of 2 because symbol <<= 1. */ \
+		"mov	%w[prob], (%[probs_base], %q[t1], 1)\n\t"
+
+
+#if LZMA_RANGE_DECODER_CONFIG & 0x080
+#undef rc_matched_literal
+#define rc_matched_literal(probs_base_var, match_byte_value) \
+do { \
+	uint32_t t0; \
+	uint32_t t1; \
+	uint32_t t_prob; \
+	uint32_t t_match_byte = (uint32_t)(match_byte_value) << 1; \
+	uint32_t t_match_bit = t_match_byte; \
+	uint32_t t_offset = 0x100; \
+	symbol = 1; \
+	\
+	__asm__( \
+		rc_asm_matched_literal(rc_asm_y) \
+		rc_asm_matched_literal(rc_asm_y) \
+		rc_asm_matched_literal(rc_asm_y) \
+		rc_asm_matched_literal(rc_asm_y) \
+		rc_asm_matched_literal(rc_asm_y) \
+		rc_asm_matched_literal(rc_asm_y) \
+		rc_asm_matched_literal(rc_asm_y) \
+		rc_asm_matched_literal(rc_asm_n) \
+		: \
+		[range]       "+&r"(rc.range), \
+		[code]        "+&r"(rc.code), \
+		[t0]          "=&r"(t0), \
+		[t1]          "=&r"(t1), \
+		[prob]        "=&r"(t_prob), \
+		[match_bit]   "+&r"(t_match_bit), \
+		[symbol]      "+&r"(symbol), \
+		[match_byte]  "+&r"(t_match_byte), \
+		[offset]      "+&r"(t_offset), \
+		[in_ptr]      "+&r"(rc_in_ptr) \
+		: \
+		[probs_base]           "r"(probs_base_var), \
+		[top_value]            "n"(RC_TOP_VALUE), \
+		[shift_bits]           "n"(RC_SHIFT_BITS), \
+		[bit_model_total_bits] "n"(RC_BIT_MODEL_TOTAL_BITS), \
+		[bit_model_offset]     "n"(RC_BIT_MODEL_OFFSET), \
+		[move_bits]            "n"(RC_MOVE_BITS) \
+		: \
+		"cc", "memory"); \
+} while (0)
+#endif // LZMA_RANGE_DECODER_CONFIG & 0x080
+
+
+// Doing the loop in asm instead of C seems to help a little.
+#if LZMA_RANGE_DECODER_CONFIG & 0x100
+#undef rc_direct
+#define rc_direct(dest_var, count_var) \
+do { \
+	uint32_t t0; \
+	uint32_t t1; \
+	\
+	__asm__( \
+		"2:\n\t" \
+		"add	%[dest], %[dest]\n\t" \
+		"lea	1(%q[dest]), %[t1]\n\t" \
+		\
+		rc_asm_normalize \
+		\
+		"shr	$1, %[range]\n\t" \
+		"mov	%[code], %[t0]\n\t" \
+		"sub	%[range], %[code]\n\t" \
+		"cmovns	%[t1], %[dest]\n\t" \
+		"cmovs	%[t0], %[code]\n\t" \
+		"dec	%[count]\n\t" \
+		"jnz	2b\n\t" \
+		: \
+		[range]       "+&r"(rc.range), \
+		[code]        "+&r"(rc.code), \
+		[t0]          "=&r"(t0), \
+		[t1]          "=&r"(t1), \
+		[dest]        "+&r"(dest_var), \
+		[count]       "+&r"(count_var), \
+		[in_ptr]      "+&r"(rc_in_ptr) \
+		: \
+		[top_value]   "n"(RC_TOP_VALUE), \
+		[shift_bits]  "n"(RC_SHIFT_BITS) \
+		: \
+		"cc", "memory"); \
+} while (0)
+#endif // LZMA_RANGE_DECODER_CONFIG & 0x100
+
+#endif // x86_64
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_encoder.h
new file mode 100644
index 00000000000..8f62a47ac0a
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/rangecoder/range_encoder.h
@@ -0,0 +1,349 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       range_encoder.h
+/// \brief      Range Encoder
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_RANGE_ENCODER_H
+#define LZMA_RANGE_ENCODER_H
+
+#include "range_common.h"
+#include "price.h"
+
+
+/// Maximum number of symbols that can be put pending into lzma_range_encoder
+/// structure between calls to lzma_rc_encode(). For LZMA, 48+5 is enough
+/// (match with big distance and length followed by range encoder flush).
+#define RC_SYMBOLS_MAX 53
+
+
+typedef struct {
+	uint64_t low;
+	uint64_t cache_size;
+	uint32_t range;
+	uint8_t cache;
+
+	/// Number of bytes written out by rc_encode() -> rc_shift_low()
+	uint64_t out_total;
+
+	/// Number of symbols in the tables
+	size_t count;
+
+	/// rc_encode()'s position in the tables
+	size_t pos;
+
+	/// Symbols to encode
+	enum {
+		RC_BIT_0,
+		RC_BIT_1,
+		RC_DIRECT_0,
+		RC_DIRECT_1,
+		RC_FLUSH,
+	} symbols[RC_SYMBOLS_MAX];
+
+	/// Probabilities associated with RC_BIT_0 or RC_BIT_1
+	probability *probs[RC_SYMBOLS_MAX];
+
+} lzma_range_encoder;
+
+
+static inline void
+rc_reset(lzma_range_encoder *rc)
+{
+	rc->low = 0;
+	rc->cache_size = 1;
+	rc->range = UINT32_MAX;
+	rc->cache = 0;
+	rc->out_total = 0;
+	rc->count = 0;
+	rc->pos = 0;
+}
+
+
+static inline void
+rc_forget(lzma_range_encoder *rc)
+{
+	// This must not be called when rc_encode() is partially done.
+	assert(rc->pos == 0);
+	rc->count = 0;
+}
+
+
+static inline void
+rc_bit(lzma_range_encoder *rc, probability *prob, uint32_t bit)
+{
+	rc->symbols[rc->count] = bit;
+	rc->probs[rc->count] = prob;
+	++rc->count;
+}
+
+
+static inline void
+rc_bittree(lzma_range_encoder *rc, probability *probs,
+		uint32_t bit_count, uint32_t symbol)
+{
+	uint32_t model_index = 1;
+
+	do {
+		const uint32_t bit = (symbol >> --bit_count) & 1;
+		rc_bit(rc, &probs[model_index], bit);
+		model_index = (model_index << 1) + bit;
+	} while (bit_count != 0);
+}
+
+
+static inline void
+rc_bittree_reverse(lzma_range_encoder *rc, probability *probs,
+		uint32_t bit_count, uint32_t symbol)
+{
+	uint32_t model_index = 1;
+
+	do {
+		const uint32_t bit = symbol & 1;
+		symbol >>= 1;
+		rc_bit(rc, &probs[model_index], bit);
+		model_index = (model_index << 1) + bit;
+	} while (--bit_count != 0);
+}
+
+
+static inline void
+rc_direct(lzma_range_encoder *rc,
+		uint32_t value, uint32_t bit_count)
+{
+	do {
+		rc->symbols[rc->count++]
+				= RC_DIRECT_0 + ((value >> --bit_count) & 1);
+	} while (bit_count != 0);
+}
+
+
+static inline void
+rc_flush(lzma_range_encoder *rc)
+{
+	for (size_t i = 0; i < 5; ++i)
+		rc->symbols[rc->count++] = RC_FLUSH;
+}
+
+
+static inline bool
+rc_shift_low(lzma_range_encoder *rc,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+{
+	if ((uint32_t)(rc->low) < (uint32_t)(0xFF000000)
+			|| (uint32_t)(rc->low >> 32) != 0) {
+		do {
+			if (*out_pos == out_size)
+				return true;
+
+			out[*out_pos] = rc->cache + (uint8_t)(rc->low >> 32);
+			++*out_pos;
+			++rc->out_total;
+			rc->cache = 0xFF;
+
+		} while (--rc->cache_size != 0);
+
+		rc->cache = (rc->low >> 24) & 0xFF;
+	}
+
+	++rc->cache_size;
+	rc->low = (rc->low & 0x00FFFFFF) << RC_SHIFT_BITS;
+
+	return false;
+}
+
+
+// NOTE: The last two arguments are uint64_t instead of size_t because in
+// the dummy version these refer to the size of the whole range-encoded
+// output stream, not just to the currently available output buffer space.
+static inline bool
+rc_shift_low_dummy(uint64_t *low, uint64_t *cache_size, uint8_t *cache,
+		uint64_t *out_pos, uint64_t out_size)
+{
+	if ((uint32_t)(*low) < (uint32_t)(0xFF000000)
+			|| (uint32_t)(*low >> 32) != 0) {
+		do {
+			if (*out_pos == out_size)
+				return true;
+
+			++*out_pos;
+			*cache = 0xFF;
+
+		} while (--*cache_size != 0);
+
+		*cache = (*low >> 24) & 0xFF;
+	}
+
+	++*cache_size;
+	*low = (*low & 0x00FFFFFF) << RC_SHIFT_BITS;
+
+	return false;
+}
+
+
+static inline bool
+rc_encode(lzma_range_encoder *rc,
+		uint8_t *out, size_t *out_pos, size_t out_size)
+{
+	assert(rc->count <= RC_SYMBOLS_MAX);
+
+	while (rc->pos < rc->count) {
+		// Normalize
+		if (rc->range < RC_TOP_VALUE) {
+			if (rc_shift_low(rc, out, out_pos, out_size))
+				return true;
+
+			rc->range <<= RC_SHIFT_BITS;
+		}
+
+		// Encode a bit
+		switch (rc->symbols[rc->pos]) {
+		case RC_BIT_0: {
+			probability prob = *rc->probs[rc->pos];
+			rc->range = (rc->range >> RC_BIT_MODEL_TOTAL_BITS)
+					* prob;
+			prob += (RC_BIT_MODEL_TOTAL - prob) >> RC_MOVE_BITS;
+			*rc->probs[rc->pos] = prob;
+			break;
+		}
+
+		case RC_BIT_1: {
+			probability prob = *rc->probs[rc->pos];
+			const uint32_t bound = prob * (rc->range
+					>> RC_BIT_MODEL_TOTAL_BITS);
+			rc->low += bound;
+			rc->range -= bound;
+			prob -= prob >> RC_MOVE_BITS;
+			*rc->probs[rc->pos] = prob;
+			break;
+		}
+
+		case RC_DIRECT_0:
+			rc->range >>= 1;
+			break;
+
+		case RC_DIRECT_1:
+			rc->range >>= 1;
+			rc->low += rc->range;
+			break;
+
+		case RC_FLUSH:
+			// Prevent further normalizations.
+			rc->range = UINT32_MAX;
+
+			// Flush the last five bytes (see rc_flush()).
+			do {
+				if (rc_shift_low(rc, out, out_pos, out_size))
+					return true;
+			} while (++rc->pos < rc->count);
+
+			// Reset the range encoder so we are ready to continue
+			// encoding if we weren't finishing the stream.
+			rc_reset(rc);
+			return false;
+
+		default:
+			assert(0);
+			break;
+		}
+
+		++rc->pos;
+	}
+
+	rc->count = 0;
+	rc->pos = 0;
+
+	return false;
+}
+
+
+static inline bool
+rc_encode_dummy(const lzma_range_encoder *rc, uint64_t out_limit)
+{
+	assert(rc->count <= RC_SYMBOLS_MAX);
+
+	uint64_t low = rc->low;
+	uint64_t cache_size = rc->cache_size;
+	uint32_t range = rc->range;
+	uint8_t cache = rc->cache;
+	uint64_t out_pos = rc->out_total;
+
+	size_t pos = rc->pos;
+
+	while (true) {
+		// Normalize
+		if (range < RC_TOP_VALUE) {
+			if (rc_shift_low_dummy(&low, &cache_size, &cache,
+					&out_pos, out_limit))
+				return true;
+
+			range <<= RC_SHIFT_BITS;
+		}
+
+		// This check is here because the normalization above must
+		// be done before flushing the last bytes.
+		if (pos == rc->count)
+			break;
+
+		// Encode a bit
+		switch (rc->symbols[pos]) {
+		case RC_BIT_0: {
+			probability prob = *rc->probs[pos];
+			range = (range >> RC_BIT_MODEL_TOTAL_BITS)
+					* prob;
+			break;
+		}
+
+		case RC_BIT_1: {
+			probability prob = *rc->probs[pos];
+			const uint32_t bound = prob * (range
+					>> RC_BIT_MODEL_TOTAL_BITS);
+			low += bound;
+			range -= bound;
+			break;
+		}
+
+		case RC_DIRECT_0:
+			range >>= 1;
+			break;
+
+		case RC_DIRECT_1:
+			range >>= 1;
+			low += range;
+			break;
+
+		case RC_FLUSH:
+		default:
+			assert(0);
+			break;
+		}
+
+		++pos;
+	}
+
+	// Flush the last bytes. This isn't in rc->symbols[] so we do
+	// it after the above loop to take into account the size of
+	// the flushing that will be done at the end of the stream.
+	for (pos = 0; pos < 5; ++pos) {
+		if (rc_shift_low_dummy(&low, &cache_size,
+				&cache, &out_pos, out_limit))
+			return true;
+	}
+
+	return false;
+}
+
+
+static inline uint64_t
+rc_pending(const lzma_range_encoder *rc)
+{
+	return rc->cache_size + 5 - 1;
+}
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm.c
new file mode 100644
index 00000000000..58acb2d11ad
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       arm.c
+/// \brief      Filter for ARM binaries
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_private.h"
+
+
+static size_t
+arm_code(void *simple lzma_attribute((__unused__)),
+		uint32_t now_pos, bool is_encoder,
+		uint8_t *buffer, size_t size)
+{
+	size_t i;
+	for (i = 0; i + 4 <= size; i += 4) {
+		if (buffer[i + 3] == 0xEB) {
+			uint32_t src = ((uint32_t)(buffer[i + 2]) << 16)
+					| ((uint32_t)(buffer[i + 1]) << 8)
+					| (uint32_t)(buffer[i + 0]);
+			src <<= 2;
+
+			uint32_t dest;
+			if (is_encoder)
+				dest = now_pos + (uint32_t)(i) + 8 + src;
+			else
+				dest = src - (now_pos + (uint32_t)(i) + 8);
+
+			dest >>= 2;
+			buffer[i + 2] = (dest >> 16);
+			buffer[i + 1] = (dest >> 8);
+			buffer[i + 0] = dest;
+		}
+	}
+
+	return i;
+}
+
+
+static lzma_ret
+arm_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters, bool is_encoder)
+{
+	return lzma_simple_coder_init(next, allocator, filters,
+			&arm_code, 0, 4, 4, is_encoder);
+}
+
+
+#ifdef HAVE_ENCODER_ARM
+extern lzma_ret
+lzma_simple_arm_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return arm_coder_init(next, allocator, filters, true);
+}
+#endif
+
+
+#ifdef HAVE_DECODER_ARM
+extern lzma_ret
+lzma_simple_arm_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return arm_coder_init(next, allocator, filters, false);
+}
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm64.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm64.c
new file mode 100644
index 00000000000..16c2f565f73
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/arm64.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       arm64.c
+/// \brief      Filter for ARM64 binaries
+///
+/// This converts ARM64 relative addresses in the BL and ADRP immediates
+/// to absolute values to increase redundancy of ARM64 code.
+///
+/// Converting B or ADR instructions was also tested but it's not useful.
+/// A majority of the jumps for the B instruction are very small (+/- 0xFF).
+/// These are typical for loops and if-statements. Encoding them to their
+/// absolute address reduces redundancy since many of the small relative
+/// jump values are repeated, but very few of the absolute addresses are.
+//
+//  Authors:    Lasse Collin
+//              Jia Tan
+//              Igor Pavlov
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_private.h"
+
+
+static size_t
+arm64_code(void *simple lzma_attribute((__unused__)),
+		uint32_t now_pos, bool is_encoder,
+		uint8_t *buffer, size_t size)
+{
+	size_t i;
+
+	// Clang 14.0.6 on x86-64 makes this four times bigger and 40 % slower
+	// with auto-vectorization that is enabled by default with -O2.
+	// Such vectorization bloat happens with -O2 when targeting ARM64 too
+	// but performance hasn't been tested.
+#ifdef __clang__
+#	pragma clang loop vectorize(disable)
+#endif
+	for (i = 0; i + 4 <= size; i += 4) {
+		uint32_t pc = (uint32_t)(now_pos + i);
+		uint32_t instr = read32le(buffer + i);
+
+		if ((instr >> 26) == 0x25) {
+			// BL instruction:
+			// The full 26-bit immediate is converted.
+			// The range is +/-128 MiB.
+			//
+			// Using the full range helps quite a lot with
+			// big executables. Smaller range would reduce false
+			// positives in non-code sections of the input though
+			// so this is a compromise that slightly favors big
+			// files. With the full range, only six bits of the 32
+			// need to match to trigger a conversion.
+			const uint32_t src = instr;
+			instr = 0x94000000;
+
+			pc >>= 2;
+			if (!is_encoder)
+				pc = 0U - pc;
+
+			instr |= (src + pc) & 0x03FFFFFF;
+			write32le(buffer + i, instr);
+
+		} else if ((instr & 0x9F000000) == 0x90000000) {
+			// ADRP instruction:
+			// Only values in the range +/-512 MiB are converted.
+			//
+			// Using less than the full +/-4 GiB range reduces
+			// false positives on non-code sections of the input
+			// while being excellent for executables up to 512 MiB.
+			// The positive effect of ADRP conversion is smaller
+			// than that of BL but it also doesn't hurt so much in
+			// non-code sections of input because, with +/-512 MiB
+			// range, nine bits of 32 need to match to trigger a
+			// conversion (two 10-bit match choices = 9 bits).
+			const uint32_t src = ((instr >> 29) & 3)
+					| ((instr >> 3) & 0x001FFFFC);
+
+			// With the addition only one branch is needed to
+			// check the +/- range. This is usually false when
+			// processing ARM64 code so branch prediction will
+			// handle it well in terms of performance.
+			//
+			//if ((src & 0x001E0000) != 0
+			// && (src & 0x001E0000) != 0x001E0000)
+			if ((src + 0x00020000) & 0x001C0000)
+				continue;
+
+			instr &= 0x9000001F;
+
+			pc >>= 12;
+			if (!is_encoder)
+				pc = 0U - pc;
+
+			const uint32_t dest = src + pc;
+			instr |= (dest & 3) << 29;
+			instr |= (dest & 0x0003FFFC) << 3;
+			instr |= (0U - (dest & 0x00020000)) & 0x00E00000;
+			write32le(buffer + i, instr);
+		}
+	}
+
+	return i;
+}
+
+
+static lzma_ret
+arm64_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters, bool is_encoder)
+{
+	return lzma_simple_coder_init(next, allocator, filters,
+			&arm64_code, 0, 4, 4, is_encoder);
+}
+
+
+#ifdef HAVE_ENCODER_ARM64
+extern lzma_ret
+lzma_simple_arm64_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return arm64_coder_init(next, allocator, filters, true);
+}
+#endif
+
+
+#ifdef HAVE_DECODER_ARM64
+extern lzma_ret
+lzma_simple_arm64_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return arm64_coder_init(next, allocator, filters, false);
+}
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/armthumb.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/armthumb.c
new file mode 100644
index 00000000000..f1eeca9b80f
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/armthumb.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       armthumb.c
+/// \brief      Filter for ARM-Thumb binaries
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_private.h"
+
+
+static size_t
+armthumb_code(void *simple lzma_attribute((__unused__)),
+		uint32_t now_pos, bool is_encoder,
+		uint8_t *buffer, size_t size)
+{
+	size_t i;
+	for (i = 0; i + 4 <= size; i += 2) {
+		if ((buffer[i + 1] & 0xF8) == 0xF0
+				&& (buffer[i + 3] & 0xF8) == 0xF8) {
+			uint32_t src = (((uint32_t)(buffer[i + 1]) & 7) << 19)
+				| ((uint32_t)(buffer[i + 0]) << 11)
+				| (((uint32_t)(buffer[i + 3]) & 7) << 8)
+				| (uint32_t)(buffer[i + 2]);
+
+			src <<= 1;
+
+			uint32_t dest;
+			if (is_encoder)
+				dest = now_pos + (uint32_t)(i) + 4 + src;
+			else
+				dest = src - (now_pos + (uint32_t)(i) + 4);
+
+			dest >>= 1;
+			buffer[i + 1] = 0xF0 | ((dest >> 19) & 0x7);
+			buffer[i + 0] = (dest >> 11);
+			buffer[i + 3] = 0xF8 | ((dest >> 8) & 0x7);
+			buffer[i + 2] = (dest);
+			i += 2;
+		}
+	}
+
+	return i;
+}
+
+
+static lzma_ret
+armthumb_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters, bool is_encoder)
+{
+	return lzma_simple_coder_init(next, allocator, filters,
+			&armthumb_code, 0, 4, 2, is_encoder);
+}
+
+
+#ifdef HAVE_ENCODER_ARMTHUMB
+extern lzma_ret
+lzma_simple_armthumb_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return armthumb_coder_init(next, allocator, filters, true);
+}
+#endif
+
+
+#ifdef HAVE_DECODER_ARMTHUMB
+extern lzma_ret
+lzma_simple_armthumb_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return armthumb_coder_init(next, allocator, filters, false);
+}
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/ia64.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/ia64.c
new file mode 100644
index 00000000000..50250140997
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/ia64.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       ia64.c
+/// \brief      Filter for IA64 (Itanium) binaries
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_private.h"
+
+
+static size_t
+ia64_code(void *simple lzma_attribute((__unused__)),
+		uint32_t now_pos, bool is_encoder,
+		uint8_t *buffer, size_t size)
+{
+	static const uint32_t BRANCH_TABLE[32] = {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		4, 4, 6, 6, 0, 0, 7, 7,
+		4, 4, 0, 0, 4, 4, 0, 0
+	};
+
+	size_t i;
+	for (i = 0; i + 16 <= size; i += 16) {
+		const uint32_t instr_template = buffer[i] & 0x1F;
+		const uint32_t mask = BRANCH_TABLE[instr_template];
+		uint32_t bit_pos = 5;
+
+		for (size_t slot = 0; slot < 3; ++slot, bit_pos += 41) {
+			if (((mask >> slot) & 1) == 0)
+				continue;
+
+			const size_t byte_pos = (bit_pos >> 3);
+			const uint32_t bit_res = bit_pos & 0x7;
+			uint64_t instruction = 0;
+
+			for (size_t j = 0; j < 6; ++j)
+				instruction += (uint64_t)(
+						buffer[i + j + byte_pos])
+						<< (8 * j);
+
+			uint64_t inst_norm = instruction >> bit_res;
+
+			if (((inst_norm >> 37) & 0xF) == 0x5
+					&& ((inst_norm >> 9) & 0x7) == 0
+					/* &&  (inst_norm & 0x3F)== 0 */
+					) {
+				uint32_t src = (uint32_t)(
+						(inst_norm >> 13) & 0xFFFFF);
+				src |= ((inst_norm >> 36) & 1) << 20;
+
+				src <<= 4;
+
+				uint32_t dest;
+				if (is_encoder)
+					dest = now_pos + (uint32_t)(i) + src;
+				else
+					dest = src - (now_pos + (uint32_t)(i));
+
+				dest >>= 4;
+
+				inst_norm &= ~((uint64_t)(0x8FFFFF) << 13);
+				inst_norm |= (uint64_t)(dest & 0xFFFFF) << 13;
+				inst_norm |= (uint64_t)(dest & 0x100000)
+						<< (36 - 20);
+
+				instruction &= (1U << bit_res) - 1;
+				instruction |= (inst_norm << bit_res);
+
+				for (size_t j = 0; j < 6; j++)
+					buffer[i + j + byte_pos] = (uint8_t)(
+							instruction
+							>> (8 * j));
+			}
+		}
+	}
+
+	return i;
+}
+
+
+static lzma_ret
+ia64_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters, bool is_encoder)
+{
+	return lzma_simple_coder_init(next, allocator, filters,
+			&ia64_code, 0, 16, 16, is_encoder);
+}
+
+
+#ifdef HAVE_ENCODER_IA64
+extern lzma_ret
+lzma_simple_ia64_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return ia64_coder_init(next, allocator, filters, true);
+}
+#endif
+
+
+#ifdef HAVE_DECODER_IA64
+extern lzma_ret
+lzma_simple_ia64_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return ia64_coder_init(next, allocator, filters, false);
+}
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/powerpc.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/powerpc.c
new file mode 100644
index 00000000000..ba6cfbef3ab
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/powerpc.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       powerpc.c
+/// \brief      Filter for PowerPC (big endian) binaries
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_private.h"
+
+
+static size_t
+powerpc_code(void *simple lzma_attribute((__unused__)),
+		uint32_t now_pos, bool is_encoder,
+		uint8_t *buffer, size_t size)
+{
+	size_t i;
+	for (i = 0; i + 4 <= size; i += 4) {
+		// PowerPC branch 6(48) 24(Offset) 1(Abs) 1(Link)
+		if ((buffer[i] >> 2) == 0x12
+				&& ((buffer[i + 3] & 3) == 1)) {
+
+			const uint32_t src
+				= (((uint32_t)(buffer[i + 0]) & 3) << 24)
+				| ((uint32_t)(buffer[i + 1]) << 16)
+				| ((uint32_t)(buffer[i + 2]) << 8)
+				| ((uint32_t)(buffer[i + 3]) & ~UINT32_C(3));
+
+			uint32_t dest;
+			if (is_encoder)
+				dest = now_pos + (uint32_t)(i) + src;
+			else
+				dest = src - (now_pos + (uint32_t)(i));
+
+			buffer[i + 0] = 0x48 | ((dest >> 24) &  0x03);
+			buffer[i + 1] = (dest >> 16);
+			buffer[i + 2] = (dest >> 8);
+			buffer[i + 3] &= 0x03;
+			buffer[i + 3] |= dest;
+		}
+	}
+
+	return i;
+}
+
+
+static lzma_ret
+powerpc_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters, bool is_encoder)
+{
+	return lzma_simple_coder_init(next, allocator, filters,
+			&powerpc_code, 0, 4, 4, is_encoder);
+}
+
+
+#ifdef HAVE_ENCODER_POWERPC
+extern lzma_ret
+lzma_simple_powerpc_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return powerpc_coder_init(next, allocator, filters, true);
+}
+#endif
+
+
+#ifdef HAVE_DECODER_POWERPC
+extern lzma_ret
+lzma_simple_powerpc_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return powerpc_coder_init(next, allocator, filters, false);
+}
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/riscv.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/riscv.c
new file mode 100644
index 00000000000..b18df8b637d
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/riscv.c
@@ -0,0 +1,755 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       riscv.c
+/// \brief      Filter for 32-bit/64-bit little/big endian RISC-V binaries
+///
+/// This converts program counter relative addresses in function calls
+/// (JAL, AUIPC+JALR), address calculation of functions and global
+/// variables (AUIPC+ADDI), loads (AUIPC+load), and stores (AUIPC+store).
+///
+/// For AUIPC+inst2 pairs, the paired instruction checking is fairly relaxed.
+/// The paired instruction opcode must only have its lowest two bits set,
+/// meaning it will convert any paired instruction that is not a 16-bit
+/// compressed instruction. This was shown to be enough to keep the number
+/// of false matches low while improving code size and speed.
+//
+//  Authors:    Lasse Collin
+//              Jia Tan
+//
+//  Special thanks:
+//
+//    - Chien Wong  provided a few early versions of RISC-V
+//      filter variants along with test files and benchmark results.
+//
+//    - Igor Pavlov helped a lot in the filter design, getting it both
+//      faster and smaller. The implementation here is still independently
+//      written, not based on LZMA SDK.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+
+RISC-V filtering
+================
+
+    RV32I and RV64I, possibly combined with extensions C, Zfh, F, D,
+    and Q, are identical enough that the same filter works for both.
+
+    The instruction encoding is always little endian, even on systems
+    with big endian data access. Thus the same filter works for both
+    endiannesses.
+
+    The following instructions have program counter relative
+    (pc-relative) behavior:
+
+JAL
+---
+
+    JAL is used for function calls (including tail calls) and
+    unconditional jumps within functions. Jumps within functions
+    aren't useful to filter because the absolute addresses often
+    appear only once or at most a few times. Tail calls and jumps
+    within functions look the same to a simple filter so neither
+    are filtered, that is, JAL x0 is ignored (the ABI name of the
+    register x0 is "zero").
+
+    Almost all calls store the return address to register x1 (ra)
+    or x5 (t0). To reduce false matches when the filter is applied
+    to non-code data, only the JAL instructions that use x1 or x5
+    are converted. JAL has pc-relative range of +/-1 MiB so longer
+    calls and jumps need another method (AUIPC+JALR).
+
+C.J and C.JAL
+-------------
+
+    C.J and C.JAL have pc-relative range of +/-2 KiB.
+
+    C.J is for tail calls and jumps within functions and isn't
+    filtered for the reasons mentioned for JAL x0.
+
+    C.JAL is an RV32C-only instruction. Its encoding overlaps with
+    RV64C-only C.ADDIW which is a common instruction. So if filtering
+    C.JAL was useful (it wasn't tested) then a separate filter would
+    be needed for RV32 and RV64. Also, false positives would be a
+    significant problem when the filter is applied to non-code data
+    because C.JAL needs only five bits to match. Thus, this filter
+    doesn't modify C.JAL instructions.
+
+BEQ, BNE, BLT, BGE, BLTU, BGEU, C.BEQZ, and C.BNEZ
+--------------------------------------------------
+
+    These are conditional branches with pc-relative range
+    of +/-4 KiB (+/-256 B for C.*). The absolute addresses often
+    appear only once and very short distances are the most common,
+    so filtering these instructions would make compression worse.
+
+AUIPC with rd != x0
+-------------------
+
+    AUIPC is paired with a second instruction (inst2) to do
+    pc-relative jumps, calls, loads, stores, and for taking
+    an address of a symbol. AUIPC has a 20-bit immediate and
+    the possible inst2 choices have a 12-bit immediate.
+
+    AUIPC stores pc + 20-bit signed immediate to a register.
+    The immediate encodes a multiple of 4 KiB so AUIPC itself
+    has a pc-relative range of +/-2 GiB. AUIPC does *NOT* set
+    the lowest 12 bits of the result to zero! This means that
+    the 12-bit immediate in inst2 cannot just include the lowest
+    12 bits of the absolute address as is; the immediate has to
+    compensate for the lowest 12 bits that AUIPC copies from the
+    program counter. This means that a good filter has to convert
+    not only AUIPC but also the paired inst2.
+
+    A strict filter would focus on filtering the following
+    AUIPC+inst2 pairs:
+
+      - AUIPC+JALR: Function calls, including tail calls.
+
+      - AUIPC+ADDI: Calculating the address of a function
+        or a global variable.
+
+      - AUIPC+load/store from the base instruction sets
+        (RV32I, RV64I) or from the floating point extensions
+        Zfh, F, D, and Q:
+          * RV32I: LB, LH, LW, LBU, LHU, SB, SH, SW
+          * RV64I has also: LD, LWU, SD
+          * Zfh: FLH, FSH
+          * F: FLW, FSW
+          * D: FLD, FSD
+          * Q: FLQ, FSQ
+
+    NOTE: AUIPC+inst2 can only be a pair if AUIPC's rd specifies
+    the same register as inst2's rs1.
+
+    Instead of strictly accepting only the above instructions as inst2,
+    this filter uses a much simpler condition: the lowest two bits of
+    inst2 must be set, that is, inst2 must not be a 16-bit compressed
+    instruction. So this will accept all 32-bit and possible future
+    extended instructions as a pair to AUIPC if the bits in AUIPC's
+    rd [11:7] match the bits [19:15] in inst2 (the bits that I-type and
+    S-type instructions use for rs1). Testing showed that this relaxed
+    condition for inst2 did not consistently or significantly affect
+    compression ratio but it reduced code size and improved speed.
+
+    Additionally, the paired instruction is always treated as an I-type
+    instruction. The S-type instructions used by stores (SB, SH, SW,
+    etc.) place the lowest 5 bits of the immediate in a different
+    location than I-type instructions. AUIPC+store pairs are less
+    common than other pairs, and testing showed that the extra
+    code required to handle S-type instructions was not worth the
+    compression ratio gained.
+
+    AUIPC+inst2 don't necessarily appear sequentially next to each
+    other although very often they do. Especially AUIPC+JALR are
+    sequential as that may allow instruction fusion in processors
+    (and perhaps help branch prediction as a fused AUIPC+JALR is
+    a direct branch while JALR alone is an indirect branch).
+
+    Clang 16 can generate code where AUIPC+inst2 is split:
+
+      - AUIPC is outside a loop and inst2 (load/store) is inside
+        the loop. This way the AUIPC instruction needs to be
+        executed only once.
+
+      - Load-modify-store may have AUIPC for the load and the same
+        AUIPC-result is used for the store too. This may get combined
+        with AUIPC being outside the loop.
+
+      - AUIPC is before a conditional branch and inst2 is hundreds
+        of bytes away at the branch target.
+
+      - Inner and outer pair:
+
+            auipc   a1,0x2f
+            auipc   a2,0x3d
+            ld      a2,-500(a2)
+            addi    a1,a1,-233
+
+      - Many split pairs with an untaken conditional branch between:
+
+            auipc   s9,0x1613   # Pair 1
+            auipc   s4,0x1613   # Pair 2
+            auipc   s6,0x1613   # Pair 3
+            auipc   s10,0x1613  # Pair 4
+            beqz    a5,a3baae
+            ld      a0,0(a6)
+            ld      a6,246(s9)  # Pair 1
+            ld      a1,250(s4)  # Pair 2
+            ld      a3,254(s6)  # Pair 3
+            ld      a4,258(s10) # Pair 4
+
+    It's not possible to find all split pairs in a filter like this.
+    At least in 2024, simple sequential pairs are 99 % of AUIPC uses
+    so filtering only such pairs gives good results and makes the
+    filter simpler. However, it's possible that future compilers will
+    produce different code where sequential pairs aren't as common.
+
+    This filter doesn't convert AUIPC instructions alone because:
+
+    (1) The conversion would be off-by-one (or off-by-4096) half the
+        time because the lowest 12 bits from inst2 (inst2_imm12)
+        aren't known. We only know that the absolute address is
+        pc + AUIPC_imm20 + [-2048, +2047] but there is no way to
+        know the exact 4096-byte multiple (or 4096 * n + 2048):
+        there are always two possibilities because AUIPC copies
+        the 12 lowest bits from pc instead of zeroing them.
+
+        NOTE: The sign-extension of inst2_imm12 adds a tiny bit
+        of extra complexity to AUIPC math in general but it's not
+        the reason for this problem. The sign-extension only changes
+        the relative position of the pc-relative 4096-byte window.
+
+    (2) Matching AUIPC instruction alone requires only seven bits.
+        When the filter is applied to non-code data, that leads
+        to many false positives which make compression worse.
+        As long as most AUIPC+inst2 pairs appear as two consecutive
+        instructions, converting only such pairs gives better results.
+
+    In assembly, AUIPC+inst2 tend to look like this:
+
+        # Call:
+        auipc   ra, 0x12345
+        jalr    ra, -42(ra)
+
+        # Tail call:
+        auipc   t1, 0x12345
+        jalr    zero, -42(t1)
+
+        # Getting the absolute address:
+        auipc   a0, 0x12345
+        addi    a0, a0, -42
+
+        # rd of inst2 isn't necessarily the same as rs1 even
+        # in cases where there is no reason to preserve rs1.
+        auipc   a0, 0x12345
+        addi    a1, a0, -42
+
+    As of 2024, 16-bit instructions from the C extension don't
+    appear as inst2. The RISC-V psABI doesn't list AUIPC+C.* as
+    a linker relaxation type explicitly but it's not disallowed
+    either. Usefulness is limited as most of the time the lowest
+    12 bits won't fit in a C instruction. This filter doesn't
+    support AUIPC+C.* combinations because this makes the filter
+    simpler, there are no test files, and it hopefully will never
+    be needed anyway.
+
+    (Compare AUIPC to ARM64 where ADRP does set the lowest 12 bits
+    to zero. The paired instruction has the lowest 12 bits of the
+    absolute address as is in a zero-extended immediate. Thus the
+    ARM64 filter doesn't need to care about the instructions that
+    are paired with ADRP. An off-by-4096 issue can still occur if
+    the code section isn't aligned with the filter's start offset.
+    It's not a problem with standalone ELF files but Windows PE
+    files need start_offset=3072 for best results. Also, a .tar
+    stores files with 512-byte alignment so most of the time it
+    won't be the best for ARM64.)
+
+AUIPC with rd == x0
+-------------------
+
+    AUIPC instructions with rd=x0 are reserved for HINTs in the base
+    instruction set. Such AUIPC instructions are never filtered.
+
+    As of January 2024, it seems likely that AUIPC with rd=x0 will
+    be used for landing pads (pseudoinstruction LPAD). LPAD is used
+    to mark valid targets for indirect jumps (for JALR), for example,
+    beginnings of functions. The 20-bit immediate in LPAD instruction
+    is a label, not a pc-relative address. Thus it would be
+    counterproductive to convert AUIPC instructions with rd=x0.
+
+    Often the next instruction after LPAD won't have rs1=x0 and thus
+    the filtering would be skipped for that reason alone. However,
+    it's not good to rely on this. For example, consider a function
+    that begins like this:
+
+        int foo(int i)
+        {
+            if (i <= 234) {
+                ...
+            }
+
+    A compiler may generate something like this:
+
+        lpad    0x54321
+        li      a5, 234
+        bgt     a0, a5, .L2
+
+    Converting the pseudoinstructions to raw instructions:
+
+        auipc   x0, 0x54321
+        addi    x15, x0, 234
+        blt     x15, x10, .L2
+
+    In this case the filter would undesirably convert the AUIPC+ADDI
+    pair if the filter didn't explicitly skip AUIPC instructions
+    that have rd=x0.
+
+*/
+
+
+#include "simple_private.h"
+
+
+// This checks two conditions at once:
+//    - AUIPC rd == inst2 rs1.
+//    - inst2 opcode has the lowest two bits set.
+//
+// The 8 bit left shift aligns the rd of AUIPC with the rs1 of inst2.
+// By XORing the registers, any non-zero value in those bits indicates the
+// registers are not equal and thus not an AUIPC pair. Subtracting 3 from
+// inst2 will zero out the first two opcode bits only when they are set.
+// The mask tests if any of the register or opcode bits are set (and thus
+// not an AUIPC pair).
+//
+// Alternative expression: (((((auipc) << 8) ^ (inst2)) & 0xF8003) != 3)
+#define NOT_AUIPC_PAIR(auipc, inst2) \
+	((((auipc) << 8) ^ ((inst2) - 3)) & 0xF8003)
+
+// This macro checks multiple conditions:
+//   (1) AUIPC rd [11:7] == x2 (special rd value).
+//   (2) AUIPC bits 12 and 13 set (the lowest two opcode bits of packed inst2).
+//   (3) inst2_rs1 doesn't equal x0 or x2 because the opposite
+//       conversion is only done when
+//       auipc_rd != x0 &&
+//       auipc_rd != x2 &&
+//       auipc_rd == inst2_rs1.
+//
+// The left-hand side takes care of (1) and (2).
+//   (a) The lowest 7 bits are already known to be AUIPC so subtracting 0x17
+//       makes those bits zeros.
+//   (b) If AUIPC rd equals x2, subtracting 0x100 makes bits [11:7] zeros.
+//       If rd doesn't equal x2, then there will be at least one non-zero bit
+//       and the next step (c) is irrelevant.
+//   (c) If the lowest two opcode bits of the packed inst2 are set in [13:12],
+//       then subtracting 0x3000 will make those bits zeros. Otherwise there
+//       will be at least one non-zero bit.
+//
+// The shift by 18 removes the high bits from the final '>=' comparison and
+// ensures that any non-zero result will be larger than any possible result
+// from the right-hand side of the comparison. The cast ensures that the
+// left-hand side didn't get promoted to a larger type than uint32_t.
+//
+// On the right-hand side, inst2_rs1 & 0x1D will be non-zero as long as
+// inst2_rs1 is not x0 or x2.
+//
+// The final '>=' comparison will make the expression true if:
+//   - The subtraction caused any bits to be set (special AUIPC rd value not
+//     used or inst2 opcode bits not set). (non-zero >= non-zero or 0)
+//   - The subtraction did not cause any bits to be set but inst2_rs1 was
+//     x0 or x2. (0 >= 0)
+#define NOT_SPECIAL_AUIPC(auipc, inst2_rs1) \
+	((uint32_t)(((auipc) - 0x3117) << 18) >= ((inst2_rs1) & 0x1D))
+
+
+// The encode and decode functions are split for this filter because of the
+// AUIPC+inst2 filtering. This filter design allows a decoder-only
+// implementation to be smaller than alternative designs.
+
+#ifdef HAVE_ENCODER_RISCV
+static size_t
+riscv_encode(void *simple lzma_attribute((__unused__)),
+		uint32_t now_pos,
+		bool is_encoder lzma_attribute((__unused__)),
+		uint8_t *buffer, size_t size)
+{
+	// Avoid using i + 8 <= size in the loop condition.
+	//
+	// NOTE: If there is a JAL in the last six bytes of the stream, it
+	// won't be converted. This is intentional to keep the code simpler.
+	if (size < 8)
+		return 0;
+
+	size -= 8;
+
+	size_t i;
+
+	// The loop is advanced by 2 bytes every iteration since the
+	// instruction stream may include 16-bit instructions (C extension).
+	for (i = 0; i <= size; i += 2) {
+		uint32_t inst = buffer[i];
+
+		if (inst == 0xEF) {
+			// JAL
+			const uint32_t b1 = buffer[i + 1];
+
+			// Only filter rd=x1(ra) and rd=x5(t0).
+			if ((b1 & 0x0D) != 0)
+				continue;
+
+			// The 20-bit immediate is in four pieces.
+			// The encoder stores it in big endian form
+			// since it improves compression slightly.
+			const uint32_t b2 = buffer[i + 2];
+			const uint32_t b3 = buffer[i + 3];
+			const uint32_t pc = now_pos + (uint32_t)i;
+
+// The following chart shows the highest three bytes of JAL, focusing on
+// the 20-bit immediate field [31:12]. The first row of numbers is the
+// bit position in a 32-bit little endian instruction. The second row of
+// numbers shows the order of the immediate field in a J-type instruction.
+// The last row is the bit number in each byte.
+//
+// To determine the amount to shift each bit, subtract the value in
+// the last row from the value in the second last row. If the number
+// is positive, shift left. If negative, shift right.
+//
+// For example, at the rightmost side of the chart, the bit 4 in b1 is
+// the bit 12 of the address. Thus that bit needs to be shifted left
+// by 12 - 4 = 8 bits to put it in the right place in the addr variable.
+//
+// NOTE: The immediate of a J-type instruction holds bits [20:1] of
+// the address. The bit [0] is always 0 and not part of the immediate.
+//
+// |          b3             |          b2             |          b1         |
+// | 31 30 29 28 27 26 25 24 | 23 22 21 20 19 18 17 16 | 15 14 13 12 x x x x |
+// | 20 10  9  8  7  6  5  4 |  3  2  1 11 19 18 17 16 | 15 14 13 12 x x x x |
+// |  7  6  5  4  3  2  1  0 |  7  6  5  4  3  2  1  0 |  7  6  5  4 x x x x |
+
+			uint32_t addr = ((b1 & 0xF0) << 8)
+					| ((b2 & 0x0F) << 16)
+					| ((b2 & 0x10) << 7)
+					| ((b2 & 0xE0) >> 4)
+					| ((b3 & 0x7F) << 4)
+					| ((b3 & 0x80) << 13);
+
+			addr += pc;
+
+			buffer[i + 1] = (uint8_t)((b1 & 0x0F)
+					| ((addr >> 13) & 0xF0));
+
+			buffer[i + 2] = (uint8_t)(addr >> 9);
+			buffer[i + 3] = (uint8_t)(addr >> 1);
+
+			// The "-2" is included because the for-loop will
+			// always increment by 2. In this case, we want to
+			// skip an extra 2 bytes since we used 4 bytes
+			// of input.
+			i += 4 - 2;
+
+		} else if ((inst & 0x7F) == 0x17) {
+			// AUIPC
+			inst |= (uint32_t)buffer[i + 1] << 8;
+			inst |= (uint32_t)buffer[i + 2] << 16;
+			inst |= (uint32_t)buffer[i + 3] << 24;
+
+			// Branch based on AUIPC's rd. The bitmask test does
+			// the same thing as this:
+			//
+			//     const uint32_t auipc_rd = (inst >> 7) & 0x1F;
+			//     if (auipc_rd != 0 && auipc_rd != 2) {
+ 			if (inst & 0xE80) {
+				// AUIPC's rd doesn't equal x0 or x2.
+
+				// Check if AUIPC+inst2 are a pair.
+				uint32_t inst2 = read32le(buffer + i + 4);
+
+				if (NOT_AUIPC_PAIR(inst, inst2)) {
+					// The NOT_AUIPC_PAIR macro allows
+					// a false AUIPC+AUIPC pair if the
+					// bits [19:15] (where rs1 would be)
+					// in the second AUIPC match the rd
+					// of the first AUIPC.
+					//
+					// We must skip enough forward so
+					// that the first two bytes of the
+					// second AUIPC cannot get converted.
+					// Such a conversion could make the
+					// current pair become a valid pair
+					// which would desync the decoder.
+					//
+					// Skipping six bytes is enough even
+					// though the above condition looks
+					// at the lowest four bits of the
+					// buffer[i + 6] too. This is safe
+					// because this filter never changes
+					// those bits if a conversion at
+					// that position is done.
+					i += 6 - 2;
+					continue;
+				}
+
+				// Convert AUIPC+inst2 to a special format:
+				//
+				//   - The lowest 7 bits [6:0] retain the
+				//     AUIPC opcode.
+				//
+				//   - The rd [11:7] is set to x2(sp). x2 is
+				//     used as the stack pointer so AUIPC with
+				//     rd=x2 should be very rare in real-world
+				//     executables.
+				//
+				//   - The remaining 20 bits [31:12] (that
+				//     normally hold the pc-relative immediate)
+				//     are used to store the lowest 20 bits of
+				//     inst2. That is, the 12-bit immediate of
+				//     inst2 is not included.
+				//
+				//   - The location of the original inst2 is
+				//     used to store the 32-bit absolute
+				//     address in big endian format. Compared
+				//     to the 20+12-bit split encoding, this
+				//     results in a longer uninterrupted
+				//     sequence of identical common bytes
+				//     when the same address is referred
+				//     with different instruction pairs
+				//     (like AUIPC+LD vs. AUIPC+ADDI) or
+				//     when the occurrences of the same
+				//     pair use different registers. When
+				//     referring to adjacent memory locations
+				//     (like function calls that go via the
+				//     ELF PLT), in big endian order only the
+				//     last 1-2 bytes differ; in little endian
+				//     the differing 1-2 bytes would be in the
+				//     middle of the 8-byte sequence.
+				//
+				// When reversing the transformation, the
+				// original rd of AUIPC can be restored
+				// from inst2's rs1 as they are required to
+				// be the same.
+
+				// Arithmetic right shift makes sign extension
+				// trivial but (1) it's implementation-defined
+				// behavior (C99/C11/C23 6.5.7-p5) and so is
+				// (2) casting unsigned to signed (6.3.1.3-p3).
+				//
+				// One can check for (1) with
+				//
+				//     if ((-1 >> 1) == -1) ...
+				//
+				// but (2) has to be checked from the
+				// compiler docs. GCC promises that (1)
+				// and (2) behave in the common expected
+				// way and thus
+				//
+				//     addr += (uint32_t)(
+				//             (int32_t)inst2 >> 20);
+				//
+				// does the same as the code below. But since
+				// the 100 % portable way is only a few bytes
+				// bigger code and there is no real speed
+				// difference, let's just use that, especially
+				// since the decoder doesn't need this at all.
+				uint32_t addr = inst & 0xFFFFF000;
+				addr += (inst2 >> 20)
+						- ((inst2 >> 19) & 0x1000);
+
+				addr += now_pos + (uint32_t)i;
+
+				// Construct the first 32 bits:
+				//   [6:0]    AUIPC opcode
+				//   [11:7]   Special AUIPC rd = x2
+				//   [31:12]  The lowest 20 bits of inst2
+				inst = 0x17 | (2 << 7) | (inst2 << 12);
+
+				write32le(buffer + i, inst);
+
+				// The second 32 bits store the absolute
+				// address in big endian order.
+				write32be(buffer + i + 4, addr);
+			} else {
+				// AUIPC's rd equals x0 or x2.
+				//
+				// x0 indicates a landing pad (LPAD).
+				// It's always skipped.
+				//
+				// AUIPC with rd == x2 is used for the special
+				// format as explained above. When the input
+				// contains a byte sequence that matches the
+				// special format, "fake" decoding must be
+				// done to keep the filter bijective (that
+				// is, safe to apply on arbitrary data).
+				//
+				// See the "x0 or x2" section in riscv_decode()
+				// for how the "real" decoding is done. The
+				// "fake" decoding is a simplified version
+				// of "real" decoding with the following
+				// differences (these reduce code size of
+				// the decoder):
+				// (1) The lowest 12 bits aren't sign-extended.
+				// (2) No address conversion is done.
+				// (3) Big endian format isn't used (the fake
+				//     address is in little endian order).
+
+				// Check if inst matches the special format.
+				const uint32_t fake_rs1 = inst >> 27;
+
+				if (NOT_SPECIAL_AUIPC(inst, fake_rs1)) {
+					i += 4 - 2;
+					continue;
+				}
+
+				const uint32_t fake_addr =
+						read32le(buffer + i + 4);
+
+				// Construct the second 32 bits:
+				//   [19:0]   Upper 20 bits from AUIPC
+				//   [31:20]  The lowest 12 bits of fake_addr
+				const uint32_t fake_inst2 = (inst >> 12)
+						| (fake_addr << 20);
+
+				// Construct new first 32 bits from:
+				//   [6:0]   AUIPC opcode
+				//   [11:7]  Fake AUIPC rd = fake_rs1
+				//   [31:12] The highest 20 bits of fake_addr
+				inst = 0x17 | (fake_rs1 << 7)
+					| (fake_addr & 0xFFFFF000);
+
+				write32le(buffer + i, inst);
+				write32le(buffer + i + 4, fake_inst2);
+			}
+
+			i += 8 - 2;
+		}
+	}
+
+	return i;
+}
+
+
+extern lzma_ret
+lzma_simple_riscv_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return lzma_simple_coder_init(next, allocator, filters,
+			&riscv_encode, 0, 8, 2, true);
+}
+#endif
+
+
+#ifdef HAVE_DECODER_RISCV
+static size_t
+riscv_decode(void *simple lzma_attribute((__unused__)),
+		uint32_t now_pos,
+		bool is_encoder lzma_attribute((__unused__)),
+		uint8_t *buffer, size_t size)
+{
+	if (size < 8)
+		return 0;
+
+	size -= 8;
+
+	size_t i;
+	for (i = 0; i <= size; i += 2) {
+		uint32_t inst = buffer[i];
+
+		if (inst == 0xEF) {
+			// JAL
+			const uint32_t b1 = buffer[i + 1];
+
+			// Only filter rd=x1(ra) and rd=x5(t0).
+			if ((b1 & 0x0D) != 0)
+				continue;
+
+			const uint32_t b2 = buffer[i + 2];
+			const uint32_t b3 = buffer[i + 3];
+			const uint32_t pc = now_pos + (uint32_t)i;
+
+// |          b3             |          b2             |          b1         |
+// | 31 30 29 28 27 26 25 24 | 23 22 21 20 19 18 17 16 | 15 14 13 12 x x x x |
+// | 20 10  9  8  7  6  5  4 |  3  2  1 11 19 18 17 16 | 15 14 13 12 x x x x |
+// |  7  6  5  4  3  2  1  0 |  7  6  5  4  3  2  1  0 |  7  6  5  4 x x x x |
+
+			uint32_t addr = ((b1 & 0xF0) << 13)
+					| (b2 << 9) | (b3 << 1);
+
+			addr -= pc;
+
+			buffer[i + 1] = (uint8_t)((b1 & 0x0F)
+					| ((addr >> 8) & 0xF0));
+
+			buffer[i + 2] = (uint8_t)(((addr >> 16) & 0x0F)
+					| ((addr >> 7) & 0x10)
+					| ((addr << 4) & 0xE0));
+
+			buffer[i + 3] = (uint8_t)(((addr >> 4) & 0x7F)
+					| ((addr >> 13) & 0x80));
+
+			i += 4 - 2;
+
+		} else if ((inst & 0x7F) == 0x17) {
+			// AUIPC
+			uint32_t inst2;
+
+			inst |= (uint32_t)buffer[i + 1] << 8;
+			inst |= (uint32_t)buffer[i + 2] << 16;
+			inst |= (uint32_t)buffer[i + 3] << 24;
+
+			if (inst & 0xE80) {
+				// AUIPC's rd doesn't equal x0 or x2.
+
+				// Check if it is a "fake" AUIPC+inst2 pair.
+				inst2 = read32le(buffer + i + 4);
+
+				if (NOT_AUIPC_PAIR(inst, inst2)) {
+					i += 6 - 2;
+					continue;
+				}
+
+				// Decode (or more like re-encode) the "fake"
+				// pair. The "fake" format doesn't do
+				// sign-extension, address conversion, or
+				// use big endian. (The use of little endian
+				// allows sharing the write32le() calls in
+				// the decoder to reduce code size when
+				// unaligned access isn't supported.)
+				uint32_t addr = inst & 0xFFFFF000;
+				addr += inst2 >> 20;
+
+				inst = 0x17 | (2 << 7) | (inst2 << 12);
+				inst2 = addr;
+			} else {
+				// AUIPC's rd equals x0 or x2.
+
+				// Check if inst matches the special format
+				// used by the encoder.
+				const uint32_t inst2_rs1 = inst >> 27;
+
+				if (NOT_SPECIAL_AUIPC(inst, inst2_rs1)) {
+					i += 4 - 2;
+					continue;
+				}
+
+				// Decode the "real" pair.
+				uint32_t addr = read32be(buffer + i + 4);
+
+				addr -= now_pos + (uint32_t)i;
+
+				// The second instruction:
+				//   - Get the lowest 20 bits from inst.
+				//   - Add the lowest 12 bits of the address
+				//     as the immediate field.
+				inst2 = (inst >> 12) | (addr << 20);
+
+				// AUIPC:
+				//   - rd is the same as inst2_rs1.
+				//   - The sign extension of the lowest 12 bits
+				//     must be taken into account.
+				inst = 0x17 | (inst2_rs1 << 7)
+					| ((addr + 0x800) & 0xFFFFF000);
+			}
+
+			// Both decoder branches write in little endian order.
+			write32le(buffer + i, inst);
+			write32le(buffer + i + 4, inst2);
+
+			i += 8 - 2;
+		}
+	}
+
+	return i;
+}
+
+
+extern lzma_ret
+lzma_simple_riscv_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return lzma_simple_coder_init(next, allocator, filters,
+			&riscv_decode, 0, 8, 2, false);
+}
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.c
new file mode 100644
index 00000000000..5cbfa822704
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       simple_coder.c
+/// \brief      Wrapper for simple filters
+///
+/// Simple filters don't change the size of the data i.e. number of bytes
+/// in equals the number of bytes out.
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_private.h"
+
+
+/// Copied or encodes/decodes more data to out[].
+static lzma_ret
+copy_or_code(lzma_simple_coder *coder, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size, lzma_action action)
+{
+	assert(!coder->end_was_reached);
+
+	if (coder->next.code == NULL) {
+		lzma_bufcpy(in, in_pos, in_size, out, out_pos, out_size);
+
+		// Check if end of stream was reached.
+		if (coder->is_encoder && action == LZMA_FINISH
+				&& *in_pos == in_size)
+			coder->end_was_reached = true;
+
+	} else {
+		// Call the next coder in the chain to provide us some data.
+		const lzma_ret ret = coder->next.code(
+				coder->next.coder, allocator,
+				in, in_pos, in_size,
+				out, out_pos, out_size, action);
+
+		if (ret == LZMA_STREAM_END) {
+			assert(!coder->is_encoder
+					|| action == LZMA_FINISH);
+			coder->end_was_reached = true;
+
+		} else if (ret != LZMA_OK) {
+			return ret;
+		}
+	}
+
+	return LZMA_OK;
+}
+
+
+static size_t
+call_filter(lzma_simple_coder *coder, uint8_t *buffer, size_t size)
+{
+	const size_t filtered = coder->filter(coder->simple,
+			coder->now_pos, coder->is_encoder,
+			buffer, size);
+	coder->now_pos += filtered;
+	return filtered;
+}
+
+
+static lzma_ret
+simple_code(void *coder_ptr, const lzma_allocator *allocator,
+		const uint8_t *restrict in, size_t *restrict in_pos,
+		size_t in_size, uint8_t *restrict out,
+		size_t *restrict out_pos, size_t out_size, lzma_action action)
+{
+	lzma_simple_coder *coder = coder_ptr;
+
+	// TODO: Add partial support for LZMA_SYNC_FLUSH. We can support it
+	// in cases when the filter is able to filter everything. With most
+	// simple filters it can be done at offset that is a multiple of 2,
+	// 4, or 16. With x86 filter, it needs good luck, and thus cannot
+	// be made to work predictably.
+	if (action == LZMA_SYNC_FLUSH)
+		return LZMA_OPTIONS_ERROR;
+
+	// Flush already filtered data from coder->buffer[] to out[].
+	if (coder->pos < coder->filtered) {
+		lzma_bufcpy(coder->buffer, &coder->pos, coder->filtered,
+				out, out_pos, out_size);
+
+		// If we couldn't flush all the filtered data, return to
+		// application immediately.
+		if (coder->pos < coder->filtered)
+			return LZMA_OK;
+
+		if (coder->end_was_reached) {
+			assert(coder->filtered == coder->size);
+			return LZMA_STREAM_END;
+		}
+	}
+
+	// If we get here, there is no filtered data left in the buffer.
+	coder->filtered = 0;
+
+	assert(!coder->end_was_reached);
+
+	// If there is more output space left than there is unfiltered data
+	// in coder->buffer[], flush coder->buffer[] to out[], and copy/code
+	// more data to out[] hopefully filling it completely. Then filter
+	// the data in out[]. This step is where most of the data gets
+	// filtered if the buffer sizes used by the application are reasonable.
+	const size_t out_avail = out_size - *out_pos;
+	const size_t buf_avail = coder->size - coder->pos;
+	if (out_avail > buf_avail || buf_avail == 0) {
+		// Store the old position so that we know from which byte
+		// to start filtering.
+		const size_t out_start = *out_pos;
+
+		// Flush data from coder->buffer[] to out[], but don't reset
+		// coder->pos and coder->size yet. This way the coder can be
+		// restarted if the next filter in the chain returns e.g.
+		// LZMA_MEM_ERROR.
+		//
+		// Do the memcpy() conditionally because out can be NULL
+		// (in which case buf_avail is always 0). Calling memcpy()
+		// with a null-pointer is undefined even if the third
+		// argument is 0.
+		if (buf_avail > 0)
+			memcpy(out + *out_pos, coder->buffer + coder->pos,
+					buf_avail);
+
+		*out_pos += buf_avail;
+
+		// Copy/Encode/Decode more data to out[].
+		{
+			const lzma_ret ret = copy_or_code(coder, allocator,
+					in, in_pos, in_size,
+					out, out_pos, out_size, action);
+			assert(ret != LZMA_STREAM_END);
+			if (ret != LZMA_OK)
+				return ret;
+		}
+
+		// Filter out[] unless there is nothing to filter.
+		// This way we avoid null pointer + 0 (undefined behavior)
+		// when out == NULL.
+		const size_t size = *out_pos - out_start;
+		const size_t filtered = size == 0 ? 0 : call_filter(
+				coder, out + out_start, size);
+
+		const size_t unfiltered = size - filtered;
+		assert(unfiltered <= coder->allocated / 2);
+
+		// Now we can update coder->pos and coder->size, because
+		// the next coder in the chain (if any) was successful.
+		coder->pos = 0;
+		coder->size = unfiltered;
+
+		if (coder->end_was_reached) {
+			// The last byte has been copied to out[] already.
+			// They are left as is.
+			coder->size = 0;
+
+		} else if (unfiltered > 0) {
+			// There is unfiltered data left in out[]. Copy it to
+			// coder->buffer[] and rewind *out_pos appropriately.
+			*out_pos -= unfiltered;
+			memcpy(coder->buffer, out + *out_pos, unfiltered);
+		}
+	} else if (coder->pos > 0) {
+		memmove(coder->buffer, coder->buffer + coder->pos, buf_avail);
+		coder->size -= coder->pos;
+		coder->pos = 0;
+	}
+
+	assert(coder->pos == 0);
+
+	// If coder->buffer[] isn't empty, try to fill it by copying/decoding
+	// more data. Then filter coder->buffer[] and copy the successfully
+	// filtered data to out[]. It is probable, that some filtered and
+	// unfiltered data will be left to coder->buffer[].
+	if (coder->size > 0) {
+		{
+			const lzma_ret ret = copy_or_code(coder, allocator,
+					in, in_pos, in_size,
+					coder->buffer, &coder->size,
+					coder->allocated, action);
+			assert(ret != LZMA_STREAM_END);
+			if (ret != LZMA_OK)
+				return ret;
+		}
+
+		coder->filtered = call_filter(
+				coder, coder->buffer, coder->size);
+
+		// Everything is considered to be filtered if coder->buffer[]
+		// contains the last bytes of the data.
+		if (coder->end_was_reached)
+			coder->filtered = coder->size;
+
+		// Flush as much as possible.
+		lzma_bufcpy(coder->buffer, &coder->pos, coder->filtered,
+				out, out_pos, out_size);
+	}
+
+	// Check if we got everything done.
+	if (coder->end_was_reached && coder->pos == coder->size)
+		return LZMA_STREAM_END;
+
+	return LZMA_OK;
+}
+
+
+static void
+simple_coder_end(void *coder_ptr, const lzma_allocator *allocator)
+{
+	lzma_simple_coder *coder = coder_ptr;
+	lzma_next_end(&coder->next, allocator);
+	lzma_free(coder->simple, allocator);
+	lzma_free(coder, allocator);
+	return;
+}
+
+
+static lzma_ret
+simple_coder_update(void *coder_ptr, const lzma_allocator *allocator,
+		const lzma_filter *filters_null lzma_attribute((__unused__)),
+		const lzma_filter *reversed_filters)
+{
+	lzma_simple_coder *coder = coder_ptr;
+
+	// No update support, just call the next filter in the chain.
+	return lzma_next_filter_update(
+			&coder->next, allocator, reversed_filters + 1);
+}
+
+
+extern lzma_ret
+lzma_simple_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters,
+		size_t (*filter)(void *simple, uint32_t now_pos,
+			bool is_encoder, uint8_t *buffer, size_t size),
+		size_t simple_size, size_t unfiltered_max,
+		uint32_t alignment, bool is_encoder)
+{
+	// Allocate memory for the lzma_simple_coder structure if needed.
+	lzma_simple_coder *coder = next->coder;
+	if (coder == NULL) {
+		// Here we allocate space also for the temporary buffer. We
+		// need twice the size of unfiltered_max, because then it
+		// is always possible to filter at least unfiltered_max bytes
+		// more data in coder->buffer[] if it can be filled completely.
+		coder = lzma_alloc(sizeof(lzma_simple_coder)
+				+ 2 * unfiltered_max, allocator);
+		if (coder == NULL)
+			return LZMA_MEM_ERROR;
+
+		next->coder = coder;
+		next->code = &simple_code;
+		next->end = &simple_coder_end;
+		next->update = &simple_coder_update;
+
+		coder->next = LZMA_NEXT_CODER_INIT;
+		coder->filter = filter;
+		coder->allocated = 2 * unfiltered_max;
+
+		// Allocate memory for filter-specific data structure.
+		if (simple_size > 0) {
+			coder->simple = lzma_alloc(simple_size, allocator);
+			if (coder->simple == NULL)
+				return LZMA_MEM_ERROR;
+		} else {
+			coder->simple = NULL;
+		}
+	}
+
+	if (filters[0].options != NULL) {
+		const lzma_options_bcj *simple = filters[0].options;
+		coder->now_pos = simple->start_offset;
+		if (coder->now_pos & (alignment - 1))
+			return LZMA_OPTIONS_ERROR;
+	} else {
+		coder->now_pos = 0;
+	}
+
+	// Reset variables.
+	coder->is_encoder = is_encoder;
+	coder->end_was_reached = false;
+	coder->pos = 0;
+	coder->filtered = 0;
+	coder->size = 0;
+
+	return lzma_next_filter_init(&coder->next, allocator, filters + 1);
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.h
new file mode 100644
index 00000000000..2b762d50071
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_coder.h
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       simple_coder.h
+/// \brief      Wrapper for simple filters
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_SIMPLE_CODER_H
+#define LZMA_SIMPLE_CODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_simple_x86_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+extern lzma_ret lzma_simple_x86_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+
+extern lzma_ret lzma_simple_powerpc_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+extern lzma_ret lzma_simple_powerpc_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+
+extern lzma_ret lzma_simple_ia64_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+extern lzma_ret lzma_simple_ia64_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+
+extern lzma_ret lzma_simple_arm_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+extern lzma_ret lzma_simple_arm_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+
+extern lzma_ret lzma_simple_armthumb_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+extern lzma_ret lzma_simple_armthumb_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+
+extern lzma_ret lzma_simple_arm64_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+extern lzma_ret lzma_simple_arm64_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+
+extern lzma_ret lzma_simple_sparc_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+extern lzma_ret lzma_simple_sparc_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+
+extern lzma_ret lzma_simple_riscv_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+extern lzma_ret lzma_simple_riscv_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.c
new file mode 100644
index 00000000000..d9820ee8ed2
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       simple_decoder.c
+/// \brief      Properties decoder for simple filters
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_decoder.h"
+
+
+extern lzma_ret
+lzma_simple_props_decode(void **options, const lzma_allocator *allocator,
+		const uint8_t *props, size_t props_size)
+{
+	if (props_size == 0)
+		return LZMA_OK;
+
+	if (props_size != 4)
+		return LZMA_OPTIONS_ERROR;
+
+	lzma_options_bcj *opt = lzma_alloc(
+			sizeof(lzma_options_bcj), allocator);
+	if (opt == NULL)
+		return LZMA_MEM_ERROR;
+
+	opt->start_offset = read32le(props);
+
+	// Don't leave an options structure allocated if start_offset is zero.
+	if (opt->start_offset == 0)
+		lzma_free(opt, allocator);
+	else
+		*options = opt;
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.h
new file mode 100644
index 00000000000..2ae87bb8632
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_decoder.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       simple_decoder.h
+/// \brief      Properties decoder for simple filters
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_SIMPLE_DECODER_H
+#define LZMA_SIMPLE_DECODER_H
+
+#include "simple_coder.h"
+
+extern lzma_ret lzma_simple_props_decode(
+		void **options, const lzma_allocator *allocator,
+		const uint8_t *props, size_t props_size);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.c
new file mode 100644
index 00000000000..d1f35096e2a
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       simple_encoder.c
+/// \brief      Properties encoder for simple filters
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_encoder.h"
+
+
+extern lzma_ret
+lzma_simple_props_size(uint32_t *size, const void *options)
+{
+	const lzma_options_bcj *const opt = options;
+	*size = (opt == NULL || opt->start_offset == 0) ? 0 : 4;
+	return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_simple_props_encode(const void *options, uint8_t *out)
+{
+	const lzma_options_bcj *const opt = options;
+
+	// The default start offset is zero, so we don't need to store any
+	// options unless the start offset is non-zero.
+	if (opt == NULL || opt->start_offset == 0)
+		return LZMA_OK;
+
+	write32le(out, opt->start_offset);
+
+	return LZMA_OK;
+}
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.h
new file mode 100644
index 00000000000..bf5edbb1c3f
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_encoder.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       simple_encoder.c
+/// \brief      Properties encoder for simple filters
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_SIMPLE_ENCODER_H
+#define LZMA_SIMPLE_ENCODER_H
+
+#include "simple_coder.h"
+
+
+extern lzma_ret lzma_simple_props_size(uint32_t *size, const void *options);
+
+extern lzma_ret lzma_simple_props_encode(const void *options, uint8_t *out);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_private.h b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_private.h
new file mode 100644
index 00000000000..7aa360ff49e
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/simple_private.h
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       simple_private.h
+/// \brief      Private definitions for so called simple filters
+//
+//  Author:     Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_SIMPLE_PRIVATE_H
+#define LZMA_SIMPLE_PRIVATE_H
+
+#include "simple_coder.h"
+
+
+typedef struct {
+	/// Next filter in the chain
+	lzma_next_coder next;
+
+	/// True if the next coder in the chain has returned LZMA_STREAM_END.
+	bool end_was_reached;
+
+	/// True if filter() should encode the data; false to decode.
+	/// Currently all simple filters use the same function for encoding
+	/// and decoding, because the difference between encoders and decoders
+	/// is very small.
+	bool is_encoder;
+
+	/// Pointer to filter-specific function, which does
+	/// the actual filtering.
+	size_t (*filter)(void *simple, uint32_t now_pos,
+			bool is_encoder, uint8_t *buffer, size_t size);
+
+	/// Pointer to filter-specific data, or NULL if filter doesn't need
+	/// any extra data.
+	void *simple;
+
+	/// The lowest 32 bits of the current position in the data. Most
+	/// filters need this to do conversions between absolute and relative
+	/// addresses.
+	uint32_t now_pos;
+
+	/// Size of the memory allocated for the buffer.
+	size_t allocated;
+
+	/// Flushing position in the temporary buffer. buffer[pos] is the
+	/// next byte to be copied to out[].
+	size_t pos;
+
+	/// buffer[filtered] is the first unfiltered byte. When pos is smaller
+	/// than filtered, there is unflushed filtered data in the buffer.
+	size_t filtered;
+
+	/// Total number of bytes (both filtered and unfiltered) currently
+	/// in the temporary buffer.
+	size_t size;
+
+	/// Temporary buffer
+	uint8_t buffer[];
+} lzma_simple_coder;
+
+
+extern lzma_ret lzma_simple_coder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters,
+		size_t (*filter)(void *simple, uint32_t now_pos,
+			bool is_encoder, uint8_t *buffer, size_t size),
+		size_t simple_size, size_t unfiltered_max,
+		uint32_t alignment, bool is_encoder);
+
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/sparc.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/sparc.c
new file mode 100644
index 00000000000..e8ad285a192
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/sparc.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       sparc.c
+/// \brief      Filter for SPARC binaries
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_private.h"
+
+
+static size_t
+sparc_code(void *simple lzma_attribute((__unused__)),
+		uint32_t now_pos, bool is_encoder,
+		uint8_t *buffer, size_t size)
+{
+	size_t i;
+	for (i = 0; i + 4 <= size; i += 4) {
+
+		if ((buffer[i] == 0x40 && (buffer[i + 1] & 0xC0) == 0x00)
+				|| (buffer[i] == 0x7F
+				&& (buffer[i + 1] & 0xC0) == 0xC0)) {
+
+			uint32_t src = ((uint32_t)buffer[i + 0] << 24)
+					| ((uint32_t)buffer[i + 1] << 16)
+					| ((uint32_t)buffer[i + 2] << 8)
+					| ((uint32_t)buffer[i + 3]);
+
+			src <<= 2;
+
+			uint32_t dest;
+			if (is_encoder)
+				dest = now_pos + (uint32_t)(i) + src;
+			else
+				dest = src - (now_pos + (uint32_t)(i));
+
+			dest >>= 2;
+
+			dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF)
+					| (dest & 0x3FFFFF)
+					| 0x40000000;
+
+			buffer[i + 0] = (uint8_t)(dest >> 24);
+			buffer[i + 1] = (uint8_t)(dest >> 16);
+			buffer[i + 2] = (uint8_t)(dest >> 8);
+			buffer[i + 3] = (uint8_t)(dest);
+		}
+	}
+
+	return i;
+}
+
+
+static lzma_ret
+sparc_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters, bool is_encoder)
+{
+	return lzma_simple_coder_init(next, allocator, filters,
+			&sparc_code, 0, 4, 4, is_encoder);
+}
+
+
+#ifdef HAVE_ENCODER_SPARC
+extern lzma_ret
+lzma_simple_sparc_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return sparc_coder_init(next, allocator, filters, true);
+}
+#endif
+
+
+#ifdef HAVE_DECODER_SPARC
+extern lzma_ret
+lzma_simple_sparc_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return sparc_coder_init(next, allocator, filters, false);
+}
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/x86.c b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/x86.c
new file mode 100644
index 00000000000..f216231f2d1
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/simple/x86.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       x86.c
+/// \brief      Filter for x86 binaries (BCJ filter)
+///
+//  Authors:    Igor Pavlov
+//              Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_private.h"
+
+
+#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
+
+
+typedef struct {
+	uint32_t prev_mask;
+	uint32_t prev_pos;
+} lzma_simple_x86;
+
+
+static size_t
+x86_code(void *simple_ptr, uint32_t now_pos, bool is_encoder,
+		uint8_t *buffer, size_t size)
+{
+	static const uint32_t MASK_TO_BIT_NUMBER[5] = { 0, 1, 2, 2, 3 };
+
+	lzma_simple_x86 *simple = simple_ptr;
+	uint32_t prev_mask = simple->prev_mask;
+	uint32_t prev_pos = simple->prev_pos;
+
+	if (size < 5)
+		return 0;
+
+	if (now_pos - prev_pos > 5)
+		prev_pos = now_pos - 5;
+
+	const size_t limit = size - 5;
+	size_t buffer_pos = 0;
+
+	while (buffer_pos <= limit) {
+		uint8_t b = buffer[buffer_pos];
+		if (b != 0xE8 && b != 0xE9) {
+			++buffer_pos;
+			continue;
+		}
+
+		const uint32_t offset = now_pos + (uint32_t)(buffer_pos)
+				- prev_pos;
+		prev_pos = now_pos + (uint32_t)(buffer_pos);
+
+		if (offset > 5) {
+			prev_mask = 0;
+		} else {
+			for (uint32_t i = 0; i < offset; ++i) {
+				prev_mask &= 0x77;
+				prev_mask <<= 1;
+			}
+		}
+
+		b = buffer[buffer_pos + 4];
+
+		if (Test86MSByte(b) && (prev_mask >> 1) <= 4
+			&& (prev_mask >> 1) != 3) {
+
+			uint32_t src = ((uint32_t)(b) << 24)
+				| ((uint32_t)(buffer[buffer_pos + 3]) << 16)
+				| ((uint32_t)(buffer[buffer_pos + 2]) << 8)
+				| (buffer[buffer_pos + 1]);
+
+			uint32_t dest;
+			while (true) {
+				if (is_encoder)
+					dest = src + (now_pos + (uint32_t)(
+							buffer_pos) + 5);
+				else
+					dest = src - (now_pos + (uint32_t)(
+							buffer_pos) + 5);
+
+				if (prev_mask == 0)
+					break;
+
+				const uint32_t i = MASK_TO_BIT_NUMBER[
+						prev_mask >> 1];
+
+				b = (uint8_t)(dest >> (24 - i * 8));
+
+				if (!Test86MSByte(b))
+					break;
+
+				src = dest ^ ((1U << (32 - i * 8)) - 1);
+			}
+
+			buffer[buffer_pos + 4]
+					= (uint8_t)(~(((dest >> 24) & 1) - 1));
+			buffer[buffer_pos + 3] = (uint8_t)(dest >> 16);
+			buffer[buffer_pos + 2] = (uint8_t)(dest >> 8);
+			buffer[buffer_pos + 1] = (uint8_t)(dest);
+			buffer_pos += 5;
+			prev_mask = 0;
+
+		} else {
+			++buffer_pos;
+			prev_mask |= 1;
+			if (Test86MSByte(b))
+				prev_mask |= 0x10;
+		}
+	}
+
+	simple->prev_mask = prev_mask;
+	simple->prev_pos = prev_pos;
+
+	return buffer_pos;
+}
+
+
+static lzma_ret
+x86_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
+		const lzma_filter_info *filters, bool is_encoder)
+{
+	const lzma_ret ret = lzma_simple_coder_init(next, allocator, filters,
+			&x86_code, sizeof(lzma_simple_x86), 5, 1, is_encoder);
+
+	if (ret == LZMA_OK) {
+		lzma_simple_coder *coder = next->coder;
+		lzma_simple_x86 *simple = coder->simple;
+		simple->prev_mask = 0;
+		simple->prev_pos = (uint32_t)(-5);
+	}
+
+	return ret;
+}
+
+
+#ifdef HAVE_ENCODER_X86
+extern lzma_ret
+lzma_simple_x86_encoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return x86_coder_init(next, allocator, filters, true);
+}
+#endif
+
+
+#ifdef HAVE_DECODER_X86
+extern lzma_ret
+lzma_simple_x86_decoder_init(lzma_next_coder *next,
+		const lzma_allocator *allocator,
+		const lzma_filter_info *filters)
+{
+	return x86_coder_init(next, allocator, filters, false);
+}
+#endif
diff --git a/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/validate_map.sh b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/validate_map.sh
new file mode 100644
index 00000000000..dd1589d236e
--- /dev/null
+++ b/src/libs/3rdparty/karchive/3rdparty/xz/src/liblzma/validate_map.sh
@@ -0,0 +1,163 @@
+#!/bin/sh
+# SPDX-License-Identifier: 0BSD
+
+###############################################################################
+#
+# Check liblzma_*.map for certain types of errors.
+#
+# liblzma_generic.map is for FreeBSD and Solaris and possibly others
+# except GNU/Linux.
+#
+# liblzma_linux.map is for GNU/Linux only. This and the matching extra code
+# in the .c files make liblzma >= 5.2.7 compatible with binaries that were
+# linked against ill-patched liblzma in RHEL/CentOS 7. By providing the
+# compatibility in official XZ Utils release will hopefully prevent people
+# from further copying the broken patch to other places when they want
+# compatibility with binaries linked on RHEL/CentOS 7. The long version
+# of the story:
+#
+#     RHEL/CentOS 7 shipped with 5.1.2alpha, including the threaded
+#     encoder that is behind #ifdef LZMA_UNSTABLE in the API headers.
+#     In 5.1.2alpha these symbols are under XZ_5.1.2alpha in liblzma.map.
+#     API/ABI compatibility tracking isn't done between development
+#     releases so newer releases didn't have XZ_5.1.2alpha anymore.
+#
+#     Later RHEL/CentOS 7 updated xz to 5.2.2 but they wanted to keep
+#     the exported symbols compatible with 5.1.2alpha. After checking
+#     the ABI changes it turned out that >= 5.2.0 ABI is backward
+#     compatible with the threaded encoder functions from 5.1.2alpha
+#     (but not vice versa as fixes and extensions to these functions
+#     were made between 5.1.2alpha and 5.2.0).
+#
+#     In RHEL/CentOS 7, XZ Utils 5.2.2 was patched with
+#     xz-5.2.2-compat-libs.patch to modify liblzma.map:
+#
+#       - XZ_5.1.2alpha was added with lzma_stream_encoder_mt and
+#         lzma_stream_encoder_mt_memusage. This matched XZ Utils 5.1.2alpha.
+#
+#       - XZ_5.2 was replaced with XZ_5.2.2. It is clear that this was
+#         an error; the intention was to keep using XZ_5.2 (XZ_5.2.2
+#         has never been used in XZ Utils). So XZ_5.2.2 lists all
+#         symbols that were listed under XZ_5.2 before the patch.
+#         lzma_stream_encoder_mt and _mt_memusage are included too so
+#         they are listed both here and under XZ_5.1.2alpha.
+#
+#     The patch didn't add any __asm__(".symver ...") lines to the .c
+#     files. Thus the resulting liblzma.so exports the threaded encoder
+#     functions under XZ_5.1.2alpha only. Listing the two functions
+#     also under XZ_5.2.2 in liblzma.map has no effect without
+#     matching .symver lines.
+#
+#     The lack of XZ_5.2 in RHEL/CentOS 7 means that binaries linked
+#     against unpatched XZ Utils 5.2.x won't run on RHEL/CentOS 7.
+#     This is unfortunate but this alone isn't too bad as the problem
+#     is contained within RHEL/CentOS 7 and doesn't affect users
+#     of other distributions. It could also be fixed internally in
+#     RHEL/CentOS 7.
+#
+#     The second problem is more serious: In XZ Utils 5.2.2 the API
+#     headers don't have #ifdef LZMA_UNSTABLE for obvious reasons.
+#     This is true in RHEL/CentOS 7 version too. Thus now programs
+#     using new APIs can be compiled without an extra #define. However,
+#     the programs end up depending on symbol version XZ_5.1.2alpha
+#     (and possibly also XZ_5.2.2) instead of XZ_5.2 as they would
+#     with an unpatched XZ Utils 5.2.2. This means that such binaries
+#     won't run on other distributions shipping XZ Utils >= 5.2.0 as
+#     they don't provide XZ_5.1.2alpha or XZ_5.2.2; they only provide
+#     XZ_5.2 (and XZ_5.0). (This includes RHEL/CentOS 8 as the patch
+#     luckily isn't included there anymore with XZ Utils 5.2.4.)
+#
+#     Binaries built by RHEL/CentOS 7 users get distributed and then
+#     people wonder why they don't run on some other distribution.
+#     Seems that people have found out about the patch and been copying
+#     it to some build scripts, seemingly curing the symptoms but
+#     actually spreading the illness further and outside RHEL/CentOS 7.
+#     Adding compatibility in an official XZ Utils release should work
+#     as a vaccine against this ill patch and stop it from spreading.
+#     The vaccine is kept GNU/Linux-only as other OSes should be immune
+#     (hopefully it hasn't spread via some build script to other OSes).
+#
+# Author: Lasse Collin
+#
+###############################################################################
+
+LC_ALL=C
+export LC_ALL
+
+STATUS=0
+
+cd "$(dirname "$0")"
+
+# Get the list of symbols that aren't defined in liblzma_generic.map.
+SYMS=$(sed -n 's/^extern LZMA_API([^)]*) \([a-z0-9_]*\)(.*$/\1;/p' \
+		api/lzma/*.h \
+	| sort \
+	| grep -Fve "$(sed '/[{}:*]/d;/^$/d;s/^	//' liblzma_generic.map)")
+
+# Check that there are no old alpha or beta versions listed.
+VER=$(cd ../.. && sh build-aux/version.sh)
+NAMES=
+case $VER in
+	*alpha | *beta)
+		NAMES=$(sed -n 's/^.*XZ_\([^ ]*\)\(alpha\|beta\) .*$/\1\2/p' \
+			liblzma_generic.map | grep -Fv "$VER")
+		;;
+esac
+
+# Check for duplicate lines. It can catch missing dependencies.
+DUPS=$(sort liblzma_generic.map | sed '/^$/d;/^global:$/d' | uniq -d)
+
+# Check that liblzma_linux.map is in sync with liblzma_generic.map.
+# The RHEL/CentOS 7 compatibility symbols are in a fixed location
+# so it makes it easy to remove them for comparison with liblzma_generic.map.
+#
+# NOTE: Putting XZ_5.2 before the compatibility symbols XZ_5.1.2alpha
+# and XZ_5.2.2 in liblzma_linux.map is important: If liblzma_linux.map is
+# incorrectly used without #define HAVE_SYMBOL_VERSIONS_LINUX, only the first
+# occurrence of each function name will be used from liblzma_linux.map;
+# the rest are ignored by the linker. Thus having XZ_5.2 before the
+# compatibility symbols means that @@XZ_5.2 will be used for the symbols
+# listed under XZ_5.2 {...} and the same function names later in
+# the file under XZ_5.1.2alpha {...} and XZ_5.2.2 {...} will be
+# ignored (@XZ_5.1.2alpha or @XZ_5.2.2 won't be added at all when
+# the #define HAVE_SYMBOL_VERSIONS_LINUX isn't used).
+IN_SYNC=
+if ! sed '111,125d' liblzma_linux.map \
+		| cmp -s - liblzma_generic.map; then
+	IN_SYNC=no
+fi
+
+# Print error messages if needed.
+if test -n "$SYMS$NAMES$DUPS$IN_SYNC"; then
+	echo
+	echo 'validate_map.sh found problems from liblzma_*.map:'
+	echo
+
+	if test -n "$SYMS"; then
+		echo 'liblzma_generic.map lacks the following symbols:'
+		echo "$SYMS"
+		echo
+	fi
+
+	if test -n "$NAMES"; then
+		echo 'Obsolete alpha or beta version names:'
+		echo "$NAMES"
+		echo
+	fi
+
+	if test -n "$DUPS"; then
+		echo 'Duplicate lines:'
+		echo "$DUPS"
+		echo
+	fi
+
+	if test -n "$IN_SYNC"; then
+		echo "liblzma_generic.map and liblzma_linux.map aren't in sync"
+		echo
+	fi
+
+	STATUS=1
+fi
+
+# Exit status is 1 if problems were found, 0 otherwise.
+exit "$STATUS"
diff --git a/src/libs/3rdparty/karchive/AUTHORS b/src/libs/3rdparty/karchive/AUTHORS
new file mode 100644
index 00000000000..f6ec78707c6
--- /dev/null
+++ b/src/libs/3rdparty/karchive/AUTHORS
@@ -0,0 +1,10 @@
+Maintainers:
+Mario Bensi 
+David Faure 
+
+Many other contributors, see git log.
+
+For questions about this package, email kde-frameworks-devel@kde.org.
+
+For bug reports, please use https://bugs.kde.org
+
diff --git a/src/libs/3rdparty/karchive/CMakeLists.txt b/src/libs/3rdparty/karchive/CMakeLists.txt
new file mode 100644
index 00000000000..43b61a998f1
--- /dev/null
+++ b/src/libs/3rdparty/karchive/CMakeLists.txt
@@ -0,0 +1,152 @@
+cmake_minimum_required(VERSION 3.16)
+
+set(KF_VERSION "6.10.0") # handled by release scripts
+project(KArchive VERSION ${KF_VERSION})
+
+include(FeatureSummary)
+find_package(ECM 6.9.0  NO_MODULE)
+set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules")
+feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)
+
+option(WITH_BZIP2 "Make bzip2 required" ON)
+option(WITH_LIBLZMA "Make liblzma required" ON)
+option(WITH_LIBZSTD "Make libzstd required" ON)
+
+set(PKGCONFIG_REQUIRED_TYPE "")
+
+if(WITH_BZIP2)
+    set(BZIP2_PACKAGE_TYPE "REQUIRED")
+else()
+    set(BZIP2_PACKAGE_TYPE "RECOMMENDED")
+endif()
+
+if(WITH_LIBLZMA)
+    set(LIBLZMA_PACKAGE_TYPE "REQUIRED")
+else()
+    set(LIBLZMA_PACKAGE_TYPE "RECOMMENDED")
+endif()
+
+if(WITH_LIBZSTD)
+    set(PKGCONFIG_REQUIRED_TYPE "REQUIRED")
+    set(LIBZSTD_REQUIRED_TYPE "REQUIRED")
+else()
+    set(LIBZSTD_REQUIRED_TYPE "")
+endif()
+
+set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
+
+include(KDEInstallDirs)
+include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
+include(KDECMakeSettings)
+include(KDEGitCommitHooks)
+
+include(ECMGenerateExportHeader)
+
+set(REQUIRED_QT_VERSION 6.6.0)
+find_package(Qt6Core ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
+
+find_package(ZLIB)
+set_package_properties(ZLIB PROPERTIES
+    URL "https://www.zlib.net"
+    DESCRIPTION "Support for gzip compressed files and data streams"
+    TYPE REQUIRED
+    PURPOSE "Support for gzip compressed files and data streams"
+)
+
+find_package(BZip2)
+set_package_properties(BZip2 PROPERTIES
+    URL "https://sourceware.org/bzip2/"
+    DESCRIPTION "Support for BZip2 compressed files and data streams"
+    TYPE ${BZIP2_PACKAGE_TYPE}
+    PURPOSE "Support for BZip2 compressed files and data streams"
+)
+
+find_package(LibLZMA)
+set_package_properties(LibLZMA PROPERTIES
+    URL "https://tukaani.org/xz/"
+    DESCRIPTION "Support for xz compressed files and data streams"
+    TYPE ${LIBLZMA_PACKAGE_TYPE}
+    PURPOSE "Support for xz compressed files and data streams"
+)
+
+
+find_package(PkgConfig ${PKGCONFIG_REQUIRED_TYPE})
+if (PkgConfig_FOUND)
+    pkg_check_modules(LibZstd ${LIBZSTD_REQUIRED_TYPE} IMPORTED_TARGET "libzstd")
+endif()
+add_feature_info(LibZstd LibZstd_FOUND
+                "Support for zstd compressed files and data streams"
+)
+
+include(ECMSetupVersion)
+include(ECMGenerateHeaders)
+include(ECMQtDeclareLoggingCategory)
+include(ECMAddQch)
+include(ECMDeprecationSettings)
+include(ECMPoQmTools)
+
+set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].")
+
+option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF)
+add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)")
+
+set(karchive_version_header "${CMAKE_CURRENT_BINARY_DIR}/src/karchive_version.h")
+ecm_setup_version(PROJECT
+    VARIABLE_PREFIX KARCHIVE
+    VERSION_HEADER "${karchive_version_header}"
+    PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfigVersion.cmake"
+    SOVERSION 6)
+
+ecm_set_disabled_deprecation_versions(
+    QT 6.8
+)
+
+
+add_subdirectory(src)
+if (BUILD_TESTING)
+    add_subdirectory(autotests)
+    add_subdirectory(tests)
+endif()
+
+ecm_install_po_files_as_qm(poqm)
+
+# create a Config.cmake and a ConfigVersion.cmake file and install them
+set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF6Archive")
+
+if (BUILD_QCH)
+    ecm_install_qch_export(
+        TARGETS KF6Archive_QCH
+        FILE KF6ArchiveQchTargets.cmake
+        DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
+        COMPONENT Devel
+    )
+    set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF6ArchiveQchTargets.cmake\")")
+endif()
+
+include(CMakePackageConfigHelpers)
+
+configure_package_config_file(
+    "${CMAKE_CURRENT_SOURCE_DIR}/KF6ArchiveConfig.cmake.in"
+    "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfig.cmake"
+    INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
+)
+
+install(FILES ${karchive_version_header}
+        DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KArchive
+        COMPONENT Devel)
+
+install(FILES
+            "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfig.cmake"
+            "${CMAKE_CURRENT_BINARY_DIR}/KF6ArchiveConfigVersion.cmake"
+        DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
+        COMPONENT Devel)
+
+install(EXPORT KF6ArchiveTargets
+        DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
+        FILE KF6ArchiveTargets.cmake
+        NAMESPACE KF6::)
+
+include(ECMFeatureSummary)
+ecm_feature_summary(WHAT ALL   FATAL_ON_MISSING_REQUIRED_PACKAGES)
+
+kde_configure_git_pre_commit_hook(CHECKS CLANG_FORMAT)
diff --git a/src/libs/3rdparty/karchive/LICENSES/BSD-2-Clause.txt b/src/libs/3rdparty/karchive/LICENSES/BSD-2-Clause.txt
new file mode 100644
index 00000000000..2d2bab1127b
--- /dev/null
+++ b/src/libs/3rdparty/karchive/LICENSES/BSD-2-Clause.txt
@@ -0,0 +1,22 @@
+Copyright (c)  . All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/libs/3rdparty/karchive/LICENSES/CC0-1.0.txt b/src/libs/3rdparty/karchive/LICENSES/CC0-1.0.txt
new file mode 100644
index 00000000000..0e259d42c99
--- /dev/null
+++ b/src/libs/3rdparty/karchive/LICENSES/CC0-1.0.txt
@@ -0,0 +1,121 @@
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+    HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+  i. the right to reproduce, adapt, distribute, perform, display,
+     communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+     likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+     subject to the limitations in paragraph 4(a), below;
+  v. rights protecting the extraction, dissemination, use and reuse of data
+     in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+     European Parliament and of the Council of 11 March 1996 on the legal
+     protection of databases, and under any national implementation
+     thereof, including any amended or successor version of such
+     directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+     world based on applicable law or treaty, and any national
+     implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+    surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+    warranties of any kind concerning the Work, express, implied,
+    statutory or otherwise, including without limitation warranties of
+    title, merchantability, fitness for a particular purpose, non
+    infringement, or the absence of latent or other defects, accuracy, or
+    the present or absence of errors, whether or not discoverable, all to
+    the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+    that may apply to the Work or any use thereof, including without
+    limitation any person's Copyright and Related Rights in the Work.
+    Further, Affirmer disclaims responsibility for obtaining any necessary
+    consents, permissions or other rights required for any use of the
+    Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+    party to this document and has no duty or obligation with respect to
+    this CC0 or use of the Work.
diff --git a/src/libs/3rdparty/karchive/LICENSES/LGPL-2.0-or-later.txt b/src/libs/3rdparty/karchive/LICENSES/LGPL-2.0-or-later.txt
new file mode 100644
index 00000000000..5c96471aafa
--- /dev/null
+++ b/src/libs/3rdparty/karchive/LICENSES/LGPL-2.0-or-later.txt
@@ -0,0 +1,446 @@
+GNU LIBRARY GENERAL PUBLIC LICENSE
+
+Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc.
+
+51 Franklin St, 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.
+
+[This is the first released version of the library GPL. It is numbered 2 because
+it goes with version 2 of the ordinary GPL.]
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to share
+and change it. By contrast, the GNU General Public Licenses are intended to
+guarantee your freedom to share and change free software--to make sure the
+software is free for all its users.
+
+This license, the Library General Public License, applies to some specially
+designated Free Software Foundation software, and to any other libraries whose
+authors decide to use it. You can use it for your libraries, 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 library, or if you modify it.
+
+For example, if you distribute copies of the library, whether gratis or for
+a fee, you must give the recipients all the rights that we gave you. You must
+make sure that they, too, receive or can get the source code. If you link
+a program with the library, you must provide complete object files to the
+recipients so that they can relink them with the library, after making changes
+to the library and recompiling it. And you must show them these terms so they
+know their rights.
+
+Our method of protecting your rights has two steps: (1) copyright the library,
+and (2) offer you this license which gives you legal permission to copy, distribute
+and/or modify the library.
+
+Also, for each distributor's protection, we want to make certain that everyone
+understands that there is no warranty for this free library. If the library
+is modified by someone else and passed on, we want its recipients to know
+that what they have is not the original version, 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 companies distributing free software will individually
+obtain patent licenses, thus in effect transforming the program into proprietary
+software. To prevent this, we have made it clear that any patent must be licensed
+for everyone's free use or not licensed at all.
+
+Most GNU software, including some libraries, is covered by the ordinary GNU
+General Public License, which was designed for utility programs. This license,
+the GNU Library General Public License, applies to certain designated libraries.
+This license is quite different from the ordinary one; be sure to read it
+in full, and don't assume that anything in it is the same as in the ordinary
+license.
+
+The reason we have a separate public license for some libraries is that they
+blur the distinction we usually make between modifying or adding to a program
+and simply using it. Linking a program with a library, without changing the
+library, is in some sense simply using the library, and is analogous to running
+a utility program or application program. However, in a textual and legal
+sense, the linked executable is a combined work, a derivative of the original
+library, and the ordinary General Public License treats it as such.
+
+Because of this blurred distinction, using the ordinary General Public License
+for libraries did not effectively promote software sharing, because most developers
+did not use the libraries. We concluded that weaker conditions might promote
+sharing better.
+
+However, unrestricted linking of non-free programs would deprive the users
+of those programs of all benefit from the free status of the libraries themselves.
+This Library General Public License is intended to permit developers of non-free
+programs to use free libraries, while preserving your freedom as a user of
+such programs to change the free libraries that are incorporated in them.
+(We have not seen how to achieve this as regards changes in header files,
+but we have achieved it as regards changes in the actual functions of the
+Library.) The hope is that this will lead to faster development of free libraries.
+
+The precise terms and conditions for copying, distribution and modification
+follow. Pay close attention to the difference between a "work based on the
+library" and a "work that uses the library". The former contains code derived
+from the library, while the latter only works together with the library.
+
+Note that it is possible for a library to be covered by the ordinary General
+Public License rather than by this special one.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License Agreement applies to any software library which contains a
+notice placed by the copyright holder or other authorized party saying it
+may be distributed under the terms of this Library General Public License
+(also called "this License"). Each licensee is addressed as "you".
+
+A "library" means a collection of software functions and/or data prepared
+so as to be conveniently linked with application programs (which use some
+of those functions and data) to form executables.
+
+The "Library", below, refers to any such software library or work which has
+been distributed under these terms. A "work based on the Library" means either
+the Library or any derivative work under copyright law: that is to say, a
+work containing the Library or a portion of it, either verbatim or with modifications
+and/or translated straightforwardly into another language. (Hereinafter, translation
+is included without limitation in the term "modification".)
+
+"Source code" for a work means the preferred form of the work for making modifications
+to it. For a library, 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 library.
+
+Activities other than copying, distribution and modification are not covered
+by this License; they are outside its scope. The act of running a program
+using the Library is not restricted, and output from such a program is covered
+only if its contents constitute a work based on the Library (independent of
+the use of the Library in a tool for writing it). Whether that is true depends
+on what the Library does and what the program that uses the Library does.
+
+1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with
+the Library.
+
+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 Library or any portion of it,
+thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+b) You must cause the files modified to carry prominent notices stating that
+you changed the files and the date of any change.
+
+c) You must cause the whole of the work to be licensed at no charge to all
+third parties under the terms of this License.
+
+d) If a facility in the modified Library refers to a function or a table of
+data to be supplied by an application program that uses the facility, other
+than as an argument passed when the facility is invoked, then you must make
+a good faith effort to ensure that, in the event an application does not supply
+such function or table, the facility still operates, and performs whatever
+part of its purpose remains meaningful.
+
+(For example, a function in a library to compute square roots has a purpose
+that is entirely well-defined independent of the application. Therefore, Subsection
+2d requires that any application-supplied function or table used by this function
+must be optional: if the application does not supply it, the square root function
+must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Library, 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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library with
+the Library (or with a work based on the Library) on a volume of a storage
+or distribution medium does not bring the other work under the scope of this
+License.
+
+3. You may opt to apply the terms of the ordinary GNU General Public License
+instead of this License to a given copy of the Library. To do this, you must
+alter all the notices that refer to this License, so that they refer to the
+ordinary GNU General Public License, version 2, instead of to this License.
+(If a newer version than version 2 of the ordinary GNU General Public License
+has appeared, then you can specify that version instead if you wish.) Do not
+make any other change in these notices.
+
+Once this change is made in a given copy, it is irreversible for that copy,
+so the ordinary GNU General Public License applies to all subsequent copies
+and derivative works made from that copy.
+
+This option is useful when you wish to copy part of the code of the Library
+into a program that is not a library.
+
+4. You may copy and distribute the Library (or a portion or derivative of
+it, under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you 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.
+
+If distribution of 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 satisfies the requirement to distribute the source code, even though
+third parties are not compelled to copy the source along with the object code.
+
+5. A program that contains no derivative of any portion of the Library, but
+is designed to work with the Library by being compiled or linked with it,
+is called a "work that uses the Library". Such a work, in isolation, is not
+a derivative work of the Library, and therefore falls outside the scope of
+this License.
+
+However, linking a "work that uses the Library" with the Library creates an
+executable that is a derivative of the Library (because it contains portions
+of the Library), rather than a "work that uses the library". The executable
+is therefore covered by this License. Section 6 states terms for distribution
+of such executables.
+
+When a "work that uses the Library" uses material from a header file that
+is part of the Library, the object code for the work may be a derivative work
+of the Library even though the source code is not. Whether this is true is
+especially significant if the work can be linked without the Library, or if
+the work is itself a library. The threshold for this to be true is not precisely
+defined by law.
+
+If such an object file uses only numerical parameters, data structure layouts
+and accessors, and small macros and small inline functions (ten lines or less
+in length), then the use of the object file is unrestricted, regardless of
+whether it is legally a derivative work. (Executables containing this object
+code plus portions of the Library will still fall under Section 6.)
+
+Otherwise, if the work is a derivative of the Library, you may distribute
+the object code for the work under the terms of Section 6. Any executables
+containing that work also fall under Section 6, whether or not they are linked
+directly with the Library itself.
+
+6. As an exception to the Sections above, you may also compile or link a "work
+that uses the Library" with the Library to produce a work containing portions
+of the Library, and distribute that work under terms of your choice, provided
+that the terms permit modification of the work for the customer's own use
+and reverse engineering for debugging such modifications.
+
+You must give prominent notice with each copy of the work that the Library
+is used in it and that the Library and its use are covered by this License.
+You must supply a copy of this License. If the work during execution displays
+copyright notices, you must include the copyright notice for the Library among
+them, as well as a reference directing the user to the copy of this License.
+Also, you must do one of these things:
+
+a) Accompany the work with the complete corresponding machine-readable source
+code for the Library including whatever changes were used in the work (which
+must be distributed under Sections 1 and 2 above); and, if the work is an
+executable linked with the Library, with the complete machine-readable "work
+that uses the Library", as object code and/or source code, so that the user
+can modify the Library and then relink to produce a modified executable containing
+the modified Library. (It is understood that the user who changes the contents
+of definitions files in the Library will not necessarily be able to recompile
+the application to use the modified definitions.)
+
+b) Accompany the work with a written offer, valid for at least three years,
+to give the same user the materials specified in Subsection 6a, above, for
+a charge no more than the cost of performing this distribution.
+
+c) If distribution of the work is made by offering access to copy from a designated
+place, offer equivalent access to copy the above specified materials from
+the same place.
+
+d) Verify that the user has already received a copy of these materials or
+that you have already sent this user a copy.
+
+For an executable, the required form of the "work that uses the Library" must
+include any data and utility programs needed for reproducing the executable
+from it. 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.
+
+It may happen that this requirement contradicts the license restrictions of
+other proprietary libraries that do not normally accompany the operating system.
+Such a contradiction means you cannot use both them and the Library together
+in an executable that you distribute.
+
+7. You may place library facilities that are a work based on the Library side-by-side
+in a single library together with other library facilities not covered by
+this License, and distribute such a combined library, provided that the separate
+distribution of the work based on the Library and of the other library facilities
+is otherwise permitted, and provided that you do these two things:
+
+a) Accompany the combined library with a copy of the same work based on the
+Library, uncombined with any other library facilities. This must be distributed
+under the terms of the Sections above.
+
+b) Give prominent notice with the combined library of the fact that part of
+it is a work based on the Library, and explaining where to find the accompanying
+uncombined form of the same work.
+
+8. You may not copy, modify, sublicense, link with, or distribute the Library
+except as expressly provided under this License. Any attempt otherwise to
+copy, modify, sublicense, link with, or distribute the Library 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.
+
+9. 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
+Library or its derivative works. These actions are prohibited by law if you
+do not accept this License. Therefore, by modifying or distributing the Library
+(or any work based on the Library), you indicate your acceptance of this License
+to do so, and all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+10. Each time you redistribute the Library (or any work based on the Library),
+the recipient automatically receives a license from the original licensor
+to copy, distribute, link with or modify the Library 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.
+
+11. 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 Library at all. For example, if a
+patent license would not permit royalty-free redistribution of the Library
+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 Library.
+
+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.
+
+12. If the distribution and/or use of the Library is restricted in certain
+countries either by patents or by copyrighted interfaces, the original copyright
+holder who places the Library 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.
+
+13. The Free Software Foundation may publish revised and/or new versions of
+the Library 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 Library 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
+Library does not specify a license version number, you may choose any version
+ever published by the Free Software Foundation.
+
+14. If you wish to incorporate parts of the Library into other free programs
+whose distribution conditions are incompatible with these, 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
+
+15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
+THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
+STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY
+"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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries
+
+If you develop a new library, and you want it to be of the greatest possible
+use to the public, we recommend making it free software that everyone can
+redistribute and change. You can do so by permitting redistribution under
+these terms (or, alternatively, under the terms of the ordinary General Public
+License).
+
+To apply these terms, attach the following notices to the library. 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 library's name and an idea of what it does.
+
+Copyright (C) year name of author
+
+This library is free software; you can redistribute it and/or modify it under
+the terms of the GNU Library General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your option)
+any later version.
+
+This library is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more
+details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; if not, write to the Free Software Foundation, Inc.,
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your school,
+if any, to sign a "copyright disclaimer" for the library, if necessary. Here
+is a sample; alter the names:
+
+Yoyodyne, Inc., hereby disclaims all copyright interest in
+
+the library `Frob' (a library for tweaking knobs) written
+
+by James Random Hacker.
+
+signature of Ty Coon, 1 April 1990
+
+Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/src/libs/3rdparty/karchive/README.md b/src/libs/3rdparty/karchive/README.md
new file mode 100644
index 00000000000..6caf60dc454
--- /dev/null
+++ b/src/libs/3rdparty/karchive/README.md
@@ -0,0 +1,33 @@
+# KArchive
+
+Reading, creating, and manipulating file archives
+
+## Introduction
+
+KArchive provides classes for easy reading, creation and manipulation of
+"archive" formats like ZIP and TAR.
+
+It also provides transparent compression and decompression of data, like the
+GZip format, via a subclass of QIODevice.
+
+## Usage
+
+If you want to read and write compressed data, just create an instance of
+KCompressionDevice and write to or read from that.
+
+If you want to read and write archive formats, create an instance of the
+appropriate subclass of KArchive (eg: K7Zip for 7-Zip files).  You may need to
+combine this with usage of KCompressionDevice (see the API documentation for the
+relevant KArchive subclass for details).
+
+## Changes for Qt Creator
+
+* Stripped everything but src folder
+* Created simplified and qtc'ified CMakeLists.txt
+* Removed config-compression.h (defines moved to CMakeLists.txt)
+* Replaced QMutableListIterator usages 
+  ([upstream](https://invent.kde.org/frameworks/karchive/-/merge_requests/82))
+* Added "progress" parameter to KArchive::copyTo
+  ([upstream](https://invent.kde.org/frameworks/karchive/-/merge_requests/84))
+* Added "Fix" to KTar to workaround mime database changes in Qt 6.8.0
+  ([upstream](https://invent.kde.org/frameworks/karchive/-/merge_requests/83))
diff --git a/src/libs/3rdparty/karchive/src/k7zip.cpp b/src/libs/3rdparty/karchive/src/k7zip.cpp
new file mode 100644
index 00000000000..03ee383aa11
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/k7zip.cpp
@@ -0,0 +1,3028 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2011 Mario Bensi 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "k7zip.h"
+#include "karchive_p.h"
+#include "loggingcategory.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "kcompressiondevice.h"
+#include "klimitediodevice_p.h"
+#include 
+#include 
+
+#include "zlib.h"
+#include 
+#include  // time()
+
+#ifndef QT_STAT_LNK
+#define QT_STAT_LNK 0120000
+#endif // QT_STAT_LNK
+
+////////////////////////////////////////////////////////////////////////
+/////////////////////////// K7Zip //////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+#define BUFFER_SIZE 8 * 1024
+
+static const unsigned char k7zip_signature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+// static const unsigned char XZ_HEADER_MAGIC[6] = { 0xFD, '7', 'z', 'X', 'Z', 0x00 };
+
+/* clang-format off */
+static QChar GetUi16(const char *p, quint64 offset)
+{
+    return QChar(static_cast(p[offset + 0])
+                 | (static_cast(p[1]) << 8));
+}
+
+static quint32 GetUi32(const char *p, quint64 offset)
+{
+    return (static_cast(p[offset + 0])
+            | (static_cast(p[offset + 1]) << 8)
+            | (static_cast(p[offset + 2]) << 16)
+            | (static_cast(p[offset + 3]) << 24));
+}
+
+static quint64 GetUi64(const char *p, quint64 offset)
+{
+    return (GetUi32(p, offset)
+            | (static_cast(GetUi32(p, offset + 4)) << 32));
+}
+
+static quint32 lzma2_dic_size_from_prop(int p)
+{
+    return ((static_cast(2) | (p & 1)) << ((p / 2) + 11));
+}
+
+/* clang-format on*/
+
+#define FILE_ATTRIBUTE_READONLY 1
+#define FILE_ATTRIBUTE_HIDDEN 2
+#define FILE_ATTRIBUTE_SYSTEM 4
+#define FILE_ATTRIBUTE_DIRECTORY 16
+#define FILE_ATTRIBUTE_ARCHIVE 32
+#define FILE_ATTRIBUTE_DEVICE 64
+#define FILE_ATTRIBUTE_NORMAL 128
+#define FILE_ATTRIBUTE_TEMPORARY 256
+#define FILE_ATTRIBUTE_SPARSE_FILE 512
+#define FILE_ATTRIBUTE_REPARSE_POINT 1024
+#define FILE_ATTRIBUTE_COMPRESSED 2048
+#define FILE_ATTRIBUTE_OFFLINE 0x1000
+#define FILE_ATTRIBUTE_ENCRYPTED 0x4000
+#define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 /* trick for Unix */
+
+enum HeaderType {
+    kEnd,
+
+    kHeader,
+
+    kArchiveProperties,
+
+    kAdditionalStreamsInfo,
+    kMainStreamsInfo,
+    kFilesInfo,
+
+    kPackInfo,
+    kUnpackInfo,
+    kSubStreamsInfo,
+
+    kSize,
+    kCRC,
+
+    kFolder,
+
+    kCodersUnpackSize,
+    kNumUnpackStream,
+
+    kEmptyStream,
+    kEmptyFile,
+    kAnti,
+
+    kName,
+    kCTime,
+    kATime,
+    kMTime,
+    kAttributes,
+    kComment,
+
+    kEncodedHeader,
+
+    kStartPos,
+    kDummy,
+};
+
+// Method ID
+// static const quint64 k_Copy = 0x00;
+// static const quint64 k_Delta = 0x03;
+// static const quint64 k_x86 = 0x04; //BCJ
+// static const quint64 k_PPC = 0x05; // BIG Endian
+// static const quint64 k_IA64 = 0x06;
+// static const quint64 k_ARM = 0x07; // little Endian
+// static const quint64 k_ARM_Thumb = 0x08; // little Endian
+// static const quint64 k_SPARC = 0x09;
+static const quint64 k_LZMA2 = 0x21;
+// static const quint64 k_Swap2 = 0x020302;
+// static const quint64 k_Swap4 = 0x020304;
+static const quint64 k_LZMA = 0x030101;
+static const quint64 k_BCJ = 0x03030103;
+static const quint64 k_BCJ2 = 0x0303011B;
+// static const quint64 k_7zPPC = 0x03030205;
+// static const quint64 k_Alpha = 0x03030301;
+// static const quint64 k_7zIA64 = 0x03030401;
+// static const quint64 k_7zARM = 0x03030501;
+// static const quint64 k_M68 = 0x03030605; //Big Endian
+// static const quint64 k_ARMT = 0x03030701;
+// static const quint64 k_7zSPARC = 0x03030805;
+static const quint64 k_PPMD = 0x030401;
+// static const quint64 k_Experimental = 0x037F01;
+// static const quint64 k_Shrink = 0x040101;
+// static const quint64 k_Implode = 0x040106;
+// static const quint64 k_Deflate = 0x040108;
+// static const quint64 k_Deflate64 = 0x040109;
+// static const quint64 k_Imploding = 0x040110;
+// static const quint64 k_Jpeg = 0x040160;
+// static const quint64 k_WavPack = 0x040161;
+// static const quint64 k_PPMd = 0x040162;
+// static const quint64 k_wzAES = 0x040163;
+static const quint64 k_BZip2 = 0x040202;
+// static const quint64 k_Rar15 = 0x040301;
+// static const quint64 k_Rar20 = 0x040302;
+// static const quint64 k_Rar29 = 0x040303;
+// static const quint64 k_Arj = 0x040401; //1 2 3
+// static const quint64 k_Arj4 = 0x040402;
+// static const quint64 k_Z = 0x0405;
+// static const quint64 k_Lzh = 0x0406;
+// static const quint64 k_Cab = 0x0408;
+// static const quint64 k_DeflateNSIS = 0x040901;
+// static const quint64 k_Bzip2NSIS = 0x040902;
+static const quint64 k_AES = 0x06F10701;
+
+/**
+ * A K7ZipFileEntry represents a file in a 7zip archive.
+ */
+class K7ZipFileEntry : public KArchiveFile
+{
+public:
+    K7ZipFileEntry(K7Zip *zip,
+                   const QString &name,
+                   int access,
+                   const QDateTime &date,
+                   const QString &user,
+                   const QString &group,
+                   const QString &symlink,
+                   qint64 pos,
+                   qint64 size,
+                   const QByteArray &data);
+
+    ~K7ZipFileEntry() override;
+
+    /**
+     * @return the content of this file.
+     * Call data() with care (only once per file), this data isn't cached.
+     */
+    QByteArray data() const override;
+
+    /**
+     * This method returns QIODevice (internal class: KLimitedIODevice)
+     * on top of the underlying QIODevice. This is obviously for reading only.
+     *
+     * WARNING: Note that the ownership of the device is being transferred to the caller,
+     * who will have to delete it.
+     *
+     * The returned device auto-opens (in readonly mode), no need to open it.
+     * @return the QIODevice of the file
+     */
+    QIODevice *createDevice() const override;
+
+private:
+    const QByteArray m_data;
+    QBuffer *m_buffer;
+};
+
+K7ZipFileEntry::K7ZipFileEntry(K7Zip *zip,
+                               const QString &name,
+                               int access,
+                               const QDateTime &date,
+                               const QString &user,
+                               const QString &group,
+                               const QString &symlink,
+                               qint64 pos,
+                               qint64 size,
+                               const QByteArray &data)
+    : KArchiveFile(zip, name, access, date, user, group, symlink, pos, size)
+    , m_data(data)
+    , m_buffer(new QBuffer)
+{
+    m_buffer->setData(m_data);
+    m_buffer->open(QIODevice::ReadOnly);
+}
+
+K7ZipFileEntry::~K7ZipFileEntry()
+{
+    delete m_buffer;
+}
+
+QByteArray K7ZipFileEntry::data() const
+{
+    return m_data.mid(position(), size());
+}
+
+QIODevice *K7ZipFileEntry::createDevice() const
+{
+    return new KLimitedIODevice(m_buffer, position(), size());
+}
+
+class FileInfo
+{
+public:
+    FileInfo()
+        : size(0)
+        , attributes(0)
+        , crc(0)
+        , attribDefined(false)
+        , crcDefined(false)
+        , hasStream(false)
+        , isDir(false)
+    {
+    }
+
+    QString path;
+    quint64 size;
+    quint32 attributes;
+    quint32 crc;
+    bool attribDefined;
+    bool crcDefined;
+    bool hasStream;
+    bool isDir;
+};
+
+class Folder
+{
+public:
+    class FolderInfo
+    {
+    public:
+        FolderInfo()
+            : numInStreams(0)
+            , numOutStreams(0)
+            , methodID(0)
+        {
+        }
+
+        bool isSimpleCoder() const
+        {
+            return (numInStreams == 1) && (numOutStreams == 1);
+        }
+
+        int numInStreams;
+        int numOutStreams;
+        QList properties;
+        quint64 methodID;
+    };
+
+    Folder()
+        : unpackCRCDefined(false)
+        , unpackCRC(0)
+    {
+    }
+
+    ~Folder()
+    {
+        qDeleteAll(folderInfos);
+    }
+
+    Q_DISABLE_COPY(Folder)
+
+    quint64 getUnpackSize() const
+    {
+        if (unpackSizes.isEmpty()) {
+            return 0;
+        }
+        for (int i = unpackSizes.size() - 1; i >= 0; i--) {
+            if (findBindPairForOutStream(i) < 0) {
+                return unpackSizes.at(i);
+            }
+        }
+        return 0;
+    }
+
+    int getNumOutStreams() const
+    {
+        int result = 0;
+        for (int i = 0; i < folderInfos.size(); i++) {
+            result += folderInfos.at(i)->numOutStreams;
+        }
+        return result;
+    }
+
+    quint32 getCoderInStreamIndex(quint32 coderIndex) const
+    {
+        quint32 streamIndex = 0;
+        for (quint32 i = 0; i < coderIndex; i++) {
+            streamIndex += folderInfos.at(i)->numInStreams;
+        }
+        return streamIndex;
+    }
+
+    quint32 getCoderOutStreamIndex(quint32 coderIndex) const
+    {
+        quint32 streamIndex = 0;
+        for (quint32 i = 0; i < coderIndex; i++) {
+            streamIndex += folderInfos.at(i)->numOutStreams;
+        }
+        return streamIndex;
+    }
+
+    int findBindPairForInStream(size_t inStreamIndex) const
+    {
+        for (int i = 0; i < inIndexes.size(); i++) {
+            if (inIndexes[i] == inStreamIndex) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    int findBindPairForOutStream(size_t outStreamIndex) const
+    {
+        for (int i = 0; i < outIndexes.size(); i++) {
+            if (outIndexes[i] == outStreamIndex) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    int findPackStreamArrayIndex(size_t inStreamIndex) const
+    {
+        for (int i = 0; i < packedStreams.size(); i++) {
+            if (packedStreams[i] == inStreamIndex) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    void findInStream(quint32 streamIndex, quint32 &coderIndex, quint32 &coderStreamIndex) const
+    {
+        for (coderIndex = 0; coderIndex < (quint32)folderInfos.size(); coderIndex++) {
+            quint32 curSize = folderInfos[coderIndex]->numInStreams;
+            if (streamIndex < curSize) {
+                coderStreamIndex = streamIndex;
+                return;
+            }
+            streamIndex -= curSize;
+        }
+    }
+
+    void findOutStream(quint32 streamIndex, quint32 &coderIndex, quint32 &coderStreamIndex) const
+    {
+        for (coderIndex = 0; coderIndex < (quint32)folderInfos.size(); coderIndex++) {
+            quint32 curSize = folderInfos[coderIndex]->numOutStreams;
+            if (streamIndex < curSize) {
+                coderStreamIndex = streamIndex;
+                return;
+            }
+            streamIndex -= curSize;
+        }
+    }
+
+    bool isEncrypted() const
+    {
+        for (int i = folderInfos.size() - 1; i >= 0; i--) {
+            if (folderInfos.at(i)->methodID == k_AES) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // bool CheckStructure() const;
+
+    bool unpackCRCDefined;
+    quint32 unpackCRC;
+    QList folderInfos;
+    QList inIndexes;
+    QList outIndexes;
+    QList packedStreams;
+    QList unpackSizes;
+};
+
+class Q_DECL_HIDDEN K7Zip::K7ZipPrivate
+{
+public:
+    K7ZipPrivate(K7Zip *parent)
+        : q(parent)
+        , packPos(0)
+        , numPackStreams(0)
+        , buffer(nullptr)
+        , pos(0)
+        , end(0)
+        , headerSize(0)
+        , countSize(0)
+        , m_currentFile(nullptr)
+    {
+    }
+
+    ~K7ZipPrivate()
+    {
+        qDeleteAll(folders);
+        qDeleteAll(fileInfos);
+    }
+
+    K7Zip *q;
+
+    QList packCRCsDefined;
+    QList packCRCs;
+    QList numUnpackStreamsInFolders;
+
+    QList folders;
+    QList fileInfos;
+    // File information
+    QList cTimesDefined;
+    QList cTimes;
+    QList aTimesDefined;
+    QList aTimes;
+    QList mTimesDefined;
+    QList mTimes;
+    QList startPositionsDefined;
+    QList startPositions;
+    QList fileInfoPopIDs;
+
+    quint64 packPos;
+    quint64 numPackStreams;
+    QList packSizes;
+    QList unpackSizes;
+    QList digestsDefined;
+    QList digests;
+
+    QList isAnti;
+
+    const char *buffer;
+    quint64 pos;
+    quint64 end;
+    quint64 headerSize;
+    quint64 countSize;
+
+    // Write
+    QByteArray header;
+    QByteArray outData; // Store data in this buffer before compress and write in archive.
+    K7ZipFileEntry *m_currentFile;
+    QList m_entryList;
+
+    void clear()
+    {
+        packCRCsDefined.clear();
+        packCRCs.clear();
+        numUnpackStreamsInFolders.clear();
+        qDeleteAll(folders);
+        folders.clear();
+        qDeleteAll(fileInfos);
+        fileInfos.clear();
+        cTimesDefined.clear();
+        cTimes.clear();
+        aTimesDefined.clear();
+        aTimes.clear();
+        mTimesDefined.clear();
+        mTimes.clear();
+        startPositionsDefined.clear();
+        startPositions.clear();
+        fileInfoPopIDs.clear();
+        packSizes.clear();
+        unpackSizes.clear();
+        digestsDefined.clear();
+        digests.clear();
+        isAnti.clear();
+
+        buffer = nullptr;
+        pos = 0;
+        end = 0;
+        headerSize = 0;
+        countSize = 0;
+    }
+
+    // Read
+    int readByte();
+    quint32 readUInt32();
+    quint64 readUInt64();
+    quint64 readNumber();
+    QString readString();
+    void readHashDigests(int numItems, QList &digestsDefined, QList &digests);
+    void readBoolVector(int numItems, QList &v);
+    void readBoolVector2(int numItems, QList &v);
+    void skipData(int size);
+    bool findAttribute(int attribute);
+    bool readUInt64DefVector(int numFiles, QList &values, QList &defined);
+
+    Folder *folderItem();
+    bool readMainStreamsInfo();
+    bool readPackInfo();
+    bool readUnpackInfo();
+    bool readSubStreamsInfo();
+    QByteArray readAndDecodePackedStreams(bool readMainStreamInfo = true);
+
+    // Write
+    void createItemsFromEntities(const KArchiveDirectory *, const QString &, QByteArray &);
+    void writeByte(unsigned char b);
+    void writeNumber(quint64 value);
+    void writeBoolVector(const QList &boolVector);
+    void writeUInt32(quint32 value);
+    void writeUInt64(quint64 value);
+    void writeHashDigests(const QList &digestsDefined, const QList &digests);
+    void writeAlignedBoolHeader(const QList &v, int numDefined, int type, unsigned itemSize);
+    void writeUInt64DefVector(const QList &v, const QList &defined, int type);
+    void writeFolder(const Folder *folder);
+    void writePackInfo(quint64 dataOffset, QList &packedSizes, QList &packedCRCsDefined, QList &packedCRCs);
+    void writeUnpackInfo(const QList &folderItems);
+    void writeSubStreamsInfo(const QList &unpackSizes, const QList &digestsDefined, const QList &digests);
+    void writeHeader(quint64 &headerOffset);
+    void writeSignature();
+    void writeStartHeader(const quint64 nextHeaderSize, const quint32 nextHeaderCRC, const quint64 nextHeaderOffset);
+    QByteArray encodeStream(QList &packSizes, QList &folds);
+};
+
+K7Zip::K7Zip(const QString &fileName)
+    : KArchive(fileName)
+    , d(new K7ZipPrivate(this))
+{
+}
+
+K7Zip::K7Zip(QIODevice *dev)
+    : KArchive(dev)
+    , d(new K7ZipPrivate(this))
+{
+    Q_ASSERT(dev);
+}
+
+K7Zip::~K7Zip()
+{
+    if (isOpen()) {
+        close();
+    }
+
+    delete d;
+}
+
+int K7Zip::K7ZipPrivate::readByte()
+{
+    if (!buffer || pos + 1 > end) {
+        return -1;
+    }
+    return buffer[pos++];
+}
+
+quint32 K7Zip::K7ZipPrivate::readUInt32()
+{
+    if (!buffer || (quint64)(pos + 4) > end) {
+        qCDebug(KArchiveLog) << "error size";
+        return 0;
+    }
+
+    quint32 res = GetUi32(buffer, pos);
+    pos += 4;
+    return res;
+}
+
+quint64 K7Zip::K7ZipPrivate::readUInt64()
+{
+    if (!buffer || (quint64)(pos + 8) > end) {
+        qCDebug(KArchiveLog) << "error size";
+        return 0;
+    }
+
+    quint64 res = GetUi64(buffer, pos);
+    pos += 8;
+    return res;
+}
+
+quint64 K7Zip::K7ZipPrivate::readNumber()
+{
+    if (!buffer || (quint64)(pos + 8) > end) {
+        return 0;
+    }
+
+    unsigned char firstByte = buffer[pos++];
+    unsigned char mask = 0x80;
+    quint64 value = 0;
+    for (int i = 0; i < 8; i++) {
+        if ((firstByte & mask) == 0) {
+            quint64 highPart = firstByte & (mask - 1);
+            value += (highPart << (i * 8));
+            return value;
+        }
+        value |= ((unsigned char)buffer[pos++] << (8 * i));
+        mask >>= 1;
+    }
+    return value;
+}
+
+QString K7Zip::K7ZipPrivate::readString()
+{
+    if (!buffer) {
+        return QString();
+    }
+
+    const char *buf = buffer + pos;
+    size_t rem = (end - pos) / 2 * 2;
+    {
+        size_t i;
+        for (i = 0; i < rem; i += 2) {
+            if (buf[i] == 0 && buf[i + 1] == 0) {
+                break;
+            }
+        }
+        if (i == rem) {
+            qCDebug(KArchiveLog) << "read string error";
+            return QString();
+        }
+        rem = i;
+    }
+
+    int len = (int)(rem / 2);
+    if (len < 0 || (size_t)len * 2 != rem) {
+        qCDebug(KArchiveLog) << "read string unsupported";
+        return QString();
+    }
+
+    QString p;
+    for (int i = 0; i < len; i++, buf += 2) {
+        p += GetUi16(buf, 0);
+    }
+
+    pos += rem + 2;
+    return p;
+}
+
+void K7Zip::K7ZipPrivate::skipData(int size)
+{
+    if (!buffer || pos + size > end) {
+        return;
+    }
+    pos += size;
+}
+
+bool K7Zip::K7ZipPrivate::findAttribute(int attribute)
+{
+    if (!buffer) {
+        return false;
+    }
+
+    for (;;) {
+        int type = readByte();
+        if (type == attribute) {
+            return true;
+        }
+        if (type == kEnd) {
+            return false;
+        }
+        skipData(readNumber());
+    }
+}
+
+void K7Zip::K7ZipPrivate::readBoolVector(int numItems, QList &v)
+{
+    if (!buffer) {
+        return;
+    }
+
+    unsigned char b = 0;
+    unsigned char mask = 0;
+    for (int i = 0; i < numItems; i++) {
+        if (mask == 0) {
+            b = readByte();
+            mask = 0x80;
+        }
+        v.append((b & mask) != 0);
+        mask >>= 1;
+    }
+}
+
+void K7Zip::K7ZipPrivate::readBoolVector2(int numItems, QList &v)
+{
+    if (!buffer) {
+        return;
+    }
+
+    int allAreDefined = readByte();
+    if (allAreDefined == 0) {
+        readBoolVector(numItems, v);
+        return;
+    }
+
+    for (int i = 0; i < numItems; i++) {
+        v.append(true);
+    }
+}
+
+void K7Zip::K7ZipPrivate::readHashDigests(int numItems, QList &digestsDefined, QList &digests)
+{
+    if (!buffer) {
+        return;
+    }
+
+    readBoolVector2(numItems, digestsDefined);
+    for (int i = 0; i < numItems; i++) {
+        quint32 crc = 0;
+        if (digestsDefined[i]) {
+            crc = GetUi32(buffer, pos);
+            pos += 4;
+        }
+        digests.append(crc);
+    }
+}
+
+Folder *K7Zip::K7ZipPrivate::folderItem()
+{
+    if (!buffer) {
+        return nullptr;
+    }
+
+    Folder *folder = new Folder;
+    int numCoders = readNumber();
+
+    quint64 numInStreamsTotal = 0;
+    quint64 numOutStreamsTotal = 0;
+    for (int i = 0; i < numCoders; ++i) {
+        // BYTE
+        //    {
+        //      0:3 CodecIdSize
+        //      4:  Is Complex Coder
+        //      5:  There Are Attributes
+        //      6:  Reserved
+        //      7:  There are more alternative methods. (Not used
+        //      anymore, must be 0).
+        //    }
+        unsigned char coderInfo = readByte();
+        int codecIdSize = (coderInfo & 0xF);
+        if (codecIdSize > 8) {
+            qCDebug(KArchiveLog) << "unsupported codec id size";
+            delete folder;
+            return nullptr;
+        }
+        Folder::FolderInfo *info = new Folder::FolderInfo();
+        std::unique_ptr codecID(new unsigned char[codecIdSize]);
+        for (int i = 0; i < codecIdSize; ++i) {
+            codecID[i] = readByte();
+        }
+
+        int id = 0;
+        for (int j = 0; j < codecIdSize; j++) {
+            id |= codecID[codecIdSize - 1 - j] << (8 * j);
+        }
+        info->methodID = id;
+
+        // if (Is Complex Coder)
+        if ((coderInfo & 0x10) != 0) {
+            info->numInStreams = readNumber();
+            info->numOutStreams = readNumber();
+        } else {
+            info->numInStreams = 1;
+            info->numOutStreams = 1;
+        }
+
+        // if (There Are Attributes)
+        if ((coderInfo & 0x20) != 0) {
+            int propertiesSize = readNumber();
+            for (int i = 0; i < propertiesSize; ++i) {
+                info->properties.append(readByte());
+            }
+        }
+
+        if ((coderInfo & 0x80) != 0) {
+            qCDebug(KArchiveLog) << "unsupported";
+            delete info;
+            delete folder;
+            return nullptr;
+        }
+
+        numInStreamsTotal += info->numInStreams;
+        numOutStreamsTotal += info->numOutStreams;
+        folder->folderInfos.append(info);
+    }
+
+    int numBindPairs = numOutStreamsTotal - 1;
+    for (int i = 0; i < numBindPairs; i++) {
+        folder->inIndexes.append(readNumber());
+        folder->outIndexes.append(readNumber());
+    }
+
+    int numPackedStreams = numInStreamsTotal - numBindPairs;
+    if (numPackedStreams > 1) {
+        for (int i = 0; i < numPackedStreams; ++i) {
+            folder->packedStreams.append(readNumber());
+        }
+    } else {
+        if (numPackedStreams == 1) {
+            for (quint64 i = 0; i < numInStreamsTotal; i++) {
+                if (folder->findBindPairForInStream(i) < 0) {
+                    folder->packedStreams.append(i);
+                    break;
+                }
+            }
+            if (folder->packedStreams.size() != 1) {
+                delete folder;
+                return nullptr;
+            }
+        }
+    }
+    return folder;
+}
+
+bool K7Zip::K7ZipPrivate::readUInt64DefVector(int numFiles, QList &values, QList &defined)
+{
+    if (!buffer) {
+        return false;
+    }
+
+    readBoolVector2(numFiles, defined);
+
+    int external = readByte();
+    if (external != 0) {
+        int dataIndex = readNumber();
+        if (dataIndex < 0 /*|| dataIndex >= dataVector->Size()*/) {
+            qCDebug(KArchiveLog) << "wrong data index";
+            return false;
+        }
+
+        // TODO : go to the new index
+    }
+
+    for (int i = 0; i < numFiles; i++) {
+        quint64 t = 0;
+        if (defined[i]) {
+            t = readUInt64();
+        }
+        values.append(t);
+    }
+    return true;
+}
+
+bool K7Zip::K7ZipPrivate::readPackInfo()
+{
+    if (!buffer) {
+        return false;
+    }
+
+    packPos = readNumber();
+    numPackStreams = readNumber();
+    packSizes.clear();
+
+    packCRCsDefined.clear();
+    packCRCs.clear();
+
+    if (!findAttribute(kSize)) {
+        qCDebug(KArchiveLog) << "kSize not found";
+        return false;
+    }
+
+    for (quint64 i = 0; i < numPackStreams; ++i) {
+        packSizes.append(readNumber());
+    }
+
+    for (;;) {
+        int type = readByte();
+        if (type == kEnd) {
+            break;
+        }
+        if (type == kCRC) {
+            readHashDigests(numPackStreams, packCRCsDefined, packCRCs);
+            continue;
+        }
+        skipData(readNumber());
+    }
+
+    if (packCRCs.isEmpty()) {
+        for (quint64 i = 0; i < numPackStreams; ++i) {
+            packCRCsDefined.append(false);
+            packCRCs.append(0);
+        }
+    }
+    return true;
+}
+
+bool K7Zip::K7ZipPrivate::readUnpackInfo()
+{
+    if (!buffer) {
+        return false;
+    }
+
+    if (!findAttribute(kFolder)) {
+        qCDebug(KArchiveLog) << "kFolder not found";
+        return false;
+    }
+
+    int numFolders = readNumber();
+    qDeleteAll(folders);
+    folders.clear();
+    int external = readByte();
+    switch (external) {
+    case 0: {
+        for (int i = 0; i < numFolders; ++i) {
+            folders.append(folderItem());
+        }
+        break;
+    }
+    case 1: {
+        int dataIndex = readNumber();
+        if (dataIndex < 0 /*|| dataIndex >= dataVector->Size()*/) {
+            qCDebug(KArchiveLog) << "wrong data index";
+        }
+        // TODO : go to the new index
+        break;
+    }
+    default:
+        qCDebug(KArchiveLog) << "external error";
+        return false;
+    }
+
+    if (!findAttribute(kCodersUnpackSize)) {
+        qCDebug(KArchiveLog) << "kCodersUnpackSize not found";
+        return false;
+    }
+
+    for (int i = 0; i < numFolders; ++i) {
+        Folder *folder = folders.at(i);
+        int numOutStreams = folder->getNumOutStreams();
+        for (int j = 0; j < numOutStreams; ++j) {
+            folder->unpackSizes.append(readNumber());
+        }
+    }
+
+    for (;;) {
+        int type = readByte();
+        if (type == kEnd) {
+            break;
+        }
+        if (type == kCRC) {
+            QList crcsDefined;
+            QList crcs;
+            readHashDigests(numFolders, crcsDefined, crcs);
+            for (int i = 0; i < numFolders; i++) {
+                Folder *folder = folders.at(i);
+                folder->unpackCRCDefined = crcsDefined[i];
+                folder->unpackCRC = crcs[i];
+            }
+            continue;
+        }
+        skipData(readNumber());
+    }
+    return true;
+}
+
+bool K7Zip::K7ZipPrivate::readSubStreamsInfo()
+{
+    if (!buffer) {
+        return false;
+    }
+
+    numUnpackStreamsInFolders.clear();
+
+    int type;
+    for (;;) {
+        type = readByte();
+        if (type == kNumUnpackStream) {
+            for (int i = 0; i < folders.size(); i++) {
+                numUnpackStreamsInFolders.append(readNumber());
+            }
+            continue;
+        }
+        if (type == kCRC || type == kSize) {
+            break;
+        }
+        if (type == kEnd) {
+            break;
+        }
+        skipData(readNumber());
+    }
+
+    if (numUnpackStreamsInFolders.isEmpty()) {
+        for (int i = 0; i < folders.size(); i++) {
+            numUnpackStreamsInFolders.append(1);
+        }
+    }
+
+    for (int i = 0; i < numUnpackStreamsInFolders.size(); i++) {
+        quint64 numSubstreams = numUnpackStreamsInFolders.at(i);
+        if (numSubstreams == 0) {
+            continue;
+        }
+        quint64 sum = 0;
+        for (quint64 j = 1; j < numSubstreams; j++) {
+            if (type == kSize) {
+                int size = readNumber();
+                unpackSizes.append(size);
+                sum += size;
+            }
+        }
+        unpackSizes.append(folders.at(i)->getUnpackSize() - sum);
+    }
+
+    if (type == kSize) {
+        type = readByte();
+    }
+
+    int numDigests = 0;
+    int numDigestsTotal = 0;
+    for (int i = 0; i < folders.size(); i++) {
+        quint64 numSubstreams = numUnpackStreamsInFolders.at(i);
+        if (numSubstreams != 1 || !folders.at(i)->unpackCRCDefined) {
+            numDigests += numSubstreams;
+        }
+        numDigestsTotal += numSubstreams;
+    }
+
+    for (;;) {
+        if (type == kCRC) {
+            QList digestsDefined2;
+            QList digests2;
+            readHashDigests(numDigests, digestsDefined2, digests2);
+            int digestIndex = 0;
+            for (int i = 0; i < folders.size(); i++) {
+                quint64 numSubstreams = numUnpackStreamsInFolders.at(i);
+                const Folder *folder = folders.at(i);
+                if (numSubstreams == 1 && folder->unpackCRCDefined) {
+                    digestsDefined.append(true);
+                    digests.append(folder->unpackCRC);
+                } else {
+                    for (quint64 j = 0; j < numSubstreams; j++, digestIndex++) {
+                        digestsDefined.append(digestsDefined2[digestIndex]);
+                        digests.append(digests2[digestIndex]);
+                    }
+                }
+            }
+        } else if (type == kEnd) {
+            if (digestsDefined.isEmpty()) {
+                for (int i = 0; i < numDigestsTotal; i++) {
+                    digestsDefined.append(false);
+                    digests.append(0);
+                }
+            }
+
+            break;
+        } else {
+            skipData(readNumber());
+        }
+
+        type = readByte();
+    }
+    return true;
+}
+
+#define TICKSPERSEC 10000000
+#define TICKSPERMSEC 10000
+#define SECSPERDAY 86400
+#define SECSPERHOUR 3600
+#define SECSPERMIN 60
+#define EPOCHWEEKDAY 1 /* Jan 1, 1601 was Monday */
+#define DAYSPERWEEK 7
+#define DAYSPERQUADRICENTENNIUM (365 * 400 + 97)
+#define DAYSPERNORMALQUADRENNIUM (365 * 4 + 1)
+#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
+#define SECS_1601_TO_1970 ((369 * 365 + 89) * (unsigned long long)SECSPERDAY)
+
+static uint toTimeT(const long long liTime)
+{
+    long long time = liTime / TICKSPERSEC;
+
+    /* The native version of RtlTimeToTimeFields does not take leap seconds
+     * into account */
+
+    /* Split the time into days and seconds within the day */
+    long int days = time / SECSPERDAY;
+    int secondsInDay = time % SECSPERDAY;
+
+    /* compute time of day */
+    short hour = (short)(secondsInDay / SECSPERHOUR);
+    secondsInDay = secondsInDay % SECSPERHOUR;
+    short minute = (short)(secondsInDay / SECSPERMIN);
+    short second = (short)(secondsInDay % SECSPERMIN);
+
+    /* compute year, month and day of month. */
+    long int cleaps = (3 * ((4 * days + 1227) / DAYSPERQUADRICENTENNIUM) + 3) / 4;
+    days += 28188 + cleaps;
+    long int years = (20 * days - 2442) / (5 * DAYSPERNORMALQUADRENNIUM);
+    long int yearday = days - (years * DAYSPERNORMALQUADRENNIUM) / 4;
+    long int months = (64 * yearday) / 1959;
+    /* the result is based on a year starting on March.
+     * To convert take 12 from January and February and
+     * increase the year by one. */
+
+    short month;
+    short year;
+    if (months < 14) {
+        month = (short)(months - 1);
+        year = (short)(years + 1524);
+    } else {
+        month = (short)(months - 13);
+        year = (short)(years + 1525);
+    }
+    /* calculation of day of month is based on the wonderful
+     * sequence of INT( n * 30.6): it reproduces the·
+     * 31-30-31-30-31-31 month lengths exactly for small n's */
+    short day = (short)(yearday - (1959 * months) / 64);
+
+    QDateTime t(QDate(year, month, day), QTime(hour, minute, second));
+    t.setTimeZone(QTimeZone::utc());
+    return t.toSecsSinceEpoch();
+}
+
+long long rtlSecondsSince1970ToSpecTime(quint32 seconds)
+{
+    long long secs = seconds * (long long)TICKSPERSEC + TICKS_1601_TO_1970;
+    return secs;
+}
+
+bool K7Zip::K7ZipPrivate::readMainStreamsInfo()
+{
+    if (!buffer) {
+        return false;
+    }
+
+    quint32 type;
+    for (;;) {
+        type = readByte();
+        if (type > ((quint32)1 << 30)) {
+            qCDebug(KArchiveLog) << "type error";
+            return false;
+        }
+        switch (type) {
+        case kEnd:
+            return true;
+        case kPackInfo: {
+            if (!readPackInfo()) {
+                qCDebug(KArchiveLog) << "error during read pack information";
+                return false;
+            }
+            break;
+        }
+        case kUnpackInfo: {
+            if (!readUnpackInfo()) {
+                qCDebug(KArchiveLog) << "error during read pack information";
+                return false;
+            }
+            break;
+        }
+        case kSubStreamsInfo: {
+            if (!readSubStreamsInfo()) {
+                qCDebug(KArchiveLog) << "error during read substreams information";
+                return false;
+            }
+            break;
+        }
+        default:
+            qCDebug(KArchiveLog) << "Wrong type";
+            return false;
+        }
+    }
+
+    qCDebug(KArchiveLog) << "should not reach";
+    return false;
+}
+
+static bool getInStream(const Folder *folder, quint32 streamIndex, int &seqInStream, quint32 &coderIndex)
+{
+    for (int i = 0; i < folder->packedStreams.size(); i++) {
+        if (folder->packedStreams[i] == streamIndex) {
+            seqInStream = i;
+            return true;
+        }
+    }
+
+    int binderIndex = folder->findBindPairForInStream(streamIndex);
+    if (binderIndex < 0) {
+        return false;
+    }
+
+    quint32 coderStreamIndex;
+    folder->findOutStream(folder->outIndexes[binderIndex], coderIndex, coderStreamIndex);
+
+    quint32 startIndex = folder->getCoderInStreamIndex(coderIndex);
+
+    if (folder->folderInfos[coderIndex]->numInStreams > 1) {
+        return false;
+    }
+
+    for (int i = 0; i < (int)folder->folderInfos[coderIndex]->numInStreams; i++) {
+        getInStream(folder, startIndex + i, seqInStream, coderIndex);
+    }
+
+    return true;
+}
+
+static bool getOutStream(const Folder *folder, quint32 streamIndex, int &seqOutStream)
+{
+    QList outStreams;
+    quint32 outStreamIndex = 0;
+    for (int i = 0; i < folder->folderInfos.size(); i++) {
+        const Folder::FolderInfo *coderInfo = folder->folderInfos.at(i);
+
+        for (int j = 0; j < coderInfo->numOutStreams; j++, outStreamIndex++) {
+            if (folder->findBindPairForOutStream(outStreamIndex) < 0) {
+                outStreams.append(outStreamIndex);
+            }
+        }
+    }
+
+    for (int i = 0; i < outStreams.size(); i++) {
+        if (outStreams[i] == streamIndex) {
+            seqOutStream = i;
+            return true;
+        }
+    }
+
+    int binderIndex = folder->findBindPairForOutStream(streamIndex);
+    if (binderIndex < 0) {
+        return false;
+    }
+
+    quint32 coderIndex;
+    quint32 coderStreamIndex;
+    folder->findInStream(folder->inIndexes[binderIndex], coderIndex, coderStreamIndex);
+
+    quint32 startIndex = folder->getCoderOutStreamIndex(coderIndex);
+
+    if (folder->folderInfos[coderIndex]->numOutStreams > 1) {
+        return false;
+    }
+
+    for (int i = 0; i < (int)folder->folderInfos[coderIndex]->numOutStreams; i++) {
+        getOutStream(folder, startIndex + i, seqOutStream);
+    }
+
+    return true;
+}
+
+const int kNumTopBits = 24;
+const quint32 kTopValue = (1 << kNumTopBits);
+
+class RangeDecoder
+{
+    int pos;
+
+public:
+    QByteArray stream;
+    quint32 range;
+    quint32 code;
+
+    RangeDecoder(const QByteArray &s)
+        : pos(0)
+        , stream(s)
+        , range(0xFFFFFFFF)
+        , code(0)
+    {
+        for (int i = 0; i < 5; i++) {
+            code = (code << 8) | readByte();
+        }
+    }
+
+    unsigned char readByte()
+    {
+        if (pos >= stream.size()) {
+            return 0;
+        }
+        return stream[pos++];
+    }
+
+    void normalize()
+    {
+        while (range < kTopValue) {
+            code = (code << 8) | readByte();
+            range <<= 8;
+        }
+    }
+
+    quint32 getThreshold(quint32 total)
+    {
+        return (code) / (range /= total);
+    }
+
+    void decode(quint32 start, quint32 size)
+    {
+        code -= start * range;
+        range *= size;
+        normalize();
+    }
+
+    quint32 decodeDirectBits(int numTotalBits)
+    {
+        quint32 r = range;
+        quint32 c = code;
+        quint32 result = 0;
+        for (int i = numTotalBits; i != 0; i--) {
+            r >>= 1;
+            quint32 t = (c - r) >> 31;
+            c -= r & (t - 1);
+            result = (result << 1) | (1 - t);
+
+            if (r < kTopValue) {
+                c = (c << 8) | readByte();
+                r <<= 8;
+            }
+        }
+        range = r;
+        code = c;
+        return result;
+    }
+
+    quint32 DecodeBit(quint32 size0, quint32 numTotalBits)
+    {
+        quint32 newBound = (range >> numTotalBits) * size0;
+        quint32 symbol;
+        if (code < newBound) {
+            symbol = 0;
+            range = newBound;
+        } else {
+            symbol = 1;
+            code -= newBound;
+            range -= newBound;
+        }
+        normalize();
+        return symbol;
+    }
+};
+
+const int kNumBitModelTotalBits = 11;
+const quint32 kBitModelTotal = (1 << kNumBitModelTotalBits);
+
+template
+class CBitModel
+{
+public:
+    quint32 prob;
+    void updateModel(quint32 symbol)
+    {
+        if (symbol == 0) {
+            prob += (kBitModelTotal - prob) >> numMoveBits;
+        } else {
+            prob -= (prob) >> numMoveBits;
+        }
+    }
+
+    void init()
+    {
+        prob = kBitModelTotal / 2;
+    }
+};
+
+template
+class CBitDecoder : public CBitModel
+{
+public:
+    quint32 decode(RangeDecoder *decoder)
+    {
+        quint32 newBound = (decoder->range >> kNumBitModelTotalBits) * this->prob;
+        if (decoder->code < newBound) {
+            decoder->range = newBound;
+            this->prob += (kBitModelTotal - this->prob) >> numMoveBits;
+            if (decoder->range < kTopValue) {
+                decoder->code = (decoder->code << 8) | decoder->readByte();
+                decoder->range <<= 8;
+            }
+            return 0;
+        } else {
+            decoder->range -= newBound;
+            decoder->code -= newBound;
+            this->prob -= (this->prob) >> numMoveBits;
+            if (decoder->range < kTopValue) {
+                decoder->code = (decoder->code << 8) | decoder->readByte();
+                decoder->range <<= 8;
+            }
+            return 1;
+        }
+    }
+};
+
+inline bool isJcc(unsigned char b0, unsigned char b1)
+{
+    return (b0 == 0x0F && (b1 & 0xF0) == 0x80);
+}
+inline bool isJ(unsigned char b0, unsigned char b1)
+{
+    return ((b1 & 0xFE) == 0xE8 || isJcc(b0, b1));
+}
+inline unsigned getIndex(unsigned char b0, unsigned char b1)
+{
+    return ((b1 == 0xE8) ? b0 : ((b1 == 0xE9) ? 256 : 257));
+}
+
+const int kNumMoveBits = 5;
+
+static QByteArray decodeBCJ2(const QByteArray &mainStream, const QByteArray &callStream, const QByteArray &jumpStream, const QByteArray &rangeBuffer)
+{
+    unsigned char prevByte = 0;
+    QByteArray outStream;
+    int mainStreamPos = 0;
+    int callStreamPos = 0;
+    int jumpStreamPos = 0;
+
+    RangeDecoder rangeDecoder(rangeBuffer);
+
+    QList> statusDecoder(256 + 2);
+
+    for (int i = 0; i < 256 + 2; i++) {
+        statusDecoder[i].init();
+    }
+
+    for (;;) {
+        quint32 i;
+        unsigned char b = 0;
+        const quint32 kBurstSize = (1 << 18);
+        for (i = 0; i < kBurstSize; i++) {
+            if (mainStreamPos == mainStream.size()) {
+                return outStream;
+            }
+
+            b = mainStream[mainStreamPos++];
+            outStream.append(b);
+
+            if (isJ(prevByte, b)) {
+                break;
+            }
+            prevByte = b;
+        }
+
+        if (i == kBurstSize) {
+            continue;
+        }
+
+        unsigned index = getIndex(prevByte, b);
+        if (statusDecoder[index].decode(&rangeDecoder) == 1) {
+            if (b == 0xE8) {
+                if (callStreamPos + 4 > callStream.size()) {
+                    return QByteArray();
+                }
+            } else {
+                if (jumpStreamPos + 4 > jumpStream.size()) {
+                    return QByteArray();
+                }
+            }
+            quint32 src = 0;
+            for (int i = 0; i < 4; i++) {
+                unsigned char b0;
+                if (b == 0xE8) {
+                    b0 = callStream[callStreamPos++];
+                } else {
+                    b0 = jumpStream[jumpStreamPos++];
+                }
+                src <<= 8;
+                src |= ((quint32)b0);
+            }
+
+            quint32 dest = src - (quint32(outStream.size()) + 4);
+            outStream.append((unsigned char)(dest));
+            outStream.append((unsigned char)(dest >> 8));
+            outStream.append((unsigned char)(dest >> 16));
+            outStream.append((unsigned char)(dest >> 24));
+            prevByte = (unsigned char)(dest >> 24);
+        } else {
+            prevByte = b;
+        }
+    }
+}
+
+QByteArray K7Zip::K7ZipPrivate::readAndDecodePackedStreams(bool readMainStreamInfo)
+{
+    if (!buffer) {
+        return QByteArray();
+    }
+
+    if (readMainStreamInfo) {
+        readMainStreamsInfo();
+    }
+
+    QByteArray inflatedData;
+
+    quint64 startPos = 32 + packPos;
+    for (int i = 0; i < folders.size(); i++) {
+        const Folder *folder = folders.at(i);
+        quint64 unpackSize64 = folder->getUnpackSize();
+        size_t unpackSize = (size_t)unpackSize64;
+        if (unpackSize != unpackSize64) {
+            qCDebug(KArchiveLog) << "unsupported";
+            return inflatedData;
+        }
+
+        // Find main coder
+        quint32 mainCoderIndex = 0;
+        QList outStreamIndexed;
+        int outStreamIndex = 0;
+        for (int j = 0; j < folder->folderInfos.size(); j++) {
+            const Folder::FolderInfo *info = folder->folderInfos[j];
+            for (int k = 0; k < info->numOutStreams; k++, outStreamIndex++) {
+                if (folder->findBindPairForOutStream(outStreamIndex) < 0) {
+                    outStreamIndexed.append(outStreamIndex);
+                    break;
+                }
+            }
+        }
+
+        quint32 temp = 0;
+        if (!outStreamIndexed.isEmpty()) {
+            folder->findOutStream(outStreamIndexed[0], mainCoderIndex, temp);
+        }
+
+        quint32 startInIndex = folder->getCoderInStreamIndex(mainCoderIndex);
+        quint32 startOutIndex = folder->getCoderOutStreamIndex(mainCoderIndex);
+
+        Folder::FolderInfo *mainCoder = folder->folderInfos[mainCoderIndex];
+
+        QList seqInStreams;
+        QList coderIndexes;
+        seqInStreams.reserve(mainCoder->numInStreams);
+        coderIndexes.reserve(mainCoder->numInStreams);
+        for (int j = 0; j < (int)mainCoder->numInStreams; j++) {
+            int seqInStream;
+            quint32 coderIndex;
+            getInStream(folder, startInIndex + j, seqInStream, coderIndex);
+            seqInStreams.append(seqInStream);
+            coderIndexes.append(coderIndex);
+        }
+
+        QList seqOutStreams;
+        seqOutStreams.reserve(mainCoder->numOutStreams);
+        for (int j = 0; j < (int)mainCoder->numOutStreams; j++) {
+            int seqOutStream;
+            getOutStream(folder, startOutIndex + j, seqOutStream);
+            seqOutStreams.append(seqOutStream);
+        }
+
+        QList datas;
+        for (int j = 0; j < (int)mainCoder->numInStreams; j++) {
+            quint64 size = packSizes[j + i];
+            std::unique_ptr encodedBuffer(new char[size]);
+            QIODevice *dev = q->device();
+            dev->seek(startPos);
+            quint64 n = dev->read(encodedBuffer.get(), size);
+            if (n != size) {
+                qCDebug(KArchiveLog) << "Failed read next size, should read " << size << ", read " << n;
+                return inflatedData;
+            }
+            QByteArray deflatedData(encodedBuffer.get(), size);
+            datas.append(deflatedData);
+            startPos += size;
+            pos += size;
+            headerSize += size;
+        }
+
+        QList inflatedDatas;
+        QByteArray deflatedData;
+        for (int j = 0; j < seqInStreams.size(); ++j) {
+            Folder::FolderInfo *coder = nullptr;
+            if ((quint32)j != mainCoderIndex) {
+                coder = folder->folderInfos[coderIndexes[j]];
+            } else {
+                coder = folder->folderInfos[mainCoderIndex];
+            }
+
+            deflatedData = datas[seqInStreams[j]];
+
+            KFilterBase *filter = nullptr;
+
+            switch (coder->methodID) {
+            case k_LZMA:
+                filter = KCompressionDevice::filterForCompressionType(KCompressionDevice::Xz);
+                if (!filter) {
+                    qCDebug(KArchiveLog) << "filter not found";
+                    return QByteArray();
+                }
+                static_cast(filter)->init(QIODevice::ReadOnly, KXzFilter::LZMA, coder->properties);
+                break;
+            case k_LZMA2:
+                filter = KCompressionDevice::filterForCompressionType(KCompressionDevice::Xz);
+                if (!filter) {
+                    qCDebug(KArchiveLog) << "filter not found";
+                    return QByteArray();
+                }
+                static_cast(filter)->init(QIODevice::ReadOnly, KXzFilter::LZMA2, coder->properties);
+                break;
+            case k_PPMD: {
+                /*if (coder->properties.size() == 5) {
+                    //Byte order = *(const Byte *)coder.Props;
+                    qint32 dicSize = ((unsigned char)coder->properties[1]        |
+                                     (((unsigned char)coder->properties[2]) <<  8) |
+                                     (((unsigned char)coder->properties[3]) << 16) |
+                                     (((unsigned char)coder->properties[4]) << 24));
+                }*/
+                break;
+            }
+            case k_AES:
+                if (coder->properties.size() >= 1) {
+                    // const Byte *data = (const Byte *)coder.Props;
+                    // Byte firstByte = *data++;
+                    // UInt32 numCyclesPower = firstByte & 0x3F;
+                }
+                break;
+            case k_BCJ:
+                filter = KCompressionDevice::filterForCompressionType(KCompressionDevice::Xz);
+                if (!filter) {
+                    qCDebug(KArchiveLog) << "filter not found";
+                    return QByteArray();
+                }
+                static_cast(filter)->init(QIODevice::ReadOnly, KXzFilter::BCJ, coder->properties);
+                break;
+            case k_BCJ2: {
+                QByteArray bcj2 = decodeBCJ2(inflatedDatas[0], inflatedDatas[1], inflatedDatas[2], deflatedData);
+                inflatedDatas.clear();
+                inflatedDatas.append(bcj2);
+                break;
+            }
+            case k_BZip2:
+                filter = KCompressionDevice::filterForCompressionType(KCompressionDevice::BZip2);
+                if (!filter) {
+                    qCDebug(KArchiveLog) << "filter not found";
+                    return QByteArray();
+                }
+                filter->init(QIODevice::ReadOnly);
+                break;
+            }
+
+            if (coder->methodID == k_BCJ2) {
+                continue;
+            }
+
+            if (!filter) {
+                return QByteArray();
+            }
+
+            filter->setInBuffer(deflatedData.data(), deflatedData.size());
+
+            QByteArray outBuffer;
+            // reserve memory
+            outBuffer.resize(unpackSize);
+
+            KFilterBase::Result result = KFilterBase::Ok;
+            QByteArray inflatedDataTmp;
+            while (result != KFilterBase::End && result != KFilterBase::Error && !filter->inBufferEmpty()) {
+                filter->setOutBuffer(outBuffer.data(), outBuffer.size());
+                result = filter->uncompress();
+                if (result == KFilterBase::Error) {
+                    qCDebug(KArchiveLog) << " decode error";
+                    filter->terminate();
+                    delete filter;
+                    return QByteArray();
+                }
+                int uncompressedBytes = outBuffer.size() - filter->outBufferAvailable();
+
+                // append the uncompressed data to inflate buffer
+                inflatedDataTmp.append(outBuffer.data(), uncompressedBytes);
+
+                if (result == KFilterBase::End) {
+                    // qCDebug(KArchiveLog) << "Finished unpacking";
+                    break; // Finished.
+                }
+            }
+
+            if (result != KFilterBase::End && !filter->inBufferEmpty()) {
+                qCDebug(KArchiveLog) << "decode failed result" << result;
+                filter->terminate();
+                delete filter;
+                return QByteArray();
+            }
+
+            filter->terminate();
+            delete filter;
+
+            inflatedDatas.append(inflatedDataTmp);
+        }
+
+        QByteArray inflated;
+        for (const QByteArray &data : std::as_const(inflatedDatas)) {
+            inflated.append(data);
+        }
+
+        inflatedDatas.clear();
+
+        if (folder->unpackCRCDefined) {
+            if ((size_t)inflated.size() < unpackSize) {
+                qCDebug(KArchiveLog) << "wrong crc size data";
+                return QByteArray();
+            }
+            quint32 crc = crc32(0, (Bytef *)(inflated.data()), unpackSize);
+            if (crc != folder->unpackCRC) {
+                qCDebug(KArchiveLog) << "wrong crc";
+                return QByteArray();
+            }
+        }
+
+        inflatedData.append(inflated);
+    }
+
+    return inflatedData;
+}
+
+///////////////// Write ////////////////////
+
+void K7Zip::K7ZipPrivate::createItemsFromEntities(const KArchiveDirectory *dir, const QString &path, QByteArray &data)
+{
+    const QStringList l = dir->entries();
+    QStringList::ConstIterator it = l.begin();
+    for (; it != l.end(); ++it) {
+        const KArchiveEntry *entry = dir->entry((*it));
+
+        FileInfo *fileInfo = new FileInfo;
+        fileInfo->attribDefined = true;
+
+        fileInfo->path = path + entry->name();
+        mTimesDefined.append(true);
+        mTimes.append(rtlSecondsSince1970ToSpecTime(entry->date().toSecsSinceEpoch()));
+
+        if (entry->isFile()) {
+            const K7ZipFileEntry *fileEntry = static_cast(entry);
+
+            fileInfo->attributes = FILE_ATTRIBUTE_ARCHIVE;
+            fileInfo->attributes |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((entry->permissions() & 0xFFFF) << 16);
+            fileInfo->size = fileEntry->size();
+            QString symLink = fileEntry->symLinkTarget();
+            if (fileInfo->size > 0) {
+                fileInfo->hasStream = true;
+                data.append(outData.mid(fileEntry->position(), fileEntry->size()));
+                unpackSizes.append(fileInfo->size);
+            } else if (!symLink.isEmpty()) {
+                fileInfo->hasStream = true;
+                data.append(symLink.toUtf8());
+                unpackSizes.append(symLink.size());
+            }
+            fileInfos.append(fileInfo);
+        } else if (entry->isDirectory()) {
+            fileInfo->attributes = FILE_ATTRIBUTE_DIRECTORY;
+            fileInfo->attributes |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((entry->permissions() & 0xFFFF) << 16);
+            fileInfo->isDir = true;
+            fileInfos.append(fileInfo);
+            createItemsFromEntities((KArchiveDirectory *)entry, path + (*it) + QLatin1Char('/'), data);
+        }
+    }
+}
+
+void K7Zip::K7ZipPrivate::writeByte(unsigned char b)
+{
+    header.append(b);
+    countSize++;
+}
+
+void K7Zip::K7ZipPrivate::writeNumber(quint64 value)
+{
+    int firstByte = 0;
+    short mask = 0x80;
+    int i;
+    for (i = 0; i < 8; i++) {
+        if (value < ((quint64(1) << (7 * (i + 1))))) {
+            firstByte |= (int)(value >> (8 * i));
+            break;
+        }
+        firstByte |= mask;
+        mask >>= 1;
+    }
+    writeByte(firstByte);
+    for (; i > 0; i--) {
+        writeByte((int)value);
+        value >>= 8;
+    }
+}
+
+void K7Zip::K7ZipPrivate::writeBoolVector(const QList &boolVector)
+{
+    int b = 0;
+    short mask = 0x80;
+    for (int i = 0; i < boolVector.size(); i++) {
+        if (boolVector[i]) {
+            b |= mask;
+        }
+        mask >>= 1;
+        if (mask == 0) {
+            writeByte(b);
+            mask = 0x80;
+            b = 0;
+        }
+    }
+    if (mask != 0x80) {
+        writeByte(b);
+    }
+}
+
+void K7Zip::K7ZipPrivate::writeUInt32(quint32 value)
+{
+    for (int i = 0; i < 4; i++) {
+        writeByte((unsigned char)value);
+        value >>= 8;
+    }
+}
+
+void K7Zip::K7ZipPrivate::writeUInt64(quint64 value)
+{
+    for (int i = 0; i < 8; i++) {
+        writeByte((unsigned char)value);
+        value >>= 8;
+    }
+}
+
+void K7Zip::K7ZipPrivate::writeAlignedBoolHeader(const QList &v, int numDefined, int type, unsigned itemSize)
+{
+    const unsigned bvSize = (numDefined == v.size()) ? 0 : ((unsigned)v.size() + 7) / 8;
+    const quint64 dataSize = (quint64)numDefined * itemSize + bvSize + 2;
+    // SkipAlign(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSize);
+
+    writeByte(type);
+    writeNumber(dataSize);
+    if (numDefined == v.size()) {
+        writeByte(1);
+    } else {
+        writeByte(0);
+        writeBoolVector(v);
+    }
+    writeByte(0);
+}
+
+void K7Zip::K7ZipPrivate::writeUInt64DefVector(const QList &v, const QList &defined, int type)
+{
+    int numDefined = 0;
+
+    for (int i = 0; i < defined.size(); i++) {
+        if (defined[i]) {
+            numDefined++;
+        }
+    }
+
+    if (numDefined == 0) {
+        return;
+    }
+
+    writeAlignedBoolHeader(defined, numDefined, type, 8);
+
+    for (int i = 0; i < defined.size(); i++) {
+        if (defined[i]) {
+            writeUInt64(v[i]);
+        }
+    }
+}
+
+void K7Zip::K7ZipPrivate::writeHashDigests(const QList &digestsDefined, const QList &digests)
+{
+    int numDefined = 0;
+    int i;
+    for (i = 0; i < digestsDefined.size(); i++) {
+        if (digestsDefined[i]) {
+            numDefined++;
+        }
+    }
+
+    if (numDefined == 0) {
+        return;
+    }
+
+    writeByte(kCRC);
+    if (numDefined == digestsDefined.size()) {
+        writeByte(1);
+    } else {
+        writeByte(0);
+        writeBoolVector(digestsDefined);
+    }
+
+    for (i = 0; i < digests.size(); i++) {
+        if (digestsDefined[i]) {
+            writeUInt32(digests[i]);
+        }
+    }
+}
+
+void K7Zip::K7ZipPrivate::writePackInfo(quint64 dataOffset, QList &packedSizes, QList &packedCRCsDefined, QList &packedCRCs)
+{
+    if (packedSizes.isEmpty()) {
+        return;
+    }
+    writeByte(kPackInfo);
+    writeNumber(dataOffset);
+    writeNumber(packedSizes.size());
+    writeByte(kSize);
+
+    for (int i = 0; i < packedSizes.size(); i++) {
+        writeNumber(packedSizes[i]);
+    }
+
+    writeHashDigests(packedCRCsDefined, packedCRCs);
+
+    writeByte(kEnd);
+}
+
+void K7Zip::K7ZipPrivate::writeFolder(const Folder *folder)
+{
+    writeNumber(folder->folderInfos.size());
+    for (int i = 0; i < folder->folderInfos.size(); i++) {
+        const Folder::FolderInfo *info = folder->folderInfos.at(i);
+        {
+            size_t propsSize = info->properties.size();
+
+            quint64 id = info->methodID;
+            size_t idSize;
+            for (idSize = 1; idSize < sizeof(id); idSize++) {
+                if ((id >> (8 * idSize)) == 0) {
+                    break;
+                }
+            }
+
+            int longID[15];
+            for (int t = idSize - 1; t >= 0; t--, id >>= 8) {
+                longID[t] = (int)(id & 0xFF);
+            }
+
+            int b;
+            b = (int)(idSize & 0xF);
+            bool isComplex = !info->isSimpleCoder();
+            b |= (isComplex ? 0x10 : 0);
+            b |= ((propsSize != 0) ? 0x20 : 0);
+
+            writeByte(b);
+            for (size_t j = 0; j < idSize; ++j) {
+                writeByte(longID[j]);
+            }
+
+            if (isComplex) {
+                writeNumber(info->numInStreams);
+                writeNumber(info->numOutStreams);
+            }
+
+            if (propsSize == 0) {
+                continue;
+            }
+
+            writeNumber(propsSize);
+            for (size_t j = 0; j < propsSize; ++j) {
+                writeByte(info->properties[j]);
+            }
+        }
+    }
+
+    for (int i = 0; i < folder->inIndexes.size(); i++) {
+        writeNumber(folder->inIndexes[i]);
+        writeNumber(folder->outIndexes[i]);
+    }
+
+    if (folder->packedStreams.size() > 1) {
+        for (int i = 0; i < folder->packedStreams.size(); i++) {
+            writeNumber(folder->packedStreams[i]);
+        }
+    }
+}
+
+void K7Zip::K7ZipPrivate::writeUnpackInfo(const QList &folderItems)
+{
+    if (folderItems.isEmpty()) {
+        return;
+    }
+
+    writeByte(kUnpackInfo);
+
+    writeByte(kFolder);
+    writeNumber(folderItems.size());
+    {
+        writeByte(0);
+        for (int i = 0; i < folderItems.size(); i++) {
+            writeFolder(folderItems[i]);
+        }
+    }
+
+    writeByte(kCodersUnpackSize);
+    int i;
+    for (i = 0; i < folderItems.size(); i++) {
+        const Folder *folder = folderItems[i];
+        for (int j = 0; j < folder->unpackSizes.size(); j++) {
+            writeNumber(folder->unpackSizes.at(j));
+        }
+    }
+
+    QList unpackCRCsDefined;
+    QList unpackCRCs;
+    unpackCRCsDefined.reserve(folderItems.size());
+    unpackCRCs.reserve(folderItems.size());
+    for (i = 0; i < folderItems.size(); i++) {
+        const Folder *folder = folderItems[i];
+        unpackCRCsDefined.append(folder->unpackCRCDefined);
+        unpackCRCs.append(folder->unpackCRC);
+    }
+    writeHashDigests(unpackCRCsDefined, unpackCRCs);
+
+    writeByte(kEnd);
+}
+
+void K7Zip::K7ZipPrivate::writeSubStreamsInfo(const QList &unpackSizes, const QList &digestsDefined, const QList &digests)
+{
+    writeByte(kSubStreamsInfo);
+
+    for (int i = 0; i < numUnpackStreamsInFolders.size(); i++) {
+        if (numUnpackStreamsInFolders.at(i) != 1) {
+            writeByte(kNumUnpackStream);
+            for (int j = 0; j < numUnpackStreamsInFolders.size(); j++) {
+                writeNumber(numUnpackStreamsInFolders.at(j));
+            }
+            break;
+        }
+    }
+
+    bool needFlag = true;
+    int index = 0;
+    for (int i = 0; i < numUnpackStreamsInFolders.size(); i++) {
+        for (quint32 j = 0; j < numUnpackStreamsInFolders.at(i); j++) {
+            if (j + 1 != numUnpackStreamsInFolders.at(i)) {
+                if (needFlag) {
+                    writeByte(kSize);
+                }
+                needFlag = false;
+                writeNumber(unpackSizes[index]);
+            }
+            index++;
+        }
+    }
+
+    QList digestsDefined2;
+    QList digests2;
+
+    int digestIndex = 0;
+    for (int i = 0; i < folders.size(); i++) {
+        int numSubStreams = (int)numUnpackStreamsInFolders.at(i);
+        if (numSubStreams == 1 && folders.at(i)->unpackCRCDefined) {
+            digestIndex++;
+        } else {
+            for (int j = 0; j < numSubStreams; j++, digestIndex++) {
+                digestsDefined2.append(digestsDefined[digestIndex]);
+                digests2.append(digests[digestIndex]);
+            }
+        }
+    }
+    writeHashDigests(digestsDefined2, digests2);
+    writeByte(kEnd);
+}
+
+QByteArray K7Zip::K7ZipPrivate::encodeStream(QList &packSizes, QList &folds)
+{
+    Folder *folder = new Folder;
+    folder->unpackCRCDefined = true;
+    folder->unpackCRC = crc32(0, (Bytef *)(header.data()), header.size());
+    folder->unpackSizes.append(header.size());
+
+    Folder::FolderInfo *info = new Folder::FolderInfo();
+    info->numInStreams = 1;
+    info->numOutStreams = 1;
+    info->methodID = k_LZMA2;
+
+    quint32 dictSize = header.size();
+    const quint32 kMinReduceSize = (1 << 16);
+    if (dictSize < kMinReduceSize) {
+        dictSize = kMinReduceSize;
+    }
+
+    int dict;
+    for (dict = 0; dict < 40; dict++) {
+        if (dictSize <= lzma2_dic_size_from_prop(dict)) {
+            break;
+        }
+    }
+
+    info->properties.append(dict);
+    folder->folderInfos.append(info);
+
+    folds.append(folder);
+
+    // compress data
+    QByteArray encodedData;
+    if (!header.isEmpty()) {
+        QByteArray enc;
+        QBuffer inBuffer(&enc);
+
+        KCompressionDevice flt(&inBuffer, false, KCompressionDevice::Xz);
+        flt.open(QIODevice::WriteOnly);
+
+        KFilterBase *filter = flt.filterBase();
+
+        static_cast(filter)->init(QIODevice::WriteOnly, KXzFilter::LZMA2, info->properties);
+
+        const int ret = flt.write(header);
+        if (ret != header.size()) {
+            qCDebug(KArchiveLog) << "write error write " << ret << "expected" << header.size();
+            return encodedData;
+        }
+
+        flt.close();
+        encodedData = inBuffer.data();
+    }
+
+    packSizes.append(encodedData.size());
+    return encodedData;
+}
+
+void K7Zip::K7ZipPrivate::writeHeader(quint64 &headerOffset)
+{
+    quint64 packedSize = 0;
+    for (int i = 0; i < packSizes.size(); ++i) {
+        packedSize += packSizes[i];
+    }
+
+    headerOffset = packedSize;
+
+    writeByte(kHeader);
+
+    // Archive Properties
+
+    if (!folders.isEmpty()) {
+        writeByte(kMainStreamsInfo);
+        writePackInfo(0, packSizes, packCRCsDefined, packCRCs);
+
+        writeUnpackInfo(folders);
+
+        QList unpackFileSizes;
+        QList digestsDefined;
+        QList digests;
+        for (int i = 0; i < fileInfos.size(); i++) {
+            const FileInfo *file = fileInfos.at(i);
+            if (!file->hasStream) {
+                continue;
+            }
+            unpackFileSizes.append(file->size);
+            digestsDefined.append(file->crcDefined);
+            digests.append(file->crc);
+        }
+
+        writeSubStreamsInfo(unpackSizes, digestsDefined, digests);
+        writeByte(kEnd);
+    }
+
+    if (fileInfos.isEmpty()) {
+        writeByte(kEnd);
+        return;
+    }
+
+    writeByte(kFilesInfo);
+    writeNumber(fileInfos.size());
+
+    {
+        /* ---------- Empty Streams ---------- */
+        QList emptyStreamVector;
+        int numEmptyStreams = 0;
+        for (int i = 0; i < fileInfos.size(); i++) {
+            if (fileInfos.at(i)->hasStream) {
+                emptyStreamVector.append(false);
+            } else {
+                emptyStreamVector.append(true);
+                numEmptyStreams++;
+            }
+        }
+
+        if (numEmptyStreams > 0) {
+            writeByte(kEmptyStream);
+            writeNumber(((unsigned)emptyStreamVector.size() + 7) / 8);
+            writeBoolVector(emptyStreamVector);
+
+            QList emptyFileVector;
+            QList antiVector;
+            int numEmptyFiles = 0;
+            int numAntiItems = 0;
+            for (int i = 0; i < fileInfos.size(); i++) {
+                const FileInfo *file = fileInfos.at(i);
+                if (!file->hasStream) {
+                    emptyFileVector.append(!file->isDir);
+                    if (!file->isDir) {
+                        numEmptyFiles++;
+                        bool isAnti = (i < this->isAnti.size() && this->isAnti[i]);
+                        antiVector.append(isAnti);
+                        if (isAnti) {
+                            numAntiItems++;
+                        }
+                    }
+                }
+            }
+
+            if (numEmptyFiles > 0) {
+                writeByte(kEmptyFile);
+                writeNumber(((unsigned)emptyFileVector.size() + 7) / 8);
+                writeBoolVector(emptyFileVector);
+            }
+
+            if (numAntiItems > 0) {
+                writeByte(kAnti);
+                writeNumber(((unsigned)antiVector.size() + 7) / 8);
+                writeBoolVector(antiVector);
+            }
+        }
+    }
+
+    {
+        /* ---------- Names ---------- */
+
+        int numDefined = 0;
+        size_t namesDataSize = 0;
+        for (int i = 0; i < fileInfos.size(); i++) {
+            const QString &name = fileInfos.at(i)->path;
+            if (!name.isEmpty()) {
+                numDefined++;
+                namesDataSize += (name.length() + 1) * 2;
+            }
+        }
+
+        if (numDefined > 0) {
+            namesDataSize++;
+            // SkipAlign(2 + GetBigNumberSize(namesDataSize), 2);
+
+            writeByte(kName);
+            writeNumber(namesDataSize);
+            writeByte(0);
+            for (int i = 0; i < fileInfos.size(); i++) {
+                const QString &name = fileInfos.at(i)->path;
+                for (int t = 0; t < name.length(); t++) {
+                    wchar_t c = name[t].toLatin1();
+                    writeByte((unsigned char)c);
+                    writeByte((unsigned char)(c >> 8));
+                }
+                // End of string
+                writeByte(0);
+                writeByte(0);
+            }
+        }
+    }
+
+    writeUInt64DefVector(mTimes, mTimesDefined, kMTime);
+
+    writeUInt64DefVector(startPositions, startPositionsDefined, kStartPos);
+
+    {
+        /* ---------- Write Attrib ---------- */
+        QList boolVector;
+        int numDefined = 0;
+        boolVector.reserve(fileInfos.size());
+        for (int i = 0; i < fileInfos.size(); i++) {
+            bool defined = fileInfos.at(i)->attribDefined;
+            boolVector.append(defined);
+            if (defined) {
+                numDefined++;
+            }
+        }
+
+        if (numDefined > 0) {
+            writeAlignedBoolHeader(boolVector, numDefined, kAttributes, 4);
+            for (int i = 0; i < fileInfos.size(); i++) {
+                const FileInfo *file = fileInfos.at(i);
+                if (file->attribDefined) {
+                    writeUInt32(file->attributes);
+                }
+            }
+        }
+    }
+
+    writeByte(kEnd); // for files
+    writeByte(kEnd); // for headers*/
+}
+
+static void setUInt32(unsigned char *p, quint32 d)
+{
+    for (int i = 0; i < 4; i++, d >>= 8) {
+        p[i] = (unsigned)d;
+    }
+}
+
+static void setUInt64(unsigned char *p, quint64 d)
+{
+    for (int i = 0; i < 8; i++, d >>= 8) {
+        p[i] = (unsigned char)d;
+    }
+}
+
+void K7Zip::K7ZipPrivate::writeStartHeader(const quint64 nextHeaderSize, const quint32 nextHeaderCRC, const quint64 nextHeaderOffset)
+{
+    unsigned char buf[24];
+    setUInt64(buf + 4, nextHeaderOffset);
+    setUInt64(buf + 12, nextHeaderSize);
+    setUInt32(buf + 20, nextHeaderCRC);
+    setUInt32(buf, crc32(0, (Bytef *)(buf + 4), 20));
+    q->device()->write((char *)buf, 24);
+}
+
+void K7Zip::K7ZipPrivate::writeSignature()
+{
+    unsigned char buf[8];
+    memcpy(buf, k7zip_signature, 6);
+    buf[6] = 0 /*kMajorVersion*/;
+    buf[7] = 3;
+    q->device()->write((char *)buf, 8);
+}
+
+bool K7Zip::openArchive(QIODevice::OpenMode mode)
+{
+    if (!(mode & QIODevice::ReadOnly)) {
+        return true;
+    }
+
+    QIODevice *dev = device();
+
+    if (!dev) {
+        setErrorString(tr("Could not get underlying device"));
+        return false;
+    }
+
+    char header[32];
+    // check signature
+    qint64 n = dev->read(header, 32);
+    if (n != 32) {
+        setErrorString(tr("Read header failed"));
+        return false;
+    }
+
+    for (int i = 0; i < 6; ++i) {
+        if ((unsigned char)header[i] != k7zip_signature[i]) {
+            setErrorString(tr("Check signature failed"));
+            return false;
+        }
+    }
+
+    // get Archive Version
+    int major = header[6];
+    int minor = header[7];
+
+    /*if (major > 0 || minor > 2) {
+        qCDebug(KArchiveLog) << "wrong archive version";
+        return false;
+    }*/
+
+    // get Start Header CRC
+    quint32 startHeaderCRC = GetUi32(header, 8);
+    quint64 nextHeaderOffset = GetUi64(header, 12);
+    quint64 nextHeaderSize = GetUi64(header, 20);
+    quint32 nextHeaderCRC = GetUi32(header, 28);
+
+    quint32 crc = crc32(0, (Bytef *)(header + 0xC), 20);
+
+    if (crc != startHeaderCRC) {
+        setErrorString(tr("Bad CRC"));
+        return false;
+    }
+
+    if (nextHeaderSize == 0) {
+        return true;
+    }
+
+    if (nextHeaderSize > (quint64)0xFFFFFFFF) {
+        setErrorString(tr("Next header size is too big"));
+        return false;
+    }
+
+    if ((qint64)nextHeaderOffset < 0) {
+        setErrorString(tr("Next header size is less than zero"));
+        return false;
+    }
+
+    dev->seek(nextHeaderOffset + 32);
+
+    QByteArray inBuffer;
+    inBuffer.resize(nextHeaderSize);
+
+    n = dev->read(inBuffer.data(), inBuffer.size());
+    if (n != (qint64)nextHeaderSize) {
+        setErrorString(tr("Failed read next header size; should read %1, read %2").arg(nextHeaderSize).arg(n));
+        return false;
+    }
+    d->buffer = inBuffer.data();
+    d->end = nextHeaderSize;
+
+    d->headerSize = 32 + nextHeaderSize;
+    // int physSize = 32 + nextHeaderSize + nextHeaderOffset;
+
+    crc = crc32(0, (Bytef *)(d->buffer), (quint32)nextHeaderSize);
+
+    if (crc != nextHeaderCRC) {
+        setErrorString(tr("Bad next header CRC"));
+        return false;
+    }
+
+    int type = d->readByte();
+    QByteArray decodedData;
+    if (type != kHeader) {
+        if (type != kEncodedHeader) {
+            setErrorString(tr("Error in header"));
+            return false;
+        }
+
+        decodedData = d->readAndDecodePackedStreams();
+
+        int external = d->readByte();
+        if (external != 0) {
+            int dataIndex = (int)d->readNumber();
+            if (dataIndex < 0) {
+                // qCDebug(KArchiveLog) << "dataIndex error";
+            }
+            d->buffer = decodedData.constData();
+            d->pos = 0;
+            d->end = decodedData.size();
+        }
+
+        type = d->readByte();
+        if (type != kHeader) {
+            setErrorString(tr("Wrong header type"));
+            return false;
+        }
+    }
+    // read header
+
+    type = d->readByte();
+
+    if (type == kArchiveProperties) {
+        // TODO : implement this part
+        setErrorString(tr("Not implemented"));
+        return false;
+    }
+
+    if (type == kAdditionalStreamsInfo) {
+        // TODO : implement this part
+        setErrorString(tr("Not implemented"));
+        return false;
+    }
+
+    if (type == kMainStreamsInfo) {
+        if (!d->readMainStreamsInfo()) {
+            setErrorString(tr("Error while reading main streams information"));
+            return false;
+        }
+        type = d->readByte();
+    } else {
+        for (int i = 0; i < d->folders.size(); ++i) {
+            Folder *folder = d->folders.at(i);
+            d->unpackSizes.append(folder->getUnpackSize());
+            d->digestsDefined.append(folder->unpackCRCDefined);
+            d->digests.append(folder->unpackCRC);
+        }
+    }
+
+    if (type == kEnd) {
+        return true;
+    }
+
+    if (type != kFilesInfo) {
+        setErrorString(tr("Error while reading header"));
+        return false;
+    }
+
+    // read files info
+    int numFiles = d->readNumber();
+    for (int i = 0; i < numFiles; ++i) {
+        d->fileInfos.append(new FileInfo);
+    }
+
+    QList emptyStreamVector;
+    QList emptyFileVector;
+    QList antiFileVector;
+    int numEmptyStreams = 0;
+
+    for (;;) {
+        quint64 type = d->readByte();
+        if (type == kEnd) {
+            break;
+        }
+
+        quint64 size = d->readNumber();
+
+        size_t ppp = d->pos;
+
+        bool addPropIdToList = true;
+        bool isKnownType = true;
+
+        if (type > ((quint32)1 << 30)) {
+            isKnownType = false;
+        } else {
+            switch (type) {
+            case kEmptyStream: {
+                d->readBoolVector(numFiles, emptyStreamVector);
+                for (int i = 0; i < emptyStreamVector.size(); ++i) {
+                    if (emptyStreamVector[i]) {
+                        numEmptyStreams++;
+                    }
+                }
+
+                break;
+            }
+            case kEmptyFile:
+                d->readBoolVector(numEmptyStreams, emptyFileVector);
+                break;
+            case kAnti:
+                d->readBoolVector(numEmptyStreams, antiFileVector);
+                break;
+            case kCTime:
+                if (!d->readUInt64DefVector(numFiles, d->cTimes, d->cTimesDefined)) {
+                    return false;
+                }
+                break;
+            case kATime:
+                if (!d->readUInt64DefVector(numFiles, d->aTimes, d->aTimesDefined)) {
+                    return false;
+                }
+                break;
+            case kMTime:
+                if (!d->readUInt64DefVector(numFiles, d->mTimes, d->mTimesDefined)) {
+                    setErrorString(tr("Error reading modification time"));
+                    return false;
+                }
+                break;
+            case kName: {
+                int external = d->readByte();
+                if (external != 0) {
+                    int dataIndex = d->readNumber();
+                    if (dataIndex < 0 /*|| dataIndex >= dataVector->Size()*/) {
+                        qCDebug(KArchiveLog) << "wrong data index";
+                    }
+
+                    // TODO : go to the new index
+                }
+
+                QString name;
+                for (int i = 0; i < numFiles; i++) {
+                    name = d->readString();
+                    d->fileInfos.at(i)->path = name;
+                }
+                break;
+            }
+            case kAttributes: {
+                QList attributesAreDefined;
+                d->readBoolVector2(numFiles, attributesAreDefined);
+                int external = d->readByte();
+                if (external != 0) {
+                    int dataIndex = d->readNumber();
+                    if (dataIndex < 0) {
+                        qCDebug(KArchiveLog) << "wrong data index";
+                    }
+
+                    // TODO : go to the new index
+                }
+
+                for (int i = 0; i < numFiles; i++) {
+                    FileInfo *fileInfo = d->fileInfos.at(i);
+                    fileInfo->attribDefined = attributesAreDefined[i];
+                    if (fileInfo->attribDefined) {
+                        fileInfo->attributes = d->readUInt32();
+                    }
+                }
+                break;
+            }
+            case kStartPos:
+                if (!d->readUInt64DefVector(numFiles, d->startPositions, d->startPositionsDefined)) {
+                    setErrorString(tr("Error reading MTime"));
+                    return false;
+                }
+                break;
+            case kDummy: {
+                for (quint64 i = 0; i < size; i++) {
+                    if (d->readByte() != 0) {
+                        setErrorString(tr("Invalid"));
+                        return false;
+                    }
+                }
+                addPropIdToList = false;
+                break;
+            }
+            default:
+                addPropIdToList = isKnownType = false;
+            }
+        }
+
+        if (isKnownType) {
+            if (addPropIdToList) {
+                d->fileInfoPopIDs.append(type);
+            }
+        } else {
+            d->skipData(d->readNumber());
+        }
+
+        bool checkRecordsSize = (major > 0 || minor > 2);
+        if (checkRecordsSize && d->pos - ppp != size) {
+            setErrorString(tr("Read size failed "
+                              "(checkRecordsSize: %1, d->pos - ppp: %2, size: %3)")
+                               .arg(checkRecordsSize)
+                               .arg(d->pos - ppp)
+                               .arg(size));
+            return false;
+        }
+    }
+
+    int emptyFileIndex = 0;
+    int sizeIndex = 0;
+
+    int numAntiItems = 0;
+
+    if (emptyStreamVector.isEmpty()) {
+        emptyStreamVector.fill(false, numFiles);
+    }
+
+    if (antiFileVector.isEmpty()) {
+        antiFileVector.fill(false, numEmptyStreams);
+    }
+    if (emptyFileVector.isEmpty()) {
+        emptyFileVector.fill(false, numEmptyStreams);
+    }
+
+    for (int i = 0; i < numEmptyStreams; i++) {
+        if (antiFileVector[i]) {
+            numAntiItems++;
+        }
+    }
+
+    d->outData = d->readAndDecodePackedStreams(false);
+
+    int oldPos = 0;
+    for (int i = 0; i < numFiles; i++) {
+        FileInfo *fileInfo = d->fileInfos.at(i);
+        bool isAnti;
+        fileInfo->hasStream = !emptyStreamVector[i];
+        if (fileInfo->hasStream) {
+            fileInfo->isDir = false;
+            isAnti = false;
+            fileInfo->size = d->unpackSizes[sizeIndex];
+            fileInfo->crc = d->digests[sizeIndex];
+            fileInfo->crcDefined = d->digestsDefined[sizeIndex];
+            sizeIndex++;
+        } else {
+            fileInfo->isDir = !emptyFileVector[emptyFileIndex];
+            isAnti = antiFileVector[emptyFileIndex];
+            emptyFileIndex++;
+            fileInfo->size = 0;
+            fileInfo->crcDefined = false;
+        }
+        if (numAntiItems != 0) {
+            d->isAnti.append(isAnti);
+        }
+
+        int access;
+        bool symlink = false;
+        if (fileInfo->attributes & FILE_ATTRIBUTE_UNIX_EXTENSION) {
+            access = fileInfo->attributes >> 16;
+            if ((access & QT_STAT_MASK) == QT_STAT_LNK) {
+                symlink = true;
+            }
+        } else {
+            if (fileInfo->isDir) {
+                access = S_IFDIR | 0755;
+            } else {
+                access = 0100644;
+            }
+        }
+
+        qint64 pos = 0;
+        if (!fileInfo->isDir) {
+            pos = oldPos;
+            oldPos += fileInfo->size;
+        }
+
+        KArchiveEntry *e;
+        QString entryName;
+        int index = fileInfo->path.lastIndexOf(QLatin1Char('/'));
+        if (index == -1) {
+            entryName = fileInfo->path;
+        } else {
+            entryName = fileInfo->path.mid(index + 1);
+        }
+        Q_ASSERT(!entryName.isEmpty());
+
+        QDateTime mTime;
+        if (d->mTimesDefined.size() > i && d->mTimesDefined[i]) {
+            mTime = KArchivePrivate::time_tToDateTime(toTimeT(d->mTimes[i]));
+        } else {
+            mTime = KArchivePrivate::time_tToDateTime(time(nullptr));
+        }
+
+        if (fileInfo->isDir) {
+            QString path = QDir::cleanPath(fileInfo->path);
+            const KArchiveEntry *ent = rootDir()->entry(path);
+            if (ent && ent->isDirectory()) {
+                e = nullptr;
+            } else {
+                e = new KArchiveDirectory(this, entryName, access, mTime, rootDir()->user(), rootDir()->group(), QString() /*symlink*/);
+            }
+        } else {
+            if (!symlink) {
+                e = new K7ZipFileEntry(this,
+                                       entryName,
+                                       access,
+                                       mTime,
+                                       rootDir()->user(),
+                                       rootDir()->group(),
+                                       QString() /*symlink*/,
+                                       pos,
+                                       fileInfo->size,
+                                       d->outData);
+            } else {
+                QString target = QFile::decodeName(d->outData.mid(pos, fileInfo->size));
+                e = new K7ZipFileEntry(this, entryName, access, mTime, rootDir()->user(), rootDir()->group(), target, 0, 0, nullptr);
+            }
+        }
+
+        if (e) {
+            if (index == -1) {
+                rootDir()->addEntry(e);
+            } else {
+                QString path = QDir::cleanPath(fileInfo->path.left(index));
+                KArchiveDirectory *d = findOrCreate(path);
+                d->addEntry(e);
+            }
+        }
+    }
+
+    return true;
+}
+
+bool K7Zip::closeArchive()
+{
+    // Unnecessary check (already checked by KArchive::close())
+    if (!isOpen()) {
+        // qCWarning(KArchiveLog) << "You must open the file before close it\n";
+        return false;
+    }
+
+    if ((mode() == QIODevice::ReadOnly)) {
+        return true;
+    }
+
+    d->clear();
+
+    Folder *folder = new Folder();
+
+    folder->unpackSizes.clear();
+    folder->unpackSizes.append(d->outData.size());
+
+    Folder::FolderInfo *info = new Folder::FolderInfo();
+
+    info->numInStreams = 1;
+    info->numOutStreams = 1;
+    info->methodID = k_LZMA2;
+
+    quint32 dictSize = d->outData.size();
+
+    const quint32 kMinReduceSize = (1 << 16);
+    if (dictSize < kMinReduceSize) {
+        dictSize = kMinReduceSize;
+    }
+
+    // k_LZMA2 method
+    int dict;
+    for (dict = 0; dict < 40; dict++) {
+        if (dictSize <= lzma2_dic_size_from_prop(dict)) {
+            break;
+        }
+    }
+    info->properties.append(dict);
+
+    folder->folderInfos.append(info);
+    d->folders.append(folder);
+
+    const KArchiveDirectory *dir = directory();
+    QByteArray data;
+    d->createItemsFromEntities(dir, QString(), data);
+    d->outData = data;
+
+    folder->unpackCRCDefined = true;
+    folder->unpackCRC = crc32(0, (Bytef *)(d->outData.data()), d->outData.size());
+
+    // compress data
+    QByteArray encodedData;
+    if (!d->outData.isEmpty()) {
+        QByteArray enc;
+        QBuffer inBuffer(&enc);
+
+        KCompressionDevice flt(&inBuffer, false, KCompressionDevice::Xz);
+        flt.open(QIODevice::WriteOnly);
+
+        KFilterBase *filter = flt.filterBase();
+
+        static_cast(filter)->init(QIODevice::WriteOnly, KXzFilter::LZMA2, info->properties);
+
+        const int ret = flt.write(d->outData);
+        if (ret != d->outData.size()) {
+            setErrorString(tr("Write error"));
+            return false;
+        }
+
+        flt.close();
+        encodedData = inBuffer.data();
+    }
+
+    d->packSizes.append(encodedData.size());
+
+    int numUnpackStream = 0;
+    for (int i = 0; i < d->fileInfos.size(); ++i) {
+        if (d->fileInfos.at(i)->hasStream) {
+            numUnpackStream++;
+        }
+    }
+    d->numUnpackStreamsInFolders.append(numUnpackStream);
+
+    quint64 headerOffset;
+    d->writeHeader(headerOffset);
+
+    // Encode Header
+    QByteArray encodedStream;
+    {
+        QList packSizes;
+        QList folders;
+        encodedStream = d->encodeStream(packSizes, folders);
+
+        if (folders.isEmpty()) {
+            // FIXME Not sure why this is an error. Come up with a better message
+            setErrorString(tr("Failed while encoding header"));
+            return false;
+        }
+
+        d->header.clear();
+
+        d->writeByte(kEncodedHeader);
+        QList emptyDefined;
+        QList emptyCrcs;
+        d->writePackInfo(headerOffset, packSizes, emptyDefined, emptyCrcs);
+        d->writeUnpackInfo(folders);
+        d->writeByte(kEnd);
+        for (int i = 0; i < packSizes.size(); i++) {
+            headerOffset += packSizes.at(i);
+        }
+        qDeleteAll(folders);
+    }
+    // end encode header
+
+    quint64 nextHeaderSize = d->header.size();
+    quint32 nextHeaderCRC = crc32(0, (Bytef *)(d->header.data()), d->header.size());
+    quint64 nextHeaderOffset = headerOffset;
+
+    device()->seek(0);
+    d->writeSignature();
+    d->writeStartHeader(nextHeaderSize, nextHeaderCRC, nextHeaderOffset);
+    device()->write(encodedData.data(), encodedData.size());
+    device()->write(encodedStream.data(), encodedStream.size());
+    device()->write(d->header.data(), d->header.size());
+
+    return true;
+}
+
+bool K7Zip::doFinishWriting(qint64 size)
+{
+    d->m_currentFile->setSize(size);
+    d->m_currentFile = nullptr;
+
+    return true;
+}
+
+bool K7Zip::doWriteData(const char *data, qint64 size)
+{
+    if (!d->m_currentFile) {
+        setErrorString(tr("No file currently selected"));
+        return false;
+    }
+
+    if (d->m_currentFile->position() == d->outData.size()) {
+        d->outData.append(data, size);
+    } else {
+        d->outData.remove(d->m_currentFile->position(), d->m_currentFile->size());
+        d->outData.insert(d->m_currentFile->position(), data, size);
+    }
+
+    return true;
+}
+
+bool K7Zip::doPrepareWriting(const QString &name,
+                             const QString &user,
+                             const QString &group,
+                             qint64 /*size*/,
+                             mode_t perm,
+                             const QDateTime & /*atime*/,
+                             const QDateTime &mtime,
+                             const QDateTime & /*ctime*/)
+{
+    if (!isOpen()) {
+        setErrorString(tr("Application error: 7-Zip file must be open before being written into"));
+        qCWarning(KArchiveLog) << "doPrepareWriting failed: !isOpen()";
+        return false;
+    }
+
+    if (!(mode() & QIODevice::WriteOnly)) {
+        setErrorString(tr("Application error: attempted to write into non-writable 7-Zip file"));
+        qCWarning(KArchiveLog) << "doPrepareWriting failed: !(mode() & QIODevice::WriteOnly)";
+        return false;
+    }
+
+    // Find or create parent dir
+    KArchiveDirectory *parentDir = rootDir();
+    // QString fileName( name );
+    // In some files we can find dir/./file => call cleanPath
+    QString fileName(QDir::cleanPath(name));
+    int i = name.lastIndexOf(QLatin1Char('/'));
+    if (i != -1) {
+        QString dir = name.left(i);
+        fileName = name.mid(i + 1);
+        parentDir = findOrCreate(dir);
+    }
+
+    // test if the entry already exist
+    const KArchiveEntry *entry = parentDir->entry(fileName);
+    if (!entry) {
+        K7ZipFileEntry *e =
+            new K7ZipFileEntry(this, fileName, perm, mtime, user, group, QString() /*symlink*/, d->outData.size(), 0 /*unknown yet*/, d->outData);
+        if (!parentDir->addEntryV2(e)) {
+            return false;
+        }
+        d->m_entryList << e;
+        d->m_currentFile = e;
+    } else {
+        // TODO : find and replace in m_entryList
+        // d->m_currentFile = static_cast(entry);
+    }
+
+    return true;
+}
+
+bool K7Zip::doWriteDir(const QString &name,
+                       const QString &user,
+                       const QString &group,
+                       mode_t perm,
+                       const QDateTime & /*atime*/,
+                       const QDateTime &mtime,
+                       const QDateTime & /*ctime*/)
+{
+    if (!isOpen()) {
+        setErrorString(tr("Application error: 7-Zip file must be open before being written into"));
+        qCWarning(KArchiveLog) << "doWriteDir failed: !isOpen()";
+        return false;
+    }
+
+    if (!(mode() & QIODevice::WriteOnly)) {
+        // qCWarning(KArchiveLog) << "You must open the tar file for writing\n";
+        return false;
+    }
+
+    // In some tar files we can find dir/./ => call cleanPath
+    QString dirName(QDir::cleanPath(name));
+
+    // Remove trailing '/'
+    if (dirName.endsWith(QLatin1Char('/'))) {
+        dirName.remove(dirName.size() - 1, 1);
+    }
+
+    KArchiveDirectory *parentDir = rootDir();
+    int i = dirName.lastIndexOf(QLatin1Char('/'));
+    if (i != -1) {
+        QString dir = name.left(i);
+        dirName = name.mid(i + 1);
+        parentDir = findOrCreate(dir);
+    }
+
+    KArchiveDirectory *e = new KArchiveDirectory(this, dirName, perm, mtime, user, group, QString() /*symlink*/);
+    parentDir->addEntry(e);
+
+    return true;
+}
+
+bool K7Zip::doWriteSymLink(const QString &name,
+                           const QString &target,
+                           const QString &user,
+                           const QString &group,
+                           mode_t perm,
+                           const QDateTime & /*atime*/,
+                           const QDateTime &mtime,
+                           const QDateTime & /*ctime*/)
+{
+    if (!isOpen()) {
+        setErrorString(tr("Application error: 7-Zip file must be open before being written into"));
+        qCWarning(KArchiveLog) << "doWriteSymLink failed: !isOpen()";
+        return false;
+    }
+
+    if (!(mode() & QIODevice::WriteOnly)) {
+        setErrorString(tr("Application error: attempted to write into non-writable 7-Zip file"));
+        qCWarning(KArchiveLog) << "doWriteSymLink failed: !(mode() & QIODevice::WriteOnly)";
+        return false;
+    }
+
+    // Find or create parent dir
+    KArchiveDirectory *parentDir = rootDir();
+    // In some files we can find dir/./file => call cleanPath
+    QString fileName(QDir::cleanPath(name));
+    int i = name.lastIndexOf(QLatin1Char('/'));
+    if (i != -1) {
+        QString dir = name.left(i);
+        fileName = name.mid(i + 1);
+        parentDir = findOrCreate(dir);
+    }
+    QByteArray encodedTarget = QFile::encodeName(target);
+
+    K7ZipFileEntry *e = new K7ZipFileEntry(this, fileName, perm, mtime, user, group, target, 0, 0, nullptr);
+    d->outData.append(encodedTarget);
+
+    if (!parentDir->addEntryV2(e)) {
+        return false;
+    }
+
+    d->m_entryList << e;
+
+    return true;
+}
+
+void K7Zip::virtual_hook(int id, void *data)
+{
+    KArchive::virtual_hook(id, data);
+}
diff --git a/src/libs/3rdparty/karchive/src/k7zip.h b/src/libs/3rdparty/karchive/src/k7zip.h
new file mode 100644
index 00000000000..b065e4ccb3b
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/k7zip.h
@@ -0,0 +1,100 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2011 Mario Bensi 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+#ifndef K7ZIP_H
+#define K7ZIP_H
+
+#include "karchive.h"
+
+/**
+ * @class K7Zip k7zip.h K7Zip
+ *
+ * A class for reading / writing p7zip archives.
+ *
+ * @author Mario Bensi
+ */
+class KARCHIVE_EXPORT K7Zip : public KArchive
+{
+    Q_DECLARE_TR_FUNCTIONS(K7Zip)
+
+public:
+    /**
+     * Creates an instance that operates on the given filename
+     * using the compression filter associated to given mimetype.
+     *
+     * @param filename is a local path (e.g. "/home/user/myfile.7z")
+     */
+    explicit K7Zip(const QString &filename);
+
+    /**
+     * Creates an instance that operates on the given device.
+     * The device can be compressed (KCompressionDevice) or not (QFile, etc.).
+     * @warning Do not assume that giving a QFile here will decompress the file,
+     * in case it's compressed!
+     * @param dev the device to read from. If the source is compressed, the
+     * QIODevice must take care of decompression
+     */
+    explicit K7Zip(QIODevice *dev);
+
+    /**
+     * If the archive is still opened, then it will be
+     * closed automatically by the destructor.
+     */
+    ~K7Zip() override;
+
+protected:
+    /// Reimplemented from KArchive
+    bool doWriteSymLink(
+        const QString &name,
+        const QString &target,
+        const QString &user,
+        const QString &group,
+        mode_t perm,
+        const QDateTime &atime,
+        const QDateTime &mtime,
+        const QDateTime &ctime) override;
+    /// Reimplemented from KArchive
+    bool doWriteDir(
+        const QString &name,
+        const QString &user,
+        const QString &group,
+        mode_t perm,
+        const QDateTime &atime,
+        const QDateTime &mtime,
+        const QDateTime &ctime) override;
+    /// Reimplemented from KArchive
+    bool doPrepareWriting(
+        const QString &name,
+        const QString &user,
+        const QString &group,
+        qint64 size,
+        mode_t perm,
+        const QDateTime &atime,
+        const QDateTime &mtime,
+        const QDateTime &ctime) override;
+    /// Reimplemented from KArchive
+    bool doFinishWriting(qint64 size) override;
+
+    /// Reimplemented from KArchive
+    bool doWriteData(const char *data, qint64 size) override;
+
+    /**
+     * Opens the archive for reading.
+     * Parses the directory listing of the archive
+     * and creates the KArchiveDirectory/KArchiveFile entries.
+     * @param mode the mode of the file
+     */
+    bool openArchive(QIODevice::OpenMode mode) override;
+    bool closeArchive() override;
+
+protected:
+    void virtual_hook(int id, void *data) override;
+
+private:
+    class K7ZipPrivate;
+    K7ZipPrivate *const d;
+};
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/kar.cpp b/src/libs/3rdparty/karchive/src/kar.cpp
new file mode 100644
index 00000000000..5bbe3de9312
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kar.cpp
@@ -0,0 +1,195 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2002 Laurence Anderson 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "kar.h"
+#include "karchive_p.h"
+#include "loggingcategory.h"
+
+#include 
+#include 
+
+#include 
+
+#include "kcompressiondevice.h"
+//#include "klimitediodevice_p.h"
+
+// As documented in QByteArray
+static constexpr int kMaxQByteArraySize = std::numeric_limits::max() - 32;
+
+////////////////////////////////////////////////////////////////////////
+/////////////////////////// KAr ///////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+class Q_DECL_HIDDEN KAr::KArPrivate
+{
+public:
+    KArPrivate()
+    {
+    }
+};
+
+KAr::KAr(const QString &filename)
+    : KArchive(filename)
+    , d(new KArPrivate)
+{
+}
+
+KAr::KAr(QIODevice *dev)
+    : KArchive(dev)
+    , d(new KArPrivate)
+{
+}
+
+KAr::~KAr()
+{
+    if (isOpen()) {
+        close();
+    }
+    delete d;
+}
+
+bool KAr::doPrepareWriting(const QString &, const QString &, const QString &, qint64, mode_t, const QDateTime &, const QDateTime &, const QDateTime &)
+{
+    setErrorString(tr("Cannot write to AR file"));
+    qCWarning(KArchiveLog) << "doPrepareWriting not implemented for KAr";
+    return false;
+}
+
+bool KAr::doFinishWriting(qint64)
+{
+    setErrorString(tr("Cannot write to AR file"));
+    qCWarning(KArchiveLog) << "doFinishWriting not implemented for KAr";
+    return false;
+}
+
+bool KAr::doWriteDir(const QString &, const QString &, const QString &, mode_t, const QDateTime &, const QDateTime &, const QDateTime &)
+{
+    setErrorString(tr("Cannot write to AR file"));
+    qCWarning(KArchiveLog) << "doWriteDir not implemented for KAr";
+    return false;
+}
+
+bool KAr::doWriteSymLink(const QString &, const QString &, const QString &, const QString &, mode_t, const QDateTime &, const QDateTime &, const QDateTime &)
+{
+    setErrorString(tr("Cannot write to AR file"));
+    qCWarning(KArchiveLog) << "doWriteSymLink not implemented for KAr";
+    return false;
+}
+
+bool KAr::openArchive(QIODevice::OpenMode mode)
+{
+    // Open archive
+
+    if (mode == QIODevice::WriteOnly) {
+        return true;
+    }
+    if (mode != QIODevice::ReadOnly && mode != QIODevice::ReadWrite) {
+        setErrorString(tr("Unsupported mode %1").arg(mode));
+        return false;
+    }
+
+    QIODevice *dev = device();
+    if (!dev) {
+        return false;
+    }
+
+    QByteArray magic = dev->read(7);
+    if (magic != "!") {
+        setErrorString(tr("Invalid main magic"));
+        return false;
+    }
+
+    QByteArray ar_longnames;
+    while (!dev->atEnd()) {
+        QByteArray ar_header;
+        ar_header.resize(60);
+
+        dev->seek(dev->pos() + (2 - (dev->pos() % 2)) % 2); // Ar headers are padded to byte boundary
+
+        if (dev->read(ar_header.data(), 60) != 60) { // Read ar header
+            qCWarning(KArchiveLog) << "Couldn't read header";
+            return true; // Probably EOF / trailing junk
+        }
+
+        if (!ar_header.endsWith("`\n")) { // Check header magic // krazy:exclude=strings
+            setErrorString(tr("Invalid magic"));
+            return false;
+        }
+
+        QByteArray name = ar_header.mid(0, 16); // Process header
+        const int date = ar_header.mid(16, 12).trimmed().toInt();
+        // const int uid = ar_header.mid( 28, 6 ).trimmed().toInt();
+        // const int gid = ar_header.mid( 34, 6 ).trimmed().toInt();
+        const int mode = ar_header.mid(40, 8).trimmed().toInt(nullptr, 8);
+        const qint64 size = ar_header.mid(48, 10).trimmed().toInt();
+        if (size < 0 || size > kMaxQByteArraySize) {
+            setErrorString(tr("Invalid size"));
+            return false;
+        }
+
+        bool skip_entry = false; // Deal with special entries
+        if (name.mid(0, 1) == "/") {
+            if (name.mid(1, 1) == "/") { // Longfilename table entry
+                ar_longnames.resize(size);
+                // Read the table. Note that the QByteArray will contain NUL characters after each entry.
+                dev->read(ar_longnames.data(), size);
+                skip_entry = true;
+                qCDebug(KArchiveLog) << "Read in longnames entry";
+            } else if (name.mid(1, 1) == " ") { // Symbol table entry
+                qCDebug(KArchiveLog) << "Skipped symbol entry";
+                dev->seek(dev->pos() + size);
+                skip_entry = true;
+            } else { // Longfilename, look it up in the table
+                const int ar_longnamesIndex = name.mid(1, 15).trimmed().toInt();
+                qCDebug(KArchiveLog) << "Longfilename #" << ar_longnamesIndex;
+                if (ar_longnames.isEmpty()) {
+                    setErrorString(tr("Invalid longfilename reference"));
+                    return false;
+                }
+                if (ar_longnamesIndex < 0 || ar_longnamesIndex >= ar_longnames.size()) {
+                    setErrorString(tr("Invalid longfilename position reference"));
+                    return false;
+                }
+                name = QByteArray(ar_longnames.constData() + ar_longnamesIndex);
+                name.truncate(name.indexOf('/'));
+            }
+        }
+        if (skip_entry) {
+            continue;
+        }
+
+        // Process filename
+        name = name.trimmed();
+        name.replace('/', QByteArray());
+        qCDebug(KArchiveLog) << "Filename: " << name << " Size: " << size;
+
+        KArchiveEntry *entry = new KArchiveFile(this,
+                                                QString::fromLocal8Bit(name.constData()),
+                                                mode,
+                                                KArchivePrivate::time_tToDateTime(date),
+                                                rootDir()->user(),
+                                                rootDir()->group(),
+                                                /*symlink*/ QString(),
+                                                dev->pos(),
+                                                size);
+        rootDir()->addEntry(entry); // Ar files don't support directories, so everything in root
+
+        dev->seek(dev->pos() + size); // Skip contents
+    }
+
+    return true;
+}
+
+bool KAr::closeArchive()
+{
+    // Close the archive
+    return true;
+}
+
+void KAr::virtual_hook(int id, void *data)
+{
+    KArchive::virtual_hook(id, data);
+}
diff --git a/src/libs/3rdparty/karchive/src/kar.h b/src/libs/3rdparty/karchive/src/kar.h
new file mode 100644
index 00000000000..17e5b1abbc7
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kar.h
@@ -0,0 +1,106 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2002 Laurence Anderson 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+#ifndef KAR_H
+#define KAR_H
+
+#include "karchive.h"
+
+/**
+ * @class KAr kar.h KAr
+ *
+ * KAr is a class for reading archives in ar format. Writing
+ * is not supported. Reading archives that contain files bigger than
+ * INT_MAX - 32 bytes is not supported.
+ * @short A class for reading ar archives.
+ * @author Laurence Anderson 
+ */
+class KARCHIVE_EXPORT KAr : public KArchive
+{
+    Q_DECLARE_TR_FUNCTIONS(KAr)
+
+public:
+    /**
+     * Creates an instance that operates on the given filename.
+     *
+     * @param filename is a local path (e.g. "/home/holger/myfile.ar")
+     */
+    explicit KAr(const QString &filename);
+
+    /**
+     * Creates an instance that operates on the given device.
+     * The device can be compressed (KCompressionDevice) or not (QFile, etc.).
+     * @param dev the device to read from
+     */
+    explicit KAr(QIODevice *dev);
+
+    /**
+     * If the ar file is still opened, then it will be
+     * closed automatically by the destructor.
+     */
+    ~KAr() override;
+
+protected:
+    /*
+     * Writing is not supported by this class, will always fail.
+     * @return always false
+     */
+    bool doPrepareWriting(
+        const QString &name,
+        const QString &user,
+        const QString &group,
+        qint64 size,
+        mode_t perm,
+        const QDateTime &atime,
+        const QDateTime &mtime,
+        const QDateTime &ctime) override;
+
+    /*
+     * Writing is not supported by this class, will always fail.
+     * @return always false
+     */
+    bool doFinishWriting(qint64 size) override;
+
+    /*
+     * Writing is not supported by this class, will always fail.
+     * @return always false
+     */
+    bool doWriteDir(
+        const QString &name,
+        const QString &user,
+        const QString &group,
+        mode_t perm,
+        const QDateTime &atime,
+        const QDateTime &mtime,
+        const QDateTime &ctime) override;
+
+    bool doWriteSymLink(
+        const QString &name,
+        const QString &target,
+        const QString &user,
+        const QString &group,
+        mode_t perm,
+        const QDateTime &atime,
+        const QDateTime &mtime,
+        const QDateTime &ctime) override;
+
+    /**
+     * Opens the archive for reading.
+     * Parses the directory listing of the archive
+     * and creates the KArchiveDirectory/KArchiveFile entries.
+     *
+     */
+    bool openArchive(QIODevice::OpenMode mode) override;
+    bool closeArchive() override;
+
+protected:
+    void virtual_hook(int id, void *data) override;
+
+private:
+    class KArPrivate;
+    KArPrivate *const d;
+};
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/karchive.cpp b/src/libs/3rdparty/karchive/src/karchive.cpp
new file mode 100644
index 00000000000..2a3e7b38348
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/karchive.cpp
@@ -0,0 +1,1062 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000-2005 David Faure 
+   SPDX-FileCopyrightText: 2003 Leo Savernik 
+
+   Moved from ktar.cpp by Roberto Teixeira 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "karchive.h"
+#include "karchive_p.h"
+#include "klimitediodevice_p.h"
+#include "loggingcategory.h"
+
+#include  // QT_STATBUF, QT_LSTAT
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+
+#ifdef Q_OS_UNIX
+#include 
+#include  // PATH_MAX
+#include 
+#include 
+#endif
+#ifdef Q_OS_WIN
+#include  // DWORD, GetUserNameW
+#endif // Q_OS_WIN
+
+#if defined(Q_OS_UNIX)
+#define STAT_METHOD QT_LSTAT
+#else
+#define STAT_METHOD QT_STAT
+#endif
+
+////////////////////////////////////////////////////////////////////////
+/////////////////// KArchiveDirectoryPrivate ///////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+class KArchiveDirectoryPrivate
+{
+public:
+    KArchiveDirectoryPrivate(KArchiveDirectory *parent)
+        : q(parent)
+    {
+    }
+
+    ~KArchiveDirectoryPrivate()
+    {
+        qDeleteAll(entries);
+    }
+
+    KArchiveDirectoryPrivate(const KArchiveDirectoryPrivate &) = delete;
+    KArchiveDirectoryPrivate &operator=(const KArchiveDirectoryPrivate &) = delete;
+
+    static KArchiveDirectoryPrivate *get(KArchiveDirectory *directory)
+    {
+        return directory->d;
+    }
+
+    // Returns in containingDirectory the directory that actually contains the returned entry
+    const KArchiveEntry *entry(const QString &_name, KArchiveDirectory **containingDirectory) const
+    {
+        *containingDirectory = q;
+
+        QString name = QDir::cleanPath(_name);
+        int pos = name.indexOf(QLatin1Char('/'));
+        if (pos == 0) { // absolute path (see also KArchive::findOrCreate)
+            if (name.length() > 1) {
+                name = name.mid(1); // remove leading slash
+                pos = name.indexOf(QLatin1Char('/')); // look again
+            } else { // "/"
+                return q;
+            }
+        }
+        // trailing slash ? -> remove
+        if (pos != -1 && pos == name.length() - 1) {
+            name = name.left(pos);
+            pos = name.indexOf(QLatin1Char('/')); // look again
+        }
+        if (pos != -1) {
+            const QString left = name.left(pos);
+            const QString right = name.mid(pos + 1);
+
+            // qCDebug(KArchiveLog) << "left=" << left << "right=" << right;
+
+            KArchiveEntry *e = entries.value(left);
+            if (!e || !e->isDirectory()) {
+                return nullptr;
+            }
+            *containingDirectory = static_cast(e);
+            return (*containingDirectory)->d->entry(right, containingDirectory);
+        }
+
+        return entries.value(name);
+    }
+
+    KArchiveDirectory *q;
+    QHash entries;
+};
+
+////////////////////////////////////////////////////////////////////////
+/////////////////////////// KArchive ///////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+KArchive::KArchive(const QString &fileName)
+    : d(new KArchivePrivate(this))
+{
+    if (fileName.isEmpty()) {
+        qCWarning(KArchiveLog) << "KArchive: No file name specified";
+    }
+    d->fileName = fileName;
+    // This constructor leaves the device set to 0.
+    // This is for the use of QSaveFile, see open().
+}
+
+KArchive::KArchive(QIODevice *dev)
+    : d(new KArchivePrivate(this))
+{
+    if (!dev) {
+        qCWarning(KArchiveLog) << "KArchive: Null device specified";
+    }
+    d->dev = dev;
+}
+
+KArchive::~KArchive()
+{
+    Q_ASSERT(!isOpen()); // the derived class destructor must have closed already
+    delete d;
+}
+
+bool KArchive::open(QIODevice::OpenMode mode)
+{
+    Q_ASSERT(mode != QIODevice::NotOpen);
+
+    if (isOpen()) {
+        close();
+    }
+
+    if (!d->fileName.isEmpty()) {
+        Q_ASSERT(!d->dev);
+        if (!createDevice(mode)) {
+            return false;
+        }
+    }
+
+    if (!d->dev) {
+        setErrorString(tr("No filename or device was specified"));
+        return false;
+    }
+
+    if (!d->dev->isOpen() && !d->dev->open(mode)) {
+        setErrorString(tr("Could not open device in mode %1").arg(mode));
+        return false;
+    }
+
+    d->mode = mode;
+
+    Q_ASSERT(!d->rootDir);
+    d->rootDir = nullptr;
+
+    return openArchive(mode);
+}
+
+bool KArchive::createDevice(QIODevice::OpenMode mode)
+{
+    switch (mode) {
+    case QIODevice::WriteOnly:
+        if (!d->fileName.isEmpty()) {
+            // The use of QSaveFile can't be done in the ctor (no mode known yet)
+            // qCDebug(KArchiveLog) << "Writing to a file using QSaveFile";
+            d->saveFile = new QSaveFile(d->fileName);
+#ifdef Q_OS_ANDROID
+            // we cannot rename on to Android content: URLs
+            if (d->fileName.startsWith(QLatin1String("content://"))) {
+                d->saveFile->setDirectWriteFallback(true);
+            }
+#endif
+            if (!d->saveFile->open(QIODevice::WriteOnly)) {
+                setErrorString(tr("QSaveFile creation for %1 failed: %2").arg(d->fileName, d->saveFile->errorString()));
+
+                delete d->saveFile;
+                d->saveFile = nullptr;
+                return false;
+            }
+            d->dev = d->saveFile;
+            Q_ASSERT(d->dev);
+        }
+        break;
+    case QIODevice::ReadOnly:
+    case QIODevice::ReadWrite:
+        // ReadWrite mode still uses QFile for now; we'd need to copy to the tempfile, in fact.
+        if (!d->fileName.isEmpty()) {
+            d->dev = new QFile(d->fileName);
+            d->deviceOwned = true;
+        }
+        break; // continued below
+    default:
+        setErrorString(tr("Unsupported mode %1").arg(d->mode));
+        return false;
+    }
+    return true;
+}
+
+bool KArchive::close()
+{
+    if (!isOpen()) {
+        setErrorString(tr("Archive already closed"));
+        return false; // already closed (return false or true? arguable...)
+    }
+
+    // moved by holger to allow kzip to write the zip central dir
+    // to the file in closeArchive()
+    // DF: added d->dev so that we skip closeArchive if saving aborted.
+    bool closeSucceeded = true;
+    if (d->dev) {
+        closeSucceeded = closeArchive();
+        if (d->mode == QIODevice::WriteOnly && !closeSucceeded) {
+            d->abortWriting();
+        }
+    }
+
+    if (d->dev && d->dev != d->saveFile) {
+        d->dev->close();
+    }
+
+    // if d->saveFile is not null then it is equal to d->dev.
+    if (d->saveFile) {
+        closeSucceeded = d->saveFile->commit();
+        delete d->saveFile;
+        d->saveFile = nullptr;
+    }
+    if (d->deviceOwned) {
+        delete d->dev; // we created it ourselves in open()
+    }
+
+    delete d->rootDir;
+    d->rootDir = nullptr;
+    d->mode = QIODevice::NotOpen;
+    d->dev = nullptr;
+    return closeSucceeded;
+}
+
+QString KArchive::errorString() const
+{
+    return d->errorStr;
+}
+
+const KArchiveDirectory *KArchive::directory() const
+{
+    // rootDir isn't const so that parsing-on-demand is possible
+    return const_cast(this)->rootDir();
+}
+
+bool KArchive::addLocalFile(const QString &fileName, const QString &destName)
+{
+    QFileInfo fileInfo(fileName);
+    if (!fileInfo.isFile() && !fileInfo.isSymLink()) {
+        setErrorString(tr("%1 doesn't exist or is not a regular file.").arg(fileName));
+        return false;
+    }
+
+    QT_STATBUF fi;
+    if (STAT_METHOD(QFile::encodeName(fileName).constData(), &fi) == -1) {
+        setErrorString(tr("Failed accessing the file %1 for adding to the archive. The error was: %2").arg(fileName).arg(QLatin1String{strerror(errno)}));
+        return false;
+    }
+
+    if (fileInfo.isSymLink()) {
+        QString symLinkTarget;
+        // Do NOT use fileInfo.symLinkTarget() for unix symlinks!
+        // It returns the -full- path to the target, while we want the target string "as is".
+#if defined(Q_OS_UNIX) && !defined(Q_OS_OS2EMX)
+        const QByteArray encodedFileName = QFile::encodeName(fileName);
+        QByteArray s;
+#if defined(PATH_MAX)
+        s.resize(PATH_MAX + 1);
+#else
+        int path_max = pathconf(encodedFileName.data(), _PC_PATH_MAX);
+        if (path_max <= 0) {
+            path_max = 4096;
+        }
+        s.resize(path_max);
+#endif
+        int len = readlink(encodedFileName.data(), s.data(), s.size() - 1);
+        if (len >= 0) {
+            s[len] = '\0';
+            symLinkTarget = QFile::decodeName(s.constData());
+        }
+#endif
+        if (symLinkTarget.isEmpty()) { // Mac or Windows
+            symLinkTarget = fileInfo.symLinkTarget();
+        }
+        return writeSymLink(destName,
+                            symLinkTarget,
+                            fileInfo.owner(),
+                            fileInfo.group(),
+                            fi.st_mode,
+                            fileInfo.lastRead(),
+                            fileInfo.lastModified(),
+                            fileInfo.birthTime());
+    } /*end if*/
+
+    qint64 size = fileInfo.size();
+
+    // the file must be opened before prepareWriting is called, otherwise
+    // if the opening fails, no content will follow the already written
+    // header and the tar file is incorrect
+    QFile file(fileName);
+    if (!file.open(QIODevice::ReadOnly)) {
+        setErrorString(tr("Couldn't open file %1: %2").arg(fileName, file.errorString()));
+        return false;
+    }
+
+    if (!prepareWriting(destName, fileInfo.owner(), fileInfo.group(), size, fi.st_mode, fileInfo.lastRead(), fileInfo.lastModified(), fileInfo.birthTime())) {
+        // qCWarning(KArchiveLog) << " prepareWriting" << destName << "failed";
+        return false;
+    }
+
+    // Read and write data in chunks to minimize memory usage
+    QByteArray array;
+    array.resize(int(qMin(qint64(1024 * 1024), size)));
+    qint64 n;
+    qint64 total = 0;
+    while ((n = file.read(array.data(), array.size())) > 0) {
+        if (!writeData(array.data(), n)) {
+            // qCWarning(KArchiveLog) << "writeData failed";
+            return false;
+        }
+        total += n;
+    }
+    Q_ASSERT(total == size);
+
+    if (!finishWriting(size)) {
+        // qCWarning(KArchiveLog) << "finishWriting failed";
+        return false;
+    }
+    return true;
+}
+
+bool KArchive::addLocalDirectory(const QString &path, const QString &destName)
+{
+    QDir dir(path);
+    if (!dir.exists()) {
+        setErrorString(tr("Directory %1 does not exist").arg(path));
+        return false;
+    }
+    dir.setFilter(dir.filter() | QDir::Hidden);
+    const QStringList files = dir.entryList();
+    for (const QString &file : files) {
+        if (file != QLatin1String(".") && file != QLatin1String("..")) {
+            const QString fileName = path + QLatin1Char('/') + file;
+            //            qCDebug(KArchiveLog) << "storing " << fileName;
+            const QString dest = destName.isEmpty() ? file : (destName + QLatin1Char('/') + file);
+            QFileInfo fileInfo(fileName);
+
+            if (fileInfo.isFile() || fileInfo.isSymLink()) {
+                addLocalFile(fileName, dest);
+            } else if (fileInfo.isDir()) {
+                // Write directory, so that empty dirs are preserved (and permissions written out, etc.)
+                int perms = 0;
+                QT_STATBUF fi;
+                if (STAT_METHOD(QFile::encodeName(fileName).constData(), &fi) != -1) {
+                    perms = fi.st_mode;
+                }
+                writeDir(dest, fileInfo.owner(), fileInfo.group(), perms, fileInfo.lastRead(), fileInfo.lastModified(), fileInfo.birthTime());
+                // Recurse
+                addLocalDirectory(fileName, dest);
+            }
+            // We omit sockets
+        }
+    }
+    return true;
+}
+
+bool KArchive::writeFile(const QString &name,
+                         QByteArrayView data,
+                         mode_t perm,
+                         const QString &user,
+                         const QString &group,
+                         const QDateTime &atime,
+                         const QDateTime &mtime,
+                         const QDateTime &ctime)
+{
+    const qint64 size = data.size();
+    if (!prepareWriting(name, user, group, size, perm, atime, mtime, ctime)) {
+        // qCWarning(KArchiveLog) << "prepareWriting failed";
+        return false;
+    }
+
+    // Write data
+    // Note: if data is null, don't call write, it would terminate the KCompressionDevice
+    if (data.constData() && size && !writeData(data.constData(), size)) {
+        // qCWarning(KArchiveLog) << "writeData failed";
+        return false;
+    }
+
+    if (!finishWriting(size)) {
+        // qCWarning(KArchiveLog) << "finishWriting failed";
+        return false;
+    }
+    return true;
+}
+
+bool KArchive::writeData(const char *data, qint64 size)
+{
+    return doWriteData(data, size);
+}
+
+bool KArchive::writeData(QByteArrayView data)
+{
+    return doWriteData(data.constData(), data.size());
+}
+
+bool KArchive::doWriteData(const char *data, qint64 size)
+{
+    bool ok = device()->write(data, size) == size;
+    if (!ok) {
+        setErrorString(tr("Writing failed: %1").arg(device()->errorString()));
+        d->abortWriting();
+    }
+    return ok;
+}
+
+// The writeDir -> doWriteDir pattern allows to avoid propagating the default
+// values into all virtual methods of subclasses, and it allows more extensibility:
+// if a new argument is needed, we can add a writeDir overload which stores the
+// additional argument in the d pointer, and doWriteDir reimplementations can fetch
+// it from there.
+
+bool KArchive::writeDir(const QString &name,
+                        const QString &user,
+                        const QString &group,
+                        mode_t perm,
+                        const QDateTime &atime,
+                        const QDateTime &mtime,
+                        const QDateTime &ctime)
+{
+    return doWriteDir(name, user, group, perm | 040000, atime, mtime, ctime);
+}
+
+bool KArchive::writeSymLink(const QString &name,
+                            const QString &target,
+                            const QString &user,
+                            const QString &group,
+                            mode_t perm,
+                            const QDateTime &atime,
+                            const QDateTime &mtime,
+                            const QDateTime &ctime)
+{
+    return doWriteSymLink(name, target, user, group, perm, atime, mtime, ctime);
+}
+
+bool KArchive::prepareWriting(const QString &name,
+                              const QString &user,
+                              const QString &group,
+                              qint64 size,
+                              mode_t perm,
+                              const QDateTime &atime,
+                              const QDateTime &mtime,
+                              const QDateTime &ctime)
+{
+    bool ok = doPrepareWriting(name, user, group, size, perm, atime, mtime, ctime);
+    if (!ok) {
+        d->abortWriting();
+    }
+    return ok;
+}
+
+bool KArchive::finishWriting(qint64 size)
+{
+    return doFinishWriting(size);
+}
+
+void KArchive::setErrorString(const QString &errorStr)
+{
+    d->errorStr = errorStr;
+}
+
+static QString getCurrentUserName()
+{
+#if defined(Q_OS_UNIX)
+    struct passwd *pw = getpwuid(getuid());
+    return pw ? QFile::decodeName(pw->pw_name) : QString::number(getuid());
+#elif defined(Q_OS_WIN)
+    wchar_t buffer[255];
+    DWORD size = 255;
+    bool ok = GetUserNameW(buffer, &size);
+    if (!ok) {
+        return QString();
+    }
+    return QString::fromWCharArray(buffer);
+#else
+    return QString();
+#endif
+}
+
+static QString getCurrentGroupName()
+{
+#if defined(Q_OS_UNIX)
+    struct group *grp = getgrgid(getgid());
+    return grp ? QFile::decodeName(grp->gr_name) : QString::number(getgid());
+#elif defined(Q_OS_WIN)
+    return QString();
+#else
+    return QString();
+#endif
+}
+
+KArchiveDirectory *KArchive::rootDir()
+{
+    if (!d->rootDir) {
+        // qCDebug(KArchiveLog) << "Making root dir ";
+        QString username = ::getCurrentUserName();
+        QString groupname = ::getCurrentGroupName();
+
+        d->rootDir = new KArchiveDirectory(this, QStringLiteral("/"), int(0777 + S_IFDIR), QDateTime(), username, groupname, QString());
+    }
+    return d->rootDir;
+}
+
+KArchiveDirectory *KArchive::findOrCreate(const QString &path)
+{
+    return d->findOrCreate(path, 0 /*recursionCounter*/);
+}
+
+KArchiveDirectory *KArchivePrivate::findOrCreate(const QString &path, int recursionCounter)
+{
+    // Check we're not in a path that is ultra deep, this is most probably fine since PATH_MAX on Linux
+    // is defined as 4096, so even on /a/a/a/a/a/a 2500 recursions puts us over that limit
+    // an ultra deep recursion will make us crash due to not enough stack. Tests show that 1MB stack
+    // (default on Linux seems to be 8MB) gives us up to around 4000 recursions
+    if (recursionCounter > 2500) {
+        qCWarning(KArchiveLog) << "path recursion limit exceeded, bailing out";
+        return nullptr;
+    }
+    // qCDebug(KArchiveLog) << path;
+    if (path.isEmpty() || path == QLatin1String("/") || path == QLatin1String(".")) { // root dir => found
+        // qCDebug(KArchiveLog) << "returning rootdir";
+        return q->rootDir();
+    }
+    // Important note : for tar files containing absolute paths
+    // (i.e. beginning with "/"), this means the leading "/" will
+    // be removed (no KDirectory for it), which is exactly the way
+    // the "tar" program works (though it displays a warning about it)
+    // See also KArchiveDirectory::entry().
+
+    // Already created ? => found
+    KArchiveDirectory *existingEntryParentDirectory;
+    const KArchiveEntry *existingEntry = KArchiveDirectoryPrivate::get(q->rootDir())->entry(path, &existingEntryParentDirectory);
+    if (existingEntry) {
+        if (existingEntry->isDirectory())
+        // qCDebug(KArchiveLog) << "found it";
+        {
+            const KArchiveDirectory *dir = static_cast(existingEntry);
+            return const_cast(dir);
+        } else {
+            const KArchiveFile *file = static_cast(existingEntry);
+            if (file->size() > 0) {
+                qCWarning(KArchiveLog) << path << "is normal file, but there are file paths in the archive assuming it is a directory, bailing out";
+                return nullptr;
+            }
+
+            qCDebug(KArchiveLog) << path << " is an empty file, assuming it is actually a directory and replacing";
+            KArchiveEntry *myEntry = const_cast(existingEntry);
+            existingEntryParentDirectory->removeEntry(myEntry);
+            delete myEntry;
+        }
+    }
+
+    // Otherwise go up and try again
+    int pos = path.lastIndexOf(QLatin1Char('/'));
+    KArchiveDirectory *parent;
+    QString dirname;
+    if (pos == -1) { // no more slash => create in root dir
+        parent = q->rootDir();
+        dirname = path;
+    } else {
+        QString left = path.left(pos);
+        dirname = path.mid(pos + 1);
+        parent = findOrCreate(left, recursionCounter + 1); // recursive call... until we find an existing dir.
+    }
+
+    if (!parent) {
+        return nullptr;
+    }
+
+    // qCDebug(KArchiveLog) << "found parent " << parent->name() << " adding " << dirname << " to ensure " << path;
+    // Found -> add the missing piece
+    KArchiveDirectory *e = new KArchiveDirectory(q, dirname, rootDir->permissions(), rootDir->date(), rootDir->user(), rootDir->group(), QString());
+    if (parent->addEntryV2(e)) {
+        return e; // now a directory to  exists
+    } else {
+        return nullptr;
+    }
+}
+
+void KArchive::setDevice(QIODevice *dev)
+{
+    if (d->deviceOwned) {
+        delete d->dev;
+    }
+    d->dev = dev;
+    d->deviceOwned = false;
+}
+
+void KArchive::setRootDir(KArchiveDirectory *rootDir)
+{
+    Q_ASSERT(!d->rootDir); // Call setRootDir only once during parsing please ;)
+    delete d->rootDir; // but if it happens, don't leak
+    d->rootDir = rootDir;
+}
+
+QIODevice::OpenMode KArchive::mode() const
+{
+    return d->mode;
+}
+
+QIODevice *KArchive::device() const
+{
+    return d->dev;
+}
+
+bool KArchive::isOpen() const
+{
+    return d->mode != QIODevice::NotOpen;
+}
+
+QString KArchive::fileName() const
+{
+    return d->fileName;
+}
+
+void KArchivePrivate::abortWriting()
+{
+    if (saveFile) {
+        saveFile->cancelWriting();
+        delete saveFile;
+        saveFile = nullptr;
+        dev = nullptr;
+    }
+}
+
+// this is a hacky wrapper to check if time_t value is invalid
+QDateTime KArchivePrivate::time_tToDateTime(uint time_t)
+{
+    if (time_t == uint(-1)) {
+        return QDateTime();
+    }
+    return QDateTime::fromSecsSinceEpoch(time_t);
+}
+
+////////////////////////////////////////////////////////////////////////
+/////////////////////// KArchiveEntry //////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+class KArchiveEntryPrivate
+{
+public:
+    KArchiveEntryPrivate(KArchive *_archive,
+                         const QString &_name,
+                         int _access,
+                         const QDateTime &_date,
+                         const QString &_user,
+                         const QString &_group,
+                         const QString &_symlink)
+        : name(_name)
+        , date(_date)
+        , access(_access)
+        , user(_user)
+        , group(_group)
+        , symlink(_symlink)
+        , archive(_archive)
+    {
+    }
+    QString name;
+    QDateTime date;
+    mode_t access;
+    QString user;
+    QString group;
+    QString symlink;
+    KArchive *archive;
+};
+
+KArchiveEntry::KArchiveEntry(KArchive *t,
+                             const QString &name,
+                             int access,
+                             const QDateTime &date,
+                             const QString &user,
+                             const QString &group,
+                             const QString &symlink)
+    : d(new KArchiveEntryPrivate(t, name, access, date, user, group, symlink))
+{
+}
+
+KArchiveEntry::~KArchiveEntry()
+{
+    delete d;
+}
+
+QDateTime KArchiveEntry::date() const
+{
+    return d->date;
+}
+
+QString KArchiveEntry::name() const
+{
+    return d->name;
+}
+
+mode_t KArchiveEntry::permissions() const
+{
+    return d->access;
+}
+
+QString KArchiveEntry::user() const
+{
+    return d->user;
+}
+
+QString KArchiveEntry::group() const
+{
+    return d->group;
+}
+
+QString KArchiveEntry::symLinkTarget() const
+{
+    return d->symlink;
+}
+
+bool KArchiveEntry::isFile() const
+{
+    return false;
+}
+
+bool KArchiveEntry::isDirectory() const
+{
+    return false;
+}
+
+KArchive *KArchiveEntry::archive() const
+{
+    return d->archive;
+}
+
+////////////////////////////////////////////////////////////////////////
+/////////////////////// KArchiveFile ///////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+class KArchiveFilePrivate
+{
+public:
+    KArchiveFilePrivate(qint64 _pos, qint64 _size)
+        : pos(_pos)
+        , size(_size)
+    {
+    }
+    qint64 pos;
+    qint64 size;
+};
+
+KArchiveFile::KArchiveFile(KArchive *t,
+                           const QString &name,
+                           int access,
+                           const QDateTime &date,
+                           const QString &user,
+                           const QString &group,
+                           const QString &symlink,
+                           qint64 pos,
+                           qint64 size)
+    : KArchiveEntry(t, name, access, date, user, group, symlink)
+    , d(new KArchiveFilePrivate(pos, size))
+{
+}
+
+KArchiveFile::~KArchiveFile()
+{
+    delete d;
+}
+
+qint64 KArchiveFile::position() const
+{
+    return d->pos;
+}
+
+qint64 KArchiveFile::size() const
+{
+    return d->size;
+}
+
+void KArchiveFile::setSize(qint64 s)
+{
+    d->size = s;
+}
+
+QByteArray KArchiveFile::data() const
+{
+    bool ok = archive()->device()->seek(d->pos);
+    if (!ok) {
+        // qCWarning(KArchiveLog) << "Failed to sync to" << d->pos << "to read" << name();
+    }
+
+    // Read content
+    QByteArray arr;
+    if (d->size) {
+        arr = archive()->device()->read(d->size);
+        Q_ASSERT(arr.size() == d->size);
+    }
+    return arr;
+}
+
+QIODevice *KArchiveFile::createDevice() const
+{
+    return new KLimitedIODevice(archive()->device(), d->pos, d->size);
+}
+
+bool KArchiveFile::isFile() const
+{
+    return true;
+}
+
+static QFileDevice::Permissions withExecutablePerms(QFileDevice::Permissions filePerms, mode_t perms)
+{
+    if (perms & 01) {
+        filePerms |= QFileDevice::ExeOther;
+    }
+
+    if (perms & 010) {
+        filePerms |= QFileDevice::ExeGroup;
+    }
+
+    if (perms & 0100) {
+        filePerms |= QFileDevice::ExeOwner;
+    }
+
+    return filePerms;
+}
+
+bool KArchiveFile::copyTo(const QString &dest) const
+{
+    QFile f(dest + QLatin1Char('/') + name());
+    if (f.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
+        QIODevice *inputDev = createDevice();
+        if (!inputDev) {
+            f.remove();
+            return false;
+        }
+
+        // Read and write data in chunks to minimize memory usage
+        const qint64 chunkSize = 1024 * 1024;
+        qint64 remainingSize = d->size;
+        QByteArray array;
+        array.resize(int(qMin(chunkSize, remainingSize)));
+
+        while (remainingSize > 0) {
+            const qint64 currentChunkSize = qMin(chunkSize, remainingSize);
+            const qint64 n = inputDev->read(array.data(), currentChunkSize);
+            Q_UNUSED(n) // except in Q_ASSERT
+            Q_ASSERT(n == currentChunkSize);
+            f.write(array.data(), currentChunkSize);
+            remainingSize -= currentChunkSize;
+        }
+        f.setPermissions(withExecutablePerms(f.permissions(), permissions()));
+        f.close();
+
+        delete inputDev;
+        return true;
+    }
+    return false;
+}
+
+////////////////////////////////////////////////////////////////////////
+//////////////////////// KArchiveDirectory /////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+KArchiveDirectory::KArchiveDirectory(KArchive *t,
+                                     const QString &name,
+                                     int access,
+                                     const QDateTime &date,
+                                     const QString &user,
+                                     const QString &group,
+                                     const QString &symlink)
+    : KArchiveEntry(t, name, access, date, user, group, symlink)
+    , d(new KArchiveDirectoryPrivate(this))
+{
+}
+
+KArchiveDirectory::~KArchiveDirectory()
+{
+    delete d;
+}
+
+QStringList KArchiveDirectory::entries() const
+{
+    return d->entries.keys();
+}
+
+const KArchiveEntry *KArchiveDirectory::entry(const QString &_name) const
+{
+    KArchiveDirectory *dummy;
+    return d->entry(_name, &dummy);
+}
+
+const KArchiveFile *KArchiveDirectory::file(const QString &name) const
+{
+    const KArchiveEntry *e = entry(name);
+    if (e && e->isFile()) {
+        return static_cast(e);
+    }
+    return nullptr;
+}
+
+void KArchiveDirectory::addEntry(KArchiveEntry *entry)
+{
+    addEntryV2(entry);
+}
+
+bool KArchiveDirectory::addEntryV2(KArchiveEntry *entry)
+{
+    if (d->entries.value(entry->name())) {
+        qCWarning(KArchiveLog) << "directory " << name() << "has entry" << entry->name() << "already";
+        delete entry;
+        return false;
+    }
+    d->entries.insert(entry->name(), entry);
+    return true;
+}
+
+void KArchiveDirectory::removeEntry(KArchiveEntry *entry)
+{
+    if (!entry) {
+        return;
+    }
+
+    QHash::Iterator it = d->entries.find(entry->name());
+    // nothing removed?
+    if (it == d->entries.end()) {
+        qCWarning(KArchiveLog) << "directory " << name() << "has no entry with name " << entry->name();
+        return;
+    }
+    if (it.value() != entry) {
+        qCWarning(KArchiveLog) << "directory " << name() << "has another entry for name " << entry->name();
+        return;
+    }
+    d->entries.erase(it);
+}
+
+bool KArchiveDirectory::isDirectory() const
+{
+    return true;
+}
+
+static bool sortByPosition(const KArchiveFile *file1, const KArchiveFile *file2)
+{
+    return file1->position() < file2->position();
+}
+
+bool KArchiveDirectory::copyTo(const QString &dest, bool recursiveCopy) const
+{
+    QDir root;
+    const QString destDir(QDir(dest).absolutePath()); // get directory path without any "." or ".."
+
+    QList fileList;
+    QMap fileToDir;
+
+    // placeholders for iterated items
+    QStack dirStack;
+    QStack dirNameStack;
+
+    dirStack.push(this); // init stack at current directory
+    dirNameStack.push(destDir); // ... with given path
+    do {
+        const KArchiveDirectory *curDir = dirStack.pop();
+
+        // extract only to specified folder if it is located within archive's extraction folder
+        // otherwise put file under root position in extraction folder
+        QString curDirName = dirNameStack.pop();
+        if (!QDir(curDirName).absolutePath().startsWith(destDir)) {
+            qCWarning(KArchiveLog) << "Attempted export into folder" << curDirName << "which is outside of the extraction root folder" << destDir << "."
+                                   << "Changing export of contained files to extraction root folder.";
+            curDirName = destDir;
+        }
+
+        if (!root.mkpath(curDirName)) {
+            return false;
+        }
+
+        const QStringList dirEntries = curDir->entries();
+        for (QStringList::const_iterator it = dirEntries.begin(); it != dirEntries.end(); ++it) {
+            const KArchiveEntry *curEntry = curDir->entry(*it);
+            if (!curEntry->symLinkTarget().isEmpty()) {
+                QString linkName = curDirName + QLatin1Char('/') + curEntry->name();
+                // To create a valid link on Windows, linkName must have a .lnk file extension.
+#ifdef Q_OS_WIN
+                if (!linkName.endsWith(QLatin1String(".lnk"))) {
+                    linkName += QLatin1String(".lnk");
+                }
+#endif
+                QFile symLinkTarget(curEntry->symLinkTarget());
+                if (!symLinkTarget.link(linkName)) {
+                    // qCDebug(KArchiveLog) << "symlink(" << curEntry->symLinkTarget() << ',' << linkName << ") failed:" << strerror(errno);
+                }
+            } else {
+                if (curEntry->isFile()) {
+                    const KArchiveFile *curFile = dynamic_cast(curEntry);
+                    if (curFile) {
+                        fileList.append(curFile);
+                        fileToDir.insert(curFile->position(), curDirName);
+                    }
+                }
+
+                if (curEntry->isDirectory() && recursiveCopy) {
+                    const KArchiveDirectory *ad = dynamic_cast(curEntry);
+                    if (ad) {
+                        dirStack.push(ad);
+                        dirNameStack.push(curDirName + QLatin1Char('/') + curEntry->name());
+                    }
+                }
+            }
+        }
+    } while (!dirStack.isEmpty());
+
+    std::sort(fileList.begin(), fileList.end(), sortByPosition); // sort on d->pos, so we have a linear access
+
+    for (QList::const_iterator it = fileList.constBegin(), end = fileList.constEnd(); it != end; ++it) {
+        const KArchiveFile *f = *it;
+        qint64 pos = f->position();
+        if (!f->copyTo(fileToDir[pos])) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void KArchive::virtual_hook(int, void *)
+{
+    /*BASE::virtual_hook( id, data )*/;
+}
+
+void KArchiveEntry::virtual_hook(int, void *)
+{
+    /*BASE::virtual_hook( id, data );*/
+}
+
+void KArchiveFile::virtual_hook(int id, void *data)
+{
+    KArchiveEntry::virtual_hook(id, data);
+}
+
+void KArchiveDirectory::virtual_hook(int id, void *data)
+{
+    KArchiveEntry::virtual_hook(id, data);
+}
diff --git a/src/libs/3rdparty/karchive/src/karchive.h b/src/libs/3rdparty/karchive/src/karchive.h
new file mode 100644
index 00000000000..8d490304546
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/karchive.h
@@ -0,0 +1,433 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000-2005 David Faure 
+   SPDX-FileCopyrightText: 2003 Leo Savernik 
+
+   Moved from ktar.h by Roberto Teixeira 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+#ifndef KARCHIVE_H
+#define KARCHIVE_H
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "karchive_export.h"
+
+#ifdef Q_OS_WIN
+#include  // mode_t
+#endif
+
+class KArchiveDirectory;
+class KArchiveFile;
+
+class KArchivePrivate;
+/**
+ * @class KArchive karchive.h KArchive
+ *
+ * KArchive is a base class for reading and writing archives.
+ * @short generic class for reading/writing archives
+ * @author David Faure 
+ */
+class KARCHIVE_EXPORT KArchive
+{
+    Q_DECLARE_TR_FUNCTIONS(KArchive)
+
+protected:
+    /**
+     * Base constructor (protected since this is a pure virtual class).
+     * @param fileName is a local path (e.g. "/tmp/myfile.ext"),
+     * from which the archive will be read from, or into which the archive
+     * will be written, depending on the mode given to open().
+     */
+    explicit KArchive(const QString &fileName);
+
+    /**
+     * Base constructor (protected since this is a pure virtual class).
+     * @param dev the I/O device where the archive reads its data
+     * Note that this can be a file, but also a data buffer, a compression filter, etc.
+     * For a file in writing mode it is better to use the other constructor
+     * though, to benefit from the use of QSaveFile when saving.
+     */
+    explicit KArchive(QIODevice *dev);
+
+public:
+    virtual ~KArchive();
+
+    /**
+     * Opens the archive for reading or writing.
+     * Inherited classes might want to reimplement openArchive instead.
+     * @param mode may be QIODevice::ReadOnly or QIODevice::WriteOnly
+     * @see close
+     */
+    virtual bool open(QIODevice::OpenMode mode);
+
+    /**
+     * Closes the archive.
+     * Inherited classes might want to reimplement closeArchive instead.
+     *
+     * @return true if close succeeded without problems
+     * @see open
+     */
+    virtual bool close();
+
+    /**
+     * Returns a description of the last error
+     * @since 5.29
+     */
+    QString errorString() const;
+
+    /**
+     * Checks whether the archive is open.
+     * @return true if the archive is opened
+     */
+    bool isOpen() const;
+
+    /**
+     * Returns the mode in which the archive was opened
+     * @return the mode in which the archive was opened (QIODevice::ReadOnly or QIODevice::WriteOnly)
+     * @see open()
+     */
+    QIODevice::OpenMode mode() const;
+
+    /**
+     * The underlying device.
+     * @return the underlying device.
+     */
+    QIODevice *device() const;
+
+    /**
+     * The name of the archive file, as passed to the constructor that takes a
+     * fileName, or an empty string if you used the QIODevice constructor.
+     * @return the name of the file, or QString() if unknown
+     */
+    QString fileName() const;
+
+    /**
+     * If an archive is opened for reading, then the contents
+     * of the archive can be accessed via this function.
+     * @return the directory of the archive
+     */
+    const KArchiveDirectory *directory() const;
+
+    /**
+     * Writes a local file into the archive. The main difference with writeFile,
+     * is that this method minimizes memory usage, by not loading the whole file
+     * into memory in one go.
+     *
+     * If @p fileName is a symbolic link, it will be written as is, i.e.
+     * it will not be resolved before.
+     * @param fileName full path to an existing local file, to be added to the archive.
+     * @param destName the resulting name (or relative path) of the file in the archive.
+     */
+    bool addLocalFile(const QString &fileName, const QString &destName);
+
+    /**
+     * Writes a local directory into the archive, including all its contents, recursively.
+     * Calls addLocalFile for each file to be added.
+     *
+     * It will also add a @p path that is a symbolic link to a
+     * directory. The symbolic link will be dereferenced and the content of the
+     * directory it is pointing to added recursively. However, symbolic links
+     * *under* @p path will be stored as is.
+     * @param path full path to an existing local directory, to be added to the archive.
+     * @param destName the resulting name (or relative path) of the file in the archive.
+     */
+    bool addLocalDirectory(const QString &path, const QString &destName);
+
+    /**
+     * If an archive is opened for writing then you can add new directories
+     * using this function. KArchive won't write one directory twice.
+     *
+     * This method also allows some file metadata to be set.
+     * However, depending on the archive type not all metadata might be regarded.
+     *
+     * @param name the name of the directory
+     * @param user the user that owns the directory
+     * @param group the group that owns the directory
+     * @param perm permissions of the directory
+     * @param atime time the file was last accessed
+     * @param mtime modification time of the file
+     * @param ctime time of last status change
+     */
+    bool writeDir(const QString &name,
+                  const QString &user = QString(),
+                  const QString &group = QString(),
+                  mode_t perm = 040755,
+                  const QDateTime &atime = QDateTime(),
+                  const QDateTime &mtime = QDateTime(),
+                  const QDateTime &ctime = QDateTime());
+
+    /**
+     * Writes a symbolic link to the archive if supported.
+     * The archive must be opened for writing.
+     *
+     * @param name name of symbolic link
+     * @param target target of symbolic link
+     * @param user the user that owns the directory
+     * @param group the group that owns the directory
+     * @param perm permissions of the directory
+     * @param atime time the file was last accessed
+     * @param mtime modification time of the file
+     * @param ctime time of last status change
+     */
+    bool writeSymLink(const QString &name,
+                      const QString &target,
+                      const QString &user = QString(),
+                      const QString &group = QString(),
+                      mode_t perm = 0120755,
+                      const QDateTime &atime = QDateTime(),
+                      const QDateTime &mtime = QDateTime(),
+                      const QDateTime &ctime = QDateTime());
+
+    /**
+     * Writes a new file into the archive.
+     *
+     * The archive must be opened for writing first.
+     *
+     * The necessary parent directories are created automatically
+     * if needed. For instance, writing "mydir/test1" does not
+     * require creating the directory "mydir" first.
+     *
+     * This method also allows some file metadata to be
+     * set. However, depending on the archive type not all metadata might be
+     * written out.
+     *
+     * @param name the name of the file
+     * @param data the data to write
+     * @param perm permissions of the file
+     * @param user the user that owns the file
+     * @param group the group that owns the file
+     * @param atime time the file was last accessed
+     * @param mtime modification time of the file
+     * @param ctime time of last status change
+     * @since 6.0
+     */
+    bool writeFile(const QString &name,
+                   QByteArrayView data,
+                   mode_t perm = 0100644,
+                   const QString &user = QString(),
+                   const QString &group = QString(),
+                   const QDateTime &atime = QDateTime(),
+                   const QDateTime &mtime = QDateTime(),
+                   const QDateTime &ctime = QDateTime());
+
+    /**
+     * Here's another way of writing a file into an archive:
+     * Call prepareWriting(), then call writeData()
+     * as many times as wanted then call finishWriting( totalSize ).
+     * For tar.gz files, you need to know the size before hand, it is needed in the header!
+     * For zip files, size isn't used.
+     *
+     * This method also allows some file metadata to be
+     * set. However, depending on the archive type not all metadata might be
+     * regarded.
+     * @param name the name of the file
+     * @param user the user that owns the file
+     * @param group the group that owns the file
+     * @param size the size of the file
+     * @param perm permissions of the file
+     * @param atime time the file was last accessed
+     * @param mtime modification time of the file
+     * @param ctime time of last status change
+     */
+    bool prepareWriting(const QString &name,
+                        const QString &user,
+                        const QString &group,
+                        qint64 size,
+                        mode_t perm = 0100644,
+                        const QDateTime &atime = QDateTime(),
+                        const QDateTime &mtime = QDateTime(),
+                        const QDateTime &ctime = QDateTime());
+
+    /**
+     * Write data into the current file - to be called after calling prepareWriting
+     * @param data a pointer to the data
+     * @param size the size of the chunk
+     * @return @c true if successful, @c false otherwise
+     */
+    bool writeData(const char *data, qint64 size);
+
+    /**
+     * Overload for writeData(const char *, qint64);
+     * @since 6.0
+     */
+    bool writeData(QByteArrayView data);
+
+    /**
+     * Call finishWriting after writing the data.
+     * @param size the size of the file
+     * @see prepareWriting()
+     */
+    bool finishWriting(qint64 size);
+
+protected:
+    /**
+     * Opens an archive for reading or writing.
+     * Called by open.
+     * @param mode may be QIODevice::ReadOnly or QIODevice::WriteOnly
+     */
+    virtual bool openArchive(QIODevice::OpenMode mode) = 0;
+
+    /**
+     * Closes the archive.
+     * Called by close.
+     */
+    virtual bool closeArchive() = 0;
+
+    /**
+     * Sets error description
+     * @param errorStr error description
+     * @since 5.29
+     */
+    void setErrorString(const QString &errorStr);
+
+    /**
+     * Retrieves or create the root directory.
+     * The default implementation assumes that openArchive() did the parsing,
+     * so it creates a dummy rootdir if none was set (write mode, or no '/' in the archive).
+     * Reimplement this to provide parsing/listing on demand.
+     * @return the root directory
+     */
+    virtual KArchiveDirectory *rootDir();
+
+    /**
+     * Write a directory to the archive.
+     * This virtual method must be implemented by subclasses.
+     *
+     * Depending on the archive type not all metadata might be used.
+     *
+     * @param name the name of the directory
+     * @param user the user that owns the directory
+     * @param group the group that owns the directory
+     * @param perm permissions of the directory. Use 040755 if you don't have any other information.
+     * @param atime time the file was last accessed
+     * @param mtime modification time of the file
+     * @param ctime time of last status change
+     * @see writeDir
+     */
+    virtual bool doWriteDir(const QString &name,
+                            const QString &user,
+                            const QString &group,
+                            mode_t perm,
+                            const QDateTime &atime,
+                            const QDateTime &mtime,
+                            const QDateTime &ctime) = 0;
+
+    /**
+     * Writes a symbolic link to the archive.
+     * This virtual method must be implemented by subclasses.
+     *
+     * @param name name of symbolic link
+     * @param target target of symbolic link
+     * @param user the user that owns the directory
+     * @param group the group that owns the directory
+     * @param perm permissions of the directory
+     * @param atime time the file was last accessed
+     * @param mtime modification time of the file
+     * @param ctime time of last status change
+     * @see writeSymLink
+     */
+    virtual bool doWriteSymLink(const QString &name,
+                                const QString &target,
+                                const QString &user,
+                                const QString &group,
+                                mode_t perm,
+                                const QDateTime &atime,
+                                const QDateTime &mtime,
+                                const QDateTime &ctime) = 0;
+
+    /**
+     * This virtual method must be implemented by subclasses.
+     *
+     * Depending on the archive type not all metadata might be used.
+     *
+     * @param name the name of the file
+     * @param user the user that owns the file
+     * @param group the group that owns the file
+     * @param size the size of the file
+     * @param perm permissions of the file. Use 0100644 if you don't have any more specific permissions to set.
+     * @param atime time the file was last accessed
+     * @param mtime modification time of the file
+     * @param ctime time of last status change
+     * @see prepareWriting
+     */
+    virtual bool doPrepareWriting(const QString &name,
+                                  const QString &user,
+                                  const QString &group,
+                                  qint64 size,
+                                  mode_t perm,
+                                  const QDateTime &atime,
+                                  const QDateTime &mtime,
+                                  const QDateTime &ctime) = 0;
+
+    /**
+     * Write data into the current file.
+     * Called by writeData.
+     *
+     * @param data a pointer to the data
+     * @param size the size of the chunk
+     * @return @c true if successful, @c false otherwise
+     * @see writeData
+     * @since 6.0
+     */
+    virtual bool doWriteData(const char *data, qint64 size);
+
+    /**
+     * Called after writing the data.
+     * This virtual method must be implemented by subclasses.
+     *
+     * @param size the size of the file
+     * @see finishWriting()
+     */
+    virtual bool doFinishWriting(qint64 size) = 0;
+
+    /**
+     * Ensures that @p path exists, create otherwise.
+     * This handles e.g. tar files missing directory entries, like mico-2.3.0.tar.gz :)
+     * @param path the path of the directory
+     * @return the directory with the given @p path
+     */
+    KArchiveDirectory *findOrCreate(const QString &path);
+
+    /**
+     * Can be reimplemented in order to change the creation of the device
+     * (when using the fileName constructor). By default this method uses
+     * QSaveFile when saving, and a simple QFile on reading.
+     * This method is called by open().
+     */
+    virtual bool createDevice(QIODevice::OpenMode mode);
+
+    /**
+     * Can be called by derived classes in order to set the underlying device.
+     * Note that KArchive will -not- own the device, it must be deleted by the derived class.
+     */
+    void setDevice(QIODevice *dev);
+
+    /**
+     * Derived classes call setRootDir from openArchive,
+     * to set the root directory after parsing an existing archive.
+     */
+    void setRootDir(KArchiveDirectory *rootDir);
+
+protected:
+    virtual void virtual_hook(int id, void *data);
+
+private:
+    friend class KArchivePrivate;
+    KArchivePrivate *const d;
+};
+
+// for source compat
+#include "karchivedirectory.h"
+#include "karchivefile.h"
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/karchive_export.h b/src/libs/3rdparty/karchive/src/karchive_export.h
new file mode 100644
index 00000000000..0e1d27afc8a
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/karchive_export.h
@@ -0,0 +1,14 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include 
+
+#ifndef KARCHIVE_EXPORT
+#ifdef KARCHIVE_LIBRARY
+#define KARCHIVE_EXPORT Q_DECL_EXPORT
+#else
+#define KARCHIVE_EXPORT Q_DECL_IMPORT
+#endif
+#endif
diff --git a/src/libs/3rdparty/karchive/src/karchive_p.h b/src/libs/3rdparty/karchive/src/karchive_p.h
new file mode 100644
index 00000000000..0a83def8cb9
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/karchive_p.h
@@ -0,0 +1,59 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000-2005 David Faure 
+   SPDX-FileCopyrightText: 2003 Leo Savernik 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KARCHIVE_P_H
+#define KARCHIVE_P_H
+
+#include "karchive.h"
+
+#include 
+
+class KArchivePrivate
+{
+    Q_DECLARE_TR_FUNCTIONS(KArchivePrivate)
+
+public:
+    KArchivePrivate(KArchive *parent)
+        : q(parent)
+    {
+    }
+    ~KArchivePrivate()
+    {
+        if (deviceOwned) {
+            delete dev; // we created it ourselves in open()
+            dev = nullptr;
+        }
+
+        delete saveFile;
+        delete rootDir;
+    }
+
+    KArchivePrivate(const KArchivePrivate &) = delete;
+    KArchivePrivate &operator=(const KArchivePrivate &) = delete;
+
+    static bool hasRootDir(KArchive *archive)
+    {
+        return archive->d->rootDir;
+    }
+
+    void abortWriting();
+
+    static QDateTime time_tToDateTime(uint time_t);
+
+    KArchiveDirectory *findOrCreate(const QString &path, int recursionCounter);
+
+    KArchive *q = nullptr;
+    KArchiveDirectory *rootDir = nullptr;
+    QSaveFile *saveFile = nullptr;
+    QIODevice *dev = nullptr;
+    QString fileName;
+    QIODevice::OpenMode mode = QIODevice::NotOpen;
+    bool deviceOwned = false; // if true, we (KArchive) own dev and must delete it
+    QString errorStr{tr("Unknown error")};
+};
+
+#endif // KARCHIVE_P_H
diff --git a/src/libs/3rdparty/karchive/src/karchivedirectory.h b/src/libs/3rdparty/karchive/src/karchivedirectory.h
new file mode 100644
index 00000000000..9a45b9ad71e
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/karchivedirectory.h
@@ -0,0 +1,131 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000-2005 David Faure 
+   SPDX-FileCopyrightText: 2003 Leo Savernik 
+
+   Moved from ktar.h by Roberto Teixeira 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+#ifndef KARCHIVEDIRECTORY_H
+#define KARCHIVEDIRECTORY_H
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include "karchiveentry.h"
+
+class KArchiveDirectoryPrivate;
+class KArchiveFile;
+/**
+ * @class KArchiveDirectory karchivedirectory.h KArchiveDirectory
+ *
+ * Represents a directory entry in a KArchive.
+ * @short A directory in an archive.
+ *
+ * @see KArchive
+ * @see KArchiveFile
+ */
+class KARCHIVE_EXPORT KArchiveDirectory : public KArchiveEntry
+{
+public:
+    /**
+     * Creates a new directory entry.
+     * @param archive the entries archive
+     * @param name the name of the entry
+     * @param access the permissions in unix format
+     * @param date the date (in seconds since 1970)
+     * @param user the user that owns the entry
+     * @param group the group that owns the entry
+     * @param symlink the symlink, or QString()
+     */
+    KArchiveDirectory(
+        KArchive *archive,
+        const QString &name,
+        int access,
+        const QDateTime &date,
+        const QString &user,
+        const QString &group,
+        const QString &symlink);
+
+    ~KArchiveDirectory() override;
+
+    /**
+     * Returns a list of sub-entries.
+     * Note that the list is not sorted, it's even in random order (due to using a hashtable).
+     * Use sort() on the result to sort the list by filename.
+     *
+     * @return the names of all entries in this directory (filenames, no path).
+     */
+    QStringList entries() const;
+
+    /**
+     * Returns the entry in the archive with the given name.
+     * The entry could be a file or a directory, use isFile() to find out which one it is.
+     * @param name may be "test1", "mydir/test3", "mydir/mysubdir/test3", etc.
+     * @return a pointer to the entry in the directory, or a null pointer if there is no such entry.
+     */
+    const KArchiveEntry *entry(const QString &name) const;
+
+    /**
+     * Returns the file entry in the archive with the given name.
+     * If the entry exists and is a file, a KArchiveFile is returned.
+     * Otherwise, a null pointer is returned.
+     * This is a convenience method for entry(), when we know the entry is expected to be a file.
+     *
+     * @param name may be "test1", "mydir/test3", "mydir/mysubdir/test3", etc.
+     * @return a pointer to the file entry in the directory, or a null pointer if there is no such file entry.
+     * @since 5.3
+     */
+    const KArchiveFile *file(const QString &name) const;
+
+    /**
+     * @internal
+     * Adds a new entry to the directory.
+     * Note: this can delete the entry if another one with the same name is already present
+     */
+    void addEntry(KArchiveEntry *); // KF6 TODO: return bool
+
+    /**
+     * @internal
+     * Adds a new entry to the directory.
+     * @return whether the entry was added or not. Non added entries are deleted
+     */
+    bool addEntryV2(KArchiveEntry *); // KF6 TODO: merge with the one above
+
+    /**
+     * @internal
+     * Removes an entry from the directory.
+     */
+    void removeEntry(KArchiveEntry *); // KF6 TODO: return bool since it can fail
+
+    /**
+     * Checks whether this entry is a directory.
+     * @return true, since this entry is a directory
+     */
+    bool isDirectory() const override;
+
+    /**
+     * Extracts all entries in this archive directory to the directory
+     * @p dest.
+     * @param dest the directory to extract to
+     * @param recursive if set to true, subdirectories are extracted as well
+     * @return true on success, false if the directory (dest + '/' + name()) couldn't be created
+     */
+    bool copyTo(
+        const QString &dest,
+        bool recursive = true,
+        std::function progress = nullptr) const;
+
+protected:
+    void virtual_hook(int id, void *data) override;
+
+private:
+    friend class KArchiveDirectoryPrivate;
+    KArchiveDirectoryPrivate *const d;
+};
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/karchiveentry.h b/src/libs/3rdparty/karchive/src/karchiveentry.h
new file mode 100644
index 00000000000..c18bf685cda
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/karchiveentry.h
@@ -0,0 +1,111 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000-2005 David Faure 
+   SPDX-FileCopyrightText: 2003 Leo Savernik 
+
+   Moved from ktar.h by Roberto Teixeira 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+#ifndef KARCHIVEENTRY_H
+#define KARCHIVEENTRY_H
+
+#include 
+#include 
+
+#include "karchive_export.h"
+
+#include 
+#include 
+
+#ifdef Q_OS_WIN
+#include  // mode_t
+#endif
+
+class KArchiveDirectory;
+class KArchiveFile;
+class KArchive;
+
+class KArchiveEntryPrivate;
+/**
+ * @class KArchiveEntry karchiveentry.h KArchiveEntry
+ *
+ * A base class for entries in an KArchive.
+ * @short Base class for the archive-file's directory structure.
+ *
+ * @see KArchiveFile
+ * @see KArchiveDirectory
+ */
+class KARCHIVE_EXPORT KArchiveEntry
+{
+public:
+    /**
+     * Creates a new entry.
+     * @param archive the entries archive
+     * @param name the name of the entry
+     * @param access the permissions in unix format
+     * @param date the date (in seconds since 1970)
+     * @param user the user that owns the entry
+     * @param group the group that owns the entry
+     * @param symlink the symlink, or QString()
+     */
+    KArchiveEntry(KArchive *archive, const QString &name, int access, const QDateTime &date, const QString &user, const QString &group, const QString &symlink);
+
+    virtual ~KArchiveEntry();
+
+    /**
+     * Creation date of the file.
+     * @return the creation date
+     */
+    QDateTime date() const;
+
+    /**
+     * Name of the file without path.
+     * @return the file name without path
+     */
+    QString name() const;
+    /**
+     * The permissions and mode flags as returned by the stat() function
+     * in st_mode.
+     * @return the permissions
+     */
+    mode_t permissions() const;
+    /**
+     * User who created the file.
+     * @return the owner of the file
+     */
+    QString user() const;
+    /**
+     * Group of the user who created the file.
+     * @return the group of the file
+     */
+    QString group() const;
+
+    /**
+     * Symlink if there is one.
+     * @return the symlink, or QString()
+     */
+    QString symLinkTarget() const;
+
+    /**
+     * Checks whether the entry is a file.
+     * @return true if this entry is a file
+     */
+    virtual bool isFile() const;
+
+    /**
+     * Checks whether the entry is a directory.
+     * @return true if this entry is a directory
+     */
+    virtual bool isDirectory() const;
+
+protected:
+    KArchive *archive() const;
+
+protected:
+    virtual void virtual_hook(int id, void *data);
+
+private:
+    KArchiveEntryPrivate *const d;
+};
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/karchivefile.h b/src/libs/3rdparty/karchive/src/karchivefile.h
new file mode 100644
index 00000000000..fae0d584897
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/karchivefile.h
@@ -0,0 +1,110 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000-2005 David Faure 
+   SPDX-FileCopyrightText: 2003 Leo Savernik 
+
+   Moved from ktar.h by Roberto Teixeira 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+#ifndef KARCHIVEFILE_H
+#define KARCHIVEFILE_H
+
+#include "karchiveentry.h"
+
+class KArchiveFilePrivate;
+/**
+ * @class KArchiveFile karchivefile.h KArchiveFile
+ *
+ * Represents a file entry in a KArchive.
+ * @short A file in an archive.
+ *
+ * @see KArchive
+ * @see KArchiveDirectory
+ */
+class KARCHIVE_EXPORT KArchiveFile : public KArchiveEntry
+{
+public:
+    /**
+     * Creates a new file entry. Do not call this, KArchive takes care of it.
+     * @param archive the entries archive
+     * @param name the name of the entry
+     * @param access the permissions in unix format
+     * @param date the date (in seconds since 1970)
+     * @param user the user that owns the entry
+     * @param group the group that owns the entry
+     * @param symlink the symlink, or QString()
+     * @param pos the position of the file in the directory
+     * @param size the size of the file
+     */
+    KArchiveFile(
+        KArchive *archive,
+        const QString &name,
+        int access,
+        const QDateTime &date,
+        const QString &user,
+        const QString &group,
+        const QString &symlink,
+        qint64 pos,
+        qint64 size);
+
+    /**
+     * Destructor. Do not call this, KArchive takes care of it.
+     */
+    ~KArchiveFile() override;
+
+    /**
+     * Position of the data in the [uncompressed] archive.
+     * @return the position of the file
+     */
+    qint64 position() const;
+    /**
+     * Size of the data.
+     * @return the size of the file
+     */
+    qint64 size() const;
+    /**
+     * Set size of data, usually after writing the file.
+     * @param s the new size of the file
+     */
+    void setSize(qint64 s);
+
+    /**
+     * Returns the data of the file.
+     * Call data() with care (only once per file), this data isn't cached.
+     * @return the content of this file.
+     */
+    virtual QByteArray data() const;
+
+    /**
+     * This method returns QIODevice (internal class: KLimitedIODevice)
+     * on top of the underlying QIODevice. This is obviously for reading only.
+     *
+     * WARNING: Note that the ownership of the device is being transferred to the caller,
+     * who will have to delete it.
+     *
+     * The returned device auto-opens (in readonly mode), no need to open it.
+     * @return the QIODevice of the file
+     */
+    virtual QIODevice *createDevice() const;
+
+    /**
+     * Checks whether this entry is a file.
+     * @return true, since this entry is a file
+     */
+    bool isFile() const override;
+
+    /**
+     * Extracts the file to the directory @p dest
+     * @param dest the directory to extract to
+     * @return true on success, false if the file (dest + '/' + name()) couldn't be created
+     */
+    bool copyTo(const QString &dest) const;
+
+protected:
+    void virtual_hook(int id, void *data) override;
+
+private:
+    KArchiveFilePrivate *const d;
+};
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/kbzip2filter.cpp b/src/libs/3rdparty/karchive/src/kbzip2filter.cpp
new file mode 100644
index 00000000000..67532b640cd
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kbzip2filter.cpp
@@ -0,0 +1,198 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000-2005 David Faure 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "kbzip2filter.h"
+#include "loggingcategory.h"
+
+#if HAVE_BZIP2_SUPPORT
+
+// we don't need that
+#define BZ_NO_STDIO
+extern "C" {
+#include 
+}
+
+#if NEED_BZ2_PREFIX
+#define bzDecompressInit(x, y, z) BZ2_bzDecompressInit(x, y, z)
+#define bzDecompressEnd(x) BZ2_bzDecompressEnd(x)
+#define bzCompressEnd(x) BZ2_bzCompressEnd(x)
+#define bzDecompress(x) BZ2_bzDecompress(x)
+#define bzCompress(x, y) BZ2_bzCompress(x, y)
+#define bzCompressInit(x, y, z, a) BZ2_bzCompressInit(x, y, z, a);
+#endif
+
+#include 
+
+#include 
+
+// For docu on this, see /usr/doc/bzip2-0.9.5d/bzip2-0.9.5d/manual_3.html
+
+class Q_DECL_HIDDEN KBzip2Filter::Private
+{
+public:
+    Private()
+        : isInitialized(false)
+    {
+        memset(&zStream, 0, sizeof(zStream));
+        mode = 0;
+    }
+
+    bz_stream zStream;
+    int mode;
+    bool isInitialized;
+};
+
+KBzip2Filter::KBzip2Filter()
+    : d(new Private)
+{
+}
+
+KBzip2Filter::~KBzip2Filter()
+{
+    delete d;
+}
+
+bool KBzip2Filter::init(int mode)
+{
+    if (d->isInitialized) {
+        terminate();
+    }
+
+    d->zStream.next_in = nullptr;
+    d->zStream.avail_in = 0;
+    if (mode == QIODevice::ReadOnly) {
+        const int result = bzDecompressInit(&d->zStream, 0, 0);
+        if (result != BZ_OK) {
+            // qCDebug(KArchiveLog) << "bzDecompressInit returned " << result;
+            return false;
+        }
+    } else if (mode == QIODevice::WriteOnly) {
+        const int result = bzCompressInit(&d->zStream, 5, 0, 0);
+        if (result != BZ_OK) {
+            // qCDebug(KArchiveLog) << "bzDecompressInit returned " << result;
+            return false;
+        }
+    } else {
+        // qCWarning(KArchiveLog) << "Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
+        return false;
+    }
+    d->mode = mode;
+    d->isInitialized = true;
+    return true;
+}
+
+int KBzip2Filter::mode() const
+{
+    return d->mode;
+}
+
+bool KBzip2Filter::terminate()
+{
+    if (d->mode == QIODevice::ReadOnly) {
+        const int result = bzDecompressEnd(&d->zStream);
+        if (result != BZ_OK) {
+            // qCDebug(KArchiveLog) << "bzDecompressEnd returned " << result;
+            return false;
+        }
+    } else if (d->mode == QIODevice::WriteOnly) {
+        const int result = bzCompressEnd(&d->zStream);
+        if (result != BZ_OK) {
+            // qCDebug(KArchiveLog) << "bzCompressEnd returned " << result;
+            return false;
+        }
+    } else {
+        // qCWarning(KArchiveLog) << "Unsupported mode " << d->mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
+        return false;
+    }
+    d->isInitialized = false;
+    return true;
+}
+
+void KBzip2Filter::reset()
+{
+    // bzip2 doesn't seem to have a reset call...
+    terminate();
+    init(d->mode);
+}
+
+void KBzip2Filter::setOutBuffer(char *data, uint maxlen)
+{
+    d->zStream.avail_out = maxlen;
+    d->zStream.next_out = data;
+}
+
+void KBzip2Filter::setInBuffer(const char *data, unsigned int size)
+{
+    d->zStream.avail_in = size;
+    d->zStream.next_in = const_cast(data);
+}
+
+int KBzip2Filter::inBufferAvailable() const
+{
+    return d->zStream.avail_in;
+}
+
+int KBzip2Filter::outBufferAvailable() const
+{
+    return d->zStream.avail_out;
+}
+
+KBzip2Filter::Result KBzip2Filter::uncompress()
+{
+    // qCDebug(KArchiveLog) << "Calling bzDecompress with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
+    int result = bzDecompress(&d->zStream);
+    if (result < BZ_OK) {
+        bzDecompressEnd(&d->zStream);
+    }
+
+    switch (result) {
+    case BZ_OK:
+        return KFilterBase::Ok;
+    case BZ_STREAM_END:
+        return KFilterBase::End;
+    case BZ_MEM_ERROR:
+        qCWarning(KArchiveLog) << "bzDecompress error, insufficient memory";
+        break;
+    case BZ_DATA_ERROR:
+        qCWarning(KArchiveLog) << "bzDecompress error, data integrity error";
+        break;
+    case BZ_DATA_ERROR_MAGIC:
+        qCWarning(KArchiveLog) << "bzDecompress error, stream does not start with the right magic bytes";
+        break;
+    case BZ_PARAM_ERROR:
+        qCWarning(KArchiveLog) << "bzDecompress error, parameter error";
+        break;
+    default:
+        qCWarning(KArchiveLog) << "bzDecompress error, returned:" << result;
+        break;
+    }
+    return KFilterBase::Error;
+}
+
+KBzip2Filter::Result KBzip2Filter::compress(bool finish)
+{
+    // qCDebug(KArchiveLog) << "Calling bzCompress with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
+    int result = bzCompress(&d->zStream, finish ? BZ_FINISH : BZ_RUN);
+
+    switch (result) {
+    case BZ_OK:
+    case BZ_FLUSH_OK:
+    case BZ_RUN_OK:
+    case BZ_FINISH_OK:
+        return KFilterBase::Ok;
+        break;
+    case BZ_STREAM_END:
+        // qCDebug(KArchiveLog) << "  bzCompress returned " << result;
+        return KFilterBase::End;
+        break;
+    default:
+        // qCDebug(KArchiveLog) << "  bzCompress returned " << result;
+        return KFilterBase::Error;
+        break;
+    }
+}
+
+#endif /* HAVE_BZIP2_SUPPORT */
diff --git a/src/libs/3rdparty/karchive/src/kbzip2filter.h b/src/libs/3rdparty/karchive/src/kbzip2filter.h
new file mode 100644
index 00000000000..2aca8ebaaaa
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kbzip2filter.h
@@ -0,0 +1,47 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000 David Faure 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef __kbzip2filter__h
+#define __kbzip2filter__h
+
+#if HAVE_BZIP2_SUPPORT
+
+#include "kfilterbase.h"
+
+/**
+ * Internal class used by KCompressionDevice
+ * @internal
+ */
+class KBzip2Filter : public KFilterBase
+{
+public:
+    KBzip2Filter();
+    ~KBzip2Filter() override;
+
+    bool init(int) override;
+    int mode() const override;
+    bool terminate() override;
+    void reset() override;
+    bool readHeader() override
+    {
+        return true; // bzip2 handles it by itself ! Cool !
+    }
+    bool writeHeader(const QByteArray &) override { return true; }
+    void setOutBuffer(char *data, uint maxlen) override;
+    void setInBuffer(const char *data, uint size) override;
+    int inBufferAvailable() const override;
+    int outBufferAvailable() const override;
+    Result uncompress() override;
+    Result compress(bool finish) override;
+
+private:
+    class Private;
+    Private *const d;
+};
+
+#endif
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/kcompressiondevice.cpp b/src/libs/3rdparty/karchive/src/kcompressiondevice.cpp
new file mode 100644
index 00000000000..56f2f47bef3
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kcompressiondevice.cpp
@@ -0,0 +1,519 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000 David Faure 
+   SPDX-FileCopyrightText: 2011 Mario Bensi 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "kcompressiondevice.h"
+#include "kcompressiondevice_p.h"
+#include "kfilterbase.h"
+#include "loggingcategory.h"
+#include "kgzipfilter.h"
+#include "knonefilter.h"
+
+#include "config-compression.h"
+
+#if HAVE_BZIP2_SUPPORT
+#include "kbzip2filter.h"
+#endif
+#if HAVE_XZ_SUPPORT
+#include "kxzfilter.h"
+#endif
+#if HAVE_ZSTD_SUPPORT
+#include "kzstdfilter.h"
+#endif
+
+#include 
+#include 
+#include 
+
+#include 
+#include  // for EOF
+#include 
+
+class KCompressionDevicePrivate
+{
+public:
+    KCompressionDevicePrivate(KCompressionDevice *qq)
+        : bNeedHeader(true)
+        , bSkipHeaders(false)
+        , bOpenedUnderlyingDevice(false)
+        , type(KCompressionDevice::None)
+        , errorCode(QFileDevice::NoError)
+        , deviceReadPos(0)
+        , q(qq)
+    {
+    }
+
+    void propagateErrorCode();
+
+    bool bNeedHeader;
+    bool bSkipHeaders;
+    bool bOpenedUnderlyingDevice;
+    QByteArray buffer; // Used as 'input buffer' when reading, as 'output buffer' when writing
+    QByteArray origFileName;
+    KFilterBase::Result result;
+    KFilterBase *filter;
+    KCompressionDevice::CompressionType type;
+    QFileDevice::FileError errorCode;
+    qint64 deviceReadPos;
+    KCompressionDevice *q;
+};
+
+void KCompressionDevicePrivate::propagateErrorCode()
+{
+    QIODevice *dev = filter->device();
+    if (QFileDevice *fileDev = qobject_cast(dev)) {
+        if (fileDev->error() != QFileDevice::NoError) {
+            errorCode = fileDev->error();
+            q->setErrorString(dev->errorString());
+        }
+    }
+    // ... we have no generic way to propagate errors from other kinds of iodevices. Sucks, heh? :(
+}
+
+static KCompressionDevice::CompressionType findCompressionByFileName(const QString &fileName)
+{
+    if (fileName.endsWith(QLatin1String(".gz"), Qt::CaseInsensitive)) {
+        return KCompressionDevice::GZip;
+    }
+#if HAVE_BZIP2_SUPPORT
+    if (fileName.endsWith(QLatin1String(".bz2"), Qt::CaseInsensitive)) {
+        return KCompressionDevice::BZip2;
+    }
+#endif
+#if HAVE_XZ_SUPPORT
+    if (fileName.endsWith(QLatin1String(".lzma"), Qt::CaseInsensitive) || fileName.endsWith(QLatin1String(".xz"), Qt::CaseInsensitive)) {
+        return KCompressionDevice::Xz;
+    }
+#endif
+#if HAVE_ZSTD_SUPPORT
+    if (fileName.endsWith(QLatin1String(".zst"), Qt::CaseInsensitive)) {
+        return KCompressionDevice::Zstd;
+    }
+#endif
+    else {
+        // not a warning, since this is called often with other MIME types (see #88574)...
+        // maybe we can avoid that though?
+        // qCDebug(KArchiveLog) << "findCompressionByFileName : no compression found for " << fileName;
+    }
+
+    return KCompressionDevice::None;
+}
+
+KCompressionDevice::CompressionType KCompressionDevice::compressionTypeForMimeType(const QString &mimeType)
+{
+    if (mimeType == QLatin1String("application/gzip") //
+        || mimeType == QLatin1String("application/x-gzip") // legacy name, kept for compatibility
+    ) {
+        return KCompressionDevice::GZip;
+    }
+#if HAVE_BZIP2_SUPPORT
+    if (mimeType == QLatin1String("application/x-bzip") //
+        || mimeType == QLatin1String("application/x-bzip2") // old name, kept for compatibility
+    ) {
+        return KCompressionDevice::BZip2;
+    }
+#endif
+#if HAVE_XZ_SUPPORT
+    if (mimeType == QLatin1String("application/x-lzma") // legacy name, still used
+        || mimeType == QLatin1String("application/x-xz") // current naming
+    ) {
+        return KCompressionDevice::Xz;
+    }
+#endif
+#if HAVE_ZSTD_SUPPORT
+    if (mimeType == QLatin1String("application/zstd")) {
+        return KCompressionDevice::Zstd;
+    }
+#endif
+    QMimeDatabase db;
+    const QMimeType mime = db.mimeTypeForName(mimeType);
+    if (mime.isValid()) {
+        // use legacy MIME type for now, see comment in impl. of KTar(const QString &, const QString &_mimetype)
+        if (mime.inherits(QStringLiteral("application/x-gzip"))) {
+            return KCompressionDevice::GZip;
+        }
+#if HAVE_BZIP2_SUPPORT
+        if (mime.inherits(QStringLiteral("application/x-bzip"))) {
+            return KCompressionDevice::BZip2;
+        }
+#endif
+#if HAVE_XZ_SUPPORT
+        if (mime.inherits(QStringLiteral("application/x-lzma"))) {
+            return KCompressionDevice::Xz;
+        }
+
+        if (mime.inherits(QStringLiteral("application/x-xz"))) {
+            return KCompressionDevice::Xz;
+        }
+#endif
+    }
+
+    // not a warning, since this is called often with other MIME types (see #88574)...
+    // maybe we can avoid that though?
+    // qCDebug(KArchiveLog) << "no compression found for" << mimeType;
+    return KCompressionDevice::None;
+}
+
+KFilterBase *KCompressionDevice::filterForCompressionType(KCompressionDevice::CompressionType type)
+{
+    switch (type) {
+    case KCompressionDevice::GZip:
+        return new KGzipFilter;
+    case KCompressionDevice::BZip2:
+#if HAVE_BZIP2_SUPPORT
+        return new KBzip2Filter;
+#else
+        return nullptr;
+#endif
+    case KCompressionDevice::Xz:
+#if HAVE_XZ_SUPPORT
+        return new KXzFilter;
+#else
+        return nullptr;
+#endif
+    case KCompressionDevice::None:
+        return new KNoneFilter;
+    case KCompressionDevice::Zstd:
+#if HAVE_ZSTD_SUPPORT
+        return new KZstdFilter;
+#else
+        return nullptr;
+#endif
+    }
+    return nullptr;
+}
+
+KCompressionDevice::KCompressionDevice(QIODevice *inputDevice, bool autoDeleteInputDevice, CompressionType type)
+    : d(new KCompressionDevicePrivate(this))
+{
+    assert(inputDevice);
+    d->filter = filterForCompressionType(type);
+    if (d->filter) {
+        d->type = type;
+        d->filter->setDevice(inputDevice, autoDeleteInputDevice);
+    }
+}
+
+KCompressionDevice::KCompressionDevice(const QString &fileName, CompressionType type)
+    : d(new KCompressionDevicePrivate(this))
+{
+    QFile *f = new QFile(fileName);
+    d->filter = filterForCompressionType(type);
+    if (d->filter) {
+        d->type = type;
+        d->filter->setDevice(f, true);
+    } else {
+        delete f;
+    }
+}
+
+KCompressionDevice::KCompressionDevice(const QString &fileName)
+    : KCompressionDevice(fileName, findCompressionByFileName(fileName))
+{
+}
+
+KCompressionDevice::~KCompressionDevice()
+{
+    if (isOpen()) {
+        close();
+    }
+    delete d->filter;
+    delete d;
+}
+
+KCompressionDevice::CompressionType KCompressionDevice::compressionType() const
+{
+    return d->type;
+}
+
+bool KCompressionDevice::open(QIODevice::OpenMode mode)
+{
+    if (isOpen()) {
+        // qCWarning(KArchiveLog) << "KCompressionDevice::open: device is already open";
+        return true; // QFile returns false, but well, the device -is- open...
+    }
+    if (!d->filter) {
+        return false;
+    }
+    d->bOpenedUnderlyingDevice = false;
+    // qCDebug(KArchiveLog) << mode;
+    if (mode == QIODevice::ReadOnly) {
+        d->buffer.resize(0);
+    } else {
+        d->buffer.resize(BUFFER_SIZE);
+        d->filter->setOutBuffer(d->buffer.data(), d->buffer.size());
+    }
+    if (!d->filter->device()->isOpen()) {
+        if (!d->filter->device()->open(mode)) {
+            // qCWarning(KArchiveLog) << "KCompressionDevice::open: Couldn't open underlying device";
+            d->propagateErrorCode();
+            return false;
+        }
+        d->bOpenedUnderlyingDevice = true;
+    }
+    d->bNeedHeader = !d->bSkipHeaders;
+    d->filter->setFilterFlags(d->bSkipHeaders ? KFilterBase::NoHeaders : KFilterBase::WithHeaders);
+    if (!d->filter->init(mode & ~QIODevice::Truncate)) {
+        return false;
+    }
+    d->result = KFilterBase::Ok;
+    setOpenMode(mode);
+    return true;
+}
+
+void KCompressionDevice::close()
+{
+    if (!isOpen()) {
+        return;
+    }
+    if (d->filter->mode() == QIODevice::WriteOnly && d->errorCode == QFileDevice::NoError) {
+        write(nullptr, 0); // finish writing
+    }
+    // qCDebug(KArchiveLog) << "Calling terminate().";
+
+    if (!d->filter->terminate()) {
+        // qCWarning(KArchiveLog) << "KCompressionDevice::close: terminate returned an error";
+        d->errorCode = QFileDevice::UnspecifiedError;
+    }
+    if (d->bOpenedUnderlyingDevice) {
+        QIODevice *dev = d->filter->device();
+        dev->close();
+        d->propagateErrorCode();
+    }
+    setOpenMode(QIODevice::NotOpen);
+}
+
+QFileDevice::FileError KCompressionDevice::error() const
+{
+    return d->errorCode;
+}
+
+bool KCompressionDevice::seek(qint64 pos)
+{
+    if (d->deviceReadPos == pos) {
+        return QIODevice::seek(pos);
+    }
+
+    // qCDebug(KArchiveLog) << "seek(" << pos << ") called, current pos=" << QIODevice::pos();
+
+    Q_ASSERT(d->filter->mode() == QIODevice::ReadOnly);
+
+    if (pos == 0) {
+        if (!QIODevice::seek(pos)) {
+            return false;
+        }
+
+        // We can forget about the cached data
+        d->bNeedHeader = !d->bSkipHeaders;
+        d->result = KFilterBase::Ok;
+        d->filter->setInBuffer(nullptr, 0);
+        d->filter->reset();
+        d->deviceReadPos = 0;
+        return d->filter->device()->reset();
+    }
+
+    qint64 bytesToRead;
+    if (d->deviceReadPos < pos) { // we can start from here
+        bytesToRead = pos - d->deviceReadPos;
+        // Since we're going to do a read() below
+        // we need to reset the internal QIODevice pos to the real position we are
+        // so that after read() we are indeed pointing to the pos seek
+        // asked us to be in
+        if (!QIODevice::seek(d->deviceReadPos)) {
+            return false;
+        }
+    } else {
+        // we have to start from 0 ! Ugly and slow, but better than the previous
+        // solution (KTarGz was allocating everything into memory)
+        if (!seek(0)) { // recursive
+            return false;
+        }
+        bytesToRead = pos;
+    }
+
+    // qCDebug(KArchiveLog) << "reading " << bytesToRead << " dummy bytes";
+    QByteArray dummy(qMin(bytesToRead, qint64(SEEK_BUFFER_SIZE)), 0);
+    while (bytesToRead > 0) {
+        const qint64 bytesToReadThisTime = qMin(bytesToRead, qint64(dummy.size()));
+        const bool result = (read(dummy.data(), bytesToReadThisTime) == bytesToReadThisTime);
+        if (!result) {
+            return false;
+        }
+        bytesToRead -= bytesToReadThisTime;
+    }
+    return true;
+}
+
+bool KCompressionDevice::atEnd() const
+{
+    return (d->type == KCompressionDevice::None || d->result == KFilterBase::End) //
+        && QIODevice::atEnd() // take QIODevice's internal buffer into account
+        && d->filter->device()->atEnd();
+}
+
+qint64 KCompressionDevice::readData(char *data, qint64 maxlen)
+{
+    Q_ASSERT(d->filter->mode() == QIODevice::ReadOnly);
+    // qCDebug(KArchiveLog) << "maxlen=" << maxlen;
+    KFilterBase *filter = d->filter;
+
+    uint dataReceived = 0;
+
+    // We came to the end of the stream
+    if (d->result == KFilterBase::End) {
+        return dataReceived;
+    }
+
+    // If we had an error, return -1.
+    if (d->result != KFilterBase::Ok) {
+        return -1;
+    }
+
+    qint64 availOut = maxlen;
+    filter->setOutBuffer(data, maxlen);
+
+    while (dataReceived < maxlen) {
+        if (filter->inBufferEmpty()) {
+            // Not sure about the best size to set there.
+            // For sure, it should be bigger than the header size (see comment in readHeader)
+            d->buffer.resize(BUFFER_SIZE);
+            // Request data from underlying device
+            int size = filter->device()->read(d->buffer.data(), d->buffer.size());
+            // qCDebug(KArchiveLog) << "got" << size << "bytes from device";
+            if (size) {
+                filter->setInBuffer(d->buffer.data(), size);
+            } else {
+                // Not enough data available in underlying device for now
+                break;
+            }
+        }
+        if (d->bNeedHeader) {
+            (void)filter->readHeader();
+            d->bNeedHeader = false;
+        }
+
+        d->result = filter->uncompress();
+
+        if (d->result == KFilterBase::Error) {
+            // qCWarning(KArchiveLog) << "KCompressionDevice: Error when uncompressing data";
+            break;
+        }
+
+        // We got that much data since the last time we went here
+        uint outReceived = availOut - filter->outBufferAvailable();
+        // qCDebug(KArchiveLog) << "avail_out = " << filter->outBufferAvailable() << " result=" << d->result << " outReceived=" << outReceived;
+        if (availOut < uint(filter->outBufferAvailable())) {
+            // qCWarning(KArchiveLog) << " last availOut " << availOut << " smaller than new avail_out=" << filter->outBufferAvailable() << " !";
+        }
+
+        dataReceived += outReceived;
+        data += outReceived;
+        availOut = maxlen - dataReceived;
+        if (d->result == KFilterBase::End) {
+            // We're actually at the end, no more data to check
+            if (filter->device()->atEnd()) {
+                break;
+            }
+
+            // Still not done, re-init and try again
+            filter->init(filter->mode());
+        }
+        filter->setOutBuffer(data, availOut);
+    }
+
+    d->deviceReadPos += dataReceived;
+    return dataReceived;
+}
+
+qint64 KCompressionDevice::writeData(const char *data /*0 to finish*/, qint64 len)
+{
+    KFilterBase *filter = d->filter;
+    Q_ASSERT(filter->mode() == QIODevice::WriteOnly);
+    // If we had an error, return 0.
+    if (d->result != KFilterBase::Ok) {
+        return 0;
+    }
+
+    bool finish = (data == nullptr);
+    if (!finish) {
+        filter->setInBuffer(data, len);
+        if (d->bNeedHeader) {
+            (void)filter->writeHeader(d->origFileName);
+            d->bNeedHeader = false;
+        }
+    }
+
+    uint dataWritten = 0;
+    uint availIn = len;
+    while (dataWritten < len || finish) {
+        d->result = filter->compress(finish);
+
+        if (d->result == KFilterBase::Error) {
+            // qCWarning(KArchiveLog) << "KCompressionDevice: Error when compressing data";
+            // What to do ?
+            break;
+        }
+
+        // Wrote everything ?
+        if (filter->inBufferEmpty() || (d->result == KFilterBase::End)) {
+            // We got that much data since the last time we went here
+            uint wrote = availIn - filter->inBufferAvailable();
+
+            // qCDebug(KArchiveLog) << " Wrote everything for now. avail_in=" << filter->inBufferAvailable() << "result=" << d->result << "wrote=" << wrote;
+
+            // Move on in the input buffer
+            data += wrote;
+            dataWritten += wrote;
+
+            availIn = len - dataWritten;
+            // qCDebug(KArchiveLog) << " availIn=" << availIn << "dataWritten=" << dataWritten << "pos=" << pos();
+            if (availIn > 0) {
+                filter->setInBuffer(data, availIn);
+            }
+        }
+
+        if (filter->outBufferFull() || (d->result == KFilterBase::End) || finish) {
+            // qCDebug(KArchiveLog) << " writing to underlying. avail_out=" << filter->outBufferAvailable();
+            int towrite = d->buffer.size() - filter->outBufferAvailable();
+            if (towrite > 0) {
+                // Write compressed data to underlying device
+                int size = filter->device()->write(d->buffer.data(), towrite);
+                if (size != towrite) {
+                    // qCWarning(KArchiveLog) << "KCompressionDevice::write. Could only write " << size << " out of " << towrite << " bytes";
+                    d->errorCode = QFileDevice::WriteError;
+                    setErrorString(tr("Could not write. Partition full?"));
+                    return 0; // indicate an error
+                }
+                // qCDebug(KArchiveLog) << " wrote " << size << " bytes";
+            }
+            if (d->result == KFilterBase::End) {
+                Q_ASSERT(finish); // hopefully we don't get end before finishing
+                break;
+            }
+            d->buffer.resize(BUFFER_SIZE);
+            filter->setOutBuffer(d->buffer.data(), d->buffer.size());
+        }
+    }
+
+    return dataWritten;
+}
+
+void KCompressionDevice::setOrigFileName(const QByteArray &fileName)
+{
+    d->origFileName = fileName;
+}
+
+void KCompressionDevice::setSkipHeaders()
+{
+    d->bSkipHeaders = true;
+}
+
+KFilterBase *KCompressionDevice::filterBase()
+{
+    return d->filter;
+}
+
+#include "moc_kcompressiondevice.cpp"
diff --git a/src/libs/3rdparty/karchive/src/kcompressiondevice.h b/src/libs/3rdparty/karchive/src/kcompressiondevice.h
new file mode 100644
index 00000000000..218f2d51234
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kcompressiondevice.h
@@ -0,0 +1,146 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000 David Faure 
+   SPDX-FileCopyrightText: 2011 Mario Bensi 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+#ifndef __kcompressiondevice_h
+#define __kcompressiondevice_h
+
+#include "karchive_export.h"
+
+#include 
+#include 
+#include 
+#include 
+
+class KCompressionDevicePrivate;
+
+class KFilterBase;
+
+/**
+ * @class KCompressionDevice kcompressiondevice.h KCompressionDevice
+ *
+ * A class for reading and writing compressed data onto a device
+ * (e.g. file, but other usages are possible, like a buffer or a socket).
+ *
+ * Use this class to read/write compressed files.
+ */
+
+class KARCHIVE_EXPORT KCompressionDevice : public QIODevice // KF6 TODO: consider inheriting from QFileDevice, so apps can use error() generically ?
+{
+    Q_OBJECT
+public:
+    enum CompressionType {
+        GZip,
+        BZip2,
+        Xz,
+        None,
+        Zstd, ///< @since 5.82
+    };
+
+    /**
+     * Constructs a KCompressionDevice for a given CompressionType (e.g. GZip, BZip2 etc.).
+     * @param inputDevice input device.
+     * @param autoDeleteInputDevice if true, @p inputDevice will be deleted automatically
+     * @param type the CompressionType to use.
+     */
+    KCompressionDevice(QIODevice *inputDevice, bool autoDeleteInputDevice, CompressionType type);
+
+    /**
+     * Constructs a KCompressionDevice for a given CompressionType (e.g. GZip, BZip2 etc.).
+     * @param fileName the name of the file to filter.
+     * @param type the CompressionType to use.
+     */
+    KCompressionDevice(const QString &fileName, CompressionType type);
+
+    /**
+     * Constructs a KCompressionDevice for a given @p fileName.
+     * @param fileName the name of the file to filter.
+     * @since 5.85
+     */
+    explicit KCompressionDevice(const QString &fileName);
+
+    /**
+     * Destructs the KCompressionDevice.
+     * Calls close() if the filter device is still open.
+     */
+    ~KCompressionDevice() override;
+
+    /**
+     * The compression actually used by this device.
+     * If the support for the compression requested in the constructor
+     * is not available, then the device will use None.
+     */
+    CompressionType compressionType() const;
+
+    /**
+     * Open for reading or writing.
+     */
+    bool open(QIODevice::OpenMode mode) override;
+
+    /**
+     * Close after reading or writing.
+     */
+    void close() override;
+
+    /**
+     * For writing gzip compressed files only:
+     * set the name of the original file, to be used in the gzip header.
+     * @param fileName the name of the original file
+     */
+    void setOrigFileName(const QByteArray &fileName);
+
+    /**
+     * Call this let this device skip the gzip headers when reading/writing.
+     * This way KCompressionDevice (with gzip filter) can be used as a direct wrapper
+     * around zlib - this is used by KZip.
+     */
+    void setSkipHeaders();
+
+    /**
+     * That one can be quite slow, when going back. Use with care.
+     */
+    bool seek(qint64) override;
+
+    bool atEnd() const override;
+
+    /**
+     * Call this to create the appropriate filter for the CompressionType
+     * named @p type.
+     * @param type the type of the compression filter
+     * @return the filter for the @p type, or 0 if not found
+     */
+    static KFilterBase *filterForCompressionType(CompressionType type);
+
+    /**
+     * Returns the compression type for the given MIME type, if possible. Otherwise returns None.
+     * This handles simple cases like application/gzip, but also application/x-compressed-tar, and inheritance.
+     * @since 5.85
+     */
+    static CompressionType compressionTypeForMimeType(const QString &mimetype);
+
+    /**
+     * Returns the error code from the last failing operation.
+     * This is especially useful after calling close(), which unfortunately returns void
+     * (see https://bugreports.qt.io/browse/QTBUG-70033), to see if the flushing done by close
+     * was able to write all the data to disk.
+     */
+    QFileDevice::FileError error() const;
+
+protected:
+    friend class K7Zip;
+
+    qint64 readData(char *data, qint64 maxlen) override;
+    qint64 writeData(const char *data, qint64 len) override;
+
+    KFilterBase *filterBase();
+
+private:
+    friend KCompressionDevicePrivate;
+    KCompressionDevicePrivate *const d;
+};
+
+Q_DECLARE_METATYPE(KCompressionDevice::CompressionType)
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/kcompressiondevice_p.h b/src/libs/3rdparty/karchive/src/kcompressiondevice_p.h
new file mode 100644
index 00000000000..dda5f98276e
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kcompressiondevice_p.h
@@ -0,0 +1,13 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000 David Faure 
+   SPDX-FileCopyrightText: 2011 Mario Bensi 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+#ifndef __kcompressiondevice_p_h
+#define __kcompressiondevice_p_h
+
+#define BUFFER_SIZE 8 * 1024
+#define SEEK_BUFFER_SIZE 3 * BUFFER_SIZE
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/kfilterbase.cpp b/src/libs/3rdparty/karchive/src/kfilterbase.cpp
new file mode 100644
index 00000000000..dc7bea840e7
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kfilterbase.cpp
@@ -0,0 +1,81 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000-2005 David Faure 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "kfilterbase.h"
+
+#include 
+
+class KFilterBasePrivate
+{
+public:
+    KFilterBasePrivate()
+        : m_flags(KFilterBase::WithHeaders)
+        , m_dev(nullptr)
+        , m_bAutoDel(false)
+    {
+    }
+    KFilterBase::FilterFlags m_flags;
+    QIODevice *m_dev;
+    bool m_bAutoDel;
+};
+
+KFilterBase::KFilterBase()
+    : d(new KFilterBasePrivate)
+{
+}
+
+KFilterBase::~KFilterBase()
+{
+    if (d->m_bAutoDel) {
+        delete d->m_dev;
+    }
+    delete d;
+}
+
+void KFilterBase::setDevice(QIODevice *dev, bool autodelete)
+{
+    d->m_dev = dev;
+    d->m_bAutoDel = autodelete;
+}
+
+QIODevice *KFilterBase::device()
+{
+    return d->m_dev;
+}
+
+bool KFilterBase::inBufferEmpty() const
+{
+    return inBufferAvailable() == 0;
+}
+
+bool KFilterBase::outBufferFull() const
+{
+    return outBufferAvailable() == 0;
+}
+
+bool KFilterBase::terminate()
+{
+    return true;
+}
+
+void KFilterBase::reset()
+{
+}
+
+void KFilterBase::setFilterFlags(FilterFlags flags)
+{
+    d->m_flags = flags;
+}
+
+KFilterBase::FilterFlags KFilterBase::filterFlags() const
+{
+    return d->m_flags;
+}
+
+void KFilterBase::virtual_hook(int, void *)
+{
+    /*BASE::virtual_hook( id, data );*/
+}
diff --git a/src/libs/3rdparty/karchive/src/kfilterbase.h b/src/libs/3rdparty/karchive/src/kfilterbase.h
new file mode 100644
index 00000000000..bf0e7883700
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kfilterbase.h
@@ -0,0 +1,109 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000 David Faure 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef __kfilterbase__h
+#define __kfilterbase__h
+
+#include "karchive_export.h"
+
+#include 
+#include 
+class KFilterBasePrivate;
+
+class QIODevice;
+
+/**
+ * @class KFilterBase kfilterbase.h KFilterBase
+ *
+ * This is the base class for compression filters
+ * such as gzip and bzip2. It's pretty much internal.
+ * Don't use directly, use KCompressionDevice instead.
+ * @internal
+ */
+class KARCHIVE_EXPORT KFilterBase
+{
+public:
+    KFilterBase();
+    virtual ~KFilterBase();
+
+    /**
+     * Sets the device on which the filter will work
+     * @param dev the device on which the filter will work
+     * @param autodelete if true, @p dev is deleted when the filter is deleted
+     */
+    void setDevice(QIODevice *dev, bool autodelete = false);
+    // Note that this isn't in the constructor, because of KLibFactory::create,
+    // but it should be called before using the filterbase !
+
+    /**
+     * Returns the device on which the filter will work.
+     * @returns the device on which the filter will work
+     */
+    QIODevice *device();
+    /** \internal */
+    virtual bool init(int mode) = 0;
+    /** \internal */
+    virtual int mode() const = 0;
+    /** \internal */
+    virtual bool terminate();
+    /** \internal */
+    virtual void reset();
+    /** \internal */
+    virtual bool readHeader() = 0;
+    /** \internal */
+    virtual bool writeHeader(const QByteArray &filename) = 0;
+    /** \internal */
+    virtual void setOutBuffer(char *data, uint maxlen) = 0;
+    /** \internal */
+    virtual void setInBuffer(const char *data, uint size) = 0;
+    /** \internal */
+    virtual bool inBufferEmpty() const;
+    /** \internal */
+    virtual int inBufferAvailable() const = 0;
+    /** \internal */
+    virtual bool outBufferFull() const;
+    /** \internal */
+    virtual int outBufferAvailable() const = 0;
+
+    /** \internal */
+    enum Result {
+        Ok,
+        End,
+        Error,
+    };
+    /** \internal */
+    virtual Result uncompress() = 0;
+    /** \internal */
+    virtual Result compress(bool finish) = 0;
+
+    /**
+     * \internal
+     * \since 4.3
+     */
+    enum FilterFlags {
+        NoHeaders = 0,
+        WithHeaders = 1,
+        ZlibHeaders = 2, // only use for gzip compression
+    };
+    /**
+     * \internal
+     * \since 4.3
+     */
+    void setFilterFlags(FilterFlags flags);
+    FilterFlags filterFlags() const;
+
+protected:
+    /** Virtual hook, used to add new "virtual" functions while maintaining
+        binary compatibility. Unused in this class.
+    */
+    virtual void virtual_hook(int id, void *data);
+
+private:
+    Q_DISABLE_COPY(KFilterBase)
+    KFilterBasePrivate *const d;
+};
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/kgzipfilter.cpp b/src/libs/3rdparty/karchive/src/kgzipfilter.cpp
new file mode 100644
index 00000000000..c7623f7ba57
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kgzipfilter.cpp
@@ -0,0 +1,366 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000-2005 David Faure 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "kgzipfilter.h"
+#include "loggingcategory.h"
+
+#include 
+#include 
+
+#include 
+#include 
+
+/* gzip flag byte */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+
+// #define DEBUG_GZIP
+
+class Q_DECL_HIDDEN KGzipFilter::Private
+{
+public:
+    Private()
+        : headerWritten(false)
+        , footerWritten(false)
+        , compressed(false)
+        , mode(0)
+        , crc(0)
+        , isInitialized(false)
+    {
+        zStream.zalloc = static_cast(nullptr);
+        zStream.zfree = static_cast(nullptr);
+        zStream.opaque = static_cast(nullptr);
+    }
+
+    z_stream zStream;
+    bool headerWritten;
+    bool footerWritten;
+    bool compressed;
+    int mode;
+    ulong crc;
+    bool isInitialized;
+};
+
+KGzipFilter::KGzipFilter()
+    : d(new Private)
+{
+}
+
+KGzipFilter::~KGzipFilter()
+{
+    delete d;
+}
+
+bool KGzipFilter::init(int mode)
+{
+    switch (filterFlags()) {
+    case NoHeaders:
+        return init(mode, RawDeflate);
+    case WithHeaders:
+        return init(mode, GZipHeader);
+    case ZlibHeaders:
+        return init(mode, ZlibHeader);
+    }
+    return false;
+}
+
+bool KGzipFilter::init(int mode, Flag flag)
+{
+    if (d->isInitialized) {
+        terminate();
+    }
+    d->zStream.next_in = Z_NULL;
+    d->zStream.avail_in = 0;
+    if (mode == QIODevice::ReadOnly) {
+        const int windowBits = (flag == RawDeflate) ? -MAX_WBITS /*no zlib header*/
+            : (flag == GZipHeader)                  ? MAX_WBITS + 32 /* auto-detect and eat gzip header */
+                                                    : MAX_WBITS /*zlib header*/;
+        const int result = inflateInit2(&d->zStream, windowBits);
+        if (result != Z_OK) {
+            // qCDebug(KArchiveLog) << "inflateInit2 returned " << result;
+            return false;
+        }
+    } else if (mode == QIODevice::WriteOnly) {
+        int result = deflateInit2(&d->zStream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY); // same here
+        if (result != Z_OK) {
+            // qCDebug(KArchiveLog) << "deflateInit returned " << result;
+            return false;
+        }
+    } else {
+        // qCWarning(KArchiveLog) << "KGzipFilter: Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
+        return false;
+    }
+    d->mode = mode;
+    d->compressed = true;
+    d->headerWritten = false;
+    d->footerWritten = false;
+    d->isInitialized = true;
+    return true;
+}
+
+int KGzipFilter::mode() const
+{
+    return d->mode;
+}
+
+bool KGzipFilter::terminate()
+{
+    if (d->mode == QIODevice::ReadOnly) {
+        int result = inflateEnd(&d->zStream);
+        if (result != Z_OK) {
+            // qCDebug(KArchiveLog) << "inflateEnd returned " << result;
+            return false;
+        }
+    } else if (d->mode == QIODevice::WriteOnly) {
+        int result = deflateEnd(&d->zStream);
+        if (result != Z_OK) {
+            // qCDebug(KArchiveLog) << "deflateEnd returned " << result;
+            return false;
+        }
+    }
+    d->isInitialized = false;
+    return true;
+}
+
+void KGzipFilter::reset()
+{
+    if (d->mode == QIODevice::ReadOnly) {
+        int result = inflateReset(&d->zStream);
+        if (result != Z_OK) {
+            // qCDebug(KArchiveLog) << "inflateReset returned " << result;
+            // TODO return false
+        }
+    } else if (d->mode == QIODevice::WriteOnly) {
+        int result = deflateReset(&d->zStream);
+        if (result != Z_OK) {
+            // qCDebug(KArchiveLog) << "deflateReset returned " << result;
+            // TODO return false
+        }
+        d->headerWritten = false;
+        d->footerWritten = false;
+    }
+}
+
+bool KGzipFilter::readHeader()
+{
+    // We now rely on zlib to read the full header (see the MAX_WBITS + 32 in init).
+    // We just use this method to check if the data is actually compressed.
+
+#ifdef DEBUG_GZIP
+    qCDebug(KArchiveLog) << "avail=" << d->zStream.avail_in;
+#endif
+    // Assume not compressed until we see a gzip header
+    d->compressed = false;
+    const Bytef *p = d->zStream.next_in;
+    int i = d->zStream.avail_in;
+    if ((i -= 10) < 0) {
+        return false; // Need at least 10 bytes
+    }
+#ifdef DEBUG_GZIP
+    qCDebug(KArchiveLog) << "first byte is " << QString::number(*p, 16);
+#endif
+    if (*p++ != 0x1f) {
+        return false; // GZip magic
+    }
+#ifdef DEBUG_GZIP
+    qCDebug(KArchiveLog) << "second byte is " << QString::number(*p, 16);
+#endif
+    if (*p++ != 0x8b) {
+        return false;
+    }
+
+    d->compressed = true;
+#ifdef DEBUG_GZIP
+    qCDebug(KArchiveLog) << "header OK";
+#endif
+    return true;
+}
+
+/* Output a 16 bit value, lsb first */
+#define put_short(w)                                                                                                                                           \
+    *p++ = uchar((w)&0xff);                                                                                                                                    \
+    *p++ = uchar(ushort(w) >> 8);
+
+/* Output a 32 bit value to the bit stream, lsb first */
+#define put_long(n)                                                                                                                                            \
+    put_short((n)&0xffff);                                                                                                                                     \
+    put_short((ulong(n)) >> 16);
+
+bool KGzipFilter::writeHeader(const QByteArray &fileName)
+{
+    Bytef *p = d->zStream.next_out;
+    int i = d->zStream.avail_out;
+    *p++ = 0x1f;
+    *p++ = 0x8b;
+    *p++ = Z_DEFLATED;
+    *p++ = ORIG_NAME;
+    put_long(time(nullptr)); // Modification time (in unix format)
+    *p++ = 0; // Extra flags (2=max compress, 4=fastest compress)
+    *p++ = 3; // Unix
+
+    uint len = fileName.length();
+    for (uint j = 0; j < len; ++j) {
+        *p++ = fileName[j];
+    }
+    *p++ = 0;
+    int headerSize = p - d->zStream.next_out;
+    i -= headerSize;
+    Q_ASSERT(i > 0);
+    d->crc = crc32(0L, nullptr, 0);
+    d->zStream.next_out = p;
+    d->zStream.avail_out = i;
+    d->headerWritten = true;
+    return true;
+}
+
+void KGzipFilter::writeFooter()
+{
+    Q_ASSERT(d->headerWritten);
+    Q_ASSERT(!d->footerWritten);
+    Bytef *p = d->zStream.next_out;
+    int i = d->zStream.avail_out;
+    // qCDebug(KArchiveLog) << "avail_out=" << i << "writing CRC=" << QString::number(d->crc, 16) << "at p=" << p;
+    put_long(d->crc);
+    // qCDebug(KArchiveLog) << "writing totalin=" << d->zStream.total_in << "at p=" << p;
+    put_long(d->zStream.total_in);
+    i -= p - d->zStream.next_out;
+    d->zStream.next_out = p;
+    d->zStream.avail_out = i;
+    d->footerWritten = true;
+}
+
+void KGzipFilter::setOutBuffer(char *data, uint maxlen)
+{
+    d->zStream.avail_out = maxlen;
+    d->zStream.next_out = reinterpret_cast(data);
+}
+void KGzipFilter::setInBuffer(const char *data, uint size)
+{
+#ifdef DEBUG_GZIP
+    qCDebug(KArchiveLog) << "avail_in=" << size;
+#endif
+    d->zStream.avail_in = size;
+    d->zStream.next_in = reinterpret_cast(const_cast(data));
+}
+int KGzipFilter::inBufferAvailable() const
+{
+    return d->zStream.avail_in;
+}
+int KGzipFilter::outBufferAvailable() const
+{
+    return d->zStream.avail_out;
+}
+
+KGzipFilter::Result KGzipFilter::uncompress_noop()
+{
+    // I'm not sure that we really need support for that (uncompressed streams),
+    // but why not, it can't hurt to have it. One case I can think of is someone
+    // naming a tar file "blah.tar.gz" :-)
+    if (d->zStream.avail_in > 0) {
+        int n = (d->zStream.avail_in < d->zStream.avail_out) ? d->zStream.avail_in : d->zStream.avail_out;
+        memcpy(d->zStream.next_out, d->zStream.next_in, n);
+        d->zStream.avail_out -= n;
+        d->zStream.next_in += n;
+        d->zStream.avail_in -= n;
+        return KFilterBase::Ok;
+    } else {
+        return KFilterBase::End;
+    }
+}
+
+KGzipFilter::Result KGzipFilter::uncompress()
+{
+#ifndef NDEBUG
+    if (d->mode == 0) {
+        // qCWarning(KArchiveLog) << "mode==0; KGzipFilter::init was not called!";
+        return KFilterBase::Error;
+    } else if (d->mode == QIODevice::WriteOnly) {
+        // qCWarning(KArchiveLog) << "uncompress called but the filter was opened for writing!";
+        return KFilterBase::Error;
+    }
+    Q_ASSERT(d->mode == QIODevice::ReadOnly);
+#endif
+
+    if (!d->compressed) {
+        return uncompress_noop();
+    }
+
+#ifdef DEBUG_GZIP
+    qCDebug(KArchiveLog) << "Calling inflate with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
+    qCDebug(KArchiveLog) << "    next_in=" << d->zStream.next_in;
+#endif
+
+    while (d->zStream.avail_in > 0) {
+        int result = inflate(&d->zStream, Z_SYNC_FLUSH);
+
+#ifdef DEBUG_GZIP
+        qCDebug(KArchiveLog) << " -> inflate returned " << result;
+        qCDebug(KArchiveLog) << " now avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
+        qCDebug(KArchiveLog) << "     next_in=" << d->zStream.next_in;
+#endif
+
+        if (result == Z_OK) {
+            return KFilterBase::Ok;
+        }
+
+        // We can't handle any other results
+        if (result != Z_STREAM_END) {
+            return KFilterBase::Error;
+        }
+
+        // It really was the end
+        if (d->zStream.avail_in == 0) {
+            return KFilterBase::End;
+        }
+
+        // Store before resetting
+        Bytef *data = d->zStream.next_in; // This is increased appropriately by zlib beforehand
+        uInt size = d->zStream.avail_in;
+
+        // Reset the stream, if that fails we assume we're at the end
+        if (!init(d->mode)) {
+            return KFilterBase::End;
+        }
+
+        // Reset the data to where we left off
+        d->zStream.next_in = data;
+        d->zStream.avail_in = size;
+    }
+
+    return KFilterBase::End;
+}
+
+KGzipFilter::Result KGzipFilter::compress(bool finish)
+{
+    Q_ASSERT(d->compressed);
+    Q_ASSERT(d->mode == QIODevice::WriteOnly);
+
+    const Bytef *p = d->zStream.next_in;
+    ulong len = d->zStream.avail_in;
+#ifdef DEBUG_GZIP
+    qCDebug(KArchiveLog) << "  calling deflate with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
+#endif
+    const int result = deflate(&d->zStream, finish ? Z_FINISH : Z_NO_FLUSH);
+    if (result != Z_OK && result != Z_STREAM_END) {
+        // qCDebug(KArchiveLog) << "  deflate returned " << result;
+    }
+    if (d->headerWritten) {
+        // qCDebug(KArchiveLog) << "Computing CRC for the next " << len - d->zStream.avail_in << " bytes";
+        d->crc = crc32(d->crc, p, len - d->zStream.avail_in);
+    }
+    KGzipFilter::Result callerResult = result == Z_OK ? KFilterBase::Ok : (Z_STREAM_END ? KFilterBase::End : KFilterBase::Error);
+
+    if (result == Z_STREAM_END && d->headerWritten && !d->footerWritten) {
+        if (d->zStream.avail_out >= 8 /*footer size*/) {
+            // qCDebug(KArchiveLog) << "finished, write footer";
+            writeFooter();
+        } else {
+            // No room to write the footer (#157706/#188415), we'll have to do it on the next pass.
+            // qCDebug(KArchiveLog) << "finished, but no room for footer yet";
+            callerResult = KFilterBase::Ok;
+        }
+    }
+    return callerResult;
+}
diff --git a/src/libs/3rdparty/karchive/src/kgzipfilter.h b/src/libs/3rdparty/karchive/src/kgzipfilter.h
new file mode 100644
index 00000000000..05e84d86f53
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kgzipfilter.h
@@ -0,0 +1,59 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000, 2009 David Faure 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef __kgzipfilter__h
+#define __kgzipfilter__h
+
+#include "kfilterbase.h"
+
+/**
+ * Internal class used by KCompressionDevice
+ *
+ * This header is not installed.
+ *
+ * @internal
+ */
+class KGzipFilter : public KFilterBase
+{
+public:
+    KGzipFilter();
+    ~KGzipFilter() override;
+
+    bool init(int mode) override;
+
+    // The top of zlib.h explains it: there are three cases.
+    // - Raw deflate, no header (e.g. inside a ZIP file)
+    // - Thin zlib header (1) (which is normally what HTTP calls "deflate" (2))
+    // - Gzip header, implemented here by readHeader
+    //
+    // (1) as written out by compress()/compress2()
+    // (2) see https://www.zlib.net/zlib_faq.html#faq39
+    enum Flag {
+        RawDeflate = 0, // raw deflate data
+        ZlibHeader = 1, // zlib headers (HTTP deflate)
+        GZipHeader = 2,
+    };
+    bool init(int mode, Flag flag); // for direct users of KGzipFilter
+    int mode() const override;
+    bool terminate() override;
+    void reset() override;
+    bool readHeader() override; // this is about the GZIP header
+    bool writeHeader(const QByteArray &fileName) override;
+    void writeFooter();
+    void setOutBuffer(char *data, uint maxlen) override;
+    void setInBuffer(const char *data, uint size) override;
+    int inBufferAvailable() const override;
+    int outBufferAvailable() const override;
+    Result uncompress() override;
+    Result compress(bool finish) override;
+
+private:
+    Result uncompress_noop();
+    class Private;
+    Private *const d;
+};
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/klimitediodevice.cpp b/src/libs/3rdparty/karchive/src/klimitediodevice.cpp
new file mode 100644
index 00000000000..d8b35b0257a
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/klimitediodevice.cpp
@@ -0,0 +1,73 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2001, 2002, 2007 David Faure 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "klimitediodevice_p.h"
+#include "loggingcategory.h"
+
+KLimitedIODevice::KLimitedIODevice(QIODevice *dev, qint64 start, qint64 length)
+    : m_dev(dev)
+    , m_start(start)
+    , m_length(length)
+{
+    // qCDebug(KArchiveLog) << "start=" << start << "length=" << length;
+    open(QIODevice::ReadOnly); // krazy:exclude=syscalls
+}
+
+bool KLimitedIODevice::open(QIODevice::OpenMode m)
+{
+    // qCDebug(KArchiveLog) << "m=" << m;
+    if (m & QIODevice::ReadOnly) {
+        /*bool ok = false;
+          if ( m_dev->isOpen() )
+          ok = ( m_dev->mode() == QIODevice::ReadOnly );
+          else
+          ok = m_dev->open( m );
+          if ( ok )*/
+        m_dev->seek(m_start); // No concurrent access !
+    } else {
+        // qCWarning(KArchiveLog) << "KLimitedIODevice::open only supports QIODevice::ReadOnly!";
+    }
+    setOpenMode(QIODevice::ReadOnly);
+    return true;
+}
+
+void KLimitedIODevice::close()
+{
+}
+
+qint64 KLimitedIODevice::size() const
+{
+    return m_length;
+}
+
+qint64 KLimitedIODevice::readData(char *data, qint64 maxlen)
+{
+    maxlen = qMin(maxlen, m_length - pos()); // Apply upper limit
+    return m_dev->read(data, maxlen);
+}
+
+bool KLimitedIODevice::seek(qint64 pos)
+{
+    Q_ASSERT(pos <= m_length);
+    pos = qMin(pos, m_length); // Apply upper limit
+    bool ret = m_dev->seek(m_start + pos);
+    if (ret) {
+        QIODevice::seek(pos);
+    }
+    return ret;
+}
+
+qint64 KLimitedIODevice::bytesAvailable() const
+{
+    return QIODevice::bytesAvailable();
+}
+
+bool KLimitedIODevice::isSequential() const
+{
+    return m_dev->isSequential();
+}
+
+#include "moc_klimitediodevice_p.cpp"
diff --git a/src/libs/3rdparty/karchive/src/klimitediodevice_p.h b/src/libs/3rdparty/karchive/src/klimitediodevice_p.h
new file mode 100644
index 00000000000..ca5db975d36
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/klimitediodevice_p.h
@@ -0,0 +1,58 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2001, 2002, 2007 David Faure 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef klimitediodevice_p_h
+#define klimitediodevice_p_h
+
+#include 
+#include 
+/**
+ * A readonly device that reads from an underlying device
+ * from a given point to another (e.g. to give access to a single
+ * file inside an archive).
+ * @author David Faure 
+ * @internal - used by KArchive
+ */
+class KLimitedIODevice : public QIODevice
+{
+    Q_OBJECT
+public:
+    /**
+     * Creates a new KLimitedIODevice.
+     * @param dev the underlying device, opened or not
+     * This device itself auto-opens (in readonly mode), no need to open it.
+     * @param start where to start reading (position in bytes)
+     * @param length the length of the data to read (in bytes)
+     */
+    KLimitedIODevice(QIODevice *dev, qint64 start, qint64 length);
+    ~KLimitedIODevice() override
+    {
+    }
+
+    bool isSequential() const override;
+
+    bool open(QIODevice::OpenMode m) override;
+    void close() override;
+
+    qint64 size() const override;
+
+    qint64 readData(char *data, qint64 maxlen) override;
+    qint64 writeData(const char *, qint64) override
+    {
+        return -1; // unsupported
+    }
+
+    // virtual qint64 pos() const { return m_dev->pos() - m_start; }
+    bool seek(qint64 pos) override;
+    qint64 bytesAvailable() const override;
+
+private:
+    QIODevice *m_dev;
+    qint64 m_start;
+    qint64 m_length;
+};
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/knonefilter.cpp b/src/libs/3rdparty/karchive/src/knonefilter.cpp
new file mode 100644
index 00000000000..b0fd8328dfc
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/knonefilter.cpp
@@ -0,0 +1,127 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2011 Mario Bensi 
+
+   Based on kbzip2filter:
+   SPDX-FileCopyrightText: 2000, 2009 David Faure 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "knonefilter.h"
+
+#include 
+
+class Q_DECL_HIDDEN KNoneFilter::Private
+{
+public:
+    Private()
+        : mode(0)
+        , avail_out(0)
+        , avail_in(0)
+        , next_in(nullptr)
+        , next_out(nullptr)
+    {
+    }
+
+    int mode;
+    int avail_out;
+    int avail_in;
+    const char *next_in;
+    char *next_out;
+};
+
+KNoneFilter::KNoneFilter()
+    : d(new Private)
+{
+}
+
+KNoneFilter::~KNoneFilter()
+{
+    delete d;
+}
+
+bool KNoneFilter::init(int mode)
+{
+    d->mode = mode;
+    return true;
+}
+
+int KNoneFilter::mode() const
+{
+    return d->mode;
+}
+
+bool KNoneFilter::terminate()
+{
+    return true;
+}
+
+void KNoneFilter::reset()
+{
+}
+
+bool KNoneFilter::readHeader()
+{
+    return true;
+}
+
+bool KNoneFilter::writeHeader(const QByteArray & /*fileName*/)
+{
+    return true;
+}
+
+void KNoneFilter::setOutBuffer(char *data, uint maxlen)
+{
+    d->avail_out = maxlen;
+    d->next_out = data;
+}
+
+void KNoneFilter::setInBuffer(const char *data, uint size)
+{
+    d->next_in = data;
+    d->avail_in = size;
+}
+
+int KNoneFilter::inBufferAvailable() const
+{
+    return d->avail_in;
+}
+
+int KNoneFilter::outBufferAvailable() const
+{
+    return d->avail_out;
+}
+
+KNoneFilter::Result KNoneFilter::uncompress()
+{
+#ifndef NDEBUG
+    if (d->mode != QIODevice::ReadOnly) {
+        return KFilterBase::Error;
+    }
+#endif
+    return copyData();
+}
+
+KNoneFilter::Result KNoneFilter::compress(bool finish)
+{
+    Q_ASSERT(d->mode == QIODevice::WriteOnly);
+    Q_UNUSED(finish);
+
+    return copyData();
+}
+
+KNoneFilter::Result KNoneFilter::copyData()
+{
+    Q_ASSERT(d->avail_out > 0);
+    if (d->avail_in > 0) {
+        const int n = qMin(d->avail_in, d->avail_out);
+        memcpy(d->next_out, d->next_in, n);
+        d->avail_out -= n;
+        d->next_in += n;
+        d->next_out += n;
+        d->avail_in -= n;
+        return KFilterBase::Ok;
+    } else {
+        return KFilterBase::End;
+    }
+}
diff --git a/src/libs/3rdparty/karchive/src/knonefilter.h b/src/libs/3rdparty/karchive/src/knonefilter.h
new file mode 100644
index 00000000000..ce3da48ca95
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/knonefilter.h
@@ -0,0 +1,48 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2011 Mario Bensi 
+
+   Based on kbzip2filter:
+   SPDX-FileCopyrightText: 2000, 2009 David Faure 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef __knonefilter__h
+#define __knonefilter__h
+
+#include "kfilterbase.h"
+
+/**
+ * Internal class used by KCompressionDevice
+ *
+ * This header is not installed.
+ *
+ * @internal
+ */
+class KNoneFilter : public KFilterBase
+{
+public:
+    KNoneFilter();
+    ~KNoneFilter() override;
+
+    bool init(int mode) override;
+    int mode() const override;
+    bool terminate() override;
+    void reset() override;
+    bool readHeader() override; // this is about the GZIP header
+    bool writeHeader(const QByteArray &fileName) override;
+    void setOutBuffer(char *data, uint maxlen) override;
+    void setInBuffer(const char *data, uint size) override;
+    int inBufferAvailable() const override;
+    int outBufferAvailable() const override;
+    Result uncompress() override;
+    Result compress(bool finish) override;
+
+private:
+    Result copyData();
+
+    class Private;
+    Private *const d;
+};
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/krcc.cpp b/src/libs/3rdparty/karchive/src/krcc.cpp
new file mode 100644
index 00000000000..e5eef4508a5
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/krcc.cpp
@@ -0,0 +1,162 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2014 David Faure 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "krcc.h"
+#include "karchive_p.h"
+#include "loggingcategory.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+class Q_DECL_HIDDEN KRcc::KRccPrivate
+{
+public:
+    KRccPrivate()
+    {
+    }
+    void createEntries(const QDir &dir, KArchiveDirectory *parentDir, KRcc *q);
+
+    QString m_prefix; // '/' + uuid
+};
+
+/**
+ * A KRccFileEntry represents a file in a rcc archive.
+ */
+class KRccFileEntry : public KArchiveFile
+{
+public:
+    KRccFileEntry(KArchive *archive,
+                  const QString &name,
+                  int access,
+                  const QDateTime &date,
+                  const QString &user,
+                  const QString &group,
+                  qint64 size,
+                  const QString &resourcePath)
+        : KArchiveFile(archive, name, access, date, user, group, QString(), 0, size)
+        , m_resourcePath(resourcePath)
+    {
+    }
+
+    QByteArray data() const override
+    {
+        QFile f(m_resourcePath);
+        if (f.open(QIODevice::ReadOnly)) {
+            return f.readAll();
+        }
+        qCWarning(KArchiveLog) << "Couldn't open" << m_resourcePath;
+        return QByteArray();
+    }
+    QIODevice *createDevice() const override
+    {
+        return new QFile(m_resourcePath);
+    }
+
+private:
+    QString m_resourcePath;
+};
+
+KRcc::KRcc(const QString &filename)
+    : KArchive(filename)
+    , d(new KRccPrivate)
+{
+}
+
+KRcc::~KRcc()
+{
+    if (isOpen()) {
+        close();
+    }
+    delete d;
+}
+
+bool KRcc::doPrepareWriting(const QString &, const QString &, const QString &, qint64, mode_t, const QDateTime &, const QDateTime &, const QDateTime &)
+{
+    setErrorString(tr("Cannot write to RCC file"));
+    qCWarning(KArchiveLog) << "doPrepareWriting not implemented for KRcc";
+    return false;
+}
+
+bool KRcc::doFinishWriting(qint64)
+{
+    setErrorString(tr("Cannot write to RCC file"));
+    qCWarning(KArchiveLog) << "doFinishWriting not implemented for KRcc";
+    return false;
+}
+
+bool KRcc::doWriteDir(const QString &, const QString &, const QString &, mode_t, const QDateTime &, const QDateTime &, const QDateTime &)
+{
+    setErrorString(tr("Cannot write to RCC file"));
+    qCWarning(KArchiveLog) << "doWriteDir not implemented for KRcc";
+    return false;
+}
+
+bool KRcc::doWriteSymLink(const QString &, const QString &, const QString &, const QString &, mode_t, const QDateTime &, const QDateTime &, const QDateTime &)
+{
+    setErrorString(tr("Cannot write to RCC file"));
+    qCWarning(KArchiveLog) << "doWriteSymLink not implemented for KRcc";
+    return false;
+}
+
+bool KRcc::openArchive(QIODevice::OpenMode mode)
+{
+    // Open archive
+
+    if (mode == QIODevice::WriteOnly) {
+        return true;
+    }
+    if (mode != QIODevice::ReadOnly && mode != QIODevice::ReadWrite) {
+        setErrorString(tr("Unsupported mode %1").arg(mode));
+        return false;
+    }
+
+    QUuid uuid = QUuid::createUuid();
+    d->m_prefix = QLatin1Char('/') + uuid.toString();
+    if (!QResource::registerResource(fileName(), d->m_prefix)) {
+        setErrorString(tr("Failed to register resource %1 under prefix %2").arg(fileName(), d->m_prefix));
+        return false;
+    }
+
+    QDir dir(QLatin1Char(':') + d->m_prefix);
+    d->createEntries(dir, rootDir(), this);
+    return true;
+}
+
+void KRcc::KRccPrivate::createEntries(const QDir &dir, KArchiveDirectory *parentDir, KRcc *q)
+{
+    for (const QString &fileName : dir.entryList()) {
+        const QString entryPath = dir.path() + QLatin1Char('/') + fileName;
+        const QFileInfo info(entryPath);
+        if (info.isFile()) {
+            KArchiveEntry *entry = new KRccFileEntry(q, fileName, 0444, info.lastModified(), parentDir->user(), parentDir->group(), info.size(), entryPath);
+            parentDir->addEntry(entry);
+        } else {
+            KArchiveDirectory *entry =
+                new KArchiveDirectory(q, fileName, 0555, info.lastModified(), parentDir->user(), parentDir->group(), /*symlink*/ QString());
+            if (parentDir->addEntryV2(entry)) {
+                createEntries(QDir(entryPath), entry, q);
+            }
+        }
+    }
+}
+
+bool KRcc::closeArchive()
+{
+    // Close the archive
+    QResource::unregisterResource(fileName(), d->m_prefix);
+    // ignore errors
+    return true;
+}
+
+void KRcc::virtual_hook(int id, void *data)
+{
+    KArchive::virtual_hook(id, data);
+}
diff --git a/src/libs/3rdparty/karchive/src/krcc.h b/src/libs/3rdparty/karchive/src/krcc.h
new file mode 100644
index 00000000000..1c1bfd67971
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/krcc.h
@@ -0,0 +1,103 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2014 David Faure 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+#ifndef KRCC_H
+#define KRCC_H
+
+#include "karchive.h"
+
+/**
+ * KRcc is a class for reading dynamic binary resources created by Qt's rcc tool
+ * from a .qrc file and the files it points to.
+ *
+ * Writing is not supported.
+ * @short A class for reading rcc resources.
+ * @since 5.3
+ */
+class KARCHIVE_EXPORT KRcc : public KArchive
+{
+    Q_DECLARE_TR_FUNCTIONS(KRcc)
+
+public:
+    /**
+     * Creates an instance that operates on the given filename.
+     *
+     * @param filename is a local path (e.g. "/home/holger/myfile.rcc")
+     */
+    explicit KRcc(const QString &filename);
+
+    /**
+     * If the rcc file is still opened, then it will be
+     * closed automatically by the destructor.
+     */
+    ~KRcc() override;
+
+protected:
+    /*
+     * Writing is not supported by this class, will always fail.
+     * @return always false
+     */
+    bool doPrepareWriting(
+        const QString &name,
+        const QString &user,
+        const QString &group,
+        qint64 size,
+        mode_t perm,
+        const QDateTime &atime,
+        const QDateTime &mtime,
+        const QDateTime &ctime) override;
+
+    /*
+     * Writing is not supported by this class, will always fail.
+     * @return always false
+     */
+    bool doFinishWriting(qint64 size) override;
+
+    /*
+     * Writing is not supported by this class, will always fail.
+     * @return always false
+     */
+    bool doWriteDir(
+        const QString &name,
+        const QString &user,
+        const QString &group,
+        mode_t perm,
+        const QDateTime &atime,
+        const QDateTime &mtime,
+        const QDateTime &ctime) override;
+
+    /*
+     * Writing is not supported by this class, will always fail.
+     * @return always false
+     */
+    bool doWriteSymLink(
+        const QString &name,
+        const QString &target,
+        const QString &user,
+        const QString &group,
+        mode_t perm,
+        const QDateTime &atime,
+        const QDateTime &mtime,
+        const QDateTime &ctime) override;
+
+    /**
+     * Registers the .rcc resource in the QResource system under a unique identifier,
+     * then lists that, and creates the KArchiveFile/KArchiveDirectory entries.
+     */
+    bool openArchive(QIODevice::OpenMode mode) override;
+    /**
+     * Unregisters the .rcc resource from the QResource system.
+     */
+    bool closeArchive() override;
+
+protected:
+    void virtual_hook(int id, void *data) override;
+
+private:
+    class KRccPrivate;
+    KRccPrivate *const d;
+};
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/ktar.cpp b/src/libs/3rdparty/karchive/src/ktar.cpp
new file mode 100644
index 00000000000..0ea6313b931
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/ktar.cpp
@@ -0,0 +1,975 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000 David Faure 
+   SPDX-FileCopyrightText: 2003 Leo Savernik 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "ktar.h"
+#include "karchive_p.h"
+#include "kcompressiondevice.h"
+#include "kfilterbase.h"
+#include "loggingcategory.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include  // strtol
+
+////////////////////////////////////////////////////////////////////////
+/////////////////////////// KTar ///////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+// Mime types of known filters
+static const char application_bzip[] = "application/x-bzip";
+static const char application_lzma[] = "application/x-lzma";
+static const char application_xz[] = "application/x-xz";
+static const char application_zstd[] = "application/zstd";
+
+/* clang-format off */
+namespace MimeType
+{
+QString application_gzip()     { return QStringLiteral("application/gzip"); }
+QString application_gzip_old() { return QStringLiteral("application/x-gzip"); }
+}
+/* clang-format on */
+
+class Q_DECL_HIDDEN KTar::KTarPrivate
+{
+public:
+    KTarPrivate(KTar *parent)
+        : q(parent)
+        , tarEnd(0)
+        , tmpFile(nullptr)
+        , compressionDevice(nullptr)
+    {
+    }
+
+    KTar *q;
+    QStringList dirList;
+    qint64 tarEnd;
+    QTemporaryFile *tmpFile;
+    QString mimetype;
+    QByteArray origFileName;
+    KCompressionDevice *compressionDevice;
+
+    bool fillTempFile(const QString &fileName);
+    bool writeBackTempFile(const QString &fileName);
+    void fillBuffer(char *buffer, const char *mode, qint64 size, const QDateTime &mtime, char typeflag, const char *uname, const char *gname);
+    void writeLonglink(char *buffer, const QByteArray &name, char typeflag, const char *uname, const char *gname);
+    qint64 readRawHeader(char *buffer);
+    bool readLonglink(char *buffer, QByteArray &longlink);
+    qint64 readHeader(char *buffer, QString &name, QString &symlink);
+};
+
+KTar::KTar(const QString &fileName, const QString &_mimetype)
+    : KArchive(fileName)
+    , d(new KTarPrivate(this))
+{
+    // shared-mime-info < 1.1 does not know about application/gzip.
+    // While Qt has optionally a copy of shared-mime-info (1.10 for 5.15.0),
+    // it uses the system one if it exists.
+    // Once shared-mime-info 1.1 is required or can be assumed on all targeted
+    // platforms (right now RHEL/CentOS 6 as target of appimage-based apps
+    // bundling also karchive does not meet this requirement)
+    // switch to use the new application/gzip id instead when interacting with QMimeDatabase
+    // For now: map new name to legacy name and use that
+    d->mimetype = (_mimetype == MimeType::application_gzip()) ? MimeType::application_gzip_old() : _mimetype;
+}
+
+KTar::KTar(QIODevice *dev)
+    : KArchive(dev)
+    , d(new KTarPrivate(this))
+{
+}
+
+// Only called when a filename was given
+bool KTar::createDevice(QIODevice::OpenMode mode)
+{
+    if (d->mimetype.isEmpty()) {
+        // Find out mimetype manually
+
+        QMimeDatabase db;
+        QMimeType mime;
+        if (mode != QIODevice::WriteOnly && QFile::exists(fileName())) {
+            // Give priority to file contents: if someone renames a .tar.bz2 to .tar.gz,
+            // we can still do the right thing here.
+            QFile f(fileName());
+            if (f.open(QIODevice::ReadOnly)) {
+                mime = db.mimeTypeForData(&f);
+            }
+            if (!mime.isValid()) {
+                // Unable to determine mimetype from contents, get it from file name
+                mime = db.mimeTypeForFile(fileName(), QMimeDatabase::MatchExtension);
+            }
+        } else {
+            mime = db.mimeTypeForFile(fileName(), QMimeDatabase::MatchExtension);
+        }
+
+        // qCDebug(KArchiveLog) << mode << mime->name();
+
+        if (mime.inherits(QStringLiteral("application/x-compressed-tar")) || mime.inherits(MimeType::application_gzip_old())) {
+            // gzipped tar file (with possibly invalid file name), ask for gzip filter
+            d->mimetype = MimeType::application_gzip_old();
+        } else if (mime.inherits(QStringLiteral("application/x-bzip-compressed-tar")) || mime.inherits(QStringLiteral("application/x-bzip2-compressed-tar"))
+                   || mime.inherits(QStringLiteral("application/x-bzip2")) || mime.inherits(QString::fromLatin1(application_bzip))) {
+            // bzipped2 tar file (with possibly invalid file name), ask for bz2 filter
+            d->mimetype = QString::fromLatin1(application_bzip);
+        } else if (mime.inherits(QStringLiteral("application/x-lzma-compressed-tar")) || mime.inherits(QString::fromLatin1(application_lzma))) {
+            // lzma compressed tar file (with possibly invalid file name), ask for xz filter
+            d->mimetype = QString::fromLatin1(application_lzma);
+        } else if (mime.inherits(QStringLiteral("application/x-xz-compressed-tar")) || mime.inherits(QString::fromLatin1(application_xz))) {
+            // xz compressed tar file (with possibly invalid name), ask for xz filter
+            d->mimetype = QString::fromLatin1(application_xz);
+        } else if (mime.inherits(QStringLiteral("application/x-zstd-compressed-tar")) || mime.inherits(QString::fromLatin1(application_zstd))) {
+            // zstd compressed tar file (with possibly invalid name), ask for zstd filter
+            d->mimetype = QString::fromLatin1(application_zstd);
+        }
+    }
+
+    if (d->mimetype == QLatin1String("application/x-tar")) {
+        return KArchive::createDevice(mode);
+    } else if (mode == QIODevice::WriteOnly) {
+        if (!KArchive::createDevice(mode)) {
+            return false;
+        }
+        if (!d->mimetype.isEmpty()) {
+            // Create a compression filter on top of the QSaveFile device that KArchive created.
+            // qCDebug(KArchiveLog) << "creating KCompressionDevice for" << d->mimetype;
+            KCompressionDevice::CompressionType type = KCompressionDevice::compressionTypeForMimeType(d->mimetype);
+            d->compressionDevice = new KCompressionDevice(device(), false, type);
+            setDevice(d->compressionDevice);
+        }
+        return true;
+    } else {
+        // The compression filters are very slow with random access.
+        // So instead of applying the filter to the device,
+        // the file is completely extracted instead,
+        // and we work on the extracted tar file.
+        // This improves the extraction speed by the archive KIO worker supporting the tar protocol dramatically,
+        // if the archive file contains many files.
+        // This is because the archive KIO worker extracts one file after the other and normally
+        // has to walk through the decompression filter each time.
+        // Which is in fact nearly as slow as a complete decompression for each file.
+
+        Q_ASSERT(!d->tmpFile);
+        d->tmpFile = new QTemporaryFile();
+        d->tmpFile->setFileTemplate(QDir::tempPath() + QLatin1Char('/') + QLatin1String("ktar-XXXXXX.tar"));
+        d->tmpFile->open();
+        // qCDebug(KArchiveLog) << "creating tempfile:" << d->tmpFile->fileName();
+
+        setDevice(d->tmpFile);
+        return true;
+    }
+}
+
+KTar::~KTar()
+{
+    // mjarrett: Closes to prevent ~KArchive from aborting w/o device
+    if (isOpen()) {
+        close();
+    }
+
+    delete d->tmpFile;
+    delete d->compressionDevice;
+    delete d;
+}
+
+void KTar::setOrigFileName(const QByteArray &fileName)
+{
+    if (!isOpen() || !(mode() & QIODevice::WriteOnly)) {
+        // qCWarning(KArchiveLog) << "KTar::setOrigFileName: File must be opened for writing first.\n";
+        return;
+    }
+    d->origFileName = fileName;
+}
+
+qint64 KTar::KTarPrivate::readRawHeader(char *buffer)
+{
+    // Read header
+    qint64 n = q->device()->read(buffer, 0x200);
+    // we need to test if there is a prefix value because the file name can be null
+    // and the prefix can have a value and in this case we don't reset n.
+    if (n == 0x200 && (buffer[0] != 0 || buffer[0x159] != 0)) {
+        // Make sure this is actually a tar header
+        if (strncmp(buffer + 257, "ustar", 5)) {
+            // The magic isn't there (broken/old tars), but maybe a correct checksum?
+
+            int check = 0;
+            for (uint j = 0; j < 0x200; ++j) {
+                check += static_cast(buffer[j]);
+            }
+
+            // adjust checksum to count the checksum fields as blanks
+            for (uint j = 0; j < 8 /*size of the checksum field including the \0 and the space*/; j++) {
+                check -= static_cast(buffer[148 + j]);
+            }
+            check += 8 * ' ';
+
+            QByteArray s = QByteArray::number(check, 8); // octal
+
+            // only compare those of the 6 checksum digits that mean something,
+            // because the other digits are filled with all sorts of different chars by different tars ...
+            // Some tars right-justify the checksum so it could start in one of three places - we have to check each.
+            if (strncmp(buffer + 148 + 6 - s.length(), s.data(), s.length()) //
+                && strncmp(buffer + 148 + 7 - s.length(), s.data(), s.length()) //
+                && strncmp(buffer + 148 + 8 - s.length(), s.data(), s.length())) {
+                /*qCWarning(KArchiveLog) << "KTar: invalid TAR file. Header is:" << QByteArray( buffer+257, 5 )
+                               << "instead of ustar. Reading from wrong pos in file?"
+                               << "checksum=" << QByteArray( buffer + 148 + 6 - s.length(), s.length() );*/
+                return -1;
+            }
+        } /*end if*/
+    } else {
+        // reset to 0 if 0x200 because logical end of archive has been reached
+        if (n == 0x200) {
+            n = 0;
+        }
+    } /*end if*/
+    return n;
+}
+
+bool KTar::KTarPrivate::readLonglink(char *buffer, QByteArray &longlink)
+{
+    qint64 n = 0;
+    // qCDebug(KArchiveLog) << "reading longlink from pos " << q->device()->pos();
+    QIODevice *dev = q->device();
+    // read size of longlink from size field in header
+    // size is in bytes including the trailing null (which we ignore)
+    qint64 size = QByteArray(buffer + 0x7c, 12).trimmed().toLongLong(nullptr, 8 /*octal*/);
+
+    size--; // ignore trailing null
+    if (size > std::numeric_limits::max() - 32) { // QByteArray can't really be INT_MAX big, it's max size is something between INT_MAX - 32 and INT_MAX
+                                                       // depending the platform so just be safe
+        qCWarning(KArchiveLog) << "Failed to allocate memory for longlink of size" << size;
+        return false;
+    }
+    if (size < 0) {
+        qCWarning(KArchiveLog) << "Invalid longlink size" << size;
+        return false;
+    }
+    longlink.resize(size);
+    qint64 offset = 0;
+    while (size > 0) {
+        int chunksize = qMin(size, 0x200LL);
+        n = dev->read(longlink.data() + offset, chunksize);
+        if (n == -1) {
+            return false;
+        }
+        size -= chunksize;
+        offset += 0x200;
+    } /*wend*/
+    // jump over the rest
+    const int skip = 0x200 - (n % 0x200);
+    if (skip <= 0x200) {
+        if (dev->read(buffer, skip) != skip) {
+            return false;
+        }
+    }
+    longlink.truncate(qstrlen(longlink.constData()));
+    return true;
+}
+
+qint64 KTar::KTarPrivate::readHeader(char *buffer, QString &name, QString &symlink)
+{
+    name.truncate(0);
+    symlink.truncate(0);
+    while (true) {
+        qint64 n = readRawHeader(buffer);
+        if (n != 0x200) {
+            return n;
+        }
+
+        // is it a longlink?
+        if (strcmp(buffer, "././@LongLink") == 0) {
+            char typeflag = buffer[0x9c];
+            QByteArray longlink;
+            if (readLonglink(buffer, longlink)) {
+                switch (typeflag) {
+                case 'L':
+                    name = QFile::decodeName(longlink.constData());
+                    break;
+                case 'K':
+                    symlink = QFile::decodeName(longlink.constData());
+                    break;
+                } /*end switch*/
+            }
+        } else {
+            break;
+        } /*end if*/
+    } /*wend*/
+
+    // if not result of longlink, read names directly from the header
+    if (name.isEmpty())
+    // there are names that are exactly 100 bytes long
+    // and neither longlink nor \0 terminated (bug:101472)
+    {
+        name = QFile::decodeName(QByteArray(buffer, qstrnlen(buffer, 100)));
+    }
+    if (symlink.isEmpty()) {
+        char *symlinkBuffer = buffer + 0x9d /*?*/;
+        symlink = QFile::decodeName(QByteArray(symlinkBuffer, qstrnlen(symlinkBuffer, 100)));
+    }
+
+    return 0x200;
+}
+
+/*
+ * If we have created a temporary file, we have
+ * to decompress the original file now and write
+ * the contents to the temporary file.
+ */
+bool KTar::KTarPrivate::fillTempFile(const QString &fileName)
+{
+    if (!tmpFile) {
+        return true;
+    }
+
+    // qCDebug(KArchiveLog) << "filling tmpFile of mimetype" << mimetype;
+
+    KCompressionDevice::CompressionType compressionType = KCompressionDevice::compressionTypeForMimeType(mimetype);
+    KCompressionDevice filterDev(fileName, compressionType);
+
+    QFile *file = tmpFile;
+    Q_ASSERT(file->isOpen());
+    Q_ASSERT(file->openMode() & QIODevice::WriteOnly);
+    file->seek(0);
+    QByteArray buffer;
+    buffer.resize(8 * 1024);
+    if (!filterDev.open(QIODevice::ReadOnly)) {
+        q->setErrorString(tr("File %1 does not exist").arg(fileName));
+        return false;
+    }
+    qint64 len = -1;
+    while (!filterDev.atEnd() && len != 0) {
+        len = filterDev.read(buffer.data(), buffer.size());
+        if (len < 0) { // corrupted archive
+            q->setErrorString(tr("Archive %1 is corrupt").arg(fileName));
+            return false;
+        }
+        if (file->write(buffer.data(), len) != len) { // disk full
+            q->setErrorString(tr("Disk full"));
+            return false;
+        }
+    }
+    filterDev.close();
+
+    file->flush();
+    file->seek(0);
+    Q_ASSERT(file->isOpen());
+    Q_ASSERT(file->openMode() & QIODevice::ReadOnly);
+
+    // qCDebug(KArchiveLog) << "filling tmpFile finished.";
+    return true;
+}
+
+bool KTar::openArchive(QIODevice::OpenMode mode)
+{
+    if (!(mode & QIODevice::ReadOnly)) {
+        return true;
+    }
+
+    if (!d->fillTempFile(fileName())) {
+        return false;
+    }
+
+    // We'll use the permission and user/group of d->rootDir
+    // for any directory we emulate (see findOrCreate)
+    // struct stat buf;
+    // stat( fileName(), &buf );
+
+    d->dirList.clear();
+    QIODevice *dev = device();
+
+    if (!dev) {
+        setErrorString(tr("Could not get underlying device"));
+        qCWarning(KArchiveLog) << "Could not get underlying device";
+        return false;
+    }
+
+    // read dir information
+    char buffer[0x200];
+    bool ende = false;
+    do {
+        QString name;
+        QString symlink;
+
+        // Read header
+        qint64 n = d->readHeader(buffer, name, symlink);
+        if (n < 0) {
+            setErrorString(tr("Could not read tar header"));
+            return false;
+        }
+        if (n == 0x200) {
+            bool isdir = false;
+
+            if (name.isEmpty()) {
+                continue;
+            }
+            if (name.endsWith(QLatin1Char('/'))) {
+                isdir = true;
+                name.truncate(name.length() - 1);
+            }
+
+            QByteArray prefix = QByteArray(buffer + 0x159, 155);
+            if (prefix[0] != '\0') {
+                name = (QString::fromLatin1(prefix.constData()) + QLatin1Char('/') + name);
+            }
+
+            int pos = name.lastIndexOf(QLatin1Char('/'));
+            QString nm = (pos == -1) ? name : name.mid(pos + 1);
+
+            // read access
+            buffer[0x6b] = 0;
+            char *dummy;
+            const char *p = buffer + 0x64;
+            while (*p == ' ') {
+                ++p;
+            }
+            int access = strtol(p, &dummy, 8);
+
+            // read user and group
+            const int maxUserGroupLength = 32;
+            const char *userStart = buffer + 0x109;
+            const int userLen = qstrnlen(userStart, maxUserGroupLength);
+            const QString user = QString::fromLocal8Bit(userStart, userLen);
+            const char *groupStart = buffer + 0x129;
+            const int groupLen = qstrnlen(groupStart, maxUserGroupLength);
+            const QString group = QString::fromLocal8Bit(groupStart, groupLen);
+
+            // read time
+            buffer[0x93] = 0;
+            p = buffer + 0x88;
+            while (*p == ' ') {
+                ++p;
+            }
+            uint time = strtol(p, &dummy, 8);
+
+            // read type flag
+            char typeflag = buffer[0x9c];
+            // '0' for files, '1' hard link, '2' symlink, '5' for directory
+            // (and 'L' for longlink fileNames, 'K' for longlink symlink targets)
+            // 'D' for GNU tar extension DUMPDIR, 'x' for Extended header referring
+            // to the next file in the archive and 'g' for Global extended header
+
+            if (typeflag == '5') {
+                isdir = true;
+            }
+
+            bool isDumpDir = false;
+            if (typeflag == 'D') {
+                isdir = false;
+                isDumpDir = true;
+            }
+            // qCDebug(KArchiveLog) << nm << "isdir=" << isdir << "pos=" << dev->pos() << "typeflag=" << typeflag << " islink=" << ( typeflag == '1' || typeflag
+            // == '2' );
+
+            if (typeflag == 'x' || typeflag == 'g') { // pax extended header, or pax global extended header
+                // Skip it for now. TODO: implement reading of extended header, as per https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
+                (void)dev->read(buffer, 0x200);
+                continue;
+            }
+
+            if (isdir) {
+                access |= S_IFDIR; // broken tar files...
+            }
+
+            KArchiveEntry *e;
+            if (isdir) {
+                // qCDebug(KArchiveLog) << "directory" << nm;
+                e = new KArchiveDirectory(this, nm, access, KArchivePrivate::time_tToDateTime(time), user, group, symlink);
+            } else {
+                // read size
+                QByteArray sizeBuffer(buffer + 0x7c, 12);
+                qint64 size = sizeBuffer.trimmed().toLongLong(nullptr, 8 /*octal*/);
+                if (size < 0) {
+                    qWarning() << "Tar file has negative size, resetting to 0";
+                    size = 0;
+                }
+                // qCDebug(KArchiveLog) << "sizeBuffer='" << sizeBuffer << "' -> size=" << size;
+
+                // for isDumpDir we will skip the additional info about that dirs contents
+                if (isDumpDir) {
+                    // qCDebug(KArchiveLog) << nm << "isDumpDir";
+                    e = new KArchiveDirectory(this, nm, access, KArchivePrivate::time_tToDateTime(time), user, group, symlink);
+                } else {
+                    // Let's hack around hard links. Our classes don't support that, so make them symlinks
+                    if (typeflag == '1') {
+                        // qCDebug(KArchiveLog) << "Hard link, setting size to 0 instead of" << size;
+                        size = 0; // no contents
+                    }
+
+                    // qCDebug(KArchiveLog) << "file" << nm << "size=" << size;
+                    e = new KArchiveFile(this, nm, access, KArchivePrivate::time_tToDateTime(time), user, group, symlink, dev->pos(), size);
+                }
+
+                // Skip contents + align bytes
+                qint64 rest = size % 0x200;
+                qint64 skip = size + (rest ? 0x200 - rest : 0);
+                // qCDebug(KArchiveLog) << "pos()=" << dev->pos() << "rest=" << rest << "skipping" << skip;
+                if (!dev->seek(dev->pos() + skip)) {
+                    // qCWarning(KArchiveLog) << "skipping" << skip << "failed";
+                }
+            }
+
+            if (pos == -1) {
+                if (nm == QLatin1String(".")) { // special case
+                    if (isdir) {
+                        if (KArchivePrivate::hasRootDir(this)) {
+                            qWarning() << "Broken tar file has two root dir entries";
+                            delete e;
+                        } else {
+                            setRootDir(static_cast(e));
+                        }
+                    } else {
+                        delete e;
+                    }
+                } else {
+                    rootDir()->addEntry(e);
+                }
+            } else {
+                // In some tar files we can find dir/./file => call cleanPath
+                QString path = QDir::cleanPath(name.left(pos));
+                // Ensure container directory exists, create otherwise
+                KArchiveDirectory *d = findOrCreate(path);
+                if (d) {
+                    d->addEntry(e);
+                } else {
+                    delete e;
+                    return false;
+                }
+            }
+        } else {
+            // qCDebug(KArchiveLog) << "Terminating. Read " << n << " bytes, first one is " << buffer[0];
+            d->tarEnd = dev->pos() - n; // Remember end of archive
+            ende = true;
+        }
+    } while (!ende);
+    return true;
+}
+
+/*
+ * Writes back the changes of the temporary file
+ * to the original file.
+ * Must only be called if in write mode, not in read mode
+ */
+bool KTar::KTarPrivate::writeBackTempFile(const QString &fileName)
+{
+    if (!tmpFile) {
+        return true;
+    }
+
+    // qCDebug(KArchiveLog) << "Write temporary file to compressed file" << fileName << mimetype;
+
+    bool forced = false;
+    /* clang-format off */
+    if (MimeType::application_gzip_old() == mimetype ||
+        QLatin1String(application_bzip) == mimetype ||
+        QLatin1String(application_lzma) == mimetype ||
+        QLatin1String(application_xz) == mimetype) {
+        /* clang-format on */
+        forced = true;
+    }
+
+    // #### TODO this should use QSaveFile to avoid problems on disk full
+    // (KArchive uses QSaveFile by default, but the temp-uncompressed-file trick
+    // circumvents that).
+
+    KCompressionDevice dev(fileName);
+    QFile *file = tmpFile;
+    if (!dev.open(QIODevice::WriteOnly)) {
+        file->close();
+        q->setErrorString(tr("Failed to write back temp file: %1").arg(dev.errorString()));
+        return false;
+    }
+    if (forced) {
+        dev.setOrigFileName(origFileName);
+    }
+    file->seek(0);
+    QByteArray buffer;
+    buffer.resize(8 * 1024);
+    qint64 len;
+    while (!file->atEnd()) {
+        len = file->read(buffer.data(), buffer.size());
+        dev.write(buffer.data(), len); // TODO error checking
+    }
+    file->close();
+    dev.close();
+
+    // qCDebug(KArchiveLog) << "Write temporary file to compressed file done.";
+    return true;
+}
+
+bool KTar::closeArchive()
+{
+    d->dirList.clear();
+
+    bool ok = true;
+
+    // If we are in readwrite mode and had created
+    // a temporary tar file, we have to write
+    // back the changes to the original file
+    if (d->tmpFile && (mode() & QIODevice::WriteOnly)) {
+        ok = d->writeBackTempFile(fileName());
+        delete d->tmpFile;
+        d->tmpFile = nullptr;
+        setDevice(nullptr);
+    }
+
+    return ok;
+}
+
+bool KTar::doFinishWriting(qint64 size)
+{
+    // Write alignment
+    int rest = size % 0x200;
+    if ((mode() & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
+        d->tarEnd = device()->pos() + (rest ? 0x200 - rest : 0); // Record our new end of archive
+    }
+    if (rest) {
+        char buffer[0x201];
+        for (uint i = 0; i < 0x200; ++i) {
+            buffer[i] = 0;
+        }
+        qint64 nwritten = device()->write(buffer, 0x200 - rest);
+        const bool ok = nwritten == 0x200 - rest;
+
+        if (!ok) {
+            setErrorString(tr("Couldn't write alignment: %1").arg(device()->errorString()));
+        }
+
+        return ok;
+    }
+    return true;
+}
+
+/*** Some help from the tar sources
+struct posix_header
+{                               byte offset
+  char name[100];               *   0 *     0x0
+  char mode[8];                 * 100 *     0x64
+  char uid[8];                  * 108 *     0x6c
+  char gid[8];                  * 116 *     0x74
+  char size[12];                * 124 *     0x7c
+  char mtime[12];               * 136 *     0x88
+  char chksum[8];               * 148 *     0x94
+  char typeflag;                * 156 *     0x9c
+  char linkname[100];           * 157 *     0x9d
+  char magic[6];                * 257 *     0x101
+  char version[2];              * 263 *     0x107
+  char uname[32];               * 265 *     0x109
+  char gname[32];               * 297 *     0x129
+  char devmajor[8];             * 329 *     0x149
+  char devminor[8];             * 337 *     ...
+  char prefix[155];             * 345 *
+                                * 500 *
+};
+*/
+
+void KTar::KTarPrivate::fillBuffer(char *buffer, const char *mode, qint64 size, const QDateTime &mtime, char typeflag, const char *uname, const char *gname)
+{
+    // mode (as in stpos())
+    assert(strlen(mode) == 6);
+    memcpy(buffer + 0x64, mode, 6);
+    buffer[0x6a] = ' ';
+    buffer[0x6b] = '\0';
+
+    // dummy uid
+    strcpy(buffer + 0x6c, "   765 "); // 501 in decimal
+    // dummy gid
+    strcpy(buffer + 0x74, "   144 "); // 100 in decimal
+
+    // size
+    QByteArray s = QByteArray::number(size, 8); // octal
+    s = s.rightJustified(11, '0');
+    memcpy(buffer + 0x7c, s.data(), 11);
+    buffer[0x87] = ' '; // space-terminate (no null after)
+
+    // modification time
+    const QDateTime modificationTime = mtime.isValid() ? mtime : QDateTime::currentDateTime();
+    s = QByteArray::number(static_cast(modificationTime.toMSecsSinceEpoch() / 1000), 8); // octal
+    s = s.rightJustified(11, '0');
+    memcpy(buffer + 0x88, s.data(), 11);
+    buffer[0x93] = ' '; // space-terminate (no null after) -- well current tar writes a null byte
+
+    // spaces, replaced by the check sum later
+    buffer[0x94] = 0x20;
+    buffer[0x95] = 0x20;
+    buffer[0x96] = 0x20;
+    buffer[0x97] = 0x20;
+    buffer[0x98] = 0x20;
+    buffer[0x99] = 0x20;
+
+    /* From the tar sources :
+       Fill in the checksum field.  It's formatted differently from the
+       other fields: it has [6] digits, a null, then a space -- rather than
+       digits, a space, then a null. */
+
+    buffer[0x9a] = '\0';
+    buffer[0x9b] = ' ';
+
+    // type flag (dir, file, link)
+    buffer[0x9c] = typeflag;
+
+    // magic + version
+    strcpy(buffer + 0x101, "ustar");
+    strcpy(buffer + 0x107, "00");
+
+    // user
+    strcpy(buffer + 0x109, uname);
+    // group
+    strcpy(buffer + 0x129, gname);
+
+    // Header check sum
+    int check = 32;
+    for (uint j = 0; j < 0x200; ++j) {
+        check += static_cast(buffer[j]);
+    }
+    s = QByteArray::number(check, 8); // octal
+    s = s.rightJustified(6, '0');
+    memcpy(buffer + 0x94, s.constData(), 6);
+}
+
+void KTar::KTarPrivate::writeLonglink(char *buffer, const QByteArray &name, char typeflag, const char *uname, const char *gname)
+{
+    strcpy(buffer, "././@LongLink");
+    qint64 namelen = name.length() + 1;
+    fillBuffer(buffer, "     0", namelen, QDateTime(), typeflag, uname, gname);
+    q->device()->write(buffer, 0x200); // TODO error checking
+    qint64 offset = 0;
+    while (namelen > 0) {
+        int chunksize = qMin(namelen, 0x200LL);
+        memcpy(buffer, name.data() + offset, chunksize);
+        // write long name
+        q->device()->write(buffer, 0x200); // TODO error checking
+        // not even needed to reclear the buffer, tar doesn't do it
+        namelen -= chunksize;
+        offset += 0x200;
+    } /*wend*/
+}
+
+bool KTar::doPrepareWriting(const QString &name,
+                            const QString &user,
+                            const QString &group,
+                            qint64 size,
+                            mode_t perm,
+                            const QDateTime & /*atime*/,
+                            const QDateTime &mtime,
+                            const QDateTime & /*ctime*/)
+{
+    if (!isOpen()) {
+        setErrorString(tr("Application error: TAR file must be open before being written into"));
+        qCWarning(KArchiveLog) << "doPrepareWriting failed: !isOpen()";
+        return false;
+    }
+
+    if (!(mode() & QIODevice::WriteOnly)) {
+        setErrorString(tr("Application error: attempted to write into non-writable 7-Zip file"));
+        qCWarning(KArchiveLog) << "doPrepareWriting failed: !(mode() & QIODevice::WriteOnly)";
+        return false;
+    }
+
+    const qint64 MAX_FILESIZE = 077777777777L; // the format we use only allows 11 octal digits for size
+    if (size > MAX_FILESIZE) {
+        setErrorString(tr("Application limitation: Can not add file larger than %1 bytes").arg(MAX_FILESIZE));
+        return false;
+    }
+
+    // In some tar files we can find dir/./file => call cleanPath
+    QString fileName(QDir::cleanPath(name));
+
+    /*
+      // Create toplevel dirs
+      // Commented out by David since it's not necessary, and if anybody thinks it is,
+      // he needs to implement a findOrCreate equivalent in writeDir.
+      // But as KTar and the "tar" program both handle tar files without
+      // dir entries, there's really no need for that
+      QString tmp ( fileName );
+      int i = tmp.lastIndexOf( '/' );
+      if ( i != -1 )
+      {
+      QString d = tmp.left( i + 1 ); // contains trailing slash
+      if ( !m_dirList.contains( d ) )
+      {
+      tmp = tmp.mid( i + 1 );
+      writeDir( d, user, group ); // WARNING : this one doesn't create its toplevel dirs
+      }
+      }
+    */
+
+    char buffer[0x201] = {0};
+
+    if ((mode() & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
+        device()->seek(d->tarEnd); // Go to end of archive as might have moved with a read
+    }
+
+    // provide converted stuff we need later on
+    const QByteArray encodedFileName = QFile::encodeName(fileName);
+    const QByteArray uname = user.toLocal8Bit();
+    const QByteArray gname = group.toLocal8Bit();
+
+    // If more than 100 bytes, we need to use the LongLink trick
+    if (encodedFileName.length() > 99) {
+        d->writeLonglink(buffer, encodedFileName, 'L', uname.constData(), gname.constData());
+    }
+
+    // Write (potentially truncated) name
+    strncpy(buffer, encodedFileName.constData(), 99);
+    buffer[99] = 0;
+    // zero out the rest (except for what gets filled anyways)
+    memset(buffer + 0x9d, 0, 0x200 - 0x9d);
+
+    QByteArray permstr = QByteArray::number(static_cast(perm), 8);
+    permstr = permstr.rightJustified(6, '0');
+    d->fillBuffer(buffer, permstr.constData(), size, mtime, 0x30, uname.constData(), gname.constData());
+
+    // Write header
+    if (device()->write(buffer, 0x200) != 0x200) {
+        setErrorString(tr("Failed to write header: %1").arg(device()->errorString()));
+        return false;
+    } else {
+        return true;
+    }
+}
+
+bool KTar::doWriteDir(const QString &name,
+                      const QString &user,
+                      const QString &group,
+                      mode_t perm,
+                      const QDateTime & /*atime*/,
+                      const QDateTime &mtime,
+                      const QDateTime & /*ctime*/)
+{
+    if (!isOpen()) {
+        setErrorString(tr("Application error: TAR file must be open before being written into"));
+        qCWarning(KArchiveLog) << "doWriteDir failed: !isOpen()";
+        return false;
+    }
+
+    if (!(mode() & QIODevice::WriteOnly)) {
+        setErrorString(tr("Application error: attempted to write into non-writable TAR file"));
+        qCWarning(KArchiveLog) << "doWriteDir failed: !(mode() & QIODevice::WriteOnly)";
+        return false;
+    }
+
+    // In some tar files we can find dir/./ => call cleanPath
+    QString dirName(QDir::cleanPath(name));
+
+    // Need trailing '/'
+    if (!dirName.endsWith(QLatin1Char('/'))) {
+        dirName += QLatin1Char('/');
+    }
+
+    if (d->dirList.contains(dirName)) {
+        return true; // already there
+    }
+
+    char buffer[0x201] = {0};
+
+    if ((mode() & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
+        device()->seek(d->tarEnd); // Go to end of archive as might have moved with a read
+    }
+
+    // provide converted stuff we need lateron
+    QByteArray encodedDirname = QFile::encodeName(dirName);
+    QByteArray uname = user.toLocal8Bit();
+    QByteArray gname = group.toLocal8Bit();
+
+    // If more than 100 bytes, we need to use the LongLink trick
+    if (encodedDirname.length() > 99) {
+        d->writeLonglink(buffer, encodedDirname, 'L', uname.constData(), gname.constData());
+    }
+
+    // Write (potentially truncated) name
+    strncpy(buffer, encodedDirname.constData(), 99);
+    buffer[99] = 0;
+    // zero out the rest (except for what gets filled anyways)
+    memset(buffer + 0x9d, 0, 0x200 - 0x9d);
+
+    QByteArray permstr = QByteArray::number(static_cast(perm), 8);
+    permstr = permstr.rightJustified(6, ' ');
+    d->fillBuffer(buffer, permstr.constData(), 0, mtime, 0x35, uname.constData(), gname.constData());
+
+    // Write header
+    device()->write(buffer, 0x200);
+    if ((mode() & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
+        d->tarEnd = device()->pos();
+    }
+
+    d->dirList.append(dirName); // contains trailing slash
+    return true; // TODO if wanted, better error control
+}
+
+bool KTar::doWriteSymLink(const QString &name,
+                          const QString &target,
+                          const QString &user,
+                          const QString &group,
+                          mode_t perm,
+                          const QDateTime & /*atime*/,
+                          const QDateTime &mtime,
+                          const QDateTime & /*ctime*/)
+{
+    if (!isOpen()) {
+        setErrorString(tr("Application error: TAR file must be open before being written into"));
+        qCWarning(KArchiveLog) << "doWriteSymLink failed: !isOpen()";
+        return false;
+    }
+
+    if (!(mode() & QIODevice::WriteOnly)) {
+        setErrorString(tr("Application error: attempted to write into non-writable TAR file"));
+        qCWarning(KArchiveLog) << "doWriteSymLink failed: !(mode() & QIODevice::WriteOnly)";
+        return false;
+    }
+
+    // In some tar files we can find dir/./file => call cleanPath
+    QString fileName(QDir::cleanPath(name));
+
+    char buffer[0x201] = {0};
+
+    if ((mode() & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
+        device()->seek(d->tarEnd); // Go to end of archive as might have moved with a read
+    }
+
+    // provide converted stuff we need lateron
+    QByteArray encodedFileName = QFile::encodeName(fileName);
+    QByteArray encodedTarget = QFile::encodeName(target);
+    QByteArray uname = user.toLocal8Bit();
+    QByteArray gname = group.toLocal8Bit();
+
+    // If more than 100 bytes, we need to use the LongLink trick
+    if (encodedTarget.length() > 99) {
+        d->writeLonglink(buffer, encodedTarget, 'K', uname.constData(), gname.constData());
+    }
+    if (encodedFileName.length() > 99) {
+        d->writeLonglink(buffer, encodedFileName, 'L', uname.constData(), gname.constData());
+    }
+
+    // Write (potentially truncated) name
+    strncpy(buffer, encodedFileName.constData(), 99);
+    buffer[99] = 0;
+    // Write (potentially truncated) symlink target
+    strncpy(buffer + 0x9d, encodedTarget.constData(), 99);
+    buffer[0x9d + 99] = 0;
+    // zero out the rest
+    memset(buffer + 0x9d + 100, 0, 0x200 - 100 - 0x9d);
+
+    QByteArray permstr = QByteArray::number(static_cast(perm), 8);
+    permstr = permstr.rightJustified(6, ' ');
+    d->fillBuffer(buffer, permstr.constData(), 0, mtime, 0x32, uname.constData(), gname.constData());
+
+    // Write header
+    bool retval = device()->write(buffer, 0x200) == 0x200;
+    if ((mode() & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
+        d->tarEnd = device()->pos();
+    }
+    return retval;
+}
+
+void KTar::virtual_hook(int id, void *data)
+{
+    KArchive::virtual_hook(id, data);
+}
diff --git a/src/libs/3rdparty/karchive/src/ktar.h b/src/libs/3rdparty/karchive/src/ktar.h
new file mode 100644
index 00000000000..24f6c355e6e
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/ktar.h
@@ -0,0 +1,117 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000-2005 David Faure 
+   SPDX-FileCopyrightText: 2003 Leo Savernik 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+#ifndef KTAR_H
+#define KTAR_H
+
+#include "karchive.h"
+
+/**
+ * @class KTar ktar.h KTar
+ *
+ * A class for reading / writing (optionally compressed) tar archives.
+ *
+ * KTar allows you to read and write tar archives, including those
+ * that are compressed using gzip, bzip2 or xz.
+ *
+ * @author Torben Weis , David Faure 
+ */
+class KARCHIVE_EXPORT KTar : public KArchive
+{
+    Q_DECLARE_TR_FUNCTIONS(KTar)
+
+public:
+    /**
+     * Creates an instance that operates on the given filename
+     * using the compression filter associated to given mimetype.
+     *
+     * @param filename is a local path (e.g. "/home/weis/myfile.tgz")
+     * @param mimetype "application/gzip" (before 5.85: "application/x-gzip"), "application/x-bzip",
+     * "application/x-xz", "application/zstd" (since 5.82)
+     * Do not use application/x-compressed-tar or similar - you only need to
+     * specify the compression layer !  If the mimetype is omitted, it
+     * will be determined from the filename.
+     */
+    explicit KTar(const QString &filename, const QString &mimetype = QString());
+
+    /**
+     * Creates an instance that operates on the given device.
+     * The device can be compressed (KCompressionDevice) or not (QFile, etc.).
+     * @warning Do not assume that giving a QFile here will decompress the file,
+     * in case it's compressed!
+     * @param dev the device to read from. If the source is compressed, the
+     * QIODevice must take care of decompression
+     */
+    explicit KTar(QIODevice *dev);
+
+    /**
+     * If the tar ball is still opened, then it will be
+     * closed automatically by the destructor.
+     */
+    ~KTar() override;
+
+    /**
+     * Special function for setting the "original file name" in the gzip header,
+     * when writing a tar.gz file. It appears when using in the "file" command,
+     * for instance. Should only be called if the underlying device is a KCompressionDevice!
+     * @param fileName the original file name
+     */
+    void setOrigFileName(const QByteArray &fileName);
+
+protected:
+    /// Reimplemented from KArchive
+    bool doWriteSymLink(
+        const QString &name,
+        const QString &target,
+        const QString &user,
+        const QString &group,
+        mode_t perm,
+        const QDateTime &atime,
+        const QDateTime &mtime,
+        const QDateTime &ctime) override;
+    /// Reimplemented from KArchive
+    bool doWriteDir(
+        const QString &name,
+        const QString &user,
+        const QString &group,
+        mode_t perm,
+        const QDateTime &atime,
+        const QDateTime &mtime,
+        const QDateTime &ctime) override;
+    /// Reimplemented from KArchive
+    bool doPrepareWriting(
+        const QString &name,
+        const QString &user,
+        const QString &group,
+        qint64 size,
+        mode_t perm,
+        const QDateTime &atime,
+        const QDateTime &mtime,
+        const QDateTime &ctime) override;
+    /// Reimplemented from KArchive
+    bool doFinishWriting(qint64 size) override;
+
+    /**
+     * Opens the archive for reading.
+     * Parses the directory listing of the archive
+     * and creates the KArchiveDirectory/KArchiveFile entries.
+     * @param mode the mode of the file
+     */
+    bool openArchive(QIODevice::OpenMode mode) override;
+    bool closeArchive() override;
+
+    bool createDevice(QIODevice::OpenMode mode) override;
+
+private:
+protected:
+    void virtual_hook(int id, void *data) override;
+
+private:
+    class KTarPrivate;
+    KTarPrivate *const d;
+};
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/kxzfilter.cpp b/src/libs/3rdparty/karchive/src/kxzfilter.cpp
new file mode 100644
index 00000000000..f34c237c856
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kxzfilter.cpp
@@ -0,0 +1,279 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2007-2008 Per Øyvind Karlsen 
+
+   Based on kbzip2filter:
+   SPDX-FileCopyrightText: 2000-2005 David Faure 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "kxzfilter.h"
+#include "loggingcategory.h"
+
+#if HAVE_XZ_SUPPORT
+extern "C" {
+#include 
+}
+
+#include 
+
+#include 
+
+class Q_DECL_HIDDEN KXzFilter::Private
+{
+public:
+    Private()
+        : isInitialized(false)
+    {
+        memset(&zStream, 0, sizeof(zStream));
+        mode = 0;
+    }
+
+    lzma_stream zStream;
+    int mode;
+    bool isInitialized;
+    KXzFilter::Flag flag;
+};
+
+KXzFilter::KXzFilter()
+    : d(new Private)
+{
+}
+
+KXzFilter::~KXzFilter()
+{
+    delete d;
+}
+
+bool KXzFilter::init(int mode)
+{
+    QList props;
+    return init(mode, AUTO, props);
+}
+
+static void freeFilters(lzma_filter filters[])
+{
+    for (int i = 0; filters[i].id != LZMA_VLI_UNKNOWN; i++) {
+        free(filters[i].options);
+    }
+}
+
+bool KXzFilter::init(int mode, Flag flag, const QList &properties)
+{
+    if (d->isInitialized) {
+        terminate();
+    }
+
+    d->flag = flag;
+    lzma_ret result;
+    d->zStream.next_in = nullptr;
+    d->zStream.avail_in = 0;
+    if (mode == QIODevice::ReadOnly) {
+        // TODO when we can depend on Qt 5.12 Use a QScopeGuard to call freeFilters
+        lzma_filter filters[5];
+        filters[0].id = LZMA_VLI_UNKNOWN;
+
+        switch (flag) {
+        case AUTO:
+            /* We set the memlimit for decompression to 100MiB which should be
+             * more than enough to be sufficient for level 9 which requires 65 MiB.
+             */
+            result = lzma_auto_decoder(&d->zStream, 100 << 20, 0);
+            if (result != LZMA_OK) {
+                qCWarning(KArchiveLog) << "lzma_auto_decoder returned" << result;
+                return false;
+            }
+            break;
+        case LZMA: {
+            filters[0].id = LZMA_FILTER_LZMA1;
+            filters[0].options = nullptr;
+            filters[1].id = LZMA_VLI_UNKNOWN;
+            filters[1].options = nullptr;
+
+            Q_ASSERT(properties.size() == 5);
+            unsigned char props[5];
+            for (int i = 0; i < properties.size(); ++i) {
+                props[i] = properties[i];
+            }
+
+            result = lzma_properties_decode(&filters[0], nullptr, props, sizeof(props));
+            if (result != LZMA_OK) {
+                qCWarning(KArchiveLog) << "lzma_properties_decode returned" << result;
+                freeFilters(filters);
+                return false;
+            }
+            break;
+        }
+        case LZMA2: {
+            filters[0].id = LZMA_FILTER_LZMA2;
+            filters[0].options = nullptr;
+            filters[1].id = LZMA_VLI_UNKNOWN;
+            filters[1].options = nullptr;
+
+            Q_ASSERT(properties.size() == 1);
+            unsigned char props[1];
+            props[0] = properties[0];
+
+            result = lzma_properties_decode(&filters[0], nullptr, props, sizeof(props));
+            if (result != LZMA_OK) {
+                qCWarning(KArchiveLog) << "lzma_properties_decode returned" << result;
+                freeFilters(filters);
+                return false;
+            }
+            break;
+        }
+        case BCJ: {
+            filters[0].id = LZMA_FILTER_X86;
+            filters[0].options = nullptr;
+
+            unsigned char props[5] = {0x5d, 0x00, 0x00, 0x08, 0x00};
+            filters[1].id = LZMA_FILTER_LZMA1;
+            filters[1].options = nullptr;
+            result = lzma_properties_decode(&filters[1], nullptr, props, sizeof(props));
+            if (result != LZMA_OK) {
+                qCWarning(KArchiveLog) << "lzma_properties_decode1 returned" << result;
+                freeFilters(filters);
+                return false;
+            }
+
+            filters[2].id = LZMA_VLI_UNKNOWN;
+            filters[2].options = nullptr;
+
+            break;
+        }
+        case POWERPC:
+        case IA64:
+        case ARM:
+        case ARMTHUMB:
+        case SPARC:
+            // qCDebug(KArchiveLog) << "flag" << flag << "props size" << properties.size();
+            break;
+        }
+
+        if (flag != AUTO) {
+            result = lzma_raw_decoder(&d->zStream, filters);
+            if (result != LZMA_OK) {
+                qCWarning(KArchiveLog) << "lzma_raw_decoder returned" << result;
+                freeFilters(filters);
+                return false;
+            }
+        }
+        freeFilters(filters);
+
+    } else if (mode == QIODevice::WriteOnly) {
+        if (flag == AUTO) {
+            result = lzma_easy_encoder(&d->zStream, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC32);
+        } else {
+            lzma_filter filters[5];
+            if (flag == LZMA2) {
+                lzma_options_lzma lzma_opt;
+                lzma_lzma_preset(&lzma_opt, LZMA_PRESET_DEFAULT);
+
+                filters[0].id = LZMA_FILTER_LZMA2;
+                filters[0].options = &lzma_opt;
+                filters[1].id = LZMA_VLI_UNKNOWN;
+                filters[1].options = nullptr;
+            }
+            result = lzma_raw_encoder(&d->zStream, filters);
+        }
+        if (result != LZMA_OK) {
+            qCWarning(KArchiveLog) << "lzma_easy_encoder returned" << result;
+            return false;
+        }
+    } else {
+        // qCWarning(KArchiveLog) << "Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
+        return false;
+    }
+    d->mode = mode;
+    d->isInitialized = true;
+    return true;
+}
+
+int KXzFilter::mode() const
+{
+    return d->mode;
+}
+
+bool KXzFilter::terminate()
+{
+    if (d->mode == QIODevice::ReadOnly || d->mode == QIODevice::WriteOnly) {
+        lzma_end(&d->zStream);
+    } else {
+        // qCWarning(KArchiveLog) << "Unsupported mode " << d->mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
+        return false;
+    }
+    d->isInitialized = false;
+    return true;
+}
+
+void KXzFilter::reset()
+{
+    // qCDebug(KArchiveLog) << "KXzFilter::reset";
+    // liblzma doesn't have a reset call...
+    terminate();
+    init(d->mode);
+}
+
+void KXzFilter::setOutBuffer(char *data, uint maxlen)
+{
+    d->zStream.avail_out = maxlen;
+    d->zStream.next_out = (uint8_t *)data;
+}
+
+void KXzFilter::setInBuffer(const char *data, unsigned int size)
+{
+    d->zStream.avail_in = size;
+    d->zStream.next_in = (uint8_t *)const_cast(data);
+}
+
+int KXzFilter::inBufferAvailable() const
+{
+    return d->zStream.avail_in;
+}
+
+int KXzFilter::outBufferAvailable() const
+{
+    return d->zStream.avail_out;
+}
+
+KXzFilter::Result KXzFilter::uncompress()
+{
+    // qCDebug(KArchiveLog) << "Calling lzma_code with avail_in=" << inBufferAvailable() << " avail_out =" << outBufferAvailable();
+    lzma_ret result;
+    result = lzma_code(&d->zStream, LZMA_RUN);
+
+    /*if (result != LZMA_OK) {
+        qCDebug(KArchiveLog) << "lzma_code returned " << result;
+        //qCDebug(KArchiveLog) << "KXzFilter::uncompress " << ( result == LZMA_STREAM_END ? KFilterBase::End : KFilterBase::Error );
+    }*/
+
+    switch (result) {
+    case LZMA_OK:
+        return KFilterBase::Ok;
+    case LZMA_STREAM_END:
+        return KFilterBase::End;
+    default:
+        return KFilterBase::Error;
+    }
+}
+
+KXzFilter::Result KXzFilter::compress(bool finish)
+{
+    // qCDebug(KArchiveLog) << "Calling lzma_code with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
+    lzma_ret result = lzma_code(&d->zStream, finish ? LZMA_FINISH : LZMA_RUN);
+    switch (result) {
+    case LZMA_OK:
+        return KFilterBase::Ok;
+        break;
+    case LZMA_STREAM_END:
+        // qCDebug(KArchiveLog) << "  lzma_code returned " << result;
+        return KFilterBase::End;
+        break;
+    default:
+        // qCDebug(KArchiveLog) << "  lzma_code returned " << result;
+        return KFilterBase::Error;
+        break;
+    }
+}
+
+#endif /* HAVE_XZ_SUPPORT */
diff --git a/src/libs/3rdparty/karchive/src/kxzfilter.h b/src/libs/3rdparty/karchive/src/kxzfilter.h
new file mode 100644
index 00000000000..914d47dbe52
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kxzfilter.h
@@ -0,0 +1,67 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2007-2008 Per Øyvind Karlsen 
+
+   Based on kbzip2filter:
+   SPDX-FileCopyrightText: 2000 David Faure 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KXZFILTER_H
+#define KXZFILTER_H
+
+#if HAVE_XZ_SUPPORT
+
+#include "kfilterbase.h"
+
+/**
+ * Internal class used by KCompressionDevice
+ * @internal
+ */
+class KXzFilter : public KFilterBase
+{
+public:
+    KXzFilter();
+    ~KXzFilter() override;
+
+    bool init(int) override;
+
+    enum Flag {
+        AUTO = 0,
+        LZMA = 1,
+        LZMA2 = 2,
+        BCJ = 3, // X86
+        POWERPC = 4,
+        IA64 = 5,
+        ARM = 6,
+        ARMTHUMB = 7,
+        SPARC = 8,
+    };
+
+    virtual bool init(int, Flag flag, const QList &props);
+    int mode() const override;
+    bool terminate() override;
+    void reset() override;
+    bool readHeader() override
+    {
+        return true; // lzma handles it by itself ! Cool !
+    }
+    bool writeHeader(const QByteArray &) override
+    {
+        return true;
+    }
+    void setOutBuffer(char *data, uint maxlen) override;
+    void setInBuffer(const char *data, uint size) override;
+    int inBufferAvailable() const override;
+    int outBufferAvailable() const override;
+    Result uncompress() override;
+    Result compress(bool finish) override;
+
+private:
+    class Private;
+    Private *const d;
+};
+
+#endif
+
+#endif // KXZFILTER_H
diff --git a/src/libs/3rdparty/karchive/src/kzip.cpp b/src/libs/3rdparty/karchive/src/kzip.cpp
new file mode 100644
index 00000000000..23bf9aa4a3b
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kzip.cpp
@@ -0,0 +1,1477 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2000 David Faure 
+   SPDX-FileCopyrightText: 2002 Holger Schroeder 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "kzip.h"
+#include "karchive_p.h"
+#include "kcompressiondevice.h"
+#include "klimitediodevice_p.h"
+#include "loggingcategory.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#ifndef QT_STAT_LNK
+#define QT_STAT_LNK 0120000
+#endif // QT_STAT_LNK
+
+static const int max_path_len = 4095; // maximum number of character a path may contain
+
+static void transformToMsDos(const QDateTime &_dt, char *buffer)
+{
+    const QDateTime dt = _dt.isValid() ? _dt : QDateTime::currentDateTime();
+    /* clang-format off */
+    const quint16 time = (dt.time().hour() << 11) // 5 bit hour
+                         | (dt.time().minute() << 5) // 6 bit minute
+                         | (dt.time().second() >> 1); // 5 bit double seconds
+    /* clang-format on */
+
+    buffer[0] = char(time);
+    buffer[1] = char(time >> 8);
+
+    /* clang-format off */
+    const quint16 date = ((dt.date().year() - 1980) << 9) // 7 bit year 1980-based
+                         | (dt.date().month() << 5) // 4 bit month
+                         | (dt.date().day()); // 5 bit day
+    /* clang-format on */
+
+    buffer[2] = char(date);
+    buffer[3] = char(date >> 8);
+}
+
+static uint transformFromMsDos(const char *buffer)
+{
+    quint16 time = (uchar)buffer[0] | ((uchar)buffer[1] << 8);
+    int h = time >> 11;
+    int m = (time & 0x7ff) >> 5;
+    int s = (time & 0x1f) * 2;
+    QTime qt(h, m, s);
+
+    quint16 date = (uchar)buffer[2] | ((uchar)buffer[3] << 8);
+    int y = (date >> 9) + 1980;
+    int o = (date & 0x1ff) >> 5;
+    int d = (date & 0x1f);
+    QDate qd(y, o, d);
+
+    QDateTime dt(qd, qt);
+    return dt.toSecsSinceEpoch();
+}
+
+// == parsing routines for zip headers
+
+/** all relevant information about parsing file information */
+struct ParseFileInfo {
+    // file related info
+    mode_t perm; // permissions of this file
+    // TODO: use quint32 instead of a uint?
+    uint atime; // last access time (UNIX format)
+    uint mtime; // modification time (UNIX format)
+    uint ctime; // creation time (UNIX format)
+    int uid; // user id (-1 if not specified)
+    int gid; // group id (-1 if not specified)
+    QByteArray guessed_symlink; // guessed symlink target
+    int extralen; // length of extra field
+
+    // parsing related info
+    bool exttimestamp_seen; // true if extended timestamp extra field
+    // has been parsed
+    bool newinfounix_seen; // true if Info-ZIP Unix New extra field has
+    // been parsed
+
+    // file sizes from a ZIP64 extra field
+    quint64 uncompressedSize = 0;
+    quint64 compressedSize = 0;
+
+    ParseFileInfo()
+        : perm(0100644)
+        , uid(-1)
+        , gid(-1)
+        , extralen(0)
+        , exttimestamp_seen(false)
+        , newinfounix_seen(false)
+    {
+        ctime = mtime = atime = time(nullptr);
+    }
+};
+
+/** updates the parse information with the given extended timestamp extra field.
+ * @param buffer start content of buffer known to contain an extended
+ *  timestamp extra field (without magic & size)
+ * @param size size of field content (must not count magic and size entries)
+ * @param islocal true if this is a local field, false if central
+ * @param pfi ParseFileInfo object to be updated
+ * @return true if processing was successful
+ */
+static bool parseExtTimestamp(const char *buffer, int size, bool islocal, ParseFileInfo &pfi)
+{
+    if (size < 1) {
+        // qCDebug(KArchiveLog) << "premature end of extended timestamp (#1)";
+        return false;
+    } /*end if*/
+    int flags = *buffer; // read flags
+    buffer += 1;
+    size -= 1;
+
+    if (flags & 1) { // contains modification time
+        if (size < 4) {
+            // qCDebug(KArchiveLog) << "premature end of extended timestamp (#2)";
+            return false;
+        } /*end if*/
+        pfi.mtime = uint((uchar)buffer[0] | (uchar)buffer[1] << 8 | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
+        buffer += 4;
+        size -= 4;
+    } /*end if*/
+    // central extended field cannot contain more than the modification time
+    // even if other flags are set
+    if (!islocal) {
+        pfi.exttimestamp_seen = true;
+        return true;
+    } /*end if*/
+
+    if (flags & 2) { // contains last access time
+        if (size < 4) {
+            // qCDebug(KArchiveLog) << "premature end of extended timestamp (#3)";
+            return true;
+        } /*end if*/
+        pfi.atime = uint((uchar)buffer[0] | (uchar)buffer[1] << 8 | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
+        buffer += 4;
+        size -= 4;
+    } /*end if*/
+
+    if (flags & 4) { // contains creation time
+        if (size < 4) {
+            // qCDebug(KArchiveLog) << "premature end of extended timestamp (#4)";
+            return true;
+        } /*end if*/
+        pfi.ctime = uint((uchar)buffer[0] | (uchar)buffer[1] << 8 | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
+        buffer += 4;
+    } /*end if*/
+
+    pfi.exttimestamp_seen = true;
+    return true;
+}
+
+/** updates the parse information with the given Info-ZIP Unix old extra field.
+ * @param buffer start of content of buffer known to contain an Info-ZIP
+ *  Unix old extra field (without magic & size)
+ * @param size size of field content (must not count magic and size entries)
+ * @param islocal true if this is a local field, false if central
+ * @param pfi ParseFileInfo object to be updated
+ * @return true if processing was successful
+ */
+static bool parseInfoZipUnixOld(const char *buffer, int size, bool islocal, ParseFileInfo &pfi)
+{
+    // spec mandates to omit this field if one of the newer fields are available
+    if (pfi.exttimestamp_seen || pfi.newinfounix_seen) {
+        return true;
+    }
+
+    if (size < 8) {
+        // qCDebug(KArchiveLog) << "premature end of Info-ZIP unix extra field old";
+        return false;
+    }
+
+    pfi.atime = uint((uchar)buffer[0] | (uchar)buffer[1] << 8 | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
+    buffer += 4;
+    pfi.mtime = uint((uchar)buffer[0] | (uchar)buffer[1] << 8 | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
+    buffer += 4;
+    if (islocal && size >= 12) {
+        pfi.uid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
+        buffer += 2;
+        pfi.gid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
+        buffer += 2;
+    } /*end if*/
+    return true;
+}
+
+#if 0 // not needed yet
+/** updates the parse information with the given Info-ZIP Unix new extra field.
+ * @param buffer start of content of buffer known to contain an Info-ZIP
+ *      Unix new extra field (without magic & size)
+ * @param size size of field content (must not count magic and size entries)
+ * @param islocal true if this is a local field, false if central
+ * @param pfi ParseFileInfo object to be updated
+ * @return true if processing was successful
+ */
+static bool parseInfoZipUnixNew(const char *buffer, int size, bool islocal,
+                                ParseFileInfo &pfi)
+{
+    if (!islocal) { // contains nothing in central field
+        pfi.newinfounix = true;
+        return true;
+    }
+
+    if (size < 4) {
+        qCDebug(KArchiveLog) << "premature end of Info-ZIP unix extra field new";
+        return false;
+    }
+
+    pfi.uid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
+    buffer += 2;
+    pfi.gid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
+    buffer += 2;
+
+    pfi.newinfounix = true;
+    return true;
+}
+#endif
+
+/**
+ * parses the extra field
+ * @param buffer start of buffer where the extra field is to be found
+ * @param size size of the extra field
+ * @param islocal true if this is part of a local header, false if of central
+ * @param pfi ParseFileInfo object which to write the results into
+ * @return true if parsing was successful
+ */
+static bool parseExtraField(const char *buffer, int size, bool islocal, ParseFileInfo &pfi)
+{
+    // extra field in central directory doesn't contain useful data, so we
+    // don't bother parsing it
+    if (!islocal) {
+        return true;
+    }
+
+    while (size >= 4) { // as long as a potential extra field can be read
+        int magic = (uchar)buffer[0] | (uchar)buffer[1] << 8;
+        buffer += 2;
+        int fieldsize = (uchar)buffer[0] | (uchar)buffer[1] << 8;
+        buffer += 2;
+        size -= 4;
+
+        if (fieldsize > size) {
+            // qCDebug(KArchiveLog) << "fieldsize: " << fieldsize << " size: " << size;
+            // qCDebug(KArchiveLog) << "premature end of extra fields reached";
+            break;
+        }
+
+        switch (magic) {
+        case 0x0001: // ZIP64 extended file information
+            if (size >= 8) {
+                pfi.uncompressedSize = qFromLittleEndian(*reinterpret_cast(buffer));
+            }
+            if (size >= 16) {
+                pfi.compressedSize = qFromLittleEndian(*reinterpret_cast(buffer + 8));
+            }
+            break;
+        case 0x5455: // extended timestamp
+            if (!parseExtTimestamp(buffer, fieldsize, islocal, pfi)) {
+                return false;
+            }
+            break;
+        case 0x5855: // old Info-ZIP unix extra field
+            if (!parseInfoZipUnixOld(buffer, fieldsize, islocal, pfi)) {
+                return false;
+            }
+            break;
+#if 0 // not needed yet
+        case 0x7855:        // new Info-ZIP unix extra field
+            if (!parseInfoZipUnixNew(buffer, fieldsize, islocal, pfi)) {
+                return false;
+            }
+            break;
+#endif
+        default:
+            /* ignore everything else */
+            ;
+        } /*end switch*/
+
+        buffer += fieldsize;
+        size -= fieldsize;
+    } /*wend*/
+    return true;
+}
+
+/**
+ * Checks if a token for a central or local header has been found and resets
+ * the device to the begin of the token. If a token for the data descriptor is
+ * found it is assumed there is a central or local header token starting right
+ * behind the data descriptor, and the device is set accordingly to the begin
+ * of that token.
+ * To be called when a 'P' has been found.
+ * @param buffer start of buffer with the 3 bytes behind 'P'
+ * @param dev device that is read from
+ * @param dataDescriptor only search for data descriptor
+ * @return true if a local or central header begin is or could be reached
+ */
+static bool handlePossibleHeaderBegin(const char *buffer, QIODevice *dev, bool dataDescriptor)
+{
+    // we have to detect three magic tokens here:
+    // PK34 for the next local header in case there is no data descriptor
+    // PK12 for the central header in case there is no data descriptor
+    // PK78 for the data descriptor in case it is following the compressed data
+    // TODO: optimize using 32bit const data for comparison instead of byte-wise,
+    // given we run at least on 32bit CPUs
+
+    if (buffer[0] == 'K') {
+        if (buffer[1] == 7 && buffer[2] == 8) {
+            // data descriptor token found
+            dev->seek(dev->pos() + 12); // skip the 'data_descriptor'
+            return true;
+        }
+
+        if (!dataDescriptor
+            && ((buffer[1] == 1 && buffer[2] == 2) //
+                || (buffer[1] == 3 && buffer[2] == 4))) {
+            // central/local header token found
+            dev->seek(dev->pos() - 4);
+            // go back 4 bytes, so that the magic bytes can be found
+            // in the next cycle...
+            return true;
+        }
+    }
+    return false;
+}
+
+/**
+ * Reads the device forwards from the current pos until a token for a central or
+ * local header has been found or is to be assumed.
+ * @param dev device that is read from
+ * @return true if a local or central header token could be reached, false on error
+ */
+static bool seekToNextHeaderToken(QIODevice *dev, bool dataDescriptor)
+{
+    bool headerTokenFound = false;
+    char buffer[3];
+
+    while (!headerTokenFound) {
+        int n = dev->read(buffer, 1);
+        if (n < 1) {
+            // qCWarning(KArchiveLog) << "Invalid ZIP file. Unexpected end of file. (#2)";
+            return false;
+        }
+
+        if (buffer[0] != 'P') {
+            continue;
+        }
+
+        n = dev->read(buffer, 3);
+        if (n < 3) {
+            // qCWarning(KArchiveLog) << "Invalid ZIP file. Unexpected end of file. (#3)";
+            return false;
+        }
+
+        if (handlePossibleHeaderBegin(buffer, dev, dataDescriptor)) {
+            headerTokenFound = true;
+        } else {
+            for (int i = 0; i < 3; ++i) {
+                if (buffer[i] == 'P') {
+                    // We have another P character so we must go back a little to check if it is a magic
+                    dev->seek(dev->pos() - 3 + i);
+                    break;
+                }
+            }
+        }
+    }
+    return true;
+}
+
+////////////////////////////////////////////////////////////////////////
+/////////////////////////// KZip ///////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+class Q_DECL_HIDDEN KZip::KZipPrivate
+{
+public:
+    KZipPrivate()
+        : m_crc(0)
+        , m_currentFile(nullptr)
+        , m_currentDev(nullptr)
+        , m_compression(8)
+        , m_extraField(KZip::NoExtraField)
+        , m_offset(0)
+    {
+    }
+
+    unsigned long m_crc; // checksum
+    KZipFileEntry *m_currentFile; // file currently being written
+    QIODevice *m_currentDev; // filterdev used to write to the above file
+    QList m_fileList; // flat list of all files, for the index (saves a recursive method ;)
+    int m_compression;
+    KZip::ExtraField m_extraField;
+    // m_offset holds the offset of the place in the zip,
+    // where new data can be appended. after openarchive it points to 0, when in
+    // writeonly mode, or it points to the beginning of the central directory.
+    // each call to writefile updates this value.
+    quint64 m_offset;
+};
+
+KZip::KZip(const QString &fileName)
+    : KArchive(fileName)
+    , d(new KZipPrivate)
+{
+}
+
+KZip::KZip(QIODevice *dev)
+    : KArchive(dev)
+    , d(new KZipPrivate)
+{
+}
+
+KZip::~KZip()
+{
+    // qCDebug(KArchiveLog) << this;
+    if (isOpen()) {
+        close();
+    }
+    delete d;
+}
+
+bool KZip::openArchive(QIODevice::OpenMode mode)
+{
+    // qCDebug(KArchiveLog);
+    d->m_fileList.clear();
+
+    if (mode == QIODevice::WriteOnly) {
+        return true;
+    }
+
+    char buffer[47];
+
+    // Check that it's a valid ZIP file
+    // KArchive::open() opened the underlying device already.
+
+    quint64 offset = 0; // holds offset, where we read
+    // contains information gathered from the local file headers
+    QHash pfi_map;
+
+    QIODevice *dev = device();
+
+    // We set a bool for knowing if we are allowed to skip the start of the file
+    bool startOfFile = true;
+
+    for (;;) { // repeat until 'end of entries' signature is reached
+        // qCDebug(KArchiveLog) << "loop starts";
+        // qCDebug(KArchiveLog) << "dev->pos() now : " << dev->pos();
+        int n = dev->read(buffer, 4);
+
+        if (n < 4) {
+            setErrorString(tr("Invalid ZIP file. Unexpected end of file. (Error code: %1)").arg(1));
+            return false;
+        }
+
+        if (!memcmp(buffer, "PK\5\6", 4)) { // 'end of entries'
+            // qCDebug(KArchiveLog) << "PK56 found end of archive";
+            startOfFile = false;
+            break;
+        }
+
+        if (!memcmp(buffer, "PK\3\4", 4)) { // local file header
+            // qCDebug(KArchiveLog) << "PK34 found local file header";
+            startOfFile = false;
+            // can this fail ???
+            dev->seek(dev->pos() + 2); // skip 'version needed to extract'
+
+            // read static header stuff
+            n = dev->read(buffer, 24);
+            if (n < 24) {
+                setErrorString(tr("Invalid ZIP file. Unexpected end of file. (Error code: %1)").arg(4));
+                return false;
+            }
+
+            int gpf = (uchar)buffer[0]; // "general purpose flag" not "general protection fault" ;-)
+            int compression_mode = (uchar)buffer[2] | (uchar)buffer[3] << 8;
+            uint mtime = transformFromMsDos(buffer + 4);
+
+            const qint64 compr_size = uint(uchar(buffer[12])) | uint(uchar(buffer[13])) << 8 | uint(uchar(buffer[14])) << 16 | uint(uchar(buffer[15])) << 24;
+            const qint64 uncomp_size = uint(uchar(buffer[16])) | uint(uchar(buffer[17])) << 8 | uint(uchar(buffer[18])) << 16 | uint(uchar(buffer[19])) << 24;
+            const int namelen = uint(uchar(buffer[20])) | uint(uchar(buffer[21])) << 8;
+            const int extralen = uint(uchar(buffer[22])) | uint(uchar(buffer[23])) << 8;
+
+            /*
+              qCDebug(KArchiveLog) << "general purpose bit flag: " << gpf;
+              qCDebug(KArchiveLog) << "compressed size: " << compr_size;
+              qCDebug(KArchiveLog) << "uncompressed size: " << uncomp_size;
+              qCDebug(KArchiveLog) << "namelen: " << namelen;
+              qCDebug(KArchiveLog) << "extralen: " << extralen;
+              qCDebug(KArchiveLog) << "archive size: " << dev->size();
+            */
+
+            // read fileName
+            if (namelen <= 0) {
+                setErrorString(tr("Invalid ZIP file. Negative name length"));
+                return false;
+            }
+            QByteArray fileName = dev->read(namelen);
+            if (fileName.size() < namelen) {
+                setErrorString(tr("Invalid ZIP file. Name not completely read (#2)"));
+                return false;
+            }
+
+            ParseFileInfo pfi;
+            pfi.mtime = mtime;
+
+            // read and parse the beginning of the extra field,
+            // skip rest of extra field in case it is too long
+            unsigned int extraFieldEnd = dev->pos() + extralen;
+            pfi.extralen = extralen;
+            int handledextralen = qMin(extralen, (int)sizeof buffer);
+
+            // if (handledextralen)
+            //    qCDebug(KArchiveLog) << "handledextralen: " << handledextralen;
+
+            n = dev->read(buffer, handledextralen);
+            // no error msg necessary as we deliberately truncate the extra field
+            if (!parseExtraField(buffer, n, true, pfi)) {
+                setErrorString(tr("Invalid ZIP File. Broken ExtraField."));
+                return false;
+            }
+
+            // jump to end of extra field
+            dev->seek(extraFieldEnd);
+
+            // we have to take care of the 'general purpose bit flag'.
+            // if bit 3 is set, the header doesn't contain the length of
+            // the file and we look for the signature 'PK\7\8'.
+            if (gpf & 8) {
+                // here we have to read through the compressed data to find
+                // the next PKxx
+                if (!seekToNextHeaderToken(dev, true)) {
+                    setErrorString(tr("Could not seek to next header token"));
+                    return false;
+                }
+            } else {
+                // here we skip the compressed data and jump to the next header
+                // qCDebug(KArchiveLog) << "general purpose bit flag indicates, that local file header contains valid size";
+                bool foundSignature = false;
+                // check if this could be a symbolic link
+                if (compression_mode == NoCompression //
+                    && uncomp_size <= max_path_len //
+                    && uncomp_size > 0) {
+                    // read content and store it
+                    // If it's not a symlink, then we'll just discard the data for now.
+                    pfi.guessed_symlink = dev->read(uncomp_size);
+                    if (pfi.guessed_symlink.size() < uncomp_size) {
+                        setErrorString(tr("Invalid ZIP file. Unexpected end of file. (#5)"));
+                        return false;
+                    }
+                } else {
+                    if (compr_size > dev->size()) {
+                        // here we cannot trust the compressed size, so scan through the compressed
+                        // data to find the next header
+                        if (!seekToNextHeaderToken(dev, false)) {
+                            setErrorString(tr("Could not seek to next header token"));
+                            return false;
+                        }
+                        foundSignature = true;
+                    } else {
+                        //          qCDebug(KArchiveLog) << "before interesting dev->pos(): " << dev->pos();
+                        const bool success = dev->seek(dev->pos() + compr_size);
+                        if (!success) {
+                            setErrorString(tr("Could not seek to file compressed size"));
+                            return false;
+                        }
+                        /*          qCDebug(KArchiveLog) << "after interesting dev->pos(): " << dev->pos();
+                                                if (success)
+                                                qCDebug(KArchiveLog) << "dev->at was successful... ";
+                                                else
+                                                qCDebug(KArchiveLog) << "dev->at failed... ";*/
+                    }
+                }
+                // test for optional data descriptor
+                if (!foundSignature) {
+                    //                     qCDebug(KArchiveLog) << "Testing for optional data descriptor";
+                    // read static data descriptor
+                    n = dev->read(buffer, 4);
+                    if (n < 4) {
+                        setErrorString(tr("Invalid ZIP file. Unexpected end of file. (#1)"));
+                        return false;
+                    }
+
+                    if (buffer[0] != 'P' || !handlePossibleHeaderBegin(buffer + 1, dev, false)) {
+                        // assume data descriptor without signature
+                        dev->seek(dev->pos() + 8); // skip rest of the 'data_descriptor'
+                    }
+                }
+
+                // not needed any more
+                /*                // here we calculate the length of the file in the zip
+                // with headers and jump to the next header.
+                uint skip = compr_size + namelen + extralen;
+                offset += 30 + skip;*/
+            }
+            pfi_map.insert(fileName, pfi);
+        } else if (!memcmp(buffer, "PK\1\2", 4)) { // central block
+            // qCDebug(KArchiveLog) << "PK12 found central block";
+            startOfFile = false;
+
+            // so we reached the central header at the end of the zip file
+            // here we get all interesting data out of the central header
+            // of a file
+            offset = dev->pos() - 4;
+
+            // set offset for appending new files
+            if (d->m_offset == 0) {
+                d->m_offset = offset;
+            }
+
+            n = dev->read(buffer + 4, 42);
+            if (n < 42) {
+                setErrorString(tr("Invalid ZIP file, central entry too short (not long enough for valid entry)"));
+                return false;
+            }
+
+            // int gpf = (uchar)buffer[9] << 8 | (uchar)buffer[10];
+            // qCDebug(KArchiveLog) << "general purpose flag=" << gpf;
+            // length of the fileName (well, pathname indeed)
+            int namelen = (uchar)buffer[29] << 8 | (uchar)buffer[28];
+            if (namelen <= 0) {
+                setErrorString(tr("Invalid ZIP file, file path name length smaller or equal to zero"));
+                return false;
+            }
+            QByteArray bufferName = dev->read(namelen);
+            if (bufferName.size() < namelen) {
+                // qCWarning(KArchiveLog) << "Invalid ZIP file. Name not completely read";
+            }
+
+            ParseFileInfo pfi = pfi_map.value(bufferName, ParseFileInfo());
+
+            QString name(QFile::decodeName(bufferName));
+
+            // qCDebug(KArchiveLog) << "name: " << name;
+            // only in central header ! see below.
+            // length of extra attributes
+            int extralen = (uchar)buffer[31] << 8 | (uchar)buffer[30];
+            // length of comment for this file
+            int commlen = (uchar)buffer[33] << 8 | (uchar)buffer[32];
+            // compression method of this file
+            int cmethod = (uchar)buffer[11] << 8 | (uchar)buffer[10];
+
+            // qCDebug(KArchiveLog) << "cmethod: " << cmethod;
+            // qCDebug(KArchiveLog) << "extralen: " << extralen;
+
+            // crc32 of the file
+            uint crc32 = (uchar)buffer[19] << 24 | (uchar)buffer[18] << 16 | (uchar)buffer[17] << 8 | (uchar)buffer[16];
+
+            // uncompressed file size
+            quint64 ucsize = uint32_t((uchar)buffer[27] << 24 | (uchar)buffer[26] << 16 | (uchar)buffer[25] << 8 | (uchar)buffer[24]);
+            if (ucsize == 0xFFFFFFFF) {
+                ucsize = pfi.uncompressedSize;
+            }
+            // compressed file size
+            quint64 csize = uint32_t((uchar)buffer[23] << 24 | (uchar)buffer[22] << 16 | (uchar)buffer[21] << 8 | (uchar)buffer[20]);
+            if (csize == 0xFFFFFFFF) {
+                csize = pfi.compressedSize;
+            }
+
+            // offset of local header
+            uint localheaderoffset = (uchar)buffer[45] << 24 | (uchar)buffer[44] << 16 | (uchar)buffer[43] << 8 | (uchar)buffer[42];
+
+            // some clever people use different extra field lengths
+            // in the central header and in the local header... funny.
+            // so we need to get the localextralen to calculate the offset
+            // from localheaderstart to dataoffset
+            int localextralen = pfi.extralen; // FIXME: this will not work if
+            // no local header exists
+
+            // qCDebug(KArchiveLog) << "localextralen: " << localextralen;
+
+            // offset, where the real data for uncompression starts
+            uint dataoffset = localheaderoffset + 30 + localextralen + namelen; // comment only in central header
+
+            // qCDebug(KArchiveLog) << "csize: " << csize;
+
+            int os_madeby = (uchar)buffer[5];
+            bool isdir = false;
+            int access = 0100644;
+
+            if (os_madeby == 3) { // good ole unix
+                access = (uchar)buffer[40] | (uchar)buffer[41] << 8;
+            }
+
+            QString entryName;
+
+            if (name.endsWith(QLatin1Char('/'))) { // Entries with a trailing slash are directories
+                isdir = true;
+                name = name.left(name.length() - 1);
+                if (os_madeby != 3) {
+                    access = S_IFDIR | 0755;
+                } else {
+                    access |= S_IFDIR | 0700;
+                }
+            }
+
+            int pos = name.lastIndexOf(QLatin1Char('/'));
+            if (pos == -1) {
+                entryName = name;
+            } else {
+                entryName = name.mid(pos + 1);
+            }
+            if (entryName.isEmpty()) {
+                setErrorString(tr("Invalid ZIP file, found empty entry name"));
+                return false;
+            }
+
+            KArchiveEntry *entry;
+            if (isdir) {
+                QString path = QDir::cleanPath(name);
+                const KArchiveEntry *ent = rootDir()->entry(path);
+                if (ent && ent->isDirectory()) {
+                    // qCDebug(KArchiveLog) << "Directory already exists, NOT going to add it again";
+                    entry = nullptr;
+                } else {
+                    QDateTime mtime = KArchivePrivate::time_tToDateTime(pfi.mtime);
+                    entry = new KArchiveDirectory(this, entryName, access, mtime, rootDir()->user(), rootDir()->group(), QString());
+                    // qCDebug(KArchiveLog) << "KArchiveDirectory created, entryName= " << entryName << ", name=" << name;
+                }
+            } else {
+                QString symlink;
+                if ((access & QT_STAT_MASK) == QT_STAT_LNK) {
+                    symlink = QFile::decodeName(pfi.guessed_symlink);
+                }
+                QDateTime mtime = KArchivePrivate::time_tToDateTime(pfi.mtime);
+                entry =
+                    new KZipFileEntry(this, entryName, access, mtime, rootDir()->user(), rootDir()->group(), symlink, name, dataoffset, ucsize, cmethod, csize);
+                static_cast(entry)->setHeaderStart(localheaderoffset);
+                static_cast(entry)->setCRC32(crc32);
+                // qCDebug(KArchiveLog) << "KZipFileEntry created, entryName= " << entryName << ", name=" << name;
+                d->m_fileList.append(static_cast(entry));
+            }
+
+            if (entry) {
+                if (pos == -1) {
+                    rootDir()->addEntry(entry);
+                } else {
+                    // In some tar files we can find dir/./file => call cleanPath
+                    QString path = QDir::cleanPath(name.left(pos));
+                    // Ensure container directory exists, create otherwise
+                    KArchiveDirectory *tdir = findOrCreate(path);
+                    if (tdir) {
+                        tdir->addEntry(entry);
+                    } else {
+                        setErrorString(tr("File %1 is in folder %2, but %3 is actually a file.").arg(entryName, path, path));
+                        delete entry;
+                        return false;
+                    }
+                }
+            }
+
+            // calculate offset to next entry
+            offset += 46 + commlen + extralen + namelen;
+            const bool b = dev->seek(offset);
+            if (!b) {
+                setErrorString(tr("Could not seek to next entry"));
+                return false;
+            }
+        } else if (startOfFile) {
+            // The file does not start with any ZIP header (e.g. self-extractable ZIP files)
+            // Therefore we need to find the first PK\003\004 (local header)
+            // qCDebug(KArchiveLog) << "Try to skip start of file";
+            startOfFile = false;
+            bool foundSignature = false;
+
+            while (!foundSignature) {
+                n = dev->read(buffer, 1);
+                if (n < 1) {
+                    setErrorString(tr("Invalid ZIP file. Unexpected end of file."));
+                    return false;
+                }
+
+                if (buffer[0] != 'P') {
+                    continue;
+                }
+
+                n = dev->read(buffer, 3);
+                if (n < 3) {
+                    setErrorString(tr("Invalid ZIP file. Unexpected end of file."));
+                    return false;
+                }
+
+                // We have to detect the magic token for a local header: PK\003\004
+                /*
+                 * Note: we do not need to check the other magics, if the ZIP file has no
+                 * local header, then it has not any files!
+                 */
+                if (buffer[0] == 'K' && buffer[1] == 3 && buffer[2] == 4) {
+                    foundSignature = true;
+                    dev->seek(dev->pos() - 4); // go back 4 bytes, so that the magic bytes can be found...
+                } else {
+                    for (int i = 0; i < 3; ++i) {
+                        if (buffer[i] == 'P') {
+                            // We have another P character so we must go back a little to check if it is a magic
+                            dev->seek(dev->pos() - 3 + i);
+                            break;
+                        }
+                    }
+                }
+            }
+        } else {
+            setErrorString(tr("Invalid ZIP file. Unrecognized header at offset %1").arg(dev->pos() - 4));
+            return false;
+        }
+    }
+    // qCDebug(KArchiveLog) << "*** done *** ";
+    return true;
+}
+
+bool KZip::closeArchive()
+{
+    if (!(mode() & QIODevice::WriteOnly)) {
+        // qCDebug(KArchiveLog) << "readonly";
+        return true;
+    }
+
+    // ReadWrite or WriteOnly
+    // write all central dir file entries
+
+    // to be written at the end of the file...
+    char buffer[22]; // first used for 12, then for 22 at the end
+    uLong crc = crc32(0L, nullptr, 0);
+
+    qint64 centraldiroffset = device()->pos();
+    // qCDebug(KArchiveLog) << "closearchive: centraldiroffset: " << centraldiroffset;
+    qint64 atbackup = centraldiroffset;
+    QMutableListIterator it(d->m_fileList);
+
+    while (it.hasNext()) {
+        // set crc and compressed size in each local file header
+        it.next();
+        if (!device()->seek(it.value()->headerStart() + 14)) {
+            setErrorString(tr("Could not seek to next file header: %1").arg(device()->errorString()));
+            return false;
+        }
+        // qCDebug(KArchiveLog) << "closearchive setcrcandcsize: fileName:"
+        //    << it.value()->path()
+        //    << "encoding:" << it.value()->encoding();
+
+        uLong mycrc = it.value()->crc32();
+        buffer[0] = char(mycrc); // crc checksum, at headerStart+14
+        buffer[1] = char(mycrc >> 8);
+        buffer[2] = char(mycrc >> 16);
+        buffer[3] = char(mycrc >> 24);
+
+        int mysize1 = it.value()->compressedSize();
+        buffer[4] = char(mysize1); // compressed file size, at headerStart+18
+        buffer[5] = char(mysize1 >> 8);
+        buffer[6] = char(mysize1 >> 16);
+        buffer[7] = char(mysize1 >> 24);
+
+        int myusize = it.value()->size();
+        buffer[8] = char(myusize); // uncompressed file size, at headerStart+22
+        buffer[9] = char(myusize >> 8);
+        buffer[10] = char(myusize >> 16);
+        buffer[11] = char(myusize >> 24);
+
+        if (device()->write(buffer, 12) != 12) {
+            setErrorString(tr("Could not write file header: %1").arg(device()->errorString()));
+            return false;
+        }
+    }
+    device()->seek(atbackup);
+
+    it.toFront();
+    while (it.hasNext()) {
+        it.next();
+        // qCDebug(KArchiveLog) << "fileName:" << it.value()->path()
+        //              << "encoding:" << it.value()->encoding();
+
+        QByteArray path = QFile::encodeName(it.value()->path());
+
+        const int extra_field_len = (d->m_extraField == ModificationTime) ? 9 : 0;
+        const int bufferSize = extra_field_len + path.length() + 46;
+        char *buffer = new char[bufferSize];
+
+        memset(buffer, 0, 46); // zero is a nice default for most header fields
+
+        /* clang-format off */
+        const char head[] = {
+            'P', 'K', 1, 2, // central file header signature
+            0x14, 3, // version made by (3 == UNIX)
+            0x14, 0 // version needed to extract
+        };
+        /* clang-format on */
+
+        // I do not know why memcpy is not working here
+        // memcpy(buffer, head, sizeof(head));
+        memmove(buffer, head, sizeof(head));
+
+        buffer[10] = char(it.value()->encoding()); // compression method
+        buffer[11] = char(it.value()->encoding() >> 8);
+
+        transformToMsDos(it.value()->date(), &buffer[12]);
+
+        uLong mycrc = it.value()->crc32();
+        buffer[16] = char(mycrc); // crc checksum
+        buffer[17] = char(mycrc >> 8);
+        buffer[18] = char(mycrc >> 16);
+        buffer[19] = char(mycrc >> 24);
+
+        int mysize1 = it.value()->compressedSize();
+        buffer[20] = char(mysize1); // compressed file size
+        buffer[21] = char(mysize1 >> 8);
+        buffer[22] = char(mysize1 >> 16);
+        buffer[23] = char(mysize1 >> 24);
+
+        int mysize = it.value()->size();
+        buffer[24] = char(mysize); // uncompressed file size
+        buffer[25] = char(mysize >> 8);
+        buffer[26] = char(mysize >> 16);
+        buffer[27] = char(mysize >> 24);
+
+        buffer[28] = char(path.length()); // fileName length
+        buffer[29] = char(path.length() >> 8);
+
+        buffer[30] = char(extra_field_len);
+        buffer[31] = char(extra_field_len >> 8);
+
+        buffer[40] = char(it.value()->permissions());
+        buffer[41] = char(it.value()->permissions() >> 8);
+
+        int myhst = it.value()->headerStart();
+        buffer[42] = char(myhst); // relative offset of local header
+        buffer[43] = char(myhst >> 8);
+        buffer[44] = char(myhst >> 16);
+        buffer[45] = char(myhst >> 24);
+
+        // file name
+        strncpy(buffer + 46, path.constData(), path.length());
+        // qCDebug(KArchiveLog) << "closearchive length to write: " << bufferSize;
+
+        // extra field
+        if (d->m_extraField == ModificationTime) {
+            char *extfield = buffer + 46 + path.length();
+            // "Extended timestamp" header (0x5455)
+            extfield[0] = 'U';
+            extfield[1] = 'T';
+            extfield[2] = 5; // data size
+            extfield[3] = 0;
+            extfield[4] = 1 | 2 | 4; // specify flags from local field
+            // (unless I misread the spec)
+            // provide only modification time
+            unsigned long time = (unsigned long)it.value()->date().toSecsSinceEpoch();
+            extfield[5] = char(time);
+            extfield[6] = char(time >> 8);
+            extfield[7] = char(time >> 16);
+            extfield[8] = char(time >> 24);
+        }
+
+        crc = crc32(crc, (Bytef *)buffer, bufferSize);
+        bool ok = (device()->write(buffer, bufferSize) == bufferSize);
+        delete[] buffer;
+        if (!ok) {
+            setErrorString(tr("Could not write file header: %1").arg(device()->errorString()));
+            return false;
+        }
+    }
+    qint64 centraldirendoffset = device()->pos();
+    // qCDebug(KArchiveLog) << "closearchive: centraldirendoffset: " << centraldirendoffset;
+    // qCDebug(KArchiveLog) << "closearchive: device()->pos(): " << device()->pos();
+
+    // write end of central dir record.
+    buffer[0] = 'P'; // end of central dir signature
+    buffer[1] = 'K';
+    buffer[2] = 5;
+    buffer[3] = 6;
+
+    buffer[4] = 0; // number of this disk
+    buffer[5] = 0;
+
+    buffer[6] = 0; // number of disk with start of central dir
+    buffer[7] = 0;
+
+    int count = d->m_fileList.count();
+    // qCDebug(KArchiveLog) << "number of files (count): " << count;
+
+    buffer[8] = char(count); // total number of entries in central dir of
+    buffer[9] = char(count >> 8); // this disk
+
+    buffer[10] = buffer[8]; // total number of entries in the central dir
+    buffer[11] = buffer[9];
+
+    int cdsize = centraldirendoffset - centraldiroffset;
+    buffer[12] = char(cdsize); // size of the central dir
+    buffer[13] = char(cdsize >> 8);
+    buffer[14] = char(cdsize >> 16);
+    buffer[15] = char(cdsize >> 24);
+
+    // qCDebug(KArchiveLog) << "end : centraldiroffset: " << centraldiroffset;
+    // qCDebug(KArchiveLog) << "end : centraldirsize: " << cdsize;
+
+    buffer[16] = char(centraldiroffset); // central dir offset
+    buffer[17] = char(centraldiroffset >> 8);
+    buffer[18] = char(centraldiroffset >> 16);
+    buffer[19] = char(centraldiroffset >> 24);
+
+    buffer[20] = 0; // zipfile comment length
+    buffer[21] = 0;
+
+    if (device()->write(buffer, 22) != 22) {
+        setErrorString(tr("Could not write central dir record: %1").arg(device()->errorString()));
+        return false;
+    }
+
+    return true;
+}
+
+bool KZip::doWriteDir(const QString &name,
+                      const QString &user,
+                      const QString &group,
+                      mode_t perm,
+                      const QDateTime &atime,
+                      const QDateTime &mtime,
+                      const QDateTime &ctime)
+{
+    // Zip files have no explicit directories, they are implicitly created during extraction time
+    // when file entries have paths in them.
+    // However, to support empty directories, we must create a dummy file entry which ends with '/'.
+    QString dirName = name;
+    if (!name.endsWith(QLatin1Char('/'))) {
+        dirName = dirName.append(QLatin1Char('/'));
+    }
+    return writeFile(dirName, QByteArrayView(), perm, user, group, atime, mtime, ctime);
+}
+
+bool KZip::doPrepareWriting(const QString &name,
+                            const QString &user,
+                            const QString &group,
+                            qint64 /*size*/,
+                            mode_t perm,
+                            const QDateTime &accessTime,
+                            const QDateTime &modificationTime,
+                            const QDateTime &creationTime)
+{
+    // qCDebug(KArchiveLog);
+    if (!isOpen()) {
+        setErrorString(tr("Application error: ZIP file must be open before being written into"));
+        qCWarning(KArchiveLog) << "doPrepareWriting failed: !isOpen()";
+        return false;
+    }
+
+    if (!(mode() & QIODevice::WriteOnly)) { // accept WriteOnly and ReadWrite
+        setErrorString(tr("Application error: attempted to write into non-writable ZIP file"));
+        qCWarning(KArchiveLog) << "doPrepareWriting failed: !(mode() & QIODevice::WriteOnly)";
+        return false;
+    }
+
+    if (!device()) {
+        setErrorString(tr("Cannot create a device. Disk full?"));
+        return false;
+    }
+
+    // set right offset in zip.
+    if (!device()->seek(d->m_offset)) {
+        setErrorString(tr("Cannot seek in ZIP file. Disk full?"));
+        return false;
+    }
+
+    uint atime = accessTime.toSecsSinceEpoch();
+    uint mtime = modificationTime.toSecsSinceEpoch();
+    uint ctime = creationTime.toSecsSinceEpoch();
+
+    // Find or create parent dir
+    KArchiveDirectory *parentDir = rootDir();
+    QString fileName(name);
+    int i = name.lastIndexOf(QLatin1Char('/'));
+    if (i != -1) {
+        QString dir = name.left(i);
+        fileName = name.mid(i + 1);
+        // qCDebug(KArchiveLog) << "ensuring" << dir << "exists. fileName=" << fileName;
+        parentDir = findOrCreate(dir);
+    }
+
+    // delete entries in the filelist with the same fileName as the one we want
+    // to save, so that we don't have duplicate file entries when viewing the zip
+    // with konqi...
+    // CAUTION: the old file itself is still in the zip and won't be removed !!!
+    QMutableListIterator it(d->m_fileList);
+    // qCDebug(KArchiveLog) << "fileName to write: " << name;
+    while (it.hasNext()) {
+        it.next();
+        // qCDebug(KArchiveLog) << "prepfileName: " << it.value()->path();
+        if (name == it.value()->path()) {
+            // also remove from the parentDir
+            parentDir->removeEntry(it.value());
+            // qCDebug(KArchiveLog) << "removing following entry: " << it.value()->path();
+            delete it.value();
+            it.remove();
+        }
+    }
+
+    // construct a KZipFileEntry and add it to list
+    KZipFileEntry *e = new KZipFileEntry(this,
+                                         fileName,
+                                         perm,
+                                         modificationTime,
+                                         user,
+                                         group,
+                                         QString(),
+                                         name,
+                                         device()->pos() + 30 + name.length(), // start
+                                         0 /*size unknown yet*/,
+                                         d->m_compression,
+                                         0 /*csize unknown yet*/);
+    e->setHeaderStart(device()->pos());
+    // qCDebug(KArchiveLog) << "wrote file start: " << e->position() << " name: " << name;
+    if (!parentDir->addEntryV2(e)) {
+        return false;
+    }
+
+    d->m_currentFile = e;
+    d->m_fileList.append(e);
+
+    int extra_field_len = 0;
+    if (d->m_extraField == ModificationTime) {
+        extra_field_len = 17; // value also used in finishWriting()
+    }
+
+    // write out zip header
+    QByteArray encodedName = QFile::encodeName(name);
+    int bufferSize = extra_field_len + encodedName.length() + 30;
+    // qCDebug(KArchiveLog) << "bufferSize=" << bufferSize;
+    char *buffer = new char[bufferSize];
+
+    buffer[0] = 'P'; // local file header signature
+    buffer[1] = 'K';
+    buffer[2] = 3;
+    buffer[3] = 4;
+
+    buffer[4] = 0x14; // version needed to extract
+    buffer[5] = 0;
+
+    buffer[6] = 0; // general purpose bit flag
+    buffer[7] = 0;
+
+    buffer[8] = char(e->encoding()); // compression method
+    buffer[9] = char(e->encoding() >> 8);
+
+    transformToMsDos(e->date(), &buffer[10]);
+
+    buffer[14] = 'C'; // dummy crc
+    buffer[15] = 'R';
+    buffer[16] = 'C';
+    buffer[17] = 'q';
+
+    buffer[18] = 'C'; // compressed file size
+    buffer[19] = 'S';
+    buffer[20] = 'I';
+    buffer[21] = 'Z';
+
+    buffer[22] = 'U'; // uncompressed file size
+    buffer[23] = 'S';
+    buffer[24] = 'I';
+    buffer[25] = 'Z';
+
+    buffer[26] = (uchar)(encodedName.length()); // fileName length
+    buffer[27] = (uchar)(encodedName.length() >> 8);
+
+    buffer[28] = (uchar)(extra_field_len); // extra field length
+    buffer[29] = (uchar)(extra_field_len >> 8);
+
+    // file name
+    strncpy(buffer + 30, encodedName.constData(), encodedName.length());
+
+    // extra field
+    if (d->m_extraField == ModificationTime) {
+        char *extfield = buffer + 30 + encodedName.length();
+        // "Extended timestamp" header (0x5455)
+        extfield[0] = 'U';
+        extfield[1] = 'T';
+        extfield[2] = 13; // data size
+        extfield[3] = 0;
+        extfield[4] = 1 | 2 | 4; // contains mtime, atime, ctime
+
+        extfield[5] = char(mtime);
+        extfield[6] = char(mtime >> 8);
+        extfield[7] = char(mtime >> 16);
+        extfield[8] = char(mtime >> 24);
+
+        extfield[9] = char(atime);
+        extfield[10] = char(atime >> 8);
+        extfield[11] = char(atime >> 16);
+        extfield[12] = char(atime >> 24);
+
+        extfield[13] = char(ctime);
+        extfield[14] = char(ctime >> 8);
+        extfield[15] = char(ctime >> 16);
+        extfield[16] = char(ctime >> 24);
+    }
+
+    // Write header
+    bool b = (device()->write(buffer, bufferSize) == bufferSize);
+    d->m_crc = 0;
+    delete[] buffer;
+
+    if (!b) {
+        setErrorString(tr("Could not write to the archive. Disk full?"));
+        return false;
+    }
+
+    // Prepare device for writing the data
+    // Either device() if no compression, or a KCompressionDevice to compress
+    if (d->m_compression == 0) {
+        d->m_currentDev = device();
+        return true;
+    }
+
+    auto compressionDevice = new KCompressionDevice(device(), false, KCompressionDevice::GZip);
+    d->m_currentDev = compressionDevice;
+    compressionDevice->setSkipHeaders(); // Just zlib, not gzip
+
+    b = d->m_currentDev->open(QIODevice::WriteOnly);
+    Q_ASSERT(b);
+
+    if (!b) {
+        setErrorString(tr("Could not open compression device: %1").arg(d->m_currentDev->errorString()));
+    }
+
+    return b;
+}
+
+bool KZip::doFinishWriting(qint64 size)
+{
+    if (d->m_currentFile->encoding() == 8) {
+        // Finish
+        (void)d->m_currentDev->write(nullptr, 0);
+        delete d->m_currentDev;
+    }
+    // If 0, d->m_currentDev was device() - don't delete ;)
+    d->m_currentDev = nullptr;
+
+    Q_ASSERT(d->m_currentFile);
+    // qCDebug(KArchiveLog) << "fileName: " << d->m_currentFile->path();
+    // qCDebug(KArchiveLog) << "getpos (at): " << device()->pos();
+    d->m_currentFile->setSize(size);
+    int extra_field_len = 0;
+    if (d->m_extraField == ModificationTime) {
+        extra_field_len = 17; // value also used in finishWriting()
+    }
+
+    const QByteArray encodedName = QFile::encodeName(d->m_currentFile->path());
+    int csize = device()->pos() - d->m_currentFile->headerStart() - 30 - encodedName.length() - extra_field_len;
+    d->m_currentFile->setCompressedSize(csize);
+    // qCDebug(KArchiveLog) << "usize: " << d->m_currentFile->size();
+    // qCDebug(KArchiveLog) << "csize: " << d->m_currentFile->compressedSize();
+    // qCDebug(KArchiveLog) << "headerstart: " << d->m_currentFile->headerStart();
+
+    // qCDebug(KArchiveLog) << "crc: " << d->m_crc;
+    d->m_currentFile->setCRC32(d->m_crc);
+
+    d->m_currentFile = nullptr;
+
+    // update saved offset for appending new files
+    d->m_offset = device()->pos();
+    return true;
+}
+
+bool KZip::doWriteSymLink(const QString &name,
+                          const QString &target,
+                          const QString &user,
+                          const QString &group,
+                          mode_t perm,
+                          const QDateTime &atime,
+                          const QDateTime &mtime,
+                          const QDateTime &ctime)
+{
+    // reassure that symlink flag is set, otherwise strange things happen on
+    // extraction
+    perm |= QT_STAT_LNK;
+    Compression c = compression();
+    setCompression(NoCompression); // link targets are never compressed
+
+    if (!doPrepareWriting(name, user, group, 0, perm, atime, mtime, ctime)) {
+        setCompression(c);
+        return false;
+    }
+
+    QByteArray symlink_target = QFile::encodeName(target);
+    if (!writeData(symlink_target.constData(), symlink_target.length())) {
+        setCompression(c);
+        return false;
+    }
+
+    if (!finishWriting(symlink_target.length())) {
+        setCompression(c);
+        return false;
+    }
+
+    setCompression(c);
+    return true;
+}
+
+void KZip::virtual_hook(int id, void *data)
+{
+    KArchive::virtual_hook(id, data);
+}
+
+bool KZip::doWriteData(const char *data, qint64 size)
+{
+    Q_ASSERT(d->m_currentFile);
+    Q_ASSERT(d->m_currentDev);
+    if (!d->m_currentFile || !d->m_currentDev) {
+        setErrorString(tr("No file or device"));
+        return false;
+    }
+
+    // crc to be calculated over uncompressed stuff...
+    // and they didn't mention it in their docs...
+    d->m_crc = crc32(d->m_crc, (const Bytef *)data, size);
+
+    qint64 written = d->m_currentDev->write(data, size);
+    // qCDebug(KArchiveLog) << "wrote" << size << "bytes.";
+    const bool ok = written == size;
+
+    if (!ok) {
+        setErrorString(tr("Error writing data: %1").arg(d->m_currentDev->errorString()));
+    }
+
+    return ok;
+}
+
+void KZip::setCompression(Compression c)
+{
+    d->m_compression = (c == NoCompression) ? 0 : 8;
+}
+
+KZip::Compression KZip::compression() const
+{
+    return (d->m_compression == 8) ? DeflateCompression : NoCompression;
+}
+
+void KZip::setExtraField(ExtraField ef)
+{
+    d->m_extraField = ef;
+}
+
+KZip::ExtraField KZip::extraField() const
+{
+    return d->m_extraField;
+}
+
+////////////////////////////////////////////////////////////////////////
+////////////////////// KZipFileEntry////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+class Q_DECL_HIDDEN KZipFileEntry::KZipFileEntryPrivate
+{
+public:
+    KZipFileEntryPrivate()
+        : crc(0)
+        , compressedSize(0)
+        , headerStart(0)
+        , encoding(0)
+    {
+    }
+    unsigned long crc;
+    qint64 compressedSize;
+    qint64 headerStart;
+    int encoding;
+    QString path;
+};
+
+KZipFileEntry::KZipFileEntry(KZip *zip,
+                             const QString &name,
+                             int access,
+                             const QDateTime &date,
+                             const QString &user,
+                             const QString &group,
+                             const QString &symlink,
+                             const QString &path,
+                             qint64 start,
+                             qint64 uncompressedSize,
+                             int encoding,
+                             qint64 compressedSize)
+    : KArchiveFile(zip, name, access, date, user, group, symlink, start, uncompressedSize)
+    , d(new KZipFileEntryPrivate)
+{
+    d->path = path;
+    d->encoding = encoding;
+    d->compressedSize = compressedSize;
+}
+
+KZipFileEntry::~KZipFileEntry()
+{
+    delete d;
+}
+
+int KZipFileEntry::encoding() const
+{
+    return d->encoding;
+}
+
+qint64 KZipFileEntry::compressedSize() const
+{
+    return d->compressedSize;
+}
+
+void KZipFileEntry::setCompressedSize(qint64 compressedSize)
+{
+    d->compressedSize = compressedSize;
+}
+
+void KZipFileEntry::setHeaderStart(qint64 headerstart)
+{
+    d->headerStart = headerstart;
+}
+
+qint64 KZipFileEntry::headerStart() const
+{
+    return d->headerStart;
+}
+
+unsigned long KZipFileEntry::crc32() const
+{
+    return d->crc;
+}
+
+void KZipFileEntry::setCRC32(unsigned long crc32)
+{
+    d->crc = crc32;
+}
+
+const QString &KZipFileEntry::path() const
+{
+    return d->path;
+}
+
+QByteArray KZipFileEntry::data() const
+{
+    QIODevice *dev = createDevice();
+    QByteArray arr;
+    if (dev) {
+        arr = dev->readAll();
+        delete dev;
+    }
+    return arr;
+}
+
+QIODevice *KZipFileEntry::createDevice() const
+{
+    // qCDebug(KArchiveLog) << "creating iodevice limited to pos=" << position() << ", csize=" << compressedSize();
+    // Limit the reading to the appropriate part of the underlying device (e.g. file)
+    KLimitedIODevice *limitedDev = new KLimitedIODevice(archive()->device(), position(), compressedSize());
+    if (encoding() == 0 || compressedSize() == 0) { // no compression (or even no data)
+        return limitedDev;
+    }
+
+    if (encoding() == 8) {
+        // On top of that, create a device that uncompresses the zlib data
+        KCompressionDevice *filterDev = new KCompressionDevice(limitedDev, true, KCompressionDevice::GZip);
+
+        if (!filterDev) {
+            return nullptr; // ouch
+        }
+        filterDev->setSkipHeaders(); // Just zlib, not gzip
+        bool b = filterDev->open(QIODevice::ReadOnly);
+        Q_UNUSED(b);
+        Q_ASSERT(b);
+        return filterDev;
+    }
+
+    qCCritical(KArchiveLog) << "This zip file contains files compressed with method" << encoding() << ", this method is currently not supported by KZip,"
+                            << "please use a command-line tool to handle this file.";
+    delete limitedDev;
+    return nullptr;
+}
diff --git a/src/libs/3rdparty/karchive/src/kzip.h b/src/libs/3rdparty/karchive/src/kzip.h
new file mode 100644
index 00000000000..da84285ba9a
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kzip.h
@@ -0,0 +1,178 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2002 Holger Schroeder 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+#ifndef KZIP_H
+#define KZIP_H
+
+#include "karchive.h"
+
+#include "kzipfileentry.h" // for source compat
+
+class KZipFileEntry;
+/**
+ *   @class KZip zip.h KZip
+ *
+ *   A class for reading / writing zip archives.
+ *
+ *   You can use it in QIODevice::ReadOnly or in QIODevice::WriteOnly mode, and it
+ *   behaves just as expected.
+ *   It can also be used in QIODevice::ReadWrite mode, in this case one can
+ *   append files to an existing zip archive. When you append new files, which
+ *   are not yet in the zip, it works as expected, i.e. the files are appended at the end.
+ *   When you append a file, which is already in the file, the reference to the
+ *   old file is dropped and the new one is added to the zip - but the
+ *   old data from the file itself is not deleted, it is still in the
+ *   zipfile. So when you want to have a small and garbage-free zipfile,
+ *   just read the contents of the appended zip file and write it to a new one
+ *   in QIODevice::WriteOnly mode. This is especially important when you don't want
+ *   to leak information of how intermediate versions of files in the zip
+ *   were looking.
+ *
+ *   For more information on the zip fileformat go to
+ *   http://www.pkware.com/products/enterprise/white_papers/appnote.html
+ * @author Holger Schroeder 
+ */
+class KARCHIVE_EXPORT KZip : public KArchive
+{
+    Q_DECLARE_TR_FUNCTIONS(KZip)
+
+public:
+    /**
+     * Creates an instance that operates on the given filename.
+     * using the compression filter associated to given mimetype.
+     *
+     * @param filename is a local path (e.g. "/home/holger/myfile.zip")
+     */
+    explicit KZip(const QString &filename);
+
+    /**
+     * Creates an instance that operates on the given device.
+     * The device can be compressed (KCompressionDevice) or not (QFile, etc.).
+     * @warning Do not assume that giving a QFile here will decompress the file,
+     * in case it's compressed!
+     * @param dev the device to access
+     */
+    explicit KZip(QIODevice *dev);
+
+    /**
+     * If the zip file is still opened, then it will be
+     * closed automatically by the destructor.
+     */
+    ~KZip() override;
+
+    /**
+     * Describes the contents of the "extra field" for a given file in the Zip archive.
+     */
+    enum ExtraField {
+        NoExtraField = 0,      ///< No extra field
+        ModificationTime = 1,  ///< Modification time ("extended timestamp" header)
+        DefaultExtraField = 1, // alias of ModificationTime
+    };
+
+    /**
+     * Call this before writeFile or prepareWriting, to define what the next
+     * file to be written should have in its extra field.
+     * @param ef the type of "extra field"
+     * @see extraField()
+     */
+    void setExtraField(ExtraField ef);
+
+    /**
+     * The current type of "extra field" that will be used for new files.
+     * @return the current type of "extra field"
+     * @see setExtraField()
+     */
+    ExtraField extraField() const;
+
+    /**
+     * Describes the compression type for a given file in the Zip archive.
+     */
+    enum Compression {
+        NoCompression = 0,      ///< Uncompressed.
+        DeflateCompression = 1, ///< Deflate compression method.
+    };
+
+    /**
+     * Call this before writeFile or prepareWriting, to define whether the next
+     * files to be written should be compressed or not.
+     * @param c the new compression mode
+     * @see compression()
+     */
+    void setCompression(Compression c);
+
+    /**
+     * The current compression mode that will be used for new files.
+     * @return the current compression mode
+     * @see setCompression()
+     */
+    Compression compression() const;
+
+protected:
+    /// Reimplemented from KArchive
+    bool doWriteSymLink(
+        const QString &name,
+        const QString &target,
+        const QString &user,
+        const QString &group,
+        mode_t perm,
+        const QDateTime &atime,
+        const QDateTime &mtime,
+        const QDateTime &ctime) override;
+    /// Reimplemented from KArchive
+    bool doPrepareWriting(
+        const QString &name,
+        const QString &user,
+        const QString &group,
+        qint64 size,
+        mode_t perm,
+        const QDateTime &atime,
+        const QDateTime &mtime,
+        const QDateTime &creationTime) override;
+
+    /**
+     * Write data to a file that has been created using prepareWriting().
+     * @param size the size of the file
+     * @return true if successful, false otherwise
+     */
+    bool doFinishWriting(qint64 size) override;
+
+    /**
+     * Write data to a file that has been created using prepareWriting().
+     * @param data a pointer to the data
+     * @param size the size of the chunk
+     * @return true if successful, false otherwise
+     */
+    bool doWriteData(const char *data, qint64 size) override;
+
+    /**
+     * Opens the archive for reading.
+     * Parses the directory listing of the archive
+     * and creates the KArchiveDirectory/KArchiveFile entries.
+     * @param mode the mode of the file
+     */
+    bool openArchive(QIODevice::OpenMode mode) override;
+
+    /// Closes the archive
+    bool closeArchive() override;
+
+    /// Reimplemented from KArchive
+    bool doWriteDir(
+        const QString &name,
+        const QString &user,
+        const QString &group,
+        mode_t perm,
+        const QDateTime &atime,
+        const QDateTime &mtime,
+        const QDateTime &ctime) override;
+
+protected:
+    void virtual_hook(int id, void *data) override;
+
+private:
+    class KZipPrivate;
+    KZipPrivate *const d;
+};
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/kzipfileentry.h b/src/libs/3rdparty/karchive/src/kzipfileentry.h
new file mode 100644
index 00000000000..c7c74e59561
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kzipfileentry.h
@@ -0,0 +1,79 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2002 Holger Schroeder 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KZIPFILEENTRY_H
+#define KZIPFILEENTRY_H
+
+#include "karchive.h"
+
+class KZip;
+/**
+ * @class KZipFileEntry kzipfileentry.h KZipFileEntry
+ *
+ * A KZipFileEntry represents a file in a zip archive.
+ */
+class KARCHIVE_EXPORT KZipFileEntry : public KArchiveFile
+{
+public:
+    /**
+     * Creates a new zip file entry. Do not call this, KZip takes care of it.
+     */
+    KZipFileEntry(KZip *zip,
+                  const QString &name,
+                  int access,
+                  const QDateTime &date,
+                  const QString &user,
+                  const QString &group,
+                  const QString &symlink,
+                  const QString &path,
+                  qint64 start,
+                  qint64 uncompressedSize,
+                  int encoding,
+                  qint64 compressedSize);
+
+    /**
+     * Destructor. Do not call this.
+     */
+    ~KZipFileEntry() override;
+
+    int encoding() const;
+    qint64 compressedSize() const;
+
+    /// Only used when writing
+    void setCompressedSize(qint64 compressedSize);
+
+    /// Header start: only used when writing
+    void setHeaderStart(qint64 headerstart);
+    qint64 headerStart() const;
+
+    /// CRC: only used when writing
+    unsigned long crc32() const;
+    void setCRC32(unsigned long crc32);
+
+    /// Name with complete path - KArchiveFile::name() is the filename only (no path)
+    const QString &path() const;
+
+    /**
+     * @return the content of this file.
+     * Call data() with care (only once per file), this data isn't cached.
+     */
+    QByteArray data() const override;
+
+    /**
+     * This method returns a QIODevice to read the file contents.
+     * This is obviously for reading only.
+     * Note that the ownership of the device is being transferred to the caller,
+     * who will have to delete it.
+     * The returned device auto-opens (in readonly mode), no need to open it.
+     */
+    QIODevice *createDevice() const override;
+
+private:
+    class KZipFileEntryPrivate;
+    KZipFileEntryPrivate *const d;
+};
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/kzstdfilter.cpp b/src/libs/3rdparty/karchive/src/kzstdfilter.cpp
new file mode 100644
index 00000000000..cf28368a5b8
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kzstdfilter.cpp
@@ -0,0 +1,134 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2021 Albert Astals Cid 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "kzstdfilter.h"
+#include "loggingcategory.h"
+
+#include 
+
+#if HAVE_ZSTD_SUPPORT
+
+extern "C" {
+#include 
+}
+
+class Q_DECL_HIDDEN KZstdFilter::Private
+{
+public:
+    union {
+        ZSTD_CStream *cStream;
+        ZSTD_DStream *dStream;
+    };
+    int mode;
+    bool isInitialized = false;
+    ZSTD_inBuffer inBuffer;
+    ZSTD_outBuffer outBuffer;
+};
+
+KZstdFilter::KZstdFilter()
+    : d(new Private)
+{
+}
+
+KZstdFilter::~KZstdFilter()
+{
+}
+
+bool KZstdFilter::init(int mode)
+{
+    if (d->isInitialized) {
+        terminate();
+    }
+
+    d->inBuffer.size = 0;
+    d->inBuffer.pos = 0;
+
+    if (mode == QIODevice::ReadOnly) {
+        d->dStream = ZSTD_createDStream();
+    } else if (mode == QIODevice::WriteOnly) {
+        d->cStream = ZSTD_createCStream();
+    } else {
+        // qCWarning(KArchiveLog) << "Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
+        return false;
+    }
+    d->mode = mode;
+    d->isInitialized = true;
+    return true;
+}
+
+int KZstdFilter::mode() const
+{
+    return d->mode;
+}
+
+bool KZstdFilter::terminate()
+{
+    if (d->mode == QIODevice::ReadOnly) {
+        ZSTD_freeDStream(d->dStream);
+    } else if (d->mode == QIODevice::WriteOnly) {
+        ZSTD_freeCStream(d->cStream);
+    } else {
+        // qCWarning(KArchiveLog) << "Unsupported mode " << d->mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
+        return false;
+    }
+    d->isInitialized = false;
+    return true;
+}
+
+void KZstdFilter::reset()
+{
+    terminate();
+    init(d->mode);
+}
+
+void KZstdFilter::setOutBuffer(char *data, uint maxlen)
+{
+    d->outBuffer.dst = data;
+    d->outBuffer.size = maxlen;
+    d->outBuffer.pos = 0;
+}
+
+void KZstdFilter::setInBuffer(const char *data, unsigned int size)
+{
+    d->inBuffer.src = data;
+    d->inBuffer.size = size;
+    d->inBuffer.pos = 0;
+}
+
+int KZstdFilter::inBufferAvailable() const
+{
+    return d->inBuffer.size - d->inBuffer.pos;
+}
+
+int KZstdFilter::outBufferAvailable() const
+{
+    return d->outBuffer.size - d->outBuffer.pos;
+}
+
+KZstdFilter::Result KZstdFilter::uncompress()
+{
+    // qCDebug(KArchiveLog) << "Calling ZSTD_decompressStream with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
+    const size_t result = ZSTD_decompressStream(d->dStream, &d->outBuffer, &d->inBuffer);
+    if (ZSTD_isError(result)) {
+        qCWarning(KArchiveLog) << "ZSTD_decompressStream returned" << result << ZSTD_getErrorName(result);
+        return KFilterBase::Error;
+    }
+
+    return result == 0 ? KFilterBase::End : KFilterBase::Ok;
+}
+
+KZstdFilter::Result KZstdFilter::compress(bool finish)
+{
+    // qCDebug(KArchiveLog) << "Calling ZSTD_compressStream2 with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
+    const size_t result = ZSTD_compressStream2(d->cStream, &d->outBuffer, &d->inBuffer, finish ? ZSTD_e_end : ZSTD_e_continue);
+    if (ZSTD_isError(result)) {
+        return KFilterBase::Error;
+    }
+
+    return finish && result == 0 ? KFilterBase::End : KFilterBase::Ok;
+}
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/kzstdfilter.h b/src/libs/3rdparty/karchive/src/kzstdfilter.h
new file mode 100644
index 00000000000..a61c0e96c2c
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/kzstdfilter.h
@@ -0,0 +1,46 @@
+/* This file is part of the KDE libraries
+   SPDX-FileCopyrightText: 2021 Albert Astals Cid 
+
+   SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KZSTDFILTER_H
+#define KZSTDFILTER_H
+
+#if HAVE_ZSTD_SUPPORT
+
+#include "kfilterbase.h"
+
+#include 
+
+/**
+ * Internal class used by KCompressionDevice
+ * @internal
+ */
+class KZstdFilter : public KFilterBase
+{
+public:
+    KZstdFilter();
+    ~KZstdFilter() override;
+
+    bool init(int) override;
+    int mode() const override;
+    bool terminate() override;
+    void reset() override;
+    bool readHeader() override { return true; }
+    bool writeHeader(const QByteArray &) override { return true; }
+    void setOutBuffer(char *data, uint maxlen) override;
+    void setInBuffer(const char *data, uint size) override;
+    int inBufferAvailable() const override;
+    int outBufferAvailable() const override;
+    Result uncompress() override;
+    Result compress(bool finish) override;
+
+private:
+    class Private;
+    const std::unique_ptr d;
+};
+
+#endif
+
+#endif
diff --git a/src/libs/3rdparty/karchive/src/loggingcategory.cpp b/src/libs/3rdparty/karchive/src/loggingcategory.cpp
new file mode 100644
index 00000000000..0b40e483c15
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/loggingcategory.cpp
@@ -0,0 +1,3 @@
+#include "loggingcategory.h"
+
+Q_LOGGING_CATEGORY(KArchiveLog, "kf.archive", QtWarningMsg)
diff --git a/src/libs/3rdparty/karchive/src/loggingcategory.h b/src/libs/3rdparty/karchive/src/loggingcategory.h
new file mode 100644
index 00000000000..a05b84da4a3
--- /dev/null
+++ b/src/libs/3rdparty/karchive/src/loggingcategory.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include 
+
+Q_DECLARE_LOGGING_CATEGORY(KArchiveLog)