xz-clib 5.6.4 → 5.8.0
raw patch · 57 files changed
+2008/−681 lines, 57 files
Files
- Changelog.md +4/−0
- cbits/common/my_landlock.h +141/−0
- cbits/common/sysdefs.h +21/−5
- cbits/common/tuklib_common.h +8/−3
- cbits/common/tuklib_gettext.h +11/−0
- cbits/common/tuklib_mbstr.h +19/−6
- cbits/common/tuklib_mbstr_nonprint.c +162/−0
- cbits/common/tuklib_mbstr_nonprint.h +71/−0
- cbits/common/tuklib_mbstr_width.c +17/−4
- cbits/common/tuklib_mbstr_wrap.c +294/−0
- cbits/common/tuklib_mbstr_wrap.h +204/−0
- cbits/common/tuklib_physmem.c +2/−9
- cbits/config.h.in +3/−0
- cbits/liblzma/api/lzma/bcj.h +97/−0
- cbits/liblzma/api/lzma/container.h +1/−1
- cbits/liblzma/api/lzma/version.h +2/−2
- cbits/liblzma/check/check.h +0/−18
- cbits/liblzma/check/crc32_arm64.h +40/−15
- cbits/liblzma/check/crc32_fast.c +19/−27
- cbits/liblzma/check/crc32_loongarch.h +65/−0
- cbits/liblzma/check/crc32_small.c +3/−0
- cbits/liblzma/check/crc32_table.c +0/−42
- cbits/liblzma/check/crc64_fast.c +26/−13
- cbits/liblzma/check/crc64_table.c +0/−37
- cbits/liblzma/check/crc_clmul_consts_gen.c +160/−0
- cbits/liblzma/check/crc_common.h +72/−39
- cbits/liblzma/check/crc_x86_clmul.h +227/−282
- cbits/liblzma/common/alone_decoder.c +1/−2
- cbits/liblzma/common/auto_decoder.c +2/−3
- cbits/liblzma/common/block_decoder.c +2/−4
- cbits/liblzma/common/block_encoder.c +2/−4
- cbits/liblzma/common/common.c +1/−1
- cbits/liblzma/common/file_info.c +9/−13
- cbits/liblzma/common/index_decoder.c +3/−6
- cbits/liblzma/common/index_encoder.c +2/−4
- cbits/liblzma/common/index_hash.c +3/−4
- cbits/liblzma/common/lzip_decoder.c +5/−9
- cbits/liblzma/common/memcmplen.h +1/−2
- cbits/liblzma/common/stream_decoder.c +6/−10
- cbits/liblzma/common/stream_decoder_mt.c +9/−16
- cbits/liblzma/common/stream_encoder_mt.c +4/−6
- cbits/liblzma/common/string_conversion.c +59/−38
- cbits/liblzma/lz/lz_decoder.c +15/−6
- cbits/liblzma/lz/lz_decoder.h +89/−14
- cbits/liblzma/lz/lz_encoder.c +1/−1
- cbits/liblzma/lz/lz_encoder_hash.h +22/−8
- cbits/liblzma/lzma/lzma2_encoder.c +3/−6
- cbits/liblzma/simple/arm.c +3/−1
- cbits/liblzma/simple/arm64.c +21/−1
- cbits/liblzma/simple/armthumb.c +6/−1
- cbits/liblzma/simple/ia64.c +3/−1
- cbits/liblzma/simple/powerpc.c +3/−1
- cbits/liblzma/simple/riscv.c +18/−0
- cbits/liblzma/simple/sparc.c +3/−2
- cbits/liblzma/simple/x86.c +24/−0
- configure +15/−11
- xz-clib.cabal +4/−3
Changelog.md view
@@ -1,3 +1,7 @@+## 5.8.0++* Update to 5.8.0 upstream sources+ ## 5.6.3 * Update to 5.6.3 upstream sources
+ cbits/common/my_landlock.h view
@@ -0,0 +1,141 @@+// SPDX-License-Identifier: 0BSD++///////////////////////////////////////////////////////////////////////////////+//+/// \file my_landlock.h+/// \brief Linux Landlock sandbox helper functions+//+// Author: Lasse Collin+//+///////////////////////////////////////////////////////////////////////////////++#ifndef MY_LANDLOCK_H+#define MY_LANDLOCK_H++#include "sysdefs.h"++#include <linux/landlock.h>+#include <sys/syscall.h>+#include <sys/prctl.h>+++/// \brief Initialize Landlock ruleset attributes to forbid everything+///+/// The supported Landlock ABI is checked at runtime and only the supported+/// actions are forbidden in the attributes. Thus, if the attributes are+/// used with my_landlock_create_ruleset(), it shouldn't fail.+///+/// \return On success, the Landlock ABI version is returned (a positive+/// integer). If Landlock isn't supported, -1 is returned.+static int+my_landlock_ruleset_attr_forbid_all(struct landlock_ruleset_attr *attr)+{+ memzero(attr, sizeof(*attr));++ const int abi_version = syscall(SYS_landlock_create_ruleset,+ (void *)NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);+ if (abi_version <= 0)+ return -1;++ // ABI 1 except the few at the end+ attr->handled_access_fs+ = LANDLOCK_ACCESS_FS_EXECUTE+ | LANDLOCK_ACCESS_FS_WRITE_FILE+ | LANDLOCK_ACCESS_FS_READ_FILE+ | LANDLOCK_ACCESS_FS_READ_DIR+ | LANDLOCK_ACCESS_FS_REMOVE_DIR+ | LANDLOCK_ACCESS_FS_REMOVE_FILE+ | LANDLOCK_ACCESS_FS_MAKE_CHAR+ | LANDLOCK_ACCESS_FS_MAKE_DIR+ | LANDLOCK_ACCESS_FS_MAKE_REG+ | LANDLOCK_ACCESS_FS_MAKE_SOCK+ | LANDLOCK_ACCESS_FS_MAKE_FIFO+ | LANDLOCK_ACCESS_FS_MAKE_BLOCK+ | LANDLOCK_ACCESS_FS_MAKE_SYM+#ifdef LANDLOCK_ACCESS_FS_REFER+ | LANDLOCK_ACCESS_FS_REFER // ABI 2+#endif+#ifdef LANDLOCK_ACCESS_FS_TRUNCATE+ | LANDLOCK_ACCESS_FS_TRUNCATE // ABI 3+#endif+#ifdef LANDLOCK_ACCESS_FS_IOCTL_DEV+ | LANDLOCK_ACCESS_FS_IOCTL_DEV // ABI 5+#endif+ ;++#ifdef LANDLOCK_ACCESS_NET_BIND_TCP+ // ABI 4+ attr->handled_access_net+ = LANDLOCK_ACCESS_NET_BIND_TCP+ | LANDLOCK_ACCESS_NET_CONNECT_TCP;+#endif++#ifdef LANDLOCK_SCOPE_SIGNAL+ // ABI 6+ attr->scoped+ = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET+ | LANDLOCK_SCOPE_SIGNAL;+#endif++ // Disable flags that require a new ABI version.+ switch (abi_version) {+ case 1:+#ifdef LANDLOCK_ACCESS_FS_REFER+ attr->handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER;+#endif+ FALLTHROUGH;++ case 2:+#ifdef LANDLOCK_ACCESS_FS_TRUNCATE+ attr->handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE;+#endif+ FALLTHROUGH;++ case 3:+#ifdef LANDLOCK_ACCESS_NET_BIND_TCP+ attr->handled_access_net = 0;+#endif+ FALLTHROUGH;++ case 4:+#ifdef LANDLOCK_ACCESS_FS_IOCTL_DEV+ attr->handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV;+#endif+ FALLTHROUGH;++ case 5:+#ifdef LANDLOCK_SCOPE_SIGNAL+ attr->scoped = 0;+#endif+ FALLTHROUGH;++ default:+ // We only know about the features of the ABIs 1-6.+ break;+ }++ return abi_version;+}+++/// \brief Wrapper for the landlock_create_ruleset(2) syscall+///+/// Syscall wrappers provide argument type checking.+///+/// \note Remember to call `prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)` too!+static inline int+my_landlock_create_ruleset(const struct landlock_ruleset_attr *attr,+ size_t size, uint32_t flags)+{+ return syscall(SYS_landlock_create_ruleset, attr, size, flags);+}+++/// \brief Wrapper for the landlock_restrict_self(2) syscall+static inline int+my_landlock_restrict_self(int ruleset_fd, uint32_t flags)+{+ return syscall(SYS_landlock_restrict_self, ruleset_fd, flags);+}++#endif
cbits/common/sysdefs.h view
@@ -168,17 +168,24 @@ # define __bool_true_false_are_defined 1 #endif +// We may need alignas from C11/C17/C23.+#if __STDC_VERSION__ >= 202311+ // alignas is a keyword in C23. Do nothing.+#elif __STDC_VERSION__ >= 201112+# include <stdalign.h>+#elif defined(__GNUC__) || defined(__clang__)+# define alignas(n) __attribute__((__aligned__(n)))+#else+# define alignas(n)+#endif+ #include <string.h> -// Visual Studio 2013 update 2 supports only __inline, not inline.-// MSVC v19.0 / VS 2015 and newer support both.+// MSVC v19.00 (VS 2015 version 14.0) and later should work. // // 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@@ -206,6 +213,15 @@ # define lzma_attr_alloc_size(x) __attribute__((__alloc_size__(x))) #else # define lzma_attr_alloc_size(x)+#endif++#if __STDC_VERSION__ >= 202311+# define FALLTHROUGH [[__fallthrough__]]+#elif (defined(__GNUC__) && __GNUC__ >= 7) \+ || (defined(__clang_major__) && __clang_major__ >= 10)+# define FALLTHROUGH __attribute__((__fallthrough__))+#else+# define FALLTHROUGH ((void)0) #endif #endif
cbits/common/tuklib_common.h view
@@ -56,6 +56,13 @@ # define TUKLIB_GNUC_REQ(major, minor) 0 #endif +#if defined(__GNUC__) || defined(__clang__)+# define tuklib_attr_format_printf(fmt_index, args_index) \+ __attribute__((__format__(__printf__, fmt_index, args_index)))+#else+# define tuklib_attr_format_printf(fmt_index, args_index)+#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]] ]].@@ -68,9 +75,7 @@ // __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+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311 # define tuklib_attr_noreturn [[noreturn]] #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112 # define tuklib_attr_noreturn _Noreturn
cbits/common/tuklib_gettext.h view
@@ -40,4 +40,15 @@ #endif #define N_(msgid) msgid +// Optional: Strings that are word wrapped using tuklib_mbstr_wrap may be+// marked with W_("foo) in the source code. xgettext can then add a comment+// to all such strings to inform translators. The following option needs to+// be added to XGETTEXT_OPTIONS in po/Makevars or in an equivalent place:+//+// '--keyword=W_:1,"This is word wrapped at spaces. The Unicode character U+00A0 works as a non-breaking space. Tab (\t) is interpret as a zero-width space (the tab itself is not displayed); U+200B is NOT supported. Manual word wrapping with \n is supported but requires care."'+//+// NOTE: The double-quotes in the --keyword argument above must be passed to+// xgettext as is, thus one needs the single-quotes in Makevars.+#define W_(msgid) _(msgid)+ #endif
cbits/common/tuklib_mbstr.h view
@@ -27,10 +27,7 @@ /// /// 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 str String whose width is to be calculated. /// \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).@@ -38,8 +35,24 @@ /// \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.+/// partial, or non-printable multibyte character in str.++#define tuklib_mbstr_width_mem TUKLIB_SYMBOL(tuklib_mbstr_width_mem)+extern size_t tuklib_mbstr_width_mem(const char *str, size_t len);+///<+/// \brief Get the number of columns needed for the multibyte buffer+///+/// This is like tuklib_mbstr_width() except that this takes the buffer+/// length in bytes as the second argument. This allows using the function+/// for buffers that aren't terminated with '\0'.+///+/// \param str String whose width is to be calculated.+/// \param len Number of bytes to read from str.+///+/// \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. #define tuklib_mbstr_fw TUKLIB_SYMBOL(tuklib_mbstr_fw) extern int tuklib_mbstr_fw(const char *str, int columns_min);
+ cbits/common/tuklib_mbstr_nonprint.c view
@@ -0,0 +1,162 @@+// SPDX-License-Identifier: 0BSD++///////////////////////////////////////////////////////////////////////////////+//+/// \file tuklib_mbstr_nonprint.c+/// \brief Find and replace non-printable characters with question marks+//+// Author: Lasse Collin+//+///////////////////////////////////////////////////////////////////////////////++#include "tuklib_mbstr_nonprint.h"+#include <stdlib.h>+#include <string.h>+#include <errno.h>++#ifdef HAVE_MBRTOWC+# include <wchar.h>+# include <wctype.h>+#else+# include <ctype.h>+#endif+++static bool+is_next_printable(const char *str, size_t len, size_t *next_len)+{+#ifdef HAVE_MBRTOWC+ // This assumes that character sets with locking shift states aren't+ // used, and thus mbsinit() is never needed.+ mbstate_t ps;+ memset(&ps, 0, sizeof(ps));++ wchar_t wc;+ *next_len = mbrtowc(&wc, str, len, &ps);++ if (*next_len == (size_t)-2) {+ // Incomplete multibyte sequence: Treat the whole sequence+ // as a single non-printable multibyte character that ends+ // the string.+ *next_len = len;+ return false;+ }++ // Check more broadly than just ret == (size_t)-1 to be safe+ // in case mbrtowc() returns something weird. This check+ // covers (size_t)-1 (that is, SIZE_MAX) too because len is from+ // strlen() and the terminating '\0' isn't part of the length.+ if (*next_len < 1 || *next_len > len) {+ // Invalid multibyte sequence: Treat the first byte as+ // a non-printable single-byte character. Decoding will+ // be restarted from the next byte on the next call to+ // this function.+ *next_len = 1;+ return false;+ }++# if defined(_WIN32) && !defined(__CYGWIN__)+ // On Windows, wchar_t stores UTF-16 code units, thus characters+ // outside the Basic Multilingual Plane (BMP) don't fit into+ // a single wchar_t. In an UTF-8 locale, UCRT's mbrtowc() returns+ // successfully when the input is a non-BMP character but the+ // output is the replacement character U+FFFD.+ //+ // iswprint() returns 0 for U+FFFD on Windows for some reason. Treat+ // U+FFFD as printable and thus also all non-BMP chars as printable.+ if (wc == 0xFFFD)+ return true;+# endif++ return iswprint((wint_t)wc) != 0;+#else+ (void)len;+ *next_len = 1;+ return isprint((unsigned char)str[0]) != 0;+#endif+}+++static bool+has_nonprint(const char *str, size_t len)+{+ for (size_t i = 0; i < len; ) {+ size_t next_len;+ if (!is_next_printable(str + i, len - i, &next_len))+ return true;++ i += next_len;+ }++ return false;+}+++extern bool+tuklib_has_nonprint(const char *str)+{+ const int saved_errno = errno;+ const bool ret = has_nonprint(str, strlen(str));+ errno = saved_errno;+ return ret;+}+++extern const char *+tuklib_mask_nonprint_r(const char *str, char **mem)+{+ const int saved_errno = errno;++ // Free the old string, if any.+ free(*mem);+ *mem = NULL;++ // If the whole input string contains only printable characters,+ // return the input string.+ const size_t len = strlen(str);+ if (!has_nonprint(str, len)) {+ errno = saved_errno;+ return str;+ }++ // Allocate memory for the masked string. Since we use the single-byte+ // character '?' to mask non-printable characters, it's possible that+ // a few bytes less memory would be needed in reality if multibyte+ // characters are masked.+ //+ // If allocation fails, return "???" because it should be safer than+ // returning the unmasked string.+ *mem = malloc(len + 1);+ if (*mem == NULL) {+ errno = saved_errno;+ return "???";+ }++ // Replace all non-printable characters with '?'.+ char *dest = *mem;++ for (size_t i = 0; i < len; ) {+ size_t next_len;+ if (is_next_printable(str + i, len - i, &next_len)) {+ memcpy(dest, str + i, next_len);+ dest += next_len;+ } else {+ *dest++ = '?';+ }++ i += next_len;+ }++ *dest = '\0';++ errno = saved_errno;+ return *mem;+}+++extern const char *+tuklib_mask_nonprint(const char *str)+{+ static char *mem = NULL;+ return tuklib_mask_nonprint_r(str, &mem);+}
+ cbits/common/tuklib_mbstr_nonprint.h view
@@ -0,0 +1,71 @@+// SPDX-License-Identifier: 0BSD++///////////////////////////////////////////////////////////////////////////////+//+/// \file tuklib_mbstr_nonprint.h+/// \brief Find and replace non-printable characters with question marks+///+/// If mbrtowc(3) is available, it and iswprint(3) is used to check if all+/// characters are printable. Otherwise single-byte character set is assumed+/// and isprint(3) is used.+//+// Author: Lasse Collin+//+///////////////////////////////////////////////////////////////////////////////++#ifndef TUKLIB_MBSTR_NONPRINT_H+#define TUKLIB_MBSTR_NONPRINT_H++#include "tuklib_common.h"+TUKLIB_DECLS_BEGIN++#define tuklib_has_nonprint TUKLIB_SYMBOL(tuklib_has_nonprint)+extern bool tuklib_has_nonprint(const char *str);+///<+/// \brief Check if a string contains any non-printable characters+///+/// \return false if str contains only valid multibyte characters and+/// iswprint(3) returns non-zero for all of them; true otherwise.+/// The value of errno is preserved.+///+/// \note In case mbrtowc(3) isn't available, single-byte character set+/// is assumed and isprint(3) is used instead of iswprint(3).++#define tuklib_mask_nonprint_r TUKLIB_SYMBOL(tuklib_mask_nonprint_r)+extern const char *tuklib_mask_nonprint_r(const char *str, char **mem);+///<+/// \brief Replace non-printable characters with question marks+///+/// \param str Untrusted string, for example, a filename+/// \param mem This function always calls free(*mem) to free the old+/// allocation and then sets *mem = NULL. Before the first+/// call, *mem should be initialized to NULL. If this+/// function needs to allocate memory for a modified+/// string, a pointer to the allocated memory will be+/// stored to *mem. Otherwise *mem will remain NULL.+///+/// \return If tuklib_has_nonprint(str) returns false, this function+/// returns str. Otherwise memory is allocated to hold a modified+/// string and a pointer to that is returned. The pointer to the+/// allocated memory is also stored to *mem. A modified string+/// has the problematic characters replaced by '?'. If memory+/// allocation fails, "???" is returned and *mem is NULL.+/// The value of errno is preserved.++#define tuklib_mask_nonprint TUKLIB_SYMBOL(tuklib_mask_nonprint)+extern const char *tuklib_mask_nonprint(const char *str);+///<+/// \brief Replace non-printable characters with question marks+///+/// This is a convenience function for single-threaded use. This calls+/// tuklib_mask_nonprint_r() using an internal static variable to hold+/// the possible allocation.+///+/// \param str Untrusted string, for example, a filename+///+/// \return See tuklib_mask_nonprint_r().+///+/// \note This function is not thread safe!++TUKLIB_DECLS_END+#endif
cbits/common/tuklib_mbstr_width.c view
@@ -24,9 +24,17 @@ if (bytes != NULL) *bytes = len; + return tuklib_mbstr_width_mem(str, len);+}+++extern size_t+tuklib_mbstr_width_mem(const char *str, size_t len)+{ #ifndef HAVE_MBRTOWC // In single-byte mode, the width of the string is the same // as its length.+ (void)str; return len; #else@@ -41,7 +49,7 @@ while (i < len) { wchar_t wc; const size_t ret = mbrtowc(&wc, str + i, len - i, &state);- if (ret < 1 || ret > len)+ if (ret < 1 || ret > len - i) return (size_t)-1; i += ret;@@ -62,9 +70,14 @@ #endif } - // 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.+ // It's good to check that the string ended in the initial state.+ // However, in practice this is redundant:+ //+ // - No one will use this code with character sets that have+ // locking shift states.+ //+ // - We already checked that mbrtowc() didn't return (size_t)-2+ // which would indicate a partial multibyte character. if (!mbsinit(&state)) return (size_t)-1;
+ cbits/common/tuklib_mbstr_wrap.c view
@@ -0,0 +1,294 @@+// SPDX-License-Identifier: 0BSD++///////////////////////////////////////////////////////////////////////////////+//+/// \file tuklib_mbstr_wrap.c+/// \brief Word wraps a string and prints it to a FILE stream+///+/// This depends on tuklib_mbstr_width.c.+//+// Author: Lasse Collin+//+///////////////////////////////////////////////////////////////////////////////++#include "tuklib_mbstr.h"+#include "tuklib_mbstr_wrap.h"+#include <stdarg.h>+#include <stdlib.h>+#include <stdio.h>+#include <string.h>+++extern int+tuklib_wraps(FILE *outfile, const struct tuklib_wrap_opt *opt, const char *str)+{+ // left_cont may be less than left_margin. In that case, if the first+ // word is extremely long, it will stay on the first line even if+ // the line then gets overlong.+ //+ // On the other hand, left2_cont < left2_margin isn't allowed because+ // it could result in inconsistent behavior when a very long word+ // comes right after a \v.+ //+ // It is fine to have left2_margin < left_margin although it would be+ // an odd use case.+ if (!(opt->left_margin < opt->right_margin+ && opt->left_cont < opt->right_margin+ && opt->left2_margin <= opt->left2_cont+ && opt->left2_cont < opt->right_margin))+ return TUKLIB_WRAP_ERR_OPT;++ // This is set to TUKLIB_WRAP_WARN_OVERLONG if one or more+ // output lines extend past opt->right_margin columns.+ int warn_overlong = 0;++ // Indentation of the first output line after \n or \r.+ // \v sets this to opt->left2_margin.+ // \r resets this back to the original value.+ size_t first_indent = opt->left_margin;++ // Indentation of the output lines that occur due to word wrapping.+ // \v sets this to opt->left2_cont and \r back to the original value.+ size_t cont_indent = opt->left_cont;++ // If word wrapping occurs, the newline isn't printed unless more+ // text would be put on the continuation line. This is also used+ // when \v needs to start on a new line.+ bool pending_newline = false;++ // Spaces are printed only when there is something else to put+ // after the spaces on the line. This avoids unwanted empty lines+ // in the output and makes it possible to ignore possible spaces+ // before a \v character.+ size_t pending_spaces = first_indent;++ // Current output column. When cur_col == pending_spaces, nothing+ // has been actually printed to the current output line.+ size_t cur_col = pending_spaces;++ while (true) {+ // Number of bytes until the *next* line-break opportunity.+ size_t len = 0;++ // Number of columns until the *next* line-break opportunity.+ size_t width = 0;++ // Text between a pair of \b characters is treated as+ // an unbreakable block even if it contains spaces.+ // It must not contain any control characters before+ // the closing \b.+ bool unbreakable = false;++ while (true) {+ // Find the next character that we handle specially.+ // In an unbreakable block, search only for the+ // closing \b; if missing, the unbreakable block+ // extends to the end of the string.+ const size_t n = strcspn(str + len,+ unbreakable ? "\b" : " \t\n\r\v\b");++ // Calculate how many columns the characters need.+ const size_t w = tuklib_mbstr_width_mem(str + len, n);+ if (w == (size_t)-1)+ return TUKLIB_WRAP_ERR_STR;++ width += w;+ len += n;++ // \b isn't a line-break opportunity so it has to+ // be handled here. For simplicity, empty blocks+ // are treated as zero-width characters.+ if (str[len] == '\b') {+ ++len;+ unbreakable = !unbreakable;+ continue;+ }++ break;+ }++ // Determine if adding this chunk of text would make the+ // current output line exceed opt->right_margin columns.+ const bool too_long = cur_col + width > opt->right_margin;++ // Wrap the line if needed. However:+ //+ // - Don't wrap if the current column is less than where+ // the continuation line would begin. In that case+ // the chunk wouldn't fit on the next line either so+ // we just have to produce an overlong line.+ //+ // - Don't wrap if so far the line only contains spaces.+ // Wrapping in that case would leave a weird empty line.+ // NOTE: This "only contains spaces" condition is the+ // reason why left2_margin > left2_cont isn't allowed.+ if (too_long && cur_col > cont_indent+ && cur_col > pending_spaces) {+ // There might be trailing spaces or zero-width spaces+ // which need to be ignored to keep the output pretty.+ //+ // Spaces need to be ignored because in some+ // writing styles there are two spaces after+ // a full stop. Example string:+ //+ // "Foo bar. Abc def."+ // ^+ // If the first space after the first full stop+ // triggers word wrapping, both spaces must be+ // ignored. Otherwise the next line would be+ // indented too much.+ //+ // Zero-width spaces are ignored the same way+ // because they are meaningless if an adjacent+ // character is a space.+ while (*str == ' ' || *str == '\t')+ ++str;++ // Don't print the newline here; only mark it as+ // pending. This avoids an unwanted empty line if+ // there is a \n or \r or \0 after the spaces have+ // been ignored.+ pending_newline = true;+ pending_spaces = cont_indent;+ cur_col = pending_spaces;++ // Since str may have been incremented due to the+ // ignored spaces, the loop needs to be restarted.+ continue;+ }++ // Print the current chunk of text before the next+ // line-break opportunity. If the chunk was empty,+ // don't print anything so that the pending newline+ // and pending spaces aren't printed on their own.+ if (len > 0) {+ if (pending_newline) {+ pending_newline = false;+ if (putc('\n', outfile) == EOF)+ return TUKLIB_WRAP_ERR_IO;+ }++ while (pending_spaces > 0) {+ if (putc(' ', outfile) == EOF)+ return TUKLIB_WRAP_ERR_IO;++ --pending_spaces;+ }++ for (size_t i = 0; i < len; ++i) {+ // Ignore unbreakable block characters (\b).+ const int c = (unsigned char)str[i];+ if (c != '\b' && putc(c, outfile) == EOF)+ return TUKLIB_WRAP_ERR_IO;+ }++ str += len;+ cur_col += width;++ // Remember if the line got overlong. If no other+ // errors occur, we return warn_overlong. It might+ // help in catching problematic strings.+ if (too_long)+ warn_overlong = TUKLIB_WRAP_WARN_OVERLONG;+ }++ // Handle the special character after the chunk of text.+ switch (*str) {+ case ' ':+ // Regular space.+ ++cur_col;+ ++pending_spaces;+ break;++ case '\v':+ // Set the alternative indentation settings.+ first_indent = opt->left2_margin;+ cont_indent = opt->left2_cont;++ if (first_indent > cur_col) {+ // Add one or more spaces to reach+ // the column specified in first_indent.+ pending_spaces += first_indent - cur_col;+ } else {+ // There is no room to add even one space+ // before reaching the column first_indent.+ pending_newline = true;+ pending_spaces = first_indent;+ }++ cur_col = first_indent;+ break;++ case '\0': // Implicit newline at the end of the string.+ case '\r': // Newline that also resets the effect of \v.+ case '\n': // Newline without resetting the indentation mode.+ if (putc('\n', outfile) == EOF)+ return TUKLIB_WRAP_ERR_IO;++ if (*str == '\0')+ return warn_overlong;++ if (*str == '\r') {+ first_indent = opt->left_margin;+ cont_indent = opt->left_cont;+ }++ pending_newline = false;+ pending_spaces = first_indent;+ cur_col = first_indent;+ break;+ }++ // Skip the specially-handled character.+ ++str;+ }+}+++extern int+tuklib_wrapf(FILE *stream, const struct tuklib_wrap_opt *opt,+ const char *fmt, ...)+{+ va_list ap;+ char *buf;++#ifdef HAVE_VASPRINTF+ va_start(ap, fmt);++#ifdef __clang__+# pragma GCC diagnostic push+# pragma GCC diagnostic ignored "-Wformat-nonliteral"+#endif+ const int n = vasprintf(&buf, fmt, ap);+#ifdef __clang__+# pragma GCC diagnostic pop+#endif++ va_end(ap);+ if (n == -1)+ return TUKLIB_WRAP_ERR_FORMAT;+#else+ // Fixed buffer size is dumb but in practice one shouldn't need+ // huge strings for *formatted* output. This simple method is safe+ // with pre-C99 vsnprintf() implementations too which don't return+ // the required buffer size (they return -1 or buf_size - 1) or+ // which might not null-terminate the buffer in case it's too small.+ const size_t buf_size = 128 * 1024;+ buf = malloc(buf_size);+ if (buf == NULL)+ return TUKLIB_WRAP_ERR_FORMAT;++ va_start(ap, fmt);+ const int n = vsnprintf(buf, buf_size, fmt, ap);+ va_end(ap);++ if (n <= 0 || n >= (int)(buf_size - 1)) {+ free(buf);+ return TUKLIB_WRAP_ERR_FORMAT;+ }+#endif++ const int ret = tuklib_wraps(stream, opt, buf);+ free(buf);+ return ret;+}
+ cbits/common/tuklib_mbstr_wrap.h view
@@ -0,0 +1,204 @@+// SPDX-License-Identifier: 0BSD++///////////////////////////////////////////////////////////////////////////////+//+/// \file tuklib_mbstr_wrap.h+/// \brief Word wrapping for multibyte strings+///+/// The word wrapping functions are intended to be usable, for example,+/// for printing --help text in command line tools. While manually-wrapped+/// --help text allows precise formatting, such freedom requires translators+/// to count spaces and determine where line breaks should occur. It's+/// tedious and error prone, and experience has shown that only some+/// translators do it well. Automatic word wrapping is less flexible but+/// results in polished-enough look with less effort from everyone.+/// Right-to-left languages and languages that don't use spaces between+/// words will still need extra effort though.+//+// Author: Lasse Collin+//+///////////////////////////////////////////////////////////////////////////////++#ifndef TUKLIB_MBSTR_WRAP_H+#define TUKLIB_MBSTR_WRAP_H++#include "tuklib_common.h"+#include <stdio.h>++TUKLIB_DECLS_BEGIN++/// One or more output lines exceeded right_margin.+/// This only a warning; everything was still printed successfully.+#define TUKLIB_WRAP_WARN_OVERLONG 0x01++/// Error writing to to the output FILE. The error flag in the FILE+/// should have been set as well.+#define TUKLIB_WRAP_ERR_IO 0x02++/// Invalid options in struct tuklib_wrap_opt.+/// Nothing was printed.+#define TUKLIB_WRAP_ERR_OPT 0x04++/// Invalid or unsupported multibyte character in the input string:+/// either mbrtowc() failed or wcwidth() returned a negative value.+#define TUKLIB_WRAP_ERR_STR 0x08++/// Only tuklib_wrapf(): Error in converting the format string.+/// It's either a memory allocation failure or something bad with the+/// format string or arguments.+#define TUKLIB_WRAP_ERR_FORMAT 0x10++/// Options for tuklib_wraps() and tuklib_wrapf()+struct tuklib_wrap_opt {+ /// Indentation of the first output line after `\n` or `\r`.+ /// This can be anything less than right_margin.+ unsigned short left_margin;++ /// Column where word-wrapped continuation lines start.+ /// This can be anything less than right_margin.+ unsigned short left_cont;++ /// Column where the text after `\v` will start, either on the current+ /// line (when there is room to add at least one space) or on a new+ /// empty line.+ unsigned short left2_margin;++ /// Like left_cont but for text after a `\v`. However, this must+ /// be greater than or equal to left2_margin in addition to being+ /// less than right_margin.+ unsigned short left2_cont;++ /// For 80-column terminals, it is recommended to use 79 here for+ /// maximum portability. 80 will work most of the time but it will+ /// result in unwanted empty lines in the rare case where a terminal+ /// moves the cursor to the beginning of the next line immediately+ /// when the last column has been used.+ unsigned short right_margin;+};++#define tuklib_wraps TUKLIB_SYMBOL(tuklib_wraps)+extern int tuklib_wraps(FILE *stream, const struct tuklib_wrap_opt *opt,+ const char *str);+///<+/// \brief Word wrap a multibyte string and write it to a FILE+///+/// Word wrapping is done only at spaces and at the special control characters+/// described below. Multiple consecutive spaces are handled properly: strings+/// that have two (or more) spaces after a full sentence will look good even+/// when the spaces occur at a word wrapping boundary. Trailing spaces are+/// ignored at the end of a line or at the end of a string.+///+/// The following control characters have been repurposed:+///+/// - `\t` = Zero-width space allows a line break without producing any+/// output by itself. This can be useful after hard hyphens as+/// hyphens aren't otherwise used for line breaking. This can also+/// be useful in languages that don't use spaces between words.+/// (The Unicode character U+200B isn't supported.)+/// - `\b` = Text between a pair of `\b` characters is treated as an+/// unbreakable block (not wrapped even if there are spaces).+/// For example, a non-breaking space can be done like+/// in `"123\b \bMiB"`. Control characters (like `\n` or `\t`)+/// aren't allowed before the closing `\b`. If closing `\b` is+/// missing, the block extends to the end of the string. Empty+/// blocks are treated as zero-width characters. If line breaks+/// are possible around an empty block (like in `"foo \b\b bar"`+/// or `"foo \b"`), it can result in weird output.+/// - `\v` = Change to alternative indentation (left2_margin).+/// - `\r` = Reset back to the initial indentation and add a newline.+/// The next line will be indented by left_margin.+/// - `\n` = Add a newline without resetting the effect of `\v`. The+/// next line will be indented by left_margin or left2_margin+/// (not left_cont or left2_cont).+///+/// Only `\n` should appear in translatable strings. `\t` works too but+/// even that might confuse some translators even if there is a TRANSLATORS+/// comment explaining its meaning.+///+/// To use the other control characters in messages, one should use+/// tuklib_wrapf() with appropriate printf format string to combine+/// translatable strings with non-translatable portions. For example:+///+/// \code{.c}+/// static const struct tuklib_wrap_opt wrap2 = { 2, 2, 22, 22, 79 };+/// int e = 0;+/// ...+/// e |= tuklib_wrapf(stdout, &wrap2,+/// "-h, --help\v%s\r"+/// " --version\v%s",+/// W_("display this help and exit"),+/// W_("display version information and exit"));+/// ...+/// if (e != 0) {+/// // Handle warning or error.+/// ...+/// }+/// \endcode+///+/// Control characters other than `\n` and `\t` are unusable in+/// translatable strings:+///+/// - Gettext tools show annoying warnings if C escape sequences other+/// than `\n` or `\t` are seen. (Otherwise they still work perfectly+/// fine though.)+///+/// - While at least Poedit and Lokalize support all escapes, some+/// editors only support `\n` and `\t`.+///+/// - They could confuse some translators, resulting in broken+/// translations.+///+/// Using non-control characters would solve some issues but it wouldn't+/// help with the unfortunate real-world issue that some translators would+/// likely have trouble understanding a new syntax. The Gettext manual+/// specifically warns about this, see the subheading "No unusual markup"+/// in `info (gettext)Preparing Strings`. (While using `\t` for zero-width+/// space is such custom markup, most translators will never need it.)+///+/// Translators can use the Unicode character U+00A0 (or U+202F) if they+/// need a non-breaking space. For example, in French a non-breaking space+/// may be needed before colons and question marks (U+00A0 is common in+/// real-world French PO files).+///+/// Using a non-ASCII char in a string in the C code (like `"123\u00A0MiB"`)+/// can work if one tells xgettext that input encoding is UTF-8, one+/// ensures that the C compiler uses UTF-8 as the input charset, and one+/// is certain that the program is *always* run under an UTF-8 locale.+/// Unfortunately a portable program cannot make this kind of assumptions,+/// which means that there is no pretty way to have a non-breaking space in+/// a translatable string.+///+/// Optional: To tell translators which strings are automatically word+/// wrapped, see the macro `W_` in tuklib_gettext.h.+///+/// \param stream Output FILE stream. For decent performance, it+/// should be in buffered mode because this function+/// writes the output one byte at a time with fputc().+/// \param opt Word wrapping options.+/// \param str Null-terminated multibyte string that is in+/// the encoding used by the current locale.+///+/// \return Returns 0 on success. If an error or warning occurs, one of+/// TUKLIB_WRAP_* codes is returned. Those codes are powers+/// of two. When warning/error detection can be delayed, the+/// return values can be accumulated from multiple calls using+/// bitwise-or into a single variable which can be checked after+/// all strings have (hopefully) been printed.++#define tuklib_wrapf TUKLIB_SYMBOL(tuklib_wrapf)+tuklib_attr_format_printf(3, 4)+extern int tuklib_wrapf(FILE *stream, const struct tuklib_wrap_opt *opt,+ const char *fmt, ...);+///<+/// \brief Format and word-wrap a multibyte string and write it to a FILE+///+/// This is like tuklib_wraps() except that this takes a printf+/// format string.+///+/// \note On platforms that lack vasprintf(), the intermediate+/// result from vsnprintf() must fit into a 128 KiB buffer.+/// TUKLIB_WRAP_ERR_FORMAT is returned if it doesn't but+/// only on platforms that lack vasprintf().++TUKLIB_DECLS_END+#endif
cbits/common/tuklib_physmem.c view
@@ -91,18 +91,11 @@ // 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"));+ HMODULE kernel32 = GetModuleHandleA("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);@@ -155,7 +148,7 @@ ret += entries[i].end - entries[i].start + 1; #elif defined(TUKLIB_PHYSMEM_AIX)- ret = _system_configuration.physmem;+ ret = (uint64_t)_system_configuration.physmem; #elif defined(TUKLIB_PHYSMEM_SYSCONF) const long pagesize = sysconf(_SC_PAGESIZE);
cbits/config.h.in view
@@ -330,6 +330,9 @@ /* Define to 1 if you have the 'utimes' function. */ #undef HAVE_UTIMES +/* Define to 1 if you have the 'vasprintf' function. */+#undef HAVE_VASPRINTF+ /* Define to 1 or 0, depending whether the compiler supports simple visibility declarations. */ #undef HAVE_VISIBILITY
cbits/liblzma/api/lzma/bcj.h view
@@ -96,3 +96,100 @@ uint32_t start_offset; } lzma_options_bcj;+++/**+ * \brief Raw ARM64 BCJ encoder+ *+ * This is for special use cases only.+ *+ * \param start_offset The lowest 32 bits of the offset in the+ * executable being filtered. For the ARM64+ * filter, this must be a multiple of four.+ * For the very best results, this should also+ * be in sync with 4096-byte page boundaries+ * in the executable due to how ARM64's ADRP+ * instruction works.+ * \param buf Buffer to be filtered in place+ * \param size Size of the buffer+ *+ * \return Number of bytes that were processed in `buf`. This is at most+ * `size`. With the ARM64 filter, the return value is always+ * a multiple of 4, and at most 3 bytes are left unfiltered.+ *+ * \since 5.7.1alpha+ */+extern LZMA_API(size_t) lzma_bcj_arm64_encode(+ uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow;++/**+ * \brief Raw ARM64 BCJ decoder+ *+ * See lzma_bcj_arm64_encode().+ *+ * \since 5.7.1alpha+ */+extern LZMA_API(size_t) lzma_bcj_arm64_decode(+ uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow;+++/**+ * \brief Raw RISC-V BCJ encoder+ *+ * This is for special use cases only.+ *+ * \param start_offset The lowest 32 bits of the offset in the+ * executable being filtered. For the RISC-V+ * filter, this must be a multiple of 2.+ * \param buf Buffer to be filtered in place+ * \param size Size of the buffer+ *+ * \return Number of bytes that were processed in `buf`. This is at most+ * `size`. With the RISC-V filter, the return value is always+ * a multiple of 2, and at most 7 bytes are left unfiltered.+ *+ * \since 5.7.1alpha+ */+extern LZMA_API(size_t) lzma_bcj_riscv_encode(+ uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow;++/**+ * \brief Raw RISC-V BCJ decoder+ *+ * See lzma_bcj_riscv_encode().+ *+ * \since 5.7.1alpha+ */+extern LZMA_API(size_t) lzma_bcj_riscv_decode(+ uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow;+++/**+ * \brief Raw x86 BCJ encoder+ *+ * This is for special use cases only.+ *+ * \param start_offset The lowest 32 bits of the offset in the+ * executable being filtered. For the x86+ * filter, all values are valid.+ * \param buf Buffer to be filtered in place+ * \param size Size of the buffer+ *+ * \return Number of bytes that were processed in `buf`. This is at most+ * `size`. For the x86 filter, the return value is always+ * a multiple of 1, and at most 4 bytes are left unfiltered.+ *+ * \since 5.7.1alpha+ */+extern LZMA_API(size_t) lzma_bcj_x86_encode(+ uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow;++/**+ * \brief Raw x86 BCJ decoder+ *+ * See lzma_bcj_x86_encode().+ *+ * \since 5.7.1alpha+ */+extern LZMA_API(size_t) lzma_bcj_x86_decode(+ uint32_t start_offset, uint8_t *buf, size_t size) lzma_nothrow;
cbits/liblzma/api/lzma/container.h view
@@ -573,7 +573,7 @@ * 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+ * function and lzma_code() is that memory allocations can be reused for * better performance. * * lzma_code() will try to encode as much input as is possible to fit into
cbits/liblzma/api/lzma/version.h view
@@ -19,10 +19,10 @@ #define LZMA_VERSION_MAJOR 5 /** \brief Minor version number of the liblzma release. */-#define LZMA_VERSION_MINOR 6+#define LZMA_VERSION_MINOR 8 /** \brief Patch version number of the liblzma release. */-#define LZMA_VERSION_PATCH 4+#define LZMA_VERSION_PATCH 0 /** * \brief Version stability marker
cbits/liblzma/check/check.h view
@@ -95,24 +95,6 @@ } 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);
cbits/liblzma/check/crc32_arm64.h view
@@ -7,7 +7,7 @@ // // Authors: Chenxi Mao // Jia Tan-// Hans Jansen+// Lasse Collin // /////////////////////////////////////////////////////////////////////////////// @@ -49,25 +49,50 @@ { 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);+ if (size >= 8) {+ // Align the input buffer because this was shown to be+ // significantly faster than unaligned accesses.+ const size_t align = (0 - (uintptr_t)buf) & 7; - for (const uint8_t *limit = buf + align_amount; buf < limit; ++buf)- crc = __crc32b(crc, *buf);+ if (align & 1)+ crc = __crc32b(crc, *buf++); - size -= align_amount;+ if (align & 2) {+ crc = __crc32h(crc, aligned_read16le(buf));+ buf += 2;+ } - // 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));+ if (align & 4) {+ crc = __crc32w(crc, aligned_read32le(buf));+ buf += 4;+ } + size -= align;++ // 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));++ size &= 7;+ }+ // Process the remaining bytes that are not 8 byte aligned.- for (const uint8_t *limit = buf + (size & 7); buf < limit; ++buf)+ if (size & 4) {+ crc = __crc32w(crc, aligned_read32le(buf));+ buf += 4;+ }++ if (size & 2) {+ crc = __crc32h(crc, aligned_read16le(buf));+ buf += 2;+ }++ if (size & 1) crc = __crc32b(crc, *buf); return ~crc;
cbits/liblzma/check/crc32_fast.c view
@@ -7,7 +7,6 @@ // // Authors: Lasse Collin // Ilya Kurdyukov-// Hans Jansen // /////////////////////////////////////////////////////////////////////////////// @@ -15,10 +14,12 @@ #include "crc_common.h" #if defined(CRC_X86_CLMUL)-# define BUILDING_CRC32_CLMUL+# define BUILDING_CRC_CLMUL 32 # include "crc_x86_clmul.h" #elif defined(CRC32_ARM64) # include "crc32_arm64.h"+#elif defined(CRC32_LOONGARCH)+# include "crc32_loongarch.h" #endif @@ -28,8 +29,19 @@ // Generic CRC32 // /////////////////// +#ifdef WORDS_BIGENDIAN+# include "crc32_table_be.h"+#else+# include "crc32_table_le.h"+#endif+++#ifdef HAVE_CRC_X86_ASM+extern uint32_t lzma_crc32_generic(+ const uint8_t *buf, size_t size, uint32_t crc);+#else static uint32_t-crc32_generic(const uint8_t *buf, size_t size, uint32_t crc)+lzma_crc32_generic(const uint8_t *buf, size_t size, uint32_t crc) { crc = ~crc; @@ -85,7 +97,8 @@ return ~crc; }-#endif+#endif // HAVE_CRC_X86_ASM+#endif // CRC32_GENERIC #if defined(CRC32_GENERIC) && defined(CRC32_ARCH_OPTIMIZED)@@ -119,7 +132,7 @@ crc32_resolve(void) { return is_arch_extension_supported()- ? &crc32_arch_optimized : &crc32_generic;+ ? &crc32_arch_optimized : &lzma_crc32_generic; } @@ -164,27 +177,6 @@ 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@@ -199,6 +191,6 @@ return crc32_arch_optimized(buf, size, crc); #else- return crc32_generic(buf, size, crc);+ return lzma_crc32_generic(buf, size, crc); #endif }
+ cbits/liblzma/check/crc32_loongarch.h view
@@ -0,0 +1,65 @@+// SPDX-License-Identifier: 0BSD++///////////////////////////////////////////////////////////////////////////////+//+/// \file crc32_loongarch.h+/// \brief CRC32 calculation with LoongArch optimization+//+// Authors: Xi Ruoyao+// Lasse Collin+//+///////////////////////////////////////////////////////////////////////////////++#ifndef LZMA_CRC32_LOONGARCH_H+#define LZMA_CRC32_LOONGARCH_H++#include <larchintrin.h>+++static uint32_t+crc32_arch_optimized(const uint8_t *buf, size_t size, uint32_t crc_unsigned)+{+ int32_t crc = (int32_t)~crc_unsigned;++ if (size >= 8) {+ const size_t align = (0 - (uintptr_t)buf) & 7;++ if (align & 1)+ crc = __crc_w_b_w((int8_t)*buf++, crc);++ if (align & 2) {+ crc = __crc_w_h_w((int16_t)aligned_read16le(buf), crc);+ buf += 2;+ }++ if (align & 4) {+ crc = __crc_w_w_w((int32_t)aligned_read32le(buf), crc);+ buf += 4;+ }++ size -= align;++ for (const uint8_t *limit = buf + (size & ~(size_t)7);+ buf < limit; buf += 8)+ crc = __crc_w_d_w((int64_t)aligned_read64le(buf), crc);++ size &= 7;+ }++ if (size & 4) {+ crc = __crc_w_w_w((int32_t)aligned_read32le(buf), crc);+ buf += 4;+ }++ if (size & 2) {+ crc = __crc_w_h_w((int16_t)aligned_read16le(buf), crc);+ buf += 2;+ }++ if (size & 1)+ crc = __crc_w_b_w((int8_t)*buf, crc);++ return (uint32_t)~crc;+}++#endif // LZMA_CRC32_LOONGARCH_H
cbits/liblzma/check/crc32_small.c view
@@ -10,8 +10,11 @@ /////////////////////////////////////////////////////////////////////////////// #include "check.h"+#include "crc_common.h" +// The table is used by the LZ encoder too, thus it's not static like+// in crc64_small.c. uint32_t lzma_crc32_table[1][256];
− cbits/liblzma/check/crc32_table.c
@@ -1,42 +0,0 @@-// 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
cbits/liblzma/check/crc64_fast.c view
@@ -14,7 +14,7 @@ #include "crc_common.h" #if defined(CRC_X86_CLMUL)-# define BUILDING_CRC64_CLMUL+# define BUILDING_CRC_CLMUL 64 # include "crc_x86_clmul.h" #endif @@ -25,6 +25,18 @@ // Generic slice-by-four CRC64 // ///////////////////////////////// +#if defined(WORDS_BIGENDIAN)+# include "crc64_table_be.h"+#else+# include "crc64_table_le.h"+#endif+++#ifdef HAVE_CRC_X86_ASM+extern uint64_t lzma_crc64_generic(+ const uint8_t *buf, size_t size, uint64_t crc);+#else+ #ifdef WORDS_BIGENDIAN # define A1(x) ((x) >> 56) #else@@ -34,7 +46,7 @@ // 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)+lzma_crc64_generic(const uint8_t *buf, size_t size, uint64_t crc) { crc = ~crc; @@ -78,7 +90,8 @@ return ~crc; }-#endif+#endif // HAVE_CRC_X86_ASM+#endif // CRC64_GENERIC #if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED)@@ -97,7 +110,7 @@ crc64_resolve(void) { return is_arch_extension_supported()- ? &crc64_arch_optimized : &crc64_generic;+ ? &crc64_arch_optimized : &lzma_crc64_generic; } #ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR@@ -133,24 +146,24 @@ 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);+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) \+ && defined(_M_IX86) && defined(CRC64_ARCH_OPTIMIZED)+ // VS2015-2022 might corrupt the ebx register on 32-bit x86 when+ // the CLMUL code is enabled. This hack forces MSVC to store and+ // restore ebx. This is only needed here, not in lzma_crc32().+ __asm mov ebx, ebx #endif++#if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED) 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);+ return lzma_crc64_generic(buf, size, crc); #endif }
− cbits/liblzma/check/crc64_table.c
@@ -1,37 +0,0 @@-// 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
+ cbits/liblzma/check/crc_clmul_consts_gen.c view
@@ -0,0 +1,160 @@+// SPDX-License-Identifier: 0BSD++///////////////////////////////////////////////////////////////////////////////+//+/// \file crc_clmul_consts_gen.c+/// \brief Generate constants for CLMUL CRC code+///+/// Compiling: gcc -std=c99 -o crc_clmul_consts_gen crc_clmul_consts_gen.c+///+/// This is for CRCs that use reversed bit order (bit reflection).+/// The same CLMUL CRC code can be used with CRC64 and smaller ones like+/// CRC32 apart from one special case: CRC64 needs an extra step in the+/// Barrett reduction to handle the 65th bit; the smaller ones don't.+/// Otherwise it's enough to just change the polynomial and the derived+/// constants and use the same code.+///+/// See the Intel white paper "Fast CRC Computation for Generic Polynomials+/// Using PCLMULQDQ Instruction" from 2009.+//+// Author: Lasse Collin+//+///////////////////////////////////////////////////////////////////////////////++#include <inttypes.h>+#include <stdio.h>+++/// CRC32 (Ethernet) polynomial in reversed representation+static const uint64_t p32 = 0xedb88320;++// CRC64 (ECMA-182) polynomial in reversed representation+static const uint64_t p64 = 0xc96c5795d7870f42;+++/// Calculates floor(x^128 / p) where p is a CRC64 polynomial in+/// reversed representation. The result is in reversed representation too.+static uint64_t+calc_cldiv(uint64_t p)+{+ // Quotient+ uint64_t q = 0;++ // Align the x^64 term with the x^128 (the implied high bits of the+ // divisor and the dividend) and do the first step of polynomial long+ // division, calculating the first remainder. The variable q remains+ // zero because the highest bit of the quotient is an implied bit 1+ // (we kind of set q = 1 << -1).+ uint64_t r = p;++ // Then process the remaining 64 terms. Note that r has no implied+ // high bit, only q and p do. (And remember that a high bit in the+ // polynomial is stored at a low bit in the variable due to the+ // reversed bit order.)+ for (unsigned i = 0; i < 64; ++i) {+ q |= (r & 1) << i;+ r = (r >> 1) ^ (r & 1 ? p : 0);+ }++ return q;+}+++/// Calculate the remainder of carryless division:+///+/// x^(bits + n - 1) % p, where n=64 (for CRC64)+///+/// p must be in reversed representation which omits the bit of+/// the highest term of the polynomial. Instead, it is an implied bit+/// at kind of like "1 << -1" position, as if it had just been shifted out.+///+/// The return value is in the reversed bit order. (There are no implied bits.)+static uint64_t+calc_clrem(uint64_t p, unsigned bits)+{+ // Do the first step of polynomial long division.+ uint64_t r = p;++ // Then process the remaining terms. Start with i = 1 instead of i = 0+ // to account for the -1 in x^(bits + n - 1). This -1 is convenient+ // with the reversed bit order. See the "Bit-Reflection" section in+ // the Intel white paper.+ for (unsigned i = 1; i < bits; ++i)+ r = (r >> 1) ^ (r & 1 ? p : 0);++ return r;+}+++extern int+main(void)+{+ puts("// CRC64");++ // The order of the two 64-bit constants in a vector don't matter.+ // It feels logical to put them in this order as it matches the+ // order in which the input bytes are read.+ printf("const __m128i fold512 = _mm_set_epi64x("+ "0x%016" PRIx64 ", 0x%016" PRIx64 ");\n",+ calc_clrem(p64, 4 * 128 - 64),+ calc_clrem(p64, 4 * 128));++ printf("const __m128i fold128 = _mm_set_epi64x("+ "0x%016" PRIx64 ", 0x%016" PRIx64 ");\n",+ calc_clrem(p64, 128 - 64),+ calc_clrem(p64, 128));++ // When we multiply by mu, we care about the high bits of the result+ // (in reversed bit order!). It doesn't matter that the low bit gets+ // shifted out because the affected output bits will be ignored.+ // Below we add the implied high bit with "| 1" after the shifting+ // so that the high bits of the multiplication will be correct.+ //+ // p64 is shifted left by one so that the final multiplication+ // in Barrett reduction won't be misaligned by one bit. We could+ // use "(p64 << 1) | 1" instead of "p64 << 1" too but it makes+ // no difference as that bit won't affect the relevant output bits+ // (we only care about the lowest 64 bits of the result, that is,+ // lowest in the reversed bit order).+ //+ // NOTE: The 65rd bit of p64 gets shifted out. It needs to be+ // compensated with 64-bit shift and xor in the CRC64 code.+ printf("const __m128i mu_p = _mm_set_epi64x("+ "0x%016" PRIx64 ", 0x%016" PRIx64 ");\n",+ (calc_cldiv(p64) << 1) | 1,+ p64 << 1);++ puts("");++ puts("// CRC32");++ printf("const __m128i fold512 = _mm_set_epi64x("+ "0x%08" PRIx64 ", 0x%08" PRIx64 ");\n",+ calc_clrem(p32, 4 * 128 - 64),+ calc_clrem(p32, 4 * 128));++ printf("const __m128i fold128 = _mm_set_epi64x("+ "0x%08" PRIx64 ", 0x%08" PRIx64 ");\n",+ calc_clrem(p32, 128 - 64),+ calc_clrem(p32, 128));++ // CRC32 calculation is done by modulus scaling it to a CRC64.+ // Since the CRC is in reversed representation, only the mu+ // constant changes with the modulus scaling. This method avoids+ // one additional constant and one additional clmul in the final+ // reduction steps, making the code both simpler and faster.+ //+ // p32 is shifted left by one so that the final multiplication+ // in Barrett reduction won't be misaligned by one bit. We could+ // use "(p32 << 1) | 1" instead of "p32 << 1" too but it makes+ // no difference as that bit won't affect the relevant output bits.+ //+ // NOTE: The 33-bit value fits in 64 bits so, unlike with CRC64,+ // there is no need to compensate for any missing bits in the code.+ printf("const __m128i mu_p = _mm_set_epi64x("+ "0x%016" PRIx64 ", 0x%" PRIx64 ");\n",+ (calc_cldiv(p32) << 1) | 1,+ p32 << 1);++ return 0;+}
cbits/liblzma/check/crc_common.h view
@@ -3,11 +3,10 @@ /////////////////////////////////////////////////////////////////////////////// // /// \file crc_common.h-/// \brief Some functions and macros for CRC32 and CRC64+/// \brief Macros and declarations for CRC32 and CRC64 // // Authors: Lasse Collin // Ilya Kurdyukov-// Hans Jansen // Jia Tan // ///////////////////////////////////////////////////////////////////////////////@@ -18,6 +17,10 @@ #include "common.h" +/////////////+// Generic //+/////////////+ #ifdef WORDS_BIGENDIAN # define A(x) ((x) >> 24) # define B(x) (((x) >> 16) & 0xFF)@@ -38,43 +41,63 @@ #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__))+/// 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-# 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+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 +///////////////////+// Configuration //+///////////////////++// NOTE: This config isn't used if HAVE_SMALL is defined!++// These are defined if the generic slicing-by-n implementations and their+// lookup tables are built. #undef CRC32_GENERIC #undef CRC64_GENERIC +// These are defined if an arch-specific version is built. If both this+// and matching _GENERIC is defined then runtime detection must be used. #undef CRC32_ARCH_OPTIMIZED #undef CRC64_ARCH_OPTIMIZED // The x86 CLMUL is used for both CRC32 and CRC64. #undef CRC_X86_CLMUL +// Many ARM64 processor have CRC32 instructions.+// CRC64 could be done with CLMUL but it's not implemented yet. #undef CRC32_ARM64-#undef CRC64_ARM64_CLMUL -#undef CRC_USE_GENERIC_FOR_SMALL_INPUTS+// 64-bit LoongArch has CRC32 instructions.+#undef CRC32_LOONGARCH ++// ARM64+//+// 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 CRC_ARM64_RUNTIME_DETECTION 1+#endif+ // 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@@ -82,21 +105,40 @@ # if defined(__ARM_FEATURE_CRC32) # define CRC32_ARCH_OPTIMIZED 1 # define CRC32_ARM64 1-# elif defined(ARM64_RUNTIME_DETECTION)+# elif defined(CRC_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.++// LoongArch //-// 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__)) \+// Only 64-bit LoongArch is supported for now. No runtime detection+// is needed because the LoongArch specification says that the CRC32+// instructions are a part of the Basic Integer Instructions and+// they shall be implemented by 64-bit LoongArch implementations.+#ifdef HAVE_LOONGARCH_CRC32+# define CRC32_ARCH_OPTIMIZED 1+# define CRC32_LOONGARCH 1+#endif+++// x86 and E2K+#if defined(HAVE_USABLE_CLMUL)+ // If CLMUL is allowed unconditionally in the compiler options then+ // the generic version and the tables can be omitted. Exceptions:+ //+ // - If 32-bit x86 assembly files are enabled then those are always+ // built and runtime detection is used even if compiler flags+ // were set to allow CLMUL unconditionally.+ //+ // - This doesn't work with MSVC as I don't know how to detect+ // the features here.+ //+# if (defined(__SSSE3__) && defined(__SSE4_1__) && defined(__PCLMUL__) \+ && !defined(HAVE_CRC_X86_ASM)) \ || (defined(__e2k__) && __iset__ >= 6) # define CRC32_ARCH_OPTIMIZED 1 # define CRC64_ARCH_OPTIMIZED 1@@ -107,21 +149,12 @@ # 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 ++// Fallback configuration+// // For CRC32 use the generic slice-by-eight implementation if no optimized // version is available. #if !defined(CRC32_ARCH_OPTIMIZED) && !defined(CRC32_GENERIC)
cbits/liblzma/check/crc_x86_clmul.h view
@@ -8,26 +8,20 @@ /// 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+/// See the Intel white paper "Fast CRC Computation for Generic Polynomials+/// Using PCLMULQDQ Instruction" from 2009. The original file seems to be+/// gone from Intel's website but a version is available here: /// 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).+/// (The link was checked on 2024-06-11.) /// /// 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.+/// can be built at a time. The version to build is selected by defining+/// BUILDING_CRC_CLMUL to 32 or 64 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.+/// NOTE: The x86 CLMUL CRC implementation was rewritten for XZ Utils 5.8.0. //-// Authors: Ilya Kurdyukov-// Hans Jansen-// Lasse Collin-// Jia Tan+// Authors: Lasse Collin+// Ilya Kurdyukov // /////////////////////////////////////////////////////////////////////////////// @@ -37,6 +31,10 @@ #endif #define LZMA_CRC_X86_CLMUL_H +#if BUILDING_CRC_CLMUL != 32 && BUILDING_CRC_CLMUL != 64+# error BUILDING_CRC_CLMUL is undefined or has an invalid value+#endif+ #include <immintrin.h> #if defined(_MSC_VER)@@ -59,330 +57,277 @@ #endif -#define MASK_L(in, mask, r) r = _mm_shuffle_epi8(in, mask)+// GCC and Clang would produce good code with _mm_set_epi64x+// but MSVC needs _mm_cvtsi64_si128 on x86-64.+#if defined(__i386__) || defined(_M_IX86)+# define my_set_low64(a) _mm_set_epi64x(0, (a))+#else+# define my_set_low64(a) _mm_cvtsi64_si128(a)+#endif -#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)+// Align it so that the whole array is within the same cache line.+// More than one unaligned load can be done from this during the+// same CRC function call.+//+// The bytes [0] to [31] are used with AND to clear the low bytes. (With ANDN+// those could be used to clear the high bytes too but it's not needed here.)+//+// The bytes [16] to [47] are for left shifts.+// The bytes [32] to [63] are for right shifts.+alignas(64)+static uint8_t vmasks[64] = {+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,+}; +// *Unaligned* 128-bit load 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)+static inline __m128i+my_load128(const uint8_t *p) {- // 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);+ return _mm_loadu_si128((const __m128i *)p);+} - // 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);+// Keep the highest "count" bytes as is and clear the remaining low bytes.+crc_attr_target+static inline __m128i+keep_high_bytes(__m128i v, size_t count)+{+ return _mm_and_si128(my_load128((vmasks + count)), v);+} - // 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));+// Shift the 128-bit value left by "amount" bytes (not bits).+crc_attr_target+static inline __m128i+shift_left(__m128i v, size_t amount)+{+ return _mm_shuffle_epi8(v, my_load128((vmasks + 32 - amount)));+} - // 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);- }+// Shift the 128-bit value right by "amount" bytes (not bits).+crc_attr_target+static inline __m128i+shift_right(__m128i v, size_t amount)+{+ return _mm_shuffle_epi8(v, my_load128((vmasks + 32 + amount))); } -/////////////////////-// 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)+crc_attr_target+static inline __m128i+fold(__m128i v, __m128i k) {- 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;+ __m128i a = _mm_clmulepi64_si128(v, k, 0x00);+ __m128i b = _mm_clmulepi64_si128(v, k, 0x11);+ return _mm_xor_si128(a, b); } -// same as ~crc(&a, sizeof(a), ~0)-static uint64_t-calc_hi(uint64_t p, uint64_t a, int n)++crc_attr_target+static inline __m128i+fold_xor(__m128i v, __m128i k, const uint8_t *buf) {- int i;- for (i = 0; i < n; i++)- a = (a >> 1) ^ ((0 - (a & 1)) & p);- return a;+ return _mm_xor_si128(my_load128(buf), fold(v, k)); }-*/ -#ifdef BUILDING_CRC32_CLMUL +#if BUILDING_CRC_CLMUL == 32 crc_attr_target-crc_attr_no_sanitize_address static uint32_t crc32_arch_optimized(const uint8_t *buf, size_t size, uint32_t crc)+#else+crc_attr_target+static uint64_t+crc64_arch_optimized(const uint8_t *buf, size_t size, uint64_t crc)+#endif {-#ifndef CRC_USE_GENERIC_FOR_SMALL_INPUTS- // The code assumes that there is at least one byte of input.+ // We will assume 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+ // See crc_clmul_consts_gen.c.+#if BUILDING_CRC_CLMUL == 32+ const __m128i fold512 = _mm_set_epi64x(0x1d9513d7, 0x8f352d95);+ const __m128i fold128 = _mm_set_epi64x(0xccaa009e, 0xae689191);+ const __m128i mu_p = _mm_set_epi64x(+ (int64_t)0xb4e5b025f7011641, 0x1db710640);+#else+ const __m128i fold512 = _mm_set_epi64x(+ (int64_t)0x081f6054a7842df4, (int64_t)0x6ae3efbb9dd441f3); - const __m128i vfold4 = _mm_set_epi64x(mu, p);- const __m128i vfold8 = _mm_set_epi64x(0, k5);- const __m128i vfold16 = _mm_set_epi64x(k4, k3);+ const __m128i fold128 = _mm_set_epi64x(+ (int64_t)0xdabe95afc7875f40, (int64_t)0xe05dd497ca393ae4); - __m128i v0, v1, v2;+ const __m128i mu_p = _mm_set_epi64x(+ (int64_t)0x9c3e466c172963d5, (int64_t)0x92d8af2baf0e1e84);+#endif - crc_simd_body(buf, size, &v0, &v1, vfold16,- _mm_cvtsi32_si128((int32_t)~crc));+ __m128i v0, v1, v2, v3; - 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+ crc = ~crc; + if (size < 8) {+ uint64_t x = crc;+ size_t i = 0; -/////////////////////-// x86 CLMUL CRC64 //-/////////////////////+ // Checking the bit instead of comparing the size means+ // that we don't need to update the size between the steps.+ if (size & 4) {+ x ^= read32le(buf);+ buf += 4;+ i = 32;+ } -/*-// 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;+ if (size & 2) {+ x ^= (uint64_t)read16le(buf) << i;+ buf += 2;+ i += 16;+ } - for (unsigned i = 0; i < 64; ++i) {- b = (b >> 1) | (a << 63);- a = (a >> 1) ^ (a & 1 ? poly : 0);- }+ if (size & 1)+ x ^= (uint64_t)*buf << i; - return b;-}+ v0 = my_set_low64((int64_t)x);+ v0 = shift_left(v0, 8 - size); -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);+ } else if (size < 16) {+ v0 = my_set_low64((int64_t)(crc ^ read64le(buf))); - return a;-}-*/+ // NOTE: buf is intentionally left 8 bytes behind so that+ // we can read the last 1-7 bytes with read64le(buf + size).+ size -= 8; -#ifdef BUILDING_CRC64_CLMUL+ // Handling 8-byte input specially is a speed optimization+ // as the clmul can be skipped. A branch is also needed to+ // avoid a too high shift amount.+ if (size > 0) {+ const size_t padding = 8 - size;+ uint64_t high = read64le(buf + size) >> (padding * 8); -// 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)+#if defined(__i386__) || defined(_M_IX86)+ // Simple but likely not the best code for 32-bit x86.+ v0 = _mm_insert_epi32(v0, (int32_t)high, 2);+ v0 = _mm_insert_epi32(v0, (int32_t)(high >> 32), 3);+#else+ v0 = _mm_insert_epi64(v0, (int64_t)high, 1); #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+ v0 = shift_left(v0, padding); - // 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)+ v1 = _mm_srli_si128(v0, 8);+ v0 = _mm_clmulepi64_si128(v0, fold128, 0x10);+ v0 = _mm_xor_si128(v0, v1);+ }+ } else {+ v0 = my_set_low64((int64_t)crc); - const __m128i vfold8 = _mm_set_epi64x((int64_t)p, (int64_t)mu);- const __m128i vfold16 = _mm_set_epi64x((int64_t)k2, (int64_t)k1);+ // To align or not to align the buf pointer? If the end of+ // the buffer isn't aligned, aligning the pointer here would+ // make us do an extra folding step with the associated byte+ // shuffling overhead. The cost of that would need to be+ // lower than the benefit of aligned reads. Testing on an old+ // Intel Ivy Bridge processor suggested that aligning isn't+ // worth the cost but it likely depends on the processor and+ // buffer size. Unaligned loads (MOVDQU) should be fast on+ // x86 processors that support PCLMULQDQ, so we don't align+ // the buf pointer here. - __m128i v0, v1, v2;+ // Read the first (and possibly the only) full 16 bytes.+ v0 = _mm_xor_si128(v0, my_load128(buf));+ buf += 16;+ size -= 16; -#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+ if (size >= 48) {+ v1 = my_load128(buf);+ v2 = my_load128(buf + 16);+ v3 = my_load128(buf + 32);+ buf += 48;+ size -= 48; - 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);+ while (size >= 64) {+ v0 = fold_xor(v0, fold512, buf);+ v1 = fold_xor(v1, fold512, buf + 16);+ v2 = fold_xor(v2, fold512, buf + 32);+ v3 = fold_xor(v3, fold512, buf + 48);+ buf += 64;+ size -= 64;+ } + v0 = _mm_xor_si128(v1, fold(v0, fold128));+ v0 = _mm_xor_si128(v2, fold(v0, fold128));+ v0 = _mm_xor_si128(v3, fold(v0, fold128));+ }++ while (size >= 16) {+ v0 = fold_xor(v0, fold128, buf);+ buf += 16;+ size -= 16;+ }++ if (size > 0) {+ // We want the last "size" number of input bytes to+ // be at the high bits of v1. First do a full 16-byte+ // load and then mask the low bytes to zeros.+ v1 = my_load128(buf + size - 16);+ v1 = keep_high_bytes(v1, size);++ // Shift high bytes from v0 to the low bytes of v1.+ //+ // Alternatively we could replace the combination+ // keep_high_bytes + shift_right + _mm_or_si128 with+ // _mm_shuffle_epi8 + _mm_blendv_epi8 but that would+ // require larger tables for the masks. Now there are+ // three loads (instead of two) from the mask tables+ // but they all are from the same cache line.+ v1 = _mm_or_si128(v1, shift_right(v0, size));++ // Shift high bytes of v0 away, padding the+ // low bytes with zeros.+ v0 = shift_left(v0, 16 - size);++ v0 = _mm_xor_si128(v1, fold(v0, fold128));+ }++ v1 = _mm_srli_si128(v0, 8);+ v0 = _mm_clmulepi64_si128(v0, fold128, 0x10);+ v0 = _mm_xor_si128(v0, v1);+ }++ // Barrett reduction++#if BUILDING_CRC_CLMUL == 32+ v1 = _mm_clmulepi64_si128(v0, mu_p, 0x10); // v0 * mu+ v1 = _mm_clmulepi64_si128(v1, mu_p, 0x00); // v1 * p+ v0 = _mm_xor_si128(v0, v1);+ return ~(uint32_t)_mm_extract_epi32(v0, 2);+#else+ // Because p is 65 bits but one bit doesn't fit into the 64-bit+ // half of __m128i, finish the second clmul by shifting v1 left+ // by 64 bits and xorring it to the final result.+ v1 = _mm_clmulepi64_si128(v0, mu_p, 0x10); // v0 * mu+ v2 = _mm_slli_si128(v1, 8);+ v1 = _mm_clmulepi64_si128(v1, mu_p, 0x00); // v1 * p+ v0 = _mm_xor_si128(v0, v2);+ v0 = _mm_xor_si128(v0, v1); #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.
cbits/liblzma/common/alone_decoder.c view
@@ -134,8 +134,7 @@ coder->pos = 0; coder->sequence = SEQ_CODER_INIT;-- // Fall through+ FALLTHROUGH; case SEQ_CODER_INIT: { if (coder->memusage > coder->memlimit)
cbits/liblzma/common/auto_decoder.c view
@@ -79,7 +79,7 @@ return LZMA_GET_CHECK; } - // Fall through+ FALLTHROUGH; case SEQ_CODE: { const lzma_ret ret = coder->next.code(@@ -91,9 +91,8 @@ return ret; coder->sequence = SEQ_FINISH;+ FALLTHROUGH; }-- // Fall through case SEQ_FINISH: // When LZMA_CONCATENATED was used and we were decoding
cbits/liblzma/common/block_decoder.c view
@@ -146,10 +146,9 @@ coder->block->uncompressed_size = coder->uncompressed_size; coder->sequence = SEQ_PADDING;+ FALLTHROUGH; } - // Fall through- case SEQ_PADDING: // Compressed Data is padded to a multiple of four bytes. while (coder->compressed_size & 3) {@@ -173,8 +172,7 @@ lzma_check_finish(&coder->check, coder->block->check); coder->sequence = SEQ_CHECK;-- // Fall through+ FALLTHROUGH; case SEQ_CHECK: { const size_t check_size = lzma_check_size(coder->block->check);
cbits/liblzma/common/block_encoder.c view
@@ -94,10 +94,9 @@ coder->block->uncompressed_size = coder->uncompressed_size; coder->sequence = SEQ_PADDING;+ FALLTHROUGH; } - // 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@@ -117,8 +116,7 @@ lzma_check_finish(&coder->check, coder->block->check); coder->sequence = SEQ_CHECK;-- // Fall through+ FALLTHROUGH; case SEQ_CHECK: { const size_t check_size = lzma_check_size(coder->block->check);
cbits/liblzma/common/common.c view
@@ -348,7 +348,7 @@ else strm->internal->sequence = ISEQ_END; - // Fall through+ FALLTHROUGH; case LZMA_NO_CHECK: case LZMA_UNSUPPORTED_CHECK:
cbits/liblzma/common/file_info.c view
@@ -298,15 +298,13 @@ // Start looking for Stream Padding and Stream Footer // at the end of the file. coder->file_target_pos = coder->file_size;-- // Fall through+ FALLTHROUGH; case SEQ_PADDING_SEEK: coder->sequence = SEQ_PADDING_DECODE; return_if_error(reverse_seek( coder, in_start, in_pos, in_size));-- // Fall through+ FALLTHROUGH; case SEQ_PADDING_DECODE: { // Copy to coder->temp first. This keeps the code simpler if@@ -356,9 +354,9 @@ if (coder->temp_size < LZMA_STREAM_HEADER_SIZE) return_if_error(reverse_seek( coder, in_start, in_pos, in_size));- } - // Fall through+ FALLTHROUGH;+ } case SEQ_FOOTER: // Copy the Stream Footer field into coder->temp.@@ -414,7 +412,7 @@ return LZMA_SEEK_NEEDED; } - // Fall through+ FALLTHROUGH; case SEQ_INDEX_INIT: { // Calculate the amount of memory already used by the earlier@@ -444,10 +442,9 @@ coder->index_remaining = coder->footer_flags.backward_size; coder->sequence = SEQ_INDEX_DECODE;+ FALLTHROUGH; } - // 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@@ -574,9 +571,9 @@ return_if_error(reverse_seek(coder, in_start, in_pos, in_size)); }- } - // Fall through+ FALLTHROUGH;+ } case SEQ_HEADER_DECODE: // Copy the Stream Header field into coder->temp.@@ -596,8 +593,7 @@ coder->temp + coder->temp_size))); coder->sequence = SEQ_HEADER_COMPARE;-- // Fall through+ FALLTHROUGH; case SEQ_HEADER_COMPARE: // Compare Stream Header against Stream Footer. They must
cbits/liblzma/common/index_decoder.c view
@@ -93,8 +93,7 @@ coder->pos = 0; coder->sequence = SEQ_MEMUSAGE;-- // Fall through+ FALLTHROUGH; case SEQ_MEMUSAGE: if (lzma_index_memusage(1, coder->count) > coder->memlimit) {@@ -153,8 +152,7 @@ case SEQ_PADDING_INIT: coder->pos = lzma_index_padding_size(coder->index); coder->sequence = SEQ_PADDING;-- // Fall through+ FALLTHROUGH; case SEQ_PADDING: if (coder->pos > 0) {@@ -170,8 +168,7 @@ *in_pos - in_start, coder->crc32); coder->sequence = SEQ_CRC32;-- // Fall through+ FALLTHROUGH; case SEQ_CRC32: do {
cbits/liblzma/common/index_encoder.c view
@@ -93,8 +93,7 @@ } coder->sequence = SEQ_UNPADDED;-- // Fall through+ FALLTHROUGH; case SEQ_UNPADDED: case SEQ_UNCOMPRESSED: {@@ -127,8 +126,7 @@ *out_pos - out_start, coder->crc32); coder->sequence = SEQ_CRC32;-- // Fall through+ FALLTHROUGH; case SEQ_CRC32: // We don't use the main loop, because we don't want
cbits/liblzma/common/index_hash.c view
@@ -267,9 +267,9 @@ 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+ index_hash->sequence = SEQ_PADDING;+ FALLTHROUGH; case SEQ_PADDING: if (index_hash->pos > 0) {@@ -302,8 +302,7 @@ *in_pos - in_start, index_hash->crc32); index_hash->sequence = SEQ_CRC32;-- // Fall through+ FALLTHROUGH; case SEQ_CRC32: do {
cbits/liblzma/common/lzip_decoder.c view
@@ -150,10 +150,9 @@ coder->member_size = sizeof(lzip_id_string); coder->sequence = SEQ_VERSION;+ FALLTHROUGH; } - // Fall through- case SEQ_VERSION: if (*in_pos >= in_size) return LZMA_OK;@@ -173,7 +172,7 @@ if (coder->tell_any_check) return LZMA_GET_CHECK; - // Fall through+ FALLTHROUGH; case SEQ_DICT_SIZE: { if (*in_pos >= in_size)@@ -220,10 +219,9 @@ // LZMA_MEMLIMIT_ERROR we need to be able to restart after // the memlimit has been increased. coder->sequence = SEQ_CODER_INIT;+ FALLTHROUGH; } - // Fall through- case SEQ_CODER_INIT: { if (coder->memusage > coder->memlimit) return LZMA_MEMLIMIT_ERROR;@@ -243,10 +241,9 @@ coder->crc32 = 0; coder->sequence = SEQ_LZMA_STREAM;+ FALLTHROUGH; } - // Fall through- case SEQ_LZMA_STREAM: { const size_t in_start = *in_pos; const size_t out_start = *out_pos;@@ -273,9 +270,8 @@ return ret; coder->sequence = SEQ_MEMBER_FOOTER;+ FALLTHROUGH; }-- // Fall through case SEQ_MEMBER_FOOTER: { // The footer of .lz version 0 lacks the Member size field.
cbits/liblzma/common/memcmplen.h view
@@ -58,8 +58,7 @@ #if defined(TUKLIB_FAST_UNALIGNED_ACCESS) \ && (((TUKLIB_GNUC_REQ(3, 4) || defined(__clang__)) \- && (defined(__x86_64__) \- || defined(__aarch64__))) \+ && SIZE_MAX == UINT64_MAX) \ || (defined(__INTEL_COMPILER) && defined(__x86_64__)) \ || (defined(__INTEL_COMPILER) && defined(_M_X64)) \ || (defined(_MSC_VER) && (defined(_M_X64) \
cbits/liblzma/common/stream_decoder.c view
@@ -154,9 +154,9 @@ if (coder->tell_any_check) return LZMA_GET_CHECK;- } - // Fall through+ FALLTHROUGH;+ } case SEQ_BLOCK_HEADER: { if (*in_pos >= in_size)@@ -187,10 +187,9 @@ coder->pos = 0; coder->sequence = SEQ_BLOCK_INIT;+ FALLTHROUGH; } - // Fall through- case SEQ_BLOCK_INIT: { // Checking memusage and doing the initialization needs // its own sequence point because we need to be able to@@ -252,10 +251,9 @@ return ret; coder->sequence = SEQ_BLOCK_RUN;+ FALLTHROUGH; } - // Fall through- case SEQ_BLOCK_RUN: { const lzma_ret ret = coder->block_decoder.code( coder->block_decoder.coder, allocator,@@ -291,10 +289,9 @@ return ret; coder->sequence = SEQ_STREAM_FOOTER;+ FALLTHROUGH; } - // 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,@@ -331,9 +328,8 @@ return LZMA_STREAM_END; coder->sequence = SEQ_STREAM_PADDING;+ FALLTHROUGH; }-- // Fall through case SEQ_STREAM_PADDING: assert(coder->concatenated);
cbits/liblzma/common/stream_decoder_mt.c view
@@ -1077,9 +1077,9 @@ if (coder->tell_any_check) return LZMA_GET_CHECK;- } - // Fall through+ FALLTHROUGH;+ } case SEQ_BLOCK_HEADER: { const size_t in_old = *in_pos;@@ -1214,10 +1214,9 @@ } coder->sequence = SEQ_BLOCK_INIT;+ FALLTHROUGH; } - // Fall through- case SEQ_BLOCK_INIT: { // Check if decoding is possible at all with the current // memlimit_stop which we must never exceed.@@ -1303,10 +1302,9 @@ } coder->sequence = SEQ_BLOCK_THR_INIT;+ FALLTHROUGH; } - // 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@@ -1508,10 +1506,9 @@ } coder->sequence = SEQ_BLOCK_THR_RUN;+ FALLTHROUGH; } - // 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@@ -1613,10 +1610,9 @@ coder->mem_direct_mode = coder->mem_next_filters; coder->sequence = SEQ_BLOCK_DIRECT_RUN;+ FALLTHROUGH; } - // Fall through- case SEQ_BLOCK_DIRECT_RUN: { const size_t in_old = *in_pos; const size_t out_old = *out_pos;@@ -1652,8 +1648,7 @@ return LZMA_OK; coder->sequence = SEQ_INDEX_DECODE;-- // Fall through+ FALLTHROUGH; case SEQ_INDEX_DECODE: { // If we don't have any input, don't call@@ -1672,10 +1667,9 @@ return ret; coder->sequence = SEQ_STREAM_FOOTER;+ FALLTHROUGH; } - // Fall through- case SEQ_STREAM_FOOTER: { // Copy the Stream Footer to the internal buffer. const size_t in_old = *in_pos;@@ -1714,9 +1708,8 @@ return LZMA_STREAM_END; coder->sequence = SEQ_STREAM_PADDING;+ FALLTHROUGH; }-- // Fall through case SEQ_STREAM_PADDING: assert(coder->concatenated);
cbits/liblzma/common/stream_encoder_mt.c view
@@ -731,8 +731,7 @@ coder->header_pos = 0; coder->sequence = SEQ_BLOCK;-- // Fall through+ FALLTHROUGH; case SEQ_BLOCK: { // Initialized to silence warnings.@@ -851,9 +850,9 @@ // to be ready to be copied out. coder->progress_out += lzma_index_size(coder->index) + LZMA_STREAM_HEADER_SIZE;- } - // Fall through+ FALLTHROUGH;+ } case SEQ_INDEX: { // Call the Index encoder. It doesn't take any input, so@@ -873,9 +872,8 @@ return LZMA_PROG_ERROR; coder->sequence = SEQ_STREAM_FOOTER;+ FALLTHROUGH; }-- // Fall through case SEQ_STREAM_FOOTER: lzma_bufcpy(coder->header, &coder->header_pos,
cbits/liblzma/common/string_conversion.c view
@@ -12,6 +12,11 @@ #include "filter_common.h" +// liblzma itself doesn't use gettext to translate messages.+// Mark the strings still so that xz can translate them.+#define N_(msgid) msgid++ ///////////////////// // String building // /////////////////////@@ -319,7 +324,7 @@ assert(*str < str_end); if (!(**str >= '0' && **str <= '9'))- return "Unsupported preset";+ return N_("Unsupported preset"); *preset = (uint32_t)(**str - '0'); @@ -331,7 +336,7 @@ break; default:- return "Unsupported preset flag";+ return N_("Unsupported flag in the preset"); } } @@ -350,7 +355,7 @@ lzma_options_lzma *opts = filter_options; if (lzma_lzma_preset(opts, preset))- return "Unsupported preset";+ return N_("Unsupported preset"); return NULL; }@@ -442,7 +447,7 @@ return errmsg; if (opts->lc + opts->lp > LZMA_LCLP_MAX)- return "The sum of lc and lp must not exceed 4";+ return N_("The sum of lc and lp must not exceed 4"); return NULL; }@@ -578,21 +583,21 @@ // 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";+ return N_("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";+ return N_("Unknown option name"); // Find the option name from optmap[]. size_t i = 0; while (true) { if (i == optmap_size)- return "Unknown option name";+ return N_("Unknown option name"); if (memcmp(*str, optmap[i].name, name_len) == 0 && optmap[i].name[name_len] == '\0')@@ -609,7 +614,7 @@ // 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";+ return N_("Option value cannot be empty"); // LZMA1/2 preset has its own parsing function. if (optmap[i].type == OPTMAP_TYPE_LZMA_PRESET) {@@ -630,14 +635,14 @@ // 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";+ return N_("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";+ return N_("Invalid option value"); if (memcmp(*str, map[j].name, value_len) == 0 && map[j].name[value_len]@@ -651,7 +656,8 @@ } 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";+ return N_("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@@ -665,13 +671,13 @@ v = 0; do { if (v > UINT32_MAX / 10)- return "Value out of range";+ return N_("Value out of range"); v *= 10; const uint32_t add = (uint32_t)(*p - '0'); if (UINT32_MAX - add < v)- return "Value out of range";+ return N_("Value out of range"); v += add; ++p;@@ -696,8 +702,9 @@ if ((optmap[i].flags & OPTMAP_USE_BYTE_SUFFIX) == 0) { *str = multiplier_start;- return "This option does not support "- "any integer suffixes";+ return N_("This option does not "+ "support any multiplier "+ "suffixes"); } uint32_t shift;@@ -720,8 +727,13 @@ default: *str = multiplier_start;- return "Invalid multiplier suffix "- "(KiB, MiB, or GiB)";++ // TRANSLATORS: Don't translate the+ // suffixes "KiB", "MiB", or "GiB"+ // because a user can only specify+ // untranslated suffixes.+ return N_("Invalid multiplier suffix "+ "(KiB, MiB, or GiB)"); } ++p;@@ -740,19 +752,19 @@ // Now we must have no chars remaining. if (p < name_eq_value_end) { *str = multiplier_start;- return "Invalid multiplier suffix "- "(KiB, MiB, or GiB)";+ return N_("Invalid multiplier suffix "+ "(KiB, MiB, or GiB)"); } if (v > (UINT32_MAX >> shift))- return "Value out of range";+ return N_("Value out of range"); v <<= shift; } if (v < optmap[i].u.range.min || v > optmap[i].u.range.max)- return "Value out of range";+ return N_("Value out of range"); } // Set the value in filter_options. Enums are handled@@ -814,15 +826,15 @@ // 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";+ return N_("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";+ return N_("This filter cannot be used in "+ "the .xz format"); // Allocate the filter-specific options and // initialize the memory with zeros.@@ -830,7 +842,7 @@ filter_name_map[i].opts_size, allocator); if (options == NULL)- return "Memory allocation failed";+ return N_("Memory allocation failed"); // Filter name was found so the input string is good // at least this far.@@ -850,7 +862,7 @@ } } - return "Unknown filter name";+ return N_("Unknown filter name"); } @@ -869,8 +881,8 @@ ++*str; if (**str == '\0')- return "Empty string is not allowed, "- "try \"6\" if a default value is needed";+ return N_("Empty string is not allowed, "+ "try '6' if a default value is needed"); // Detect the type of the string. //@@ -893,7 +905,7 @@ // there are no chars other than spaces. for (size_t i = 1; str_end[i] != '\0'; ++i) if (str_end[i] != ' ')- return "Unsupported preset";+ return N_("Unsupported preset"); } else { // There are no trailing spaces. Use the whole string. str_end = *str + str_len;@@ -906,11 +918,11 @@ lzma_options_lzma *opts = lzma_alloc(sizeof(*opts), allocator); if (opts == NULL)- return "Memory allocation failed";+ return N_("Memory allocation failed"); if (lzma_lzma_preset(opts, preset)) { lzma_free(opts, allocator);- return "Unsupported preset";+ return N_("Unsupported preset"); } filters[0].id = LZMA_FILTER_LZMA2;@@ -934,7 +946,7 @@ size_t i = 0; do { if (i == LZMA_FILTERS_MAX) {- errmsg = "The maximum number of filters is four";+ errmsg = N_("The maximum number of filters is four"); goto error; } @@ -956,7 +968,7 @@ // 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";+ errmsg = N_("Filter name is missing"); goto error; } @@ -983,8 +995,8 @@ 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?)";+ errmsg = N_("Invalid filter chain "+ "('lzma2' missing at the end?)"); goto error; } }@@ -1012,17 +1024,26 @@ if (error_pos != NULL) *error_pos = 0; - if (str == NULL || filters == NULL)+ if (str == NULL || filters == NULL) {+ // Don't translate this because it's only shown in case of+ // a programming error. 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)+ if (flags & ~supported_flags) {+ // This message is possible only if the caller uses flags+ // that are only supported in a newer liblzma version (or+ // the flags are simply buggy). Don't translate this at least+ // when liblzma itself doesn't use gettext; xz and liblzma+ // are usually upgraded at the same time. return "Unsupported flags to lzma_str_to_filters()";+ } const char *used = str; const char *errmsg = str_to_filters(&used, filters, flags, allocator);
cbits/liblzma/lz/lz_decoder.c view
@@ -53,9 +53,9 @@ static void lz_decoder_reset(lzma_coder *coder) {- coder->dict.pos = 2 * LZ_DICT_REPEAT_MAX;+ coder->dict.pos = LZ_DICT_INIT_POS; coder->dict.full = 0;- coder->dict.buf[2 * LZ_DICT_REPEAT_MAX - 1] = '\0';+ coder->dict.buf[LZ_DICT_INIT_POS - 1] = '\0'; coder->dict.has_wrapped = false; coder->dict.need_reset = false; return;@@ -261,10 +261,12 @@ // recommended to give aligned buffers to liblzma. // // Reserve 2 * LZ_DICT_REPEAT_MAX bytes of extra space which is- // needed for alloc_size.+ // needed for alloc_size. Reserve also LZ_DICT_EXTRA bytes of extra+ // space which is *not* counted in alloc_size or coder->dict.size. // // Avoid integer overflow.- if (lz_options.dict_size > SIZE_MAX - 15 - 2 * LZ_DICT_REPEAT_MAX)+ if (lz_options.dict_size > SIZE_MAX - 15 - 2 * LZ_DICT_REPEAT_MAX+ - LZ_DICT_EXTRA) return LZMA_MEM_ERROR; lz_options.dict_size = (lz_options.dict_size + 15) & ~((size_t)(15));@@ -277,7 +279,13 @@ // 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);++ // The LZ_DICT_EXTRA bytes at the end of the buffer aren't+ // included in alloc_size. These extra bytes allow+ // dict_repeat() to read and write more data than requested.+ // Otherwise this extra space is ignored.+ coder->dict.buf = lzma_alloc(alloc_size + LZ_DICT_EXTRA,+ allocator); if (coder->dict.buf == NULL) return LZMA_MEM_ERROR; @@ -320,5 +328,6 @@ extern uint64_t lzma_lz_decoder_memusage(size_t dictionary_size) {- return sizeof(lzma_coder) + (uint64_t)(dictionary_size);+ return sizeof(lzma_coder) + (uint64_t)(dictionary_size)+ + 2 * LZ_DICT_REPEAT_MAX + LZ_DICT_EXTRA; }
cbits/liblzma/lz/lz_decoder.h view
@@ -15,11 +15,41 @@ #include "common.h" +#ifdef HAVE_IMMINTRIN_H+# include <immintrin.h>+#endif -/// 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:++// dict_repeat() implementation variant:+// 0 = Byte-by-byte copying only.+// 1 = Use memcpy() for non-overlapping copies.+// 2 = Use x86 SSE2 for non-overlapping copies.+#ifndef LZMA_LZ_DECODER_CONFIG+# if defined(TUKLIB_FAST_UNALIGNED_ACCESS) \+ && defined(HAVE_IMMINTRIN_H) \+ && (defined(__SSE2__) || defined(_M_X64) \+ || (defined(_M_IX86_FP) && _M_IX86_FP >= 2))+# define LZMA_LZ_DECODER_CONFIG 2+# else+# define LZMA_LZ_DECODER_CONFIG 1+# endif+#endif++/// Byte-by-byte and memcpy() copy exactly the amount needed. Other methods+/// can copy up to LZ_DICT_EXTRA bytes more than requested, and this amount+/// of extra space is needed at the end of the allocated dictionary buffer. ///+/// NOTE: If this is increased, update LZMA_DICT_REPEAT_MAX too.+#if LZMA_LZ_DECODER_CONFIG >= 2+# define LZ_DICT_EXTRA 32+#else+# define LZ_DICT_EXTRA 0+#endif++/// Maximum number of bytes that dict_repeat() may copy. The allocated+/// dictionary buffer will be 2 * LZ_DICT_REPEAT_MAX + LZMA_DICT_EXTRA 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,@@ -27,15 +57,27 @@ /// /// (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)+/// position. This way dict_repeat() with the maximum valid distance /// won't need memmove() as the copying cannot overlap. ///+/// (3) LZ_DICT_EXTRA bytes are required at the end of the dictionary buffer+/// so that extra copying done by dict_repeat() won't write or read past+/// the end of the allocated buffer. This amount is *not* counted as part+/// of lzma_dict.size.+/// /// 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.+/// LZMA's longest match length is 273 bytes. The LZMA decoder looks at+/// the lowest four bits of the dictionary position, thus 273 must be+/// rounded up to the next multiple of 16 (288). In addition, optimized+/// dict_repeat() copies 32 bytes at a time, thus this must also be+/// a multiple of 32. #define LZ_DICT_REPEAT_MAX 288 +/// Initial position in lzma_dict.buf when the dictionary is empty.+#define LZ_DICT_INIT_POS (2 * LZ_DICT_REPEAT_MAX) + typedef struct { /// Pointer to the dictionary buffer. uint8_t *buf;@@ -158,7 +200,8 @@ /// Repeat *len bytes at distance. static inline bool-dict_repeat(lzma_dict *dict, uint32_t distance, uint32_t *len)+dict_repeat(lzma_dict *restrict dict,+ uint32_t distance, uint32_t *restrict len) { // Don't write past the end of the dictionary. const size_t dict_avail = dict->limit - dict->pos;@@ -169,9 +212,17 @@ 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 LZMA_LZ_DECODER_CONFIG == 0+ // Minimal byte-by-byte method. This might be the least bad choice+ // if memcpy() isn't fast and there's no replacement for it below.+ while (left-- > 0) {+ dict->buf[dict->pos++] = dict->buf[back++];+ }++#else+ // Because memcpy() or a similar method can be faster than copying+ // byte by byte in a loop, the copying process is split into+ // two cases. if (distance < left) { // Source and target areas overlap, thus we can't use // memcpy() nor even memmove() safely.@@ -179,32 +230,56 @@ dict->buf[dict->pos++] = dict->buf[back++]; } while (--left > 0); } else {+# if LZMA_LZ_DECODER_CONFIG == 1 memcpy(dict->buf + dict->pos, dict->buf + back, left); dict->pos += left;++# elif LZMA_LZ_DECODER_CONFIG == 2+ // This can copy up to 32 bytes more than required.+ // (If left == 0, we still copy 32 bytes.)+ size_t pos = dict->pos;+ dict->pos += left;+ do {+ const __m128i x0 = _mm_loadu_si128(+ (__m128i *)(dict->buf + back));+ const __m128i x1 = _mm_loadu_si128(+ (__m128i *)(dict->buf + back + 16));+ back += 32;+ _mm_storeu_si128(+ (__m128i *)(dict->buf + pos), x0);+ _mm_storeu_si128(+ (__m128i *)(dict->buf + pos + 16), x1);+ pos += 32;+ } while (pos < dict->pos);++# else+# error "Invalid LZMA_LZ_DECODER_CONFIG value"+# endif }+#endif // Update how full the dictionary is. if (!dict->has_wrapped)- dict->full = dict->pos - 2 * LZ_DICT_REPEAT_MAX;+ dict->full = dict->pos - LZ_DICT_INIT_POS; return *len != 0; } static inline void-dict_put(lzma_dict *dict, uint8_t byte)+dict_put(lzma_dict *restrict dict, uint8_t byte) { dict->buf[dict->pos++] = byte; if (!dict->has_wrapped)- dict->full = dict->pos - 2 * LZ_DICT_REPEAT_MAX;+ dict->full = dict->pos - LZ_DICT_INIT_POS; } /// 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)+dict_put_safe(lzma_dict *restrict dict, uint8_t byte) { if (unlikely(dict->pos == dict->limit)) return true;@@ -234,7 +309,7 @@ dict->buf, &dict->pos, dict->limit); if (!dict->has_wrapped)- dict->full = dict->pos - 2 * LZ_DICT_REPEAT_MAX;+ dict->full = dict->pos - LZ_DICT_INIT_POS; return; }
cbits/liblzma/lz/lz_encoder.c view
@@ -15,7 +15,7 @@ // 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)+#ifdef LZMA_LZ_HASH_TABLE_IS_NEEDED # include "lz_encoder_hash_table.h" #endif
cbits/liblzma/lz/lz_encoder_hash.h view
@@ -5,23 +5,37 @@ /// \file lz_encoder_hash.h /// \brief Hash macros for match finders //-// Author: Igor Pavlov+// Authors: Igor Pavlov+// Lasse Collin // /////////////////////////////////////////////////////////////////////////////// #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.+// We need to know if CRC32_GENERIC is defined and we may need the declaration+// of lzma_crc32_table[][].+#include "crc_common.h"++// If HAVE_SMALL is defined, then lzma_crc32_table[][] exists and+// it's little endian even on big endian systems.+//+// If HAVE_SMALL isn't defined, lzma_crc32_table[][] is in native endian+// but we want a little endian one so that the compressed output won't+// depend on the processor endianness. Big endian systems are less common+// so those get the burden of an extra 1 KiB table.+//+// If HAVE_SMALL isn't defined and CRC32_GENERIC isn't defined either,+// then lzma_crc32_table[][] doesn't exist.+#if defined(HAVE_SMALL) \+ || (defined(CRC32_GENERIC) && !defined(WORDS_BIGENDIAN))+# define hash_table lzma_crc32_table[0]+#else+ // 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]+# define LZMA_LZ_HASH_TABLE_IS_NEEDED 1 #endif #define HASH_2_SIZE (UINT32_C(1) << 10)
cbits/liblzma/lzma/lzma2_encoder.c view
@@ -159,8 +159,7 @@ coder->uncompressed_size = 0; coder->compressed_size = 0; coder->sequence = SEQ_LZMA_ENCODE;-- // Fall through+ FALLTHROUGH; case SEQ_LZMA_ENCODE: { // Calculate how much more uncompressed data this chunk@@ -219,10 +218,9 @@ lzma2_header_lzma(coder); coder->sequence = SEQ_LZMA_COPY;+ FALLTHROUGH; } - // Fall through- case SEQ_LZMA_COPY: // Copy the compressed chunk along its headers to the // output buffer.@@ -244,8 +242,7 @@ return LZMA_OK; coder->sequence = SEQ_UNCOMPRESSED_COPY;-- // Fall through+ FALLTHROUGH; case SEQ_UNCOMPRESSED_COPY: // Copy the uncompressed data as is from the dictionary
cbits/liblzma/simple/arm.c view
@@ -18,8 +18,10 @@ uint32_t now_pos, bool is_encoder, uint8_t *buffer, size_t size) {+ size &= ~(size_t)3;+ size_t i;- for (i = 0; i + 4 <= size; i += 4) {+ for (i = 0; i < size; i += 4) { if (buffer[i + 3] == 0xEB) { uint32_t src = ((uint32_t)(buffer[i + 2]) << 16) | ((uint32_t)(buffer[i + 1]) << 8)
cbits/liblzma/simple/arm64.c view
@@ -28,6 +28,8 @@ uint32_t now_pos, bool is_encoder, uint8_t *buffer, size_t size) {+ size &= ~(size_t)3;+ size_t i; // Clang 14.0.6 on x86-64 makes this four times bigger and 40 % slower@@ -37,7 +39,7 @@ #ifdef __clang__ # pragma clang loop vectorize(disable) #endif- for (i = 0; i + 4 <= size; i += 4) {+ for (i = 0; i < size; i += 4) { uint32_t pc = (uint32_t)(now_pos + i); uint32_t instr = read32le(buffer + i); @@ -122,6 +124,15 @@ { return arm64_coder_init(next, allocator, filters, true); }+++extern LZMA_API(size_t)+lzma_bcj_arm64_encode(uint32_t start_offset, uint8_t *buf, size_t size)+{+ // start_offset must be a multiple of four.+ start_offset &= ~UINT32_C(3);+ return arm64_code(NULL, start_offset, true, buf, size);+} #endif @@ -132,5 +143,14 @@ const lzma_filter_info *filters) { return arm64_coder_init(next, allocator, filters, false);+}+++extern LZMA_API(size_t)+lzma_bcj_arm64_decode(uint32_t start_offset, uint8_t *buf, size_t size)+{+ // start_offset must be a multiple of four.+ start_offset &= ~UINT32_C(3);+ return arm64_code(NULL, start_offset, false, buf, size); } #endif
cbits/liblzma/simple/armthumb.c view
@@ -18,8 +18,13 @@ uint32_t now_pos, bool is_encoder, uint8_t *buffer, size_t size) {+ if (size < 4)+ return 0;++ size -= 4;+ size_t i;- for (i = 0; i + 4 <= size; i += 2) {+ for (i = 0; i <= size; i += 2) { if ((buffer[i + 1] & 0xF8) == 0xF0 && (buffer[i + 3] & 0xF8) == 0xF8) { uint32_t src = (((uint32_t)(buffer[i + 1]) & 7) << 19)
cbits/liblzma/simple/ia64.c view
@@ -25,8 +25,10 @@ 4, 4, 0, 0, 4, 4, 0, 0 }; + size &= ~(size_t)15;+ size_t i;- for (i = 0; i + 16 <= size; i += 16) {+ for (i = 0; i < size; i += 16) { const uint32_t instr_template = buffer[i] & 0x1F; const uint32_t mask = BRANCH_TABLE[instr_template]; uint32_t bit_pos = 5;
cbits/liblzma/simple/powerpc.c view
@@ -18,8 +18,10 @@ uint32_t now_pos, bool is_encoder, uint8_t *buffer, size_t size) {+ size &= ~(size_t)3;+ size_t i;- for (i = 0; i + 4 <= size; i += 4) {+ for (i = 0; i < size; i += 4) { // PowerPC branch 6(48) 24(Offset) 1(Abs) 1(Link) if ((buffer[i] >> 2) == 0x12 && ((buffer[i + 3] & 3) == 1)) {
cbits/liblzma/simple/riscv.c view
@@ -617,6 +617,15 @@ return lzma_simple_coder_init(next, allocator, filters, &riscv_encode, 0, 8, 2, true); }+++extern LZMA_API(size_t)+lzma_bcj_riscv_encode(uint32_t start_offset, uint8_t *buf, size_t size)+{+ // start_offset must be a multiple of two.+ start_offset &= ~UINT32_C(1);+ return riscv_encode(NULL, start_offset, true, buf, size);+} #endif @@ -751,5 +760,14 @@ { return lzma_simple_coder_init(next, allocator, filters, &riscv_decode, 0, 8, 2, false);+}+++extern LZMA_API(size_t)+lzma_bcj_riscv_decode(uint32_t start_offset, uint8_t *buf, size_t size)+{+ // start_offset must be a multiple of two.+ start_offset &= ~UINT32_C(1);+ return riscv_decode(NULL, start_offset, false, buf, size); } #endif
cbits/liblzma/simple/sparc.c view
@@ -18,9 +18,10 @@ uint32_t now_pos, bool is_encoder, uint8_t *buffer, size_t size) {- size_t i;- for (i = 0; i + 4 <= size; i += 4) {+ size &= ~(size_t)3; + size_t i;+ for (i = 0; i < size; i += 4) { if ((buffer[i] == 0x40 && (buffer[i + 1] & 0xC0) == 0x00) || (buffer[i] == 0x7F && (buffer[i + 1] & 0xC0) == 0xC0)) {
cbits/liblzma/simple/x86.c view
@@ -143,6 +143,18 @@ { return x86_coder_init(next, allocator, filters, true); }+++extern LZMA_API(size_t)+lzma_bcj_x86_encode(uint32_t start_offset, uint8_t *buf, size_t size)+{+ lzma_simple_x86 simple = {+ .prev_mask = 0,+ .prev_pos = (uint32_t)(-5),+ };++ return x86_code(&simple, start_offset, true, buf, size);+} #endif @@ -153,5 +165,17 @@ const lzma_filter_info *filters) { return x86_coder_init(next, allocator, filters, false);+}+++extern LZMA_API(size_t)+lzma_bcj_x86_decode(uint32_t start_offset, uint8_t *buf, size_t size)+{+ lzma_simple_x86 simple = {+ .prev_mask = 0,+ .prev_pos = (uint32_t)(-5),+ };++ return x86_code(&simple, start_offset, false, buf, size); } #endif
configure view
@@ -4903,22 +4903,22 @@ else case e in #( e) gl_test_posix_shell_script=' func_return () {- (exit $1)+ (exit $1) } func_success () {- func_return 0+ func_return 0 } func_failure () {- func_return 1+ func_return 1 } func_ret_success () {- return 0+ return 0 } func_ret_failure () {- return 1+ return 1 } subshell_umask_sanity () {- (umask 22; (umask 0); test $(umask) -eq 22)+ (umask 22; (umask 0); test $(umask) -eq 22) } test "$(echo foo)" = foo && func_success &&@@ -4929,11 +4929,11 @@ subshell_umask_sanity ' for gl_cv_posix_shell in \- "$CONFIG_SHELL" "$SHELL" /bin/sh /bin/bash /bin/ksh /bin/sh5 no; do+ "$CONFIG_SHELL" "$SHELL" /bin/sh /bin/bash /bin/ksh /bin/sh5 no; do case $gl_cv_posix_shell in /*)- "$gl_cv_posix_shell" -c "$gl_test_posix_shell_script" 2>/dev/null \- && break;;+ "$gl_cv_posix_shell" -c "$gl_test_posix_shell_script" 2>/dev/null \+ && break;; esac done ;; esac@@ -20052,8 +20052,6 @@ esac - gl_replace_getopt=- if test -z "$gl_replace_getopt"; then for ac_header in getopt.h do :@@ -21117,6 +21115,12 @@ if test "x$ac_cv_func_wcwidth" = xyes then : printf "%s\n" "#define HAVE_WCWIDTH 1" >>confdefs.h++fi+ac_fn_c_check_func "$LINENO" "vasprintf" "ac_cv_func_vasprintf"+if test "x$ac_cv_func_vasprintf" = xyes+then :+ printf "%s\n" "#define HAVE_VASPRINTF 1" >>confdefs.h fi
xz-clib.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: xz-clib-version: 5.6.4+version: 5.8.0 synopsis: LZMA/XZ clibs description: C source code for the LZMA/XZ compression and decompression library@@ -54,12 +54,13 @@ default-language: Haskell2010 c-sources: cbits/common/tuklib_cpucores.c+ cbits/common/tuklib_mbstr_nonprint.c+ cbits/common/tuklib_mbstr_wrap.c cbits/common/tuklib_physmem.c cbits/liblzma/check/check.c cbits/liblzma/check/crc32_fast.c- cbits/liblzma/check/crc32_table.c cbits/liblzma/check/crc64_fast.c- cbits/liblzma/check/crc64_table.c+ cbits/liblzma/check/crc_clmul_consts_gen.c cbits/liblzma/check/sha256.c cbits/liblzma/common/alone_decoder.c cbits/liblzma/common/alone_encoder.c