summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 03:10:08 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 03:10:08 +0000
commit5262a872f308b3b584c97d621992fb3877e392b8 (patch)
treeb956c322376141abeafe639bd72cfecdf16954b5 /tests
parentInitial commit. (diff)
downloadxz-utils-5262a872f308b3b584c97d621992fb3877e392b8.tar.xz
xz-utils-5262a872f308b3b584c97d621992fb3877e392b8.zip
Adding upstream version 5.6.1+really5.4.5.upstream/5.6.1+really5.4.5
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.am76
-rw-r--r--tests/Makefile.in1349
-rw-r--r--tests/bcj_test.c65
-rw-r--r--tests/compress_prepared_bcj_sparcbin0 -> 1240 bytes
-rw-r--r--tests/compress_prepared_bcj_x86bin0 -> 1388 bytes
-rw-r--r--tests/create_compress_files.c163
-rw-r--r--tests/files/README409
-rw-r--r--tests/files/bad-0-backward_size.xzbin0 -> 32 bytes
-rw-r--r--tests/files/bad-0-empty-truncated.xzbin0 -> 31 bytes
-rw-r--r--tests/files/bad-0-footer_magic.xzbin0 -> 32 bytes
-rw-r--r--tests/files/bad-0-header_magic.xzbin0 -> 32 bytes
-rw-r--r--tests/files/bad-0-nonempty_index.xzbin0 -> 32 bytes
-rw-r--r--tests/files/bad-0cat-alone.xzbin0 -> 55 bytes
-rw-r--r--tests/files/bad-0cat-header_magic.xzbin0 -> 64 bytes
-rw-r--r--tests/files/bad-0catpad-empty.xzbin0 -> 69 bytes
-rw-r--r--tests/files/bad-0pad-empty.xzbin0 -> 37 bytes
-rw-r--r--tests/files/bad-1-block_header-1.xzbin0 -> 64 bytes
-rw-r--r--tests/files/bad-1-block_header-2.xzbin0 -> 64 bytes
-rw-r--r--tests/files/bad-1-block_header-3.xzbin0 -> 68 bytes
-rw-r--r--tests/files/bad-1-block_header-4.xzbin0 -> 76 bytes
-rw-r--r--tests/files/bad-1-block_header-5.xzbin0 -> 72 bytes
-rw-r--r--tests/files/bad-1-block_header-6.xzbin0 -> 72 bytes
-rw-r--r--tests/files/bad-1-check-crc32-2.xzbin0 -> 72 bytes
-rw-r--r--tests/files/bad-1-check-crc32.xzbin0 -> 68 bytes
-rw-r--r--tests/files/bad-1-check-crc64.xzbin0 -> 72 bytes
-rw-r--r--tests/files/bad-1-check-sha256.xzbin0 -> 96 bytes
-rw-r--r--tests/files/bad-1-lzma2-1.xzbin0 -> 64 bytes
-rw-r--r--tests/files/bad-1-lzma2-10.xzbin0 -> 60 bytes
-rw-r--r--tests/files/bad-1-lzma2-11.xzbin0 -> 64 bytes
-rw-r--r--tests/files/bad-1-lzma2-2.xzbin0 -> 424 bytes
-rw-r--r--tests/files/bad-1-lzma2-3.xzbin0 -> 424 bytes
-rw-r--r--tests/files/bad-1-lzma2-4.xzbin0 -> 408 bytes
-rw-r--r--tests/files/bad-1-lzma2-5.xzbin0 -> 408 bytes
-rw-r--r--tests/files/bad-1-lzma2-6.xzbin0 -> 68 bytes
-rw-r--r--tests/files/bad-1-lzma2-7.xzbin0 -> 408 bytes
-rw-r--r--tests/files/bad-1-lzma2-8.xzbin0 -> 464 bytes
-rw-r--r--tests/files/bad-1-lzma2-9.xzbin0 -> 72 bytes
-rw-r--r--tests/files/bad-1-stream_flags-1.xzbin0 -> 68 bytes
-rw-r--r--tests/files/bad-1-stream_flags-2.xzbin0 -> 68 bytes
-rw-r--r--tests/files/bad-1-stream_flags-3.xzbin0 -> 68 bytes
-rw-r--r--tests/files/bad-1-v0-uncomp-size.lzbin0 -> 42 bytes
-rw-r--r--tests/files/bad-1-v1-crc32.lzbin0 -> 50 bytes
-rw-r--r--tests/files/bad-1-v1-dict-1.lzbin0 -> 50 bytes
-rw-r--r--tests/files/bad-1-v1-dict-2.lzbin0 -> 50 bytes
-rw-r--r--tests/files/bad-1-v1-magic-1.lzbin0 -> 50 bytes
-rw-r--r--tests/files/bad-1-v1-magic-2.lzbin0 -> 50 bytes
-rw-r--r--tests/files/bad-1-v1-member-size.lzbin0 -> 50 bytes
-rw-r--r--tests/files/bad-1-v1-trailing-magic.lzbin0 -> 54 bytes
-rw-r--r--tests/files/bad-1-v1-uncomp-size.lzbin0 -> 50 bytes
-rw-r--r--tests/files/bad-1-vli-1.xzbin0 -> 72 bytes
-rw-r--r--tests/files/bad-1-vli-2.xzbin0 -> 76 bytes
-rw-r--r--tests/files/bad-2-compressed_data_padding.xzbin0 -> 92 bytes
-rw-r--r--tests/files/bad-2-index-1.xzbin0 -> 92 bytes
-rw-r--r--tests/files/bad-2-index-2.xzbin0 -> 92 bytes
-rw-r--r--tests/files/bad-2-index-3.xzbin0 -> 92 bytes
-rw-r--r--tests/files/bad-2-index-4.xzbin0 -> 92 bytes
-rw-r--r--tests/files/bad-2-index-5.xzbin0 -> 92 bytes
-rw-r--r--tests/files/bad-3-index-uncomp-overflow.xzbin0 -> 132 bytes
-rw-r--r--tests/files/bad-too_big_size-with_eopm.lzmabin0 -> 37 bytes
-rw-r--r--tests/files/bad-too_small_size-without_eopm-1.lzmabin0 -> 31 bytes
-rw-r--r--tests/files/bad-too_small_size-without_eopm-2.lzmabin0 -> 31 bytes
-rw-r--r--tests/files/bad-too_small_size-without_eopm-3.lzmabin0 -> 36 bytes
-rw-r--r--tests/files/bad-unknown_size-without_eopm.lzmabin0 -> 31 bytes
-rw-r--r--tests/files/good-0-empty.xzbin0 -> 32 bytes
-rw-r--r--tests/files/good-0cat-empty.xzbin0 -> 64 bytes
-rw-r--r--tests/files/good-0catpad-empty.xzbin0 -> 68 bytes
-rw-r--r--tests/files/good-0pad-empty.xzbin0 -> 36 bytes
-rw-r--r--tests/files/good-1-3delta-lzma2.xzbin0 -> 528 bytes
-rw-r--r--tests/files/good-1-arm64-lzma2-1.xzbin0 -> 512 bytes
-rw-r--r--tests/files/good-1-arm64-lzma2-2.xzbin0 -> 488 bytes
-rw-r--r--tests/files/good-1-block_header-1.xzbin0 -> 72 bytes
-rw-r--r--tests/files/good-1-block_header-2.xzbin0 -> 68 bytes
-rw-r--r--tests/files/good-1-block_header-3.xzbin0 -> 68 bytes
-rw-r--r--tests/files/good-1-check-crc32.xzbin0 -> 68 bytes
-rw-r--r--tests/files/good-1-check-crc64.xzbin0 -> 72 bytes
-rw-r--r--tests/files/good-1-check-none.xzbin0 -> 64 bytes
-rw-r--r--tests/files/good-1-check-sha256.xzbin0 -> 96 bytes
-rw-r--r--tests/files/good-1-delta-lzma2.tiff.xzbin0 -> 51316 bytes
-rw-r--r--tests/files/good-1-empty-bcj-lzma2.xzbin0 -> 52 bytes
-rw-r--r--tests/files/good-1-lzma2-1.xzbin0 -> 424 bytes
-rw-r--r--tests/files/good-1-lzma2-2.xzbin0 -> 424 bytes
-rw-r--r--tests/files/good-1-lzma2-3.xzbin0 -> 408 bytes
-rw-r--r--tests/files/good-1-lzma2-4.xzbin0 -> 464 bytes
-rw-r--r--tests/files/good-1-lzma2-5.xzbin0 -> 52 bytes
-rw-r--r--tests/files/good-1-sparc-lzma2.xzbin0 -> 612 bytes
-rw-r--r--tests/files/good-1-v0-trailing-1.lzbin0 -> 59 bytes
-rw-r--r--tests/files/good-1-v0.lzbin0 -> 42 bytes
-rw-r--r--tests/files/good-1-v1-trailing-1.lzbin0 -> 67 bytes
-rw-r--r--tests/files/good-1-v1-trailing-2.lzbin0 -> 70 bytes
-rw-r--r--tests/files/good-1-v1.lzbin0 -> 50 bytes
-rw-r--r--tests/files/good-1-x86-lzma2.xzbin0 -> 716 bytes
-rw-r--r--tests/files/good-2-lzma2.xzbin0 -> 92 bytes
-rw-r--r--tests/files/good-2-v0-v1.lzbin0 -> 78 bytes
-rw-r--r--tests/files/good-2-v1-v0.lzbin0 -> 78 bytes
-rw-r--r--tests/files/good-2-v1-v1.lzbin0 -> 86 bytes
-rw-r--r--tests/files/good-known_size-with_eopm.lzmabin0 -> 37 bytes
-rw-r--r--tests/files/good-known_size-without_eopm.lzmabin0 -> 31 bytes
-rw-r--r--tests/files/good-unknown_size-with_eopm.lzmabin0 -> 37 bytes
-rw-r--r--tests/files/unsupported-1-v234.lzbin0 -> 50 bytes
-rw-r--r--tests/files/unsupported-block_header.xzbin0 -> 68 bytes
-rw-r--r--tests/files/unsupported-check.xzbin0 -> 68 bytes
-rw-r--r--tests/files/unsupported-filter_flags-1.xzbin0 -> 68 bytes
-rw-r--r--tests/files/unsupported-filter_flags-2.xzbin0 -> 68 bytes
-rw-r--r--tests/files/unsupported-filter_flags-3.xzbin0 -> 68 bytes
-rw-r--r--tests/ossfuzz/Makefile7
-rw-r--r--tests/ossfuzz/config/fuzz.dict2
-rw-r--r--tests/ossfuzz/config/fuzz.options2
-rw-r--r--tests/ossfuzz/fuzz.c82
-rw-r--r--tests/test_bcj_exact_size.c124
-rw-r--r--tests/test_block_header.c520
-rw-r--r--tests/test_check.c390
-rwxr-xr-xtests/test_compress.sh150
-rwxr-xr-xtests/test_compress_generated_abc3
-rwxr-xr-xtests/test_compress_generated_random3
-rwxr-xr-xtests/test_compress_generated_text3
-rwxr-xr-xtests/test_compress_prepared_bcj_sparc3
-rwxr-xr-xtests/test_compress_prepared_bcj_x863
-rwxr-xr-xtests/test_files.sh197
-rw-r--r--tests/test_filter_flags.c527
-rw-r--r--tests/test_filter_str.c593
-rw-r--r--tests/test_hardware.c50
-rw-r--r--tests/test_index.c1715
-rw-r--r--tests/test_index_hash.c386
-rw-r--r--tests/test_lzip_decoder.c488
-rw-r--r--tests/test_memlimit.c173
-rwxr-xr-xtests/test_scripts.sh81
-rw-r--r--tests/test_stream_flags.c479
-rw-r--r--tests/test_vli.c324
-rw-r--r--tests/tests.h75
-rw-r--r--tests/tuktest.h1053
-rw-r--r--tests/xzgrep_expected_output39
131 files changed, 9534 insertions, 0 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..ebc33a7
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,76 @@
+##
+## Author: Lasse Collin
+##
+## This file has been put into the public domain.
+## You can do whatever you want with this file.
+##
+
+EXTRA_DIST = \
+ files \
+ ossfuzz \
+ tuktest.h \
+ tests.h \
+ test_files.sh \
+ test_compress.sh \
+ test_compress_prepared_bcj_sparc \
+ test_compress_prepared_bcj_x86 \
+ test_compress_generated_abc \
+ test_compress_generated_random \
+ test_compress_generated_text \
+ test_scripts.sh \
+ bcj_test.c \
+ compress_prepared_bcj_sparc \
+ compress_prepared_bcj_x86 \
+ xzgrep_expected_output
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/common \
+ -I$(top_srcdir)/src/liblzma/api \
+ -I$(top_srcdir)/src/liblzma
+
+LDADD = $(top_builddir)/src/liblzma/liblzma.la
+
+LDADD += $(LTLIBINTL)
+
+check_PROGRAMS = \
+ create_compress_files \
+ test_check \
+ test_hardware \
+ test_stream_flags \
+ test_filter_flags \
+ test_filter_str \
+ test_block_header \
+ test_index \
+ test_index_hash \
+ test_bcj_exact_size \
+ test_memlimit \
+ test_lzip_decoder \
+ test_vli
+
+TESTS = \
+ test_check \
+ test_hardware \
+ test_stream_flags \
+ test_filter_flags \
+ test_filter_str \
+ test_block_header \
+ test_index \
+ test_index_hash \
+ test_bcj_exact_size \
+ test_memlimit \
+ test_lzip_decoder \
+ test_vli \
+ test_files.sh \
+ test_compress_prepared_bcj_sparc \
+ test_compress_prepared_bcj_x86 \
+ test_compress_generated_abc \
+ test_compress_generated_random \
+ test_compress_generated_text
+
+if COND_SCRIPTS
+TESTS += test_scripts.sh
+endif
+
+clean-local:
+ -rm -f compress_generated_* \
+ xzgrep_test_output xzgrep_test_1.xz xzgrep_test_2.xz
diff --git a/tests/Makefile.in b/tests/Makefile.in
new file mode 100644
index 0000000..46cf0f0
--- /dev/null
+++ b/tests/Makefile.in
@@ -0,0 +1,1349 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = create_compress_files$(EXEEXT) test_check$(EXEEXT) \
+ test_hardware$(EXEEXT) test_stream_flags$(EXEEXT) \
+ test_filter_flags$(EXEEXT) test_filter_str$(EXEEXT) \
+ test_block_header$(EXEEXT) test_index$(EXEEXT) \
+ test_index_hash$(EXEEXT) test_bcj_exact_size$(EXEEXT) \
+ test_memlimit$(EXEEXT) test_lzip_decoder$(EXEEXT) \
+ test_vli$(EXEEXT)
+TESTS = test_check$(EXEEXT) test_hardware$(EXEEXT) \
+ test_stream_flags$(EXEEXT) test_filter_flags$(EXEEXT) \
+ test_filter_str$(EXEEXT) test_block_header$(EXEEXT) \
+ test_index$(EXEEXT) test_index_hash$(EXEEXT) \
+ test_bcj_exact_size$(EXEEXT) test_memlimit$(EXEEXT) \
+ test_lzip_decoder$(EXEEXT) test_vli$(EXEEXT) test_files.sh \
+ test_compress_prepared_bcj_sparc \
+ test_compress_prepared_bcj_x86 test_compress_generated_abc \
+ test_compress_generated_random test_compress_generated_text \
+ $(am__append_1)
+@COND_SCRIPTS_TRUE@am__append_1 = test_scripts.sh
+subdir = tests
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_capsicum.m4 \
+ $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/host-cpu-c-abi.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
+ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/posix-shell.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/m4/tuklib_common.m4 \
+ $(top_srcdir)/m4/tuklib_cpucores.m4 \
+ $(top_srcdir)/m4/tuklib_integer.m4 \
+ $(top_srcdir)/m4/tuklib_mbstr.m4 \
+ $(top_srcdir)/m4/tuklib_physmem.m4 \
+ $(top_srcdir)/m4/tuklib_progname.m4 \
+ $(top_srcdir)/m4/visibility.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+create_compress_files_SOURCES = create_compress_files.c
+create_compress_files_OBJECTS = create_compress_files.$(OBJEXT)
+create_compress_files_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+create_compress_files_DEPENDENCIES = \
+ $(top_builddir)/src/liblzma/liblzma.la $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+test_bcj_exact_size_SOURCES = test_bcj_exact_size.c
+test_bcj_exact_size_OBJECTS = test_bcj_exact_size.$(OBJEXT)
+test_bcj_exact_size_LDADD = $(LDADD)
+test_bcj_exact_size_DEPENDENCIES = \
+ $(top_builddir)/src/liblzma/liblzma.la $(am__DEPENDENCIES_1)
+test_block_header_SOURCES = test_block_header.c
+test_block_header_OBJECTS = test_block_header.$(OBJEXT)
+test_block_header_LDADD = $(LDADD)
+test_block_header_DEPENDENCIES = \
+ $(top_builddir)/src/liblzma/liblzma.la $(am__DEPENDENCIES_1)
+test_check_SOURCES = test_check.c
+test_check_OBJECTS = test_check.$(OBJEXT)
+test_check_LDADD = $(LDADD)
+test_check_DEPENDENCIES = $(top_builddir)/src/liblzma/liblzma.la \
+ $(am__DEPENDENCIES_1)
+test_filter_flags_SOURCES = test_filter_flags.c
+test_filter_flags_OBJECTS = test_filter_flags.$(OBJEXT)
+test_filter_flags_LDADD = $(LDADD)
+test_filter_flags_DEPENDENCIES = \
+ $(top_builddir)/src/liblzma/liblzma.la $(am__DEPENDENCIES_1)
+test_filter_str_SOURCES = test_filter_str.c
+test_filter_str_OBJECTS = test_filter_str.$(OBJEXT)
+test_filter_str_LDADD = $(LDADD)
+test_filter_str_DEPENDENCIES = $(top_builddir)/src/liblzma/liblzma.la \
+ $(am__DEPENDENCIES_1)
+test_hardware_SOURCES = test_hardware.c
+test_hardware_OBJECTS = test_hardware.$(OBJEXT)
+test_hardware_LDADD = $(LDADD)
+test_hardware_DEPENDENCIES = $(top_builddir)/src/liblzma/liblzma.la \
+ $(am__DEPENDENCIES_1)
+test_index_SOURCES = test_index.c
+test_index_OBJECTS = test_index.$(OBJEXT)
+test_index_LDADD = $(LDADD)
+test_index_DEPENDENCIES = $(top_builddir)/src/liblzma/liblzma.la \
+ $(am__DEPENDENCIES_1)
+test_index_hash_SOURCES = test_index_hash.c
+test_index_hash_OBJECTS = test_index_hash.$(OBJEXT)
+test_index_hash_LDADD = $(LDADD)
+test_index_hash_DEPENDENCIES = $(top_builddir)/src/liblzma/liblzma.la \
+ $(am__DEPENDENCIES_1)
+test_lzip_decoder_SOURCES = test_lzip_decoder.c
+test_lzip_decoder_OBJECTS = test_lzip_decoder.$(OBJEXT)
+test_lzip_decoder_LDADD = $(LDADD)
+test_lzip_decoder_DEPENDENCIES = \
+ $(top_builddir)/src/liblzma/liblzma.la $(am__DEPENDENCIES_1)
+test_memlimit_SOURCES = test_memlimit.c
+test_memlimit_OBJECTS = test_memlimit.$(OBJEXT)
+test_memlimit_LDADD = $(LDADD)
+test_memlimit_DEPENDENCIES = $(top_builddir)/src/liblzma/liblzma.la \
+ $(am__DEPENDENCIES_1)
+test_stream_flags_SOURCES = test_stream_flags.c
+test_stream_flags_OBJECTS = test_stream_flags.$(OBJEXT)
+test_stream_flags_LDADD = $(LDADD)
+test_stream_flags_DEPENDENCIES = \
+ $(top_builddir)/src/liblzma/liblzma.la $(am__DEPENDENCIES_1)
+test_vli_SOURCES = test_vli.c
+test_vli_OBJECTS = test_vli.$(OBJEXT)
+test_vli_LDADD = $(LDADD)
+test_vli_DEPENDENCIES = $(top_builddir)/src/liblzma/liblzma.la \
+ $(am__DEPENDENCIES_1)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/create_compress_files.Po \
+ ./$(DEPDIR)/test_bcj_exact_size.Po \
+ ./$(DEPDIR)/test_block_header.Po ./$(DEPDIR)/test_check.Po \
+ ./$(DEPDIR)/test_filter_flags.Po \
+ ./$(DEPDIR)/test_filter_str.Po ./$(DEPDIR)/test_hardware.Po \
+ ./$(DEPDIR)/test_index.Po ./$(DEPDIR)/test_index_hash.Po \
+ ./$(DEPDIR)/test_lzip_decoder.Po ./$(DEPDIR)/test_memlimit.Po \
+ ./$(DEPDIR)/test_stream_flags.Po ./$(DEPDIR)/test_vli.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = create_compress_files.c test_bcj_exact_size.c \
+ test_block_header.c test_check.c test_filter_flags.c \
+ test_filter_str.c test_hardware.c test_index.c \
+ test_index_hash.c test_lzip_decoder.c test_memlimit.c \
+ test_stream_flags.c test_vli.c
+DIST_SOURCES = create_compress_files.c test_bcj_exact_size.c \
+ test_block_header.c test_check.c test_filter_flags.c \
+ test_filter_str.c test_hardware.c test_index.c \
+ test_index_hash.c test_lzip_decoder.c test_memlimit.c \
+ test_stream_flags.c test_vli.c
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/build-aux/depcomp \
+ $(top_srcdir)/build-aux/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CAPSICUM_LIB = @CAPSICUM_LIB@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+GETOPT_H = @GETOPT_H@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_EXEEXT = @LN_EXEEXT@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+POSIX_SHELL = @POSIX_SHELL@
+POSUB = @POSUB@
+PREFERABLY_POSIX_SHELL = @PREFERABLY_POSIX_SHELL@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_path_for_scripts = @enable_path_for_scripts@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+xz = @xz@
+EXTRA_DIST = \
+ files \
+ ossfuzz \
+ tuktest.h \
+ tests.h \
+ test_files.sh \
+ test_compress.sh \
+ test_compress_prepared_bcj_sparc \
+ test_compress_prepared_bcj_x86 \
+ test_compress_generated_abc \
+ test_compress_generated_random \
+ test_compress_generated_text \
+ test_scripts.sh \
+ bcj_test.c \
+ compress_prepared_bcj_sparc \
+ compress_prepared_bcj_x86 \
+ xzgrep_expected_output
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/common \
+ -I$(top_srcdir)/src/liblzma/api \
+ -I$(top_srcdir)/src/liblzma
+
+LDADD = $(top_builddir)/src/liblzma/liblzma.la $(LTLIBINTL)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign tests/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+create_compress_files$(EXEEXT): $(create_compress_files_OBJECTS) $(create_compress_files_DEPENDENCIES) $(EXTRA_create_compress_files_DEPENDENCIES)
+ @rm -f create_compress_files$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(create_compress_files_OBJECTS) $(create_compress_files_LDADD) $(LIBS)
+
+test_bcj_exact_size$(EXEEXT): $(test_bcj_exact_size_OBJECTS) $(test_bcj_exact_size_DEPENDENCIES) $(EXTRA_test_bcj_exact_size_DEPENDENCIES)
+ @rm -f test_bcj_exact_size$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_bcj_exact_size_OBJECTS) $(test_bcj_exact_size_LDADD) $(LIBS)
+
+test_block_header$(EXEEXT): $(test_block_header_OBJECTS) $(test_block_header_DEPENDENCIES) $(EXTRA_test_block_header_DEPENDENCIES)
+ @rm -f test_block_header$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_block_header_OBJECTS) $(test_block_header_LDADD) $(LIBS)
+
+test_check$(EXEEXT): $(test_check_OBJECTS) $(test_check_DEPENDENCIES) $(EXTRA_test_check_DEPENDENCIES)
+ @rm -f test_check$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_check_OBJECTS) $(test_check_LDADD) $(LIBS)
+
+test_filter_flags$(EXEEXT): $(test_filter_flags_OBJECTS) $(test_filter_flags_DEPENDENCIES) $(EXTRA_test_filter_flags_DEPENDENCIES)
+ @rm -f test_filter_flags$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_filter_flags_OBJECTS) $(test_filter_flags_LDADD) $(LIBS)
+
+test_filter_str$(EXEEXT): $(test_filter_str_OBJECTS) $(test_filter_str_DEPENDENCIES) $(EXTRA_test_filter_str_DEPENDENCIES)
+ @rm -f test_filter_str$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_filter_str_OBJECTS) $(test_filter_str_LDADD) $(LIBS)
+
+test_hardware$(EXEEXT): $(test_hardware_OBJECTS) $(test_hardware_DEPENDENCIES) $(EXTRA_test_hardware_DEPENDENCIES)
+ @rm -f test_hardware$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_hardware_OBJECTS) $(test_hardware_LDADD) $(LIBS)
+
+test_index$(EXEEXT): $(test_index_OBJECTS) $(test_index_DEPENDENCIES) $(EXTRA_test_index_DEPENDENCIES)
+ @rm -f test_index$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_index_OBJECTS) $(test_index_LDADD) $(LIBS)
+
+test_index_hash$(EXEEXT): $(test_index_hash_OBJECTS) $(test_index_hash_DEPENDENCIES) $(EXTRA_test_index_hash_DEPENDENCIES)
+ @rm -f test_index_hash$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_index_hash_OBJECTS) $(test_index_hash_LDADD) $(LIBS)
+
+test_lzip_decoder$(EXEEXT): $(test_lzip_decoder_OBJECTS) $(test_lzip_decoder_DEPENDENCIES) $(EXTRA_test_lzip_decoder_DEPENDENCIES)
+ @rm -f test_lzip_decoder$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_lzip_decoder_OBJECTS) $(test_lzip_decoder_LDADD) $(LIBS)
+
+test_memlimit$(EXEEXT): $(test_memlimit_OBJECTS) $(test_memlimit_DEPENDENCIES) $(EXTRA_test_memlimit_DEPENDENCIES)
+ @rm -f test_memlimit$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_memlimit_OBJECTS) $(test_memlimit_LDADD) $(LIBS)
+
+test_stream_flags$(EXEEXT): $(test_stream_flags_OBJECTS) $(test_stream_flags_DEPENDENCIES) $(EXTRA_test_stream_flags_DEPENDENCIES)
+ @rm -f test_stream_flags$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_stream_flags_OBJECTS) $(test_stream_flags_LDADD) $(LIBS)
+
+test_vli$(EXEEXT): $(test_vli_OBJECTS) $(test_vli_DEPENDENCIES) $(EXTRA_test_vli_DEPENDENCIES)
+ @rm -f test_vli$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_vli_OBJECTS) $(test_vli_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/create_compress_files.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_bcj_exact_size.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_block_header.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_check.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_filter_flags.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_filter_str.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_hardware.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_index.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_index_hash.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lzip_decoder.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_memlimit.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_stream_flags.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_vli.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS: $(check_PROGRAMS)
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all $(check_PROGRAMS)
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+test_check.log: test_check$(EXEEXT)
+ @p='test_check$(EXEEXT)'; \
+ b='test_check'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_hardware.log: test_hardware$(EXEEXT)
+ @p='test_hardware$(EXEEXT)'; \
+ b='test_hardware'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_stream_flags.log: test_stream_flags$(EXEEXT)
+ @p='test_stream_flags$(EXEEXT)'; \
+ b='test_stream_flags'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_filter_flags.log: test_filter_flags$(EXEEXT)
+ @p='test_filter_flags$(EXEEXT)'; \
+ b='test_filter_flags'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_filter_str.log: test_filter_str$(EXEEXT)
+ @p='test_filter_str$(EXEEXT)'; \
+ b='test_filter_str'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_block_header.log: test_block_header$(EXEEXT)
+ @p='test_block_header$(EXEEXT)'; \
+ b='test_block_header'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_index.log: test_index$(EXEEXT)
+ @p='test_index$(EXEEXT)'; \
+ b='test_index'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_index_hash.log: test_index_hash$(EXEEXT)
+ @p='test_index_hash$(EXEEXT)'; \
+ b='test_index_hash'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_bcj_exact_size.log: test_bcj_exact_size$(EXEEXT)
+ @p='test_bcj_exact_size$(EXEEXT)'; \
+ b='test_bcj_exact_size'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_memlimit.log: test_memlimit$(EXEEXT)
+ @p='test_memlimit$(EXEEXT)'; \
+ b='test_memlimit'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_lzip_decoder.log: test_lzip_decoder$(EXEEXT)
+ @p='test_lzip_decoder$(EXEEXT)'; \
+ b='test_lzip_decoder'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_vli.log: test_vli$(EXEEXT)
+ @p='test_vli$(EXEEXT)'; \
+ b='test_vli'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_files.sh.log: test_files.sh
+ @p='test_files.sh'; \
+ b='test_files.sh'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_compress_prepared_bcj_sparc.log: test_compress_prepared_bcj_sparc
+ @p='test_compress_prepared_bcj_sparc'; \
+ b='test_compress_prepared_bcj_sparc'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_compress_prepared_bcj_x86.log: test_compress_prepared_bcj_x86
+ @p='test_compress_prepared_bcj_x86'; \
+ b='test_compress_prepared_bcj_x86'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_compress_generated_abc.log: test_compress_generated_abc
+ @p='test_compress_generated_abc'; \
+ b='test_compress_generated_abc'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_compress_generated_random.log: test_compress_generated_random
+ @p='test_compress_generated_random'; \
+ b='test_compress_generated_random'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_compress_generated_text.log: test_compress_generated_text
+ @p='test_compress_generated_text'; \
+ b='test_compress_generated_text'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+test_scripts.sh.log: test_scripts.sh
+ @p='test_scripts.sh'; \
+ b='test_scripts.sh'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool clean-local \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/create_compress_files.Po
+ -rm -f ./$(DEPDIR)/test_bcj_exact_size.Po
+ -rm -f ./$(DEPDIR)/test_block_header.Po
+ -rm -f ./$(DEPDIR)/test_check.Po
+ -rm -f ./$(DEPDIR)/test_filter_flags.Po
+ -rm -f ./$(DEPDIR)/test_filter_str.Po
+ -rm -f ./$(DEPDIR)/test_hardware.Po
+ -rm -f ./$(DEPDIR)/test_index.Po
+ -rm -f ./$(DEPDIR)/test_index_hash.Po
+ -rm -f ./$(DEPDIR)/test_lzip_decoder.Po
+ -rm -f ./$(DEPDIR)/test_memlimit.Po
+ -rm -f ./$(DEPDIR)/test_stream_flags.Po
+ -rm -f ./$(DEPDIR)/test_vli.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/create_compress_files.Po
+ -rm -f ./$(DEPDIR)/test_bcj_exact_size.Po
+ -rm -f ./$(DEPDIR)/test_block_header.Po
+ -rm -f ./$(DEPDIR)/test_check.Po
+ -rm -f ./$(DEPDIR)/test_filter_flags.Po
+ -rm -f ./$(DEPDIR)/test_filter_str.Po
+ -rm -f ./$(DEPDIR)/test_hardware.Po
+ -rm -f ./$(DEPDIR)/test_index.Po
+ -rm -f ./$(DEPDIR)/test_index_hash.Po
+ -rm -f ./$(DEPDIR)/test_lzip_decoder.Po
+ -rm -f ./$(DEPDIR)/test_memlimit.Po
+ -rm -f ./$(DEPDIR)/test_stream_flags.Po
+ -rm -f ./$(DEPDIR)/test_vli.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \
+ check-am clean clean-checkPROGRAMS clean-generic clean-libtool \
+ clean-local cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am recheck tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+clean-local:
+ -rm -f compress_generated_* \
+ xzgrep_test_output xzgrep_test_1.xz xzgrep_test_2.xz
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/bcj_test.c b/tests/bcj_test.c
new file mode 100644
index 0000000..05de38a
--- /dev/null
+++ b/tests/bcj_test.c
@@ -0,0 +1,65 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file bcj_test.c
+/// \brief Source code of compress_prepared_bcj_*
+///
+/// This is a simple program that should make the compiler to generate
+/// PC-relative branches, jumps, and calls. The compiled files can then
+/// be used to test the branch conversion filters. Note that this program
+/// itself does nothing useful.
+///
+/// Compiling: gcc -std=c99 -fPIC -c bcj_test.c
+/// Don't optimize or strip.
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+extern int jump(int a, int b);
+
+
+extern int
+call(int a, int b)
+{
+ if (a < b)
+ a = jump(a, b);
+
+ return a;
+}
+
+
+extern int
+jump(int a, int b)
+{
+ // The loop generates conditional jump backwards.
+ while (1) {
+ if (a < b) {
+ a *= 2;
+ a += 3 * b;
+ break;
+ } else {
+ // Put enough code here to prevent JMP SHORT on x86.
+ a += b;
+ a /= 2;
+ b += b % 5;
+ a -= b / 3;
+ b = 2 * b + a - 1;
+ a *= b + a + 1;
+ b += a - 1;
+ a += b * 2 - a / 5;
+ }
+ }
+
+ return a;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int a = call(argc, argc + 1);
+ return a == 0;
+}
diff --git a/tests/compress_prepared_bcj_sparc b/tests/compress_prepared_bcj_sparc
new file mode 100644
index 0000000..86ea7dd
--- /dev/null
+++ b/tests/compress_prepared_bcj_sparc
Binary files differ
diff --git a/tests/compress_prepared_bcj_x86 b/tests/compress_prepared_bcj_x86
new file mode 100644
index 0000000..bcc546f
--- /dev/null
+++ b/tests/compress_prepared_bcj_x86
Binary files differ
diff --git a/tests/create_compress_files.c b/tests/create_compress_files.c
new file mode 100644
index 0000000..76aa3e3
--- /dev/null
+++ b/tests/create_compress_files.c
@@ -0,0 +1,163 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file create_compress_files.c
+/// \brief Creates bunch of test files to be compressed
+///
+/// Using a test file generator program saves space in the source code
+/// package considerably.
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "sysdefs.h"
+#include <stdio.h>
+
+
+// If a command-line argument was given, only create the file if its
+// name was specified on the command line. If no args were given then
+// all files are created.
+//
+// Avoid re-creating the test files every time the tests are run.
+#define maybe_create_test(argc, argv, name) \
+do { \
+ if ((argc < 2 || strcmp(argv[1], "compress_generated_" #name) == 0) \
+ && !file_exists("compress_generated_" #name)) { \
+ FILE *file = file_create("compress_generated_" #name); \
+ write_ ## name(file); \
+ file_finish(file, "compress_generated_" #name); \
+ } \
+} while (0)
+
+
+static bool
+file_exists(const char *filename)
+{
+ // Trying to be somewhat portable by avoiding stat().
+ FILE *file = fopen(filename, "rb");
+ bool ret;
+
+ if (file != NULL) {
+ fclose(file);
+ ret = true;
+ } else {
+ ret = false;
+ }
+
+ return ret;
+}
+
+
+static FILE *
+file_create(const char *filename)
+{
+ FILE *file = fopen(filename, "wb");
+
+ if (file == NULL) {
+ perror(filename);
+ exit(EXIT_FAILURE);
+ }
+
+ return file;
+}
+
+
+static void
+file_finish(FILE *file, const char *filename)
+{
+ const bool ferror_fail = ferror(file);
+ const bool fclose_fail = fclose(file);
+
+ if (ferror_fail || fclose_fail) {
+ perror(filename);
+ exit(EXIT_FAILURE);
+ }
+}
+
+
+// File that repeats "abc\n" a few thousand times. This is targeted
+// especially at Subblock filter's run-length encoder.
+static void
+write_abc(FILE *file)
+{
+ for (size_t i = 0; i < 12345; ++i)
+ if (fwrite("abc\n", 4, 1, file) != 1)
+ exit(EXIT_FAILURE);
+}
+
+
+// File that doesn't compress. We always use the same random seed to
+// generate identical files on all systems.
+static void
+write_random(FILE *file)
+{
+ uint32_t n = 5;
+
+ for (size_t i = 0; i < 123456; ++i) {
+ n = 101771 * n + 71777;
+
+ putc((uint8_t)(n), file);
+ putc((uint8_t)(n >> 8), file);
+ putc((uint8_t)(n >> 16), file);
+ putc((uint8_t)(n >> 24), file);
+ }
+}
+
+
+// Text file
+static void
+write_text(FILE *file)
+{
+ static const char *lorem[] = {
+ "Lorem", "ipsum", "dolor", "sit", "amet,", "consectetur",
+ "adipisicing", "elit,", "sed", "do", "eiusmod", "tempor",
+ "incididunt", "ut", "labore", "et", "dolore", "magna",
+ "aliqua.", "Ut", "enim", "ad", "minim", "veniam,", "quis",
+ "nostrud", "exercitation", "ullamco", "laboris", "nisi",
+ "ut", "aliquip", "ex", "ea", "commodo", "consequat.",
+ "Duis", "aute", "irure", "dolor", "in", "reprehenderit",
+ "in", "voluptate", "velit", "esse", "cillum", "dolore",
+ "eu", "fugiat", "nulla", "pariatur.", "Excepteur", "sint",
+ "occaecat", "cupidatat", "non", "proident,", "sunt", "in",
+ "culpa", "qui", "officia", "deserunt", "mollit", "anim",
+ "id", "est", "laborum."
+ };
+
+ // Let the first paragraph be the original text.
+ for (size_t w = 0; w < ARRAY_SIZE(lorem); ++w) {
+ fprintf(file, "%s ", lorem[w]);
+
+ if (w % 7 == 6)
+ fprintf(file, "\n");
+ }
+
+ // The rest shall be (hopefully) meaningless combinations of
+ // the same words.
+ uint32_t n = 29;
+
+ for (size_t p = 0; p < 500; ++p) {
+ fprintf(file, "\n\n");
+
+ for (size_t w = 0; w < ARRAY_SIZE(lorem); ++w) {
+ n = 101771 * n + 71777;
+
+ fprintf(file, "%s ", lorem[n % ARRAY_SIZE(lorem)]);
+
+ if (w % 7 == 6)
+ fprintf(file, "\n");
+ }
+ }
+}
+
+
+int
+main(int argc, char **argv)
+{
+ maybe_create_test(argc, argv, abc);
+ maybe_create_test(argc, argv, random);
+ maybe_create_test(argc, argv, text);
+ return EXIT_SUCCESS;
+}
diff --git a/tests/files/README b/tests/files/README
new file mode 100644
index 0000000..119cac4
--- /dev/null
+++ b/tests/files/README
@@ -0,0 +1,409 @@
+
+.xz and .lzma Test Files
+------------------------
+
+0. Introduction
+
+ This directory contains bunch of files to test handling of .xz,
+ .lzma (LZMA_Alone), and .lz (lzip) files in decoder implementations.
+ Many of the files have been created by hand with a hex editor, thus
+ there is no better "source code" than the files themselves. All the
+ test files and this README have been put into the public domain.
+
+
+1. File Types
+
+ Good files (good-*) must decode successfully without requiring
+ a lot of CPU time or RAM.
+
+ Unsupported files (unsupported-*) are good files, but headers
+ indicate features not supported by the current file format
+ specification.
+
+ Bad files (bad-*) must cause the decoder to give an error. Like
+ with the good files, these files must not require a lot of CPU
+ time or RAM before they get detected to be broken.
+
+
+2. Descriptions of Individual .xz Files
+
+2.1. Good Files
+
+ good-0-empty.xz has one Stream with no Blocks.
+
+ good-0pad-empty.xz has one Stream with no Blocks followed by
+ four-byte Stream Padding.
+
+ good-0cat-empty.xz has two zero-Block Streams concatenated without
+ Stream Padding.
+
+ good-0catpad-empty.xz has two zero-Block Streams concatenated with
+ four-byte Stream Padding between the Streams.
+
+ good-1-check-none.xz has one Stream with one Block with two
+ uncompressed LZMA2 chunks and no integrity check.
+
+ good-1-check-crc32.xz has one Stream with one Block with two
+ uncompressed LZMA2 chunks and CRC32 check.
+
+ good-1-check-crc64.xz is like good-1-check-crc32.xz but with CRC64.
+
+ good-1-check-sha256.xz is like good-1-check-crc32.xz but with
+ SHA256.
+
+ good-2-lzma2.xz has one Stream with two Blocks with one uncompressed
+ LZMA2 chunk in each Block.
+
+ good-1-block_header-1.xz has both Compressed Size and Uncompressed
+ Size in the Block Header. This has also four extra bytes of Header
+ Padding.
+
+ good-1-block_header-2.xz has known Compressed Size.
+
+ good-1-block_header-3.xz has known Uncompressed Size.
+
+ good-1-delta-lzma2.tiff.xz is an image file that compresses
+ better with Delta+LZMA2 than with plain LZMA2.
+
+ good-1-x86-lzma2.xz uses the x86 filter (BCJ) and LZMA2. The
+ uncompressed file is compress_prepared_bcj_x86 found from the tests
+ directory.
+
+ good-1-sparc-lzma2.xz uses the SPARC filter and LZMA2. The
+ uncompressed file is compress_prepared_bcj_sparc found from the tests
+ directory.
+
+ good-1-arm64-lzma2-1.xz uses the ARM64 filter and LZMA2. The
+ uncompressed data is constructed so that it tests integer
+ wrap around and sign extension.
+
+ good-1-arm64-lzma2-2.xz is like good-1-arm64-lzma2-1.xz but with
+ non-zero start offset. XZ Embedded doesn't support this file.
+
+ good-1-lzma2-1.xz has two LZMA2 chunks, of which the second sets
+ new properties.
+
+ good-1-lzma2-2.xz has two LZMA2 chunks, of which the second resets
+ the state without specifying new properties.
+
+ good-1-lzma2-3.xz has two LZMA2 chunks, of which the first is
+ uncompressed and the second is LZMA. The first chunk resets dictionary
+ and the second sets new properties.
+
+ good-1-lzma2-4.xz has three LZMA2 chunks: First is LZMA, second is
+ uncompressed with dictionary reset, and third is LZMA with new
+ properties but without dictionary reset.
+
+ good-1-lzma2-5.xz has an empty LZMA2 stream with only the end of
+ payload marker. XZ Utils 5.0.1 and older incorrectly see this file
+ as corrupt.
+
+ good-1-3delta-lzma2.xz has three Delta filters and LZMA2.
+
+ good-1-empty-bcj-lzma2.xz has an empty Block that uses PowerPC BCJ
+ and LZMA2. liblzma from XZ Utils 5.0.1 and older may incorrectly
+ return LZMA_BUF_ERROR in some cases. See commit message
+ d8db706acb8316f9861abd432cfbe001dd6d0c5c for the details.
+
+
+2.2. Unsupported Files
+
+ unsupported-check.xz uses Check ID 0x02 which isn't supported by
+ the current version of the file format. It is implementation-defined
+ how this file handled (it may reject it, or decode it possibly with
+ a warning).
+
+ unsupported-block_header.xz has a non-null byte in Header Padding,
+ which may indicate presence of a new unsupported field.
+
+ unsupported-filter_flags-1.xz has unsupported Filter ID 0x7F.
+
+ unsupported-filter_flags-2.xz specifies only Delta filter in the
+ List of Filter Flags, but Delta isn't allowed as the last filter in
+ the chain. It could be a little more correct to detect this file as
+ corrupt instead of unsupported, but saying it is unsupported is
+ simpler in case of liblzma.
+
+ unsupported-filter_flags-3.xz specifies two LZMA2 filters in the
+ List of Filter Flags. LZMA2 is allowed only as the last filter in the
+ chain. It could be a little more correct to detect this file as
+ corrupt instead of unsupported, but saying it is unsupported is
+ simpler in case of liblzma.
+
+
+2.3. Bad Files
+
+ bad-0pad-empty.xz has one Stream with no Blocks followed by
+ five-byte Stream Padding. Stream Padding must be a multiple of four
+ bytes, thus this file is corrupt.
+
+ bad-0catpad-empty.xz has two zero-Block Streams concatenated with
+ five-byte Stream Padding between the Streams.
+
+ bad-0cat-alone.xz is good-0-empty.xz concatenated with an empty
+ LZMA_Alone file.
+
+ bad-0cat-header_magic.xz is good-0cat-empty.xz but with one byte
+ wrong in the Header Magic Bytes field of the second Stream. liblzma
+ gives LZMA_DATA_ERROR for this. (LZMA_FORMAT_ERROR is used only if
+ the first Stream of a file has invalid Header Magic Bytes.)
+
+ bad-0-header_magic.xz is good-0-empty.xz but with one byte wrong
+ in the Header Magic Bytes field. liblzma gives LZMA_FORMAT_ERROR for
+ this.
+
+ bad-0-footer_magic.xz is good-0-empty.xz but with one byte wrong
+ in the Footer Magic Bytes field. liblzma gives LZMA_DATA_ERROR for
+ this.
+
+ bad-0-empty-truncated.xz is good-0-empty.xz without the last byte
+ of the file.
+
+ bad-0-nonempty_index.xz has no Blocks but Index claims that there is
+ one Block.
+
+ bad-0-backward_size.xz has wrong Backward Size in Stream Footer.
+
+ bad-1-stream_flags-1.xz has different Stream Flags in Stream Header
+ and Stream Footer.
+
+ bad-1-stream_flags-2.xz has wrong CRC32 in Stream Header.
+
+ bad-1-stream_flags-3.xz has wrong CRC32 in Stream Footer.
+
+ bad-1-vli-1.xz has two-byte variable-length integer in the
+ Uncompressed Size field in Block Header while one-byte would be enough
+ for that value. It's important that the file gets rejected due to too
+ big integer encoding instead of due to Uncompressed Size not matching
+ the value stored in the Block Header. That is, the decoder must not
+ try to decode the Compressed Data field.
+
+ bad-1-vli-2.xz has ten-byte variable-length integer as Uncompressed
+ Size in Block Header. It's important that the file gets rejected due
+ to too big integer encoding instead of due to Uncompressed Size not
+ matching the value stored in the Block Header. That is, the decoder
+ must not try to decode the Compressed Data field.
+
+ bad-1-block_header-1.xz has Block Header that ends in the middle of
+ the Filter Flags field.
+
+ bad-1-block_header-2.xz has Block Header that has Compressed Size and
+ Uncompressed Size but no List of Filter Flags field.
+
+ bad-1-block_header-3.xz has wrong CRC32 in Block Header.
+
+ bad-1-block_header-4.xz has too big Compressed Size in Block Header
+ (2^63 - 1 bytes while maximum is a little less, because the whole
+ Block must stay smaller than 2^63). It's important that the file
+ gets rejected due to invalid Compressed Size value; the decoder
+ must not try decoding the Compressed Data field.
+
+ bad-1-block_header-5.xz has zero as Compressed Size in Block Header.
+
+ bad-1-block_header-6.xz has corrupt Block Header which may crash
+ xz -lvv in XZ Utils 5.0.3 and earlier. It was fixed in the commit
+ c0297445064951807803457dca1611b3c47e7f0f.
+
+ bad-2-index-1.xz has wrong Unpadded Sizes in Index.
+
+ bad-2-index-2.xz has wrong Uncompressed Sizes in Index.
+
+ bad-2-index-3.xz has non-null byte in Index Padding.
+
+ bad-2-index-4.xz wrong CRC32 in Index.
+
+ bad-2-index-5.xz has zero as Unpadded Size. It is important that the
+ file gets rejected specifically due to Unpadded Size having an invalid
+ value.
+
+ bad-3-index-uncomp-overflow.xz has Index whose Uncompressed Size
+ fields have huge values whose sum exceeds the maximum allowed size
+ of 2^63 - 1 bytes. In this file the sum is exactly 2^64.
+ lzma_index_append() in liblzma <= 5.2.6 lacks the integer overflow
+ check for the uncompressed size and thus doesn't catch the error
+ when decoding the Index field in this file. This makes "xz -l"
+ not detect the error and will display 0 as the uncompressed size.
+ Note that regular decompression isn't affected by this bug because
+ it uses lzma_index_hash_append() instead.
+
+ bad-2-compressed_data_padding.xz has non-null byte in the padding of
+ the Compressed Data field of the first Block.
+
+ bad-1-check-crc32.xz has wrong Check (CRC32).
+
+ bad-1-check-crc32-2.xz has Compressed Size and Uncompressed Size in
+ Block Header but wrong Check (CRC32) in the actual data. This file
+ differs by one byte from good-1-block_header-1.xz: the last byte of
+ the Check field is wrong. This file is useful for testing error
+ detection in the threaded decoder when a worker thread is configured
+ to pass input one byte at a time to the Block decoder.
+
+ bad-1-check-crc64.xz has wrong Check (CRC64).
+
+ bad-1-check-sha256.xz has wrong Check (SHA-256).
+
+ bad-1-lzma2-1.xz has LZMA2 stream whose first chunk (uncompressed)
+ doesn't reset the dictionary.
+
+ bad-1-lzma2-2.xz has two LZMA2 chunks, of which the second chunk
+ indicates dictionary reset, but the LZMA compressed data tries to
+ repeat data from the previous chunk.
+
+ bad-1-lzma2-3.xz sets new invalid properties (lc=8, lp=0, pb=0) in
+ the middle of Block.
+
+ bad-1-lzma2-4.xz has two LZMA2 chunks, of which the first is
+ uncompressed and the second is LZMA. The first chunk resets dictionary
+ as it should, but the second chunk tries to reset state without
+ specifying properties for LZMA.
+
+ bad-1-lzma2-5.xz is like bad-1-lzma2-4.xz but doesn't try to reset
+ anything in the header of the second chunk.
+
+ bad-1-lzma2-6.xz has reserved LZMA2 control byte value (0x03).
+
+ bad-1-lzma2-7.xz has EOPM at LZMA level.
+
+ bad-1-lzma2-8.xz is like good-1-lzma2-4.xz but doesn't set new
+ properties in the third LZMA2 chunk.
+
+ bad-1-lzma2-9.xz has LZMA2 stream that is truncated at the end of
+ a LZMA2 chunk (no end marker). The uncompressed size of the partial
+ LZMA2 stream exceeds the value stored in the Block Header.
+
+ bad-1-lzma2-10.xz has LZMA2 stream that, from point of view of a
+ LZMA2 decoder, extends past the end of Block (and even the end of
+ the file). Uncompressed Size in Block Header is bigger than the
+ invalid LZMA2 stream may produce (even if a decoder reads until
+ the end of the file). The Check type is None to nullify certain
+ simple size-based sanity checks in a Block decoder.
+
+ bad-1-lzma2-11.xz has LZMA2 stream that lacks the end of
+ payload marker. When Compressed Size bytes have been decoded,
+ Uncompressed Size bytes of output will have been produced but
+ the LZMA2 decoder doesn't indicate end of stream.
+
+
+3. Descriptions of Individual .lzma Files
+
+3.1. Good Files
+
+ good-unknown_size-with_eopm.lzma has unknown size in the header
+ and end of payload marker at the end.
+
+ good-known_size-without_eopm.lzma has a known size in the header
+ and no end of payload marker at the end.
+
+ good-known_size-with_eopm.lzma has a known size in the header
+ and end of payload marker at the end. XZ Utils 5.2.5 and older
+ will give an error at the end of the file after producing the
+ correct uncompressed output.
+
+
+3.2. Bad Files
+
+ bad-unknown_size-without_eopm.lzma has unknown size in the header
+ but no end of payload marker at the end. This file might be seen
+ by a decoder as if it were truncated.
+
+ bad-too_big_size-with_eopm.lzma has too big uncompressed size in
+ the header and the end of payload marker will be detected before
+ the specified number of bytes have been decoded.
+
+ bad-too_small_size-without_eopm-1.lzma has too small uncompressed
+ size in the header. The decoder will look for end of payload marker
+ but instead find a literal that would produce more output.
+
+ bad-too_small_size-without_eopm-2.lzma is like -1 above but instead
+ of a literal the problem occurs with a short repeated match.
+
+ bad-too_small_size-without_eopm-3.lzma is like -1 above but instead
+ of a literal the problem occurs in the middle of a match.
+
+
+4. Descriptions of Individual .lz (lzip) Files
+
+4.1. Good Files
+
+ good-1-v0.lz contains a single version 0 member. lzip 1.17 and
+ *older* can decompress this; support for version 0 was removed
+ in lzip 1.18.
+
+ good-1-v0-trailing-1.lz is like good-1-v0.lz but contains
+ trailing data that the decompressor must ignore.
+
+ good-1-v1.lz contains a single version 1 member. lzip 1.3 and
+ newer can decompress this.
+
+ good-1-v1-trailing-1.lz is like good-1-v1.lz but contains
+ trailing data that the decompressor must ignore.
+
+ good-1-v1-trailing-2.lz is like good-1-v1.lz but contains
+ trailing data whose first three bytes match the .lz magic bytes.
+ With lzip >= 1.20 this file results in an error unless one uses
+ the command line option --loose-trailing. lzip 1.3 to 1.19 decode
+ this file successfully by default. XZ Utils uses the old behavior
+ because it allows lzma_code() to stop at the first byte of the
+ trailing data as long as the first byte isn't 0x4C (L in US-ASCII);
+ otherwise the first 1-3 bytes that equal to the magic bytes are
+ consumed and lost in lzma_code(), and this is visible in xz too:
+
+ $ ( xz -dc ; cat ) < good-1-v1-trailing-2.lz
+ Hello
+ World!
+ Trailing garbage
+
+ $ ( xz -dc --single-stream ; cat ) < good-1-v1-trailing-2.lz
+ Hello
+ World!
+ LZITrailing garbage
+
+ good-2-v0-v1.lz contains two members of which the first is
+ version 0 and the second version 1. lzip versions 1.3 to 1.17
+ (inclusive) can decompress this.
+
+ good-2-v1-v0.lz contains two members of which the first is
+ version 1 and the second version 0. lzip versions 1.3 to 1.17
+ (inclusive) can decompress this.
+
+ good-2-v1-v1.lz contains two version 1 members. lzip versions 1.3
+ and newer can decompress this.
+
+
+4.2. Unsupported Files
+
+ unsupported-1-v234.lz is like good-1-v1.lz except the version
+ field has been set to 234 (0xEA) which, as of writing, isn't
+ defined or supported by any .lz implementation.
+
+
+4.3. Bad Files
+
+ bad-1-v1-magic-1.lz is like good-1-v1.lz but the first magic byte
+ is wrong.
+
+ bad-1-v1-magic-2.lz is like good-1-v1.lz but the last (fourth)
+ magic byte is wrong.
+
+ bad-1-v1-dict-1.lz has too low value in the dictionary size field.
+
+ bad-1-v1-dict-2.lz has too high value in the dictionary size field.
+
+ bad-1-v1-crc32.lz has wrong CRC32 value.
+
+ bad-1-v0-uncomp-size.lz is version 0 format with incorrect value
+ in the uncompressed size field.
+
+ bad-1-v1-uncomp-size.lz is version 1 format with incorrect value
+ in the uncompressed size field.
+
+ bad-1-v1-member-size.lz has incorrect value in the member size
+ field.
+
+ bad-1-v1-trailing-magic.lz has the four .lz magic bytes as trailing
+ data. This should be detected as a truncated file and thus result
+ in an error. That is, the last four bytes of the file should not be
+ ignored as trailing garbage. lzip >= 1.18 matches this behavior
+ while older versions ignore the last four bytes and don't indicate
+ an error.
+
diff --git a/tests/files/bad-0-backward_size.xz b/tests/files/bad-0-backward_size.xz
new file mode 100644
index 0000000..2b46fa9
--- /dev/null
+++ b/tests/files/bad-0-backward_size.xz
Binary files differ
diff --git a/tests/files/bad-0-empty-truncated.xz b/tests/files/bad-0-empty-truncated.xz
new file mode 100644
index 0000000..f879af8
--- /dev/null
+++ b/tests/files/bad-0-empty-truncated.xz
Binary files differ
diff --git a/tests/files/bad-0-footer_magic.xz b/tests/files/bad-0-footer_magic.xz
new file mode 100644
index 0000000..5d9e389
--- /dev/null
+++ b/tests/files/bad-0-footer_magic.xz
Binary files differ
diff --git a/tests/files/bad-0-header_magic.xz b/tests/files/bad-0-header_magic.xz
new file mode 100644
index 0000000..5984a45
--- /dev/null
+++ b/tests/files/bad-0-header_magic.xz
Binary files differ
diff --git a/tests/files/bad-0-nonempty_index.xz b/tests/files/bad-0-nonempty_index.xz
new file mode 100644
index 0000000..ed6e81f
--- /dev/null
+++ b/tests/files/bad-0-nonempty_index.xz
Binary files differ
diff --git a/tests/files/bad-0cat-alone.xz b/tests/files/bad-0cat-alone.xz
new file mode 100644
index 0000000..a915a3a
--- /dev/null
+++ b/tests/files/bad-0cat-alone.xz
Binary files differ
diff --git a/tests/files/bad-0cat-header_magic.xz b/tests/files/bad-0cat-header_magic.xz
new file mode 100644
index 0000000..426bf2d
--- /dev/null
+++ b/tests/files/bad-0cat-header_magic.xz
Binary files differ
diff --git a/tests/files/bad-0catpad-empty.xz b/tests/files/bad-0catpad-empty.xz
new file mode 100644
index 0000000..97c1330
--- /dev/null
+++ b/tests/files/bad-0catpad-empty.xz
Binary files differ
diff --git a/tests/files/bad-0pad-empty.xz b/tests/files/bad-0pad-empty.xz
new file mode 100644
index 0000000..45e00b7
--- /dev/null
+++ b/tests/files/bad-0pad-empty.xz
Binary files differ
diff --git a/tests/files/bad-1-block_header-1.xz b/tests/files/bad-1-block_header-1.xz
new file mode 100644
index 0000000..d991536
--- /dev/null
+++ b/tests/files/bad-1-block_header-1.xz
Binary files differ
diff --git a/tests/files/bad-1-block_header-2.xz b/tests/files/bad-1-block_header-2.xz
new file mode 100644
index 0000000..ae42ecf
--- /dev/null
+++ b/tests/files/bad-1-block_header-2.xz
Binary files differ
diff --git a/tests/files/bad-1-block_header-3.xz b/tests/files/bad-1-block_header-3.xz
new file mode 100644
index 0000000..606cbd2
--- /dev/null
+++ b/tests/files/bad-1-block_header-3.xz
Binary files differ
diff --git a/tests/files/bad-1-block_header-4.xz b/tests/files/bad-1-block_header-4.xz
new file mode 100644
index 0000000..e72dfbf
--- /dev/null
+++ b/tests/files/bad-1-block_header-4.xz
Binary files differ
diff --git a/tests/files/bad-1-block_header-5.xz b/tests/files/bad-1-block_header-5.xz
new file mode 100644
index 0000000..9652112
--- /dev/null
+++ b/tests/files/bad-1-block_header-5.xz
Binary files differ
diff --git a/tests/files/bad-1-block_header-6.xz b/tests/files/bad-1-block_header-6.xz
new file mode 100644
index 0000000..ecf0ff0
--- /dev/null
+++ b/tests/files/bad-1-block_header-6.xz
Binary files differ
diff --git a/tests/files/bad-1-check-crc32-2.xz b/tests/files/bad-1-check-crc32-2.xz
new file mode 100644
index 0000000..95731ae
--- /dev/null
+++ b/tests/files/bad-1-check-crc32-2.xz
Binary files differ
diff --git a/tests/files/bad-1-check-crc32.xz b/tests/files/bad-1-check-crc32.xz
new file mode 100644
index 0000000..1ebe131
--- /dev/null
+++ b/tests/files/bad-1-check-crc32.xz
Binary files differ
diff --git a/tests/files/bad-1-check-crc64.xz b/tests/files/bad-1-check-crc64.xz
new file mode 100644
index 0000000..cdb7709
--- /dev/null
+++ b/tests/files/bad-1-check-crc64.xz
Binary files differ
diff --git a/tests/files/bad-1-check-sha256.xz b/tests/files/bad-1-check-sha256.xz
new file mode 100644
index 0000000..def7bff
--- /dev/null
+++ b/tests/files/bad-1-check-sha256.xz
Binary files differ
diff --git a/tests/files/bad-1-lzma2-1.xz b/tests/files/bad-1-lzma2-1.xz
new file mode 100644
index 0000000..640f592
--- /dev/null
+++ b/tests/files/bad-1-lzma2-1.xz
Binary files differ
diff --git a/tests/files/bad-1-lzma2-10.xz b/tests/files/bad-1-lzma2-10.xz
new file mode 100644
index 0000000..246515e
--- /dev/null
+++ b/tests/files/bad-1-lzma2-10.xz
Binary files differ
diff --git a/tests/files/bad-1-lzma2-11.xz b/tests/files/bad-1-lzma2-11.xz
new file mode 100644
index 0000000..ce857b6
--- /dev/null
+++ b/tests/files/bad-1-lzma2-11.xz
Binary files differ
diff --git a/tests/files/bad-1-lzma2-2.xz b/tests/files/bad-1-lzma2-2.xz
new file mode 100644
index 0000000..69ab07d
--- /dev/null
+++ b/tests/files/bad-1-lzma2-2.xz
Binary files differ
diff --git a/tests/files/bad-1-lzma2-3.xz b/tests/files/bad-1-lzma2-3.xz
new file mode 100644
index 0000000..66f48c5
--- /dev/null
+++ b/tests/files/bad-1-lzma2-3.xz
Binary files differ
diff --git a/tests/files/bad-1-lzma2-4.xz b/tests/files/bad-1-lzma2-4.xz
new file mode 100644
index 0000000..ac97041
--- /dev/null
+++ b/tests/files/bad-1-lzma2-4.xz
Binary files differ
diff --git a/tests/files/bad-1-lzma2-5.xz b/tests/files/bad-1-lzma2-5.xz
new file mode 100644
index 0000000..700464d
--- /dev/null
+++ b/tests/files/bad-1-lzma2-5.xz
Binary files differ
diff --git a/tests/files/bad-1-lzma2-6.xz b/tests/files/bad-1-lzma2-6.xz
new file mode 100644
index 0000000..2bda0c4
--- /dev/null
+++ b/tests/files/bad-1-lzma2-6.xz
Binary files differ
diff --git a/tests/files/bad-1-lzma2-7.xz b/tests/files/bad-1-lzma2-7.xz
new file mode 100644
index 0000000..8cc711c
--- /dev/null
+++ b/tests/files/bad-1-lzma2-7.xz
Binary files differ
diff --git a/tests/files/bad-1-lzma2-8.xz b/tests/files/bad-1-lzma2-8.xz
new file mode 100644
index 0000000..f21a71b
--- /dev/null
+++ b/tests/files/bad-1-lzma2-8.xz
Binary files differ
diff --git a/tests/files/bad-1-lzma2-9.xz b/tests/files/bad-1-lzma2-9.xz
new file mode 100644
index 0000000..0553905
--- /dev/null
+++ b/tests/files/bad-1-lzma2-9.xz
Binary files differ
diff --git a/tests/files/bad-1-stream_flags-1.xz b/tests/files/bad-1-stream_flags-1.xz
new file mode 100644
index 0000000..6511773
--- /dev/null
+++ b/tests/files/bad-1-stream_flags-1.xz
Binary files differ
diff --git a/tests/files/bad-1-stream_flags-2.xz b/tests/files/bad-1-stream_flags-2.xz
new file mode 100644
index 0000000..0c66b36
--- /dev/null
+++ b/tests/files/bad-1-stream_flags-2.xz
Binary files differ
diff --git a/tests/files/bad-1-stream_flags-3.xz b/tests/files/bad-1-stream_flags-3.xz
new file mode 100644
index 0000000..a9b1f98
--- /dev/null
+++ b/tests/files/bad-1-stream_flags-3.xz
Binary files differ
diff --git a/tests/files/bad-1-v0-uncomp-size.lz b/tests/files/bad-1-v0-uncomp-size.lz
new file mode 100644
index 0000000..6bf4c6c
--- /dev/null
+++ b/tests/files/bad-1-v0-uncomp-size.lz
Binary files differ
diff --git a/tests/files/bad-1-v1-crc32.lz b/tests/files/bad-1-v1-crc32.lz
new file mode 100644
index 0000000..3387618
--- /dev/null
+++ b/tests/files/bad-1-v1-crc32.lz
Binary files differ
diff --git a/tests/files/bad-1-v1-dict-1.lz b/tests/files/bad-1-v1-dict-1.lz
new file mode 100644
index 0000000..20768d5
--- /dev/null
+++ b/tests/files/bad-1-v1-dict-1.lz
Binary files differ
diff --git a/tests/files/bad-1-v1-dict-2.lz b/tests/files/bad-1-v1-dict-2.lz
new file mode 100644
index 0000000..1f22e6d
--- /dev/null
+++ b/tests/files/bad-1-v1-dict-2.lz
Binary files differ
diff --git a/tests/files/bad-1-v1-magic-1.lz b/tests/files/bad-1-v1-magic-1.lz
new file mode 100644
index 0000000..b5e374d
--- /dev/null
+++ b/tests/files/bad-1-v1-magic-1.lz
Binary files differ
diff --git a/tests/files/bad-1-v1-magic-2.lz b/tests/files/bad-1-v1-magic-2.lz
new file mode 100644
index 0000000..f5d5b97
--- /dev/null
+++ b/tests/files/bad-1-v1-magic-2.lz
Binary files differ
diff --git a/tests/files/bad-1-v1-member-size.lz b/tests/files/bad-1-v1-member-size.lz
new file mode 100644
index 0000000..fd8636a
--- /dev/null
+++ b/tests/files/bad-1-v1-member-size.lz
Binary files differ
diff --git a/tests/files/bad-1-v1-trailing-magic.lz b/tests/files/bad-1-v1-trailing-magic.lz
new file mode 100644
index 0000000..f7926c5
--- /dev/null
+++ b/tests/files/bad-1-v1-trailing-magic.lz
Binary files differ
diff --git a/tests/files/bad-1-v1-uncomp-size.lz b/tests/files/bad-1-v1-uncomp-size.lz
new file mode 100644
index 0000000..c89a283
--- /dev/null
+++ b/tests/files/bad-1-v1-uncomp-size.lz
Binary files differ
diff --git a/tests/files/bad-1-vli-1.xz b/tests/files/bad-1-vli-1.xz
new file mode 100644
index 0000000..6514ab1
--- /dev/null
+++ b/tests/files/bad-1-vli-1.xz
Binary files differ
diff --git a/tests/files/bad-1-vli-2.xz b/tests/files/bad-1-vli-2.xz
new file mode 100644
index 0000000..c16941b
--- /dev/null
+++ b/tests/files/bad-1-vli-2.xz
Binary files differ
diff --git a/tests/files/bad-2-compressed_data_padding.xz b/tests/files/bad-2-compressed_data_padding.xz
new file mode 100644
index 0000000..382d047
--- /dev/null
+++ b/tests/files/bad-2-compressed_data_padding.xz
Binary files differ
diff --git a/tests/files/bad-2-index-1.xz b/tests/files/bad-2-index-1.xz
new file mode 100644
index 0000000..f51ed21
--- /dev/null
+++ b/tests/files/bad-2-index-1.xz
Binary files differ
diff --git a/tests/files/bad-2-index-2.xz b/tests/files/bad-2-index-2.xz
new file mode 100644
index 0000000..d7d00ff
--- /dev/null
+++ b/tests/files/bad-2-index-2.xz
Binary files differ
diff --git a/tests/files/bad-2-index-3.xz b/tests/files/bad-2-index-3.xz
new file mode 100644
index 0000000..62428b8
--- /dev/null
+++ b/tests/files/bad-2-index-3.xz
Binary files differ
diff --git a/tests/files/bad-2-index-4.xz b/tests/files/bad-2-index-4.xz
new file mode 100644
index 0000000..9cf2df6
--- /dev/null
+++ b/tests/files/bad-2-index-4.xz
Binary files differ
diff --git a/tests/files/bad-2-index-5.xz b/tests/files/bad-2-index-5.xz
new file mode 100644
index 0000000..0a79270
--- /dev/null
+++ b/tests/files/bad-2-index-5.xz
Binary files differ
diff --git a/tests/files/bad-3-index-uncomp-overflow.xz b/tests/files/bad-3-index-uncomp-overflow.xz
new file mode 100644
index 0000000..e1440ec
--- /dev/null
+++ b/tests/files/bad-3-index-uncomp-overflow.xz
Binary files differ
diff --git a/tests/files/bad-too_big_size-with_eopm.lzma b/tests/files/bad-too_big_size-with_eopm.lzma
new file mode 100644
index 0000000..b7cd3b0
--- /dev/null
+++ b/tests/files/bad-too_big_size-with_eopm.lzma
Binary files differ
diff --git a/tests/files/bad-too_small_size-without_eopm-1.lzma b/tests/files/bad-too_small_size-without_eopm-1.lzma
new file mode 100644
index 0000000..cc2805c
--- /dev/null
+++ b/tests/files/bad-too_small_size-without_eopm-1.lzma
Binary files differ
diff --git a/tests/files/bad-too_small_size-without_eopm-2.lzma b/tests/files/bad-too_small_size-without_eopm-2.lzma
new file mode 100644
index 0000000..e37cab1
--- /dev/null
+++ b/tests/files/bad-too_small_size-without_eopm-2.lzma
Binary files differ
diff --git a/tests/files/bad-too_small_size-without_eopm-3.lzma b/tests/files/bad-too_small_size-without_eopm-3.lzma
new file mode 100644
index 0000000..67a1af3
--- /dev/null
+++ b/tests/files/bad-too_small_size-without_eopm-3.lzma
Binary files differ
diff --git a/tests/files/bad-unknown_size-without_eopm.lzma b/tests/files/bad-unknown_size-without_eopm.lzma
new file mode 100644
index 0000000..b3d7a52
--- /dev/null
+++ b/tests/files/bad-unknown_size-without_eopm.lzma
Binary files differ
diff --git a/tests/files/good-0-empty.xz b/tests/files/good-0-empty.xz
new file mode 100644
index 0000000..83b95e0
--- /dev/null
+++ b/tests/files/good-0-empty.xz
Binary files differ
diff --git a/tests/files/good-0cat-empty.xz b/tests/files/good-0cat-empty.xz
new file mode 100644
index 0000000..e6fc314
--- /dev/null
+++ b/tests/files/good-0cat-empty.xz
Binary files differ
diff --git a/tests/files/good-0catpad-empty.xz b/tests/files/good-0catpad-empty.xz
new file mode 100644
index 0000000..4f86b7d
--- /dev/null
+++ b/tests/files/good-0catpad-empty.xz
Binary files differ
diff --git a/tests/files/good-0pad-empty.xz b/tests/files/good-0pad-empty.xz
new file mode 100644
index 0000000..c51e3a6
--- /dev/null
+++ b/tests/files/good-0pad-empty.xz
Binary files differ
diff --git a/tests/files/good-1-3delta-lzma2.xz b/tests/files/good-1-3delta-lzma2.xz
new file mode 100644
index 0000000..a0be1d0
--- /dev/null
+++ b/tests/files/good-1-3delta-lzma2.xz
Binary files differ
diff --git a/tests/files/good-1-arm64-lzma2-1.xz b/tests/files/good-1-arm64-lzma2-1.xz
new file mode 100644
index 0000000..78169f1
--- /dev/null
+++ b/tests/files/good-1-arm64-lzma2-1.xz
Binary files differ
diff --git a/tests/files/good-1-arm64-lzma2-2.xz b/tests/files/good-1-arm64-lzma2-2.xz
new file mode 100644
index 0000000..e0302fe
--- /dev/null
+++ b/tests/files/good-1-arm64-lzma2-2.xz
Binary files differ
diff --git a/tests/files/good-1-block_header-1.xz b/tests/files/good-1-block_header-1.xz
new file mode 100644
index 0000000..fea5ad2
--- /dev/null
+++ b/tests/files/good-1-block_header-1.xz
Binary files differ
diff --git a/tests/files/good-1-block_header-2.xz b/tests/files/good-1-block_header-2.xz
new file mode 100644
index 0000000..6b5dcb3
--- /dev/null
+++ b/tests/files/good-1-block_header-2.xz
Binary files differ
diff --git a/tests/files/good-1-block_header-3.xz b/tests/files/good-1-block_header-3.xz
new file mode 100644
index 0000000..1565312
--- /dev/null
+++ b/tests/files/good-1-block_header-3.xz
Binary files differ
diff --git a/tests/files/good-1-check-crc32.xz b/tests/files/good-1-check-crc32.xz
new file mode 100644
index 0000000..6c89593
--- /dev/null
+++ b/tests/files/good-1-check-crc32.xz
Binary files differ
diff --git a/tests/files/good-1-check-crc64.xz b/tests/files/good-1-check-crc64.xz
new file mode 100644
index 0000000..5a9915d
--- /dev/null
+++ b/tests/files/good-1-check-crc64.xz
Binary files differ
diff --git a/tests/files/good-1-check-none.xz b/tests/files/good-1-check-none.xz
new file mode 100644
index 0000000..1e85faf
--- /dev/null
+++ b/tests/files/good-1-check-none.xz
Binary files differ
diff --git a/tests/files/good-1-check-sha256.xz b/tests/files/good-1-check-sha256.xz
new file mode 100644
index 0000000..fdc556b
--- /dev/null
+++ b/tests/files/good-1-check-sha256.xz
Binary files differ
diff --git a/tests/files/good-1-delta-lzma2.tiff.xz b/tests/files/good-1-delta-lzma2.tiff.xz
new file mode 100644
index 0000000..1f033bc
--- /dev/null
+++ b/tests/files/good-1-delta-lzma2.tiff.xz
Binary files differ
diff --git a/tests/files/good-1-empty-bcj-lzma2.xz b/tests/files/good-1-empty-bcj-lzma2.xz
new file mode 100644
index 0000000..94016d8
--- /dev/null
+++ b/tests/files/good-1-empty-bcj-lzma2.xz
Binary files differ
diff --git a/tests/files/good-1-lzma2-1.xz b/tests/files/good-1-lzma2-1.xz
new file mode 100644
index 0000000..d8d6489
--- /dev/null
+++ b/tests/files/good-1-lzma2-1.xz
Binary files differ
diff --git a/tests/files/good-1-lzma2-2.xz b/tests/files/good-1-lzma2-2.xz
new file mode 100644
index 0000000..7e8cdf1
--- /dev/null
+++ b/tests/files/good-1-lzma2-2.xz
Binary files differ
diff --git a/tests/files/good-1-lzma2-3.xz b/tests/files/good-1-lzma2-3.xz
new file mode 100644
index 0000000..c4c72be
--- /dev/null
+++ b/tests/files/good-1-lzma2-3.xz
Binary files differ
diff --git a/tests/files/good-1-lzma2-4.xz b/tests/files/good-1-lzma2-4.xz
new file mode 100644
index 0000000..e0d623a
--- /dev/null
+++ b/tests/files/good-1-lzma2-4.xz
Binary files differ
diff --git a/tests/files/good-1-lzma2-5.xz b/tests/files/good-1-lzma2-5.xz
new file mode 100644
index 0000000..339d1c3
--- /dev/null
+++ b/tests/files/good-1-lzma2-5.xz
Binary files differ
diff --git a/tests/files/good-1-sparc-lzma2.xz b/tests/files/good-1-sparc-lzma2.xz
new file mode 100644
index 0000000..4532bc6
--- /dev/null
+++ b/tests/files/good-1-sparc-lzma2.xz
Binary files differ
diff --git a/tests/files/good-1-v0-trailing-1.lz b/tests/files/good-1-v0-trailing-1.lz
new file mode 100644
index 0000000..91f2b64
--- /dev/null
+++ b/tests/files/good-1-v0-trailing-1.lz
Binary files differ
diff --git a/tests/files/good-1-v0.lz b/tests/files/good-1-v0.lz
new file mode 100644
index 0000000..99e3f27
--- /dev/null
+++ b/tests/files/good-1-v0.lz
Binary files differ
diff --git a/tests/files/good-1-v1-trailing-1.lz b/tests/files/good-1-v1-trailing-1.lz
new file mode 100644
index 0000000..198e65c
--- /dev/null
+++ b/tests/files/good-1-v1-trailing-1.lz
Binary files differ
diff --git a/tests/files/good-1-v1-trailing-2.lz b/tests/files/good-1-v1-trailing-2.lz
new file mode 100644
index 0000000..9a028fa
--- /dev/null
+++ b/tests/files/good-1-v1-trailing-2.lz
Binary files differ
diff --git a/tests/files/good-1-v1.lz b/tests/files/good-1-v1.lz
new file mode 100644
index 0000000..4c9565c
--- /dev/null
+++ b/tests/files/good-1-v1.lz
Binary files differ
diff --git a/tests/files/good-1-x86-lzma2.xz b/tests/files/good-1-x86-lzma2.xz
new file mode 100644
index 0000000..8053917
--- /dev/null
+++ b/tests/files/good-1-x86-lzma2.xz
Binary files differ
diff --git a/tests/files/good-2-lzma2.xz b/tests/files/good-2-lzma2.xz
new file mode 100644
index 0000000..bed5085
--- /dev/null
+++ b/tests/files/good-2-lzma2.xz
Binary files differ
diff --git a/tests/files/good-2-v0-v1.lz b/tests/files/good-2-v0-v1.lz
new file mode 100644
index 0000000..dc3165a
--- /dev/null
+++ b/tests/files/good-2-v0-v1.lz
Binary files differ
diff --git a/tests/files/good-2-v1-v0.lz b/tests/files/good-2-v1-v0.lz
new file mode 100644
index 0000000..a999582
--- /dev/null
+++ b/tests/files/good-2-v1-v0.lz
Binary files differ
diff --git a/tests/files/good-2-v1-v1.lz b/tests/files/good-2-v1-v1.lz
new file mode 100644
index 0000000..5381891
--- /dev/null
+++ b/tests/files/good-2-v1-v1.lz
Binary files differ
diff --git a/tests/files/good-known_size-with_eopm.lzma b/tests/files/good-known_size-with_eopm.lzma
new file mode 100644
index 0000000..1b45307
--- /dev/null
+++ b/tests/files/good-known_size-with_eopm.lzma
Binary files differ
diff --git a/tests/files/good-known_size-without_eopm.lzma b/tests/files/good-known_size-without_eopm.lzma
new file mode 100644
index 0000000..83623fd
--- /dev/null
+++ b/tests/files/good-known_size-without_eopm.lzma
Binary files differ
diff --git a/tests/files/good-unknown_size-with_eopm.lzma b/tests/files/good-unknown_size-with_eopm.lzma
new file mode 100644
index 0000000..0f4ff82
--- /dev/null
+++ b/tests/files/good-unknown_size-with_eopm.lzma
Binary files differ
diff --git a/tests/files/unsupported-1-v234.lz b/tests/files/unsupported-1-v234.lz
new file mode 100644
index 0000000..e571b0f
--- /dev/null
+++ b/tests/files/unsupported-1-v234.lz
Binary files differ
diff --git a/tests/files/unsupported-block_header.xz b/tests/files/unsupported-block_header.xz
new file mode 100644
index 0000000..3830442
--- /dev/null
+++ b/tests/files/unsupported-block_header.xz
Binary files differ
diff --git a/tests/files/unsupported-check.xz b/tests/files/unsupported-check.xz
new file mode 100644
index 0000000..c28355e
--- /dev/null
+++ b/tests/files/unsupported-check.xz
Binary files differ
diff --git a/tests/files/unsupported-filter_flags-1.xz b/tests/files/unsupported-filter_flags-1.xz
new file mode 100644
index 0000000..48b9373
--- /dev/null
+++ b/tests/files/unsupported-filter_flags-1.xz
Binary files differ
diff --git a/tests/files/unsupported-filter_flags-2.xz b/tests/files/unsupported-filter_flags-2.xz
new file mode 100644
index 0000000..c283359
--- /dev/null
+++ b/tests/files/unsupported-filter_flags-2.xz
Binary files differ
diff --git a/tests/files/unsupported-filter_flags-3.xz b/tests/files/unsupported-filter_flags-3.xz
new file mode 100644
index 0000000..2608498
--- /dev/null
+++ b/tests/files/unsupported-filter_flags-3.xz
Binary files differ
diff --git a/tests/ossfuzz/Makefile b/tests/ossfuzz/Makefile
new file mode 100644
index 0000000..747fb66
--- /dev/null
+++ b/tests/ossfuzz/Makefile
@@ -0,0 +1,7 @@
+fuzz: fuzz.c
+ $(CC) $(CFLAGS) -c fuzz.c -I ../../src/liblzma/api/
+ $(CXX) $(CXXFLAGS) $(LIB_FUZZING_ENGINE) fuzz.o -o $(OUT)/fuzz \
+ ../../src/liblzma/.libs/liblzma.a
+
+clean:
+ rm -f *.o
diff --git a/tests/ossfuzz/config/fuzz.dict b/tests/ossfuzz/config/fuzz.dict
new file mode 100644
index 0000000..932d67c
--- /dev/null
+++ b/tests/ossfuzz/config/fuzz.dict
@@ -0,0 +1,2 @@
+"\xFD7zXZ\x00"
+"YZ"
diff --git a/tests/ossfuzz/config/fuzz.options b/tests/ossfuzz/config/fuzz.options
new file mode 100644
index 0000000..d59dfc1
--- /dev/null
+++ b/tests/ossfuzz/config/fuzz.options
@@ -0,0 +1,2 @@
+[libfuzzer]
+dict = fuzz.dict
diff --git a/tests/ossfuzz/fuzz.c b/tests/ossfuzz/fuzz.c
new file mode 100644
index 0000000..6d89930
--- /dev/null
+++ b/tests/ossfuzz/fuzz.c
@@ -0,0 +1,82 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file fuzz.c
+/// \brief Fuzz test program for liblzma
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "lzma.h"
+
+
+// Output buffer for decompressed data. This is write only; nothing cares
+// about the actual data written here.
+static uint8_t outbuf[4096];
+
+
+extern int
+LLVMFuzzerTestOneInput(const uint8_t *inbuf, size_t inbuf_size)
+{
+ // Some header values can make liblzma allocate a lot of RAM
+ // (up to about 4 GiB with liblzma 5.2.x). We set a limit here to
+ // prevent extreme allocations when fuzzing.
+ const uint64_t memlimit = 300 << 20; // 300 MiB
+
+ // Initialize a .xz decoder using the above memory usage limit.
+ // Enable support for concatenated .xz files which is used when
+ // decompressing regular .xz files (instead of data embedded inside
+ // some other file format). Integrity checks on the uncompressed
+ // data are ignored to make fuzzing more effective (incorrect check
+ // values won't prevent the decoder from processing more input).
+ //
+ // The flag LZMA_IGNORE_CHECK doesn't disable verification of header
+ // CRC32 values. Those checks are disabled when liblzma is built
+ // with the #define FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION.
+ lzma_stream strm = LZMA_STREAM_INIT;
+ lzma_ret ret = lzma_stream_decoder(&strm, memlimit,
+ LZMA_CONCATENATED | LZMA_IGNORE_CHECK);
+ if (ret != LZMA_OK) {
+ // This should never happen unless the system has
+ // no free memory or address space to allow the small
+ // allocations that the initialization requires.
+ fprintf(stderr, "lzma_stream_decoder() failed (%d)\n", ret);
+ abort();
+ }
+
+ // Give the whole input buffer at once to liblzma.
+ // Output buffer isn't initialized as liblzma only writes to it.
+ strm.next_in = inbuf;
+ strm.avail_in = inbuf_size;
+ strm.next_out = outbuf;
+ strm.avail_out = sizeof(outbuf);
+
+ while ((ret = lzma_code(&strm, LZMA_FINISH)) == LZMA_OK) {
+ if (strm.avail_out == 0) {
+ // outbuf became full. We don't care about the
+ // uncompressed data there, so we simply reuse
+ // the outbuf and overwrite the old data.
+ strm.next_out = outbuf;
+ strm.avail_out = sizeof(outbuf);
+ }
+ }
+
+ // LZMA_PROG_ERROR should never happen as long as the code calling
+ // the liblzma functions is correct. Thus LZMA_PROG_ERROR is a sign
+ // of a bug in either this function or in liblzma.
+ if (ret == LZMA_PROG_ERROR) {
+ fprintf(stderr, "lzma_code() returned LZMA_PROG_ERROR\n");
+ abort();
+ }
+
+ // Free the allocated memory.
+ lzma_end(&strm);
+
+ return 0;
+}
diff --git a/tests/test_bcj_exact_size.c b/tests/test_bcj_exact_size.c
new file mode 100644
index 0000000..551166c
--- /dev/null
+++ b/tests/test_bcj_exact_size.c
@@ -0,0 +1,124 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file test_bcj_exact_size.c
+/// \brief Tests BCJ decoding when the output size is known
+///
+/// These tests fail with XZ Utils 5.0.3 and earlier.
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tests.h"
+
+
+static void
+test_exact_size(void)
+{
+#if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
+ assert_skip("Encoder or decoder support disabled");
+#else
+ if (!lzma_filter_encoder_is_supported(LZMA_FILTER_POWERPC)
+ || !lzma_filter_decoder_is_supported(
+ LZMA_FILTER_POWERPC))
+ assert_skip("PowerPC BCJ encoder and/or decoder "
+ "is disabled");
+
+ // Something to be compressed
+ const uint8_t in[16] = "0123456789ABCDEF";
+
+ // in[] after compression
+ uint8_t compressed[1024];
+ size_t compressed_size = 0;
+
+ // Output buffer for decompressing compressed[]
+ uint8_t out[sizeof(in)];
+
+ // Compress with PowerPC BCJ and LZMA2. PowerPC BCJ is used because
+ // it has fixed 4-byte alignment which makes triggering the potential
+ // bug easy.
+ lzma_options_lzma opt_lzma2;
+ assert_false(lzma_lzma_preset(&opt_lzma2, 0));
+
+ lzma_filter filters[3] = {
+ { .id = LZMA_FILTER_POWERPC, .options = NULL },
+ { .id = LZMA_FILTER_LZMA2, .options = &opt_lzma2 },
+ { .id = LZMA_VLI_UNKNOWN, .options = NULL },
+ };
+
+ assert_lzma_ret(lzma_stream_buffer_encode(
+ filters, LZMA_CHECK_CRC32, NULL,
+ in, sizeof(in),
+ compressed, &compressed_size, sizeof(compressed)),
+ LZMA_OK);
+
+ // Decompress so that we won't give more output space than
+ // the Stream will need.
+ lzma_stream strm = LZMA_STREAM_INIT;
+ assert_lzma_ret(lzma_stream_decoder(&strm, 10 << 20, 0), LZMA_OK);
+
+ strm.next_in = compressed;
+ strm.next_out = out;
+
+ while (true) {
+ if (strm.total_in < compressed_size)
+ strm.avail_in = 1;
+
+ const lzma_ret ret = lzma_code(&strm, LZMA_RUN);
+ if (ret == LZMA_STREAM_END) {
+ assert_uint_eq(strm.total_in, compressed_size);
+ assert_uint_eq(strm.total_out, sizeof(in));
+ lzma_end(&strm);
+ return;
+ }
+
+ assert_lzma_ret(ret, LZMA_OK);
+
+ if (strm.total_out < sizeof(in))
+ strm.avail_out = 1;
+ }
+#endif
+}
+
+
+static void
+test_empty_block(void)
+{
+#ifndef HAVE_DECODERS
+ assert_skip("Decoder support disabled");
+#else
+ if (!lzma_filter_decoder_is_supported(LZMA_FILTER_POWERPC))
+ assert_skip("PowerPC BCJ decoder is disabled");
+
+ // An empty file with one Block using PowerPC BCJ and LZMA2.
+ size_t in_size;
+ uint8_t *empty_bcj_lzma2 = tuktest_file_from_srcdir(
+ "files/good-1-empty-bcj-lzma2.xz", &in_size);
+
+ // Decompress without giving any output space.
+ uint64_t memlimit = 1 << 20;
+ uint8_t out[1];
+ size_t in_pos = 0;
+ size_t out_pos = 0;
+ assert_lzma_ret(lzma_stream_buffer_decode(&memlimit, 0, NULL,
+ empty_bcj_lzma2, &in_pos, in_size, out, &out_pos, 0),
+ LZMA_OK);
+ assert_uint_eq(in_pos, in_size);
+ assert_uint_eq(out_pos, 0);
+#endif
+}
+
+
+extern int
+main(int argc, char **argv)
+{
+ tuktest_start(argc, argv);
+
+ tuktest_run(test_exact_size);
+ tuktest_run(test_empty_block);
+
+ return tuktest_end();
+}
diff --git a/tests/test_block_header.c b/tests/test_block_header.c
new file mode 100644
index 0000000..b310135
--- /dev/null
+++ b/tests/test_block_header.c
@@ -0,0 +1,520 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file test_block_header.c
+/// \brief Tests Block Header coders
+//
+// Authors: Lasse Collin
+// Jia Tan
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tests.h"
+
+
+static lzma_options_lzma opt_lzma;
+
+
+// Used in test_lzma_block_header_decode() between tests to ensure
+// no artifacts are leftover in the block struct that could influence
+// later tests.
+#define RESET_BLOCK(block, buf) \
+do { \
+ lzma_filter *filters_ = (block).filters; \
+ lzma_filters_free(filters_, NULL); \
+ memzero((buf), sizeof((buf))); \
+ memzero(&(block), sizeof(lzma_block)); \
+ (block).filters = filters_; \
+ (block).check = LZMA_CHECK_CRC32; \
+} while (0);
+
+
+#ifdef HAVE_ENCODERS
+static lzma_filter filters_none[1] = {
+ {
+ .id = LZMA_VLI_UNKNOWN,
+ },
+};
+
+
+static lzma_filter filters_one[2] = {
+ {
+ .id = LZMA_FILTER_LZMA2,
+ .options = &opt_lzma,
+ }, {
+ .id = LZMA_VLI_UNKNOWN,
+ }
+};
+
+
+// These filters are only used in test_lzma_block_header_decode()
+// which only runs if encoders and decoders are configured.
+#ifdef HAVE_DECODERS
+static lzma_filter filters_four[5] = {
+ {
+ .id = LZMA_FILTER_X86,
+ .options = NULL,
+ }, {
+ .id = LZMA_FILTER_X86,
+ .options = NULL,
+ }, {
+ .id = LZMA_FILTER_X86,
+ .options = NULL,
+ }, {
+ .id = LZMA_FILTER_LZMA2,
+ .options = &opt_lzma,
+ }, {
+ .id = LZMA_VLI_UNKNOWN,
+ }
+};
+#endif
+
+
+static lzma_filter filters_five[6] = {
+ {
+ .id = LZMA_FILTER_X86,
+ .options = NULL,
+ }, {
+ .id = LZMA_FILTER_X86,
+ .options = NULL,
+ }, {
+ .id = LZMA_FILTER_X86,
+ .options = NULL,
+ }, {
+ .id = LZMA_FILTER_X86,
+ .options = NULL,
+ }, {
+ .id = LZMA_FILTER_LZMA2,
+ .options = &opt_lzma,
+ }, {
+ .id = LZMA_VLI_UNKNOWN,
+ }
+};
+#endif
+
+
+static void
+test_lzma_block_header_size(void)
+{
+#ifndef HAVE_ENCODERS
+ assert_skip("Encoder support disabled");
+#else
+ if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86))
+ assert_skip("x86 BCJ encoder is disabled");
+
+ lzma_block block = {
+ .version = 0,
+ .filters = filters_one,
+ .compressed_size = LZMA_VLI_UNKNOWN,
+ .uncompressed_size = LZMA_VLI_UNKNOWN,
+ .check = LZMA_CHECK_CRC32
+ };
+
+ // Test that all initial options are valid
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
+ assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
+ assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
+ assert_uint_eq(block.header_size % 4, 0);
+
+ // Test invalid version number
+ for (uint32_t i = 2; i < 20; i++) {
+ block.version = i;
+ assert_lzma_ret(lzma_block_header_size(&block),
+ LZMA_OPTIONS_ERROR);
+ }
+
+ block.version = 1;
+
+ // Test invalid compressed size
+ block.compressed_size = 0;
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
+
+ block.compressed_size = LZMA_VLI_MAX + 1;
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
+ block.compressed_size = LZMA_VLI_UNKNOWN;
+
+ // Test invalid uncompressed size
+ block.uncompressed_size = LZMA_VLI_MAX + 1;
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
+ block.uncompressed_size = LZMA_VLI_MAX;
+
+ // Test invalid filters
+ block.filters = NULL;
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
+
+ block.filters = filters_none;
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
+
+ block.filters = filters_five;
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_PROG_ERROR);
+
+ block.filters = filters_one;
+
+ // Test setting compressed_size to something valid
+ block.compressed_size = 4096;
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
+ assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
+ assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
+ assert_uint_eq(block.header_size % 4, 0);
+
+ // Test setting uncompressed_size to something valid
+ block.uncompressed_size = 4096;
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
+ assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
+ assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
+ assert_uint_eq(block.header_size % 4, 0);
+
+ // This should pass, but header_size will be an invalid value
+ // because the total block size will not be able to fit in a valid
+ // lzma_vli. This way a temporary value can be used to reserve
+ // space for the header and later the actual value can be set.
+ block.compressed_size = LZMA_VLI_MAX;
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
+ assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
+ assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
+ assert_uint_eq(block.header_size % 4, 0);
+
+ // Use an invalid value for a filter option. This should still pass
+ // because the size of the LZMA2 properties is known by liblzma
+ // without reading any of the options so it doesn't validate them.
+ lzma_options_lzma bad_ops;
+ assert_false(lzma_lzma_preset(&bad_ops, 1));
+ bad_ops.pb = 0x1000;
+
+ lzma_filter bad_filters[2] = {
+ {
+ .id = LZMA_FILTER_LZMA2,
+ .options = &bad_ops
+ },
+ {
+ .id = LZMA_VLI_UNKNOWN,
+ .options = NULL
+ }
+ };
+
+ block.filters = bad_filters;
+
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
+ assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
+ assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
+ assert_uint_eq(block.header_size % 4, 0);
+
+ // Use an invalid block option. The check type isn't stored in
+ // the Block Header and so _header_size ignores it.
+ block.check = INVALID_LZMA_CHECK_ID;
+ block.ignore_check = false;
+
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
+ assert_uint(block.header_size, >=, LZMA_BLOCK_HEADER_SIZE_MIN);
+ assert_uint(block.header_size, <=, LZMA_BLOCK_HEADER_SIZE_MAX);
+ assert_uint_eq(block.header_size % 4, 0);
+#endif
+}
+
+
+static void
+test_lzma_block_header_encode(void)
+{
+#if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
+ assert_skip("Encoder or decoder support disabled");
+#else
+
+ if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86)
+ || !lzma_filter_decoder_is_supported(LZMA_FILTER_X86))
+ assert_skip("x86 BCJ encoder and/or decoder "
+ "is disabled");
+
+ lzma_block block = {
+ .version = 1,
+ .filters = filters_one,
+ .compressed_size = LZMA_VLI_UNKNOWN,
+ .uncompressed_size = LZMA_VLI_UNKNOWN,
+ .check = LZMA_CHECK_CRC32,
+ };
+
+ // Ensure all block options are valid before changes are tested
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
+
+ uint8_t out[LZMA_BLOCK_HEADER_SIZE_MAX];
+
+ // Test invalid block version
+ for (uint32_t i = 2; i < 20; i++) {
+ block.version = i;
+ assert_lzma_ret(lzma_block_header_encode(&block, out),
+ LZMA_PROG_ERROR);
+ }
+
+ block.version = 1;
+
+ // Test invalid header size (< min, > max, % 4 != 0)
+ block.header_size = LZMA_BLOCK_HEADER_SIZE_MIN - 4;
+ assert_lzma_ret(lzma_block_header_encode(&block, out),
+ LZMA_PROG_ERROR);
+ block.header_size = LZMA_BLOCK_HEADER_SIZE_MIN + 2;
+ assert_lzma_ret(lzma_block_header_encode(&block, out),
+ LZMA_PROG_ERROR);
+ block.header_size = LZMA_BLOCK_HEADER_SIZE_MAX + 4;
+ assert_lzma_ret(lzma_block_header_encode(&block, out),
+ LZMA_PROG_ERROR);
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
+
+ // Test invalid compressed_size
+ block.compressed_size = 0;
+ assert_lzma_ret(lzma_block_header_encode(&block, out),
+ LZMA_PROG_ERROR);
+ block.compressed_size = LZMA_VLI_MAX + 1;
+ assert_lzma_ret(lzma_block_header_encode(&block, out),
+ LZMA_PROG_ERROR);
+
+ // This test passes test_lzma_block_header_size, but should
+ // fail here because there is not enough space to encode the
+ // proper block size because the total size is too big to fit
+ // in an lzma_vli
+ block.compressed_size = LZMA_VLI_MAX;
+ assert_lzma_ret(lzma_block_header_encode(&block, out),
+ LZMA_PROG_ERROR);
+ block.compressed_size = LZMA_VLI_UNKNOWN;
+
+ // Test invalid uncompressed size
+ block.uncompressed_size = LZMA_VLI_MAX + 1;
+ assert_lzma_ret(lzma_block_header_encode(&block, out),
+ LZMA_PROG_ERROR);
+ block.uncompressed_size = LZMA_VLI_UNKNOWN;
+
+ // Test invalid block check
+ block.check = INVALID_LZMA_CHECK_ID;
+ block.ignore_check = false;
+ assert_lzma_ret(lzma_block_header_encode(&block, out),
+ LZMA_PROG_ERROR);
+ block.check = LZMA_CHECK_CRC32;
+
+ // Test invalid filters
+ block.filters = NULL;
+ assert_lzma_ret(lzma_block_header_encode(&block, out),
+ LZMA_PROG_ERROR);
+
+ block.filters = filters_none;
+ assert_lzma_ret(lzma_block_header_encode(&block, out),
+ LZMA_PROG_ERROR);
+
+ block.filters = filters_five;
+ block.header_size = LZMA_BLOCK_HEADER_SIZE_MAX - 4;
+ assert_lzma_ret(lzma_block_header_encode(&block, out),
+ LZMA_PROG_ERROR);
+
+ // Test valid encoding and verify bytes of block header.
+ // More complicated tests for encoding headers are included
+ // in test_lzma_block_header_decode.
+ block.filters = filters_one;
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
+ assert_lzma_ret(lzma_block_header_encode(&block, out), LZMA_OK);
+
+ // First read block header size from out and verify
+ // that it == (encoded size + 1) * 4
+ uint32_t header_size = (out[0] + 1U) * 4;
+ assert_uint_eq(header_size, block.header_size);
+
+ // Next read block flags
+ uint8_t flags = out[1];
+
+ // Should have number of filters = 1
+ assert_uint_eq((flags & 0x3) + 1, 1);
+
+ // Bits 2-7 must be empty not set
+ assert_uint_eq(flags & (0xFF - 0x3), 0);
+
+ // Verify filter flags
+ // Decode Filter ID
+ lzma_vli filter_id = 0;
+ size_t pos = 2;
+ assert_lzma_ret(lzma_vli_decode(&filter_id, NULL, out,
+ &pos, header_size), LZMA_OK);
+ assert_uint_eq(filter_id, filters_one[0].id);
+
+ // Decode Size of Properties
+ lzma_vli prop_size = 0;
+ assert_lzma_ret(lzma_vli_decode(&prop_size, NULL, out,
+ &pos, header_size), LZMA_OK);
+
+ // LZMA2 has 1 byte prop size
+ assert_uint_eq(prop_size, 1);
+ uint8_t expected_filter_props = 0;
+ assert_lzma_ret(lzma_properties_encode(filters_one,
+ &expected_filter_props), LZMA_OK);
+ assert_uint_eq(out[pos], expected_filter_props);
+ pos++;
+
+ // Check null-padding
+ for (size_t i = pos; i < header_size - 4; i++)
+ assert_uint_eq(out[i], 0);
+
+ // Check CRC32
+ assert_uint_eq(read32le(&out[header_size - 4]), lzma_crc32(out,
+ header_size - 4, 0));
+#endif
+}
+
+
+#if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
+// Helper function to compare two lzma_block structures field by field
+static void
+compare_blocks(lzma_block *block_expected, lzma_block *block_actual)
+{
+ assert_uint_eq(block_actual->version, block_expected->version);
+ assert_uint_eq(block_actual->compressed_size,
+ block_expected->compressed_size);
+ assert_uint_eq(block_actual->uncompressed_size,
+ block_expected->uncompressed_size);
+ assert_uint_eq(block_actual->check, block_expected->check);
+ assert_uint_eq(block_actual->header_size, block_expected->header_size);
+
+ // Compare filter IDs
+ assert_true(block_expected->filters && block_actual->filters);
+ lzma_filter expected_filter = block_expected->filters[0];
+ uint32_t filter_count = 0;
+ while (expected_filter.id != LZMA_VLI_UNKNOWN) {
+ assert_uint_eq(block_actual->filters[filter_count].id,
+ expected_filter.id);
+ expected_filter = block_expected->filters[++filter_count];
+ }
+
+ assert_uint_eq(block_actual->filters[filter_count].id,
+ LZMA_VLI_UNKNOWN);
+}
+#endif
+
+
+static void
+test_lzma_block_header_decode(void)
+{
+#if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
+ assert_skip("Encoder or decoder support disabled");
+#else
+ if (!lzma_filter_encoder_is_supported(LZMA_FILTER_X86)
+ || !lzma_filter_decoder_is_supported(LZMA_FILTER_X86))
+ assert_skip("x86 BCJ encoder and/or decoder "
+ "is disabled");
+
+ lzma_block block = {
+ .filters = filters_one,
+ .compressed_size = LZMA_VLI_UNKNOWN,
+ .uncompressed_size = LZMA_VLI_UNKNOWN,
+ .check = LZMA_CHECK_CRC32,
+ .version = 0
+ };
+
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
+
+ // Encode block header with simple options
+ uint8_t out[LZMA_BLOCK_HEADER_SIZE_MAX];
+ assert_lzma_ret(lzma_block_header_encode(&block, out), LZMA_OK);
+
+ // Decode block header and check that the options match
+ lzma_filter decoded_filters[LZMA_FILTERS_MAX + 1];
+ lzma_block decoded_block = {
+ .version = 0,
+ .filters = decoded_filters,
+ .check = LZMA_CHECK_CRC32
+ };
+ decoded_block.header_size = lzma_block_header_size_decode(out[0]);
+
+ assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
+ LZMA_OK);
+ compare_blocks(&block, &decoded_block);
+
+ // Reset output buffer and decoded_block
+ RESET_BLOCK(decoded_block, out);
+
+ // Test with compressed size set
+ block.compressed_size = 4096;
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
+ assert_lzma_ret(lzma_block_header_encode(&block, out), LZMA_OK);
+ decoded_block.header_size = lzma_block_header_size_decode(out[0]);
+ assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
+ LZMA_OK);
+ compare_blocks(&block, &decoded_block);
+
+ RESET_BLOCK(decoded_block, out);
+
+ // Test with uncompressed size set
+ block.uncompressed_size = 4096;
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
+ assert_lzma_ret(lzma_block_header_encode(&block, out), LZMA_OK);
+ decoded_block.header_size = lzma_block_header_size_decode(out[0]);
+ assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
+ LZMA_OK);
+ compare_blocks(&block, &decoded_block);
+
+ RESET_BLOCK(decoded_block, out);
+
+ // Test with multiple filters
+ block.filters = filters_four;
+ assert_lzma_ret(lzma_block_header_size(&block), LZMA_OK);
+ assert_lzma_ret(lzma_block_header_encode(&block, out), LZMA_OK);
+ decoded_block.header_size = lzma_block_header_size_decode(out[0]);
+ assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
+ LZMA_OK);
+ compare_blocks(&block, &decoded_block);
+
+ lzma_filters_free(decoded_filters, NULL);
+
+ // Test with too high version. The decoder will set it to a version
+ // that it supports.
+ decoded_block.version = 2;
+ assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
+ LZMA_OK);
+ assert_uint_eq(decoded_block.version, 1);
+
+ // Free the filters for the last time since all other cases should
+ // result in an error.
+ lzma_filters_free(decoded_filters, NULL);
+
+ // Test bad check type
+ decoded_block.check = INVALID_LZMA_CHECK_ID;
+ assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
+ LZMA_PROG_ERROR);
+ decoded_block.check = LZMA_CHECK_CRC32;
+
+ // Test bad check value
+ out[decoded_block.header_size - 1] -= 10;
+ assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
+ LZMA_DATA_ERROR);
+ out[decoded_block.header_size - 1] += 10;
+
+ // Test non-NULL padding
+ out[decoded_block.header_size - 5] = 1;
+
+ // Recompute CRC32
+ write32le(&out[decoded_block.header_size - 4], lzma_crc32(out,
+ decoded_block.header_size - 4, 0));
+ assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
+ LZMA_OPTIONS_ERROR);
+
+ // Test unsupported flags
+ out[1] = 0xFF;
+
+ // Recompute CRC32
+ write32le(&out[decoded_block.header_size - 4], lzma_crc32(out,
+ decoded_block.header_size - 4, 0));
+ assert_lzma_ret(lzma_block_header_decode(&decoded_block, NULL, out),
+ LZMA_OPTIONS_ERROR);
+#endif
+}
+
+
+extern int
+main(int argc, char **argv)
+{
+ tuktest_start(argc, argv);
+
+ if (lzma_lzma_preset(&opt_lzma, 1))
+ tuktest_error("lzma_lzma_preset() failed");
+
+ tuktest_run(test_lzma_block_header_size);
+ tuktest_run(test_lzma_block_header_encode);
+ tuktest_run(test_lzma_block_header_decode);
+
+ return tuktest_end();
+}
diff --git a/tests/test_check.c b/tests/test_check.c
new file mode 100644
index 0000000..cb1ad25
--- /dev/null
+++ b/tests/test_check.c
@@ -0,0 +1,390 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file test_check.c
+/// \brief Tests integrity checks
+//
+// Authors: Lasse Collin
+// Jia Tan
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tests.h"
+#include "mythread.h"
+
+
+// These must be specified as numbers so that the test works on EBCDIC
+// systems too.
+// static const uint8_t test_string[9] = "123456789";
+// static const uint8_t test_unaligned[12] = "xxx123456789";
+static const uint8_t test_string[9] = { 49, 50, 51, 52, 53, 54, 55, 56, 57 };
+static const uint8_t test_unaligned[12]
+ = { 120, 120, 120, 49, 50, 51, 52, 53, 54, 55, 56, 57 };
+
+// 2 MB is more than enough for the tests. Actually a tiny value would
+// work because we don't actually decompress the files, we only test
+// decoding of the Stream Header fields.
+#define TEST_CHECK_MEMLIMIT (2U << 20)
+
+static size_t no_check_size;
+static uint8_t *no_check_xz_data;
+
+static size_t unsupported_check_size;
+static uint8_t *unsupported_check_xz_data;
+
+#ifdef HAVE_CHECK_CRC32
+static size_t crc32_size;
+static uint8_t *crc32_xz_data;
+#endif
+
+#ifdef HAVE_CHECK_CRC64
+static size_t crc64_size;
+static uint8_t *crc64_xz_data;
+#endif
+
+#ifdef HAVE_CHECK_SHA256
+static size_t sha256_size;
+static uint8_t *sha256_xz_data;
+#endif
+
+
+#ifdef HAVE_CHECK_CRC64
+static const uint8_t *
+get_random256(uint32_t *seed)
+{
+ static uint8_t buf[256];
+
+ for (size_t i = 0; i < sizeof(buf); ++i) {
+ *seed = *seed * 1103515245 + 12345;
+ buf[i] = (uint8_t)(*seed >> 22);
+ }
+
+ return buf;
+}
+#endif
+
+
+static void
+test_lzma_crc32(void)
+{
+ // CRC32 is always enabled.
+ assert_true(lzma_check_is_supported(LZMA_CHECK_CRC32));
+
+ const uint32_t test_vector = 0xCBF43926;
+
+ // Test 1
+ assert_uint_eq(lzma_crc32(test_string, sizeof(test_string), 0),
+ test_vector);
+
+ // Test 2
+ assert_uint_eq(lzma_crc32(test_unaligned + 3, sizeof(test_string), 0),
+ test_vector);
+
+ // Test 3
+ uint32_t crc = 0;
+ for (size_t i = 0; i < sizeof(test_string); ++i)
+ crc = lzma_crc32(test_string + i, 1, crc);
+ assert_uint_eq(crc, test_vector);
+}
+
+
+static void
+test_lzma_crc64(void)
+{
+ // CRC64 can be disabled.
+ if (!lzma_check_is_supported(LZMA_CHECK_CRC64))
+ assert_skip("CRC64 support is disabled");
+
+ // If CRC64 is disabled then lzma_crc64() will be missing.
+ // Using an ifdef here avoids a linker error.
+#ifdef HAVE_CHECK_CRC64
+ const uint64_t test_vector = 0x995DC9BBDF1939FA;
+
+ // Test 1
+ assert_uint_eq(lzma_crc64(test_string, sizeof(test_string), 0),
+ test_vector);
+
+ // Test 2
+ assert_uint_eq(lzma_crc64(test_unaligned + 3, sizeof(test_string), 0),
+ test_vector);
+
+ // Test 3
+ uint64_t crc = 0;
+ for (size_t i = 0; i < sizeof(test_string); ++i)
+ crc = lzma_crc64(test_string + i, 1, crc);
+ assert_uint_eq(crc, test_vector);
+
+ // Test 4: The CLMUL implementation works on 16-byte chunks.
+ // Test combination of different start and end alignments
+ // and also short buffer lengths where special handling is needed.
+ uint32_t seed = 29;
+ crc = 0x96E30D5184B7FA2C; // Random initial value
+ for (size_t start = 0; start < 32; ++start)
+ for (size_t size = 1; size < 256 - 32; ++size)
+ crc = lzma_crc64(get_random256(&seed), size, crc);
+
+ assert_uint_eq(crc, 0x23AB787177231C9F);
+#endif
+}
+
+
+static void
+test_lzma_supported_checks(void)
+{
+ static const lzma_check expected_check_ids[] = {
+ LZMA_CHECK_NONE,
+#ifdef HAVE_CHECK_CRC32
+ LZMA_CHECK_CRC32,
+#endif
+#ifdef HAVE_CHECK_CRC64
+ LZMA_CHECK_CRC64,
+#endif
+#ifdef HAVE_CHECK_SHA256
+ LZMA_CHECK_SHA256,
+#endif
+ };
+
+ for (lzma_check i = 0; i <= LZMA_CHECK_ID_MAX + 1; i++) {
+ bool matched = false;
+ for (unsigned int j = 0; j < ARRAY_SIZE(expected_check_ids);
+ j++) {
+ if (expected_check_ids[j] == i) {
+ matched = true;
+ break;
+ }
+ }
+
+ if (matched)
+ assert_true(lzma_check_is_supported(i));
+ else
+ assert_false(lzma_check_is_supported(i));
+ }
+}
+
+
+static void
+test_lzma_check_size(void)
+{
+ // Expected check sizes taken from src/liblzma/api/lzma/check.h
+ static const uint32_t expected_check_sizes[] = {
+ 0, 4, 4, 4, 8, 8, 8, 16, 16, 16,
+ 32, 32, 32, 64, 64, 64
+ };
+
+ for (lzma_check i = 0; i < ARRAY_SIZE(expected_check_sizes); i++)
+ assert_uint_eq(expected_check_sizes[i], lzma_check_size(i));
+
+ assert_uint_eq(lzma_check_size(INVALID_LZMA_CHECK_ID), UINT32_MAX);
+}
+
+
+// Test the single threaded decoder for lzma_get_check
+static void
+test_lzma_get_check_st(void)
+{
+#ifndef HAVE_DECODERS
+ assert_skip("Decoder support disabled");
+#else
+ const uint32_t flags = LZMA_TELL_ANY_CHECK |
+ LZMA_TELL_UNSUPPORTED_CHECK |
+ LZMA_TELL_NO_CHECK;
+
+ uint8_t outbuf[128];
+ lzma_stream strm = LZMA_STREAM_INIT;
+
+ // Test a file with no integrity check:
+ assert_lzma_ret(lzma_stream_decoder(&strm, TEST_CHECK_MEMLIMIT,
+ flags), LZMA_OK);
+ strm.next_in = no_check_xz_data;
+ strm.avail_in = no_check_size;
+ strm.next_out = outbuf;
+ strm.avail_out = sizeof(outbuf);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_NO_CHECK);
+ assert_lzma_check(lzma_get_check(&strm), LZMA_CHECK_NONE);
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_STREAM_END);
+
+ // Test a file with an unsupported integrity check type:
+ assert_lzma_ret(lzma_stream_decoder(&strm, TEST_CHECK_MEMLIMIT,
+ flags), LZMA_OK);
+ strm.next_in = unsupported_check_xz_data;
+ strm.avail_in = unsupported_check_size;
+ strm.next_out = outbuf;
+ strm.avail_out = sizeof(outbuf);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_UNSUPPORTED_CHECK);
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_STREAM_END);
+
+ // Test a file with CRC32 as the integrity check:
+#ifdef HAVE_CHECK_CRC32
+ assert_lzma_ret(lzma_stream_decoder(&strm, TEST_CHECK_MEMLIMIT,
+ flags), LZMA_OK);
+ strm.next_in = crc32_xz_data;
+ strm.avail_in = crc32_size;
+ strm.next_out = outbuf;
+ strm.avail_out = sizeof(outbuf);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_GET_CHECK);
+ assert_lzma_check(lzma_get_check(&strm), LZMA_CHECK_CRC32);
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_STREAM_END);
+#endif
+
+ // Test a file with CRC64 as the integrity check:
+#ifdef HAVE_CHECK_CRC64
+ assert_lzma_ret(lzma_stream_decoder(&strm, TEST_CHECK_MEMLIMIT,
+ flags), LZMA_OK);
+ strm.next_in = crc64_xz_data;
+ strm.avail_in = crc64_size;
+ strm.next_out = outbuf;
+ strm.avail_out = sizeof(outbuf);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_GET_CHECK);
+ assert_lzma_check(lzma_get_check(&strm), LZMA_CHECK_CRC64);
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_STREAM_END);
+#endif
+
+ // Test a file with SHA-256 as the integrity check:
+#ifdef HAVE_CHECK_SHA256
+ assert_lzma_ret(lzma_stream_decoder(&strm, TEST_CHECK_MEMLIMIT,
+ flags), LZMA_OK);
+ strm.next_in = sha256_xz_data;
+ strm.avail_in = sha256_size;
+ strm.next_out = outbuf;
+ strm.avail_out = sizeof(outbuf);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_GET_CHECK);
+ assert_lzma_check(lzma_get_check(&strm), LZMA_CHECK_SHA256);
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_STREAM_END);
+#endif
+
+ lzma_end(&strm);
+#endif
+}
+
+
+static void
+test_lzma_get_check_mt(void)
+{
+#ifndef MYTHREAD_ENABLED
+ assert_skip("Threading support disabled");
+#elif !defined(HAVE_DECODERS)
+ assert_skip("Decoder support disabled");
+#else
+ const uint32_t flags = LZMA_TELL_ANY_CHECK |
+ LZMA_TELL_UNSUPPORTED_CHECK |
+ LZMA_TELL_NO_CHECK;
+
+ const lzma_mt options = {
+ .flags = flags,
+ .threads = 2,
+ .timeout = 0,
+ .memlimit_threading = TEST_CHECK_MEMLIMIT,
+ .memlimit_stop = TEST_CHECK_MEMLIMIT
+ };
+
+ uint8_t outbuf[128];
+ lzma_stream strm = LZMA_STREAM_INIT;
+
+ // Test a file with no integrity check:
+ assert_lzma_ret(lzma_stream_decoder_mt(&strm, &options), LZMA_OK);
+ strm.next_in = no_check_xz_data;
+ strm.avail_in = no_check_size;
+ strm.next_out = outbuf;
+ strm.avail_out = sizeof(outbuf);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_NO_CHECK);
+ assert_lzma_check(lzma_get_check(&strm), LZMA_CHECK_NONE);
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_STREAM_END);
+
+ // Test a file with an unsupported integrity check type:
+ assert_lzma_ret(lzma_stream_decoder_mt(&strm, &options), LZMA_OK);
+ strm.next_in = unsupported_check_xz_data;
+ strm.avail_in = unsupported_check_size;
+ strm.next_out = outbuf;
+ strm.avail_out = sizeof(outbuf);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_UNSUPPORTED_CHECK);
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_STREAM_END);
+
+ // Test a file with CRC32 as the integrity check:
+#ifdef HAVE_CHECK_CRC32
+ assert_lzma_ret(lzma_stream_decoder_mt(&strm, &options), LZMA_OK);
+ strm.next_in = crc32_xz_data;
+ strm.avail_in = crc32_size;
+ strm.next_out = outbuf;
+ strm.avail_out = sizeof(outbuf);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_GET_CHECK);
+ assert_lzma_check(lzma_get_check(&strm), LZMA_CHECK_CRC32);
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_STREAM_END);
+#endif
+
+ // Test a file with CRC64 as the integrity check:
+#ifdef HAVE_CHECK_CRC64
+ assert_lzma_ret(lzma_stream_decoder_mt(&strm, &options), LZMA_OK);
+ strm.next_in = crc64_xz_data;
+ strm.avail_in = crc64_size;
+ strm.next_out = outbuf;
+ strm.avail_out = sizeof(outbuf);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_GET_CHECK);
+ assert_lzma_check(lzma_get_check(&strm), LZMA_CHECK_CRC64);
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_STREAM_END);
+#endif
+
+ // Test a file with SHA-256 as the integrity check:
+#ifdef HAVE_CHECK_SHA256
+ assert_lzma_ret(lzma_stream_decoder_mt(&strm,&options), LZMA_OK);
+ strm.next_in = sha256_xz_data;
+ strm.avail_in = sha256_size;
+ strm.next_out = outbuf;
+ strm.avail_out = sizeof(outbuf);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_GET_CHECK);
+ assert_lzma_check(lzma_get_check(&strm), LZMA_CHECK_SHA256);
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN), LZMA_STREAM_END);
+#endif
+
+ lzma_end(&strm);
+#endif
+}
+
+
+extern int
+main(int argc, char **argv)
+{
+ tuktest_start(argc, argv);
+
+ no_check_xz_data = tuktest_file_from_srcdir(
+ "files/good-1-check-none.xz", &no_check_size);
+
+ unsupported_check_xz_data = tuktest_file_from_srcdir(
+ "files/unsupported-check.xz",
+ &unsupported_check_size);
+
+#ifdef HAVE_CHECK_CRC32
+ crc32_xz_data = tuktest_file_from_srcdir(
+ "files/good-1-check-crc32.xz", &crc32_size);
+#endif
+
+#ifdef HAVE_CHECK_CRC64
+ crc64_xz_data = tuktest_file_from_srcdir(
+ "files/good-1-check-crc64.xz", &crc64_size);
+#endif
+
+#ifdef HAVE_CHECK_SHA256
+ sha256_xz_data = tuktest_file_from_srcdir(
+ "files/good-1-check-sha256.xz", &sha256_size);
+#endif
+
+ tuktest_run(test_lzma_crc32);
+ tuktest_run(test_lzma_crc64);
+ tuktest_run(test_lzma_supported_checks);
+ tuktest_run(test_lzma_check_size);
+ tuktest_run(test_lzma_get_check_st);
+ tuktest_run(test_lzma_get_check_mt);
+
+ return tuktest_end();
+}
diff --git a/tests/test_compress.sh b/tests/test_compress.sh
new file mode 100755
index 0000000..ff13cef
--- /dev/null
+++ b/tests/test_compress.sh
@@ -0,0 +1,150 @@
+#!/bin/sh
+
+###############################################################################
+#
+# Author: Lasse Collin
+#
+# This file has been put into the public domain.
+# You can do whatever you want with this file.
+#
+###############################################################################
+
+# If xz wasn't built, this test is skipped.
+if test -x ../src/xz/xz ; then
+ :
+else
+ exit 77
+fi
+
+# If compression or decompression support is missing, this test is skipped.
+# This isn't perfect as if only some compressors or decompressors are disabled
+# then this script can still fail because for now this doesn't check the
+# availability of each filter.
+if grep 'define HAVE_ENCODERS' ../config.h > /dev/null \
+ && grep 'define HAVE_DECODERS' ../config.h > /dev/null ; then
+ :
+else
+ echo "Compression or decompression support is disabled, skipping this test."
+ exit 77
+fi
+
+# Find out if our shell supports functions.
+eval 'unset foo ; foo() { return 42; } ; foo'
+if test $? != 42 ; then
+ echo "/bin/sh doesn't support functions, skipping this test."
+ exit 77
+fi
+
+test_xz() {
+ if $XZ -c "$@" "$FILE" > "$TMP_COMP"; then
+ :
+ else
+ echo "Compressing failed: $* $FILE"
+ exit 1
+ fi
+
+ if $XZ -cd "$TMP_COMP" > "$TMP_UNCOMP" ; then
+ :
+ else
+ echo "Decompressing failed: $* $FILE"
+ exit 1
+ fi
+
+ if cmp "$TMP_UNCOMP" "$FILE" ; then
+ :
+ else
+ echo "Decompressed file does not match" \
+ "the original: $* $FILE"
+ exit 1
+ fi
+
+ if test -n "$XZDEC" ; then
+ if $XZDEC "$TMP_COMP" > "$TMP_UNCOMP" ; then
+ :
+ else
+ echo "Decompressing failed: $* $FILE"
+ exit 1
+ fi
+
+ if cmp "$TMP_UNCOMP" "$FILE" ; then
+ :
+ else
+ echo "Decompressed file does not match" \
+ "the original: $* $FILE"
+ exit 1
+ fi
+ fi
+}
+
+XZ="../src/xz/xz --memlimit-compress=48MiB --memlimit-decompress=5MiB \
+ --no-adjust --threads=1 --check=crc32"
+grep "define HAVE_CHECK_CRC64" ../config.h > /dev/null \
+ && XZ="$XZ --check=crc64"
+XZDEC="../src/xzdec/xzdec" # No memory usage limiter available
+test -x ../src/xzdec/xzdec || XZDEC=
+
+# Create the required input file if needed.
+#
+# Derive temporary filenames for compressed and uncompressed outputs
+# from the input filename. This is needed when multiple tests are
+# run in parallel.
+FILE=$1
+TMP_COMP="tmp_comp_$FILE"
+TMP_UNCOMP="tmp_uncomp_$FILE"
+
+case $FILE in
+ # compress_generated files will be created in the build directory
+ # in the /tests/ sub-directory.
+ compress_generated_*)
+ if ./create_compress_files "$FILE" ; then
+ :
+ else
+ rm -f "$FILE"
+ echo "Failed to create the file '$FILE'."
+ exit 1
+ fi
+ ;;
+ # compress_prepared files exist in the source directory since they
+ # do not need to be copied or regenerated.
+ compress_prepared_*)
+ FILE="$srcdir/$FILE"
+ ;;
+ '')
+ echo "No test file was specified."
+ exit 1
+ ;;
+esac
+
+# Remove temporary now (in case they are something weird), and on exit.
+rm -f "$TMP_COMP" "$TMP_UNCOMP"
+trap 'rm -f "$TMP_COMP" "$TMP_UNCOMP"' 0
+
+# Compress and decompress the file with various filter configurations.
+#
+# Don't test with empty arguments; it breaks some ancient
+# proprietary /bin/sh versions due to $@ used in test_xz().
+test_xz -1
+test_xz -2
+test_xz -3
+test_xz -4
+
+test_filter()
+{
+ grep "define HAVE_ENCODER_$1 1" ../config.h > /dev/null || return
+ grep "define HAVE_DECODER_$1 1" ../config.h > /dev/null || return
+ shift
+ test_xz "$@" --lzma2=dict=64KiB,nice=32,mode=fast
+}
+
+test_filter DELTA --delta=dist=1
+test_filter DELTA --delta=dist=4
+test_filter DELTA --delta=dist=256
+test_filter X86 --x86
+test_filter POWERPC --power
+test_filter IA64 --ia64
+test_filter ARM --arm
+test_filter ARMTHUMB --armthumb
+test_filter ARM64 --arm64
+test_filter SPARC --sparc
+
+exit 0
diff --git a/tests/test_compress_generated_abc b/tests/test_compress_generated_abc
new file mode 100755
index 0000000..43c6951
--- /dev/null
+++ b/tests/test_compress_generated_abc
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exec "$srcdir/test_compress.sh" compress_generated_abc
diff --git a/tests/test_compress_generated_random b/tests/test_compress_generated_random
new file mode 100755
index 0000000..e47555d
--- /dev/null
+++ b/tests/test_compress_generated_random
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exec "$srcdir/test_compress.sh" compress_generated_random
diff --git a/tests/test_compress_generated_text b/tests/test_compress_generated_text
new file mode 100755
index 0000000..412ae0e
--- /dev/null
+++ b/tests/test_compress_generated_text
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exec "$srcdir/test_compress.sh" compress_generated_text
diff --git a/tests/test_compress_prepared_bcj_sparc b/tests/test_compress_prepared_bcj_sparc
new file mode 100755
index 0000000..deb76ef
--- /dev/null
+++ b/tests/test_compress_prepared_bcj_sparc
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exec "$srcdir/test_compress.sh" compress_prepared_bcj_sparc
diff --git a/tests/test_compress_prepared_bcj_x86 b/tests/test_compress_prepared_bcj_x86
new file mode 100755
index 0000000..3452d7f
--- /dev/null
+++ b/tests/test_compress_prepared_bcj_x86
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exec "$srcdir/test_compress.sh" compress_prepared_bcj_x86
diff --git a/tests/test_files.sh b/tests/test_files.sh
new file mode 100755
index 0000000..60402e7
--- /dev/null
+++ b/tests/test_files.sh
@@ -0,0 +1,197 @@
+#!/bin/sh
+
+###############################################################################
+#
+# Author: Lasse Collin
+#
+# This file has been put into the public domain.
+# You can do whatever you want with this file.
+#
+###############################################################################
+
+# If both xz and xzdec were not build, skip this test.
+XZ=../src/xz/xz
+XZDEC=../src/xzdec/xzdec
+test -x "$XZ" || XZ=
+test -x "$XZDEC" || XZDEC=
+if test -z "$XZ$XZDEC"; then
+ echo "xz and xzdec were not built, skipping this test."
+ exit 77
+fi
+
+# If decompression support is missing, this test is skipped.
+# This isn't perfect as if only some decompressors are disabled
+# then some good files might not decompress and the test fails
+# for a (kind of) wrong reason.
+if grep 'define HAVE_DECODERS' ../config.h > /dev/null ; then
+ :
+else
+ echo "Decompression support is disabled, skipping this test."
+ exit 77
+fi
+
+# If a feature was disabled at build time, make it possible to skip
+# some of the test files. Use exit status 77 if any files were skipped.
+EXIT_STATUS=0
+have_feature()
+{
+ grep "define HAVE_$1 1" ../config.h > /dev/null && return 0
+ printf '%s: Skipping because HAVE_%s is not enabled\n' "$2" "$1"
+ EXIT_STATUS=77
+ return 1
+}
+
+
+#######
+# .xz #
+#######
+
+# If these integrity check types were disabled at build time,
+# allow the tests to pass still.
+NO_WARN=
+grep 'define HAVE_CHECK_CRC64' ../config.h > /dev/null || NO_WARN=-qQ
+grep 'define HAVE_CHECK_SHA256' ../config.h > /dev/null || NO_WARN=-qQ
+
+for I in "$srcdir"/files/good-*.xz
+do
+ # If features were disabled at build time, keep this still working.
+ case $I in
+ */good-1-*delta-lzma2*.xz)
+ have_feature DECODER_DELTA "$I" || continue
+ ;;
+ esac
+ case $I in
+ */good-1-empty-bcj-lzma2.xz)
+ have_feature DECODER_POWERPC "$I" || continue
+ ;;
+ esac
+ case $I in
+ */good-1-sparc-lzma2.xz)
+ have_feature DECODER_SPARC "$I" || continue
+ ;;
+ esac
+ case $I in
+ */good-1-x86-lzma2.xz)
+ have_feature DECODER_X86 "$I" || continue
+ ;;
+ esac
+ case $I in
+ */good-1-arm64-lzma2-*.xz)
+ have_feature DECODER_ARM64 "$I" || continue
+ ;;
+ esac
+
+ if test -z "$XZ" || "$XZ" $NO_WARN -dc "$I" > /dev/null; then
+ :
+ else
+ echo "Good file failed: $I"
+ exit 1
+ fi
+
+ if test -z "$XZDEC" || "$XZDEC" $NO_WARN "$I" > /dev/null; then
+ :
+ else
+ echo "Good file failed: $I"
+ exit 1
+ fi
+done
+
+for I in "$srcdir"/files/bad-*.xz
+do
+ if test -n "$XZ" && "$XZ" -dc "$I" > /dev/null 2>&1; then
+ echo "Bad file succeeded: $I"
+ exit 1
+ fi
+
+ # xzdec doesn't warn about unsupported check so skip this if any of
+ # the check types were disabled at built time (NO_WARN isn't empty).
+ if test -n "$XZDEC" && test -z "$NO_WARN" \
+ && "$XZDEC" "$I" > /dev/null 2>&1; then
+ echo "Bad file succeeded: $I"
+ exit 1
+ fi
+done
+
+# Testing for the lzma_index_append() bug in <= 5.2.6 needs "xz -l":
+I="$srcdir/files/bad-3-index-uncomp-overflow.xz"
+if test -n "$XZ" && "$XZ" -l "$I" > /dev/null 2>&1; then
+ echo "Bad file succeeded with xz -l: $I"
+ exit 1
+fi
+
+for I in "$srcdir"/files/unsupported-*.xz
+do
+ # Test these only with xz as unsupported-check.xz will exit
+ # successfully with xzdec because it doesn't warn about
+ # unsupported check type.
+ if test -n "$XZ" && "$XZ" -dc "$I" > /dev/null 2>&1; then
+ echo "Unsupported file succeeded: $I"
+ exit 1
+ fi
+done
+
+# Test that this passes with --no-warn (-Q).
+I="$srcdir/files/unsupported-check.xz"
+if test -z "$XZ" || "$XZ" -dcqQ "$I" > /dev/null; then
+ :
+else
+ echo "Unsupported file failed with xz -Q: $I"
+ exit 1
+fi
+
+if test -z "$XZDEC" || "$XZDEC" -qQ "$I" > /dev/null; then
+ :
+else
+ echo "Unsupported file failed with xzdec -Q: $I"
+ exit 1
+fi
+
+
+#########
+# .lzma #
+#########
+
+for I in "$srcdir"/files/good-*.lzma
+do
+ if test -z "$XZ" || "$XZ" -dc "$I" > /dev/null; then
+ :
+ else
+ echo "Good file failed: $I"
+ exit 1
+ fi
+done
+
+for I in "$srcdir"/files/bad-*.lzma
+do
+ if test -n "$XZ" && "$XZ" -dc "$I" > /dev/null 2>&1; then
+ echo "Bad file succeeded: $I"
+ exit 1
+ fi
+done
+
+
+#######
+# .lz #
+#######
+
+if have_feature LZIP_DECODER ".lz files" ; then
+ for I in "$srcdir"/files/good-*.lz
+ do
+ if test -z "$XZ" || "$XZ" -dc "$I" > /dev/null; then
+ :
+ else
+ echo "Good file failed: $I"
+ exit 1
+ fi
+ done
+
+ for I in "$srcdir"/files/bad-*.lz "$srcdir"/files/unsupported-*.lz
+ do
+ if test -n "$XZ" && "$XZ" -dc "$I" > /dev/null 2>&1; then
+ echo "Bad file succeeded: $I"
+ exit 1
+ fi
+ done
+fi
+
+exit "$EXIT_STATUS"
diff --git a/tests/test_filter_flags.c b/tests/test_filter_flags.c
new file mode 100644
index 0000000..6d9f0b9
--- /dev/null
+++ b/tests/test_filter_flags.c
@@ -0,0 +1,527 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file test_filter_flags.c
+/// \brief Tests Filter Flags coders
+//
+// Authors: Jia Tan
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tests.h"
+
+// FIXME: This is from src/liblzma/common/common.h but it cannot be
+// included here. This constant is needed in only a few files, perhaps
+// move it to some other internal header or create a new one?
+#define LZMA_FILTER_RESERVED_START (LZMA_VLI_C(1) << 62)
+
+
+#if defined(HAVE_ENCODERS)
+// No tests are run without encoders, so init the global filters
+// only when the encoders are enabled.
+static lzma_filter lzma1_filter = { LZMA_FILTER_LZMA1, NULL };
+static lzma_filter lzma2_filter = { LZMA_FILTER_LZMA2, NULL };
+static lzma_filter delta_filter = { LZMA_FILTER_DELTA, NULL };
+
+static lzma_filter bcj_filters_encoders[] = {
+#ifdef HAVE_ENCODER_X86
+ { LZMA_FILTER_X86, NULL },
+#endif
+#ifdef HAVE_ENCODER_POWERPC
+ { LZMA_FILTER_POWERPC, NULL },
+#endif
+#ifdef HAVE_ENCODER_IA64
+ { LZMA_FILTER_IA64, NULL },
+#endif
+#ifdef HAVE_ENCODER_ARM
+ { LZMA_FILTER_ARM, NULL },
+#endif
+#ifdef HAVE_ENCODER_ARM64
+ { LZMA_FILTER_ARM64, NULL },
+#endif
+#ifdef HAVE_ENCODER_ARMTHUMB
+ { LZMA_FILTER_ARMTHUMB, NULL },
+#endif
+#ifdef HAVE_ENCODER_SPARC
+ { LZMA_FILTER_SPARC, NULL },
+#endif
+};
+
+// HAVE_ENCODERS ifdef not terminated here because decoders are
+// only used if encoders are, but encoders can still be used
+// even if decoders are not.
+
+#ifdef HAVE_DECODERS
+static lzma_filter bcj_filters_decoders[] = {
+#ifdef HAVE_DECODER_X86
+ { LZMA_FILTER_X86, NULL },
+#endif
+#ifdef HAVE_DECODER_POWERPC
+ { LZMA_FILTER_POWERPC, NULL },
+#endif
+#ifdef HAVE_DECODER_IA64
+ { LZMA_FILTER_IA64, NULL },
+#endif
+#ifdef HAVE_DECODER_ARM
+ { LZMA_FILTER_ARM, NULL },
+#endif
+#ifdef HAVE_DECODER_ARM64
+ { LZMA_FILTER_ARM64, NULL },
+#endif
+#ifdef HAVE_DECODER_ARMTHUMB
+ { LZMA_FILTER_ARMTHUMB, NULL },
+#endif
+#ifdef HAVE_DECODER_SPARC
+ { LZMA_FILTER_SPARC, NULL },
+#endif
+};
+#endif
+#endif
+
+
+static void
+test_lzma_filter_flags_size(void)
+{
+#ifndef HAVE_ENCODERS
+ assert_skip("Encoder support disabled");
+#else
+ // For each supported filter, test that the size can be calculated
+ // and that the size calculated is reasonable. A reasonable size
+ // must be greater than 0, but less than the maximum size for the
+ // block header.
+ uint32_t size = 0;
+ if (lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA1)) {
+ assert_lzma_ret(lzma_filter_flags_size(&size,
+ &lzma1_filter), LZMA_PROG_ERROR);
+ }
+
+ if (lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA2)) {
+ assert_lzma_ret(lzma_filter_flags_size(&size,
+ &lzma2_filter), LZMA_OK);
+ assert_true(size != 0 && size < LZMA_BLOCK_HEADER_SIZE_MAX);
+ }
+
+ // Do not use macro ARRAY_SIZE() in the for loop condition directly.
+ // If the BCJ filters are not configured and built, then ARRAY_SIZE()
+ // will return 0 and cause a warning because the for loop will never
+ // execute since any unsigned number cannot be < 0 (-Werror=type-limits).
+ const uint32_t bcj_array_size = ARRAY_SIZE(bcj_filters_encoders);
+ for (uint32_t i = 0; i < bcj_array_size; i++) {
+ assert_lzma_ret(lzma_filter_flags_size(&size,
+ &bcj_filters_encoders[i]), LZMA_OK);
+ assert_true(size != 0 && size < LZMA_BLOCK_HEADER_SIZE_MAX);
+ }
+
+ if (lzma_filter_encoder_is_supported(LZMA_FILTER_DELTA)) {
+ assert_lzma_ret(lzma_filter_flags_size(&size,
+ &delta_filter), LZMA_OK);
+ assert_true(size != 0 && size < LZMA_BLOCK_HEADER_SIZE_MAX);
+ }
+
+ // Test invalid Filter IDs
+ lzma_filter bad_filter = { 2, NULL };
+
+ assert_lzma_ret(lzma_filter_flags_size(&size, &bad_filter),
+ LZMA_OPTIONS_ERROR);
+ bad_filter.id = LZMA_VLI_MAX;
+ assert_lzma_ret(lzma_filter_flags_size(&size, &bad_filter),
+ LZMA_PROG_ERROR);
+ bad_filter.id = LZMA_FILTER_RESERVED_START;
+ assert_lzma_ret(lzma_filter_flags_size(&size, &bad_filter),
+ LZMA_PROG_ERROR);
+#endif
+}
+
+
+// Helper function for test_lzma_filter_flags_encode.
+// The should_encode parameter represents if the encoding operation
+// is expected to fail.
+// Avoid data -> encode -> decode -> compare to data.
+// Instead create expected encoding and compare to result from
+// lzma_filter_flags_encode.
+// Filter Flags in .xz are encoded as:
+// |Filter ID (VLI)|Size of Properties (VLI)|Filter Properties|
+#if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
+static void
+verify_filter_flags_encode(lzma_filter *filter, bool should_encode)
+{
+ uint32_t size = 0;
+
+ // First calculate the size of Filter Flags to know how much
+ // memory to allocate to hold the encoded Filter Flags
+ assert_lzma_ret(lzma_filter_flags_size(&size, filter), LZMA_OK);
+ uint8_t *encoded_out = tuktest_malloc(size * sizeof(uint8_t));
+ size_t out_pos = 0;
+ if (!should_encode) {
+ assert_false(lzma_filter_flags_encode(filter, encoded_out,
+ &out_pos, size) == LZMA_OK);
+ return;
+ }
+
+ // Next encode the Filter Flags for the provided filter
+ assert_lzma_ret(lzma_filter_flags_encode(filter, encoded_out,
+ &out_pos, size), LZMA_OK);
+ assert_uint_eq(size, out_pos);
+
+ // Next decode the VLI for the Filter ID and verify it matches
+ // the expected Filter ID
+ size_t filter_id_vli_size = 0;
+ lzma_vli filter_id = 0;
+ assert_lzma_ret(lzma_vli_decode(&filter_id, NULL, encoded_out,
+ &filter_id_vli_size, size), LZMA_OK);
+ assert_uint_eq(filter->id, filter_id);
+
+ // Next decode the Size of Properties and ensure it equals
+ // the expected size.
+ // Expected size should be:
+ // total filter flag length - size of filter id VLI + size of
+ // property size VLI
+ // Not verifying the contents of Filter Properties since
+ // that belongs in a different test
+ size_t size_of_properties_vli_size = 0;
+ lzma_vli size_of_properties = 0;
+ assert_lzma_ret(lzma_vli_decode(&size_of_properties, NULL,
+ encoded_out + filter_id_vli_size,
+ &size_of_properties_vli_size, size), LZMA_OK);
+ assert_uint_eq(size - (size_of_properties_vli_size +
+ filter_id_vli_size), size_of_properties);
+}
+#endif
+
+
+static void
+test_lzma_filter_flags_encode(void)
+{
+#if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
+ assert_skip("Encoder or decoder support disabled");
+#else
+ // No test for LZMA1 since the .xz format does not support LZMA1
+ // and so the flags cannot be encoded for that filter
+ if (lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA2)) {
+ // Test with NULL options that should fail
+ lzma_options_lzma *options = lzma2_filter.options;
+ lzma2_filter.options = NULL;
+ verify_filter_flags_encode(&lzma2_filter, false);
+
+ // Place options back in the filter, and test should pass
+ lzma2_filter.options = options;
+ verify_filter_flags_encode(&lzma2_filter, true);
+ }
+
+ // NOTE: Many BCJ filters require that start_offset is a multiple
+ // of some power of two. The Filter Flags encoder and decoder don't
+ // completely validate the options and thus 257 passes the tests
+ // with all BCJ filters. It would be caught when initializing
+ // a filter chain encoder or decoder.
+ lzma_options_bcj bcj_options = {
+ .start_offset = 257
+ };
+
+ const uint32_t bcj_array_size = ARRAY_SIZE(bcj_filters_encoders);
+ for (uint32_t i = 0; i < bcj_array_size; i++) {
+ // NULL options should pass for bcj filters
+ verify_filter_flags_encode(&bcj_filters_encoders[i], true);
+ lzma_filter bcj_with_options = {
+ bcj_filters_encoders[i].id, &bcj_options };
+ verify_filter_flags_encode(&bcj_with_options, true);
+ }
+
+ if (lzma_filter_encoder_is_supported(LZMA_FILTER_DELTA)) {
+ lzma_options_delta delta_opts_below_min = {
+ .type = LZMA_DELTA_TYPE_BYTE,
+ .dist = LZMA_DELTA_DIST_MIN - 1
+ };
+
+ lzma_options_delta delta_opts_above_max = {
+ .type = LZMA_DELTA_TYPE_BYTE,
+ .dist = LZMA_DELTA_DIST_MAX + 1
+ };
+
+ verify_filter_flags_encode(&delta_filter, true);
+
+ lzma_filter delta_filter_bad_options = {
+ LZMA_FILTER_DELTA, &delta_opts_below_min };
+
+ // Next test error case using minimum - 1 delta distance
+ verify_filter_flags_encode(&delta_filter_bad_options, false);
+
+ // Next test error case using maximum + 1 delta distance
+ delta_filter_bad_options.options = &delta_opts_above_max;
+ verify_filter_flags_encode(&delta_filter_bad_options, false);
+
+ // Next test NULL case
+ delta_filter_bad_options.options = NULL;
+ verify_filter_flags_encode(&delta_filter_bad_options, false);
+ }
+
+ // Test expected failing cases
+ lzma_filter bad_filter = { LZMA_FILTER_RESERVED_START, NULL };
+ size_t out_pos = 0;
+ size_t out_size = LZMA_BLOCK_HEADER_SIZE_MAX;
+ uint8_t out[LZMA_BLOCK_HEADER_SIZE_MAX];
+
+
+ // Filter ID outside of valid range
+ assert_lzma_ret(lzma_filter_flags_encode(&bad_filter, out, &out_pos,
+ out_size), LZMA_PROG_ERROR);
+ out_pos = 0;
+ bad_filter.id = LZMA_VLI_MAX + 1;
+ assert_lzma_ret(lzma_filter_flags_encode(&bad_filter, out, &out_pos,
+ out_size), LZMA_PROG_ERROR);
+ out_pos = 0;
+
+ // Invalid Filter ID
+ bad_filter.id = 2;
+ assert_lzma_ret(lzma_filter_flags_encode(&bad_filter, out, &out_pos,
+ out_size), LZMA_OPTIONS_ERROR);
+ out_pos = 0;
+
+ // Out size too small
+ if (lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA2)) {
+ uint32_t bad_size = 0;
+
+ // First test with 0 output size
+ assert_lzma_ret(lzma_filter_flags_encode(
+ &lzma2_filter, out, &out_pos, 0),
+ LZMA_PROG_ERROR);
+
+ // Next calculate the size needed to encode and
+ // use less than that
+ assert_lzma_ret(lzma_filter_flags_size(&bad_size,
+ &lzma2_filter), LZMA_OK);
+
+ assert_lzma_ret(lzma_filter_flags_encode(
+ &lzma2_filter, out, &out_pos,
+ bad_size - 1), LZMA_PROG_ERROR);
+ out_pos = 0;
+ }
+
+ // Invalid options
+ if (lzma_filter_encoder_is_supported(LZMA_FILTER_DELTA)) {
+ bad_filter.id = LZMA_FILTER_DELTA;
+
+ // First test with NULL options
+ assert_lzma_ret(lzma_filter_flags_encode(&bad_filter, out,
+ &out_pos, out_size), LZMA_PROG_ERROR);
+ out_pos = 0;
+
+ // Next test with invalid options
+ lzma_options_delta bad_options = {
+ .dist = LZMA_DELTA_DIST_MAX + 1,
+ .type = LZMA_DELTA_TYPE_BYTE
+ };
+ bad_filter.options = &bad_options;
+
+ assert_lzma_ret(lzma_filter_flags_encode(&bad_filter, out,
+ &out_pos, out_size), LZMA_PROG_ERROR);
+ }
+#endif
+}
+
+
+// Helper function for test_lzma_filter_flags_decode.
+// Encodes the filter_in without using lzma_filter_flags_encode.
+// Leaves the specific assertions of filter_out options to the caller
+// because it is agnostic to the type of options used in the call
+#if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
+static void
+verify_filter_flags_decode(lzma_filter *filter_in, lzma_filter *filter_out)
+{
+ uint32_t total_size = 0;
+
+ assert_lzma_ret(lzma_filter_flags_size(&total_size, filter_in),
+ LZMA_OK);
+ assert_uint(total_size, >, 0);
+ uint8_t *filter_flag_buffer = tuktest_malloc(total_size);
+
+ uint32_t properties_size = 0;
+ size_t out_pos = 0;
+ size_t in_pos = 0;
+ assert_lzma_ret(lzma_properties_size(&properties_size, filter_in),
+ LZMA_OK);
+ assert_lzma_ret(lzma_vli_encode(filter_in->id, NULL,
+ filter_flag_buffer, &out_pos, total_size), LZMA_OK);
+ assert_lzma_ret(lzma_vli_encode(properties_size, NULL,
+ filter_flag_buffer, &out_pos, total_size),
+ LZMA_OK);
+ assert_lzma_ret(lzma_properties_encode(filter_in,
+ filter_flag_buffer + out_pos), LZMA_OK);
+ assert_lzma_ret(lzma_filter_flags_decode(filter_out, NULL,
+ filter_flag_buffer, &in_pos, total_size),
+ LZMA_OK);
+ assert_uint_eq(filter_in->id, filter_out->id);
+}
+#endif
+
+
+static void
+test_lzma_filter_flags_decode(void)
+{
+#if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
+ assert_skip("Encoder or decoder support disabled");
+#else
+ // For each filter, only run the decoder test if both the encoder
+ // and decoder are enabled. This is because verify_filter_flags_decode
+ // uses lzma_filter_flags_size which requires the encoder.
+ if (lzma_filter_decoder_is_supported(LZMA_FILTER_LZMA2) &&
+ lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA2)) {
+ lzma_filter lzma2_decoded = { LZMA_FILTER_LZMA2, NULL };
+
+ verify_filter_flags_decode(&lzma2_filter, &lzma2_decoded);
+
+ lzma_options_lzma *expected = lzma2_filter.options;
+ lzma_options_lzma *decoded = lzma2_decoded.options;
+
+ // Only the dictionary size is encoded and decoded
+ // so only compare those
+ assert_uint_eq(decoded->dict_size, expected->dict_size);
+
+ // The decoded options must be freed by the caller
+ free(decoded);
+ }
+
+ const uint32_t bcj_array_size = ARRAY_SIZE(bcj_filters_decoders);
+ for (uint32_t i = 0; i < bcj_array_size; i++) {
+ if (lzma_filter_encoder_is_supported(
+ bcj_filters_decoders[i].id)) {
+ lzma_filter bcj_decoded = {
+ bcj_filters_decoders[i].id, NULL };
+
+ lzma_filter bcj_encoded = {
+ bcj_filters_decoders[i].id, NULL };
+
+ // First test without options
+ verify_filter_flags_decode(&bcj_encoded,
+ &bcj_decoded);
+ assert_true(bcj_decoded.options == NULL);
+
+ // Next test with offset
+ lzma_options_bcj options = {
+ .start_offset = 257
+ };
+
+ bcj_encoded.options = &options;
+ verify_filter_flags_decode(&bcj_encoded,
+ &bcj_decoded);
+ lzma_options_bcj *decoded_opts = bcj_decoded.options;
+ assert_uint_eq(decoded_opts->start_offset,
+ options.start_offset);
+ free(decoded_opts);
+ }
+ }
+
+ if (lzma_filter_decoder_is_supported(LZMA_FILTER_DELTA) &&
+ lzma_filter_encoder_is_supported(LZMA_FILTER_DELTA)) {
+ lzma_filter delta_decoded = { LZMA_FILTER_DELTA, NULL };
+
+ verify_filter_flags_decode(&delta_filter, &delta_decoded);
+ lzma_options_delta *expected = delta_filter.options;
+ lzma_options_delta *decoded = delta_decoded.options;
+ assert_uint_eq(expected->dist, decoded->dist);
+ assert_uint_eq(expected->type, decoded->type);
+
+ free(decoded);
+ }
+
+ // Test expected failing cases
+ uint8_t bad_encoded_filter[LZMA_BLOCK_HEADER_SIZE_MAX];
+ lzma_filter bad_filter;
+
+ // Filter ID outside of valid range
+ lzma_vli bad_filter_id = LZMA_FILTER_RESERVED_START;
+ size_t bad_encoded_out_pos = 0;
+ size_t in_pos = 0;
+
+ assert_lzma_ret(lzma_vli_encode(bad_filter_id, NULL,
+ bad_encoded_filter, &bad_encoded_out_pos,
+ LZMA_BLOCK_HEADER_SIZE_MAX), LZMA_OK);
+
+ assert_lzma_ret(lzma_filter_flags_decode(&bad_filter, NULL,
+ bad_encoded_filter, &in_pos,
+ LZMA_BLOCK_HEADER_SIZE_MAX), LZMA_DATA_ERROR);
+
+ bad_encoded_out_pos = 0;
+ in_pos = 0;
+
+ // Invalid Filter ID
+ bad_filter_id = 2;
+ bad_encoded_out_pos = 0;
+ in_pos = 0;
+
+ assert_lzma_ret(lzma_vli_encode(bad_filter_id, NULL,
+ bad_encoded_filter, &bad_encoded_out_pos,
+ LZMA_BLOCK_HEADER_SIZE_MAX), LZMA_OK);
+
+ // Next encode Size of Properties with the value of 0
+ assert_lzma_ret(lzma_vli_encode(0, NULL,
+ bad_encoded_filter, &bad_encoded_out_pos,
+ LZMA_BLOCK_HEADER_SIZE_MAX), LZMA_OK);
+
+ // Decode should fail on bad Filter ID
+ assert_lzma_ret(lzma_filter_flags_decode(&bad_filter, NULL,
+ bad_encoded_filter, &in_pos,
+ LZMA_BLOCK_HEADER_SIZE_MAX), LZMA_OPTIONS_ERROR);
+ bad_encoded_out_pos = 0;
+ in_pos = 0;
+
+ // Outsize too small
+ // Encode the LZMA2 filter normally, but then set
+ // the out size when decoding as too small
+ if (lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA2) &&
+ lzma_filter_decoder_is_supported(LZMA_FILTER_LZMA2)) {
+ uint32_t filter_flag_size = 0;
+ assert_lzma_ret(lzma_filter_flags_size(&filter_flag_size,
+ &lzma2_filter), LZMA_OK);
+
+ assert_lzma_ret(lzma_filter_flags_encode(&lzma2_filter,
+ bad_encoded_filter, &bad_encoded_out_pos,
+ LZMA_BLOCK_HEADER_SIZE_MAX), LZMA_OK);
+
+ assert_lzma_ret(lzma_filter_flags_decode(&bad_filter, NULL,
+ bad_encoded_filter, &in_pos,
+ filter_flag_size - 1), LZMA_DATA_ERROR);
+ }
+#endif
+}
+
+
+extern int
+main(int argc, char **argv)
+{
+ tuktest_start(argc, argv);
+
+#ifdef HAVE_ENCODERS
+ // Only init filter options if encoder is supported because decoder
+ // tests requires encoder support, so the decoder tests will only
+ // run if for a given filter both the encoder and decoder are enabled.
+ if (lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA1)) {
+ lzma_options_lzma *options = tuktest_malloc(
+ sizeof(lzma_options_lzma));
+ lzma_lzma_preset(options, LZMA_PRESET_DEFAULT);
+ lzma1_filter.options = options;
+ }
+
+ if (lzma_filter_encoder_is_supported(LZMA_FILTER_LZMA2)) {
+ lzma_options_lzma *options = tuktest_malloc(
+ sizeof(lzma_options_lzma));
+ lzma_lzma_preset(options, LZMA_PRESET_DEFAULT);
+ lzma2_filter.options = options;
+ }
+
+ if (lzma_filter_encoder_is_supported(LZMA_FILTER_DELTA)) {
+ lzma_options_delta *options = tuktest_malloc(
+ sizeof(lzma_options_delta));
+ options->dist = LZMA_DELTA_DIST_MIN;
+ options->type = LZMA_DELTA_TYPE_BYTE;
+ delta_filter.options = options;
+ }
+#endif
+
+ tuktest_run(test_lzma_filter_flags_size);
+ tuktest_run(test_lzma_filter_flags_encode);
+ tuktest_run(test_lzma_filter_flags_decode);
+ return tuktest_end();
+}
diff --git a/tests/test_filter_str.c b/tests/test_filter_str.c
new file mode 100644
index 0000000..15aee55
--- /dev/null
+++ b/tests/test_filter_str.c
@@ -0,0 +1,593 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file test_filter_str.c
+/// \brief Tests Filter string functions
+//
+// Author: Jia Tan
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tests.h"
+
+
+static void
+test_lzma_str_to_filters(void)
+{
+ lzma_filter filters[LZMA_FILTERS_MAX + 1];
+ int error_pos;
+
+ // Test with NULL string.
+ assert_true(lzma_str_to_filters(NULL, &error_pos, filters, 0,
+ NULL) != NULL);
+
+ // Test with NULL filter array.
+ assert_true(lzma_str_to_filters("lzma2", &error_pos, NULL, 0,
+ NULL) != NULL);
+
+ // Test with unsupported flags.
+ assert_true(lzma_str_to_filters("lzma2", &error_pos, filters,
+ UINT32_MAX, NULL) != NULL);
+
+ assert_true(lzma_str_to_filters("lzma2", &error_pos, filters,
+ LZMA_STR_NO_SPACES << 1, NULL) != NULL);
+
+ assert_true(lzma_str_to_filters("lzma2", &error_pos, filters,
+ LZMA_STR_NO_SPACES, NULL) != NULL);
+
+ // Test with empty string.
+ assert_true(lzma_str_to_filters("", &error_pos,
+ filters, 0, NULL) != NULL);
+ assert_int_eq(error_pos, 0);
+
+ // Test with invalid filter name and missing filter name.
+ assert_true(lzma_str_to_filters("lzma2 abcd", &error_pos,
+ filters, 0, NULL) != NULL);
+ assert_int_eq(error_pos, 6);
+
+ assert_true(lzma_str_to_filters("lzma2--abcd", &error_pos,
+ filters, 0, NULL) != NULL);
+ assert_int_eq(error_pos, 7);
+
+ assert_true(lzma_str_to_filters("lzma2--", &error_pos,
+ filters, 0, NULL) != NULL);
+ assert_int_eq(error_pos, 7);
+
+ // Test LZMA_STR_ALL_FILTERS flag (should work with LZMA1 if built).
+#if defined(HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1)
+ // Using LZMA1 as a Filter should fail without LZMA_STR_ALL_FILTERS.
+ assert_true(lzma_str_to_filters("lzma1", &error_pos, filters,
+ 0, NULL) != NULL);
+ assert_int_eq(error_pos, 0);
+
+ assert_true(lzma_str_to_filters("lzma1", &error_pos, filters,
+ LZMA_STR_ALL_FILTERS, NULL) == NULL);
+
+ // Verify Filters array IDs are correct. The array should contain
+ // only two elements:
+ // 1. LZMA1 Filter
+ // 2. LZMA_VLI_UNKNOWN filter array terminator
+ assert_uint_eq(filters[0].id, LZMA_FILTER_LZMA1);
+ assert_uint_eq(filters[1].id, LZMA_VLI_UNKNOWN);
+
+ lzma_filters_free(filters, NULL);
+#endif
+
+ // Test LZMA_STR_NO_VALIDATION flag. This should allow having the
+ // same Filter multiple times in the chain and having a non-last
+ // Filter like lzma2 appear before another Filter.
+ // Without the flag, "lzma2 lzma2" must fail.
+ assert_true(lzma_str_to_filters("lzma2 lzma2", &error_pos, filters,
+ 0, NULL) != NULL);
+
+ assert_true(lzma_str_to_filters("lzma2 lzma2", &error_pos, filters,
+ LZMA_STR_NO_VALIDATION, NULL) == NULL);
+
+ assert_uint_eq(filters[0].id, LZMA_FILTER_LZMA2);
+ assert_uint_eq(filters[1].id, LZMA_FILTER_LZMA2);
+ assert_uint_eq(filters[2].id, LZMA_VLI_UNKNOWN);
+
+ lzma_filters_free(filters, NULL);
+
+ // Should fail with invalid Filter options (lc + lp must be <= 4).
+ assert_true(lzma_str_to_filters("lzma2:lc=3,lp=3", &error_pos, filters,
+ LZMA_STR_NO_VALIDATION, NULL) != NULL);
+
+ // Test invalid option name.
+ assert_true(lzma_str_to_filters("lzma2:foo=1,bar=2", &error_pos,
+ filters, 0, NULL) != NULL);
+ assert_int_eq(error_pos, 6);
+
+ // Test missing option value.
+ assert_true(lzma_str_to_filters("lzma2:lc=", &error_pos,
+ filters, 0, NULL) != NULL);
+ assert_int_eq(error_pos, 9);
+
+ assert_true(lzma_str_to_filters("lzma2:=,pb=1", &error_pos,
+ filters, 0, NULL) != NULL);
+ assert_int_eq(error_pos, 6);
+
+ // Test unsupported preset value.
+ assert_true(lzma_str_to_filters("-10", &error_pos,
+ filters, 0, NULL) != NULL);
+ assert_int_eq(error_pos, 2);
+
+ assert_true(lzma_str_to_filters("-5f", &error_pos,
+ filters, 0, NULL) != NULL);
+ assert_int_eq(error_pos, 2);
+
+ // Test filter chain too long.
+ assert_true(lzma_str_to_filters("lzma2 lzma2 lzma2 lzma2 lzma2",
+ &error_pos, filters, LZMA_STR_NO_VALIDATION,
+ NULL) != NULL);
+ assert_int_eq(error_pos, 24);
+
+#if defined(HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1)
+ // Should fail with a Filter not supported in the .xz format (lzma1).
+ assert_true(lzma_str_to_filters("lzma1", &error_pos, filters,
+ LZMA_STR_NO_VALIDATION, NULL) != NULL);
+#endif
+
+ // Test setting options with the "=" format.
+ assert_true(lzma_str_to_filters("lzma2=dict=4096,lc=2,lp=2,pb=1,"
+ "mode=fast,nice=3,mf=hc3,depth=10", &error_pos,
+ filters, 0, NULL) == NULL);
+ assert_uint_eq(filters[0].id, LZMA_FILTER_LZMA2);
+ assert_uint_eq(filters[1].id, LZMA_VLI_UNKNOWN);
+
+ lzma_options_lzma *opts = filters[0].options;
+ assert_uint_eq(opts->dict_size, 4096);
+ assert_uint_eq(opts->lc, 2);
+ assert_uint_eq(opts->lp, 2);
+ assert_uint_eq(opts->pb, 1);
+ assert_uint_eq(opts->mode, LZMA_MODE_FAST);
+ assert_uint_eq(opts->nice_len, 3);
+ assert_uint_eq(opts->mf, LZMA_MF_HC3);
+ assert_uint_eq(opts->depth, 10);
+
+ lzma_filters_free(filters, NULL);
+
+#if defined(HAVE_ENCODER_X86) || defined(HAVE_DECODER_X86)
+ // Test BCJ Filter options.
+ assert_true(lzma_str_to_filters("x86:start=16", &error_pos, filters,
+ LZMA_STR_NO_VALIDATION, NULL) == NULL);
+
+ assert_uint_eq(filters[0].id, LZMA_FILTER_X86);
+ assert_uint_eq(filters[1].id, LZMA_VLI_UNKNOWN);
+
+ lzma_options_bcj *bcj_opts = filters[0].options;
+ assert_uint_eq(bcj_opts->start_offset, 16);
+
+ lzma_filters_free(filters, NULL);
+#endif
+
+#if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
+ // Test Delta Filter options.
+ assert_true(lzma_str_to_filters("delta:dist=20", &error_pos, filters,
+ LZMA_STR_NO_VALIDATION, NULL) == NULL);
+
+ assert_uint_eq(filters[0].id, LZMA_FILTER_DELTA);
+ assert_uint_eq(filters[1].id, LZMA_VLI_UNKNOWN);
+
+ lzma_options_delta *delta_opts = filters[0].options;
+ assert_uint_eq(delta_opts->dist, 20);
+
+ lzma_filters_free(filters, NULL);
+#endif
+
+ // Test skipping leading spaces.
+ assert_true(lzma_str_to_filters(" lzma2", &error_pos, filters,
+ 0, NULL) == NULL);
+
+ assert_uint_eq(filters[0].id, LZMA_FILTER_LZMA2);
+ assert_uint_eq(filters[1].id, LZMA_VLI_UNKNOWN);
+
+ lzma_filters_free(filters, NULL);
+
+ // Test skipping trailing spaces.
+ assert_true(lzma_str_to_filters("lzma2 ", &error_pos, filters,
+ 0, NULL) == NULL);
+
+ assert_uint_eq(filters[0].id, LZMA_FILTER_LZMA2);
+ assert_uint_eq(filters[1].id, LZMA_VLI_UNKNOWN);
+
+ lzma_filters_free(filters, NULL);
+
+ // Test with "--" instead of space separating.
+ assert_true(lzma_str_to_filters("lzma2--lzma2", &error_pos, filters,
+ LZMA_STR_NO_VALIDATION, NULL) == NULL);
+
+ assert_uint_eq(filters[0].id, LZMA_FILTER_LZMA2);
+ assert_uint_eq(filters[1].id, LZMA_FILTER_LZMA2);
+ assert_uint_eq(filters[2].id, LZMA_VLI_UNKNOWN);
+
+ lzma_filters_free(filters, NULL);
+
+ // Test preset with and without leading "-", and with "e".
+ assert_true(lzma_str_to_filters("-3", &error_pos, filters,
+ 0, NULL) == NULL);
+
+ assert_uint_eq(filters[0].id, LZMA_FILTER_LZMA2);
+ assert_uint_eq(filters[1].id, LZMA_VLI_UNKNOWN);
+
+ lzma_filters_free(filters, NULL);
+
+ assert_true(lzma_str_to_filters("4", &error_pos, filters,
+ 0, NULL) == NULL);
+
+ assert_uint_eq(filters[0].id, LZMA_FILTER_LZMA2);
+ assert_uint_eq(filters[1].id, LZMA_VLI_UNKNOWN);
+
+ lzma_filters_free(filters, NULL);
+
+ assert_true(lzma_str_to_filters("9e", &error_pos, filters,
+ 0, NULL) == NULL);
+
+ assert_uint_eq(filters[0].id, LZMA_FILTER_LZMA2);
+ assert_uint_eq(filters[1].id, LZMA_VLI_UNKNOWN);
+
+ lzma_filters_free(filters, NULL);
+
+ // Test using a preset as an lzma2 option.
+ assert_true(lzma_str_to_filters("lzma2:preset=9e", &error_pos, filters,
+ 0, NULL) == NULL);
+
+ assert_uint_eq(filters[0].id, LZMA_FILTER_LZMA2);
+ assert_uint_eq(filters[1].id, LZMA_VLI_UNKNOWN);
+
+ lzma_filters_free(filters, NULL);
+
+ // Test setting dictionary size with invalid modifier suffix.
+ assert_true(lzma_str_to_filters("lzma2:dict=4096ZiB", &error_pos, filters,
+ 0, NULL) != NULL);
+
+ assert_true(lzma_str_to_filters("lzma2:dict=4096KiBs", &error_pos, filters,
+ 0, NULL) != NULL);
+
+ // Test option that cannot have multiplier modifier.
+ assert_true(lzma_str_to_filters("lzma2:pb=1k", &error_pos, filters,
+ 0, NULL) != NULL);
+
+ // Test option value too large.
+ assert_true(lzma_str_to_filters("lzma2:dict=4096GiB", &error_pos, filters,
+ 0, NULL) != NULL);
+
+ // Test valid uses of multiplier modifiers (k,m,g).
+ assert_true(lzma_str_to_filters("lzma2:dict=4096KiB", &error_pos, filters,
+ 0, NULL) == NULL);
+
+ assert_uint_eq(filters[0].id, LZMA_FILTER_LZMA2);
+ assert_uint_eq(filters[1].id, LZMA_VLI_UNKNOWN);
+
+ opts = filters[0].options;
+ assert_uint_eq(opts->dict_size, 4096 << 10);
+
+ lzma_filters_free(filters, NULL);
+
+ assert_true(lzma_str_to_filters("lzma2:dict=40Mi", &error_pos, filters,
+ 0, NULL) == NULL);
+
+ assert_uint_eq(filters[0].id, LZMA_FILTER_LZMA2);
+ assert_uint_eq(filters[1].id, LZMA_VLI_UNKNOWN);
+
+ opts = filters[0].options;
+ assert_uint_eq(opts->dict_size, 40 << 20);
+
+ lzma_filters_free(filters, NULL);
+
+ assert_true(lzma_str_to_filters("lzma2:dict=1g", &error_pos, filters,
+ 0, NULL) == NULL);
+
+ assert_uint_eq(filters[0].id, LZMA_FILTER_LZMA2);
+ assert_uint_eq(filters[1].id, LZMA_VLI_UNKNOWN);
+
+ opts = filters[0].options;
+ assert_uint_eq(opts->dict_size, 1 << 30);
+
+ lzma_filters_free(filters, NULL);
+}
+
+
+static void
+test_lzma_str_from_filters(void)
+{
+ lzma_filter filters[LZMA_FILTERS_MAX];
+ filters[0].id = LZMA_VLI_UNKNOWN;
+
+ char *output_str = NULL;
+
+ // Test basic NULL inputs.
+ assert_lzma_ret(lzma_str_from_filters(NULL, filters, 0, NULL),
+ LZMA_PROG_ERROR);
+
+ assert_lzma_ret(lzma_str_from_filters(&output_str, NULL, 0, NULL),
+ LZMA_PROG_ERROR);
+
+ // Test with empty filters array.
+ assert_lzma_ret(lzma_str_from_filters(&output_str, filters, 0, NULL),
+ LZMA_OPTIONS_ERROR);
+
+ // Create a simple filter array only containing an LZMA2 Filter.
+ assert_true(lzma_str_to_filters("lzma2", NULL, filters, 0, NULL)
+ == NULL);
+
+ // Test with bad flags.
+ assert_lzma_ret(lzma_str_from_filters(&output_str, filters,
+ LZMA_STR_ALL_FILTERS, NULL), LZMA_OPTIONS_ERROR);
+
+ assert_lzma_ret(lzma_str_from_filters(&output_str, filters,
+ LZMA_STR_NO_VALIDATION, NULL), LZMA_OPTIONS_ERROR);
+
+ // Test with no flags.
+ assert_lzma_ret(lzma_str_from_filters(&output_str, filters, 0, NULL),
+ LZMA_OK);
+
+ assert_str_eq(output_str, "lzma2");
+ free(output_str);
+
+ // Test LZMA_STR_ENCODER flag.
+ // Only the the return value is checked since the actual string
+ // may change in the future (even though it is unlikely).
+ // The order of options or the inclusion of new options could
+ // cause a change in output, so we will avoid hardcoding an
+ // expected result.
+ assert_lzma_ret(lzma_str_from_filters(&output_str, filters,
+ LZMA_STR_ENCODER, NULL), LZMA_OK);
+ free(output_str);
+
+ // Test LZMA_STR_DECODER flag.
+ assert_lzma_ret(lzma_str_from_filters(&output_str, filters,
+ LZMA_STR_DECODER, NULL), LZMA_OK);
+ free(output_str);
+
+ // Test LZMA_STR_GETOPT_LONG flag.
+ assert_lzma_ret(lzma_str_from_filters(&output_str, filters,
+ LZMA_STR_GETOPT_LONG, NULL), LZMA_OK);
+ free(output_str);
+
+ // Test LZMA_STR_NO_SPACES flag.
+ assert_lzma_ret(lzma_str_from_filters(&output_str, filters,
+ LZMA_STR_NO_SPACES, NULL), LZMA_OK);
+
+ // Check to be sure there are no spaces.
+ assert_true(strchr(output_str, ' ') == NULL);
+
+ free(output_str);
+
+ lzma_filters_free(filters, NULL);
+
+#if defined(HAVE_ENCODER_X86) || defined(HAVE_DECODER_X86)
+ assert_true(lzma_str_to_filters("x86 lzma2", NULL, filters, 0, NULL)
+ == NULL);
+
+ assert_lzma_ret(lzma_str_from_filters(&output_str, filters, 0, NULL),
+ LZMA_OK);
+
+ assert_str_eq(output_str, "x86 lzma2");
+
+ free(output_str);
+
+ // Test setting BCJ option to NULL.
+ assert_false(filters[0].options == NULL);
+ free(filters[0].options);
+
+ filters[0].options = NULL;
+
+ assert_lzma_ret(lzma_str_from_filters(&output_str, filters, 0, NULL),
+ LZMA_OK);
+
+ assert_str_eq(output_str, "x86 lzma2");
+
+ lzma_filters_free(filters, NULL);
+ free(output_str);
+#endif
+
+ lzma_options_lzma opts;
+ assert_false(lzma_lzma_preset(&opts, LZMA_PRESET_DEFAULT));
+ // Test with too many Filters (array terminated after 4+ filters).
+ lzma_filter oversized_filters[LZMA_FILTERS_MAX + 2];
+
+ for (uint32_t i = 0; i < ARRAY_SIZE(oversized_filters) - 1; i++) {
+ oversized_filters[i].id = LZMA_FILTER_LZMA2;
+ oversized_filters[i].options = &opts;
+ }
+
+ oversized_filters[LZMA_FILTERS_MAX + 1].id = LZMA_VLI_UNKNOWN;
+ oversized_filters[LZMA_FILTERS_MAX + 1].options = NULL;
+
+ assert_lzma_ret(lzma_str_from_filters(&output_str, oversized_filters,
+ 0, NULL), LZMA_OPTIONS_ERROR);
+
+ // Test with NULL filter options (when they cannot be NULL).
+ filters[0].id = LZMA_FILTER_LZMA2;
+ filters[0].options = NULL;
+ filters[1].id = LZMA_VLI_UNKNOWN;
+
+ assert_lzma_ret(lzma_str_from_filters(&output_str, filters,
+ LZMA_STR_ENCODER, NULL), LZMA_OPTIONS_ERROR);
+
+ // Test with bad Filter ID.
+ filters[0].id = LZMA_VLI_UNKNOWN - 1;
+ assert_lzma_ret(lzma_str_from_filters(&output_str, filters,
+ LZMA_STR_ENCODER, NULL), LZMA_OPTIONS_ERROR);
+}
+
+
+static const char supported_encoders[][9] = {
+ "lzma2",
+#ifdef HAVE_ENCODER_X86
+ "x86",
+#endif
+#ifdef HAVE_ENCODER_POWERPC
+ "powerpc",
+#endif
+#ifdef HAVE_ENCODER_IA64
+ "ia64",
+#endif
+#ifdef HAVE_ENCODER_ARM
+ "arm",
+#endif
+#ifdef HAVE_ENCODER_ARMTHUMB
+ "armthumb",
+#endif
+#ifdef HAVE_ENCODER_SPARC
+ "sparc",
+#endif
+#ifdef HAVE_ENCODER_ARM64
+ "arm64",
+#endif
+#ifdef HAVE_ENCODER_DELTA
+ "delta",
+#endif
+};
+
+static const char supported_decoders[][9] = {
+ "lzma2",
+#ifdef HAVE_DECODER_X86
+ "x86",
+#endif
+#ifdef HAVE_DECODER_POWERPC
+ "powerpc",
+#endif
+#ifdef HAVE_DECODER_IA64
+ "ia64",
+#endif
+#ifdef HAVE_DECODER_ARM
+ "arm",
+#endif
+#ifdef HAVE_DECODER_ARMTHUMB
+ "armthumb",
+#endif
+#ifdef HAVE_DECODER_SPARC
+ "sparc",
+#endif
+#ifdef HAVE_DECODER_ARM64
+ "arm64",
+#endif
+#ifdef HAVE_DECODER_DELTA
+ "delta",
+#endif
+};
+
+static const char supported_filters[][9] = {
+ "lzma2",
+#if defined(HAVE_ENCODER_X86) || defined(HAVE_DECODER_X86)
+ "x86",
+#endif
+#if defined(HAVE_ENCODER_POWERPC) || defined(HAVE_DECODER_POWERPC)
+ "powerpc",
+#endif
+#if defined(HAVE_ENCODER_IA64) || defined(HAVE_DECODER_IA64)
+ "ia64",
+#endif
+#if defined(HAVE_ENCODER_ARM) || defined(HAVE_DECODER_ARM)
+ "arm",
+#endif
+#if defined(HAVE_ENCODER_ARMTHUMB) || defined(HAVE_DECODER_ARMTHUMB)
+ "armthumb",
+#endif
+#if defined(HAVE_ENCODER_SPARC) || defined(HAVE_DECODER_SPARC)
+ "sparc",
+#endif
+#if defined(HAVE_ENCODER_ARM64) || defined(HAVE_DECODER_ARM64)
+ "arm64",
+#endif
+#if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
+ "delta",
+#endif
+};
+
+
+static void
+test_lzma_str_list_filters(void)
+{
+ // Test with basic NULL inputs.
+ assert_lzma_ret(lzma_str_list_filters(NULL, LZMA_VLI_UNKNOWN, 0,
+ NULL), LZMA_PROG_ERROR);
+
+ char *str = NULL;
+
+ // Test with bad flags.
+ assert_lzma_ret(lzma_str_list_filters(&str, LZMA_VLI_UNKNOWN,
+ LZMA_STR_NO_VALIDATION , NULL), LZMA_OPTIONS_ERROR);
+
+ assert_lzma_ret(lzma_str_list_filters(&str, LZMA_VLI_UNKNOWN,
+ LZMA_STR_NO_SPACES, NULL), LZMA_OPTIONS_ERROR);
+
+ // Test with bad Filter ID.
+ assert_lzma_ret(lzma_str_list_filters(&str, LZMA_VLI_UNKNOWN - 1,
+ 0, NULL), LZMA_OPTIONS_ERROR);
+
+ // Test LZMA_STR_ENCODER flag.
+ assert_lzma_ret(lzma_str_list_filters(&str, LZMA_VLI_UNKNOWN,
+ LZMA_STR_ENCODER, NULL), LZMA_OK);
+
+ for (uint32_t i = 0; i < ARRAY_SIZE(supported_encoders); i++)
+ assert_str_contains(str, supported_encoders[i]);
+
+ free(str);
+
+ // Test LZMA_STR_DECODER flag.
+ assert_lzma_ret(lzma_str_list_filters(&str, LZMA_VLI_UNKNOWN,
+ LZMA_STR_DECODER, NULL), LZMA_OK);
+
+ for (uint32_t i = 0; i < ARRAY_SIZE(supported_decoders); i++)
+ assert_str_contains(str, supported_decoders[i]);
+
+ free(str);
+
+ // Test LZMA_STR_GETOPT_LONG flag.
+ assert_lzma_ret(lzma_str_list_filters(&str, LZMA_VLI_UNKNOWN,
+ LZMA_STR_GETOPT_LONG, NULL), LZMA_OK);
+
+ free(str);
+
+ // Test LZMA_STR_ALL_FILTERS flag.
+ assert_lzma_ret(lzma_str_list_filters(&str, LZMA_VLI_UNKNOWN,
+ LZMA_STR_ALL_FILTERS, NULL), LZMA_OK);
+#if defined(HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1)
+ // With the flag, the string should contain the LZMA1 Filter.
+ assert_str_contains(str, "lzma1");
+
+ free(str);
+
+ // If a non .xz filter is specified, it should still list the Filter.
+ assert_lzma_ret(lzma_str_list_filters(&str, LZMA_FILTER_LZMA1,
+ 0, NULL), LZMA_OK);
+ assert_str_eq(str, "lzma1");
+#endif
+ free(str);
+
+ // Test with no flags.
+ assert_lzma_ret(lzma_str_list_filters(&str, LZMA_VLI_UNKNOWN,
+ 0, NULL), LZMA_OK);
+
+ for (uint32_t i = 0; i < ARRAY_SIZE(supported_filters); i++)
+ assert_str_contains(str, supported_filters[i]);
+
+ assert_str_doesnt_contain(str, "lzma1");
+
+ free(str);
+
+ // Test providing a Filter ID.
+ assert_lzma_ret(lzma_str_list_filters(&str, LZMA_FILTER_LZMA2,
+ LZMA_STR_ALL_FILTERS, NULL), LZMA_OK);
+ assert_str_eq(str, "lzma2");
+
+ free(str);
+}
+
+
+extern int
+main(int argc, char **argv)
+{
+ tuktest_start(argc, argv);
+
+ tuktest_run(test_lzma_str_to_filters);
+ tuktest_run(test_lzma_str_from_filters);
+ tuktest_run(test_lzma_str_list_filters);
+
+ return tuktest_end();
+}
diff --git a/tests/test_hardware.c b/tests/test_hardware.c
new file mode 100644
index 0000000..c72d9b2
--- /dev/null
+++ b/tests/test_hardware.c
@@ -0,0 +1,50 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file test_hardware.c
+/// \brief Tests src/liblzma/api/lzma/hardware.h API functions
+///
+/// Since the output values of these functions are hardware dependent, these
+/// tests are trivial. They are simply used to detect errors and machines
+/// that these function are not supported on.
+//
+// Author: Jia Tan
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tests.h"
+#include "mythread.h"
+
+
+static void
+test_lzma_physmem(void)
+{
+ // NOTE: Use _skip instead of _fail because 0 can also mean that we
+ // don't know how to get this information on this operating system.
+ if (lzma_physmem() == 0)
+ assert_skip("Could not determine amount of physical memory");
+}
+
+
+static void
+test_lzma_cputhreads(void)
+{
+#ifndef MYTHREAD_ENABLED
+ assert_skip("Threading support disabled");
+#else
+ if (lzma_cputhreads() == 0)
+ assert_skip("Could not determine cpu core count");
+#endif
+}
+
+
+extern int
+main(int argc, char **argv)
+{
+ tuktest_start(argc, argv);
+ tuktest_run(test_lzma_physmem);
+ tuktest_run(test_lzma_cputhreads);
+ return tuktest_end();
+}
diff --git a/tests/test_index.c b/tests/test_index.c
new file mode 100644
index 0000000..a14b33d
--- /dev/null
+++ b/tests/test_index.c
@@ -0,0 +1,1715 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file test_index.c
+/// \brief Tests functions handling the lzma_index structure
+///
+/// \todo Implement tests for lzma_file_info_decoder
+//
+// Authors: Jia Tan
+// Lasse Collin
+//
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tests.h"
+
+// liblzma internal header file needed for:
+// UNPADDED_SIZE_MIN
+// UNPADDED_SIZE_MAX
+// vli_ceil4
+#include "common/index.h"
+
+
+#define MEMLIMIT (UINT64_C(1) << 20)
+
+static uint8_t *decode_buffer;
+static size_t decode_buffer_size = 0;
+static lzma_index *decode_test_index;
+
+
+static void
+test_lzma_index_memusage(void)
+{
+ // The return value from lzma_index_memusage is an approximation
+ // of the amount of memory needed for lzma_index for a given
+ // amount of Streams and Blocks. It will be an upperbound,
+ // so this test will mostly sanity check and error check the
+ // function.
+
+ // The maximum number of Streams should be UINT32_MAX in the
+ // current implementation even though the parameter is lzma_vli.
+ assert_uint_eq(lzma_index_memusage((lzma_vli)UINT32_MAX + 1, 1),
+ UINT64_MAX);
+
+ // The maximum number of Blocks should be LZMA_VLI_MAX
+ assert_uint_eq(lzma_index_memusage(1, LZMA_VLI_MAX), UINT64_MAX);
+
+ // Number of Streams must be non-zero
+ assert_uint_eq(lzma_index_memusage(0, 1), UINT64_MAX);
+
+ // Number of Blocks CAN be zero
+ assert_uint(lzma_index_memusage(1, 0), !=, UINT64_MAX);
+
+ // Arbitrary values for Stream and Block should work without error
+ // and should always increase
+ uint64_t previous = 1;
+ lzma_vli streams = 1;
+ lzma_vli blocks = 1;
+
+ // Test 100 different increasing values for Streams and Block
+ for (int i = 0; i < 100; i++) {
+ uint64_t current = lzma_index_memusage(streams, blocks);
+ assert_uint(current, >, previous);
+ previous = current;
+ streams += 29;
+ blocks += 107;
+ }
+
+ // Force integer overflow in calculation (should result in an error)
+ assert_uint_eq(lzma_index_memusage(UINT32_MAX, LZMA_VLI_MAX),
+ UINT64_MAX);
+}
+
+
+static void
+test_lzma_index_memused(void)
+{
+ // Very similar to test_lzma_index_memusage above since
+ // lzma_index_memused is essentially a wrapper for
+ // lzma_index_memusage
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ // Test with empty Index
+ assert_uint(lzma_index_memused(idx), <, UINT64_MAX);
+
+ // Append small Blocks and then test again (should pass).
+ for (lzma_vli i = 0; i < 10; i++)
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN, 1), LZMA_OK);
+
+ assert_uint(lzma_index_memused(idx), <, UINT64_MAX);
+
+ lzma_index_end(idx, NULL);
+}
+
+
+static void
+test_lzma_index_append(void)
+{
+ // Basic input-ouput test done here.
+ // Less trivial tests for this function are done throughout
+ // other tests.
+
+ // First test with NULL lzma_index
+ assert_lzma_ret(lzma_index_append(NULL, NULL, UNPADDED_SIZE_MIN,
+ 1), LZMA_PROG_ERROR);
+
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ // Test with invalid Unpadded Size
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN - 1, 1), LZMA_PROG_ERROR);
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MAX + 1, 1), LZMA_PROG_ERROR);
+
+ // Test with invalid Uncompressed Size
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MAX, LZMA_VLI_MAX + 1),
+ LZMA_PROG_ERROR);
+
+ // Test expected successful Block appends
+ assert_lzma_ret(lzma_index_append(idx, NULL, UNPADDED_SIZE_MIN,
+ 1), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN * 2,
+ 2), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN * 3,
+ 3), LZMA_OK);
+
+ lzma_index_end(idx, NULL);
+
+ // Test compressed .xz file size growing too large. This also tests
+ // a failing assert fixed in 68bda971bb8b666a009331455fcedb4e18d837a4.
+ // Should result in LZMA_DATA_ERROR.
+ idx = lzma_index_init(NULL);
+
+ // The calculation for maximum unpadded size is to make room for the
+ // second stream when lzma_index_cat() is called. The
+ // 4 * LZMA_STREAM_HEADER_SIZE is for the header and footer of
+ // both streams. The extra 24 bytes are for the size of the indexes
+ // for both streams. This allows us to maximize the unpadded sum
+ // during the lzma_index_append() call after the indexes have been
+ // concatenated.
+ assert_lzma_ret(lzma_index_append(idx, NULL, UNPADDED_SIZE_MAX
+ - ((4 * LZMA_STREAM_HEADER_SIZE) + 24), 1), LZMA_OK);
+
+ lzma_index *second = lzma_index_init(NULL);
+ assert_true(second != NULL);
+
+ assert_lzma_ret(lzma_index_cat(second, idx, NULL), LZMA_OK);
+
+ assert_lzma_ret(lzma_index_append(second, NULL, UNPADDED_SIZE_MAX, 1),
+ LZMA_DATA_ERROR);
+
+ lzma_index_end(second, NULL);
+
+ // Test uncompressed size growing too large.
+ // Should result in LZMA_DATA_ERROR.
+ idx = lzma_index_init(NULL);
+
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN, LZMA_VLI_MAX), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN, 1), LZMA_DATA_ERROR);
+
+ lzma_index_end(idx, NULL);
+
+ // Currently not testing for error case when the size of the Index
+ // grows too large to be stored. This was not practical to test for
+ // since too many Blocks needed to be created to cause this.
+}
+
+
+static void
+test_lzma_index_stream_flags(void)
+{
+ // Only trivial tests done here testing for basic functionality.
+ // More in-depth testing for this function will be done in
+ // test_lzma_index_checks.
+
+ // Testing for NULL inputs
+ assert_lzma_ret(lzma_index_stream_flags(NULL, NULL),
+ LZMA_PROG_ERROR);
+
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ assert_lzma_ret(lzma_index_stream_flags(idx, NULL),
+ LZMA_PROG_ERROR);
+
+ lzma_stream_flags stream_flags = {
+ .version = 0,
+ .backward_size = LZMA_BACKWARD_SIZE_MIN,
+ .check = LZMA_CHECK_CRC32
+ };
+
+ assert_lzma_ret(lzma_index_stream_flags(idx, &stream_flags),
+ LZMA_OK);
+
+ lzma_index_end(idx, NULL);
+}
+
+
+static void
+test_lzma_index_checks(void)
+{
+ // Tests should still pass, even if some of the check types
+ // are disabled.
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ lzma_stream_flags stream_flags = {
+ .version = 0,
+ .backward_size = LZMA_BACKWARD_SIZE_MIN,
+ .check = LZMA_CHECK_NONE
+ };
+
+ // First set the check type to None
+ assert_lzma_ret(lzma_index_stream_flags(idx, &stream_flags),
+ LZMA_OK);
+ assert_uint_eq(lzma_index_checks(idx),
+ UINT32_C(1) << LZMA_CHECK_NONE);
+
+ // Set the check type to CRC32 and repeat
+ stream_flags.check = LZMA_CHECK_CRC32;
+ assert_lzma_ret(lzma_index_stream_flags(idx, &stream_flags),
+ LZMA_OK);
+ assert_uint_eq(lzma_index_checks(idx),
+ UINT32_C(1) << LZMA_CHECK_CRC32);
+
+ // Set the check type to CRC64 and repeat
+ stream_flags.check = LZMA_CHECK_CRC64;
+ assert_lzma_ret(lzma_index_stream_flags(idx, &stream_flags),
+ LZMA_OK);
+ assert_uint_eq(lzma_index_checks(idx),
+ UINT32_C(1) << LZMA_CHECK_CRC64);
+
+ // Set the check type to SHA256 and repeat
+ stream_flags.check = LZMA_CHECK_SHA256;
+ assert_lzma_ret(lzma_index_stream_flags(idx, &stream_flags),
+ LZMA_OK);
+ assert_uint_eq(lzma_index_checks(idx),
+ UINT32_C(1) << LZMA_CHECK_SHA256);
+
+ // Create second lzma_index and cat to first
+ lzma_index *second = lzma_index_init(NULL);
+ assert_true(second != NULL);
+
+ // Set the check type to CRC32 for the second lzma_index
+ stream_flags.check = LZMA_CHECK_CRC32;
+ assert_lzma_ret(lzma_index_stream_flags(second, &stream_flags),
+ LZMA_OK);
+
+ assert_uint_eq(lzma_index_checks(second),
+ UINT32_C(1) << LZMA_CHECK_CRC32);
+
+ assert_lzma_ret(lzma_index_cat(idx, second, NULL), LZMA_OK);
+
+ // Index should now have both CRC32 and SHA256
+ assert_uint_eq(lzma_index_checks(idx),
+ (UINT32_C(1) << LZMA_CHECK_CRC32) |
+ (UINT32_C(1) << LZMA_CHECK_SHA256));
+
+ // Change the check type of the second Stream to SHA256
+ stream_flags.check = LZMA_CHECK_SHA256;
+ assert_lzma_ret(lzma_index_stream_flags(idx, &stream_flags),
+ LZMA_OK);
+
+ // Index should now have only SHA256
+ assert_uint_eq(lzma_index_checks(idx),
+ UINT32_C(1) << LZMA_CHECK_SHA256);
+
+ // Test with a third Stream
+ lzma_index *third = lzma_index_init(NULL);
+ assert_true(third != NULL);
+
+ stream_flags.check = LZMA_CHECK_CRC64;
+ assert_lzma_ret(lzma_index_stream_flags(third, &stream_flags),
+ LZMA_OK);
+
+ assert_uint_eq(lzma_index_checks(third),
+ UINT32_C(1) << LZMA_CHECK_CRC64);
+
+ assert_lzma_ret(lzma_index_cat(idx, third, NULL), LZMA_OK);
+
+ // Index should now have CRC64 and SHA256
+ assert_uint_eq(lzma_index_checks(idx),
+ (UINT32_C(1) << LZMA_CHECK_CRC64) |
+ (UINT32_C(1) << LZMA_CHECK_SHA256));
+
+ lzma_index_end(idx, NULL);
+}
+
+
+static void
+test_lzma_index_stream_padding(void)
+{
+ // Test NULL lzma_index
+ assert_lzma_ret(lzma_index_stream_padding(NULL, 0),
+ LZMA_PROG_ERROR);
+
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ // Test Stream Padding not a multiple of 4
+ assert_lzma_ret(lzma_index_stream_padding(idx, 3),
+ LZMA_PROG_ERROR);
+
+ // Test Stream Padding too large
+ assert_lzma_ret(lzma_index_stream_padding(idx, LZMA_VLI_MAX - 3),
+ LZMA_DATA_ERROR);
+
+ // Test Stream Padding valid
+ assert_lzma_ret(lzma_index_stream_padding(idx, 0x1000),
+ LZMA_OK);
+ assert_lzma_ret(lzma_index_stream_padding(idx, 4),
+ LZMA_OK);
+ assert_lzma_ret(lzma_index_stream_padding(idx, 0),
+ LZMA_OK);
+
+ // Test Stream Padding causing the file size to grow too large
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ LZMA_VLI_MAX - 0x1000, 1), LZMA_OK);
+ assert_lzma_ret(lzma_index_stream_padding(idx, 0x1000),
+ LZMA_DATA_ERROR);
+
+ lzma_index_end(idx, NULL);
+}
+
+
+static void
+test_lzma_index_stream_count(void)
+{
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ assert_uint_eq(lzma_index_stream_count(idx), 1);
+
+ // Appending Blocks should not change the Stream count value
+ assert_lzma_ret(lzma_index_append(idx, NULL, UNPADDED_SIZE_MIN,
+ 1), LZMA_OK);
+
+ assert_uint_eq(lzma_index_stream_count(idx), 1);
+
+ // Test with multiple Streams
+ for (uint32_t i = 0; i < 100; i++) {
+ lzma_index *idx_cat = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+ assert_lzma_ret(lzma_index_cat(idx, idx_cat, NULL), LZMA_OK);
+ assert_uint_eq(lzma_index_stream_count(idx), i + 2);
+ }
+
+ lzma_index_end(idx, NULL);
+}
+
+
+static void
+test_lzma_index_block_count(void)
+{
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ assert_uint_eq(lzma_index_block_count(idx), 0);
+
+ const uint32_t iterations = 0x1000;
+ for (uint32_t i = 0; i < iterations; i++) {
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN, 1), LZMA_OK);
+ assert_uint_eq(lzma_index_block_count(idx), i + 1);
+ }
+
+ // Create new lzma_index with a few Blocks
+ lzma_index *second = lzma_index_init(NULL);
+ assert_true(second != NULL);
+
+ assert_lzma_ret(lzma_index_append(second, NULL,
+ UNPADDED_SIZE_MIN, 1), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(second, NULL,
+ UNPADDED_SIZE_MIN, 1), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(second, NULL,
+ UNPADDED_SIZE_MIN, 1), LZMA_OK);
+
+ assert_uint_eq(lzma_index_block_count(second), 3);
+
+ // Concatenate the lzma_indexes together and the result should have
+ // the sum of the two individual counts.
+ assert_lzma_ret(lzma_index_cat(idx, second, NULL), LZMA_OK);
+ assert_uint_eq(lzma_index_block_count(idx), iterations + 3);
+
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN, 1), LZMA_OK);
+
+ assert_uint_eq(lzma_index_block_count(idx), iterations + 4);
+
+ lzma_index_end(idx, NULL);
+}
+
+
+static void
+test_lzma_index_size(void)
+{
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ // Base size should be:
+ // 1 byte Index Indicator
+ // 1 byte Number of Records
+ // 0 bytes Records
+ // 2 bytes Index Padding
+ // 4 bytes CRC32
+ // Total: 8 bytes
+ assert_uint_eq(lzma_index_size(idx), 8);
+
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN, 1), LZMA_OK);
+
+ // New size should be:
+ // 1 byte Index Indicator
+ // 1 byte Number of Records
+ // 2 bytes Records
+ // 0 bytes Index Padding
+ // 4 bytes CRC32
+ // Total: 8 bytes
+ assert_uint_eq(lzma_index_size(idx), 8);
+
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ LZMA_VLI_MAX / 4, LZMA_VLI_MAX / 4), LZMA_OK);
+
+ // New size should be:
+ // 1 byte Index Indicator
+ // 1 byte Number of Records
+ // 20 bytes Records
+ // 2 bytes Index Padding
+ // 4 bytes CRC32
+ // Total: 28 bytes
+ assert_uint_eq(lzma_index_size(idx), 28);
+
+ lzma_index_end(idx, NULL);
+}
+
+
+static void
+test_lzma_index_stream_size(void)
+{
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ // Stream size calculated by:
+ // Size of Stream Header (12 bytes)
+ // Size of all Blocks
+ // Size of the Index
+ // Size of the Stream Footer (12 bytes)
+
+ // First test with empty Index
+ // Stream size should be:
+ // Size of Stream Header - 12 bytes
+ // Size of all Blocks - 0 bytes
+ // Size of Index - 8 bytes
+ // Size of Stream Footer - 12 bytes
+ // Total: 32 bytes
+ assert_uint_eq(lzma_index_stream_size(idx), 32);
+
+ // Next, append a few Blocks and retest
+ assert_lzma_ret(lzma_index_append(idx, NULL, 1000, 1), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL, 1000, 1), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL, 1000, 1), LZMA_OK);
+
+ // Stream size should be:
+ // Size of Stream Header - 12 bytes
+ // Size of all Blocks - 3000 bytes
+ // Size of Index - 16 bytes
+ // Size of Stream Footer - 12 bytes
+ // Total: 3040 bytes
+ assert_uint_eq(lzma_index_stream_size(idx), 3040);
+
+ lzma_index *second = lzma_index_init(NULL);
+ assert_true(second != NULL);
+
+ assert_uint_eq(lzma_index_stream_size(second), 32);
+ assert_lzma_ret(lzma_index_append(second, NULL, 1000, 1), LZMA_OK);
+
+ // Stream size should be:
+ // Size of Stream Header - 12 bytes
+ // Size of all Blocks - 1000 bytes
+ // Size of Index - 12 bytes
+ // Size of Stream Footer - 12 bytes
+ // Total: 1036 bytes
+ assert_uint_eq(lzma_index_stream_size(second), 1036);
+
+ assert_lzma_ret(lzma_index_cat(idx, second, NULL), LZMA_OK);
+
+ // Stream size should be:
+ // Size of Stream Header - 12 bytes
+ // Size of all Blocks - 4000 bytes
+ // Size of Index - 20 bytes
+ // Size of Stream Footer - 12 bytes
+ // Total: 4044 bytes
+ assert_uint_eq(lzma_index_stream_size(idx), 4044);
+
+ lzma_index_end(idx, NULL);
+}
+
+
+static void
+test_lzma_index_total_size(void)
+{
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ // First test empty lzma_index.
+ // Result should be 0 since no Blocks have been added.
+ assert_uint_eq(lzma_index_total_size(idx), 0);
+
+ // Add a few Blocks and retest after each append
+ assert_lzma_ret(lzma_index_append(idx, NULL, 1000, 1), LZMA_OK);
+ assert_uint_eq(lzma_index_total_size(idx), 1000);
+
+ assert_lzma_ret(lzma_index_append(idx, NULL, 1000, 1), LZMA_OK);
+ assert_uint_eq(lzma_index_total_size(idx), 2000);
+
+ assert_lzma_ret(lzma_index_append(idx, NULL, 1000, 1), LZMA_OK);
+ assert_uint_eq(lzma_index_total_size(idx), 3000);
+
+ // Create second lzma_index and append Blocks to it.
+ lzma_index *second = lzma_index_init(NULL);
+ assert_true(second != NULL);
+
+ assert_uint_eq(lzma_index_total_size(second), 0);
+
+ assert_lzma_ret(lzma_index_append(second, NULL, 100, 1), LZMA_OK);
+ assert_uint_eq(lzma_index_total_size(second), 100);
+
+ assert_lzma_ret(lzma_index_append(second, NULL, 100, 1), LZMA_OK);
+ assert_uint_eq(lzma_index_total_size(second), 200);
+
+ // Concatenate the Streams together
+ assert_lzma_ret(lzma_index_cat(idx, second, NULL), LZMA_OK);
+
+ // The resulting total size should be the size of all Blocks
+ // from both Streams
+ assert_uint_eq(lzma_index_total_size(idx), 3200);
+
+ lzma_index_end(idx, NULL);
+}
+
+
+static void
+test_lzma_index_file_size(void)
+{
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ // Should be the same as test_lzma_index_stream_size with
+ // only one Stream and no Stream Padding.
+ assert_uint_eq(lzma_index_file_size(idx), 32);
+
+ assert_lzma_ret(lzma_index_append(idx, NULL, 1000, 1), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL, 1000, 1), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL, 1000, 1), LZMA_OK);
+
+ assert_uint_eq(lzma_index_file_size(idx), 3040);
+
+ // Next add Stream Padding
+ assert_lzma_ret(lzma_index_stream_padding(idx, 1000),
+ LZMA_OK);
+
+ assert_uint_eq(lzma_index_file_size(idx), 4040);
+
+ // Create second lzma_index.
+ // Very similar to test_lzma_index_stream_size, but
+ // the values should include the headers of the second Stream.
+ lzma_index *second = lzma_index_init(NULL);
+ assert_true(second != NULL);
+
+ assert_lzma_ret(lzma_index_append(second, NULL, 1000, 1), LZMA_OK);
+ assert_uint_eq(lzma_index_stream_size(second), 1036);
+
+ assert_lzma_ret(lzma_index_cat(idx, second, NULL), LZMA_OK);
+
+ // .xz file size should be:
+ // Size of 2 Stream Headers - 12 * 2 bytes
+ // Size of all Blocks - 3000 + 1000 bytes
+ // Size of 2 Indexes - 16 + 12 bytes
+ // Size of Stream Padding - 1000 bytes
+ // Size of 2 Stream Footers - 12 * 2 bytes
+ // Total: 5076 bytes
+ assert_uint_eq(lzma_index_file_size(idx), 5076);
+
+ lzma_index_end(idx, NULL);
+}
+
+
+static void
+test_lzma_index_uncompressed_size(void)
+{
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ // Empty lzma_index should have 0 uncompressed .xz file size.
+ assert_uint_eq(lzma_index_uncompressed_size(idx), 0);
+
+ // Append a few small Blocks
+ assert_lzma_ret(lzma_index_append(idx, NULL, 1000, 1), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL, 1000, 10), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL, 1000, 100), LZMA_OK);
+
+ assert_uint_eq(lzma_index_uncompressed_size(idx), 111);
+
+ // Create another lzma_index
+ lzma_index *second = lzma_index_init(NULL);
+ assert_true(second != NULL);
+
+ // Append a few small Blocks
+ assert_lzma_ret(lzma_index_append(second, NULL, 1000, 2), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(second, NULL, 1000, 20), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(second, NULL, 1000, 200), LZMA_OK);
+
+ assert_uint_eq(lzma_index_uncompressed_size(second), 222);
+
+ // Concatenate second lzma_index to first
+ assert_lzma_ret(lzma_index_cat(idx, second, NULL), LZMA_OK);
+
+ // New uncompressed .xz file size should be the sum of the two Streams
+ assert_uint_eq(lzma_index_uncompressed_size(idx), 333);
+
+ // Append one more Block to the lzma_index and ensure that
+ // it is properly updated
+ assert_lzma_ret(lzma_index_append(idx, NULL, 1000, 111), LZMA_OK);
+ assert_uint_eq(lzma_index_uncompressed_size(idx), 444);
+
+ lzma_index_end(idx, NULL);
+}
+
+
+static void
+test_lzma_index_iter_init(void)
+{
+ // Testing basic init functionality.
+ // The init function should call rewind on the iterator.
+ lzma_index *first = lzma_index_init(NULL);
+ assert_true(first != NULL);
+
+ lzma_index *second = lzma_index_init(NULL);
+ assert_true(second != NULL);
+
+ lzma_index *third = lzma_index_init(NULL);
+ assert_true(third != NULL);
+
+ assert_lzma_ret(lzma_index_cat(first, second, NULL), LZMA_OK);
+ assert_lzma_ret(lzma_index_cat(first, third, NULL), LZMA_OK);
+
+ lzma_index_iter iter;
+ lzma_index_iter_init(&iter, first);
+
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM));
+ assert_uint_eq(iter.stream.number, 1);
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM));
+ assert_uint_eq(iter.stream.number, 2);
+
+ lzma_index_iter_init(&iter, first);
+
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM));
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM));
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM));
+ assert_uint_eq(iter.stream.number, 3);
+
+ lzma_index_end(first, NULL);
+}
+
+
+static void
+test_lzma_index_iter_rewind(void)
+{
+ lzma_index *first = lzma_index_init(NULL);
+ assert_true(first != NULL);
+
+ lzma_index_iter iter;
+ lzma_index_iter_init(&iter, first);
+
+ // Append 3 Blocks and iterate over each. This is to test
+ // the LZMA_INDEX_ITER_BLOCK mode.
+ for (uint32_t i = 0; i < 3; i++) {
+ assert_lzma_ret(lzma_index_append(first, NULL,
+ UNPADDED_SIZE_MIN, 1), LZMA_OK);
+ assert_false(lzma_index_iter_next(&iter,
+ LZMA_INDEX_ITER_BLOCK));
+ assert_uint_eq(iter.block.number_in_file, i + 1);
+ }
+
+ // Rewind back to the beginning and iterate over the Blocks again
+ lzma_index_iter_rewind(&iter);
+
+ // Should be able to re-iterate over the Blocks again.
+ for (uint32_t i = 0; i < 3; i++) {
+ assert_false(lzma_index_iter_next(&iter,
+ LZMA_INDEX_ITER_BLOCK));
+ assert_uint_eq(iter.block.number_in_file, i + 1);
+ }
+
+ // Next concatenate two more lzma_indexes, iterate over them,
+ // rewind, and iterate over them again. This is to test
+ // the LZMA_INDEX_ITER_STREAM mode.
+ lzma_index *second = lzma_index_init(NULL);
+ assert_true(second != NULL);
+
+ lzma_index *third = lzma_index_init(NULL);
+ assert_true(third != NULL);
+
+ assert_lzma_ret(lzma_index_cat(first, second, NULL), LZMA_OK);
+ assert_lzma_ret(lzma_index_cat(first, third, NULL), LZMA_OK);
+
+ assert_false(lzma_index_iter_next(&iter,
+ LZMA_INDEX_ITER_STREAM));
+ assert_false(lzma_index_iter_next(&iter,
+ LZMA_INDEX_ITER_STREAM));
+
+ assert_uint_eq(iter.stream.number, 3);
+
+ lzma_index_iter_rewind(&iter);
+
+ for (uint32_t i = 0; i < 3; i++) {
+ assert_false(lzma_index_iter_next(&iter,
+ LZMA_INDEX_ITER_STREAM));
+ assert_uint_eq(iter.stream.number, i + 1);
+ }
+
+ lzma_index_end(first, NULL);
+}
+
+
+static void
+test_lzma_index_iter_next(void)
+{
+ lzma_index *first = lzma_index_init(NULL);
+ assert_true(first != NULL);
+
+ lzma_index_iter iter;
+ lzma_index_iter_init(&iter, first);
+
+ // First test bad mode values
+ for (uint32_t i = LZMA_INDEX_ITER_NONEMPTY_BLOCK + 1; i < 100; i++)
+ assert_true(lzma_index_iter_next(&iter, i));
+
+ // Test iterating over Blocks
+ assert_lzma_ret(lzma_index_append(first, NULL,
+ UNPADDED_SIZE_MIN, 1), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(first, NULL,
+ UNPADDED_SIZE_MIN * 2, 10), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(first, NULL,
+ UNPADDED_SIZE_MIN * 3, 100), LZMA_OK);
+
+ // For Blocks, need to verify:
+ // - number_in_file (overall Block number)
+ // - compressed_file_offset
+ // - uncompressed_file_offset
+ // - number_in_stream (Block number relative to current Stream)
+ // - compressed_stream_offset
+ // - uncompressed_stream_offset
+ // - uncompressed_size
+ // - unpadded_size
+ // - total_size
+
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK));
+
+ // Verify Block data stored correctly
+ assert_uint_eq(iter.block.number_in_file, 1);
+
+ // Should start right after the Stream Header
+ assert_uint_eq(iter.block.compressed_file_offset,
+ LZMA_STREAM_HEADER_SIZE);
+ assert_uint_eq(iter.block.uncompressed_file_offset, 0);
+ assert_uint_eq(iter.block.number_in_stream, 1);
+ assert_uint_eq(iter.block.compressed_stream_offset,
+ LZMA_STREAM_HEADER_SIZE);
+ assert_uint_eq(iter.block.uncompressed_stream_offset, 0);
+ assert_uint_eq(iter.block.unpadded_size, UNPADDED_SIZE_MIN);
+ assert_uint_eq(iter.block.total_size, vli_ceil4(UNPADDED_SIZE_MIN));
+
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK));
+
+ // Verify Block data stored correctly
+ assert_uint_eq(iter.block.number_in_file, 2);
+ assert_uint_eq(iter.block.compressed_file_offset,
+ LZMA_STREAM_HEADER_SIZE +
+ vli_ceil4(UNPADDED_SIZE_MIN));
+ assert_uint_eq(iter.block.uncompressed_file_offset, 1);
+ assert_uint_eq(iter.block.number_in_stream, 2);
+ assert_uint_eq(iter.block.compressed_stream_offset,
+ LZMA_STREAM_HEADER_SIZE +
+ vli_ceil4(UNPADDED_SIZE_MIN));
+ assert_uint_eq(iter.block.uncompressed_stream_offset, 1);
+ assert_uint_eq(iter.block.unpadded_size, UNPADDED_SIZE_MIN * 2);
+ assert_uint_eq(iter.block.total_size, vli_ceil4(UNPADDED_SIZE_MIN * 2));
+
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK));
+
+ // Verify Block data stored correctly
+ assert_uint_eq(iter.block.number_in_file, 3);
+ assert_uint_eq(iter.block.compressed_file_offset,
+ LZMA_STREAM_HEADER_SIZE +
+ vli_ceil4(UNPADDED_SIZE_MIN) +
+ vli_ceil4(UNPADDED_SIZE_MIN * 2));
+ assert_uint_eq(iter.block.uncompressed_file_offset, 11);
+ assert_uint_eq(iter.block.number_in_stream, 3);
+ assert_uint_eq(iter.block.compressed_stream_offset,
+ LZMA_STREAM_HEADER_SIZE +
+ vli_ceil4(UNPADDED_SIZE_MIN) +
+ vli_ceil4(UNPADDED_SIZE_MIN * 2));
+ assert_uint_eq(iter.block.uncompressed_stream_offset, 11);
+ assert_uint_eq(iter.block.unpadded_size, UNPADDED_SIZE_MIN * 3);
+ assert_uint_eq(iter.block.total_size,
+ vli_ceil4(UNPADDED_SIZE_MIN * 3));
+
+ // Only three Blocks were added, so this should return true
+ assert_true(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK));
+
+ const lzma_vli second_stream_compressed_start =
+ LZMA_STREAM_HEADER_SIZE * 2 +
+ vli_ceil4(UNPADDED_SIZE_MIN) +
+ vli_ceil4(UNPADDED_SIZE_MIN * 2) +
+ vli_ceil4(UNPADDED_SIZE_MIN * 3) +
+ lzma_index_size(first);
+ const lzma_vli second_stream_uncompressed_start = 1 + 10 + 100;
+
+ // Test iterating over Streams.
+ // The second Stream will have 0 Blocks
+ lzma_index *second = lzma_index_init(NULL);
+ assert_true(second != NULL);
+
+ // Set Stream Flags for Stream 2
+ lzma_stream_flags flags = {
+ .version = 0,
+ .backward_size = LZMA_BACKWARD_SIZE_MIN,
+ .check = LZMA_CHECK_CRC32
+ };
+
+ assert_lzma_ret(lzma_index_stream_flags(second, &flags), LZMA_OK);
+
+ // The Second stream will have 8 bytes of Stream Padding
+ assert_lzma_ret(lzma_index_stream_padding(second, 8), LZMA_OK);
+
+ const lzma_vli second_stream_index_size = lzma_index_size(second);
+
+ // The third Stream will have 2 Blocks
+ lzma_index *third = lzma_index_init(NULL);
+ assert_true(third != NULL);
+
+ assert_lzma_ret(lzma_index_append(third, NULL, 32, 20), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(third, NULL, 64, 40), LZMA_OK);
+
+ const lzma_vli third_stream_index_size = lzma_index_size(third);
+
+ assert_lzma_ret(lzma_index_cat(first, second, NULL), LZMA_OK);
+ assert_lzma_ret(lzma_index_cat(first, third, NULL), LZMA_OK);
+
+ // For Streams, need to verify:
+ // - flags (Stream Flags)
+ // - number (Stream count)
+ // - block_count
+ // - compressed_offset
+ // - uncompressed_offset
+ // - compressed_size
+ // - uncompressed_size
+ // - padding (Stream Padding)
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM));
+
+ // Verify Stream
+ assert_uint_eq(iter.stream.flags->backward_size,
+ LZMA_BACKWARD_SIZE_MIN);
+ assert_uint_eq(iter.stream.flags->check, LZMA_CHECK_CRC32);
+ assert_uint_eq(iter.stream.number, 2);
+ assert_uint_eq(iter.stream.block_count, 0);
+ assert_uint_eq(iter.stream.compressed_offset,
+ second_stream_compressed_start);
+ assert_uint_eq(iter.stream.uncompressed_offset,
+ second_stream_uncompressed_start);
+ assert_uint_eq(iter.stream.compressed_size,
+ LZMA_STREAM_HEADER_SIZE * 2 +
+ second_stream_index_size);
+ assert_uint_eq(iter.stream.uncompressed_size, 0);
+ assert_uint_eq(iter.stream.padding, 8);
+
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM));
+
+ // Verify Stream
+ const lzma_vli third_stream_compressed_start =
+ second_stream_compressed_start +
+ LZMA_STREAM_HEADER_SIZE * 2 +
+ 8 + // Stream padding
+ second_stream_index_size;
+ const lzma_vli third_stream_uncompressed_start =
+ second_stream_uncompressed_start;
+
+ assert_uint_eq(iter.stream.number, 3);
+ assert_uint_eq(iter.stream.block_count, 2);
+ assert_uint_eq(iter.stream.compressed_offset,
+ third_stream_compressed_start);
+ assert_uint_eq(iter.stream.uncompressed_offset,
+ third_stream_uncompressed_start);
+ assert_uint_eq(iter.stream.compressed_size,
+ LZMA_STREAM_HEADER_SIZE * 2 +
+ 96 + // Total compressed size
+ third_stream_index_size);
+ assert_uint_eq(iter.stream.uncompressed_size, 60);
+ assert_uint_eq(iter.stream.padding, 0);
+
+ assert_true(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM));
+
+ // Even after a failing call to next with ITER_STREAM mode,
+ // should still be able to iterate over the 2 Blocks in
+ // Stream 3.
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK));
+
+ // Verify both Blocks
+
+ // Next call to iterate Block should return true because the
+ // first Block can already be read from the LZMA_INDEX_ITER_STREAM
+ // call.
+ assert_true(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK));
+
+ // Rewind to test LZMA_INDEX_ITER_ANY
+ lzma_index_iter_rewind(&iter);
+
+ // Iterate past the first three Blocks
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_ANY));
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_ANY));
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_ANY));
+
+ // Iterate past the next Stream
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_ANY));
+
+ // Iterate past the next Stream
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_ANY));
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_ANY));
+
+ // Last call should fail
+ assert_true(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_ANY));
+
+ // Rewind to test LZMA_INDEX_ITER_NONEMPTY_BLOCK
+ lzma_index_iter_rewind(&iter);
+
+ // Iterate past the first three Blocks
+ assert_false(lzma_index_iter_next(&iter,
+ LZMA_INDEX_ITER_NONEMPTY_BLOCK));
+ assert_false(lzma_index_iter_next(&iter,
+ LZMA_INDEX_ITER_NONEMPTY_BLOCK));
+ assert_false(lzma_index_iter_next(&iter,
+ LZMA_INDEX_ITER_NONEMPTY_BLOCK));
+
+ // Skip past the next Stream which has no Blocks.
+ // We will get to the first Block of the third Stream.
+ assert_false(lzma_index_iter_next(&iter,
+ LZMA_INDEX_ITER_NONEMPTY_BLOCK));
+
+ // Iterate past the second (the last) Block in the third Stream
+ assert_false(lzma_index_iter_next(&iter,
+ LZMA_INDEX_ITER_NONEMPTY_BLOCK));
+
+ // Last call should fail since there is nothing left to iterate over.
+ assert_true(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_ANY));
+
+ lzma_index_end(first, NULL);
+}
+
+
+static void
+test_lzma_index_iter_locate(void)
+{
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ lzma_index_iter iter;
+ lzma_index_iter_init(&iter, idx);
+
+ // Cannot locate anything from an empty Index.
+ assert_true(lzma_index_iter_locate(&iter, 0));
+ assert_true(lzma_index_iter_locate(&iter, 555));
+
+ // One empty Record: nothing is found since there's no uncompressed
+ // data.
+ assert_lzma_ret(lzma_index_append(idx, NULL, 16, 0), LZMA_OK);
+ assert_true(lzma_index_iter_locate(&iter, 0));
+
+ // Non-empty Record and we can find something.
+ assert_lzma_ret(lzma_index_append(idx, NULL, 32, 5), LZMA_OK);
+ assert_false(lzma_index_iter_locate(&iter, 0));
+ assert_uint_eq(iter.block.total_size, 32);
+ assert_uint_eq(iter.block.uncompressed_size, 5);
+ assert_uint_eq(iter.block.compressed_file_offset,
+ LZMA_STREAM_HEADER_SIZE + 16);
+ assert_uint_eq(iter.block.uncompressed_file_offset, 0);
+
+ // Still cannot find anything past the end.
+ assert_true(lzma_index_iter_locate(&iter, 5));
+
+ // Add the third Record.
+ assert_lzma_ret(lzma_index_append(idx, NULL, 40, 11), LZMA_OK);
+
+ assert_false(lzma_index_iter_locate(&iter, 0));
+ assert_uint_eq(iter.block.total_size, 32);
+ assert_uint_eq(iter.block.uncompressed_size, 5);
+ assert_uint_eq(iter.block.compressed_file_offset,
+ LZMA_STREAM_HEADER_SIZE + 16);
+ assert_uint_eq(iter.block.uncompressed_file_offset, 0);
+
+ assert_false(lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK));
+ assert_uint_eq(iter.block.total_size, 40);
+ assert_uint_eq(iter.block.uncompressed_size, 11);
+ assert_uint_eq(iter.block.compressed_file_offset,
+ LZMA_STREAM_HEADER_SIZE + 16 + 32);
+ assert_uint_eq(iter.block.uncompressed_file_offset, 5);
+
+ assert_false(lzma_index_iter_locate(&iter, 2));
+ assert_uint_eq(iter.block.total_size, 32);
+ assert_uint_eq(iter.block.uncompressed_size, 5);
+ assert_uint_eq(iter.block.compressed_file_offset,
+ LZMA_STREAM_HEADER_SIZE + 16);
+ assert_uint_eq(iter.block.uncompressed_file_offset, 0);
+
+ assert_false(lzma_index_iter_locate(&iter, 5));
+ assert_uint_eq(iter.block.total_size, 40);
+ assert_uint_eq(iter.block.uncompressed_size, 11);
+ assert_uint_eq(iter.block.compressed_file_offset,
+ LZMA_STREAM_HEADER_SIZE + 16 + 32);
+ assert_uint_eq(iter.block.uncompressed_file_offset, 5);
+
+ assert_false(lzma_index_iter_locate(&iter, 5 + 11 - 1));
+ assert_uint_eq(iter.block.total_size, 40);
+ assert_uint_eq(iter.block.uncompressed_size, 11);
+ assert_uint_eq(iter.block.compressed_file_offset,
+ LZMA_STREAM_HEADER_SIZE + 16 + 32);
+ assert_uint_eq(iter.block.uncompressed_file_offset, 5);
+
+ assert_true(lzma_index_iter_locate(&iter, 5 + 11));
+ assert_true(lzma_index_iter_locate(&iter, 5 + 15));
+
+ // Large Index
+ lzma_index_end(idx, NULL);
+ idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+ lzma_index_iter_init(&iter, idx);
+
+ for (uint32_t n = 4; n <= 4 * 5555; n += 4)
+ assert_lzma_ret(lzma_index_append(idx, NULL, n + 8, n),
+ LZMA_OK);
+
+ assert_uint_eq(lzma_index_block_count(idx), 5555);
+
+ // First Record
+ assert_false(lzma_index_iter_locate(&iter, 0));
+ assert_uint_eq(iter.block.total_size, 4 + 8);
+ assert_uint_eq(iter.block.uncompressed_size, 4);
+ assert_uint_eq(iter.block.compressed_file_offset,
+ LZMA_STREAM_HEADER_SIZE);
+ assert_uint_eq(iter.block.uncompressed_file_offset, 0);
+
+ assert_false(lzma_index_iter_locate(&iter, 3));
+ assert_uint_eq(iter.block.total_size, 4 + 8);
+ assert_uint_eq(iter.block.uncompressed_size, 4);
+ assert_uint_eq(iter.block.compressed_file_offset,
+ LZMA_STREAM_HEADER_SIZE);
+ assert_uint_eq(iter.block.uncompressed_file_offset, 0);
+
+ // Second Record
+ assert_false(lzma_index_iter_locate(&iter, 4));
+ assert_uint_eq(iter.block.total_size, 2 * 4 + 8);
+ assert_uint_eq(iter.block.uncompressed_size, 2 * 4);
+ assert_uint_eq(iter.block.compressed_file_offset,
+ LZMA_STREAM_HEADER_SIZE + 4 + 8);
+ assert_uint_eq(iter.block.uncompressed_file_offset, 4);
+
+ // Last Record
+ assert_false(lzma_index_iter_locate(
+ &iter, lzma_index_uncompressed_size(idx) - 1));
+ assert_uint_eq(iter.block.total_size, 4 * 5555 + 8);
+ assert_uint_eq(iter.block.uncompressed_size, 4 * 5555);
+ assert_uint_eq(iter.block.compressed_file_offset,
+ lzma_index_total_size(idx)
+ + LZMA_STREAM_HEADER_SIZE - 4 * 5555 - 8);
+ assert_uint_eq(iter.block.uncompressed_file_offset,
+ lzma_index_uncompressed_size(idx) - 4 * 5555);
+
+ // Allocation chunk boundaries. See INDEX_GROUP_SIZE in
+ // liblzma/common/index.c.
+ const uint32_t group_multiple = 256 * 4;
+ const uint32_t radius = 8;
+ const uint32_t start = group_multiple - radius;
+ lzma_vli ubase = 0;
+ lzma_vli tbase = 0;
+ uint32_t n;
+ for (n = 1; n < start; ++n) {
+ ubase += n * 4;
+ tbase += n * 4 + 8;
+ }
+
+ while (n < start + 2 * radius) {
+ assert_false(lzma_index_iter_locate(&iter, ubase + n * 4));
+
+ assert_uint_eq(iter.block.compressed_file_offset,
+ tbase + n * 4 + 8
+ + LZMA_STREAM_HEADER_SIZE);
+ assert_uint_eq(iter.block.uncompressed_file_offset,
+ ubase + n * 4);
+
+ tbase += n * 4 + 8;
+ ubase += n * 4;
+ ++n;
+
+ assert_uint_eq(iter.block.total_size, n * 4 + 8);
+ assert_uint_eq(iter.block.uncompressed_size, n * 4);
+ }
+
+ // Do it also backwards.
+ while (n > start) {
+ assert_false(lzma_index_iter_locate(
+ &iter, ubase + (n - 1) * 4));
+
+ assert_uint_eq(iter.block.total_size, n * 4 + 8);
+ assert_uint_eq(iter.block.uncompressed_size, n * 4);
+
+ --n;
+ tbase -= n * 4 + 8;
+ ubase -= n * 4;
+
+ assert_uint_eq(iter.block.compressed_file_offset,
+ tbase + n * 4 + 8
+ + LZMA_STREAM_HEADER_SIZE);
+ assert_uint_eq(iter.block.uncompressed_file_offset,
+ ubase + n * 4);
+ }
+
+ // Test locating in concatenated Index.
+ lzma_index_end(idx, NULL);
+ idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+ lzma_index_iter_init(&iter, idx);
+ for (n = 0; n < group_multiple; ++n)
+ assert_lzma_ret(lzma_index_append(idx, NULL, 8, 0),
+ LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL, 16, 1), LZMA_OK);
+ assert_false(lzma_index_iter_locate(&iter, 0));
+ assert_uint_eq(iter.block.total_size, 16);
+ assert_uint_eq(iter.block.uncompressed_size, 1);
+ assert_uint_eq(iter.block.compressed_file_offset,
+ LZMA_STREAM_HEADER_SIZE + group_multiple * 8);
+ assert_uint_eq(iter.block.uncompressed_file_offset, 0);
+
+ lzma_index_end(idx, NULL);
+}
+
+
+static void
+test_lzma_index_cat(void)
+{
+ // Most complex tests for this function are done in other tests.
+ // This will mostly test basic functionality.
+
+ lzma_index *dest = lzma_index_init(NULL);
+ assert_true(dest != NULL);
+
+ lzma_index *src = lzma_index_init(NULL);
+ assert_true(src != NULL);
+
+ // First test NULL dest or src
+ assert_lzma_ret(lzma_index_cat(NULL, NULL, NULL), LZMA_PROG_ERROR);
+ assert_lzma_ret(lzma_index_cat(dest, NULL, NULL), LZMA_PROG_ERROR);
+ assert_lzma_ret(lzma_index_cat(NULL, src, NULL), LZMA_PROG_ERROR);
+
+ // Check for uncompressed size overflow
+ assert_lzma_ret(lzma_index_append(dest, NULL,
+ (UNPADDED_SIZE_MAX / 2) + 1, 1), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(src, NULL,
+ (UNPADDED_SIZE_MAX / 2) + 1, 1), LZMA_OK);
+ assert_lzma_ret(lzma_index_cat(dest, src, NULL), LZMA_DATA_ERROR);
+
+ // Check for compressed size overflow
+ lzma_index_end(src, NULL);
+ lzma_index_end(dest, NULL);
+
+ dest = lzma_index_init(NULL);
+ assert_true(dest != NULL);
+
+ src = lzma_index_init(NULL);
+ assert_true(src != NULL);
+
+ assert_lzma_ret(lzma_index_append(dest, NULL,
+ UNPADDED_SIZE_MIN, LZMA_VLI_MAX - 1), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(src, NULL,
+ UNPADDED_SIZE_MIN, LZMA_VLI_MAX - 1), LZMA_OK);
+ assert_lzma_ret(lzma_index_cat(dest, src, NULL), LZMA_DATA_ERROR);
+
+ lzma_index_end(dest, NULL);
+ lzma_index_end(src, NULL);
+}
+
+
+// Helper function for test_lzma_index_dup().
+static bool
+index_is_equal(const lzma_index *a, const lzma_index *b)
+{
+ // Compare only the Stream and Block sizes and offsets.
+ lzma_index_iter ra, rb;
+ lzma_index_iter_init(&ra, a);
+ lzma_index_iter_init(&rb, b);
+
+ while (true) {
+ bool reta = lzma_index_iter_next(&ra, LZMA_INDEX_ITER_ANY);
+ bool retb = lzma_index_iter_next(&rb, LZMA_INDEX_ITER_ANY);
+
+ // If both iterators finish at the same time, then the Indexes
+ // are identical.
+ if (reta)
+ return retb;
+
+ if (ra.stream.number != rb.stream.number
+ || ra.stream.block_count
+ != rb.stream.block_count
+ || ra.stream.compressed_offset
+ != rb.stream.compressed_offset
+ || ra.stream.uncompressed_offset
+ != rb.stream.uncompressed_offset
+ || ra.stream.compressed_size
+ != rb.stream.compressed_size
+ || ra.stream.uncompressed_size
+ != rb.stream.uncompressed_size
+ || ra.stream.padding
+ != rb.stream.padding)
+ return false;
+
+ if (ra.stream.block_count == 0)
+ continue;
+
+ if (ra.block.number_in_file != rb.block.number_in_file
+ || ra.block.compressed_file_offset
+ != rb.block.compressed_file_offset
+ || ra.block.uncompressed_file_offset
+ != rb.block.uncompressed_file_offset
+ || ra.block.number_in_stream
+ != rb.block.number_in_stream
+ || ra.block.compressed_stream_offset
+ != rb.block.compressed_stream_offset
+ || ra.block.uncompressed_stream_offset
+ != rb.block.uncompressed_stream_offset
+ || ra.block.uncompressed_size
+ != rb.block.uncompressed_size
+ || ra.block.unpadded_size
+ != rb.block.unpadded_size
+ || ra.block.total_size
+ != rb.block.total_size)
+ return false;
+ }
+}
+
+
+// Allocator that succeeds for the first two allocation but fails the rest.
+static void *
+my_alloc(void *opaque, size_t a, size_t b)
+{
+ (void)opaque;
+
+ static unsigned count = 0;
+ if (++count > 2)
+ return NULL;
+
+ return malloc(a * b);
+}
+
+static const lzma_allocator test_index_dup_alloc = { &my_alloc, NULL, NULL };
+
+
+static void
+test_lzma_index_dup(void)
+{
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ // Test for the bug fix 21515d79d778b8730a434f151b07202d52a04611:
+ // liblzma: Fix lzma_index_dup() for empty Streams.
+ assert_lzma_ret(lzma_index_stream_padding(idx, 4), LZMA_OK);
+ lzma_index *copy = lzma_index_dup(idx, NULL);
+ assert_true(copy != NULL);
+ assert_true(index_is_equal(idx, copy));
+ lzma_index_end(copy, NULL);
+
+ // Test for the bug fix 3bf857edfef51374f6f3fffae3d817f57d3264a0:
+ // liblzma: Fix a memory leak in error path of lzma_index_dup().
+ // Use Valgrind to see that there are no leaks.
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN, 10), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN * 2, 100), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN * 3, 1000), LZMA_OK);
+
+ assert_true(lzma_index_dup(idx, &test_index_dup_alloc) == NULL);
+
+ // Test a few streams and blocks
+ lzma_index *second = lzma_index_init(NULL);
+ assert_true(second != NULL);
+
+ assert_lzma_ret(lzma_index_stream_padding(second, 16), LZMA_OK);
+
+ lzma_index *third = lzma_index_init(NULL);
+ assert_true(third != NULL);
+
+ assert_lzma_ret(lzma_index_append(third, NULL,
+ UNPADDED_SIZE_MIN * 10, 40), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(third, NULL,
+ UNPADDED_SIZE_MIN * 20, 400), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(third, NULL,
+ UNPADDED_SIZE_MIN * 30, 4000), LZMA_OK);
+
+ assert_lzma_ret(lzma_index_cat(idx, second, NULL), LZMA_OK);
+ assert_lzma_ret(lzma_index_cat(idx, third, NULL), LZMA_OK);
+
+ copy = lzma_index_dup(idx, NULL);
+ assert_true(copy != NULL);
+ assert_true(index_is_equal(idx, copy));
+
+ lzma_index_end(copy, NULL);
+ lzma_index_end(idx, NULL);
+}
+
+#if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
+static void
+verify_index_buffer(const lzma_index *idx, const uint8_t *buffer,
+ const size_t buffer_size)
+{
+ lzma_index_iter iter;
+ lzma_index_iter_init(&iter, idx);
+
+ size_t buffer_pos = 0;
+
+ // Verify Index Indicator
+ assert_uint_eq(buffer[buffer_pos++], 0);
+
+ // Get Number of Records
+ lzma_vli number_of_records = 0;
+ lzma_vli block_count = 0;
+ assert_lzma_ret(lzma_vli_decode(&number_of_records, NULL, buffer,
+ &buffer_pos, buffer_size), LZMA_OK);
+
+ while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_ANY)) {
+ // Verify each Record (Unpadded Size, then Uncompressed Size).
+ // Verify Unpadded Size.
+ lzma_vli unpadded_size, uncompressed_size;
+ assert_lzma_ret(lzma_vli_decode(&unpadded_size,
+ NULL, buffer, &buffer_pos,
+ buffer_size), LZMA_OK);
+ assert_uint_eq(unpadded_size,
+ iter.block.unpadded_size);
+
+ // Verify Uncompressed Size
+ assert_lzma_ret(lzma_vli_decode(&uncompressed_size,
+ NULL, buffer, &buffer_pos,
+ buffer_size), LZMA_OK);
+ assert_uint_eq(uncompressed_size,
+ iter.block.uncompressed_size);
+
+ block_count++;
+ }
+
+ // Verify Number of Records
+ assert_uint_eq(number_of_records, block_count);
+
+ // Verify Index Padding
+ for (; buffer_pos % 4 != 0; buffer_pos++)
+ assert_uint_eq(buffer[buffer_pos], 0);
+
+ // Verify CRC32
+ uint32_t crc32 = lzma_crc32(buffer, buffer_pos, 0);
+ assert_uint_eq(read32le(buffer + buffer_pos), crc32);
+}
+
+
+// In a few places the Index size is needed as a size_t but lzma_index_size()
+// returns lzma_vli.
+static size_t
+get_index_size(const lzma_index *idx)
+{
+ const lzma_vli size = lzma_index_size(idx);
+ assert_uint(size, <, SIZE_MAX);
+ return (size_t)size;
+}
+#endif
+
+
+static void
+test_lzma_index_encoder(void)
+{
+#if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
+ assert_skip("Encoder or decoder support disabled");
+#else
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ lzma_stream strm = LZMA_STREAM_INIT;
+
+ // First do basic NULL checks
+ assert_lzma_ret(lzma_index_encoder(NULL, NULL), LZMA_PROG_ERROR);
+ assert_lzma_ret(lzma_index_encoder(&strm, NULL), LZMA_PROG_ERROR);
+ assert_lzma_ret(lzma_index_encoder(NULL, idx), LZMA_PROG_ERROR);
+
+ // Append three small Blocks
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN, 10), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN * 2, 100), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN * 3, 1000), LZMA_OK);
+
+ // Encode this lzma_index into a buffer
+ size_t buffer_size = get_index_size(idx);
+ uint8_t *buffer = tuktest_malloc(buffer_size);
+
+ assert_lzma_ret(lzma_index_encoder(&strm, idx), LZMA_OK);
+
+ strm.avail_out = buffer_size;
+ strm.next_out = buffer;
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
+ assert_uint_eq(strm.avail_out, 0);
+
+ lzma_end(&strm);
+
+ verify_index_buffer(idx, buffer, buffer_size);
+
+ // Test with multiple Streams concatenated into 1 Index
+ lzma_index *second = lzma_index_init(NULL);
+ assert_true(second != NULL);
+
+ // Include 1 Block
+ assert_lzma_ret(lzma_index_append(second, NULL,
+ UNPADDED_SIZE_MIN * 4, 20), LZMA_OK);
+
+ // Include Stream Padding
+ assert_lzma_ret(lzma_index_stream_padding(second, 16), LZMA_OK);
+
+ assert_lzma_ret(lzma_index_cat(idx, second, NULL), LZMA_OK);
+ buffer_size = get_index_size(idx);
+ buffer = tuktest_malloc(buffer_size);
+ assert_lzma_ret(lzma_index_encoder(&strm, idx), LZMA_OK);
+
+ strm.avail_out = buffer_size;
+ strm.next_out = buffer;
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
+ assert_uint_eq(strm.avail_out, 0);
+
+ verify_index_buffer(idx, buffer, buffer_size);
+
+ lzma_index_end(idx, NULL);
+ lzma_end(&strm);
+#endif
+}
+
+static void
+generate_index_decode_buffer(void)
+{
+#ifdef HAVE_ENCODERS
+ decode_test_index = lzma_index_init(NULL);
+ if (decode_test_index == NULL)
+ return;
+
+ // Add 4 Blocks
+ for (uint32_t i = 1; i < 5; i++)
+ if (lzma_index_append(decode_test_index, NULL,
+ 0x1000 * i, 0x100 * i) != LZMA_OK)
+ return;
+
+ size_t size = lzma_index_size(decode_test_index);
+ decode_buffer = tuktest_malloc(size);
+
+ if (lzma_index_buffer_encode(decode_test_index,
+ decode_buffer, &decode_buffer_size, size) != LZMA_OK)
+ decode_buffer_size = 0;
+#endif
+}
+
+
+#ifdef HAVE_DECODERS
+static void
+decode_index(const uint8_t *buffer, const size_t size, lzma_stream *strm,
+ lzma_ret expected_error)
+{
+ strm->avail_in = size;
+ strm->next_in = buffer;
+ assert_lzma_ret(lzma_code(strm, LZMA_FINISH), expected_error);
+}
+#endif
+
+
+static void
+test_lzma_index_decoder(void)
+{
+#ifndef HAVE_DECODERS
+ assert_skip("Decoder support disabled");
+#else
+ if (decode_buffer_size == 0)
+ assert_skip("Could not initialize decode test buffer");
+
+ lzma_stream strm = LZMA_STREAM_INIT;
+
+ assert_lzma_ret(lzma_index_decoder(NULL, NULL, MEMLIMIT),
+ LZMA_PROG_ERROR);
+ assert_lzma_ret(lzma_index_decoder(&strm, NULL, MEMLIMIT),
+ LZMA_PROG_ERROR);
+ assert_lzma_ret(lzma_index_decoder(NULL, &decode_test_index,
+ MEMLIMIT), LZMA_PROG_ERROR);
+
+ // Do actual decode
+ lzma_index *idx;
+ assert_lzma_ret(lzma_index_decoder(&strm, &idx, MEMLIMIT),
+ LZMA_OK);
+
+ decode_index(decode_buffer, decode_buffer_size, &strm,
+ LZMA_STREAM_END);
+
+ // Compare results with expected
+ assert_true(index_is_equal(decode_test_index, idx));
+
+ lzma_index_end(idx, NULL);
+
+ // Test again with too low memory limit
+ assert_lzma_ret(lzma_index_decoder(&strm, &idx, 0), LZMA_OK);
+
+ decode_index(decode_buffer, decode_buffer_size, &strm,
+ LZMA_MEMLIMIT_ERROR);
+
+ uint8_t *corrupt_buffer = tuktest_malloc(decode_buffer_size);
+ memcpy(corrupt_buffer, decode_buffer, decode_buffer_size);
+
+ assert_lzma_ret(lzma_index_decoder(&strm, &idx, MEMLIMIT),
+ LZMA_OK);
+
+ // First corrupt the Index Indicator
+ corrupt_buffer[0] ^= 1;
+ decode_index(corrupt_buffer, decode_buffer_size, &strm,
+ LZMA_DATA_ERROR);
+ corrupt_buffer[0] ^= 1;
+
+ // Corrupt something in the middle of Index
+ corrupt_buffer[decode_buffer_size / 2] ^= 1;
+ assert_lzma_ret(lzma_index_decoder(&strm, &idx, MEMLIMIT),
+ LZMA_OK);
+ decode_index(corrupt_buffer, decode_buffer_size, &strm,
+ LZMA_DATA_ERROR);
+ corrupt_buffer[decode_buffer_size / 2] ^= 1;
+
+ // Corrupt CRC32
+ corrupt_buffer[decode_buffer_size - 1] ^= 1;
+ assert_lzma_ret(lzma_index_decoder(&strm, &idx, MEMLIMIT),
+ LZMA_OK);
+ decode_index(corrupt_buffer, decode_buffer_size, &strm,
+ LZMA_DATA_ERROR);
+ corrupt_buffer[decode_buffer_size - 1] ^= 1;
+
+ // Corrupt Index Padding by setting it to non-zero
+ corrupt_buffer[decode_buffer_size - 5] ^= 1;
+ assert_lzma_ret(lzma_index_decoder(&strm, &idx, MEMLIMIT),
+ LZMA_OK);
+ decode_index(corrupt_buffer, decode_buffer_size, &strm,
+ LZMA_DATA_ERROR);
+ corrupt_buffer[decode_buffer_size - 1] ^= 1;
+
+ lzma_end(&strm);
+#endif
+}
+
+
+static void
+test_lzma_index_buffer_encode(void)
+{
+#if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
+ assert_skip("Encoder or decoder support disabled");
+#else
+ // More simple test than test_lzma_index_encoder() because
+ // currently lzma_index_buffer_encode() is mostly a wrapper
+ // around lzma_index_encoder() anyway.
+ lzma_index *idx = lzma_index_init(NULL);
+ assert_true(idx != NULL);
+
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN, 10), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN * 2, 100), LZMA_OK);
+ assert_lzma_ret(lzma_index_append(idx, NULL,
+ UNPADDED_SIZE_MIN * 3, 1000), LZMA_OK);
+
+ size_t buffer_size = get_index_size(idx);
+ uint8_t *buffer = tuktest_malloc(buffer_size);
+ size_t out_pos = 1;
+
+ // First test bad arguments
+ assert_lzma_ret(lzma_index_buffer_encode(NULL, NULL, NULL, 0),
+ LZMA_PROG_ERROR);
+ assert_lzma_ret(lzma_index_buffer_encode(idx, NULL, NULL, 0),
+ LZMA_PROG_ERROR);
+ assert_lzma_ret(lzma_index_buffer_encode(idx, buffer, NULL, 0),
+ LZMA_PROG_ERROR);
+ assert_lzma_ret(lzma_index_buffer_encode(idx, buffer, &out_pos,
+ 0), LZMA_PROG_ERROR);
+ out_pos = 0;
+ assert_lzma_ret(lzma_index_buffer_encode(idx, buffer, &out_pos,
+ 1), LZMA_BUF_ERROR);
+
+ // Do encoding
+ assert_lzma_ret(lzma_index_buffer_encode(idx, buffer, &out_pos,
+ buffer_size), LZMA_OK);
+ assert_uint_eq(out_pos, buffer_size);
+
+ // Validate results
+ verify_index_buffer(idx, buffer, buffer_size);
+
+ lzma_index_end(idx, NULL);
+#endif
+}
+
+
+static void
+test_lzma_index_buffer_decode(void)
+{
+#ifndef HAVE_DECODERS
+ assert_skip("Decoder support disabled");
+#else
+ if (decode_buffer_size == 0)
+ assert_skip("Could not initialize decode test buffer");
+
+ // Simple test since test_lzma_index_decoder() covers most of the
+ // lzma_index_buffer_decode() code anyway.
+
+ // First test NULL checks
+ assert_lzma_ret(lzma_index_buffer_decode(NULL, NULL, NULL, NULL,
+ NULL, 0), LZMA_PROG_ERROR);
+
+ lzma_index *idx;
+ uint64_t memlimit = MEMLIMIT;
+ size_t in_pos = 0;
+
+ assert_lzma_ret(lzma_index_buffer_decode(&idx, NULL, NULL, NULL,
+ NULL, 0), LZMA_PROG_ERROR);
+
+ assert_lzma_ret(lzma_index_buffer_decode(&idx, &memlimit, NULL,
+ NULL, NULL, 0), LZMA_PROG_ERROR);
+
+ assert_lzma_ret(lzma_index_buffer_decode(&idx, &memlimit, NULL,
+ decode_buffer, NULL, 0), LZMA_PROG_ERROR);
+
+ assert_lzma_ret(lzma_index_buffer_decode(&idx, &memlimit, NULL,
+ decode_buffer, NULL, 0), LZMA_PROG_ERROR);
+
+ assert_lzma_ret(lzma_index_buffer_decode(&idx, &memlimit, NULL,
+ decode_buffer, &in_pos, 0), LZMA_DATA_ERROR);
+
+ in_pos = 1;
+ assert_lzma_ret(lzma_index_buffer_decode(&idx, &memlimit, NULL,
+ decode_buffer, &in_pos, 0), LZMA_PROG_ERROR);
+ in_pos = 0;
+
+ // Test expected successful decode
+ assert_lzma_ret(lzma_index_buffer_decode(&idx, &memlimit, NULL,
+ decode_buffer, &in_pos, decode_buffer_size), LZMA_OK);
+
+ assert_true(index_is_equal(decode_test_index, idx));
+
+ lzma_index_end(idx, NULL);
+
+ // Test too small memlimit
+ in_pos = 0;
+ memlimit = 1;
+ assert_lzma_ret(lzma_index_buffer_decode(&idx, &memlimit, NULL,
+ decode_buffer, &in_pos, decode_buffer_size),
+ LZMA_MEMLIMIT_ERROR);
+ assert_uint(memlimit, >, 1);
+ assert_uint(memlimit, <, MEMLIMIT);
+#endif
+}
+
+
+extern int
+main(int argc, char **argv)
+{
+ tuktest_start(argc, argv);
+ generate_index_decode_buffer();
+ tuktest_run(test_lzma_index_memusage);
+ tuktest_run(test_lzma_index_memused);
+ tuktest_run(test_lzma_index_append);
+ tuktest_run(test_lzma_index_stream_flags);
+ tuktest_run(test_lzma_index_checks);
+ tuktest_run(test_lzma_index_stream_padding);
+ tuktest_run(test_lzma_index_stream_count);
+ tuktest_run(test_lzma_index_block_count);
+ tuktest_run(test_lzma_index_size);
+ tuktest_run(test_lzma_index_stream_size);
+ tuktest_run(test_lzma_index_total_size);
+ tuktest_run(test_lzma_index_file_size);
+ tuktest_run(test_lzma_index_uncompressed_size);
+ tuktest_run(test_lzma_index_iter_init);
+ tuktest_run(test_lzma_index_iter_rewind);
+ tuktest_run(test_lzma_index_iter_next);
+ tuktest_run(test_lzma_index_iter_locate);
+ tuktest_run(test_lzma_index_cat);
+ tuktest_run(test_lzma_index_dup);
+ tuktest_run(test_lzma_index_encoder);
+ tuktest_run(test_lzma_index_decoder);
+ tuktest_run(test_lzma_index_buffer_encode);
+ tuktest_run(test_lzma_index_buffer_decode);
+ lzma_index_end(decode_test_index, NULL);
+ return tuktest_end();
+}
diff --git a/tests/test_index_hash.c b/tests/test_index_hash.c
new file mode 100644
index 0000000..f3c6e8f
--- /dev/null
+++ b/tests/test_index_hash.c
@@ -0,0 +1,386 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file test_index_hash.c
+/// \brief Tests src/liblzma/common/index_hash.c API functions
+///
+/// \note No test included for lzma_index_hash_end since it
+/// would be trivial unless tested for memory leaks
+/// with something like valgrind
+//
+// Author: Jia Tan
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tests.h"
+
+// Needed for UNPADDED_SIZE_MIN and UNPADDED_SIZE_MAX macro definitions
+// and index_size and vli_ceil4 helper functions
+#include "common/index.h"
+
+
+static void
+test_lzma_index_hash_init(void)
+{
+#ifndef HAVE_DECODERS
+ assert_skip("Decoder support disabled");
+#else
+ // First test with NULL index_hash.
+ // This should create a fresh index_hash.
+ lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL);
+ assert_true(index_hash != NULL);
+
+ // Next test with non-NULL index_hash.
+ lzma_index_hash *second_hash = lzma_index_hash_init(index_hash, NULL);
+
+ // It should not create a new index_hash pointer.
+ // Instead it must just re-init the first index_hash.
+ assert_true(index_hash == second_hash);
+
+ lzma_index_hash_end(index_hash, NULL);
+#endif
+}
+
+
+static void
+test_lzma_index_hash_append(void)
+{
+#ifndef HAVE_DECODERS
+ assert_skip("Decoder support disabled");
+#else
+ // Test all invalid parameters
+ assert_lzma_ret(lzma_index_hash_append(NULL, 0, 0),
+ LZMA_PROG_ERROR);
+
+ // Test NULL index_hash
+ assert_lzma_ret(lzma_index_hash_append(NULL, UNPADDED_SIZE_MIN,
+ LZMA_VLI_MAX), LZMA_PROG_ERROR);
+
+ // Test with invalid Unpadded Size
+ lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL);
+ assert_true(index_hash != NULL);
+ assert_lzma_ret(lzma_index_hash_append(index_hash,
+ UNPADDED_SIZE_MIN - 1, LZMA_VLI_MAX),
+ LZMA_PROG_ERROR);
+
+ // Test with invalid Uncompressed Size
+ assert_lzma_ret(lzma_index_hash_append(index_hash,
+ UNPADDED_SIZE_MIN, LZMA_VLI_MAX + 1),
+ LZMA_PROG_ERROR);
+
+ // First append a Record describing a small Block.
+ // This should succeed.
+ assert_lzma_ret(lzma_index_hash_append(index_hash,
+ UNPADDED_SIZE_MIN, 1), LZMA_OK);
+
+ // Append another small Record.
+ assert_lzma_ret(lzma_index_hash_append(index_hash,
+ UNPADDED_SIZE_MIN, 1), LZMA_OK);
+
+ // Append a Record that would cause the compressed size to grow
+ // too big
+ assert_lzma_ret(lzma_index_hash_append(index_hash,
+ UNPADDED_SIZE_MAX, 1), LZMA_DATA_ERROR);
+
+ lzma_index_hash_end(index_hash, NULL);
+#endif
+}
+
+
+#if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
+// Fill an index_hash with unpadded and uncompressed VLIs
+// by calling lzma_index_hash_append
+static void
+fill_index_hash(lzma_index_hash *index_hash, const lzma_vli *unpadded_sizes,
+ const lzma_vli *uncomp_sizes, uint32_t block_count)
+{
+ for (uint32_t i = 0; i < block_count; ++i)
+ assert_lzma_ret(lzma_index_hash_append(index_hash,
+ unpadded_sizes[i], uncomp_sizes[i]), LZMA_OK);
+}
+
+
+// Set the contents of buf to the expected Index based on the
+// .xz specification. This needs the unpadded and uncompressed VLIs
+// to correctly create the Index.
+static void
+generate_index(uint8_t *buf, const lzma_vli *unpadded_sizes,
+ const lzma_vli *uncomp_sizes, uint32_t block_count,
+ size_t index_max_size)
+{
+ size_t in_pos = 0;
+ size_t out_pos = 0;
+
+ // First set Index Indicator
+ buf[out_pos++] = INDEX_INDICATOR;
+
+ // Next write out Number of Records
+ assert_lzma_ret(lzma_vli_encode(block_count, &in_pos, buf,
+ &out_pos, index_max_size), LZMA_STREAM_END);
+
+ // Next write out each Record.
+ // A Record consists of Unpadded Size and Uncompressed Size
+ // written next to each other as VLIs.
+ for (uint32_t i = 0; i < block_count; ++i) {
+ in_pos = 0;
+ assert_lzma_ret(lzma_vli_encode(unpadded_sizes[i], &in_pos,
+ buf, &out_pos, index_max_size), LZMA_STREAM_END);
+ in_pos = 0;
+ assert_lzma_ret(lzma_vli_encode(uncomp_sizes[i], &in_pos,
+ buf, &out_pos, index_max_size), LZMA_STREAM_END);
+ }
+
+ // Add Index Padding
+ lzma_vli rounded_out_pos = vli_ceil4(out_pos);
+ memzero(buf + out_pos, rounded_out_pos - out_pos);
+ out_pos = rounded_out_pos;
+
+ // Add the CRC32
+ write32le(buf + out_pos, lzma_crc32(buf, out_pos, 0));
+ out_pos += 4;
+
+ assert_uint_eq(out_pos, index_max_size);
+}
+#endif
+
+
+static void
+test_lzma_index_hash_decode(void)
+{
+#if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
+ assert_skip("Encoder or decoder support disabled");
+#else
+ lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL);
+ assert_true(index_hash != NULL);
+
+ size_t in_pos = 0;
+
+ // Six valid values for the Unpadded Size fields in an Index
+ const lzma_vli unpadded_sizes[6] = {
+ UNPADDED_SIZE_MIN,
+ 1000,
+ 4000,
+ 8000,
+ 16000,
+ 32000
+ };
+
+ // Six valid values for the Uncompressed Size fields in an Index
+ const lzma_vli uncomp_sizes[6] = {
+ 1,
+ 500,
+ 8000,
+ 20,
+ 1,
+ 500
+ };
+
+ // Add two Records to an index_hash
+ fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 2);
+
+ const lzma_vli size_two_records = lzma_index_hash_size(index_hash);
+ assert_uint(size_two_records, >, 0);
+ uint8_t *index_two_records = tuktest_malloc(size_two_records);
+
+ generate_index(index_two_records, unpadded_sizes, uncomp_sizes, 2,
+ size_two_records);
+
+ // First test for basic buffer size error
+ in_pos = size_two_records + 1;
+ assert_lzma_ret(lzma_index_hash_decode(index_hash,
+ index_two_records, &in_pos,
+ size_two_records), LZMA_BUF_ERROR);
+
+ // Next test for invalid Index Indicator
+ in_pos = 0;
+ index_two_records[0] ^= 1;
+ assert_lzma_ret(lzma_index_hash_decode(index_hash,
+ index_two_records, &in_pos,
+ size_two_records), LZMA_DATA_ERROR);
+ index_two_records[0] ^= 1;
+
+ // Next verify the index_hash as expected
+ in_pos = 0;
+ assert_lzma_ret(lzma_index_hash_decode(index_hash,
+ index_two_records, &in_pos,
+ size_two_records), LZMA_STREAM_END);
+
+ // Next test an index_hash with three Records
+ index_hash = lzma_index_hash_init(index_hash, NULL);
+ fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 3);
+
+ const lzma_vli size_three_records = lzma_index_hash_size(
+ index_hash);
+ assert_uint(size_three_records, >, 0);
+ uint8_t *index_three_records = tuktest_malloc(size_three_records);
+
+ generate_index(index_three_records, unpadded_sizes, uncomp_sizes,
+ 3, size_three_records);
+
+ in_pos = 0;
+ assert_lzma_ret(lzma_index_hash_decode(index_hash,
+ index_three_records, &in_pos,
+ size_three_records), LZMA_STREAM_END);
+
+ // Next test an index_hash with five Records
+ index_hash = lzma_index_hash_init(index_hash, NULL);
+ fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 5);
+
+ const lzma_vli size_five_records = lzma_index_hash_size(
+ index_hash);
+ assert_uint(size_five_records, >, 0);
+ uint8_t *index_five_records = tuktest_malloc(size_five_records);
+
+ generate_index(index_five_records, unpadded_sizes, uncomp_sizes, 5,
+ size_five_records);
+
+ // Instead of testing all input at once, give input
+ // one byte at a time
+ in_pos = 0;
+ for (lzma_vli i = 0; i < size_five_records - 1; ++i) {
+ assert_lzma_ret(lzma_index_hash_decode(index_hash,
+ index_five_records, &in_pos, in_pos + 1),
+ LZMA_OK);
+ }
+
+ // Last byte should return LZMA_STREAM_END
+ assert_lzma_ret(lzma_index_hash_decode(index_hash,
+ index_five_records, &in_pos,
+ in_pos + 1), LZMA_STREAM_END);
+
+ // Next test if the index_hash is given an incorrect Unpadded
+ // Size. Should detect and report LZMA_DATA_ERROR
+ index_hash = lzma_index_hash_init(index_hash, NULL);
+ fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 5);
+ // The sixth Record will have an invalid Unpadded Size
+ assert_lzma_ret(lzma_index_hash_append(index_hash,
+ unpadded_sizes[5] + 1,
+ uncomp_sizes[5]), LZMA_OK);
+
+ const lzma_vli size_six_records = lzma_index_hash_size(
+ index_hash);
+
+ assert_uint(size_six_records, >, 0);
+ uint8_t *index_six_records = tuktest_malloc(size_six_records);
+
+ generate_index(index_six_records, unpadded_sizes, uncomp_sizes, 6,
+ size_six_records);
+ in_pos = 0;
+ assert_lzma_ret(lzma_index_hash_decode(index_hash,
+ index_six_records, &in_pos,
+ size_six_records), LZMA_DATA_ERROR);
+
+ // Next test if the Index is corrupt (invalid CRC32).
+ // Should detect and report LZMA_DATA_ERROR
+ index_hash = lzma_index_hash_init(index_hash, NULL);
+ fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 2);
+
+ index_two_records[size_two_records - 1] ^= 1;
+
+ in_pos = 0;
+ assert_lzma_ret(lzma_index_hash_decode(index_hash,
+ index_two_records, &in_pos,
+ size_two_records), LZMA_DATA_ERROR);
+
+ // Next test with Index and index_hash struct not matching
+ // a Record
+ index_hash = lzma_index_hash_init(index_hash, NULL);
+ fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 2);
+ // Recalculate Index with invalid Unpadded Size
+ const lzma_vli unpadded_sizes_invalid[2] = {
+ unpadded_sizes[0],
+ unpadded_sizes[1] + 1
+ };
+
+ generate_index(index_two_records, unpadded_sizes_invalid,
+ uncomp_sizes, 2, size_two_records);
+
+ in_pos = 0;
+ assert_lzma_ret(lzma_index_hash_decode(index_hash,
+ index_two_records, &in_pos,
+ size_two_records), LZMA_DATA_ERROR);
+
+ lzma_index_hash_end(index_hash, NULL);
+#endif
+}
+
+
+static void
+test_lzma_index_hash_size(void)
+{
+#ifndef HAVE_DECODERS
+ assert_skip("Decoder support disabled");
+#else
+ lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL);
+ assert_true(index_hash != NULL);
+
+ // First test empty index_hash
+ // Expected size should be:
+ // Index Indicator - 1 byte
+ // Number of Records - 1 byte
+ // List of Records - 0 bytes
+ // Index Padding - 2 bytes
+ // CRC32 - 4 bytes
+ // Total - 8 bytes
+ assert_uint_eq(lzma_index_hash_size(index_hash), 8);
+
+ // Append a Record describing a small Block to the index_hash
+ assert_lzma_ret(lzma_index_hash_append(index_hash,
+ UNPADDED_SIZE_MIN, 1), LZMA_OK);
+
+ // Expected size should be:
+ // Index Indicator - 1 byte
+ // Number of Records - 1 byte
+ // List of Records - 2 bytes
+ // Index Padding - 0 bytes
+ // CRC32 - 4 bytes
+ // Total - 8 bytes
+ lzma_vli expected_size = 8;
+ assert_uint_eq(lzma_index_hash_size(index_hash), expected_size);
+
+ // Append additional small Record
+ assert_lzma_ret(lzma_index_hash_append(index_hash,
+ UNPADDED_SIZE_MIN, 1), LZMA_OK);
+
+ // Expected size should be:
+ // Index Indicator - 1 byte
+ // Number of Records - 1 byte
+ // List of Records - 4 bytes
+ // Index Padding - 2 bytes
+ // CRC32 - 4 bytes
+ // Total - 12 bytes
+ expected_size = 12;
+ assert_uint_eq(lzma_index_hash_size(index_hash), expected_size);
+
+ // Append a larger Record to the index_hash (3 bytes for each VLI)
+ const lzma_vli three_byte_vli = 0x10000;
+ assert_lzma_ret(lzma_index_hash_append(index_hash,
+ three_byte_vli, three_byte_vli), LZMA_OK);
+
+ // Expected size should be:
+ // Index Indicator - 1 byte
+ // Number of Records - 1 byte
+ // List of Records - 10 bytes
+ // Index Padding - 0 bytes
+ // CRC32 - 4 bytes
+ // Total - 16 bytes
+ expected_size = 16;
+ assert_uint_eq(lzma_index_hash_size(index_hash), expected_size);
+
+ lzma_index_hash_end(index_hash, NULL);
+#endif
+}
+
+
+extern int
+main(int argc, char **argv)
+{
+ tuktest_start(argc, argv);
+ tuktest_run(test_lzma_index_hash_init);
+ tuktest_run(test_lzma_index_hash_append);
+ tuktest_run(test_lzma_index_hash_decode);
+ tuktest_run(test_lzma_index_hash_size);
+ return tuktest_end();
+}
diff --git a/tests/test_lzip_decoder.c b/tests/test_lzip_decoder.c
new file mode 100644
index 0000000..3743d43
--- /dev/null
+++ b/tests/test_lzip_decoder.c
@@ -0,0 +1,488 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file test_lzip_decoder.c
+/// \brief Tests decoding lzip data
+//
+// Author: Jia Tan
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tests.h"
+
+#ifdef HAVE_LZIP_DECODER
+
+// Memlimit large enough to pass all of the test files
+#define MEMLIMIT (1U << 20)
+#define DECODE_CHUNK_SIZE 1024
+
+
+// The uncompressed data in the test files are short US-ASCII strings.
+// The tests check if the decompressed output is what it is expected to be.
+// Storing the strings here as text would break the tests on EBCDIC systems
+// and storing the strings as an array of hex values is inconvenient, so
+// store the CRC32 values of the expected data instead.
+//
+// CRC32 value of "Hello\nWorld\n"
+static const uint32_t hello_world_crc = 0x15A2A343;
+
+// CRC32 value of "Trailing garbage\n"
+static const uint32_t trailing_garbage_crc = 0x87081A60;
+
+
+// Helper function to decode a good file with no flags and plenty high memlimit
+static void
+basic_lzip_decode(const char *src, const uint32_t expected_crc)
+{
+ size_t file_size;
+ uint8_t *data = tuktest_file_from_srcdir(src, &file_size);
+ uint32_t checksum = 0;
+
+ lzma_stream strm = LZMA_STREAM_INIT;
+ assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT, 0), LZMA_OK);
+
+ uint8_t *output_buffer = tuktest_malloc(DECODE_CHUNK_SIZE);
+
+ strm.next_in = data;
+ strm.next_out = output_buffer;
+ strm.avail_out = DECODE_CHUNK_SIZE;
+
+ // Feed 1 byte at a time to the decoder to look for any bugs
+ // when switching between decoding sequences
+ lzma_ret ret = LZMA_OK;
+ while (ret == LZMA_OK) {
+ strm.avail_in = 1;
+ ret = lzma_code(&strm, LZMA_RUN);
+ if (strm.avail_out == 0) {
+ checksum = lzma_crc32(output_buffer,
+ (size_t)(strm.next_out - output_buffer),
+ checksum);
+ // No need to free output_buffer because it will
+ // automatically be freed at the end of the test by
+ // tuktest.
+ output_buffer = tuktest_malloc(DECODE_CHUNK_SIZE);
+ strm.next_out = output_buffer;
+ strm.avail_out = DECODE_CHUNK_SIZE;
+ }
+ }
+
+ assert_lzma_ret(ret, LZMA_STREAM_END);
+ assert_uint_eq(strm.total_in, file_size);
+
+ checksum = lzma_crc32(output_buffer,
+ (size_t)(strm.next_out - output_buffer),
+ checksum);
+ assert_uint_eq(checksum, expected_crc);
+
+ lzma_end(&strm);
+}
+
+
+static void
+test_options(void)
+{
+ // Test NULL stream
+ assert_lzma_ret(lzma_lzip_decoder(NULL, MEMLIMIT, 0),
+ LZMA_PROG_ERROR);
+
+ // Test invalid flags
+ lzma_stream strm = LZMA_STREAM_INIT;
+ assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT, UINT32_MAX),
+ LZMA_OPTIONS_ERROR);
+ // Memlimit tests are done elsewhere
+}
+
+
+static void
+test_v0_decode(void)
+{
+ // This tests if liblzma can decode lzip version 0 files.
+ // lzip 1.17 and older can decompress this, but lzip 1.18
+ // and newer can no longer decode these files.
+ basic_lzip_decode("files/good-1-v0.lz", hello_world_crc);
+}
+
+
+static void
+test_v1_decode(void)
+{
+ // This tests decoding a basic lzip v1 file
+ basic_lzip_decode("files/good-1-v1.lz", hello_world_crc);
+}
+
+
+// Helper function to decode a good file with trailing bytes after
+// the lzip stream
+static void
+trailing_helper(const char *src, const uint32_t expected_data_checksum,
+ const uint32_t expected_trailing_checksum)
+{
+ size_t file_size;
+ uint32_t checksum = 0;
+ uint8_t *data = tuktest_file_from_srcdir(src, &file_size);
+ lzma_stream strm = LZMA_STREAM_INIT;
+ assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
+ LZMA_CONCATENATED), LZMA_OK);
+
+ uint8_t *output_buffer = tuktest_malloc(DECODE_CHUNK_SIZE);
+
+ strm.next_in = data;
+ strm.next_out = output_buffer;
+ strm.avail_in = file_size;
+ strm.avail_out = DECODE_CHUNK_SIZE;
+
+ lzma_ret ret = LZMA_OK;
+ while (ret == LZMA_OK) {
+ ret = lzma_code(&strm, LZMA_RUN);
+ if (strm.avail_out == 0) {
+ checksum = lzma_crc32(output_buffer,
+ (size_t)(strm.next_out - output_buffer),
+ checksum);
+ // No need to free output_buffer because it will
+ // automatically be freed at the end of the test by
+ // tuktest.
+ output_buffer = tuktest_malloc(DECODE_CHUNK_SIZE);
+ strm.next_out = output_buffer;
+ strm.avail_out = DECODE_CHUNK_SIZE;
+ }
+ }
+
+ assert_lzma_ret(ret, LZMA_STREAM_END);
+ assert_uint(strm.total_in, <, file_size);
+
+ checksum = lzma_crc32(output_buffer,
+ (size_t)(strm.next_out - output_buffer),
+ checksum);
+
+ assert_uint_eq(checksum, expected_data_checksum);
+
+ // Trailing data should be readable from strm.next_in
+ checksum = lzma_crc32(strm.next_in, strm.avail_in, 0);
+ assert_uint_eq(checksum, expected_trailing_checksum);
+
+ lzma_end(&strm);
+}
+
+
+// Helper function to decode a bad file and compare to returned error to
+// what the caller expects
+static void
+decode_expect_error(const char *src, lzma_ret expected_error)
+{
+ lzma_stream strm = LZMA_STREAM_INIT;
+ size_t file_size;
+ uint8_t *data = tuktest_file_from_srcdir(src, &file_size);
+
+ assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
+ LZMA_CONCATENATED), LZMA_OK);
+
+ uint8_t output_buffer[DECODE_CHUNK_SIZE];
+
+ strm.avail_in = file_size;
+ strm.next_in = data;
+ strm.avail_out = DECODE_CHUNK_SIZE;
+ strm.next_out = output_buffer;
+
+ lzma_ret ret = LZMA_OK;
+
+ while (ret == LZMA_OK) {
+ // Discard output since we are only looking for errors
+ strm.next_out = output_buffer;
+ strm.avail_out = DECODE_CHUNK_SIZE;
+ if (strm.avail_in == 0)
+ ret = lzma_code(&strm, LZMA_FINISH);
+ else
+ ret = lzma_code(&strm, LZMA_RUN);
+ }
+
+ assert_lzma_ret(ret, expected_error);
+ lzma_end(&strm);
+}
+
+
+static void
+test_v0_trailing(void)
+{
+ trailing_helper("files/good-1-v0-trailing-1.lz", hello_world_crc,
+ trailing_garbage_crc);
+}
+
+
+static void
+test_v1_trailing(void)
+{
+ trailing_helper("files/good-1-v1-trailing-1.lz", hello_world_crc,
+ trailing_garbage_crc);
+
+ // The second files/good-1-v1-trailing-2.lz will have the same
+ // expected output and trailing output as
+ // files/good-1-v1-trailing-1.lz, but this tests if the prefix
+ // to the trailing data contains lzip magic bytes.
+ // When this happens, the expected behavior is to silently ignore
+ // the magic byte prefix and consume it from the input file.
+ trailing_helper("files/good-1-v1-trailing-2.lz", hello_world_crc,
+ trailing_garbage_crc);
+
+ // Expect LZMA_BUF error if a file ends with the lzip magic bytes
+ // but does not contain any data after
+ decode_expect_error("files/bad-1-v1-trailing-magic.lz",
+ LZMA_BUF_ERROR);
+}
+
+
+static void
+test_concatentated(void)
+{
+ // First test a file with one v0 member and one v1 member
+ // The first member should contain "Hello\n" and
+ // the second member should contain "World!\n"
+
+ lzma_stream strm = LZMA_STREAM_INIT;
+ size_t file_size;
+ uint8_t *v0_v1 = tuktest_file_from_srcdir("files/good-2-v0-v1.lz",
+ &file_size);
+
+ assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
+ LZMA_CONCATENATED), LZMA_OK);
+
+ uint8_t output_buffer[DECODE_CHUNK_SIZE];
+
+ strm.avail_in = file_size;
+ strm.next_in = v0_v1;
+ strm.avail_out = DECODE_CHUNK_SIZE;
+ strm.next_out = output_buffer;
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
+
+ assert_uint_eq(strm.total_in, file_size);
+
+ uint32_t checksum = lzma_crc32(output_buffer, strm.total_out, 0);
+ assert_uint_eq(checksum, hello_world_crc);
+
+ // The second file contains one v1 member and one v2 member
+ uint8_t *v1_v0 = tuktest_file_from_srcdir("files/good-2-v1-v0.lz",
+ &file_size);
+
+ assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
+ LZMA_CONCATENATED), LZMA_OK);
+
+ strm.avail_in = file_size;
+ strm.next_in = v1_v0;
+ strm.avail_out = DECODE_CHUNK_SIZE;
+ strm.next_out = output_buffer;
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
+
+ assert_uint_eq(strm.total_in, file_size);
+ checksum = lzma_crc32(output_buffer, strm.total_out, 0);
+ assert_uint_eq(checksum, hello_world_crc);
+
+ // The third file contains 2 v1 members
+ uint8_t *v1_v1 = tuktest_file_from_srcdir("files/good-2-v1-v1.lz",
+ &file_size);
+
+ assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
+ LZMA_CONCATENATED), LZMA_OK);
+
+ strm.avail_in = file_size;
+ strm.next_in = v1_v1;
+ strm.avail_out = DECODE_CHUNK_SIZE;
+ strm.next_out = output_buffer;
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
+
+ assert_uint_eq(strm.total_in, file_size);
+ checksum = lzma_crc32(output_buffer, strm.total_out, 0);
+ assert_uint_eq(checksum, hello_world_crc);
+
+ lzma_end(&strm);
+}
+
+
+static void
+test_crc(void)
+{
+ // Test invalid checksum
+ lzma_stream strm = LZMA_STREAM_INIT;
+ size_t file_size;
+ uint8_t *data = tuktest_file_from_srcdir("files/bad-1-v1-crc32.lz",
+ &file_size);
+
+ assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
+ LZMA_CONCATENATED), LZMA_OK);
+
+ uint8_t output_buffer[DECODE_CHUNK_SIZE];
+
+ strm.avail_in = file_size;
+ strm.next_in = data;
+ strm.avail_out = DECODE_CHUNK_SIZE;
+ strm.next_out = output_buffer;
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_DATA_ERROR);
+
+ // Test ignoring the checksum value - should decode successfully
+ assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
+ LZMA_CONCATENATED | LZMA_IGNORE_CHECK), LZMA_OK);
+
+ strm.avail_in = file_size;
+ strm.next_in = data;
+ strm.avail_out = DECODE_CHUNK_SIZE;
+ strm.next_out = output_buffer;
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
+ assert_uint_eq(strm.total_in, file_size);
+
+ // Test tell check
+ assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT,
+ LZMA_CONCATENATED | LZMA_TELL_ANY_CHECK), LZMA_OK);
+
+ strm.avail_in = file_size;
+ strm.next_in = data;
+ strm.avail_out = DECODE_CHUNK_SIZE;
+ strm.next_out = output_buffer;
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_GET_CHECK);
+ assert_uint_eq(lzma_get_check(&strm), LZMA_CHECK_CRC32);
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_DATA_ERROR);
+ lzma_end(&strm);
+}
+
+
+static void
+test_invalid_magic_bytes(void)
+{
+ uint8_t lzip_id_string[] = { 0x4C, 0x5A, 0x49, 0x50 };
+ lzma_stream strm = LZMA_STREAM_INIT;
+
+ for (uint32_t i = 0; i < ARRAY_SIZE(lzip_id_string); i++) {
+ // Corrupt magic bytes
+ lzip_id_string[i] ^= 1;
+ uint8_t output_buffer[DECODE_CHUNK_SIZE];
+
+ assert_lzma_ret(lzma_lzip_decoder(&strm, MEMLIMIT, 0),
+ LZMA_OK);
+
+ strm.next_in = lzip_id_string;
+ strm.avail_in = sizeof(lzip_id_string);
+ strm.next_out = output_buffer;
+ strm.avail_out = DECODE_CHUNK_SIZE;
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_RUN),
+ LZMA_FORMAT_ERROR);
+
+ // Reset magic bytes
+ lzip_id_string[i] ^= 1;
+ }
+
+ lzma_end(&strm);
+}
+
+
+static void
+test_invalid_version(void)
+{
+ // The file contains a version number that is not 0 or 1,
+ // so it should cause an error
+ decode_expect_error("files/unsupported-1-v234.lz",
+ LZMA_OPTIONS_ERROR);
+}
+
+
+static void
+test_invalid_dictionary_size(void)
+{
+ // First file has too small dictionary size field
+ decode_expect_error("files/bad-1-v1-dict-1.lz", LZMA_DATA_ERROR);
+
+ // Second file has too large dictionary size field
+ decode_expect_error("files/bad-1-v1-dict-2.lz", LZMA_DATA_ERROR);
+}
+
+
+static void
+test_invalid_uncomp_size(void)
+{
+ // Test invalid v0 lzip file uncomp size
+ decode_expect_error("files/bad-1-v0-uncomp-size.lz",
+ LZMA_DATA_ERROR);
+
+ // Test invalid v1 lzip file uncomp size
+ decode_expect_error("files/bad-1-v1-uncomp-size.lz",
+ LZMA_DATA_ERROR);
+}
+
+
+static void
+test_invalid_member_size(void)
+{
+ decode_expect_error("files/bad-1-v1-member-size.lz",
+ LZMA_DATA_ERROR);
+}
+
+
+static void
+test_invalid_memlimit(void)
+{
+ // A very low memlimit should prevent decoding.
+ // Should be able to update the memlimit after failing
+ size_t file_size;
+ uint8_t *data = tuktest_file_from_srcdir("files/good-1-v1.lz",
+ &file_size);
+
+ uint8_t output_buffer[DECODE_CHUNK_SIZE];
+
+ lzma_stream strm = LZMA_STREAM_INIT;
+
+ assert_lzma_ret(lzma_lzip_decoder(&strm, 1, 0), LZMA_OK);
+
+ strm.next_in = data;
+ strm.avail_in = file_size;
+ strm.next_out = output_buffer;
+ strm.avail_out = DECODE_CHUNK_SIZE;
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_MEMLIMIT_ERROR);
+
+ // Up the memlimit so decoding can continue.
+ // First only increase by a small amount and expect an error
+ assert_lzma_ret(lzma_memlimit_set(&strm, 100), LZMA_MEMLIMIT_ERROR);
+ assert_lzma_ret(lzma_memlimit_set(&strm, MEMLIMIT), LZMA_OK);
+
+ // Finish decoding
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
+
+ assert_uint_eq(strm.total_in, file_size);
+ uint32_t checksum = lzma_crc32(output_buffer, strm.total_out, 0);
+ assert_uint_eq(checksum, hello_world_crc);
+
+ lzma_end(&strm);
+}
+#endif
+
+
+extern int
+main(int argc, char **argv)
+{
+ tuktest_start(argc, argv);
+
+#ifndef HAVE_LZIP_DECODER
+ tuktest_early_skip("lzip decoder disabled");
+#else
+ tuktest_run(test_options);
+ tuktest_run(test_v0_decode);
+ tuktest_run(test_v1_decode);
+ tuktest_run(test_v0_trailing);
+ tuktest_run(test_v1_trailing);
+ tuktest_run(test_concatentated);
+ tuktest_run(test_crc);
+ tuktest_run(test_invalid_magic_bytes);
+ tuktest_run(test_invalid_version);
+ tuktest_run(test_invalid_dictionary_size);
+ tuktest_run(test_invalid_uncomp_size);
+ tuktest_run(test_invalid_member_size);
+ tuktest_run(test_invalid_memlimit);
+ return tuktest_end();
+#endif
+
+}
diff --git a/tests/test_memlimit.c b/tests/test_memlimit.c
new file mode 100644
index 0000000..c45a44b
--- /dev/null
+++ b/tests/test_memlimit.c
@@ -0,0 +1,173 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file test_memlimit.c
+/// \brief Tests memory usage limit in decoders
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tests.h"
+#include "mythread.h"
+
+
+#define MEMLIMIT_TOO_LOW 1234U
+#define MEMLIMIT_HIGH_ENOUGH (2U << 20)
+
+
+static uint8_t *in;
+static size_t in_size;
+
+#ifdef HAVE_DECODERS
+static uint8_t out[8192];
+#endif
+
+
+static void
+test_memlimit_stream_decoder(void)
+{
+#ifndef HAVE_DECODERS
+ assert_skip("Decoder support disabled");
+#else
+ lzma_stream strm = LZMA_STREAM_INIT;
+ assert_lzma_ret(lzma_stream_decoder(&strm, MEMLIMIT_TOO_LOW, 0),
+ LZMA_OK);
+
+ strm.next_in = in;
+ strm.avail_in = in_size;
+ strm.next_out = out;
+ strm.avail_out = sizeof(out);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_MEMLIMIT_ERROR);
+
+ assert_uint_eq(lzma_memlimit_get(&strm), MEMLIMIT_TOO_LOW);
+ assert_lzma_ret(lzma_memlimit_set(&strm, MEMLIMIT_TOO_LOW + 1),
+ LZMA_MEMLIMIT_ERROR);
+ assert_lzma_ret(lzma_memlimit_set(&strm, MEMLIMIT_HIGH_ENOUGH),
+ LZMA_OK);
+
+ // This fails before commit 660739f99ab211edec4071de98889fb32ed04e98
+ // (liblzma <= 5.2.6, liblzma <= 5.3.3alpha). It was fixed in 5.2.7.
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
+
+ lzma_end(&strm);
+#endif
+}
+
+
+static void
+test_memlimit_stream_decoder_mt(void)
+{
+#ifndef MYTHREAD_ENABLED
+ assert_skip("Threading support disabled");
+#elif !defined(HAVE_DECODERS)
+ assert_skip("Decoder support disabled");
+#else
+ lzma_stream strm = LZMA_STREAM_INIT;
+ lzma_mt mt = {
+ .flags = 0,
+ .threads = 1,
+ .timeout = 0,
+ .memlimit_threading = 0,
+ .memlimit_stop = MEMLIMIT_TOO_LOW,
+ };
+
+ assert_lzma_ret(lzma_stream_decoder_mt(&strm, &mt), LZMA_OK);
+
+ strm.next_in = in;
+ strm.avail_in = in_size;
+ strm.next_out = out;
+ strm.avail_out = sizeof(out);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_MEMLIMIT_ERROR);
+
+ assert_uint_eq(lzma_memlimit_get(&strm), MEMLIMIT_TOO_LOW);
+ assert_lzma_ret(lzma_memlimit_set(&strm, MEMLIMIT_TOO_LOW + 1),
+ LZMA_MEMLIMIT_ERROR);
+ assert_lzma_ret(lzma_memlimit_set(&strm, MEMLIMIT_HIGH_ENOUGH),
+ LZMA_OK);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
+ lzma_end(&strm);
+#endif
+}
+
+
+static void
+test_memlimit_alone_decoder(void)
+{
+#ifndef HAVE_DECODERS
+ assert_skip("Decoder support disabled");
+#else
+ size_t alone_size;
+ uint8_t *alone_buf = tuktest_file_from_srcdir(
+ "files/good-unknown_size-with_eopm.lzma", &alone_size);
+
+ lzma_stream strm = LZMA_STREAM_INIT;
+ assert_lzma_ret(lzma_alone_decoder(&strm, MEMLIMIT_TOO_LOW), LZMA_OK);
+
+ strm.next_in = alone_buf;
+ strm.avail_in = alone_size;
+ strm.next_out = out;
+ strm.avail_out = sizeof(out);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_MEMLIMIT_ERROR);
+
+ assert_uint_eq(lzma_memlimit_get(&strm), MEMLIMIT_TOO_LOW);
+ assert_lzma_ret(lzma_memlimit_set(&strm, MEMLIMIT_TOO_LOW + 1),
+ LZMA_MEMLIMIT_ERROR);
+ assert_lzma_ret(lzma_memlimit_set(&strm, MEMLIMIT_HIGH_ENOUGH),
+ LZMA_OK);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
+ lzma_end(&strm);
+#endif
+}
+
+
+static void
+test_memlimit_auto_decoder(void)
+{
+#ifndef HAVE_DECODERS
+ assert_skip("Decoder support disabled");
+#else
+ lzma_stream strm = LZMA_STREAM_INIT;
+ assert_lzma_ret(lzma_auto_decoder(&strm, MEMLIMIT_TOO_LOW, 0),
+ LZMA_OK);
+
+ strm.next_in = in;
+ strm.avail_in = in_size;
+ strm.next_out = out;
+ strm.avail_out = sizeof(out);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_MEMLIMIT_ERROR);
+
+ assert_uint_eq(lzma_memlimit_get(&strm), MEMLIMIT_TOO_LOW);
+ assert_lzma_ret(lzma_memlimit_set(&strm, MEMLIMIT_TOO_LOW + 1),
+ LZMA_MEMLIMIT_ERROR);
+ assert_lzma_ret(lzma_memlimit_set(&strm, MEMLIMIT_HIGH_ENOUGH),
+ LZMA_OK);
+
+ assert_lzma_ret(lzma_code(&strm, LZMA_FINISH), LZMA_STREAM_END);
+ lzma_end(&strm);
+#endif
+}
+
+
+extern int
+main(int argc, char **argv)
+{
+ tuktest_start(argc, argv);
+
+ in = tuktest_file_from_srcdir("files/good-1-check-crc32.xz", &in_size);
+
+ tuktest_run(test_memlimit_stream_decoder);
+ tuktest_run(test_memlimit_stream_decoder_mt);
+ tuktest_run(test_memlimit_alone_decoder);
+ tuktest_run(test_memlimit_auto_decoder);
+
+ return tuktest_end();
+}
diff --git a/tests/test_scripts.sh b/tests/test_scripts.sh
new file mode 100755
index 0000000..ee82361
--- /dev/null
+++ b/tests/test_scripts.sh
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+###############################################################################
+#
+# Author: Jonathan Nieder
+#
+# This file has been put into the public domain.
+# You can do whatever you want with this file.
+#
+###############################################################################
+
+# If scripts weren't built, this test is skipped.
+XZ=../src/xz/xz
+XZDIFF=../src/scripts/xzdiff
+XZGREP=../src/scripts/xzgrep
+
+for i in XZ XZDIFF XZGREP; do
+ eval test -x "\$$i" && continue
+ exit 77
+done
+
+# If decompression support is missing, this test is skipped.
+# Installing the scripts in this case is a bit silly but they
+# could still be used with other decompression tools so configure
+# doesn't automatically disable scripts if decoders are disabled.
+if grep 'define HAVE_DECODERS' ../config.h > /dev/null ; then
+ :
+else
+ echo "Decompression support is disabled, skipping this test."
+ exit 77
+fi
+
+PATH=`pwd`/../src/xz:$PATH
+export PATH
+
+test -z "$srcdir" && srcdir=.
+preimage=$srcdir/files/good-1-check-crc32.xz
+samepostimage=$srcdir/files/good-1-check-crc64.xz
+otherpostimage=$srcdir/files/good-1-lzma2-1.xz
+
+"$XZDIFF" "$preimage" "$samepostimage" >/dev/null
+status=$?
+if test "$status" != 0 ; then
+ echo "xzdiff with no changes exited with status $status != 0"
+ exit 1
+fi
+
+"$XZDIFF" "$preimage" "$otherpostimage" >/dev/null
+status=$?
+if test "$status" != 1 ; then
+ echo "xzdiff with changes exited with status $status != 1"
+ exit 1
+fi
+
+"$XZDIFF" "$preimage" "$srcdir/files/missing.xz" >/dev/null 2>&1
+status=$?
+if test "$status" != 2 ; then
+ echo "xzdiff with missing operand exited with status $status != 2"
+ exit 1
+fi
+
+# The exit status must be 0 when a match was found at least from one file,
+# and 1 when no match was found in any file.
+cp "$srcdir/files/good-1-lzma2-1.xz" xzgrep_test_1.xz
+cp "$srcdir/files/good-2-lzma2.xz" xzgrep_test_2.xz
+for pattern in el Hello NOMATCH; do
+ for opts in "" "-l" "-h" "-H"; do
+ echo "=> xzgrep $opts $pattern <="
+ "$XZGREP" $opts $pattern xzgrep_test_1.xz xzgrep_test_2.xz
+ echo retval $?
+ done
+done > xzgrep_test_output 2>&1
+
+if cmp -s "$srcdir/xzgrep_expected_output" xzgrep_test_output ; then
+ :
+else
+ echo "unexpected output from xzgrep"
+ exit 1
+fi
+
+exit 0
diff --git a/tests/test_stream_flags.c b/tests/test_stream_flags.c
new file mode 100644
index 0000000..2248e67
--- /dev/null
+++ b/tests/test_stream_flags.c
@@ -0,0 +1,479 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file test_stream_flags.c
+/// \brief Tests Stream Header and Stream Footer coders
+//
+// Authors: Jia Tan
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tests.h"
+
+
+// Size of the Stream Flags field
+// (taken from src/liblzma/common/stream_flags_common.h)
+#define XZ_STREAM_FLAGS_SIZE 2
+
+#ifdef HAVE_ENCODERS
+// Header and footer magic bytes for .xz file format
+// (taken from src/liblzma/common/stream_flags_common.c)
+static const uint8_t xz_header_magic[6]
+ = { 0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00 };
+static const uint8_t xz_footer_magic[2] = { 0x59, 0x5A };
+#endif
+
+
+#ifdef HAVE_ENCODERS
+static void
+stream_header_encode_helper(lzma_check check)
+{
+ lzma_stream_flags flags = {
+ .version = 0,
+ .check = check,
+ };
+
+ uint8_t header[LZMA_STREAM_HEADER_SIZE];
+
+ // Encode Stream Header
+ assert_lzma_ret(lzma_stream_header_encode(&flags, header), LZMA_OK);
+
+ // Stream Header must start with Header Magic Bytes
+ const uint32_t magic_size = sizeof(xz_header_magic);
+ assert_array_eq(header, xz_header_magic, magic_size);
+
+ // Next must come Stream Flags
+ const uint8_t *encoded_stream_flags = header + magic_size;
+
+ // First byte is always null-byte.
+ // Second byte must have the Check ID in the lowest four bits
+ // and the highest four bits zero.
+ const uint8_t expected_stream_flags[] = { 0, check };
+ assert_array_eq(encoded_stream_flags, expected_stream_flags,
+ XZ_STREAM_FLAGS_SIZE);
+
+ // Last part is the CRC32 of the Stream Flags
+ const uint8_t *crc_ptr = encoded_stream_flags + XZ_STREAM_FLAGS_SIZE;
+ const uint32_t expected_crc = lzma_crc32(expected_stream_flags,
+ XZ_STREAM_FLAGS_SIZE, 0);
+ assert_uint_eq(read32le(crc_ptr), expected_crc);
+}
+#endif
+
+
+static void
+test_lzma_stream_header_encode(void)
+{
+#ifndef HAVE_ENCODERS
+ assert_skip("Encoder support disabled");
+#else
+ for (lzma_check i = 0; i < LZMA_CHECK_ID_MAX; i++)
+ stream_header_encode_helper(i);
+
+ lzma_stream_flags flags = {
+ .version = 0,
+ .check = LZMA_CHECK_CRC32
+ };
+
+ uint8_t header[LZMA_STREAM_HEADER_SIZE];
+
+ // Should fail if version > 0
+ flags.version = 1;
+ assert_lzma_ret(lzma_stream_header_encode(&flags, header),
+ LZMA_OPTIONS_ERROR);
+ flags.version = 0;
+
+ // Should fail if Check ID is invalid
+ flags.check = INVALID_LZMA_CHECK_ID;
+ assert_lzma_ret(lzma_stream_header_encode(&flags, header),
+ LZMA_PROG_ERROR);
+ flags.check = LZMA_CHECK_CRC32;
+
+ // Should pass even if Backward Size is invalid
+ // because Stream Header doesn't have that field.
+ flags.backward_size = LZMA_VLI_MAX + 1;
+ assert_lzma_ret(lzma_stream_header_encode(&flags, header), LZMA_OK);
+#endif
+}
+
+
+#if defined(HAVE_ENCODERS)
+static void
+stream_footer_encode_helper(lzma_check check)
+{
+ lzma_stream_flags flags = {
+ .version = 0,
+ .check = check,
+ .backward_size = LZMA_BACKWARD_SIZE_MIN,
+ };
+
+ uint8_t footer[LZMA_STREAM_HEADER_SIZE];
+
+ // Encode Stream Footer
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer), LZMA_OK);
+
+ // Stream Footer must start with CRC32
+ const uint32_t crc = read32le(footer);
+ const uint32_t expected_crc = lzma_crc32(footer + sizeof(uint32_t),
+ LZMA_STREAM_HEADER_SIZE - (sizeof(uint32_t) +
+ sizeof(xz_footer_magic)), 0);
+ assert_uint_eq(crc, expected_crc);
+
+ // Next the Backward Size
+ const uint32_t backwards_size = read32le(footer + sizeof(uint32_t));
+ const uint32_t expected_backwards_size = flags.backward_size / 4 - 1;
+ assert_uint_eq(backwards_size, expected_backwards_size);
+
+ // Next the Stream Flags
+ const uint8_t *stream_flags = footer + sizeof(uint32_t) * 2;
+
+ // First byte must be null
+ assert_uint_eq(stream_flags[0], 0);
+
+ // Second byte must have the Check ID in the lowest four bits
+ // and the highest four bits zero.
+ assert_uint_eq(stream_flags[1], check);
+
+ // And ends with Footer Magic Bytes
+ const uint8_t *expected_footer_magic = stream_flags +
+ XZ_STREAM_FLAGS_SIZE;
+ assert_array_eq(expected_footer_magic, xz_footer_magic,
+ sizeof(xz_footer_magic));
+}
+#endif
+
+
+static void
+test_lzma_stream_footer_encode(void)
+{
+#ifndef HAVE_ENCODERS
+ assert_skip("Encoder support disabled");
+#else
+ for (lzma_check i = 0; i < LZMA_CHECK_ID_MAX; i++)
+ stream_footer_encode_helper(i);
+
+ lzma_stream_flags flags = {
+ .version = 0,
+ .backward_size = LZMA_BACKWARD_SIZE_MIN,
+ .check = LZMA_CHECK_CRC32
+ };
+
+ uint8_t footer[LZMA_STREAM_HEADER_SIZE];
+
+ // Should fail if version > 0
+ flags.version = 1;
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer),
+ LZMA_OPTIONS_ERROR);
+ flags.version = 0;
+
+ // Should fail if Check ID is invalid
+ flags.check = INVALID_LZMA_CHECK_ID;
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer),
+ LZMA_PROG_ERROR);
+
+ // Should fail if Backward Size is invalid
+ flags.backward_size -= 1;
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer),
+ LZMA_PROG_ERROR);
+ flags.backward_size += 2;
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer),
+ LZMA_PROG_ERROR);
+ flags.backward_size = LZMA_BACKWARD_SIZE_MAX + 4;
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer),
+ LZMA_PROG_ERROR);
+#endif
+}
+
+
+#if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
+static void
+stream_header_decode_helper(lzma_check check)
+{
+ lzma_stream_flags flags = {
+ .version = 0,
+ .check = check
+ };
+
+ uint8_t header[LZMA_STREAM_HEADER_SIZE];
+
+ assert_lzma_ret(lzma_stream_header_encode(&flags, header), LZMA_OK);
+
+ lzma_stream_flags dest_flags;
+ assert_lzma_ret(lzma_stream_header_decode(&dest_flags, header),
+ LZMA_OK);
+
+ // Version should be 0
+ assert_uint_eq(dest_flags.version, 0);
+
+ // Backward Size should be LZMA_VLI_UNKNOWN
+ assert_uint_eq(dest_flags.backward_size, LZMA_VLI_UNKNOWN);
+
+ // Check ID must equal the argument given to this function.
+ assert_uint_eq(dest_flags.check, check);
+}
+#endif
+
+
+static void
+test_lzma_stream_header_decode(void)
+{
+#if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
+ assert_skip("Encoder or decoder support disabled");
+#else
+ for (lzma_check i = 0; i < LZMA_CHECK_ID_MAX; i++)
+ stream_header_decode_helper(i);
+
+ lzma_stream_flags flags = {
+ .version = 0,
+ .check = LZMA_CHECK_CRC32
+ };
+
+ uint8_t header[LZMA_STREAM_HEADER_SIZE];
+ lzma_stream_flags dest;
+
+ // First encode known flags to header buffer
+ assert_lzma_ret(lzma_stream_header_encode(&flags, header), LZMA_OK);
+
+ // Should fail if magic bytes do not match
+ header[0] ^= 1;
+ assert_lzma_ret(lzma_stream_header_decode(&dest, header),
+ LZMA_FORMAT_ERROR);
+ header[0] ^= 1;
+
+ // Should fail if a reserved bit is set
+ uint8_t *stream_flags = header + sizeof(xz_header_magic);
+ stream_flags[0] = 1;
+
+ // Need to adjust CRC32 after making a change since the CRC32
+ // is verified before decoding the Stream Flags field.
+ uint8_t *crc32_ptr = header + sizeof(xz_header_magic)
+ + XZ_STREAM_FLAGS_SIZE;
+ const uint32_t crc_orig = read32le(crc32_ptr);
+ uint32_t new_crc32 = lzma_crc32(
+ stream_flags, XZ_STREAM_FLAGS_SIZE, 0);
+ write32le(crc32_ptr, new_crc32);
+ assert_lzma_ret(lzma_stream_header_decode(&dest, header),
+ LZMA_OPTIONS_ERROR);
+ stream_flags[0] = 0;
+ write32le(crc32_ptr, crc_orig);
+
+ // Should fail if upper bits of check ID are set
+ stream_flags[1] |= 0xF0;
+ new_crc32 = lzma_crc32(stream_flags, XZ_STREAM_FLAGS_SIZE, 0);
+ write32le(crc32_ptr, new_crc32);
+ assert_lzma_ret(lzma_stream_header_decode(&dest, header),
+ LZMA_OPTIONS_ERROR);
+ stream_flags[1] = flags.check;
+ write32le(crc32_ptr, crc_orig);
+
+ // Should fail if CRC32 does not match.
+ // First, alter a byte in the Stream Flags.
+ stream_flags[0] = 1;
+ assert_lzma_ret(lzma_stream_header_decode(&dest, header),
+ LZMA_DATA_ERROR);
+ stream_flags[0] = 0;
+
+ // Next, change the CRC32.
+ *crc32_ptr ^= 1;
+ assert_lzma_ret(lzma_stream_header_decode(&dest, header),
+ LZMA_DATA_ERROR);
+#endif
+}
+
+
+#if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
+static void
+stream_footer_decode_helper(lzma_check check)
+{
+ lzma_stream_flags flags = {
+ .version = 0,
+ .backward_size = LZMA_BACKWARD_SIZE_MIN,
+ .check = check,
+ };
+
+ uint8_t footer[LZMA_STREAM_HEADER_SIZE];
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer), LZMA_OK);
+
+ lzma_stream_flags dest_flags;
+ assert_lzma_ret(lzma_stream_footer_decode(&dest_flags, footer),
+ LZMA_OK);
+
+ // Version should be 0.
+ assert_uint_eq(dest_flags.version, 0);
+
+ // Backward Size should equal the value from the flags.
+ assert_uint_eq(dest_flags.backward_size, flags.backward_size);
+
+ // Check ID must equal argument given to this function.
+ assert_uint_eq(dest_flags.check, check);
+}
+#endif
+
+
+static void
+test_lzma_stream_footer_decode(void)
+{
+#if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS)
+ assert_skip("Encoder or decoder support disabled");
+#else
+ for (lzma_check i = 0; i < LZMA_CHECK_ID_MAX; i++)
+ stream_footer_decode_helper(i);
+
+ lzma_stream_flags flags = {
+ .version = 0,
+ .check = LZMA_CHECK_CRC32,
+ .backward_size = LZMA_BACKWARD_SIZE_MIN
+ };
+
+ uint8_t footer[LZMA_STREAM_HEADER_SIZE];
+ lzma_stream_flags dest;
+
+ // First encode known flags to the footer buffer
+ assert_lzma_ret(lzma_stream_footer_encode(&flags, footer), LZMA_OK);
+
+ // Should fail if magic bytes do not match
+ footer[LZMA_STREAM_HEADER_SIZE - 1] ^= 1;
+ assert_lzma_ret(lzma_stream_footer_decode(&dest, footer),
+ LZMA_FORMAT_ERROR);
+ footer[LZMA_STREAM_HEADER_SIZE - 1] ^= 1;
+
+ // Should fail if a reserved bit is set.
+ // In the Stream Footer, the Stream Flags follow the CRC32 (4 bytes)
+ // and the Backward Size (4 bytes)
+ uint8_t *stream_flags = footer + sizeof(uint32_t) * 2;
+ stream_flags[0] = 1;
+
+ // Need to adjust the CRC32 so it will not fail that check instead
+ uint8_t *crc32_ptr = footer;
+ const uint32_t crc_orig = read32le(crc32_ptr);
+ uint8_t *backward_size = footer + sizeof(uint32_t);
+ uint32_t new_crc32 = lzma_crc32(backward_size, sizeof(uint32_t) +
+ XZ_STREAM_FLAGS_SIZE, 0);
+ write32le(crc32_ptr, new_crc32);
+ assert_lzma_ret(lzma_stream_footer_decode(&dest, footer),
+ LZMA_OPTIONS_ERROR);
+ stream_flags[0] = 0;
+ write32le(crc32_ptr, crc_orig);
+
+ // Should fail if upper bits of check ID are set
+ stream_flags[1] |= 0xF0;
+ new_crc32 = lzma_crc32(backward_size, sizeof(uint32_t) +
+ XZ_STREAM_FLAGS_SIZE, 0);
+ write32le(crc32_ptr, new_crc32);
+ assert_lzma_ret(lzma_stream_footer_decode(&dest, footer),
+ LZMA_OPTIONS_ERROR);
+ stream_flags[1] = flags.check;
+ write32le(crc32_ptr, crc_orig);
+
+ // Should fail if CRC32 does not match.
+ // First, alter a byte in the Stream Flags.
+ stream_flags[0] = 1;
+ assert_lzma_ret(lzma_stream_footer_decode(&dest, footer),
+ LZMA_DATA_ERROR);
+ stream_flags[0] = 0;
+
+ // Next, change the CRC32
+ *crc32_ptr ^= 1;
+ assert_lzma_ret(lzma_stream_footer_decode(&dest, footer),
+ LZMA_DATA_ERROR);
+#endif
+}
+
+
+static void
+test_lzma_stream_flags_compare(void)
+{
+ lzma_stream_flags first = {
+ .version = 0,
+ .backward_size = LZMA_BACKWARD_SIZE_MIN,
+ .check = LZMA_CHECK_CRC32,
+ };
+
+ lzma_stream_flags second = first;
+
+ // First test should pass
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second), LZMA_OK);
+
+ // Altering either version should cause an error
+ first.version = 1;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_OPTIONS_ERROR);
+ second.version = 1;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_OPTIONS_ERROR);
+ first.version = 0;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_OPTIONS_ERROR);
+ second.version = 0;
+
+ // Check types must be under the maximum
+ first.check = INVALID_LZMA_CHECK_ID;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_PROG_ERROR);
+ second.check = INVALID_LZMA_CHECK_ID;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_PROG_ERROR);
+ first.check = LZMA_CHECK_CRC32;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_PROG_ERROR);
+ second.check = LZMA_CHECK_CRC32;
+
+ // Check types must be equal
+ for (lzma_check i = 0; i < LZMA_CHECK_ID_MAX; i++) {
+ first.check = i;
+ if (i == second.check)
+ assert_lzma_ret(lzma_stream_flags_compare(&first,
+ &second), LZMA_OK);
+ else
+ assert_lzma_ret(lzma_stream_flags_compare(&first,
+ &second), LZMA_DATA_ERROR);
+ }
+ first.check = LZMA_CHECK_CRC32;
+
+ // Backward Size comparison is skipped if either are LZMA_VLI_UNKNOWN
+ first.backward_size = LZMA_VLI_UNKNOWN;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second), LZMA_OK);
+ second.backward_size = LZMA_VLI_MAX + 1;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second), LZMA_OK);
+ second.backward_size = LZMA_BACKWARD_SIZE_MIN;
+
+ // Backward Sizes need to be valid
+ first.backward_size = LZMA_VLI_MAX + 4;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_PROG_ERROR);
+ second.backward_size = LZMA_VLI_MAX + 4;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_PROG_ERROR);
+ first.backward_size = LZMA_BACKWARD_SIZE_MIN;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_PROG_ERROR);
+ second.backward_size = LZMA_BACKWARD_SIZE_MIN;
+
+ // Backward Sizes must be equal
+ second.backward_size = first.backward_size + 4;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_DATA_ERROR);
+
+ // Should fail if Backward Sizes are > LZMA_BACKWARD_SIZE_MAX
+ // even though they are equal
+ first.backward_size = LZMA_BACKWARD_SIZE_MAX + 1;
+ second.backward_size = LZMA_BACKWARD_SIZE_MAX + 1;
+ assert_lzma_ret(lzma_stream_flags_compare(&first, &second),
+ LZMA_PROG_ERROR);
+}
+
+
+extern int
+main(int argc, char **argv)
+{
+ tuktest_start(argc, argv);
+ tuktest_run(test_lzma_stream_header_encode);
+ tuktest_run(test_lzma_stream_footer_encode);
+ tuktest_run(test_lzma_stream_header_decode);
+ tuktest_run(test_lzma_stream_footer_decode);
+ tuktest_run(test_lzma_stream_flags_compare);
+ return tuktest_end();
+}
diff --git a/tests/test_vli.c b/tests/test_vli.c
new file mode 100644
index 0000000..996b775
--- /dev/null
+++ b/tests/test_vli.c
@@ -0,0 +1,324 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file test_vli.c
+/// \brief Tests liblzma vli functions
+//
+// Author: Jia Tan
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tests.h"
+
+
+// Pre-encoded VLI values for testing
+// VLI can have between 1 and 9 bytes when encoded
+// They are encoded little endian where all but the last
+// byte must have the leading 1 bit set
+#if defined(HAVE_ENCODERS) || defined(HAVE_DECODERS)
+static const uint8_t one_byte[1] = {0x25};
+static const lzma_vli one_byte_value = 37;
+
+static const uint8_t two_bytes[2] = {0x80, 0x56};
+static const lzma_vli two_byte_value = 11008;
+
+static const uint8_t three_bytes[3] = {0x99, 0x92, 0x20};
+static const lzma_vli three_byte_value = 526617;
+
+static const uint8_t four_bytes[4] = {0x97, 0x83, 0x94, 0x47};
+static const lzma_vli four_byte_value = 149225879;
+
+static const uint8_t five_bytes[5] = {0xA6, 0x92, 0x88, 0x89, 0x32};
+static const lzma_vli five_byte_value = 13440780582;
+
+static const uint8_t six_bytes[6] = {0xA9, 0x84, 0x99, 0x82, 0x94, 0x12};
+static const lzma_vli six_byte_value = 623848604201;
+
+static const uint8_t seven_bytes[7] = {0x90, 0x80, 0x90, 0x80, 0x90, 0x80,
+ 0x79};
+static const lzma_vli seven_byte_value = 532167923073040;
+
+static const uint8_t eight_bytes[8] = {0x91, 0x87, 0xF2, 0xB2, 0xC2, 0xD2,
+ 0x93, 0x63};
+static const lzma_vli eight_byte_value = 55818443594433425;
+
+static const uint8_t nine_bytes[9] = {0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1,
+ 0xE1, 0xF1, 0x1};
+static const lzma_vli nine_byte_value = 136100349976529025;
+#endif
+
+
+static void
+test_lzma_vli_size(void)
+{
+ // First test invalid VLI values (should return 0)
+ // VLI UNKNOWN is an invalid VLI
+ assert_uint_eq(lzma_vli_size(LZMA_VLI_UNKNOWN), 0);
+ // Loop over a few VLI values just over the maximum
+ for (uint64_t i = LZMA_VLI_MAX + 1; i < LZMA_VLI_MAX + 10; i++)
+ assert_uint_eq(lzma_vli_size(i), 0);
+
+ // Number should increment every seven set bits
+ lzma_vli vli = 1;
+ for (uint32_t i = 1; i < LZMA_VLI_BYTES_MAX; i++, vli <<= 7) {
+ // Test the base value and a few others around it
+ assert_uint_eq(lzma_vli_size(vli), i);
+ assert_uint_eq(lzma_vli_size(vli * 2), i);
+ assert_uint_eq(lzma_vli_size(vli + 10), i);
+ assert_uint_eq(lzma_vli_size(vli * 3 + 39), i);
+ }
+}
+
+
+#ifdef HAVE_ENCODERS
+// Helper function for test_lzma_vli_encode
+// Encodes an input VLI and compares against a pre-computed value
+static void
+encode_single_call_mode(lzma_vli input, const uint8_t *expected,
+ uint32_t expected_len)
+{
+ uint8_t out[LZMA_VLI_BYTES_MAX];
+ size_t out_pos = 0;
+ assert_lzma_ret(lzma_vli_encode(input, NULL, out, &out_pos,
+ expected_len), LZMA_OK);
+ assert_uint_eq(out_pos, expected_len);
+ assert_array_eq(out, expected, expected_len);
+}
+
+
+// Helper function for test_lzma_vli_encode
+// Encodes an input VLI one byte at a time with the multi call
+// method. Then compares against a pre-computed value
+static void
+encode_multi_call_mode(lzma_vli input, const uint8_t *expected,
+ uint32_t expected_len)
+{
+ uint8_t out[LZMA_VLI_BYTES_MAX];
+ size_t out_pos = 0;
+ size_t vli_pos = 0;
+
+ for (uint32_t i = 1; i < expected_len; i++) {
+ assert_lzma_ret(lzma_vli_encode(input, &vli_pos, out,
+ &out_pos, i), LZMA_OK);
+ assert_uint_eq(out_pos, i);
+ assert_uint_eq(vli_pos, i);
+ }
+ assert_lzma_ret(lzma_vli_encode(input, &vli_pos, out, &out_pos,
+ expected_len), LZMA_STREAM_END);
+ assert_uint_eq(out_pos, expected_len);
+ assert_uint_eq(vli_pos, expected_len);
+ assert_array_eq(out, expected, expected_len);
+}
+#endif
+
+
+static void
+test_lzma_vli_encode(void)
+{
+#ifndef HAVE_ENCODERS
+ assert_skip("Encoder support disabled");
+#else
+ size_t vli_pos = 0;
+ uint8_t out[LZMA_VLI_BYTES_MAX];
+ uint8_t zeros[LZMA_VLI_BYTES_MAX];
+ memzero(out, LZMA_VLI_BYTES_MAX);
+ memzero(zeros, LZMA_VLI_BYTES_MAX);
+ size_t out_pos = 0;
+
+ // First test invalid input parameters
+ // VLI invalid
+ assert_lzma_ret(lzma_vli_encode(LZMA_VLI_UNKNOWN, &vli_pos, out,
+ &out_pos, sizeof(out)), LZMA_PROG_ERROR);
+ // Failure should not change params
+ assert_uint_eq(vli_pos, 0);
+ assert_uint_eq(out_pos, 0);
+ assert_array_eq(out, zeros, LZMA_VLI_BYTES_MAX);
+
+ assert_lzma_ret(lzma_vli_encode(LZMA_VLI_MAX + 1, &vli_pos, out,
+ &out_pos, sizeof(out)), LZMA_PROG_ERROR);
+ assert_uint_eq(vli_pos, 0);
+ assert_uint_eq(out_pos, 0);
+ assert_array_eq(out, zeros, LZMA_VLI_BYTES_MAX);
+
+ // 0 output size
+ assert_lzma_ret(lzma_vli_encode(one_byte_value, &vli_pos, out,
+ &out_pos, 0), LZMA_BUF_ERROR);
+ assert_uint_eq(vli_pos, 0);
+ assert_uint_eq(out_pos, 0);
+ assert_array_eq(out, zeros, LZMA_VLI_BYTES_MAX);
+
+ // Size of VLI does not fit in buffer
+ size_t phony_out_pos = 3;
+ assert_lzma_ret(lzma_vli_encode(one_byte_value, NULL, out,
+ &phony_out_pos, 2), LZMA_PROG_ERROR);
+
+ assert_lzma_ret(lzma_vli_encode(LZMA_VLI_MAX / 2, NULL, out,
+ &out_pos, 2), LZMA_PROG_ERROR);
+
+ // Test single-call mode (using vli_pos as NULL)
+ encode_single_call_mode(one_byte_value, one_byte,
+ sizeof(one_byte));
+ encode_single_call_mode(two_byte_value, two_bytes,
+ sizeof(two_bytes));
+ encode_single_call_mode(three_byte_value, three_bytes,
+ sizeof(three_bytes));
+ encode_single_call_mode(four_byte_value, four_bytes,
+ sizeof(four_bytes));
+ encode_single_call_mode(five_byte_value, five_bytes,
+ sizeof(five_bytes));
+ encode_single_call_mode(six_byte_value, six_bytes,
+ sizeof(six_bytes));
+ encode_single_call_mode(seven_byte_value, seven_bytes,
+ sizeof(seven_bytes));
+ encode_single_call_mode(eight_byte_value, eight_bytes,
+ sizeof(eight_bytes));
+ encode_single_call_mode(nine_byte_value, nine_bytes,
+ sizeof(nine_bytes));
+
+ // Test multi-call mode
+ encode_multi_call_mode(one_byte_value, one_byte,
+ sizeof(one_byte));
+ encode_multi_call_mode(two_byte_value, two_bytes,
+ sizeof(two_bytes));
+ encode_multi_call_mode(three_byte_value, three_bytes,
+ sizeof(three_bytes));
+ encode_multi_call_mode(four_byte_value, four_bytes,
+ sizeof(four_bytes));
+ encode_multi_call_mode(five_byte_value, five_bytes,
+ sizeof(five_bytes));
+ encode_multi_call_mode(six_byte_value, six_bytes,
+ sizeof(six_bytes));
+ encode_multi_call_mode(seven_byte_value, seven_bytes,
+ sizeof(seven_bytes));
+ encode_multi_call_mode(eight_byte_value, eight_bytes,
+ sizeof(eight_bytes));
+ encode_multi_call_mode(nine_byte_value, nine_bytes,
+ sizeof(nine_bytes));
+#endif
+}
+
+
+#ifdef HAVE_DECODERS
+static void
+decode_single_call_mode(const uint8_t *input, uint32_t input_len,
+ lzma_vli expected)
+{
+ lzma_vli out = 0;
+ size_t in_pos = 0;
+
+ assert_lzma_ret(lzma_vli_decode(&out, NULL, input, &in_pos,
+ input_len), LZMA_OK);
+ assert_uint_eq(in_pos, input_len);
+ assert_uint_eq(out, expected);
+}
+
+
+static void
+decode_multi_call_mode(const uint8_t *input, uint32_t input_len,
+ lzma_vli expected)
+{
+ lzma_vli out = 0;
+ size_t in_pos = 0;
+ size_t vli_pos = 0;
+
+ for (uint32_t i = 1; i < input_len; i++) {
+ assert_lzma_ret(lzma_vli_decode(&out, &vli_pos, input,
+ &in_pos, i), LZMA_OK);
+ assert_uint_eq(in_pos, i);
+ assert_uint_eq(vli_pos, i);
+ }
+
+ assert_lzma_ret(lzma_vli_decode(&out, &vli_pos, input, &in_pos,
+ input_len), LZMA_STREAM_END);
+ assert_uint_eq(in_pos, input_len);
+ assert_uint_eq(vli_pos, input_len);
+ assert_uint_eq(out, expected);
+}
+#endif
+
+
+static void
+test_lzma_vli_decode(void)
+{
+#ifndef HAVE_DECODERS
+ assert_skip("Decoder support disabled");
+#else
+ lzma_vli out = 0;
+ size_t in_pos = 0;
+
+ // First test invalid input params
+ // 0 in_size
+ assert_lzma_ret(lzma_vli_decode(&out, NULL, one_byte, &in_pos, 0),
+ LZMA_DATA_ERROR);
+ assert_uint_eq(out, 0);
+ assert_uint_eq(in_pos, 0);
+
+ // VLI encoded is invalid (last digit has leading 1 set)
+ uint8_t invalid_vli[3] = {0x80, 0x80, 0x80};
+ assert_lzma_ret(lzma_vli_decode(&out, NULL, invalid_vli, &in_pos,
+ sizeof(invalid_vli)), LZMA_DATA_ERROR);
+
+ // Bad vli_pos
+ size_t vli_pos = LZMA_VLI_BYTES_MAX;
+ assert_lzma_ret(lzma_vli_decode(&out, &vli_pos, invalid_vli, &in_pos,
+ sizeof(invalid_vli)), LZMA_PROG_ERROR);
+
+ // Bad in_pos
+ in_pos = sizeof(invalid_vli);
+ assert_lzma_ret(lzma_vli_decode(&out, &in_pos, invalid_vli, &in_pos,
+ sizeof(invalid_vli)), LZMA_BUF_ERROR);
+
+ // Test single call mode
+ decode_single_call_mode(one_byte, sizeof(one_byte),
+ one_byte_value);
+ decode_single_call_mode(two_bytes, sizeof(two_bytes),
+ two_byte_value);
+ decode_single_call_mode(three_bytes, sizeof(three_bytes),
+ three_byte_value);
+ decode_single_call_mode(four_bytes, sizeof(four_bytes),
+ four_byte_value);
+ decode_single_call_mode(five_bytes, sizeof(five_bytes),
+ five_byte_value);
+ decode_single_call_mode(six_bytes, sizeof(six_bytes),
+ six_byte_value);
+ decode_single_call_mode(seven_bytes, sizeof(seven_bytes),
+ seven_byte_value);
+ decode_single_call_mode(eight_bytes, sizeof(eight_bytes),
+ eight_byte_value);
+ decode_single_call_mode(nine_bytes, sizeof(nine_bytes),
+ nine_byte_value);
+
+ // Test multi call mode
+ decode_multi_call_mode(one_byte, sizeof(one_byte),
+ one_byte_value);
+ decode_multi_call_mode(two_bytes, sizeof(two_bytes),
+ two_byte_value);
+ decode_multi_call_mode(three_bytes, sizeof(three_bytes),
+ three_byte_value);
+ decode_multi_call_mode(four_bytes, sizeof(four_bytes),
+ four_byte_value);
+ decode_multi_call_mode(five_bytes, sizeof(five_bytes),
+ five_byte_value);
+ decode_multi_call_mode(six_bytes, sizeof(six_bytes),
+ six_byte_value);
+ decode_multi_call_mode(seven_bytes, sizeof(seven_bytes),
+ seven_byte_value);
+ decode_multi_call_mode(eight_bytes, sizeof(eight_bytes),
+ eight_byte_value);
+ decode_multi_call_mode(nine_bytes, sizeof(nine_bytes),
+ nine_byte_value);
+#endif
+}
+
+
+extern int
+main(int argc, char **argv)
+{
+ tuktest_start(argc, argv);
+ tuktest_run(test_lzma_vli_size);
+ tuktest_run(test_lzma_vli_encode);
+ tuktest_run(test_lzma_vli_decode);
+ return tuktest_end();
+}
diff --git a/tests/tests.h b/tests/tests.h
new file mode 100644
index 0000000..2d42700
--- /dev/null
+++ b/tests/tests.h
@@ -0,0 +1,75 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file tests.h
+/// \brief Common definitions for test applications
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_TESTS_H
+#define LZMA_TESTS_H
+
+#include "sysdefs.h"
+#include "tuklib_integer.h"
+#include "lzma.h"
+#include "tuktest.h"
+
+
+// Invalid value for the lzma_check enumeration. This must be positive
+// but small enough to fit into signed char since the underlying type might
+// one some platform be a signed char.
+//
+// Don't put LZMA_ at the beginning of the name so that it is obvious that
+// this constant doesn't come from the API headers.
+#define INVALID_LZMA_CHECK_ID ((lzma_check)(LZMA_CHECK_ID_MAX + 1))
+
+
+// This table and macro allow getting more readable error messages when
+// comparing the lzma_ret enumeration values.
+static const char enum_strings_lzma_ret[][24] = {
+ "LZMA_OK",
+ "LZMA_STREAM_END",
+ "LZMA_NO_CHECK",
+ "LZMA_UNSUPPORTED_CHECK",
+ "LZMA_GET_CHECK",
+ "LZMA_MEM_ERROR",
+ "LZMA_MEMLIMIT_ERROR",
+ "LZMA_FORMAT_ERROR",
+ "LZMA_OPTIONS_ERROR",
+ "LZMA_DATA_ERROR",
+ "LZMA_BUF_ERROR",
+ "LZMA_PROG_ERROR",
+ "LZMA_SEEK_NEEDED",
+};
+
+#define assert_lzma_ret(test_expr, ref_val) \
+ assert_enum_eq(test_expr, ref_val, enum_strings_lzma_ret)
+
+
+static const char enum_strings_lzma_check[][24] = {
+ "LZMA_CHECK_NONE",
+ "LZMA_CHECK_CRC32",
+ "LZMA_CHECK_UNKNOWN_2",
+ "LZMA_CHECK_UNKNOWN_3",
+ "LZMA_CHECK_CRC64",
+ "LZMA_CHECK_UNKNOWN_5",
+ "LZMA_CHECK_UNKNOWN_6",
+ "LZMA_CHECK_UNKNOWN_7",
+ "LZMA_CHECK_UNKNOWN_8",
+ "LZMA_CHECK_UNKNOWN_9",
+ "LZMA_CHECK_SHA256",
+ "LZMA_CHECK_UNKNOWN_11",
+ "LZMA_CHECK_UNKNOWN_12",
+ "LZMA_CHECK_UNKNOWN_13",
+ "LZMA_CHECK_UNKNOWN_14",
+ "LZMA_CHECK_UNKNOWN_15",
+};
+
+#define assert_lzma_check(test_expr, ref_val) \
+ assert_enum_eq(test_expr, ref_val, enum_strings_lzma_check)
+
+#endif
diff --git a/tests/tuktest.h b/tests/tuktest.h
new file mode 100644
index 0000000..508eace
--- /dev/null
+++ b/tests/tuktest.h
@@ -0,0 +1,1053 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file tuktest.h
+/// \brief Helper macros for writing simple test programs
+/// \version 2023-01-08
+///
+/// Some inspiration was taken from STest by Keith Nicholas.
+///
+/// This is standard C99/C11 only and thus should be fairly portable
+/// outside POSIX systems too.
+///
+/// This supports putting multiple tests in a single test program
+/// although it is perfectly fine to have only one test per program.
+/// Each test can produce one of these results:
+/// - Pass
+/// - Fail
+/// - Skip
+/// - Hard error (the remaining tests, if any, are not run)
+///
+/// By default this produces an exit status that is compatible with
+/// Automake and Meson, and mostly compatible with CMake.[1]
+/// If a test program contains multiple tests, only one exit code can
+/// be returned. Of the following, the first match is used:
+/// - 99 if any test returned a hard error
+/// - stdlib.h's EXIT_FAILURE if at least one test failed
+/// - 77 if at least one test was skipped or no tests were run at all
+/// - stdlib.h's EXIT_SUCCESS (0 on POSIX); that is, if none of the above
+/// are true then there was at least one test to run and none of them
+/// failed, was skipped, or returned a hard error.
+///
+/// A summary of tests being run and their results are printed to stdout.
+/// If you want ANSI coloring for the output, #define TUKTEST_COLOR.
+/// If you only want output when something goes wrong, #define TUKTEST_QUIET.
+///
+/// The downside of the above mapping is that it cannot indicate if
+/// some tests were skipped and some passed. If that is likely to
+/// happen it may be better to split into multiple test programs (one
+/// test per program) or use the TAP mode described below.
+///
+/// By using #define TUKTEST_TAP before #including this file the
+/// output will be Test Anything Protocol (TAP) version 12 compatible
+/// and the exit status will always be EXIT_SUCCESS. This can be easily
+/// used with Automake via its tap-driver.sh. Meson supports TAP natively.
+/// TAP's todo-directive isn't supported for now, mostly because it's not
+/// trivially convertible to the exit-status reporting method.
+///
+/// If TUKTEST_TAP is used, TUKTEST_QUIET and TUKTEST_COLOR are ignored.
+///
+/// The main() function may look like this (remember to include config.h
+/// or such files too if needed!):
+///
+/// #include "tuktest.h"
+///
+/// int main(int argc, char **argv)
+/// {
+/// tuktest_start(argc, argv);
+///
+/// if (!is_package_foo_available())
+/// tuktest_early_skip("Optional package foo is not available");
+///
+/// if (!do_common_initializations())
+/// tuktest_error("Error during common initializations");
+///
+/// tuktest_run(testfunc1);
+/// tuktest_run(testfunc2);
+///
+/// return tuktest_end();
+/// }
+///
+/// Using exit(tuktest_end()) as a pair to tuktest_start() is OK too.
+///
+/// Each test function called via tuktest_run() should be of type
+/// "void testfunc1(void)". The test functions should use the
+/// various assert_CONDITION() macros. The current test stops if
+/// an assertion fails (this is implemented with setjmp/longjmp).
+/// Execution continues from the next test unless the failure was
+/// due to assert_error() (indicating a hard error) which makes
+/// the program exit() without running any remaining tests.
+///
+/// Search for "define assert" in this file to find the explanations
+/// of the available assertion macros.
+///
+/// IMPORTANT:
+///
+/// - The assert_CONDITION() macros may only be used by code that is
+/// called via tuktest_run()! This includes the function named in
+/// the tuktest_run() call and functions called further from there.
+/// (The assert_CONDITION() macros depend on setup code in tuktest_run()
+/// and other use results in undefined behavior.)
+///
+/// - tuktest_start(), tuktest_early_skip, tuktest_run(), and tuktest_end()
+/// must not be used in the tests called via tuktest_run()! (tuktest_end()
+/// is called more freely internally by this file but such use isn't part
+/// of the API.)
+///
+/// - tuktest_error(), tuktest_malloc(), tuktest_free(),
+/// tuktest_file_from_srcdir(), and tuktest_file_from_builddir()
+/// can be used everywhere after tuktest_start() has been called.
+/// (In tests running under tuktest_run(), assert_error() can be used
+/// instead of tuktest_error() when a hard error occurs.)
+///
+/// - Everything else is for internal use only.
+///
+/// Footnotes:
+///
+/// [1] As of 2022-06-02:
+/// See the Automake manual "info (automake)Scripts-based Testsuites" or:
+/// https://www.gnu.org/software/automake/manual/automake.html#Scripts_002dbased-Testsuites
+///
+/// Meson: https://mesonbuild.com/Unit-tests.html
+///
+/// CMake handles passing and failing tests by default but treats hard
+/// errors as regular fails. To CMake support skipped tests correctly,
+/// one has to set the SKIP_RETURN_CODE property for each test:
+///
+/// set_tests_properties(foo_test_name PROPERTIES SKIP_RETURN_CODE 77)
+///
+/// See:
+/// https://cmake.org/cmake/help/latest/command/set_tests_properties.html
+/// https://cmake.org/cmake/help/latest/prop_test/SKIP_RETURN_CODE.html
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TUKTEST_H
+#define TUKTEST_H
+
+#include <stddef.h>
+
+// On some (too) old systems inttypes.h doesn't exist or isn't good enough.
+// Include it conditionally so that any portability tricks can be done before
+// tuktest.h is included. On any modern system inttypes.h is fine as is.
+#ifndef PRIu64
+# include <inttypes.h>
+#endif
+
+#include <setjmp.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define TUKTEST_GNUC_REQ(major, minor) \
+ ((__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)) \
+ || __GNUC__ > (major))
+#else
+# define TUKTEST_GNUC_REQ(major, minor) 0
+#endif
+
+
+// This is silencing warnings about unused functions. Not all test programs
+// need all functions from this header.
+#if TUKTEST_GNUC_REQ(3, 0)
+# define tuktest_maybe_unused __attribute__((__unused__))
+#else
+# define tuktest_maybe_unused
+#endif
+
+// We need printf("") so silence the warning about empty format string.
+#if TUKTEST_GNUC_REQ(4, 2)
+# pragma GCC diagnostic ignored "-Wformat-zero-length"
+#endif
+
+
+// Types and printf format macros to use in integer assertions and also for
+// printing size_t values (C99's %zu isn't available on very old systems).
+typedef int64_t tuktest_int;
+typedef uint64_t tuktest_uint;
+#define TUKTEST_PRId PRId64
+#define TUKTEST_PRIu PRIu64
+#define TUKTEST_PRIX PRIX64
+
+
+// When TAP mode isn't used, Automake-compatible exit statuses are used.
+#define TUKTEST_EXIT_PASS EXIT_SUCCESS
+#define TUKTEST_EXIT_FAIL EXIT_FAILURE
+#define TUKTEST_EXIT_SKIP 77
+#define TUKTEST_EXIT_ERROR 99
+
+
+enum tuktest_result {
+ TUKTEST_PASS,
+ TUKTEST_FAIL,
+ TUKTEST_SKIP,
+ TUKTEST_ERROR,
+};
+
+
+#ifdef TUKTEST_TAP
+# undef TUKTEST_QUIET
+# undef TUKTEST_COLOR
+# undef TUKTEST_TAP
+# define TUKTEST_TAP 1
+# define TUKTEST_STR_PASS "ok -"
+# define TUKTEST_STR_FAIL "not ok -"
+# define TUKTEST_STR_SKIP "ok - # SKIP"
+# define TUKTEST_STR_ERROR "Bail out!"
+#else
+# define TUKTEST_TAP 0
+# ifdef TUKTEST_COLOR
+# define TUKTEST_COLOR_PASS "\x1B[0;32m"
+# define TUKTEST_COLOR_FAIL "\x1B[0;31m"
+# define TUKTEST_COLOR_SKIP "\x1B[1;34m"
+# define TUKTEST_COLOR_ERROR "\x1B[0;35m"
+# define TUKTEST_COLOR_TOTAL "\x1B[1m"
+# define TUKTEST_COLOR_OFF "\x1B[m"
+# define TUKTEST_COLOR_IF(cond, color) ((cond) ? (color) : "" )
+# else
+# define TUKTEST_COLOR_PASS ""
+# define TUKTEST_COLOR_FAIL ""
+# define TUKTEST_COLOR_SKIP ""
+# define TUKTEST_COLOR_ERROR ""
+# define TUKTEST_COLOR_TOTAL ""
+# define TUKTEST_COLOR_OFF ""
+# define TUKTEST_COLOR_IF(cond, color) ""
+# endif
+# define TUKTEST_COLOR_ADD(str, color) color str TUKTEST_COLOR_OFF
+# define TUKTEST_STR_PASS \
+ TUKTEST_COLOR_ADD("PASS:", TUKTEST_COLOR_PASS)
+# define TUKTEST_STR_FAIL \
+ TUKTEST_COLOR_ADD("FAIL:", TUKTEST_COLOR_FAIL)
+# define TUKTEST_STR_SKIP \
+ TUKTEST_COLOR_ADD("SKIP:", TUKTEST_COLOR_SKIP)
+# define TUKTEST_STR_ERROR \
+ TUKTEST_COLOR_ADD("ERROR:", TUKTEST_COLOR_ERROR)
+#endif
+
+// NOTE: If TUKTEST_TAP is defined then TUKTEST_QUIET will get undefined above.
+#ifndef TUKTEST_QUIET
+# define TUKTEST_QUIET 0
+#else
+# undef TUKTEST_QUIET
+# define TUKTEST_QUIET 1
+#endif
+
+
+// Counts of the passed, failed, skipped, and hard-errored tests.
+// This is indexed with the enumeration constants from enum tuktest_result.
+static unsigned tuktest_stats[4] = { 0, 0, 0, 0 };
+
+// Copy of argc and argv from main(). These are set by tuktest_start().
+static int tuktest_argc = 0;
+static char **tuktest_argv = NULL;
+
+// Name of the currently-running test. This exists because it's nice
+// to print the main test function name even if the failing test-assertion
+// fails in a function called by the main test function.
+static const char *tuktest_name = NULL;
+
+// longjmp() target for when a test-assertion fails.
+static jmp_buf tuktest_jmpenv;
+
+
+// This declaration is needed for tuktest_malloc().
+static int tuktest_end(void);
+
+
+// Internal helper for handling hard errors both inside and
+// outside tuktest_run().
+#define tuktest_error_impl(filename, line, ...) \
+do { \
+ tuktest_print_result_prefix(TUKTEST_ERROR, filename, line); \
+ printf(__VA_ARGS__); \
+ printf("\n"); \
+ ++tuktest_stats[TUKTEST_ERROR]; \
+ exit(tuktest_end()); \
+} while (0)
+
+
+// printf() is without checking its return value in many places. This function
+// is called before exiting to check the status of stdout and catch errors.
+static void
+tuktest_catch_stdout_errors(void)
+{
+ if (ferror(stdout) || fclose(stdout)) {
+ fputs("Error while writing to stdout\n", stderr);
+ exit(TUKTEST_EXIT_ERROR);
+ }
+}
+
+
+// A simplified basename()-like function that is good enough for
+// cleaning up __FILE__. This supports / and \ as path separator.
+// If the path separator is wrong then the full path will be printed;
+// it's a cosmetic problem only.
+static const char *
+tuktest_basename(const char *filename)
+{
+ for (const char *p = filename + strlen(filename); p > filename; --p)
+ if (*p == '/' || *p == '\\')
+ return p + 1;
+
+ return filename;
+}
+
+
+// Internal helper that prints the prefix of the fail/skip/error message line.
+static void
+tuktest_print_result_prefix(enum tuktest_result result,
+ const char *filename, unsigned line)
+{
+ // This is never called with TUKTEST_PASS but I kept it here anyway.
+ const char *result_str
+ = result == TUKTEST_PASS ? TUKTEST_STR_PASS
+ : result == TUKTEST_FAIL ? TUKTEST_STR_FAIL
+ : result == TUKTEST_SKIP ? TUKTEST_STR_SKIP
+ : TUKTEST_STR_ERROR;
+
+ const char *short_filename = tuktest_basename(filename);
+
+ if (tuktest_name != NULL)
+ printf("%s %s [%s:%u] ", result_str, tuktest_name,
+ short_filename, line);
+ else
+ printf("%s [%s:%u] ", result_str, short_filename, line);
+}
+
+
+// An entry for linked list of memory allocations.
+struct tuktest_malloc_record {
+ struct tuktest_malloc_record *next;
+ void *p;
+};
+
+// Linked list of per-test allocations. This is used when under tuktest_run().
+// These allocations are freed in tuktest_run() and, in case of a hard error,
+// also in tuktest_end().
+static struct tuktest_malloc_record *tuktest_malloc_test = NULL;
+
+// Linked list of global allocations. This is used allocations are made
+// outside tuktest_run(). These are freed in tuktest_end().
+static struct tuktest_malloc_record *tuktest_malloc_global = NULL;
+
+
+/// A wrapper for malloc() that never return NULL and the allocated memory is
+/// automatically freed at the end of tuktest_run() (if allocation was done
+/// within a test) or early in tuktest_end() (if allocation was done outside
+/// tuktest_run()).
+///
+/// If allocation fails, a hard error is reported and this function won't
+/// return. Possible other tests won't be run (this will call exit()).
+#define tuktest_malloc(size) tuktest_malloc_impl(size, __FILE__, __LINE__)
+
+static void *
+tuktest_malloc_impl(size_t size, const char *filename, unsigned line)
+{
+ void *p = malloc(size == 0 ? 1 : size);
+ struct tuktest_malloc_record *r = malloc(sizeof(*r));
+
+ if (p == NULL || r == NULL) {
+ free(r);
+ free(p);
+
+ // Avoid %zu for portability to very old systems that still
+ // can compile C99 code.
+ tuktest_error_impl(filename, line,
+ "tuktest_malloc(%" TUKTEST_PRIu ") failed",
+ (tuktest_uint)size);
+ }
+
+ r->p = p;
+
+ if (tuktest_name == NULL) {
+ // We were called outside tuktest_run().
+ r->next = tuktest_malloc_global;
+ tuktest_malloc_global = r;
+ } else {
+ // We were called under tuktest_run().
+ r->next = tuktest_malloc_test;
+ tuktest_malloc_test = r;
+ }
+
+ return p;
+}
+
+
+/// Frees memory allocated using tuktest_malloc(). Usually this isn't needed
+/// as the memory is freed automatically.
+///
+/// NULL is silently ignored.
+///
+/// NOTE: Under tuktest_run() only memory allocated there can be freed.
+/// That is, allocations done outside tuktest_run() can only be freed
+/// outside tuktest_run().
+#define tuktest_free(ptr) tuktest_free_impl(ptr, __FILE__, __LINE__)
+
+static void
+tuktest_free_impl(void *p, const char *filename, unsigned line)
+{
+ if (p == NULL)
+ return;
+
+ struct tuktest_malloc_record **r = tuktest_name != NULL
+ ? &tuktest_malloc_test : &tuktest_malloc_global;
+
+ while (*r != NULL) {
+ struct tuktest_malloc_record *tmp = *r;
+
+ if (tmp->p == p) {
+ *r = tmp->next;
+ free(p);
+ free(tmp);
+ return;
+ }
+
+ r = &tmp->next;
+ }
+
+ tuktest_error_impl(filename, line, "tuktest_free: "
+ "Allocation matching the pointer was not found");
+}
+
+
+// Frees all allocates in the given record list. The argument must be
+// either &tuktest_malloc_test or &tuktest_malloc_global.
+static void
+tuktest_free_all(struct tuktest_malloc_record **r)
+{
+ while (*r != NULL) {
+ struct tuktest_malloc_record *tmp = *r;
+ *r = tmp->next;
+ free(tmp->p);
+ free(tmp);
+ }
+}
+
+
+/// Initialize the test framework. No other functions or macros
+/// from this file may be called before calling this.
+///
+/// If the arguments from main() aren't available, use 0 and NULL.
+/// If these are set, then only a subset of tests can be run by
+/// specifying their names on the command line.
+#define tuktest_start(argc, argv) \
+do { \
+ tuktest_argc = argc; \
+ tuktest_argv = argv; \
+ if (!TUKTEST_TAP && !TUKTEST_QUIET) \
+ printf("=== %s ===\n", tuktest_basename(__FILE__)); \
+} while (0)
+
+
+/// If it can be detected early that no tests can be run, this macro can
+/// be called after tuktest_start() but before any tuktest_run() to print
+/// a reason why the tests were skipped. Note that this macro calls exit().
+///
+/// Using "return tuktest_end();" in main() when no tests were run has
+/// the same result as tuktest_early_skip() except that then no reason
+/// for the skipping can be printed.
+#define tuktest_early_skip(...) \
+do { \
+ printf("%s [%s:%u] ", \
+ TUKTEST_TAP ? "1..0 # SKIP" : TUKTEST_STR_SKIP, \
+ tuktest_basename(__FILE__), __LINE__); \
+ printf(__VA_ARGS__); \
+ printf("\n"); \
+ if (!TUKTEST_TAP && !TUKTEST_QUIET) \
+ printf("=== END ===\n"); \
+ tuktest_catch_stdout_errors(); \
+ exit(TUKTEST_TAP ? EXIT_SUCCESS : TUKTEST_EXIT_SKIP); \
+} while (0)
+
+
+/// Some test programs need to do initializations before or between
+/// calls to tuktest_run(). If such initializations unexpectedly fail,
+/// tuktest_error() can be used to report it as a hard error outside
+/// test functions, for example, in main(). Then the remaining tests
+/// won't be run (this macro calls exit()).
+///
+/// Typically tuktest_error() would be used before any tuktest_run()
+/// calls but it is also possible to use tuktest_error() after one or
+/// more tests have been run with tuktest_run(). This is in contrast to
+/// tuktest_early_skip() which must never be called after tuktest_run().
+///
+/// NOTE: tuktest_start() must have been called before tuktest_error().
+///
+/// NOTE: This macro can be called from test functions running under
+/// tuktest_run() but assert_error() is somewhat preferred in that context.
+#define tuktest_error(...) tuktest_error_impl(__FILE__, __LINE__, __VA_ARGS__)
+
+
+/// At the end of main() one should have "return tuktest_end();" which
+/// prints the stats or the TAP plan, and handles the exit status.
+/// Using exit(tuktest_end()) is OK too.
+///
+/// If the test program can detect early that all tests must be skipped,
+/// then tuktest_early_skip() may be useful so that the reason why the
+/// tests were skipped can be printed.
+static int
+tuktest_end(void)
+{
+ tuktest_free_all(&tuktest_malloc_test);
+ tuktest_free_all(&tuktest_malloc_global);
+
+ unsigned total_tests = 0;
+ for (unsigned i = 0; i <= TUKTEST_ERROR; ++i)
+ total_tests += tuktest_stats[i];
+
+ if (tuktest_stats[TUKTEST_ERROR] == 0 && tuktest_argc > 1
+ && (unsigned)(tuktest_argc - 1) > total_tests) {
+ printf(TUKTEST_STR_ERROR " Fewer tests were run than "
+ "specified on the command line. "
+ "Was a test name mistyped?\n");
+ ++tuktest_stats[TUKTEST_ERROR];
+ }
+
+#if TUKTEST_TAP
+ // Print the plan only if no "Bail out!" has occurred.
+ // Print the skip directive if no tests were run.
+ // We cannot know the reason for the skip here though
+ // (see tuktest_early_skip()).
+ if (tuktest_stats[TUKTEST_ERROR] == 0)
+ printf("1..%u%s\n", total_tests,
+ total_tests == 0 ? " # SKIP" : "");
+
+ tuktest_catch_stdout_errors();
+ return EXIT_SUCCESS;
+#else
+ if (!TUKTEST_QUIET)
+ printf("---\n"
+ "%s# TOTAL: %u" TUKTEST_COLOR_OFF "\n"
+ "%s# PASS: %u" TUKTEST_COLOR_OFF "\n"
+ "%s# SKIP: %u" TUKTEST_COLOR_OFF "\n"
+ "%s# FAIL: %u" TUKTEST_COLOR_OFF "\n"
+ "%s# ERROR: %u" TUKTEST_COLOR_OFF "\n"
+ "=== END ===\n",
+ TUKTEST_COLOR_TOTAL,
+ total_tests,
+ TUKTEST_COLOR_IF(
+ tuktest_stats[TUKTEST_PASS] > 0,
+ TUKTEST_COLOR_PASS),
+ tuktest_stats[TUKTEST_PASS],
+ TUKTEST_COLOR_IF(
+ tuktest_stats[TUKTEST_SKIP] > 0,
+ TUKTEST_COLOR_SKIP),
+ tuktest_stats[TUKTEST_SKIP],
+ TUKTEST_COLOR_IF(
+ tuktest_stats[TUKTEST_FAIL] > 0,
+ TUKTEST_COLOR_FAIL),
+ tuktest_stats[TUKTEST_FAIL],
+ TUKTEST_COLOR_IF(
+ tuktest_stats[TUKTEST_ERROR] > 0,
+ TUKTEST_COLOR_ERROR),
+ tuktest_stats[TUKTEST_ERROR]);
+
+ tuktest_catch_stdout_errors();
+
+ if (tuktest_stats[TUKTEST_ERROR] > 0)
+ return TUKTEST_EXIT_ERROR;
+
+ if (tuktest_stats[TUKTEST_FAIL] > 0)
+ return TUKTEST_EXIT_FAIL;
+
+ if (tuktest_stats[TUKTEST_SKIP] > 0 || total_tests == 0)
+ return TUKTEST_EXIT_SKIP;
+
+ return TUKTEST_EXIT_PASS;
+#endif
+}
+
+
+/// Runs the specified test function. Requires that tuktest_start()
+/// has already been called and that tuktest_end() has NOT been called yet.
+#define tuktest_run(testfunc) \
+ tuktest_run_test(&(testfunc), #testfunc)
+
+tuktest_maybe_unused
+static void
+tuktest_run_test(void (*testfunc)(void), const char *testfunc_str)
+{
+ // If any command line arguments were given, only the test functions
+ // named on the command line will be run.
+ if (tuktest_argc > 1) {
+ int i = 1;
+ while (strcmp(tuktest_argv[i], testfunc_str) != 0)
+ if (++i == tuktest_argc)
+ return;
+ }
+
+ // This is set so that failed assertions can print the correct
+ // test name even when the assertion is in a helper function
+ // called by the test function.
+ tuktest_name = testfunc_str;
+
+ // The way setjmp() may be called is very restrictive.
+ // A switch statement is one of the few conforming ways
+ // to get the value passed to longjmp(); doing something
+ // like "int x = setjmp(env)" is NOT allowed (undefined behavior).
+ switch (setjmp(tuktest_jmpenv)) {
+ case 0:
+ testfunc();
+ ++tuktest_stats[TUKTEST_PASS];
+ if (!TUKTEST_QUIET)
+ printf(TUKTEST_STR_PASS " %s\n", tuktest_name);
+ break;
+
+ case TUKTEST_FAIL:
+ ++tuktest_stats[TUKTEST_FAIL];
+ break;
+
+ case TUKTEST_SKIP:
+ ++tuktest_stats[TUKTEST_SKIP];
+ break;
+
+ default:
+ ++tuktest_stats[TUKTEST_ERROR];
+ exit(tuktest_end());
+ }
+
+ tuktest_free_all(&tuktest_malloc_test);
+ tuktest_name = NULL;
+}
+
+
+// Maximum allowed file size in tuktest_file_from_* macros and functions.
+#ifndef TUKTEST_FILE_SIZE_MAX
+# define TUKTEST_FILE_SIZE_MAX (64L << 20)
+#endif
+
+/// Allocates memory and reads the specified file into a buffer.
+/// If the environment variable srcdir is set, it will be prefixed
+/// to the filename. Otherwise the filename is used as is (and so
+/// the behavior is identical to tuktest_file_from_builddir() below).
+///
+/// On success the a pointer to malloc'ed memory is returned.
+/// The size of the allocation and the file is stored in *size.
+///
+/// If anything goes wrong, a hard error is reported and this function
+/// won't return. Possible other tests won't be run (this will call exit()).
+///
+/// Empty files and files over TUKTEST_FILE_SIZE_MAX are rejected.
+/// The assumption is that something is wrong in these cases.
+///
+/// This function can be called either from outside the tests (like in main())
+/// or from tests run via tuktest_run(). Remember to free() the memory to
+/// keep Valgrind happy.
+#define tuktest_file_from_srcdir(filename, sizeptr) \
+ tuktest_file_from_x(getenv("srcdir"), filename, sizeptr, \
+ __FILE__, __LINE__)
+
+/// Like tuktest_file_from_srcdir except this reads from the current directory.
+#define tuktest_file_from_builddir(filename, sizeptr) \
+ tuktest_file_from_x(NULL, filename, sizeptr, __FILE__, __LINE__)
+
+// Internal helper for the macros above.
+tuktest_maybe_unused
+static void *
+tuktest_file_from_x(const char *prefix, const char *filename, size_t *size,
+ const char *prog_filename, unsigned prog_line)
+{
+ // If needed: buffer for holding prefix + '/' + filename + '\0'.
+ char *alloc_name = NULL;
+
+ // Buffer for the data read from the file.
+ void *buf = NULL;
+
+ // File being read
+ FILE *f = NULL;
+
+ // Error message to use under the "error:" label.
+ const char *error_msg = NULL;
+
+ if (filename == NULL) {
+ error_msg = "Filename is NULL";
+ filename = "(NULL)";
+ goto error;
+ }
+
+ if (filename[0] == '\0') {
+ error_msg = "Filename is an empty string";
+ filename = "(empty string)";
+ goto error;
+ }
+
+ if (size == NULL) {
+ error_msg = "The size argument is NULL";
+ goto error;
+ }
+
+ // If a prefix was given, construct the full filename.
+ if (prefix != NULL && prefix[0] != '\0') {
+ const size_t prefix_len = strlen(prefix);
+ const size_t filename_len = strlen(filename);
+
+ const size_t alloc_name_size
+ = prefix_len + 1 + filename_len + 1;
+ alloc_name = tuktest_malloc_impl(alloc_name_size,
+ prog_filename, prog_line);
+
+ memcpy(alloc_name, prefix, prefix_len);
+ alloc_name[prefix_len] = '/';
+ memcpy(alloc_name + prefix_len + 1, filename, filename_len);
+ alloc_name[prefix_len + 1 + filename_len] = '\0';
+
+ // Set filename to point to the new string. alloc_name
+ // can be freed unconditionally as it is NULL if a prefix
+ // wasn't specified.
+ filename = alloc_name;
+ }
+
+ f = fopen(filename, "rb");
+ if (f == NULL) {
+ error_msg = "Failed to open the file";
+ goto error;
+ }
+
+ // Get the size of the file and store it in *size.
+ //
+ // We assume that the file isn't big and even reject very big files.
+ // There is no need to use fseeko/ftello from POSIX to support
+ // large files. Using standard C functions is portable outside POSIX.
+ if (fseek(f, 0, SEEK_END) != 0) {
+ error_msg = "Seeking failed (fseek end)";
+ goto error;
+ }
+
+ const long end = ftell(f);
+ if (end < 0) {
+ error_msg = "Seeking failed (ftell)";
+ goto error;
+ }
+
+ if (end == 0) {
+ error_msg = "File is empty";
+ goto error;
+ }
+
+ if (end > TUKTEST_FILE_SIZE_MAX) {
+ error_msg = "File size exceeds TUKTEST_FILE_SIZE_MAX";
+ goto error;
+ }
+
+ *size = (size_t)end;
+ rewind(f);
+
+ buf = tuktest_malloc_impl(*size, prog_filename, prog_line);
+
+ const size_t amount = fread(buf, 1, *size, f);
+ if (ferror(f)) {
+ error_msg = "Read error";
+ goto error;
+ }
+
+ if (amount != *size) {
+ error_msg = "File is smaller than indicated by ftell()";
+ goto error;
+ }
+
+ const int fclose_ret = fclose(f);
+ f = NULL;
+ if (fclose_ret != 0) {
+ error_msg = "Error closing the file";
+ goto error;
+ }
+
+ tuktest_free(alloc_name);
+ return buf;
+
+error:
+ if (f != NULL)
+ (void)fclose(f);
+
+ tuktest_error_impl(prog_filename, prog_line,
+ "tuktest_file_from_x: %s: %s\n", filename, error_msg);
+}
+
+
+// Internal helper for assert_fail, assert_skip, and assert_error.
+#define tuktest_print_and_jump(result, ...) \
+do { \
+ tuktest_print_result_prefix(result, __FILE__, __LINE__); \
+ printf(__VA_ARGS__); \
+ printf("\n"); \
+ longjmp(tuktest_jmpenv, result); \
+} while (0)
+
+
+/// Unconditionally fails the test (non-zero exit status if not using TAP).
+/// Execution will continue from the next test.
+///
+/// A printf format string is supported.
+/// If no extra message is wanted, use "" as the argument.
+#define assert_fail(...) tuktest_print_and_jump(TUKTEST_FAIL, __VA_ARGS__)
+
+
+/// Skips the test (exit status 77 if not using TAP).
+/// Execution will continue from the next test.
+///
+/// If you can detect early that no tests can be run, tuktest_early_skip()
+/// might be a better way to skip the test(s). Especially in TAP mode this
+/// makes a difference as with assert_skip() it will list a skipped specific
+/// test name but with tuktest_early_skip() it will indicate that the whole
+/// test program was skipped (with tuktest_early_skip() the TAP plan will
+/// indicate zero tests).
+///
+/// A printf format string is supported.
+/// If no extra message is wanted, use "" as the argument.
+#define assert_skip(...) tuktest_print_and_jump(TUKTEST_SKIP, __VA_ARGS__)
+
+
+/// Hard error (exit status 99 if not using TAP).
+/// The remaining tests in this program will not be run or reported.
+///
+/// A printf format string is supported.
+/// If no extra message is wanted, use "" as the argument.
+#define assert_error(...) tuktest_print_and_jump(TUKTEST_ERROR, __VA_ARGS__)
+
+
+/// Fails the test if the test expression doesn't evaluate to false.
+#define assert_false(test_expr) \
+do { \
+ if (test_expr) \
+ assert_fail("assert_fail: '%s' is true but should be false", \
+ #test_expr); \
+} while (0)
+
+
+/// Fails the test if the test expression doesn't evaluate to true.
+#define assert_true(test_expr) \
+do { \
+ if (!(test_expr)) \
+ assert_fail("assert_true: '%s' is false but should be true", \
+ #test_expr); \
+} while (0)
+
+
+/// Fails the test if comparing the signed integer expressions using the
+/// specified comparison operator evaluates to false. For example,
+/// assert_int(foobar(), >=, 0) fails the test if 'foobar() >= 0' isn't true.
+/// For good error messages, the first argument should be the test expression
+/// and the third argument the reference value (usually a constant).
+///
+/// For equality (==) comparison there is a assert_int_eq() which
+/// might be more convenient to use.
+#define assert_int(test_expr, cmp_op, ref_value) \
+do { \
+ const tuktest_int v_test_ = (test_expr); \
+ const tuktest_int v_ref_ = (ref_value); \
+ if (!(v_test_ cmp_op v_ref_)) \
+ assert_fail("assert_int: '%s == %" TUKTEST_PRId \
+ "' but expected '... %s %" TUKTEST_PRId "'", \
+ #test_expr, v_test_, #cmp_op, v_ref_); \
+} while (0)
+
+
+/// Like assert_int() but for unsigned integers.
+///
+/// For equality (==) comparison there is a assert_uint_eq() which
+/// might be more convenient to use.
+#define assert_uint(test_expr, cmp_op, ref_value) \
+do { \
+ const tuktest_uint v_test_ = (test_expr); \
+ const tuktest_uint v_ref_ = (ref_value); \
+ if (!(v_test_ cmp_op v_ref_)) \
+ assert_fail("assert_uint: '%s == %" TUKTEST_PRIu \
+ "' but expected '... %s %" TUKTEST_PRIu "'", \
+ #test_expr, v_test_, #cmp_op, v_ref_); \
+} while (0)
+
+
+/// Fails the test if test expression doesn't equal the expected
+/// signed integer value.
+#define assert_int_eq(test_expr, ref_value) \
+ assert_int(test_expr, ==, ref_value)
+
+
+/// Fails the test if test expression doesn't equal the expected
+/// unsigned integer value.
+#define assert_uint_eq(test_expr, ref_value) \
+ assert_uint(test_expr, ==, ref_value)
+
+
+/// Fails the test if the test expression doesn't equal the expected
+/// enumeration value. This is like assert_int_eq() but the error message
+/// shows the enumeration constant names instead of their numeric values
+/// as long as the values are non-negative and not big.
+///
+/// The third argument must be a table of string pointers. A pointer to
+/// a pointer doesn't work because this determines the number of elements
+/// in the array using sizeof. For example:
+///
+/// const char *my_enum_names[] = { "MY_FOO", "MY_BAR", "MY_BAZ" };
+/// assert_enum_eq(some_func_returning_my_enum(), MY_BAR, my_enum_names);
+///
+/// (If the reference value is out of bounds, both values are printed as
+/// an integer. If only test expression is out of bounds, it is printed
+/// as an integer and the reference as a string. Otherwise both are printed
+/// as a string.)
+#define assert_enum_eq(test_expr, ref_value, enum_strings) \
+do { \
+ const tuktest_int v_test_ = (test_expr); \
+ const tuktest_int v_ref_ = (ref_value); \
+ if (v_test_ != v_ref_) { \
+ const int array_len_ = (int)(sizeof(enum_strings) \
+ / sizeof((enum_strings)[0])); \
+ if (v_ref_ < 0 || v_ref_ >= array_len_) \
+ assert_fail("assert_enum_eq: '%s == %" TUKTEST_PRId \
+ "' but expected " \
+ "'... == %" TUKTEST_PRId "'", \
+ #test_expr, v_test_, v_ref_); \
+ else if (v_test_ < 0 || v_test_ >= array_len_) \
+ assert_fail("assert_enum_eq: '%s == %" TUKTEST_PRId \
+ "' but expected '... == %s'", \
+ #test_expr, v_test_, \
+ (enum_strings)[v_ref_]); \
+ else \
+ assert_fail("assert_enum_eq: '%s == %s' " \
+ "but expected '... = %s'", \
+ #test_expr, (enum_strings)[v_test_], \
+ (enum_strings)[v_ref_]); \
+ } \
+} while (0)
+
+
+/// Fails the test if the specified bit isn't set in the test expression.
+#define assert_bit_set(test_expr, bit) \
+do { \
+ const tuktest_uint v_test_ = (test_expr); \
+ const unsigned v_bit_ = (bit); \
+ const tuktest_uint v_mask_ = (tuktest_uint)1 << v_bit_; \
+ if (!(v_test_ & v_mask_)) \
+ assert_fail("assert_bit_set: '%s == 0x%" TUKTEST_PRIX \
+ "' but bit %u (0x%" TUKTEST_PRIX ") " \
+ "is not set", \
+ #test_expr, v_test_, v_bit_, v_mask_); \
+} while (0)
+
+
+/// Fails the test if the specified bit is set in the test expression.
+#define assert_bit_not_set(test_expr, bit) \
+do { \
+ const tuktest_uint v_test_ = (test_expr); \
+ const unsigned v_bit_ = (bit); \
+ const tuktest_uint v_mask_ = (tuktest_uint)1 << v_bit_; \
+ if (v_test_ & v_mask_) \
+ assert_fail("assert_bit_not_set: '%s == 0x%" TUKTEST_PRIX \
+ "' but bit %u (0x%" TUKTEST_PRIX ") is set", \
+ #test_expr, v_test_, v_bit_, v_mask_); \
+} while (0)
+
+
+/// Fails the test if unless all bits that are set in the bitmask are also
+/// set in the test expression.
+#define assert_bitmask_set(test_expr, mask) \
+do { \
+ const tuktest_uint v_mask_ = (mask); \
+ const tuktest_uint v_test_ = (test_expr) & v_mask_; \
+ if (v_test_ != v_mask_) \
+ assert_fail("assert_bitmask_set: " \
+ "'((%s) & 0x%" TUKTEST_PRIX ") == " \
+ "0x%" TUKTEST_PRIX "' but expected " \
+ "'... == 0x%" TUKTEST_PRIX "'", \
+ #test_expr, v_mask_, v_test_, v_mask_); \
+} while (0)
+
+
+/// Fails the test if any of the bits that are set in the bitmask are also
+/// set in the test expression.
+#define assert_bitmask_not_set(test_expr, mask) \
+do { \
+ const tuktest_uint v_mask_ = (mask); \
+ const tuktest_uint v_test_ = (test_expr) & v_mask_; \
+ if (v_test_ != 0) \
+ assert_fail("assert_bitmask_not_set: "\
+ "'((%s) & 0x%" TUKTEST_PRIX ") == " \
+ "0x%" TUKTEST_PRIX "' but expected " \
+ "'... == 0'", \
+ #test_expr, v_mask_, v_test_); \
+} while (0)
+
+
+// Internal helper to add common code for string assertions.
+#define tuktest_str_helper1(macro_name, test_expr, ref_value) \
+ const char *v_test_ = (test_expr); \
+ const char *v_ref_ = (ref_value); \
+ if (v_test_ == NULL) \
+ assert_fail(macro_name ": Test expression '%s' is NULL", \
+ #test_expr); \
+ if (v_ref_ == NULL) \
+ assert_fail(macro_name ": Reference value '%s' is NULL", \
+ #ref_value)
+
+
+// Internal helper to add common code for string assertions and to check
+// that the reference value isn't an empty string.
+#define tuktest_str_helper2(macro_name, test_expr, ref_value) \
+ tuktest_str_helper1(macro_name, test_expr, ref_value); \
+ if (v_ref_[0] == '\0') \
+ assert_fail(macro_name ": Reference value is an empty string")
+
+
+/// Fails the test if the test expression evaluates to string that doesn't
+/// equal to the expected string.
+#define assert_str_eq(test_expr, ref_value) \
+do { \
+ tuktest_str_helper1("assert_str_eq", test_expr, ref_value); \
+ if (strcmp(v_ref_, v_test_) != 0) \
+ assert_fail("assert_str_eq: '%s' evaluated to '%s' " \
+ "but expected '%s'", \
+ #test_expr, v_test_, v_ref_); \
+} while (0)
+
+
+/// Fails the test if the test expression evaluates to a string that doesn't
+/// contain the reference value as a substring. Also fails the test if
+/// the reference value is an empty string.
+#define assert_str_contains(test_expr, ref_value) \
+do { \
+ tuktest_str_helper2("assert_str_contains", test_expr, ref_value); \
+ if (strstr(v_test_, v_ref_) == NULL) \
+ assert_fail("assert_str_contains: '%s' evaluated to '%s' " \
+ "which doesn't contain '%s'", \
+ #test_expr, v_test_, v_ref_); \
+} while (0)
+
+
+/// Fails the test if the test expression evaluates to a string that
+/// contains the reference value as a substring. Also fails the test if
+/// the reference value is an empty string.
+#define assert_str_doesnt_contain(test_expr, ref_value) \
+do { \
+ tuktest_str_helper2("assert_str_doesnt_contain", \
+ test_expr, ref_value); \
+ if (strstr(v_test_, v_ref_) != NULL) \
+ assert_fail("assert_str_doesnt_contain: " \
+ "'%s' evaluated to '%s' which contains '%s'", \
+ #test_expr, v_test_, v_ref_); \
+} while (0)
+
+
+/// Fails the test if the first array_size elements of the test array
+/// don't equal to correct_array.
+///
+/// NOTE: This avoids %zu for portability to very old systems that still
+/// can compile C99 code.
+#define assert_array_eq(test_array, correct_array, array_size) \
+do { \
+ for (size_t i_ = 0; i_ < (array_size); ++i_) \
+ if ((test_array)[i_] != (correct_array)[i_]) \
+ assert_fail("assert_array_eq: " \
+ "%s[%" TUKTEST_PRIu "] != "\
+ "%s[%" TUKTEST_PRIu "] " \
+ "but should be equal", \
+ #test_array, (tuktest_uint)i_, \
+ #correct_array, (tuktest_uint)i_); \
+} while (0)
+
+#endif
diff --git a/tests/xzgrep_expected_output b/tests/xzgrep_expected_output
new file mode 100644
index 0000000..e531d93
--- /dev/null
+++ b/tests/xzgrep_expected_output
@@ -0,0 +1,39 @@
+=> xzgrep el <=
+xzgrep_test_1.xz:elit, sed do eiusmod tempor incididunt ut
+xzgrep_test_1.xz:in voluptate velit esse cillum dolore eu
+xzgrep_test_2.xz:Hello
+retval 0
+=> xzgrep -l el <=
+xzgrep_test_1.xz
+xzgrep_test_2.xz
+retval 0
+=> xzgrep -h el <=
+elit, sed do eiusmod tempor incididunt ut
+in voluptate velit esse cillum dolore eu
+Hello
+retval 0
+=> xzgrep -H el <=
+xzgrep_test_1.xz:elit, sed do eiusmod tempor incididunt ut
+xzgrep_test_1.xz:in voluptate velit esse cillum dolore eu
+xzgrep_test_2.xz:Hello
+retval 0
+=> xzgrep Hello <=
+xzgrep_test_2.xz:Hello
+retval 0
+=> xzgrep -l Hello <=
+xzgrep_test_2.xz
+retval 0
+=> xzgrep -h Hello <=
+Hello
+retval 0
+=> xzgrep -H Hello <=
+xzgrep_test_2.xz:Hello
+retval 0
+=> xzgrep NOMATCH <=
+retval 1
+=> xzgrep -l NOMATCH <=
+retval 1
+=> xzgrep -h NOMATCH <=
+retval 1
+=> xzgrep -H NOMATCH <=
+retval 1